
com.day.cq.dam.handler.standard.psd.PsdHandler Maven / Gradle / Ivy
/*
* Copyright 1997-2009 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.handler.standard.psd;
import com.adobe.granite.asset.api.AssetRelation;
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.AssetReferenceResolver;
import com.day.cq.dam.api.DamConstants;
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.handler.AbstractAssetHandler;
import com.day.image.Layer;
import com.twelvemonkeys.imageio.plugins.psd.PSDImageReader;
import com.twelvemonkeys.imageio.plugins.psd.PSDImageReaderSpi;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Activate;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.FileCacheImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.jcr.RepositoryException;
import java.awt.Dimension;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ByteArrayInputStream;
import java.util.Iterator;
import static com.day.cq.dam.api.DamConstants.TIFF_IMAGELENGTH;
import static com.day.cq.dam.api.DamConstants.TIFF_IMAGEWIDTH;
/**
* Handler for Photoshop documents.
*/
@Component(inherit = true, metatype = true)
@Service
public class PsdHandler extends AbstractAssetHandler {
/**
* The default logger
*/
private static final Logger log = LoggerFactory.getLogger(PsdHandler.class);
private static final ImageReaderSpi provider = new PSDImageReaderSpi();
public static final String CONFIG_LARGE_FILE_THRESHOLD = "large_file_threshold";
private static final long DEFAULT_LARGE_FILE_THRESHOLD = 500L;
@Property(longValue = DEFAULT_LARGE_FILE_THRESHOLD, name = CONFIG_LARGE_FILE_THRESHOLD,
label = "Threshold size in MB 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.")
private long largeFileThreshold = DEFAULT_LARGE_FILE_THRESHOLD;
/**
* Mime type
*/
public static final String PHOTOSHOP_MIMETYPE_1 = "application/x-photoshop";
public static final String PHOTOSHOP_MIMETYPE_2 = "application/photoshop";
public static final String PHOTOSHOP_MIMETYPE_3 = "image/vnd.adobe.photoshop";
public static final String PHOTOSHOP_MIMETYPE_4 = "application/vnd.adobe.photoshop";
public static final String PHOTOSHOP_MIMETYPE_5 = "application/vnd.3gpp.pic-bw-small";
@Reference(policy = ReferencePolicy.STATIC)
private AssetReferenceResolver refResolver;
@Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_UNARY)
protected XMPHandler xmpHandler;
synchronized void bindXmpHandler(final XMPHandler handler) {
xmpHandler = handler;
log.debug("binding xmp handler");
}
synchronized void unbindXmpHandler(final XMPHandler handler) {
xmpHandler = null;
log.debug("un-binding xmp handler");
}
public BufferedImage getImage(final Rendition rendition) throws IOException {
return getImage(rendition, null);
}
public BufferedImage getImage(final Rendition rendition, Dimension dim) throws IOException {
final InputStream is = rendition.getStream();
ImageInputStream stream = null;
boolean debug = log.isDebugEnabled();
try {
PSDImageReader reader = new PSDImageReader(provider);
if (doFileBuffering(rendition)) {
stream = new FileCacheImageInputStream(is, null);
log.debug("Used FileCacheInputImageStream for rendition size [{}]", rendition.getSize());
} else {
stream = ImageIO.createImageInputStream(is);
}
reader.setInput(stream);
long start = System.currentTimeMillis();
BufferedImage image = null;
ImageReadParam param = new ImageReadParam();
image = reader.read(0, param);
if (debug) {
log.debug("time: " + (System.currentTimeMillis() - start));
log.debug("image: " + image);
}
ColorModel imageColorModel = image.getColorModel();
if (imageColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
try {
/*ColorConvertOp op = new ColorConvertOp(ColorSpace
.getInstance(ColorSpace.CS_sRGB), null);
image = op.filter(image, new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR_PRE));*/
BufferedImage tmpImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
int[] rgbArray = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
tmpImage.setRGB(0, 0, image.getWidth(), image.getHeight(), rgbArray, 0, image.getWidth());
image = tmpImage;
} catch (Exception e) {
log.error("Exception", e);
}
if (debug) {
log.debug("time: " + (System.currentTimeMillis() - start));
log.debug("image: " + image);
}
}
//return image;
// start of "hack"
Layer layer;
// workaround since the gfx lib sometimes is not able to resize tiff images (BufferedImage!!)
FileOutputStream itout = null;
InputStream iis = null;
File imageTmpFile = null;
try {
imageTmpFile = File.createTempFile("image", ".tmp");
layer = new Layer(image);
itout = FileUtils.openOutputStream(imageTmpFile);
layer.write(DamConstants.THUMBNAIL_MIMETYPE, 1.0, itout);
iis = FileUtils.openInputStream(imageTmpFile);
return (new Layer(iis, dim)).getImage();
} finally {
IOUtils.closeQuietly(iis);
IOUtils.closeQuietly(itout);
FileUtils.deleteQuietly(imageTmpFile);
}
// eoh
} catch (Exception e) {
log.warn("getImage: error while getting image for PSD [{}]: ", rendition.getPath(), e);
} finally {
IOUtils.closeQuietly(is);
try {
stream.close();
} catch (Exception ignore) {
}
}
return null;
}
/**
* {@inheritDoc}
*/
public ExtractedMetadata extractMetadata(final Asset asset) {
final ExtractedMetadata metadata = new ExtractedMetadata();
final InputStream is = asset.getOriginal().getStream();
ImageInputStream stream = null;
try {
final PSDImageReader reader = new PSDImageReader(null);
if (doFileBuffering(asset.getOriginal())) {
stream = new FileCacheImageInputStream(is, null);
log.debug("Used FileCacheInputImageStream for size [{}]", asset.getOriginal().getSize());
} else {
stream = ImageIO.createImageInputStream(is);
}
reader.setInput(stream);
metadata.setMetaDataProperty(TIFF_IMAGEWIDTH,reader.getWidth(0));
metadata.setMetaDataProperty(TIFF_IMAGELENGTH, reader.getHeight(0));
setMimetype(metadata, asset);
} catch (IOException e) {
log.error("I/O error while getting metadata", e);
} finally {
IOUtils.closeQuietly(is);
try {
stream.close();
} catch (Exception ignore) {
}
}
InputStream xmps = null;
if (xmpHandler != null) { //it could be null on some platform like AIX
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(asset.getOriginal().getStream(), metadata);
} finally {
IOUtils.closeQuietly(xmps);
}
} else {
execGenericProcessor(asset.getOriginal().getStream(), metadata);
}
return metadata;
}
/**
* {@inheritDoc}
*/
public String[] getMimeTypes() {
return new String[]{PHOTOSHOP_MIMETYPE_1, PHOTOSHOP_MIMETYPE_2, PHOTOSHOP_MIMETYPE_3, PHOTOSHOP_MIMETYPE_4, PHOTOSHOP_MIMETYPE_5};
}
public Iterator extends AssetRelation> processRelated(final Asset asset) {
return refResolver.resolve(asset);
}
@Activate
@SuppressWarnings("unused")
protected void activate(final ComponentContext context) throws RepositoryException {
largeFileThreshold = PropertiesUtil.toLong(context.getProperties().get(CONFIG_LARGE_FILE_THRESHOLD), DEFAULT_LARGE_FILE_THRESHOLD);
}
private boolean doFileBuffering(final Rendition r) {
return (largeFileThreshold != -1) && (largeFileThreshold <= r.getSize());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy