diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml
index b32565a02c..8ebab92bc2 100644
--- a/config/alfresco/content-services-context.xml
+++ b/config/alfresco/content-services-context.xml
@@ -66,6 +66,9 @@
+
+
+
diff --git a/config/alfresco/mimetype/openoffice-document-formats.xml b/config/alfresco/mimetype/openoffice-document-formats.xml
index 62a0040d75..1c18b17845 100644
--- a/config/alfresco/mimetype/openoffice-document-formats.xml
+++ b/config/alfresco/mimetype/openoffice-document-formats.xml
@@ -7,7 +7,7 @@
application/pdf
pdf
- Presentationimpress_pdf_Export
+ Presentationimpress_pdf_Export
Spreadsheetcalc_pdf_Export
Textwriter_pdf_Export
@@ -30,7 +30,7 @@
text/html
html
- Presentationimpress_html_Export
+ Presentationimpress_html_Export
SpreadsheetHTML (StarCalc)
TextHTML (StarWriter)
diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml
index f3980481d6..19037c2f82 100644
--- a/config/alfresco/public-services-security-context.xml
+++ b/config/alfresco/public-services-security-context.xml
@@ -405,6 +405,7 @@
org.alfresco.service.cmr.repository.ContentService.getWriter=ACL_NODE.0.sys:base.WriteContent
org.alfresco.service.cmr.repository.ContentService.isTransformable=ACL_ALLOW
org.alfresco.service.cmr.repository.ContentService.getTransformer=ACL_ALLOW
+ org.alfresco.service.cmr.repository.ContentService.getImageTransformer=ACL_ALLOW
org.alfresco.service.cmr.repository.ContentService.transform=ACL_ALLOW
org.alfresco.service.cmr.repository.ContentService.getTempWriter=ACL_ALLOW
diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
index 4ddf81e03d..89c040ca15 100644
--- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java
@@ -169,7 +169,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
// Calculate the destination name
String originalName = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_NAME);
- String newName = transformName(originalName, mimeType);
+ String newName = transformName(this.mimetypeService, originalName, mimeType);
// Since we are overwriting we need to figure out whether the destination node exists
NodeRef copyNodeRef = null;
@@ -225,7 +225,7 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
String originalTitle = (String)nodeService.getProperty(actionedUponNodeRef, ContentModel.PROP_TITLE);
if (originalTitle != null && originalTitle.length() > 0)
{
- String newTitle = transformName(originalTitle, mimeType);
+ String newTitle = transformName(this.mimetypeService, originalTitle, mimeType);
nodeService.setProperty(copyNodeRef, ContentModel.PROP_TITLE, newTitle);
}
}
@@ -267,11 +267,11 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase
* Transform name from original extension to new extension
*
* @param original
- * @param originalMimetype
* @param newMimetype
- * @return
+ *
+ * @return name with new extension as appropriate for the mimetype
*/
- private String transformName(String original, String newMimetype)
+ public static String transformName(MimetypeService mimetypeService, String original, String newMimetype)
{
// get the current extension
int dotIndex = original.lastIndexOf('.');
diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java
index f97376ea5d..7c9fb8261b 100644
--- a/source/java/org/alfresco/repo/content/RoutingContentService.java
+++ b/source/java/org/alfresco/repo/content/RoutingContentService.java
@@ -28,6 +28,7 @@ import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy;
import org.alfresco.repo.content.filestore.FileContentStore;
import org.alfresco.repo.content.transform.ContentTransformer;
import org.alfresco.repo.content.transform.ContentTransformerRegistry;
+import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer;
import org.alfresco.repo.policy.ClassPolicyDelegate;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
@@ -72,6 +73,7 @@ public class RoutingContentService implements ContentService
private ContentStore store;
/** the store for all temporarily created content */
private ContentStore tempStore;
+ private ImageMagickContentTransformer imageMagickContentTransformer;
/**
* The policy component
@@ -122,6 +124,11 @@ public class RoutingContentService implements ContentService
this.policyComponent = policyComponent;
}
+ public void setImageMagickContentTransformer(ImageMagickContentTransformer imageMagickContentTransformer)
+ {
+ this.imageMagickContentTransformer = imageMagickContentTransformer;
+ }
+
/**
* Service initialise
*/
@@ -385,6 +392,14 @@ public class RoutingContentService implements ContentService
return transformer;
}
+ /**
+ * @see org.alfresco.service.cmr.repository.ContentService#getImageTransformer()
+ */
+ public ContentTransformer getImageTransformer()
+ {
+ return imageMagickContentTransformer;
+ }
+
/**
* @see org.alfresco.repo.content.transform.ContentTransformerRegistry
* @see org.alfresco.repo.content.transform.ContentTransformer
diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java
index edc57e7750..5644a16d51 100644
--- a/source/java/org/alfresco/repo/jscript/Node.java
+++ b/source/java/org/alfresco/repo/jscript/Node.java
@@ -30,6 +30,8 @@ import java.util.StringTokenizer;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.action.executer.TransformActionExecuter;
+import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.version.VersionModel;
import org.alfresco.service.ServiceRegistry;
@@ -45,6 +47,7 @@ import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
+import org.alfresco.service.cmr.repository.NoTransformerException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
@@ -1420,6 +1423,196 @@ public final class Node implements Serializable, Scopeable
}
+ // ------------------------------------------------------------------------------
+ // Transformation and Rendering API
+
+ /**
+ * Transform a document to a new document mimetype format. A copy of the document is made and
+ * the extension changed to match the new mimetype, then the transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ *
+ * @return Node representing the newly transformed document.
+ */
+ public Node transformDocument(String mimetype)
+ {
+ return transformDocument(mimetype, getPrimaryParentAssoc().getParentRef());
+ }
+
+ /**
+ * Transform a document to a new document mimetype format. A copy of the document is made in the
+ * specified destination folder and the extension changed to match the new mimetype, then then
+ * transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ * @param destination Destination folder location
+ *
+ * @return Node representing the newly transformed document.
+ */
+ public Node transformDocument(String mimetype, Node destination)
+ {
+ return transformDocument(mimetype, destination.getNodeRef());
+ }
+
+ private Node transformDocument(String mimetype, NodeRef destination)
+ {
+ // the delegate definition for transforming a document
+ Transformer transformer = new Transformer()
+ {
+ public Node transform(ContentService contentService, NodeRef nodeRef, ContentReader reader, ContentWriter writer)
+ {
+ Node transformedNode = null;
+ if (contentService.isTransformable(reader, writer))
+ {
+ try
+ {
+ contentService.transform(reader, writer);
+ transformedNode = new Node(nodeRef, services, imageResolver, scope);
+ }
+ catch (NoTransformerException err)
+ {
+ // failed to find a useful transformer - do not return a node instance
+ }
+ }
+ return transformedNode;
+ }
+ };
+
+ return transformNode(transformer, mimetype, destination);
+ }
+
+ /**
+ * Generic method to transform Node content from one mimetype to another.
+ *
+ * @param transformer The Transformer delegate supplying the transformation logic
+ * @param mimetype Mimetype of the destination content
+ * @param destination Destination folder location for the resulting document
+ *
+ * @return Node representing the transformed content - or null if the transform failed
+ */
+ private Node transformNode(Transformer transformer, String mimetype, NodeRef destination)
+ {
+ Node transformedNode = null;
+
+ // get the content reader
+ ContentService contentService = this.services.getContentService();
+ ContentReader reader = contentService.getReader(this.nodeRef, ContentModel.PROP_CONTENT);
+
+ // only perform the transformation if some content is available
+ if (reader != null)
+ {
+ // Copy the content node to a new node
+ NodeRef copyNodeRef = this.services.getCopyService().copy(
+ this.nodeRef,
+ destination,
+ ContentModel.ASSOC_CONTAINS,
+ getPrimaryParentAssoc().getQName(),
+ false);
+
+ // modify the name of the copy to reflect the new mimetype
+ this.nodeService.setProperty(
+ copyNodeRef,
+ ContentModel.PROP_NAME,
+ TransformActionExecuter.transformName(
+ this.services.getMimetypeService(), getName(), mimetype));
+
+ // get the writer and set it up
+ ContentWriter writer = contentService.getWriter(copyNodeRef, ContentModel.PROP_CONTENT, true);
+ writer.setMimetype(mimetype); // new mimetype
+ writer.setEncoding(reader.getEncoding()); // original encoding
+
+ // Try and transform the content using the supplied delegate
+ transformedNode = transformer.transform(contentService, copyNodeRef, reader, writer);
+ }
+
+ return transformedNode;
+ }
+
+ /**
+ * Transform an image to a new image format. A copy of the image document is made and
+ * the extension changed to match the new mimetype, then the transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ *
+ * @return Node representing the newly transformed image.
+ */
+ public Node transformImage(String mimetype)
+ {
+ return transformImage(mimetype, null, getPrimaryParentAssoc().getParentRef());
+ }
+
+ /**
+ * Transform an image to a new image format. A copy of the image document is made and
+ * the extension changed to match the new mimetype, then the transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ * @param options Image convert command options
+ *
+ * @return Node representing the newly transformed image.
+ */
+ public Node transformImage(String mimetype, String options)
+ {
+ return transformImage(mimetype, options, getPrimaryParentAssoc().getParentRef());
+ }
+
+ /**
+ * Transform an image to a new image mimetype format. A copy of the image document is made in the
+ * specified destination folder and the extension changed to match the new mimetype, then then
+ * transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ * @param destination Destination folder location
+ *
+ * @return Node representing the newly transformed image.
+ */
+ public Node transformImage(String mimetype, Node destination)
+ {
+ return transformImage(mimetype, null, destination.getNodeRef());
+ }
+
+ /**
+ * Transform an image to a new image mimetype format. A copy of the image document is made in the
+ * specified destination folder and the extension changed to match the new mimetype, then then
+ * transformation is applied.
+ *
+ * @param mimetype Mimetype destination for the transformation
+ * @param options Image convert command options
+ * @param destination Destination folder location
+ *
+ * @return Node representing the newly transformed image.
+ */
+ public Node transformImage(String mimetype, String options, Node destination)
+ {
+ return transformImage(mimetype, options, destination.getNodeRef());
+ }
+
+ private Node transformImage(String mimetype, final String options, NodeRef destination)
+ {
+ // the delegate definition for transforming an image
+ Transformer transformer = new Transformer()
+ {
+ public Node transform(ContentService contentService, NodeRef nodeRef, ContentReader reader, ContentWriter writer)
+ {
+ Node transformedNode = null;
+ try
+ {
+ Map opts = new HashMap(1);
+ opts.put(ImageMagickContentTransformer.KEY_OPTIONS, options != null ? options : "");
+ contentService.getImageTransformer().transform(reader, writer, opts);
+ transformedNode = new Node(nodeRef, services, imageResolver, scope);
+ }
+ catch (NoTransformerException err)
+ {
+ // failed to find a useful transformer - do not return a node instance
+ }
+ return transformedNode;
+ }
+ };
+
+ return transformNode(transformer, mimetype, destination);
+ }
+
+
// ------------------------------------------------------------------------------
// Helper methods
@@ -1647,4 +1840,23 @@ public final class Node implements Serializable, Scopeable
private ContentData contentData;
private QName property;
}
+
+
+ /**
+ * Interface contract for simple anonymous classes that implement document transformations
+ */
+ private interface Transformer
+ {
+ /**
+ * Transform the reader to the specified writer
+ *
+ * @param contentService ContentService
+ * @param noderef NodeRef of the destination for the transform
+ * @param reader Source reader
+ * @param writer Destination writer
+ *
+ * @return Node representing the transformed entity
+ */
+ Node transform(ContentService contentService, NodeRef noderef, ContentReader reader, ContentWriter writer);
+ }
}
\ No newline at end of file
diff --git a/source/java/org/alfresco/service/cmr/repository/ContentService.java b/source/java/org/alfresco/service/cmr/repository/ContentService.java
index cbca110d5e..c1c032a6ab 100644
--- a/source/java/org/alfresco/service/cmr/repository/ContentService.java
+++ b/source/java/org/alfresco/service/cmr/repository/ContentService.java
@@ -126,6 +126,14 @@ public interface ContentService
@Auditable(parameters = {"sourceMimetype", "targetMimetype"})
public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype);
+ /**
+ * Fetch the transformer that is capable of transforming image content.
+ *
+ * @return Returns a transformer that can be used, or null if one was not available
+ */
+ @Auditable
+ public ContentTransformer getImageTransformer();
+
/**
* Returns whether a transformer exists that can read the content from
* the reader and write the content back out to the writer.