Nuxeo Server

Thumbnail

Updated: October 13, 2017 Page Information Edit on GitHub

Documents can have a thumbnail. A thumbnail is a reduced-size version of a picture used to help in recognizing and organizing documents. It will stand for any kind of document according to the type and/or facet.

Custom thumbnail factories can be contributed to the thumbnail service, using its extension point. Thumbnails are then available through this service to define how they will be computed and fetched.

Thumbnail Service Architecture

Here are the different components of the thumbnail feature:

Thumbnail factory on GitHub

Here are Nuxeo thumbnail factory implementations on GitHub:

Registering a New Thumbnail Factory

A thumbnail factory can be registered using the following example extension:

<extension target="org.nuxeo.ecm.core.api.thumbnail.ThumbnailService"
  point="thumbnailFactory">

  <thumbnailFactory name="thumbnailAudioFactory" docType="Audio"
    factoryClass="org.nuxeo.ecm.platform.audio.extension.ThumbnailAudioFactory" />
</extension>

The above thumbnail factories will be used to compute and fetch specific thumbnails for folderish documents on one hand, and audio documents on the other hand. Here are their properties:

  • docType: string identifying the related document type. In the example, the type is "Audio".
  • facet: string identifying the related document facet. In the example, the facet is "Folderish".
  • factoryClass: string representing the class name of the factory to use.

Each factory should implement the interface ThumbnailFactory . This interface contract contains two methods to implement:

  • Blob getThumbnail(DocumentModel doc, CoreSession session): gets the document thumbnail (related to the doc type/facet).
  • Blob computeThumbnail(DocumentModel doc, CoreSession session): computes the thumbnail (related to the document type/facet).

The listener UpdateThumbnailListener is calling YourFactory#computeThumbnail that allows developers to compute the document blob when creating a document and after updating it (if the blob related to this document has been changed).

When computing your thumbnail, UpdateThumbnailListener stores it into a specific metadata thumb:thumbnail provided by the following schema:

<xs:schema xmlns:nxs="http://www.nuxeo.org/ecm/schemas/thumbnail"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.nuxeo.org/ecm/schemas/thumbnail">

  <xs:include schemaLocation="core-types.xsd" />

  <xs:element name="thumbnail" type="nxs:content" />

</xs:schema>

This process can be useful to avoid lazy loading when displaying documents list.

Picture Thumbnail Example

Here is an example with the picture thumbnail factory, which is fetching a image existing into the picture schema.

import org.nuxeo.common.utils.FileUtils;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
import org.nuxeo.ecm.platform.picture.api.PictureView;
import org.nuxeo.ecm.platform.picture.api.adapters.MultiviewPicture;
import org.nuxeo.ecm.platform.types.adapter.TypeInfo;

public class ThumbnailPictureFactory implements ThumbnailFactory {
    @Override
    public Blob getThumbnail(DocumentModel doc, CoreSession session)
            throws ClientException {
        if (!doc.hasFacet("Picture")) {
            throw new ClientException("Document is not a picture");
        }
        // Choose the nuxeo default thumbnail of the picture views if exists
        MultiviewPicture mViewPicture = doc.getAdapter(MultiviewPicture.class);
        PictureView thumbnailView = mViewPicture.getView("Small");
        if (thumbnailView == null || thumbnailView.getBlob() == null) {
            // try thumbnail view
            thumbnailView = mViewPicture.getView("Thumbnail");
            if (thumbnailView == null || thumbnailView.getBlob() == null) {
                TypeInfo docType = doc.getAdapter(TypeInfo.class);
                return new FileBlob(
                        FileUtils.getResourceFileFromContext("nuxeo.war"
                                + File.separator + docType.getBigIcon()));
            }
        }
        return thumbnailView.getBlob();
    }
    @Override
    public Blob computeThumbnail(DocumentModel doc, CoreSession session) {
        return null;
    }
}

And then the usage of ThumbnailAdapter:

import org.nuxeo.common.utils.FileUtils;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
import org.nuxeo.ecm.core.api.impl.blob.FileBlob;
import org.nuxeo.ecm.core.api.thumbnail.ThumbnailAdapter;
import org.nuxeo.ecm.core.api.CoreSession;
import com.google.inject.Inject;

@Inject
CoreSession session;

// Create a picture
DocumentModel root = session.getRootDocument();
DocumentModel picture = new DocumentModelImpl(root.getPathAsString(),"pic", "Picture");
picture.setPropertyValue("picture:views", (Serializable) createViews());
picture = session.createDocument(picture);
session.save();

// Using BlobHolder adapter
BlobHolder bh = picture.getAdapter(BlobHolder.class);
Blob blob = new FileBlob(getFileFromPath("test-data/big_nuxeo_logo.gif"), "image/gif",null, "big_nuxeo_logo.gif", null);
bh.setBlob(blob);
session.saveDocument(picture);
session.save();

// Using ThumbnailAdapter
ThumbnailAdapter pictureThumbnail = picture.getAdapter(ThumbnailAdapter.class);
Blob thumbnail = pictureThumbnail.getThumbnail(session);
String fileName = thumbnail.getFilename();

Default Nuxeo thumbnail factories fall back on Nuxeo Document BigIcon if no thumbnail has been found.

Here is a way to find it properly:

Blob getDefaultThumbnail(DocumentModel doc) {
    if (doc == null) {
        return null;
    }
    TypeInfo docType = doc.getAdapter(TypeInfo.class);
    String iconPath = docType.getBigIcon();
    if (iconPath == null) {
        iconPath = docType.getIcon();
    }
    if (iconPath == null) {
        return null;
    }
    FacesContext ctx = FacesContext.getCurrentInstance();
    if (ctx == null) {
        return null;
    }
    try {
        InputStream iconStream = ctx.getExternalContext().getResourceAsStream(
                iconPath);
        if (iconStream != null) {
            return new FileBlob(iconStream);
        }
    } catch (IOException e) {
        log.warn(String.format(
                "Could not fetch the thumbnail blob from icon path '%s'",
                iconPath), e);
    }
    return null;
}

Thumbnail Architecture

Here, we can see the ThumbnailAdapter to use and factories like the default one ThumbnailDocumentFactory and ThumbnailPictureFactory:

9 days ago manonlumeau NXDOC-1346-FT review screenshot
a year ago Manon Lumeau 35
a year ago Manon Lumeau 34
2 years ago Manon Lumeau 33 | javadoc links updated
2 years ago Manon Lumeau 32
2 years ago Thomas Roger 31
3 years ago Solen Guitter 30 | Fix links to point to latest version
3 years ago Alain Escaffre 29
4 years ago Vladimir Pasquier 28
4 years ago Solen Guitter 27 | Updated javadoc links to 5.8 release
4 years ago Solen Guitter 26
4 years ago Solen Guitter 25
4 years ago Vladimir Pasquier 24
4 years ago Solen Guitter 23 | Fixed format
4 years ago Vladimir Pasquier 22
4 years ago Vladimir Pasquier 21
4 years ago Vladimir Pasquier 20
4 years ago Vladimir Pasquier 18
4 years ago Vladimir Pasquier 19
4 years ago Vladimir Pasquier 17
4 years ago Vladimir Pasquier 16
4 years ago Vladimir Pasquier 15
4 years ago Vladimir Pasquier 14
4 years ago Vladimir Pasquier 13
4 years ago Vladimir Pasquier 12
4 years ago Vladimir Pasquier 11
4 years ago Vladimir Pasquier 8
4 years ago Vladimir Pasquier 9
4 years ago Vladimir Pasquier 10
4 years ago Vladimir Pasquier 6
4 years ago Vladimir Pasquier 7
4 years ago Vladimir Pasquier 5
4 years ago Vladimir Pasquier 4
4 years ago Vladimir Pasquier 3
4 years ago Vladimir Pasquier 2
4 years ago Vladimir Pasquier 1
History: Created by Vladimir Pasquier