001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * thibaud 016 */ 017package org.nuxeo.diff.pictures; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.OutputStream; 022import java.io.Serializable; 023import java.util.HashMap; 024 025import javax.servlet.ServletException; 026import javax.servlet.http.HttpServlet; 027import javax.servlet.http.HttpServletRequest; 028import javax.servlet.http.HttpServletResponse; 029 030import org.apache.commons.lang.StringUtils; 031import org.apache.commons.logging.Log; 032import org.apache.commons.logging.LogFactory; 033import org.nuxeo.ecm.core.api.Blob; 034import org.nuxeo.ecm.core.api.CoreInstance; 035import org.nuxeo.ecm.core.api.CoreSession; 036import org.nuxeo.ecm.core.api.DocumentModel; 037import org.nuxeo.ecm.core.api.IdRef; 038import org.nuxeo.ecm.core.api.repository.RepositoryManager; 039import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable; 040import org.nuxeo.ecm.platform.web.common.ServletHelper; 041import org.nuxeo.runtime.api.Framework; 042 043/** 044 * /nuxeo/diffPictures?&repo=therepo&leftDocId=123456&rightDocId= 456789012 045 * &xpath=file:content&commandLine=thecommandline&fuzz=1000&highlightColor=Red &lowlightColor=White&altExtension=jpg 046 * <p> 047 * <ul> 048 * <li><code>leftDocId</code> and <code>rightDocId</code> are required</li> 049 * <li>All other parameters are optional (commandLine, xpath, fuzz, ...). Default values are defined in 050 * <code>DiffPictures</code></li> 051 * <li><code>altExtension</code> is special. If the pictures to compare are _not_ jpeg, png, or gif, _and_ if this 052 * parameter is set, then the result picture will be of this kind. Useful when comparing 2 psd or tif files for example, 053 * and the browser can't display them</li> 054 * </ul> 055 * <p> 056 * commandline, xpath, fuzz, highlightColor, lowlightColor and repo are optional 057 * 058 * @since 7.4 059 */ 060public class DiffPicturesServlet extends HttpServlet { 061 062 private static final long serialVersionUID = 1L; 063 064 private static final Log log = LogFactory.getLog(DiffPicturesServlet.class); 065 066 protected static final int BUFFER_SIZE = 1024 * 512; 067 068 @Override 069 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 070 071 DocumentModel leftDoc, rightDoc; 072 073 String leftDocId = req.getParameter("leftDocId"); 074 String rightDocId = req.getParameter("rightDocId"); 075 076 if (StringUtils.isBlank(leftDocId)) { 077 sendTextResponse(resp, "you must specify a left document as origin"); 078 return; 079 } 080 if (StringUtils.isBlank(rightDocId)) { 081 sendTextResponse(resp, "you must specify 'right' used for comparison against the left document."); 082 return; 083 } 084 085 // WARNING: If you change the name of a parameter, also change it in nuxeo-diff-pictures.js 086 String repo = req.getParameter("repo"); 087 String xpath = req.getParameter("xpath"); 088 String commandLine = req.getParameter("commandLine"); 089 String fuzz = req.getParameter("fuzz"); 090 String highlightColor = req.getParameter("highlightColor"); 091 String lowlightColor = req.getParameter("lowlightColor"); 092 String altExtension = req.getParameter("altExtension"); 093 094 if (StringUtils.isBlank(repo)) { 095 repo = Framework.getLocalService(RepositoryManager.class).getDefaultRepository().getName(); 096 } 097 098 // This try-with-resources does an implicit close() at the end 099 try (CoreSession coreSession = CoreInstance.openCoreSession(repo)) { 100 101 leftDoc = coreSession.getDocument(new IdRef(leftDocId)); 102 rightDoc = coreSession.getDocument(new IdRef(rightDocId)); 103 104 DiffPictures dp = new DiffPictures(leftDoc, rightDoc, xpath); 105 106 HashMap<String, Serializable> params = new HashMap<String, Serializable>(); 107 if (StringUtils.isNotBlank(fuzz)) { 108 params.put("fuzz", fuzz); 109 } 110 if (StringUtils.isNotBlank(highlightColor)) { 111 params.put("highlightColor", highlightColor); 112 } 113 if (StringUtils.isNotBlank(lowlightColor)) { 114 params.put("lowlightColor", lowlightColor); 115 } 116 117 if (StringUtils.isNotBlank(altExtension)) { 118 // Using the leftDoc only 119 Blob leftB; 120 if (StringUtils.isBlank(xpath) || "null".equals(xpath)) { 121 leftB = (Blob) leftDoc.getPropertyValue(DiffPictures.DEFAULT_XPATH); 122 } else { 123 leftB = (Blob) leftDoc.getPropertyValue(xpath); 124 } 125 String fileName = leftB.getFilename(); 126 int dotPos = fileName.lastIndexOf("."); 127 String ext = fileName.substring(dotPos + 1); 128 ext = ext.toLowerCase(); 129 switch (ext) { 130 case "jpg": 131 case "jpeg": 132 case "png": 133 case "gif": 134 // No need to change anything 135 break; 136 137 default: 138 if (altExtension.indexOf(".") != 0) { 139 altExtension = "." + altExtension; 140 } 141 fileName = "comp-" + fileName + altExtension; 142 params.put("targetFileName", fileName); 143 break; 144 145 } 146 } 147 148 Blob bResult; 149 try { 150 bResult = dp.compare(commandLine, params); 151 } catch (CommandNotAvailable | IOException e) { 152 log.error("Unable to compare the pictures", e); 153 sendTextResponse(resp, "Unable to compare the pictures"); 154 return; 155 } 156 157 resp.setHeader("Cache-Control", "no-cache"); 158 resp.setHeader("Pragma", "no-cache"); 159 try { 160 sendBlobResult(req, resp, bResult); 161 } catch (IOException e) { 162 log.error("Unable to handleCompareResult", e); 163 sendTextResponse(resp, "Unable to return the result"); 164 return; 165 } 166 } 167 } 168 169 protected void sendTextResponse(HttpServletResponse resp, String response) throws IOException { 170 171 resp.setContentType("text/plain"); 172 resp.setContentLength(response.getBytes().length); 173 OutputStream out = resp.getOutputStream(); 174 out.write(response.getBytes()); 175 out.close(); 176 177 } 178 179 protected void sendBlobResult(HttpServletRequest req, HttpServletResponse resp, Blob blob) throws IOException { 180 181 InputStream in = blob.getStream(); 182 OutputStream out = resp.getOutputStream(); 183 String fileName = blob.getFilename(); 184 185 resp.setHeader("Content-Disposition", ServletHelper.getRFC2231ContentDisposition(req, fileName)); 186 resp.setContentType(blob.getMimeType()); 187 long fileSize = blob.getLength(); 188 resp.setContentLength((int) fileSize); 189 190 byte[] buffer = new byte[BUFFER_SIZE]; 191 int bytesRead; 192 while ((bytesRead = in.read(buffer)) != -1) { 193 out.write(buffer, 0, bytesRead); 194 } 195 196 } 197}