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

com.day.cq.dam.commons.handler.StandardImageHandler Maven / Gradle / Ivy

There is a newer version: 2025.3.19823.20250304T101418Z-250200
Show newest version
/*
 * Copyright 1997-2008 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.dam.commons.handler;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.jcr.RepositoryException;

import com.adobe.xmp.core.XMPMetadata;
import com.adobe.xmp.core.serializer.RDFXMLSerializer;
import com.adobe.xmp.core.serializer.RDFXMLSerializerContext;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.handler.xmp.XMPHandler;
import com.day.cq.dam.api.metadata.ExtractedMetadata;
import com.day.cq.dam.commons.util.AssetCache;
import com.day.cq.dam.commons.util.DamUtil;
import com.day.image.Layer;
import org.apache.commons.imaging.FormatCompliance;
import org.apache.commons.imaging.ImageFormat;
import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.ImageInfo;
import org.apache.commons.imaging.ImageParser;
import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.ImageWriteException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.GenericImageMetadata;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.common.RationalNumber;
import org.apache.commons.imaging.common.bytesource.ByteSource;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.jpeg.JpegPhotoshopMetadata;
import org.apache.commons.imaging.formats.tiff.TiffContents;
import org.apache.commons.imaging.formats.tiff.TiffDirectory;
import org.apache.commons.imaging.formats.tiff.TiffField;
import org.apache.commons.imaging.formats.tiff.TiffImageParser;
import org.apache.commons.imaging.formats.tiff.TiffReader;
import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.PropertyUnbounded;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The StandardImageHandler supports currently following image types: 
  • gif
  • png
  • photoshop *
  • jpeg
  • tiff
  • bmp
*/ @Component(inherit = true, metatype = true) @Service public class StandardImageHandler extends AbstractAssetHandler { /** * the default logger */ protected final Logger log = LoggerFactory.getLogger(StandardImageHandler.class); public static final String CONFIG_LARGE_FILE_THRESHOLD = "large_file_threshold"; private static final long DEFAULT_LARGE_FILE_THRESHOLD = 0; public static final String CONFIG_LARGE_COMMENT_THRESHOLD = "large_comment_threshold"; private static final long DEFAULT_LARGE_COMMENT_THRESHOLD = 5000; public static final String METADATA_IGNORE_LIST = "metadata_ignore_list"; private static final String[] DEFAULT_METADATA_IGNORE_LIST = new String[]{"Image Description", "Artist", "Copyright"}; @Property(longValue = DEFAULT_LARGE_FILE_THRESHOLD, name = CONFIG_LARGE_FILE_THRESHOLD, label = "Threshold size to use intermediate temporary file", description = "Asset size greater than threshold use temporary file instead of memory buffer to avoid OutOfMemoryError. Value of -1 means that the use of temporary file is disabled. 0 means it is enabled for all sizes.") private long largeFileThreshold = DEFAULT_LARGE_FILE_THRESHOLD; @Property(longValue = DEFAULT_LARGE_COMMENT_THRESHOLD, name = CONFIG_LARGE_COMMENT_THRESHOLD, label = "Threshold size to skip comments being stored", description = "Comment size greater than threshold will not be stored. Value of -1 means that all comments would be stored irrespective of their size.") private long largeCommentThreshold = DEFAULT_LARGE_COMMENT_THRESHOLD; @Property(unbounded = PropertyUnbounded.ARRAY, propertyPrivate = true, value = {"Image Description", "Artist", "Copyright"}, name = "metadata_ignore_list", label = "List of metadata tags to be ignored from extraction") private List metadataIgnoreList = Arrays.asList(DEFAULT_METADATA_IGNORE_LIST); /** * Mime type */ public static final String GIF_MIMETYPE = "image/gif"; public static final String PNG1_MIMETYPE = "image/png"; public static final String PNG2_MIMETYPE = "image/x-png"; public static final String JPEG_MIMETYPE = "image/jpeg"; public static final String PJPEG_MIMETYPE = "image/pjpeg"; public static final String TIFF_MIMETYPE = "image/tiff"; public static final String TIFF1_MIMETYPE = "image/x-tiff"; public static final String BMP1_MIMETYPE = "image/x-ms-bmp"; public static final String BMP2_MIMETYPE = "image/bmp"; public static final String RAW1_MIMETYPE = "image/x-raw-adobe"; public static final String RAW2_MIMETYPE = "image/x-raw-hasselblad"; public static final String RAW3_MIMETYPE = "image/x-raw-fuji"; public static final String RAW4_MIMETYPE = "image/x-raw-canon"; public static final String RAW5_MIMETYPE = "image/x-raw-kodak"; public static final String RAW6_MIMETYPE = "image/x-raw-minolta"; public static final String RAW7_MIMETYPE = "image/x-raw-nikon"; public static final String RAW8_MIMETYPE = "image/x-raw-olympus"; public static final String RAW9_MIMETYPE = "image/x-raw-pentax"; public static final String RAW10_MIMETYPE = "image/x-raw-sony"; public static final String RAW11_MIMETYPE = "image/x-raw-sigma"; public static final String RAW12_MIMETYPE = "image/x-raw-epson"; public static final String RAW13_MIMETYPE = "image/x-raw-mamiya"; public static final String RAW14_MIMETYPE = "image/x-raw-leaf"; public static final String RAW15_MIMETYPE = "image/x-raw-panasonic"; public static final String RAW16_MIMETYPE = "image/x-raw-phaseone"; public static final String RAW17_MIMETYPE = "image/x-raw-red"; public static final String RAW18_MIMETYPE = "image/x-raw-imacon"; public static final String RAW19_MIMETYPE = "image/x-raw-logitech"; public static final String RAW20_MIMETYPE = "image/x-raw-casio"; public static final String RAW21_MIMETYPE = "image/x-raw-rawzor"; public static final String RAW22_MIMETYPE = "image/x-canon-cr2"; public static final String RAW23_MIMETYPE = "image/x-nikon-nef"; public static final String DNG_MIMETYPE = "image/dng"; protected static final String[] MIME_TYPES = {GIF_MIMETYPE, PNG1_MIMETYPE, PNG2_MIMETYPE, TIFF_MIMETYPE, TIFF1_MIMETYPE, BMP1_MIMETYPE, BMP2_MIMETYPE, RAW1_MIMETYPE, RAW2_MIMETYPE, RAW3_MIMETYPE, RAW4_MIMETYPE, RAW5_MIMETYPE, RAW6_MIMETYPE, RAW7_MIMETYPE, RAW8_MIMETYPE, RAW9_MIMETYPE, RAW10_MIMETYPE, RAW11_MIMETYPE, RAW12_MIMETYPE, RAW13_MIMETYPE, RAW14_MIMETYPE, RAW15_MIMETYPE, RAW16_MIMETYPE, RAW17_MIMETYPE, RAW18_MIMETYPE, RAW19_MIMETYPE, RAW20_MIMETYPE, RAW21_MIMETYPE, RAW22_MIMETYPE, RAW23_MIMETYPE, DNG_MIMETYPE}; @Property(boolValue = false) protected static final String ENABLE_BINARY_META_EXTRACTION = "cq.dam.enable.ext.meta.extraction"; protected boolean enableExtMetaExtraction = false; @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_UNARY) protected XMPHandler xmpHandler; protected synchronized void bindXmpHandler(final XMPHandler handler) { xmpHandler = handler; log.debug("binding xmp handler"); } protected synchronized void unbindXmpHandler(final XMPHandler handler) { xmpHandler = null; log.debug("un-binding xmp handler"); } /** * @see com.day.cq.dam.api.handler.AssetHandler#getMimeTypes() */ public String[] getMimeTypes() { return MIME_TYPES; } public ExtractedMetadata extractMetadata(final Asset asset) { final ExtractedMetadata metadata = new ExtractedMetadata(); try { extractMetadata(asset, metadata); setMimetype(metadata, asset); } catch (Exception e) { if(log.isDebugEnabled()) log.debug("extractMetadata: error while extracting metadata for asset [{}]: ", asset.getPath(), e); else log.warn("extractMetadata: error while extracting metadata for asset [{}]: ", asset.getPath()); } return metadata; } /** * {@inheritDoc} */ public BufferedImage getImage(final Rendition rendition) throws IOException { return getImage(rendition, null); } /** * {@inheritDoc} */ public BufferedImage getImage(final Rendition rendition, Dimension maxDimension) throws IOException { AssetCache cache = DamUtil.getAssetCache(); try { if (isGif(rendition) || isPng(rendition) || isRaw(rendition)) { return new Layer(cache.getStream(rendition, false), maxDimension).getImage(); } else { Layer layer; // workaround since the gfx lib sometimes is not able to resize tiff images (BufferedImage!!) // todo: is this still needed? gfx 2.0.18 uses a different resize algorithm InputStream iis = null; File imageTmpFile = null; File assetTempFile = null; FileOutputStream fos = null; try { BufferedImage bufImage = null; imageTmpFile = File.createTempFile("image", ".tmp"); long startTime = System.currentTimeMillis(); if (doFileBuffering(rendition)) { bufImage = Imaging.getBufferedImage(cache.getFile(rendition)); ImageIO.write(bufImage, "png", imageTmpFile); } else { bufImage = Imaging.getBufferedImage(cache.getStream(rendition, false)); Imaging.writeImage(bufImage, imageTmpFile, ImageFormats.PNG, null); } long endTime = System.currentTimeMillis(); log.debug("time taken to convert to png = " + ((endTime - startTime)) + " ms"); iis = FileUtils.openInputStream(imageTmpFile); return (new Layer(iis, maxDimension)).getImage(); } finally { IOUtils.closeQuietly(iis); FileUtils.deleteQuietly(imageTmpFile); } // end workaround } } catch (ImageReadException e) { log.warn("getImage: error while reading image at path [{}]: ", rendition.getPath(), e); } catch (ImageWriteException e) { log.warn("getImage: error while writing image at path [{}]: ", rendition.getPath(), e); } catch (IOException e) { log.warn("getImage: error while reading image at path [{}]: ", rendition.getPath(), e); } finally { cache.release(); } return null; } private boolean doFileBuffering(final Rendition r) { return (largeFileThreshold != -1) && (largeFileThreshold <= r.getSize()); } private boolean doAddComment(int commentSize) { return (largeCommentThreshold == -1 || (largeCommentThreshold != -1 && largeCommentThreshold >= commentSize)); } protected Map extractImageInfo(final Asset asset) { AssetCache cache = DamUtil.getAssetCache(); try { Rendition original = asset.getOriginal(); ByteSource bs = cache.getByteSource(original, doFileBuffering(original)); ImageParser imageParser = getImageParser(bs); return extractImageInfo(asset.getPath(), bs, imageParser); } catch (ImageReadException e) { if(log.isDebugEnabled()) log.debug("extractImageInfo: error while reading metadata from image [{}]: ", asset.getPath(), e); else log.warn("extractImageInfo: error while reading metadata from image [{}]: ", asset.getPath()); } catch (IOException e) { if(log.isDebugEnabled()) log.debug("extractImageInfo: error while reading info from image [{}]: ", asset.getPath(), e); else log.warn("extractImageInfo: error while reading info from image [{}]: ", asset.getPath()); } finally { cache.release(); } return new HashMap(); } private Map extractImageInfo(final String path, ByteSource bsis, ImageParser ip) { try { // get Metadata return extractImageInfo(path, ip.getImageInfo(bsis)); } catch (ImageReadException e) { log.warn("extractImageInfo: error while reading metadata from image [{}]: ", path, e); } catch (IOException e) { log.warn("extractImageInfo: error while reading info from image [{}]: ", path, e); } return new HashMap(); } private Map extractImageInfo(String path, ImageInfo imageInfo) { final Map metadata = new HashMap(); /** * CQ5-5795 Media Handler: BMP: dam:Numberofimages always -1 if * number of images is -1 lets make it to 1. */ int numberOfImages = imageInfo.getNumberOfImages(); if (numberOfImages < 0) { numberOfImages = 1; } metadata.put("File format", imageInfo.getFormat().getName()); metadata.put("MIME type", imageInfo.getMimeType()); metadata.put("Image Width", imageInfo.getWidth()); metadata.put("Image Length", imageInfo.getHeight()); metadata.put("Bits per pixel", imageInfo.getBitsPerPixel()); metadata.put("Progressive", imageInfo.isProgressive() ? "yes" : "no"); metadata.put("Number of images", numberOfImages); metadata.put("Physical width in dpi", imageInfo.getPhysicalWidthDpi()); metadata.put("Physical height in dpi", imageInfo.getPhysicalHeightDpi()); metadata.put("Physical width in inches", (double) imageInfo.getPhysicalWidthInch()); metadata.put("Physical height in inches", (double) imageInfo.getPhysicalHeightInch()); final List comments = imageInfo.getComments(); int numComments = (comments == null ? 0 : comments.size()); int commentsStored = 0; if (numComments > 0) { final StringBuffer buffer = new StringBuffer(); for (int i = 0; i < numComments; i++) { if (comments != null) { if (doAddComment(comments.get(i).length())) { buffer.append(comments.get(i)).append('\n'); commentsStored++; } } } metadata.put("Comments", buffer.toString()); } metadata.put("Number of textual comments", commentsStored); return metadata; } protected void extractMetadata(Asset asset, ExtractedMetadata metadata) throws IOException, ImageReadException { AssetCache cache = DamUtil.getAssetCache(); ImageMetadata data = null; try { Rendition original = asset.getOriginal(); ByteSource bs = cache.getByteSource(original, doFileBuffering(original)); ImageParser imageParser = null; try { log.debug("extractMetadata, imageParser.getMetadata()"); imageParser = getImageParser(bs); if (imageParser instanceof TiffImageParser) { extractMetadataTiff(metadata, bs, asset.getPath(), imageParser); } else { extractMetadataGeneric(metadata, bs, asset.getPath(), imageParser); } } catch (Exception e) { log.warn("extractMetadata: cannot read metadata from image [{}]: ", asset.getPath(), e); if (e instanceof ImageReadException) { if (bs != null && imageParser != null) { final Map imageDimensionData = getDimensionMetadata(asset.getPath(), bs, imageParser); if (!imageDimensionData.isEmpty()) metadata.addMetadataProperties(imageDimensionData); } } } if (enableExtMetaExtraction) { // get XMP from imaging // jpeg can have XMP in the app1 segment, generic processor is not able to extract it // as the generic processor only looks for xmppacket // http://www.ozhiker.com/electronics/pjmt/jpeg_info/app_segments.html extractImageXMP(bs, metadata); } // if the image have xmppacket and then that will overwrite the above xmp, which should be fine // Use this in any case since sanselan does not extract unicode properly //todo move this to exception block once Sanselan.getMetadata is fixed if (xmpHandler != null) { //it could be null on some platform like AIX // Since NCommXMPHandler is faster, use that if available... InputStream xmps = null; try { XMPMetadata xmpMetadata = xmpHandler.readXmpMetadata(asset); if (xmpMetadata != null) { byte[] xmpBytes = (new RDFXMLSerializer()).serializeToBuffer( xmpMetadata, new RDFXMLSerializerContext()); xmps = new ByteArrayInputStream(xmpBytes); metadata.setXmp(xmps); } } catch (Exception e) { if (log.isDebugEnabled()) { log.error("Couldn't extract metadata using XMPhandler, attempting brute-force extraction", e); } else { log.warn("Couldn't extract metadata using XMPhandler, attempting brute-force extraction"); } // fallback to 'brute-force' execGenericProcessor(cache.getStream(original,doFileBuffering(original)), metadata); } finally { IOUtils.closeQuietly(xmps); } } else { //... else fallback to 'brute-force' execGenericProcessor(cache.getStream(original,doFileBuffering(original)), metadata); } if (metadata.getXmp() == null && !enableExtMetaExtraction) { extractImageXMP(bs, metadata); } } catch (Exception e) { log.warn("extractMetadata: cannot read metadata from image [{}]: ", asset.getPath(), e); } finally { cache.release(); log.debug("extractMetadata, done"); } } private void extractMetadataGeneric(ExtractedMetadata metadata, ByteSource bs, String path, ImageParser imageParser) throws Exception { /* bug 39584, for all image formats beside Tiff, imageInfo has priority over metadata. */ ImageMetadata data = imageParser.getMetadata(bs); log.debug("extractMetadata, got ImageMetadata"); JpegImageMetadata jpegMetadata; if ((data != null) && ((data instanceof JpegImageMetadata))) { jpegMetadata = (JpegImageMetadata) data; JpegPhotoshopMetadata jpegphotoshopMetadata = jpegMetadata.getPhotoshop(); // first extract photoshop segment if present, so that same value can be overridden if present in exif // we give preference to exif/tiff if (jpegphotoshopMetadata != null) { for (ImageMetadata.ImageMetadataItem item : jpegphotoshopMetadata.getItems()) { setPhotoshopItemValue(item, metadata); } } // for tiff extraction sanselan now stores the tiff metadata under exif for jpeg data = jpegMetadata.getExif(); } log.debug("extractMetadata, extract ImageInfo"); final Map imageData = extractImageInfo(path, bs, imageParser); metadata.addMetadataProperties(imageData); } private void extractMetadataTiff(ExtractedMetadata metadata, ByteSource bs, String path, ImageParser imageParser) throws Exception { TiffReader reader = new TiffReader(false); TiffContents contents = reader.readContents(bs, null, FormatCompliance.getDefault()); /* bug 39584, in Tiff metadata has priority over imageInfo.*/ log.debug("extractMetadata, extract ImageInfo"); final Map imageData = extractImageInfo(path, getImageInfo(contents)); metadata.addMetadataProperties(imageData); for (Iterator i = contents.directories.iterator(); i.hasNext(); /**/) { TiffDirectory dir = (TiffDirectory)i.next(); for (Iterator j = dir.getDirectoryEntries().iterator(); j.hasNext(); /**/) { TiffField tf = (TiffField)j.next(); if (tf.getDirectoryType() != TiffDirectoryConstants.DIRECTORY_TYPE_DIR_1) {//ignore IFD1 (thumbnail metadata) String tagName = tf.getTagName(); FieldType fieldType = tf.getFieldType(); if ((enableExtMetaExtraction || !(fieldType.equals(FieldType.BYTE) || fieldType.equals(FieldType.UNDEFINED))) && !tagName.equals(TiffTagConstants.TIFF_TAG_XMP.name) && !metadataIgnoreList.contains(tagName)) { log.debug("name =" + tagName + ", type=" + tf.getFieldTypeName()); metadata.setMetaDataProperty(tagName, trimValue(tf)); } else { // skip, we scan for XMP at the end log.debug("Skipping XMP tag [" + tagName + "], of type [" + fieldType.getName() + "] XMP is scanned by CQ generic XMP scanner", tagName); } } } } log.debug("extractMetadata, got ImageMetadata"); } private ImageInfo getImageInfo(TiffContents contents) throws ImageReadException, IOException { TiffDirectory directory = (TiffDirectory)contents.directories.get(0); TiffField widthField = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_WIDTH, true); TiffField heightField = directory.findField(TiffTagConstants.TIFF_TAG_IMAGE_LENGTH, true); if(widthField != null && heightField != null) { int height = heightField.getIntValue(); int width = widthField.getIntValue(); TiffField resolutionUnitField = directory.findField(TiffTagConstants.TIFF_TAG_RESOLUTION_UNIT); int resolutionUnit = 2; if(resolutionUnitField != null && resolutionUnitField.getValue() != null) { resolutionUnit = resolutionUnitField.getIntValue(); } double unitsPerInch = -1.0D; switch (resolutionUnit) { case 1: default: break; case 2: unitsPerInch = 1.0D; break; case 3: unitsPerInch = 2.54D; } TiffField xResolutionField = directory.findField(TiffTagConstants.TIFF_TAG_XRESOLUTION); TiffField yResolutionField = directory.findField(TiffTagConstants.TIFF_TAG_YRESOLUTION); int physicalWidthDpi = -1; float physicalWidthInch = -1.0F; int physicalHeightDpi = -1; float physicalHeightInch = -1.0F; if (unitsPerInch > 0.0D) { double bitsPerSampleField; if (xResolutionField != null && xResolutionField.getValue() != null) { bitsPerSampleField = xResolutionField.getDoubleValue(); physicalWidthDpi = (int)Math.round(bitsPerSampleField * unitsPerInch); physicalWidthInch = (float)((double)width / (bitsPerSampleField * unitsPerInch)); } if (yResolutionField != null && yResolutionField.getValue() != null) { bitsPerSampleField = yResolutionField.getDoubleValue(); physicalHeightDpi = (int)Math.round(bitsPerSampleField * unitsPerInch); physicalHeightInch = (float)((double)height / (bitsPerSampleField * unitsPerInch)); } } TiffField var38 = directory.findField(TiffTagConstants.TIFF_TAG_BITS_PER_SAMPLE); int bitsPerSample = 1; if(var38 != null && var38.getValue() != null) { bitsPerSample = var38.getIntValueOrArraySum(); } ArrayList comments = new ArrayList(); List entries = directory.entries; String mimeType; for(int format = 0; format < entries.size(); ++format) { TiffField formatName = (TiffField)entries.get(format); mimeType = formatName.toString(); comments.add(mimeType); } int numberOfImages = contents.directories.size(); String formatDetails = "Tiff v." + contents.header.tiffVersion; boolean usesPalette = false; TiffField colorMapField = directory.findField(TiffTagConstants.TIFF_TAG_COLOR_MAP); if (colorMapField != null) { usesPalette = true; } boolean colorType = true; int compression = '\uffff' & directory.getSingleFieldValue(TiffTagConstants.TIFF_TAG_COMPRESSION); ImageInfo.CompressionAlgorithm ca; ImageInfo.ColorType ctype = ImageInfo.ColorType.UNKNOWN; switch(compression) { case 1: ca = ImageInfo.CompressionAlgorithm.NONE; break; case 2: ca = ImageInfo.CompressionAlgorithm.CCITT_1D; break; case 3: ca = ImageInfo.CompressionAlgorithm.CCITT_GROUP_3; break; case 4: ca = ImageInfo.CompressionAlgorithm.CCITT_GROUP_4; break; case 5: ca = ImageInfo.CompressionAlgorithm.LZW; break; case 6: ca = ImageInfo.CompressionAlgorithm.JPEG; break; case 32771: ca = ImageInfo.CompressionAlgorithm.NONE; break; case 32773: ca = ImageInfo.CompressionAlgorithm.PACKBITS; break; default: ca = ImageInfo.CompressionAlgorithm.UNKNOWN; } ImageInfo result = new ImageInfo(formatDetails, bitsPerSample, comments, ImageFormats.TIFF, "TIFF Tag-based Image File Format", height, "image/tiff", numberOfImages, physicalHeightDpi, physicalHeightInch, physicalWidthDpi, physicalWidthInch, width, false, false, usesPalette, ctype, ca); return result; } else { throw new ImageReadException("TIFF image missing size info."); } } /** * CQ-59676, NPR-8278 : DAM does not extract width and height metadata if parsing is failed due to any reason * Below is fallback attempt to at least get image size properties. Long term fix should come from apache commons imaging( https://issues.apache.org/jira/browse/IMAGING-100) */ private Map getDimensionMetadata(final String path, ByteSource bsis, ImageParser ip) { final Map metadata = new HashMap(); try { Dimension d = ip.getImageSize(bsis, null); if (d != null) { metadata.put("Image Width", (int) d.getWidth()); metadata.put("Image Length", (int) d.getHeight()); } } catch (ImageReadException e) { log.warn("getDimensionMetadata - imageParser.getImageSize() fallback attempt: error while reading metadata from image [{}]: ", path, e); } catch (IOException e) { log.warn("getDimensionMetadata - imageParser.getImageSize() fallback attempt: error while reading info from image [{}]: ", path, e); } return metadata; } private void extractImageXMP(ByteSource bs, ExtractedMetadata metadata) { try { String xmpStr = Imaging.getXmpXml(bs, null); log.debug("extracted xmp string is {}", xmpStr); if (xmpStr != null) { metadata.setXmp(new ByteArrayInputStream(xmpStr.getBytes("utf-8"))); } } catch (Exception e) { if(log.isDebugEnabled()) log.debug("could not extract XMP from the image", e); else log.warn("could not extract XMP from the image"); // don't want to throw exception so as to keep backward compatible behavior // any error here should not stop the processing } } private void setPhotoshopItemValue(ImageMetadata.ImageMetadataItem item, ExtractedMetadata extractedMetadata) { if ((item instanceof GenericImageMetadata.GenericImageMetadataItem)) { GenericImageMetadata.GenericImageMetadataItem imageItem = (GenericImageMetadata.GenericImageMetadataItem)item; String keyword = imageItem.getKeyword(); String text = imageItem.getText(); Object existingVal; if ((existingVal = extractedMetadata.getMetaDataProperty(keyword)) != null) { if (existingVal instanceof String) { List newVal = new ArrayList(); newVal.add((String)existingVal); newVal.add(text); extractedMetadata.setMetaDataProperty(keyword, newVal); } else if (existingVal instanceof List) { ((List) existingVal).add(text); } } else { extractedMetadata.setMetaDataProperty(keyword, text); } } } private ImageParser getImageParser(ByteSource byteSrc) throws ImageReadException, IOException { final ImageFormat format = Imaging.guessFormat(byteSrc); if (!format.equals(ImageFormats.UNKNOWN)) { final ImageParser imageParsers[] = ImageParser.getAllImageParsers(); for (final ImageParser imageParser : imageParsers) { if (imageParser.canAcceptType(format)) { return imageParser; } } } throw new ImageReadException("Can't parse this format."); } /** * Sanselan seems to add control chars at the end which needs to be removed * This method removes any ctrl chars if the TIFF field type is String * * @param field, Tiff field which needs to be trimmed if String * @return Trimmed string or the original field value in case the field is not a String * @throws ImageReadException if unable to extract field value */ private Object trimValue(TiffField field) throws ImageReadException { Object fieldValue = field.getValue(); if (fieldValue instanceof String) { fieldValue = StringUtils.trimToEmpty(fieldValue.toString()); } if (fieldValue instanceof RationalNumber) { if(((RationalNumber)fieldValue).toString().indexOf(',') > 0) fieldValue = ((RationalNumber) fieldValue).numerator/((RationalNumber) fieldValue).divisor; } return fieldValue; } private boolean isPng(final Rendition rendition) { return rendition.getMimeType().startsWith(PNG1_MIMETYPE) || rendition.getMimeType().startsWith(PNG2_MIMETYPE); } private boolean isGif(final Rendition rendition) { return rendition.getMimeType().startsWith(GIF_MIMETYPE); } private boolean isRaw(final Rendition rendition) { return rendition.getMimeType().startsWith("image/x-raw-"); } @Activate @SuppressWarnings("unused") protected void activate(final ComponentContext context) throws RepositoryException { enableExtMetaExtraction = PropertiesUtil.toBoolean(context.getProperties().get(ENABLE_BINARY_META_EXTRACTION), false); largeFileThreshold = PropertiesUtil.toLong(context.getProperties().get(CONFIG_LARGE_FILE_THRESHOLD), DEFAULT_LARGE_FILE_THRESHOLD); largeCommentThreshold = PropertiesUtil.toLong(context.getProperties().get(CONFIG_LARGE_COMMENT_THRESHOLD), DEFAULT_LARGE_COMMENT_THRESHOLD); metadataIgnoreList = Arrays.asList(PropertiesUtil.toStringArray(context.getProperties().get(METADATA_IGNORE_LIST), DEFAULT_METADATA_IGNORE_LIST)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy