mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged REPO-2054 (5.2.1) to 5.2.N (5.2.1)
136871 skopf: REPO-2054 - GS Replacement: Implement new transformer to invoke the rasterizer, depending on chosen technology - rename transformer to "alfresco-pdf-renderer" transformer - added code to check availability - formatted source code git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@137097 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -657,13 +657,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- Import the Pdfium transformer from the third party subsystem -->
|
<!-- Import the Alfresco-PDF-Renderer transformer from the third party subsystem -->
|
||||||
<bean id="transformer.worker.Pdfium" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
<bean id="transformer.worker.alfresco-pdf-renderer" class="org.alfresco.repo.management.subsystems.SubsystemProxyFactory">
|
||||||
<property name="sourceApplicationContextFactory">
|
<property name="sourceApplicationContextFactory">
|
||||||
<ref bean="thirdparty" />
|
<ref bean="thirdparty" />
|
||||||
</property>
|
</property>
|
||||||
<property name="sourceBeanName">
|
<property name="sourceBeanName">
|
||||||
<value>transformer.worker.Pdfium</value>
|
<value>transformer.worker.subsys.alfresco-pdf-renderer</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="interfaces">
|
<property name="interfaces">
|
||||||
<list>
|
<list>
|
||||||
@@ -672,9 +672,9 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="transformer.Pdfium" class="org.alfresco.repo.content.transform.ProxyContentTransformer" parent="baseContentTransformer">
|
<bean id="transformer.alfresco-pdf-renderer" class="org.alfresco.repo.content.transform.ProxyContentTransformer" parent="baseContentTransformer">
|
||||||
<property name="worker">
|
<property name="worker">
|
||||||
<ref bean="transformer.worker.Pdfium" />
|
<ref bean="transformer.worker.alfresco-pdf-renderer" />
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@@ -2,17 +2,17 @@
|
|||||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||||
<beans>
|
<beans>
|
||||||
|
|
||||||
<bean id="transformer.worker.Pdfium" class="org.alfresco.repo.content.transform.pdfium.PdfiumContentTransformerWorker">
|
<bean id="transformer.worker.subsys.alfresco-pdf-renderer" class="org.alfresco.repo.content.transform.pdfrenderer.AlfrescoPdfRendererContentTransformerWorker">
|
||||||
<property name="mimetypeService">
|
<property name="mimetypeService">
|
||||||
<ref bean="mimetypeService" />
|
<ref bean="mimetypeService" />
|
||||||
</property>
|
</property>
|
||||||
<property name="executer">
|
<property name="executer">
|
||||||
<bean name="transformer.Pdfium.Command" class="org.alfresco.util.exec.RuntimeExec">
|
<bean name="transformer.alfresco-pdf-renderer.command" class="org.alfresco.util.exec.RuntimeExec">
|
||||||
<property name="commandsAndArguments">
|
<property name="commandsAndArguments">
|
||||||
<map>
|
<map>
|
||||||
<entry key=".*">
|
<entry key=".*">
|
||||||
<list>
|
<list>
|
||||||
<value>${pdfium.exe}</value>
|
<value>${alfresco-pdf-renderer.exe}</value>
|
||||||
<value>SPLIT:${options}</value>
|
<value>SPLIT:${options}</value>
|
||||||
<value>${source}</value>
|
<value>${source}</value>
|
||||||
<value>${target}</value>
|
<value>${target}</value>
|
||||||
@@ -27,8 +27,21 @@
|
|||||||
</props>
|
</props>
|
||||||
</property>
|
</property>
|
||||||
<property name="errorCodes" >
|
<property name="errorCodes" >
|
||||||
<!-- The published error and fatal error codes are in the 400 and 700 ranges, but 1 is the most common and have seen 255 (could that by -1) -->
|
<value>1</value>
|
||||||
<value>1,2,255,400,405,410,415,420,425,430,435,440,450,455,460,465,470,475,480,485,490,495,499,700,705,710,715,720,725,730,735,740,750,755,760,765,770,775,780,785,790,795,799</value>
|
</property>
|
||||||
|
</bean>
|
||||||
|
</property>
|
||||||
|
<property name="checkCommand">
|
||||||
|
<bean name="transformer.Pdfium.CheckCommand" class="org.alfresco.util.exec.RuntimeExec">
|
||||||
|
<property name="commandsAndArguments">
|
||||||
|
<map>
|
||||||
|
<entry key=".*">
|
||||||
|
<list>
|
||||||
|
<value>${alfresco-pdf-renderer.exe}</value>
|
||||||
|
<value>--version</value>
|
||||||
|
</list>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
</property>
|
</property>
|
||||||
@@ -37,8 +50,8 @@
|
|||||||
<bean id="processPropertiesWindows" class="org.springframework.beans.factory.config.MapFactoryBean">
|
<bean id="processPropertiesWindows" class="org.springframework.beans.factory.config.MapFactoryBean">
|
||||||
<property name="sourceMap">
|
<property name="sourceMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="PDFIUM_HOME">
|
<entry key="ALFRESCO-PDF-RENDERER_HOME">
|
||||||
<value>${pdfium.root}</value>
|
<value>${alfresco-pdf-renderer.root}</value>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</property>
|
</property>
|
||||||
@@ -47,8 +60,8 @@
|
|||||||
<bean id="processPropertiesUnix" class="org.springframework.beans.factory.config.MapFactoryBean">
|
<bean id="processPropertiesUnix" class="org.springframework.beans.factory.config.MapFactoryBean">
|
||||||
<property name="sourceMap">
|
<property name="sourceMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="PDFIUM_HOME">
|
<entry key="ALFRESCO-PDF-RENDERER_HOME">
|
||||||
<value>${pdfium.root}</value>
|
<value>${alfresco-pdf-renderer.root}</value>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
</property>
|
</property>
|
3
config/alfresco/subsystems/thirdparty/default/alfresco-pdf-renderer-transform.properties
vendored
Normal file
3
config/alfresco/subsystems/thirdparty/default/alfresco-pdf-renderer-transform.properties
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# External executable locations
|
||||||
|
alfresco-pdf-renderer.root=.
|
||||||
|
alfresco-pdf-renderer.exe=${alfresco-pdf-renderer.root}/alfresco-pdf-renderer
|
@@ -1,4 +0,0 @@
|
|||||||
# External executable locations
|
|
||||||
pdfium.root=./common
|
|
||||||
pdfium.exe=${pdfium.root}/alfresco-pdf-renderer
|
|
||||||
|
|
@@ -1,301 +0,0 @@
|
|||||||
/*
|
|
||||||
* #%L
|
|
||||||
* Alfresco Repository
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
|
||||||
* %%
|
|
||||||
* This file is part of the Alfresco software.
|
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
|
||||||
* the paid license agreement will prevail. Otherwise, the software is
|
|
||||||
* provided under the following open source license terms:
|
|
||||||
*
|
|
||||||
* Alfresco is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Alfresco is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* #L%
|
|
||||||
*/
|
|
||||||
package org.alfresco.repo.content.transform.pdfium;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
|
||||||
import org.alfresco.repo.content.MimetypeMap;
|
|
||||||
import org.alfresco.repo.content.transform.ContentTransformerHelper;
|
|
||||||
import org.alfresco.repo.content.transform.ContentTransformerWorker;
|
|
||||||
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
|
||||||
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentReader;
|
|
||||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
|
||||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
|
||||||
import org.alfresco.service.cmr.repository.PagedSourceOptions;
|
|
||||||
import org.alfresco.service.cmr.repository.TransformationOptions;
|
|
||||||
import org.alfresco.util.TempFileProvider;
|
|
||||||
import org.alfresco.util.exec.RuntimeExec;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
public class PdfiumContentTransformerWorker extends ContentTransformerHelper
|
|
||||||
implements ContentTransformerWorker, InitializingBean {
|
|
||||||
|
|
||||||
/** options variable name */
|
|
||||||
private static final String KEY_OPTIONS = "options";
|
|
||||||
/** source variable name */
|
|
||||||
private static final String VAR_SOURCE = "source";
|
|
||||||
/** target variable name */
|
|
||||||
private static final String VAR_TARGET = "target";
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(PdfiumContentTransformerWorker.class);
|
|
||||||
|
|
||||||
/** the system command executer */
|
|
||||||
private RuntimeExec executer;
|
|
||||||
|
|
||||||
/** the output from the check command */
|
|
||||||
private String versionString;
|
|
||||||
|
|
||||||
private boolean available;
|
|
||||||
|
|
||||||
public PdfiumContentTransformerWorker() {
|
|
||||||
this.available = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
if (executer == null) {
|
|
||||||
throw new AlfrescoRuntimeException("System runtime executer not set");
|
|
||||||
}
|
|
||||||
setAvailable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the runtime command executer that must be executed in order to run
|
|
||||||
* <b>ImageMagick</b>. Whether or not this is the full path to the convertCommand
|
|
||||||
* or just the convertCommand itself depends the environment setup.
|
|
||||||
* <p>
|
|
||||||
* The command must contain the variables <code>${source}</code> and
|
|
||||||
* <code>${target}</code>, which will be replaced by the names of the file to
|
|
||||||
* be transformed and the name of the output file respectively.
|
|
||||||
* <pre>
|
|
||||||
* convert ${source} ${target}
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param executer the system command executer
|
|
||||||
*/
|
|
||||||
public void setExecuter(RuntimeExec executer)
|
|
||||||
{
|
|
||||||
executer.setProcessProperty(
|
|
||||||
"PDFIUM_TMPDIR", TempFileProvider.getTempDir().getAbsolutePath());
|
|
||||||
this.executer = executer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Returns true if the transformer is functioning otherwise false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the transformer available
|
|
||||||
*
|
|
||||||
* @param available
|
|
||||||
* boolean
|
|
||||||
*/
|
|
||||||
protected void setAvailable(boolean available) {
|
|
||||||
this.available = available;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getVersionString() {
|
|
||||||
return this.versionString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options) {
|
|
||||||
if (!available) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add limited support (so lots of other transforms are not supported)
|
|
||||||
// for PDF to PNG.
|
|
||||||
if ((MimetypeMap.MIMETYPE_PDF.equals(sourceMimetype)
|
|
||||||
|| MimetypeMap.MIMETYPE_APPLICATION_ILLUSTRATOR.equals(sourceMimetype))
|
|
||||||
&& MimetypeMap.MIMETYPE_IMAGE_PNG.equals(targetMimetype)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception {
|
|
||||||
// get mimetypes
|
|
||||||
String sourceMimetype = getMimetype(reader);
|
|
||||||
String targetMimetype = getMimetype(writer);
|
|
||||||
|
|
||||||
// get the extensions to use
|
|
||||||
MimetypeService mimetypeService = getMimetypeService();
|
|
||||||
String sourceExtension = mimetypeService.getExtension(sourceMimetype);
|
|
||||||
String targetExtension = mimetypeService.getExtension(targetMimetype);
|
|
||||||
if (sourceExtension == null || targetExtension == null) {
|
|
||||||
throw new AlfrescoRuntimeException("Unknown extensions for mimetypes: \n" + " source mimetype: "
|
|
||||||
+ sourceMimetype + "\n" + " source extension: " + sourceExtension + "\n" + " target mimetype: "
|
|
||||||
+ targetMimetype + "\n" + " target extension: " + targetExtension);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create required temp files
|
|
||||||
File sourceFile = TempFileProvider.createTempFile(getClass().getSimpleName() + "_source_",
|
|
||||||
"." + sourceExtension);
|
|
||||||
File targetFile = TempFileProvider.createTempFile(getClass().getSimpleName() + "_target_",
|
|
||||||
"." + targetExtension);
|
|
||||||
|
|
||||||
// pull reader file into source temp file
|
|
||||||
reader.getContent(sourceFile);
|
|
||||||
|
|
||||||
transformInternal(sourceFile, sourceMimetype, targetFile, targetMimetype, options);
|
|
||||||
|
|
||||||
// check that the file was created
|
|
||||||
if (!targetFile.exists() || targetFile.length() == 0) {
|
|
||||||
throw new ContentIOException("Pdfium transformation failed to write output file");
|
|
||||||
}
|
|
||||||
// upload the output image
|
|
||||||
writer.putContent(targetFile);
|
|
||||||
// done
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Transformation completed: \n" + " source: " + reader + "\n" + " target: " + writer + "\n"
|
|
||||||
+ " options: " + options);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform the pdf content from the source file to the target file
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void transformInternal(File sourceFile, String sourceMimetype, File targetFile, String targetMimetype,
|
|
||||||
TransformationOptions options) throws Exception {
|
|
||||||
Map<String, String> properties = new HashMap<String, String>(5);
|
|
||||||
// set properties
|
|
||||||
if (options instanceof ImageTransformationOptions) {
|
|
||||||
ImageTransformationOptions imageOptions = (ImageTransformationOptions)options;
|
|
||||||
ImageResizeOptions resizeOptions = imageOptions.getResizeOptions();
|
|
||||||
String commandOptions = imageOptions.getCommandOptions();
|
|
||||||
if (commandOptions == null)
|
|
||||||
{
|
|
||||||
commandOptions = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(resizeOptions.getHeight() > -1){
|
|
||||||
commandOptions += " --height=" + resizeOptions.getHeight();
|
|
||||||
}
|
|
||||||
if(resizeOptions.getWidth() > -1){
|
|
||||||
commandOptions += " --width=" + resizeOptions.getHeight();
|
|
||||||
}
|
|
||||||
if(resizeOptions.getAllowEnlargement()){
|
|
||||||
commandOptions += " --allow-enlargement";
|
|
||||||
}
|
|
||||||
if(resizeOptions.isMaintainAspectRatio()){
|
|
||||||
commandOptions += " --maintain-aspect-ratio";
|
|
||||||
}
|
|
||||||
commandOptions += " --page="+ getSourcePageRange(imageOptions, sourceMimetype, targetMimetype);
|
|
||||||
|
|
||||||
properties.put(KEY_OPTIONS, commandOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.put(VAR_SOURCE,
|
|
||||||
sourceFile.getAbsolutePath());
|
|
||||||
properties.put(VAR_TARGET, targetFile.getAbsolutePath());
|
|
||||||
|
|
||||||
// execute the statement
|
|
||||||
long timeoutMs = options.getTimeoutMs();
|
|
||||||
RuntimeExec.ExecutionResult result = executer.execute(properties, timeoutMs);
|
|
||||||
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0) {
|
|
||||||
throw new ContentIOException("Failed to perform Pdfium transformation: \n" + result);
|
|
||||||
}
|
|
||||||
// success
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Pdfium executed successfully: \n" + executer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getComments(boolean available) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("# Supports transformations between mimetypes");
|
|
||||||
sb.append("# pdf or ai to png.\n");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether or not a single page range is required for the given
|
|
||||||
* source and target mimetypes.
|
|
||||||
*
|
|
||||||
* @param sourceMimetype
|
|
||||||
* @param targetMimetype
|
|
||||||
* @return whether or not a page range must be specified for the transformer
|
|
||||||
* to read the target files
|
|
||||||
*/
|
|
||||||
private boolean isSingleSourcePageRangeRequired(String sourceMimetype, String targetMimetype) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the page range from the source to use in the command line.
|
|
||||||
*
|
|
||||||
* @param options
|
|
||||||
* the transformation options
|
|
||||||
* @param sourceMimetype
|
|
||||||
* the source mimetype
|
|
||||||
* @param targetMimetype
|
|
||||||
* the target mimetype
|
|
||||||
* @return the source page range for the command line
|
|
||||||
*/
|
|
||||||
private String getSourcePageRange(TransformationOptions options, String sourceMimetype, String targetMimetype) {
|
|
||||||
if (options instanceof ImageTransformationOptions) {
|
|
||||||
ImageTransformationOptions imageOptions = (ImageTransformationOptions) options;
|
|
||||||
PagedSourceOptions pagedSourceOptions = imageOptions.getSourceOptions(PagedSourceOptions.class);
|
|
||||||
if (pagedSourceOptions != null) {
|
|
||||||
if (pagedSourceOptions.getStartPageNumber() != null && pagedSourceOptions.getEndPageNumber() != null) {
|
|
||||||
if (pagedSourceOptions.getStartPageNumber().equals(pagedSourceOptions.getEndPageNumber())) {
|
|
||||||
return "" + (pagedSourceOptions.getStartPageNumber() - 1) ;
|
|
||||||
} else {
|
|
||||||
if (isSingleSourcePageRangeRequired(sourceMimetype, targetMimetype)) {
|
|
||||||
throw new AlfrescoRuntimeException(
|
|
||||||
"A single page is required for targets of type " + targetMimetype);
|
|
||||||
}
|
|
||||||
return "" + (pagedSourceOptions.getStartPageNumber() - 1) + "-"
|
|
||||||
+ (pagedSourceOptions.getEndPageNumber() - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO specified start to end of doc and start of doc to
|
|
||||||
// specified end not yet supported
|
|
||||||
// Just grab a single page specified by either start or end
|
|
||||||
if (pagedSourceOptions.getStartPageNumber() != null)
|
|
||||||
return "" + (pagedSourceOptions.getStartPageNumber() - 1) ;
|
|
||||||
if (pagedSourceOptions.getEndPageNumber() != null)
|
|
||||||
return "" + (pagedSourceOptions.getEndPageNumber() - 1) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.getPageLimit() == 1 || isSingleSourcePageRangeRequired(sourceMimetype, targetMimetype)) {
|
|
||||||
return "0";
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Repository
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.repo.content.transform.pdfrenderer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.repo.content.MimetypeMap;
|
||||||
|
import org.alfresco.repo.content.transform.ContentTransformerHelper;
|
||||||
|
import org.alfresco.repo.content.transform.ContentTransformerWorker;
|
||||||
|
import org.alfresco.repo.content.transform.magick.ImageResizeOptions;
|
||||||
|
import org.alfresco.repo.content.transform.magick.ImageTransformationOptions;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentReader;
|
||||||
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||||
|
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||||
|
import org.alfresco.service.cmr.repository.PagedSourceOptions;
|
||||||
|
import org.alfresco.service.cmr.repository.TransformationOptions;
|
||||||
|
import org.alfresco.util.PropertyCheck;
|
||||||
|
import org.alfresco.util.TempFileProvider;
|
||||||
|
import org.alfresco.util.exec.RuntimeExec;
|
||||||
|
import org.alfresco.util.exec.RuntimeExec.ExecutionResult;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
public class AlfrescoPdfRendererContentTransformerWorker extends ContentTransformerHelper implements ContentTransformerWorker, InitializingBean
|
||||||
|
{
|
||||||
|
|
||||||
|
/** options variable name */
|
||||||
|
private static final String KEY_OPTIONS = "options";
|
||||||
|
/** source variable name */
|
||||||
|
private static final String VAR_SOURCE = "source";
|
||||||
|
/** target variable name */
|
||||||
|
private static final String VAR_TARGET = "target";
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AlfrescoPdfRendererContentTransformerWorker.class);
|
||||||
|
|
||||||
|
/** the system command executer */
|
||||||
|
private RuntimeExec executer;
|
||||||
|
|
||||||
|
/** the check command executer */
|
||||||
|
private RuntimeExec checkCommand;
|
||||||
|
|
||||||
|
/** the output from the check command */
|
||||||
|
private String versionString;
|
||||||
|
|
||||||
|
private boolean available;
|
||||||
|
|
||||||
|
public AlfrescoPdfRendererContentTransformerWorker()
|
||||||
|
{
|
||||||
|
this.available = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the runtime command executer that must be executed in order to run <b>alfresco-pdf-renderer</b>. Whether or not this is
|
||||||
|
* the full path to the command or just the command itself depends the environment setup.
|
||||||
|
* <p>
|
||||||
|
* The command must contain the variables <code>${source}</code> and <code>${target}</code>, which will be replaced
|
||||||
|
* by the names of the file to be transformed and the name of the output file respectively.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* alfresco-pdf-renderer ${source} ${target}
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param executer the system command executer
|
||||||
|
*/
|
||||||
|
public void setExecuter(RuntimeExec executer)
|
||||||
|
{
|
||||||
|
this.executer = executer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the command that must be executed in order to retrieve version information from the executable
|
||||||
|
* and thus test that the executable itself is present.
|
||||||
|
*
|
||||||
|
* @param checkCommand
|
||||||
|
* command executer to retrieve version information
|
||||||
|
*/
|
||||||
|
public void setCheckCommand(RuntimeExec checkCommand)
|
||||||
|
{
|
||||||
|
this.checkCommand = checkCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception
|
||||||
|
{
|
||||||
|
PropertyCheck.mandatory(this, "executer", executer);
|
||||||
|
PropertyCheck.mandatory(this, "checkCommand", checkCommand);
|
||||||
|
// check availability
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ExecutionResult result = this.checkCommand.execute();
|
||||||
|
if(result.getSuccess())
|
||||||
|
{
|
||||||
|
this.versionString = result.getStdOut().trim();
|
||||||
|
setAvailable(true);
|
||||||
|
logger.info("Using PDF Renderer: "+this.versionString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setAvailable(false);
|
||||||
|
logger.error("Alfresco-PDF-Renderer is not available for transformations.\n"+result.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
setAvailable(false);
|
||||||
|
logger.error(getClass().getSimpleName() + " not available: " + (e.getMessage() != null ? e.getMessage() : ""));
|
||||||
|
// debug so that we can trace the issue if required
|
||||||
|
logger.debug(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns true if the transformer is functioning otherwise false
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable()
|
||||||
|
{
|
||||||
|
return available;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the transformer available
|
||||||
|
*
|
||||||
|
* @param available boolean
|
||||||
|
*/
|
||||||
|
protected void setAvailable(boolean available)
|
||||||
|
{
|
||||||
|
this.available = available;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersionString()
|
||||||
|
{
|
||||||
|
return this.versionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTransformable(String sourceMimetype, String targetMimetype, TransformationOptions options)
|
||||||
|
{
|
||||||
|
if (!available)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add limited support (so lots of other transforms are not supported)
|
||||||
|
// for PDF to PNG.
|
||||||
|
if ((MimetypeMap.MIMETYPE_PDF.equals(sourceMimetype) || MimetypeMap.MIMETYPE_APPLICATION_ILLUSTRATOR.equals(sourceMimetype)) &&
|
||||||
|
MimetypeMap.MIMETYPE_IMAGE_PNG.equals(targetMimetype))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(ContentReader reader, ContentWriter writer, TransformationOptions options) throws Exception
|
||||||
|
{
|
||||||
|
// get mimetypes
|
||||||
|
String sourceMimetype = getMimetype(reader);
|
||||||
|
String targetMimetype = getMimetype(writer);
|
||||||
|
|
||||||
|
// get the extensions to use
|
||||||
|
MimetypeService mimetypeService = getMimetypeService();
|
||||||
|
String sourceExtension = mimetypeService.getExtension(sourceMimetype);
|
||||||
|
String targetExtension = mimetypeService.getExtension(targetMimetype);
|
||||||
|
if (sourceExtension == null || targetExtension == null)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("Unknown extensions for mimetypes: \n" +
|
||||||
|
" source mimetype: " + sourceMimetype + "\n" +
|
||||||
|
" source extension: " + sourceExtension + "\n" +
|
||||||
|
" target mimetype: " + targetMimetype + "\n" +
|
||||||
|
" target extension: " + targetExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create required temp files
|
||||||
|
File sourceFile = TempFileProvider.createTempFile(getClass().getSimpleName() + "_source_", "." + sourceExtension);
|
||||||
|
File targetFile = TempFileProvider.createTempFile(getClass().getSimpleName() + "_target_", "." + targetExtension);
|
||||||
|
|
||||||
|
// pull reader file into source temp file
|
||||||
|
reader.getContent(sourceFile);
|
||||||
|
|
||||||
|
transformInternal(sourceFile, sourceMimetype, targetFile, targetMimetype, options);
|
||||||
|
|
||||||
|
// check that the file was created
|
||||||
|
if (!targetFile.exists() || targetFile.length() == 0)
|
||||||
|
{
|
||||||
|
throw new ContentIOException("alfresco-pdf-renderer transformation failed to write output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// upload the output image
|
||||||
|
writer.putContent(targetFile);
|
||||||
|
|
||||||
|
// done
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Transformation completed: \n" +
|
||||||
|
" source: " + reader + "\n" +
|
||||||
|
" target: " + writer + "\n" +
|
||||||
|
" options: " + options);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the pdf content from the source file to the target file
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void transformInternal(File sourceFile, String sourceMimetype, File targetFile, String targetMimetype, TransformationOptions options) throws Exception
|
||||||
|
{
|
||||||
|
Map<String, String> properties = new HashMap<String, String>(5);
|
||||||
|
// set properties
|
||||||
|
if (options instanceof ImageTransformationOptions)
|
||||||
|
{
|
||||||
|
ImageTransformationOptions imageOptions = (ImageTransformationOptions) options;
|
||||||
|
ImageResizeOptions resizeOptions = imageOptions.getResizeOptions();
|
||||||
|
String commandOptions = imageOptions.getCommandOptions();
|
||||||
|
if (commandOptions == null)
|
||||||
|
{
|
||||||
|
commandOptions = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizeOptions.getHeight() > -1)
|
||||||
|
{
|
||||||
|
commandOptions += " --height=" + resizeOptions.getHeight();
|
||||||
|
}
|
||||||
|
if (resizeOptions.getWidth() > -1)
|
||||||
|
{
|
||||||
|
commandOptions += " --width=" + resizeOptions.getHeight();
|
||||||
|
}
|
||||||
|
if (resizeOptions.getAllowEnlargement())
|
||||||
|
{
|
||||||
|
commandOptions += " --allow-enlargement";
|
||||||
|
}
|
||||||
|
if (resizeOptions.isMaintainAspectRatio())
|
||||||
|
{
|
||||||
|
commandOptions += " --maintain-aspect-ratio";
|
||||||
|
}
|
||||||
|
commandOptions += " --page=" + getSourcePageRange(imageOptions, sourceMimetype, targetMimetype);
|
||||||
|
|
||||||
|
properties.put(KEY_OPTIONS, commandOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(VAR_SOURCE, sourceFile.getAbsolutePath());
|
||||||
|
properties.put(VAR_TARGET, targetFile.getAbsolutePath());
|
||||||
|
|
||||||
|
// execute the statement
|
||||||
|
long timeoutMs = options.getTimeoutMs();
|
||||||
|
RuntimeExec.ExecutionResult result = executer.execute(properties, timeoutMs);
|
||||||
|
if (result.getExitValue() != 0 && result.getStdErr() != null && result.getStdErr().length() > 0)
|
||||||
|
{
|
||||||
|
throw new ContentIOException("Failed to perform alfresco-pdf-renderer transformation: \n" + result);
|
||||||
|
}
|
||||||
|
// success
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("alfresco-pdf-renderer executed successfully: \n" + executer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getComments(boolean available)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("# Supports transformations between mimetypes");
|
||||||
|
sb.append("# pdf or ai to png.\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the page range from the source to use in the command line.
|
||||||
|
*
|
||||||
|
* @param options the transformation options
|
||||||
|
* @param sourceMimetype the source mimetype
|
||||||
|
* @param targetMimetype the target mimetype
|
||||||
|
* @return the source page range for the command line
|
||||||
|
*/
|
||||||
|
private String getSourcePageRange(TransformationOptions options, String sourceMimetype, String targetMimetype)
|
||||||
|
{
|
||||||
|
if (options instanceof ImageTransformationOptions)
|
||||||
|
{
|
||||||
|
ImageTransformationOptions imageOptions = (ImageTransformationOptions) options;
|
||||||
|
PagedSourceOptions pagedSourceOptions = imageOptions.getSourceOptions(PagedSourceOptions.class);
|
||||||
|
if (pagedSourceOptions != null)
|
||||||
|
{
|
||||||
|
if (pagedSourceOptions.getStartPageNumber() != null && pagedSourceOptions.getEndPageNumber() != null)
|
||||||
|
{
|
||||||
|
if (pagedSourceOptions.getStartPageNumber().equals(pagedSourceOptions.getEndPageNumber()))
|
||||||
|
{
|
||||||
|
return "" + (pagedSourceOptions.getStartPageNumber() - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("The alfresco-pdf-renderer can only convert single pages, no page ranges.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("The alfresco-pdf-renderer can only convert single pages, no page ranges.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user