All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.sequencer.image.ImageMetadataSequencer Maven / Gradle / Ivy

There is a newer version: 5.5.1.fcr
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.modeshape.sequencer.image;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.jcr.Binary;
import javax.jcr.NamespaceRegistry;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import org.modeshape.common.util.CheckArg;
import org.modeshape.common.util.StringUtil;
import org.modeshape.jcr.api.JcrConstants;
import org.modeshape.jcr.api.nodetype.NodeTypeManager;
import org.modeshape.jcr.api.sequencer.Sequencer;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Descriptor;
import com.drew.metadata.exif.ExifIFD0Directory;

/**
 * A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then writes that image
 * metadata to the repository.
 * 

* This sequencer produces data that corresponds to the following structure: *

    *
  • image:metadata node of type image:metadata *
      *
    • jcr:mimeType - optional string property for the mime type of the image
    • *
    • jcr:encoding - optional string property for the encoding of the image
    • *
    • image:formatName - string property for the name of the format
    • *
    • image:width - optional integer property for the image's width in pixels
    • *
    • image:height - optional integer property for the image's height in pixels
    • *
    • image:bitsPerPixel - optional integer property for the number of bits per pixel
    • *
    • image:progressive - optional boolean property specifying whether the image is stored in a progressive * (i.e., interlaced) form
    • *
    • image:numberOfImages - optional integer property for the number of images stored in the file; defaults to * 1
    • *
    • image:physicalWidthDpi - optional integer property for the physical width of the image in dots per inch
    • *
    • image:physicalHeightDpi - optional integer property for the physical height of the image in dots per inch
    • *
    • image:physicalWidthInches - optional double property for the physical width of the image in inches
    • *
    • image:physicalHeightInches - optional double property for the physical height of the image in inches
    • *
    • image:exif - optional child node which contains additional EXIF information (if available)
    • *
        *
      • image:artist
      • *
      • image:copyright
      • *
      • image:datetime
      • *
      • image:description
      • *
      • image:make
      • *
      • image:model
      • *
      • image:unit
      • *
      • image:orientation
      • *
      • image:software
      • *
      • image:resolution_x
      • *
      • image:resolution_y
      • *
      *
    *
  • *
*

*/ public class ImageMetadataSequencer extends Sequencer { private static final int[] EXIF_TAGS = new int[] { ExifIFD0Directory.TAG_ARTIST, ExifIFD0Directory.TAG_COPYRIGHT, ExifIFD0Directory.TAG_DATETIME, ExifIFD0Directory.TAG_IMAGE_DESCRIPTION, ExifIFD0Directory.TAG_MAKE, ExifIFD0Directory.TAG_MODEL, ExifIFD0Directory.TAG_RESOLUTION_UNIT, ExifIFD0Directory.TAG_SOFTWARE, ExifIFD0Directory.TAG_X_RESOLUTION, ExifIFD0Directory.TAG_Y_RESOLUTION, ExifIFD0Directory.TAG_ORIENTATION }; private static final String TIFF_FORMAT = "TIFF"; private static final String[] TIFF_MIME_TYPES = new String[] {"image/tiff", "image/x-tiff", "image/tif", "image/x-tif", "application/tif", "application/x-tif", "application/tiff", "application/x-tiff" }; private static final String IMAGE_TIFF_DEFAULT_MIME_TYPE = TIFF_MIME_TYPES[0]; @Override public boolean execute( Property inputProperty, Node outputNode, Context context ) throws Exception { Binary binaryValue = inputProperty.getBinary(); CheckArg.isNotNull(binaryValue, "binary"); Node imageNode = getImageMetadataNode(outputNode); boolean imageParsedUsingDefaultMetadata = processUsingDefaultMetadata(imageNode, binaryValue); return processUsingAdvancedMetadata(imageNode, binaryValue, imageParsedUsingDefaultMetadata); } private boolean processUsingAdvancedMetadata( Node imageNode, Binary binaryValue, boolean imageParsedUsingDefaultMetadata ) throws Exception { try (InputStream stream = binaryValue.getStream()) { Metadata advancedMetadata = ImageMetadataReader.readMetadata(new BufferedInputStream(stream), false); ExifIFD0Directory exifIFD0Directory = advancedMetadata.getDirectory(ExifIFD0Directory.class); if (exifIFD0Directory == null || !hasTags(exifIFD0Directory, EXIF_TAGS)) { if (!imageParsedUsingDefaultMetadata) { getLogger().info("Neither default nor advanced metadata parser can resolve image. Ignoring sequencing"); } getLogger().debug("No relevant IFD0 information found, ignoring EXIF node."); return imageParsedUsingDefaultMetadata; } if (!imageParsedUsingDefaultMetadata) { //it's a format not supported by the default metadata and since we're reading the IFD0 descriptor, mark the image //as a TIFF getLogger().info( "Image has IFD0 block information but is not one of the standard image types, marking it as TIFF"); imageNode.setProperty(ImageMetadataLexicon.FORMAT_NAME, TIFF_FORMAT); imageNode.setProperty(JcrConstants.JCR_MIME_TYPE, IMAGE_TIFF_DEFAULT_MIME_TYPE); } addEXIFNode(imageNode, exifIFD0Directory); return true; } catch (Exception e) { getLogger().debug(e, "Cannot process image for advanced metadata"); return imageParsedUsingDefaultMetadata; } } private void addEXIFNode( Node imageNode, ExifIFD0Directory exifIFD0Directory ) throws RepositoryException { ExifIFD0Descriptor exifDescriptor = new ExifIFD0Descriptor(exifIFD0Directory); Node exifNode = imageNode.addNode(ImageMetadataLexicon.EXIF_NODE, ImageMetadataLexicon.EXIF_NODE); setStringIfTagPresent(exifNode, ImageMetadataLexicon.ARTIST, exifIFD0Directory, ExifIFD0Directory.TAG_ARTIST); setStringIfTagPresent(exifNode, ImageMetadataLexicon.COPYRIGHT, exifIFD0Directory, ExifIFD0Directory.TAG_COPYRIGHT); setStringIfTagPresent(exifNode, ImageMetadataLexicon.DESCRIPTION, exifIFD0Directory, ExifIFD0Directory.TAG_IMAGE_DESCRIPTION); setStringIfTagPresent(exifNode, ImageMetadataLexicon.MAKE, exifIFD0Directory, ExifIFD0Directory.TAG_MAKE); setStringIfTagPresent(exifNode, ImageMetadataLexicon.MODEL, exifIFD0Directory, ExifIFD0Directory.TAG_MODEL); setStringIfTagPresent(exifNode, ImageMetadataLexicon.SOFTWARE, exifIFD0Directory, ExifIFD0Directory.TAG_SOFTWARE); setStringIfTagPresent(exifNode, ImageMetadataLexicon.DATETIME, exifIFD0Directory, ExifIFD0Directory.TAG_DATETIME); setStringIfNotBlank(exifNode, ImageMetadataLexicon.UNIT, exifDescriptor.getResolutionDescription()); setStringIfNotBlank(exifNode, ImageMetadataLexicon.ORIENTATION, exifDescriptor.getOrientationDescription()); setDoubleIfTagPresent(exifNode, ImageMetadataLexicon.RESOLUTION_X, exifIFD0Directory, ExifIFD0Directory.TAG_X_RESOLUTION); setDoubleIfTagPresent(exifNode, ImageMetadataLexicon.RESOLUTION_Y, exifIFD0Directory, ExifIFD0Directory.TAG_Y_RESOLUTION); } private void setStringIfTagPresent(Node node, String propertyName, Directory directory, int tag) throws RepositoryException { setStringIfNotBlank(node, propertyName, directory.getString(tag)); } private void setStringIfNotBlank( Node node, String propertyName, String value ) throws RepositoryException { if (!StringUtil.isBlank(value)) { node.setProperty(propertyName, value); } } private void setDoubleIfTagPresent( Node node, String propertyName, Directory directory, int tag ) throws RepositoryException { if (!directory.containsTag(tag)) { return; } node.setProperty(propertyName, directory.getRational(tag).doubleValue()); } private boolean hasTags(Directory directory, int... tags) { for (int tag : tags) { if (directory.containsTag(tag)) { return true; } } return false; } private boolean processUsingDefaultMetadata( Node imageNode, Binary binaryValue ) throws Exception { InputStream stream = binaryValue.getStream(); try { ImageMetadata metadata = new ImageMetadata(); metadata.setInput(stream); metadata.setDetermineImageNumber(true); metadata.setCollectComments(true); // Process the image stream and extract the metadata ... if (!metadata.check()) { getLogger().debug("Unknown format detected using default metadata parser."); return false; } setImagePropertiesOnNode(imageNode, metadata); return true; } finally { stream.close(); } } private Node getImageMetadataNode( Node outputNode ) throws RepositoryException { if (outputNode.isNew()) { outputNode.setPrimaryType(ImageMetadataLexicon.METADATA_NODE); return outputNode; } return outputNode.addNode(ImageMetadataLexicon.METADATA_NODE, ImageMetadataLexicon.METADATA_NODE); } private void setImagePropertiesOnNode( Node node, ImageMetadata metadata ) throws Exception { node.setProperty(JcrConstants.JCR_MIME_TYPE, metadata.getMimeType()); node.setProperty(ImageMetadataLexicon.FORMAT_NAME, metadata.getFormatName()); node.setProperty(ImageMetadataLexicon.WIDTH, metadata.getWidth()); node.setProperty(ImageMetadataLexicon.HEIGHT, metadata.getHeight()); node.setProperty(ImageMetadataLexicon.BITS_PER_PIXEL, metadata.getBitsPerPixel()); node.setProperty(ImageMetadataLexicon.PROGRESSIVE, metadata.isProgressive()); node.setProperty(ImageMetadataLexicon.NUMBER_OF_IMAGES, metadata.getNumberOfImages()); node.setProperty(ImageMetadataLexicon.PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi()); node.setProperty(ImageMetadataLexicon.PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi()); node.setProperty(ImageMetadataLexicon.PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch()); node.setProperty(ImageMetadataLexicon.PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch()); } @Override public void initialize( NamespaceRegistry registry, NodeTypeManager nodeTypeManager ) throws RepositoryException, IOException { registerNodeTypes("images.cnd", nodeTypeManager, true); registerDefaultMimeTypes(ImageMetadata.MIME_TYPE_STRINGS); registerDefaultMimeTypes(TIFF_MIME_TYPES); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy