1 /*
2 * ModeShape (http://www.modeshape.org)
3 * See the COPYRIGHT.txt file distributed with this work for information
4 * regarding copyright ownership. Some portions may be licensed
5 * to Red Hat, Inc. under one or more contributor license agreements.
6 * See the AUTHORS.txt file in the distribution for a full listing of
7 * individual contributors.
8 *
9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10 * is licensed to you under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * ModeShape is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this software; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23 */
24 package org.modeshape.sequencer.image;
25
26 import java.io.InputStream;
27 import org.modeshape.graph.JcrLexicon;
28 import org.modeshape.graph.property.Path;
29 import org.modeshape.graph.property.PathFactory;
30 import org.modeshape.graph.sequencer.SequencerOutput;
31 import org.modeshape.graph.sequencer.StreamSequencer;
32 import org.modeshape.graph.sequencer.StreamSequencerContext;
33
34 /**
35 * A sequencer that processes the binary content of an image file, extracts the metadata for the image, and then writes that image
36 * metadata to the repository.
37 * <p>
38 * This sequencer produces data that corresponds to the following structure:
39 * <ul>
40 * <li><strong>image:metadata</strong> node of type <code>image:metadata</code>
41 * <ul>
42 * <li><strong>jcr:mimeType</strong> - optional string property for the mime type of the image</li>
43 * <li><strong>jcr:encoding</strong> - optional string property for the encoding of the image</li>
44 * <li><strong>image:formatName</strong> - string property for the name of the format</li>
45 * <li><strong>image:width</strong> - optional integer property for the image's width in pixels</li>
46 * <li><strong>image:height</strong> - optional integer property for the image's height in pixles</li>
47 * <li><strong>image:bitsPerPixel</strong> - optional integer property for the number of bits per pixel</li>
48 * <li><strong>image:progressive</strong> - optional boolean property specifying whether the image is stored in a progressive
49 * (i.e., interlaced) form</li>
50 * <li><strong>image:numberOfImages</strong> - optional integer property for the number of images stored in the file; defaults to
51 * 1</li>
52 * <li><strong>image:physicalWidthDpi</strong> - optional integer property for the physical width of the image in dots per inch</li>
53 * <li><strong>image:physicalHeightDpi</strong> - optional integer property for the physical height of the image in dots per inch</li>
54 * <li><strong>image:physicalWidthInches</strong> - optional double property for the physical width of the image in inches</li>
55 * <li><strong>image:physicalHeightInches</strong> - optional double property for the physical height of the image in inches</li>
56 * </ul>
57 * </li>
58 * </ul>
59 * </p>
60 * <p>
61 * This structure could be extended in the future to add EXIF and IPTC metadata as child nodes. For example, EXIF metadata is
62 * structured as tags in directories, where the directories form something like namespaces, and which are used by different camera
63 * vendors to store custom metadata. This structure could be mapped with each directory (e.g. "EXIF" or "Nikon Makernote" or
64 * "IPTC") as the name of a child node, with the EXIF tags values stored as either properties or child nodes.
65 * </p>
66 */
67 public class ImageMetadataSequencer implements StreamSequencer {
68
69 /**
70 * {@inheritDoc}
71 *
72 * @see StreamSequencer#sequence(InputStream, SequencerOutput, StreamSequencerContext)
73 */
74 public void sequence( InputStream stream,
75 SequencerOutput output,
76 StreamSequencerContext context ) {
77
78 ImageMetadata metadata = new ImageMetadata();
79 metadata.setInput(stream);
80 metadata.setDetermineImageNumber(true);
81 metadata.setCollectComments(true);
82
83 // Process the image stream and extract the metadata ...
84 if (!metadata.check()) {
85 metadata = null;
86 }
87
88 // Generate the output graph if we found useful metadata ...
89 if (metadata != null) {
90 PathFactory pathFactory = context.getValueFactories().getPathFactory();
91 Path metadataNode = pathFactory.createRelativePath(ImageMetadataLexicon.METADATA_NODE);
92
93 // Place the image metadata into the output map ...
94 output.setProperty(metadataNode, JcrLexicon.PRIMARY_TYPE, "image:metadata");
95 // output.psetProperty(metadataNode, nameFactory.create(IMAGE_MIXINS), "");
96 output.setProperty(metadataNode, JcrLexicon.MIMETYPE, metadata.getMimeType());
97 // output.setProperty(metadataNode, nameFactory.create(IMAGE_ENCODING), "");
98 output.setProperty(metadataNode, ImageMetadataLexicon.FORMAT_NAME, metadata.getFormatName());
99 output.setProperty(metadataNode, ImageMetadataLexicon.WIDTH, metadata.getWidth());
100 output.setProperty(metadataNode, ImageMetadataLexicon.HEIGHT, metadata.getHeight());
101 output.setProperty(metadataNode, ImageMetadataLexicon.BITS_PER_PIXEL, metadata.getBitsPerPixel());
102 output.setProperty(metadataNode, ImageMetadataLexicon.PROGRESSIVE, metadata.isProgressive());
103 output.setProperty(metadataNode, ImageMetadataLexicon.NUMBER_OF_IMAGES, metadata.getNumberOfImages());
104 output.setProperty(metadataNode, ImageMetadataLexicon.PHYSICAL_WIDTH_DPI, metadata.getPhysicalWidthDpi());
105 output.setProperty(metadataNode, ImageMetadataLexicon.PHYSICAL_HEIGHT_DPI, metadata.getPhysicalHeightDpi());
106 output.setProperty(metadataNode, ImageMetadataLexicon.PHYSICAL_WIDTH_INCHES, metadata.getPhysicalWidthInch());
107 output.setProperty(metadataNode, ImageMetadataLexicon.PHYSICAL_HEIGHT_INCHES, metadata.getPhysicalHeightInch());
108 }
109 }
110 }