[Q&A Friday] How to get thumbnails for PDF or PSD documents?


Fri 01 June 2012 By Laurent Doguin


How to get thumbnails from PDF How to get thumbnails from PDF

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:

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

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

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:

[java]
myDocumentModel.addFacet("Thumbnail");
[/java]

Then you can simply do:

[java]
doc.setPropertyValue("thumbnail:content", (Serializable) myThumbnailBlob);
[/java]

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.

[xml]
<extension target="org.nuxeo.ecm.platform.commandline.executor.service.CommandLineExecutorComponent"
point="command">
<command name="toThumbnail" enabled="true">
<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>
</command>
</extension>
[/xml]

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

[java]
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&lt;String, Serializable&gt; parameters) throws ConversionException {
     try {
         // Make sure the toThumbnail command is available
         CommandLineExecutorService cles = Framework
                 .getLocalService(CommandLineExecutorService.class);
         CommandAvailability commandAvailability = cles
                 .getCommandAvailability(&quot;toThumbnail&quot;);
         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(&quot;nuxeoImageTarget&quot;, &quot;.&quot;
                 + &quot;png&quot;);
         params.addNamedParameter(&quot;inputFilePath&quot;, inputFile);
         params.addNamedParameter(&quot;outputFilePath&quot;, outputFile);
    
         ExecResult res = cles.execCommand(&quot;toThumbnail&quot;, 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(&quot;Thumbnail conversion has failed&quot;, e);
     }
    

    }

    @Override
    public void init(ConverterDescriptor descriptor) {
    }
    }
    [/java]

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

[xml]
<extension target="org.nuxeo.ecm.core.convert.service.ConversionServiceImpl"
point="converter">
<converter name="toThumbnail" class="org.nuxeo.thumb.ThumbnailConverter">
</converter>
</extension>
[/xml]

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!


Category: Product & Development
Tagged: Java, Q&A