Hi there!

Here’s a common question about thumbnail preview in Nuxeo from systemz: How to get thumbnails from PDF. This question also applies to other files, like Office or PSD files.

I will mostly need two things for my thumbnail: - somewhere to store it - a way to generate it.

For the storage part I will use Mixins. In the Nuxeo Platform, this is just a facet that can be added to a document at runtime. I can add it to a document when I know I can generate a thumbnail from the document’s BlobHolder.

The definition of the facet is easy:

<extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema"><schema name="thumbnail" src="schemas/thumbnail.xsd" prefix="thumb"></schema></extension>

<extension target="org.nuxeo.ecm.core.schema.TypeService" point="doctype"><facet name="Thumbnail"><schema name="thumbnail"></schema></facet></extension>

Now I have a facet called Thumbnail that adds the thumbnail schema to the document. If you don’t know how to add a facet at runtime, it is quite simple:

myDocumentModel.addFacet("Thumbnail");

Then you can simply do:

doc.setPropertyValue("thumbnail:content", (Serializable) myThumbnailBlob);

And to generate my thumbnail, I will use a very simple converter relying on a mighty ImageMagick command. It creates a png thumbnail of any image or file supported by ImageMagick. It can, for instance, take the first page of a PDF or a PSD file.

<extension target="org.nuxeo.ecm.platform.commandline.executor.service.CommandLineExecutorComponent" point="command"><command name="toThumbnail" enabled="true"></command><commandline>convert</commandline> <parameterstring>-strip -thumbnail 100x100 -background transparent -gravity center -extent 100x100 -format png -quality 75 #{inputFilePath}[0] #{outputFilePath}</parameterstring> <winparameterstring>-strip -thumbnail 100x100 -background transparent -gravity center -extent 100x100 -format png -quality 75 #{inputFilePath}[0] #{outputFilePath}</winparameterstring> <installationdirective>You need to install ImageMagick.</installationdirective></extension>

To call that command, let’s use a Converter. This is a simple class implementing the Converter interface.

package org.nuxeo.thumb;

import java.io.File; import java.io.Serializable; import java.util.Map;

import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.blobholder.BlobHolder; import org.nuxeo.ecm.core.api.impl.blob.FileBlob; import org.nuxeo.ecm.core.convert.api.ConversionException; import org.nuxeo.ecm.core.convert.cache.SimpleCachableBlobHolder; import org.nuxeo.ecm.core.convert.extension.Converter; import org.nuxeo.ecm.core.convert.extension.ConverterDescriptor; import org.nuxeo.ecm.core.storage.sql.coremodel.SQLBlob; import org.nuxeo.ecm.platform.commandline.executor.api.CmdParameters; import org.nuxeo.ecm.platform.commandline.executor.api.CommandAvailability; import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService; import org.nuxeo.ecm.platform.commandline.executor.api.ExecResult; import org.nuxeo.ecm.platform.picture.core.im.IMImageUtils; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.services.streaming.FileSource; import org.nuxeo.runtime.services.streaming.StreamSource;

/** * @author ldoguin */ public class ThumbnailConverter extends IMImageUtils implements Converter {

private static final Log log = LogFactory.getLog(ThumbnailConverter.class);

@Override public BlobHolder convert(BlobHolder blobHolder, Map <string, serializable="">parameters) throws ConversionException { try { // Make sure the toThumbnail command is available CommandLineExecutorService cles = Framework .getLocalService(CommandLineExecutorService.class); CommandAvailability commandAvailability = cles .getCommandAvailability("toThumbnail"); if (!commandAvailability.isAvailable()) { return null; } // get the input and output of the command Blob blob = blobHolder.getBlob(); File inputFile = null; if (blob instanceof FileBlob) { inputFile = ((FileBlob) blob).getFile(); } else if (blob instanceof SQLBlob) { StreamSource source = ((SQLBlob) blob).getBinary() .getStreamSource(); inputFile = ((FileSource) source).getFile(); } if (inputFile == null) { return null; } CmdParameters params = new CmdParameters(); File outputFile = File.createTempFile("nuxeoImageTarget", "." + "png"); params.addNamedParameter("inputFilePath", inputFile); params.addNamedParameter("outputFilePath", outputFile);

ExecResult res = cles.execCommand("toThumbnail", params); if (!res.isSuccessful()) { return null; } Blob targetBlob = new FileBlob(outputFile); Framework.trackFile(outputFile, targetBlob); return new SimpleCachableBlobHolder(targetBlob); } catch (Exception e) { throw new ConversionException("Thumbnail conversion has failed", e); } }

@Override public void init(ConverterDescriptor descriptor) { } }

As usual, you have to register that class to an extension point.


Now I can generate and store the thumbnail. However, some questions remain. When will I generate the thumbnail and add it to the document? Where will I display the brand new thumbnail? What if the main Blob of the document changes? I will try to answer these remaining questions next Monday :-) Stay tuned!</string,>