
com.day.cq.dam.handler.standard.ps.PostScriptHandler Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.day.cq.dam.handler.standard.ps;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.UnsupportedEncodingException;
import java.lang.Exception;
import java.lang.String;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import com.adobe.granite.asset.api.AssetRelation;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.FormatHandler;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.ProcessorException;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.adobe.internal.pdftoolkit.core.util.Utility;
import com.day.cq.dam.api.metadata.ExtractedMetadata;
import com.day.cq.dam.commons.handler.DefaultFormatHandler;
import com.day.cq.dam.handler.standard.pdf.PdfHandler;
import com.day.cq.dam.api.AssetReferenceResolver;
/**
* PostScriptHandler Handles files with mimetype as application/postscript.
* First it tries to see if the file is an illustrator file then it delegate the handling to pdfHandler
* else, it tries to use the format handlers that are available for handle the file.
*
*/
@Component(inherit = true, metatype = true)
@Service
public class PostScriptHandler extends PdfHandler {
private static final Logger log = LoggerFactory.getLogger(PostScriptHandler.class);
@Property(boolValue = false, name = "raster.annotation")
private static final String RASTER_ANNOTATION = "raster_annotation";
@Reference(policy = ReferencePolicy.STATIC)
private AssetReferenceResolver childRefResolver;
/**
* Mime type
*/
public static final String CONTENT_MIMETYPE = "application/postscript";
public static final String XMP_MANIFEST_PATH = JcrConstants.JCR_CONTENT + "/" + DamConstants.METADATA_FOLDER + "/xmpMM:Manifest";
public static final String FILE_REFERENCE_PATH = "stMfs:reference";
/**
* Number of bytes to pre-read to determine correct format handler.
*/
private static final int MAGIC_SIZE = 1024;
/**
* {@inheritDoc}
*/
public String[] getMimeTypes() {
return new String[] { CONTENT_MIMETYPE };
}
/**
* Bundle context.
*/
protected BundleContext bundleContext;
/**
* Invoked on service activation.
*
* @param componentContext component context
*/
protected void activate(ComponentContext componentContext) {
bundleContext = componentContext.getBundleContext();
}
/**
* Invoked on service deactivation.
*
* @param componentContext component context
*/
protected void deactivate(ComponentContext componentContext) {
bundleContext = null;
}
/**
* {@inheritDoc}
*/
public final ExtractedMetadata extractMetadata(final Asset asset) {
ExtractedMetadata metadata = new ExtractedMetadata();
InputStream in = null;
try {
in = asset.getOriginal().getStream();
metadata = extractMetadata(in, asset);
} finally {
IOUtils.closeQuietly(in);
}
setMimetype(metadata, asset);
return metadata;
}
/**
* {@inheritDoc}
*/
public BufferedImage getImage(final Rendition rendition, Dimension dim) throws IOException {
InputStream in = null;
try {
in = rendition.getStream();
return getThumbnailImage(in, rendition, dim);
} finally {
IOUtils.closeQuietly(in);
}
}
/**
* Extract metadata from an input stream and store it inside metadata provided.
*
* @param in input stream
* @param asset asset being processed
* @param metadata metadata
*/
private ExtractedMetadata extractMetadata(final InputStream in, final Asset asset) {
ExtractedMetadata metadata = new ExtractedMetadata();
PushbackInputStream pin = new PushbackInputStream(in, MAGIC_SIZE);
byte[] data = new byte[MAGIC_SIZE];
int len;
try {
// prefetch some bytes to find correct handler
if ((len = pin.read(data)) <= 0) {
// no content
return metadata;
}
pin.unread(data, 0, len);
//check if it is an isAIFile with application/postscript as mimetype
if (isAIFile(data, 0, len)) {
/* On updation of asset, metadata gets updated with previous versions. Changing the behaviour for MANIFEST node of AI files such that references
doesn't gets effected.
*/
try {
Node assetNode = asset.adaptTo(Node.class);
if(assetNode.hasNode(XMP_MANIFEST_PATH)) {
Node manifestNode = assetNode.getNode(XMP_MANIFEST_PATH);
manifestNode.remove();
}
} catch(RepositoryException e) {
log.error("Error while deleting MANIFEST node of AI file", e);
}
return super.extractMetadata(asset);
} else {
FormatHandler handler = getHandler(data, 0, len);
if (handler == null) {
handler = new DefaultFormatHandler();
}
InputStream xmp = handler.getMetadata(pin);
if (xmp != null) {
metadata.setXmp(xmp);
}
}
} catch (IOException e) {
log.warn("I/O error while getting metadata.", e);
} catch (ProcessorException e) {
log.warn("Error while processing {}: {}", asset.getPath(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("Stack trace.", e);
}
}
return metadata;
}
/**
* Find a thumbnail image inside an asset given as input stream.
*
* @param in input stream
* @param rendition being processed
*
* As a last resort, try to locate a JPEG inside the asset input stream or a Base64 encoded image
* in XMP.
* @return The graphical representation.
*/
protected BufferedImage getThumbnailImage(final InputStream in, final Rendition rendition, Dimension dim) {
PushbackInputStream pin = new PushbackInputStream(in, MAGIC_SIZE);
byte[] data = new byte[MAGIC_SIZE];
int len;
try {
// prefetch some bytes to find correct handler
if ((len = pin.read(data)) <= 0) {
// no content
return null;
}
pin.unread(data, 0, len);
//check if it is an isAIFile with application/postscript as mimetype
if (isAIFile(data, 0, len)) {
return super.getImage(rendition, dim);
} else {
FormatHandler handler = getHandler(data, 0, len);
if (handler == null) {
handler = new DefaultFormatHandler();
}
return handler.getThumbnailImage(pin);
}
} catch (IOException e) {
log.warn("I/O error while getting thumbnail image.", e);
} catch (ProcessorException e) {
log.warn("Error while processing {}: {}", rendition.getPath(), e.getMessage());
if (log.isDebugEnabled()) {
log.debug("Stack trace.", e);
}
}
return null;
}
/**
* Return the handler that will accept the bytes given.
*
* @param data first bytes of stream
* @param off off
* @param len len
* @return handler or null
if no handler is willing to handle
*/
private FormatHandler getHandler(byte[] data, int off, int len) {
if (bundleContext == null) {
log.warn("No bundle context available.");
return null;
}
try {
ServiceReference[] refs = bundleContext.getServiceReferences(
FormatHandler.class.getName(),
"(mimetype=*)");
if (refs != null) {
for (ServiceReference ref : refs) {
FormatHandler handler = (FormatHandler) bundleContext.getService(ref);
if (handler.accepts(data, off, len)) {
return handler;
}
bundleContext.ungetService(ref);
}
}
} catch (InvalidSyntaxException e) {
log.warn("Unexpected exception while getting all format handlers.", e);
}
return null;
}
/**
* Return a flag indicating whether the handler is able to handle the Illustrator poastscript file.
*
* @param data data buffer
* @param off offset
* @param len number of valid bytes
* @return true
if the handler is able to handle the data; false
otherwise
*/
private boolean isAIFile(byte[] data, int off, int len){
// Is this stream a PDF data stream?
// See if you can find the PDF marker in the first 1024 bytes.
// see PDF 1.5, Appendix H, note 13
byte[]pdfMarker = {'%', 'P', 'D', 'F', '-'};
int size = 1024;
if (size > len) size = len;
byte[] header = new byte[size];
System.arraycopy(data, off, header, 0, size);
long result = Utility.KMPFindFirst(pdfMarker, Utility.ComputeKMPNextArray(pdfMarker), header);
return (result >= 0);
}
/**
* Extracts and create sub asset for the asset. For illustrator file, it tries to extract the subassets,
* for application/postscript files generated from other applications, it is a no-op
*
*/
public List processSubAssets(final Asset asset) {
InputStream in = null;
try {
in = asset.getOriginal().getStream();
PushbackInputStream pin = new PushbackInputStream(in, MAGIC_SIZE);
byte[] data = new byte[MAGIC_SIZE];
int len;
try {
// prefetch some bytes to find correct handler
if ((len = pin.read(data)) <= 0) {
// no content
return null;
}
pin.unread(data, 0, len);
//check if it is an isAIFile with application/postscript as mimetype
if (isAIFile(data, 0, len)) {
return super.processSubAssets(asset);
}
} catch (IOException e) {
log.warn("I/O error while getting processing subassets.", e);
}
} finally {
IOUtils.closeQuietly(in);
}
// noop
log.debug("processSubAssets: no subassets to process for asset [{}].", asset.getPath());
return new ArrayList();
}
public Iterator extends AssetRelation> processRelated(final Asset asset) {
return childRefResolver.resolve(asset);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy