Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.day.cq.dam.core.process.WaterMarkProcess Maven / Gradle / Ivy
package com.day.cq.dam.core.process;
import com.day.cq.commons.ImageHelper;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.commons.process.AbstractAssetWorkflowProcess;
import com.day.cq.dam.commons.util.DamUtil;
import com.day.cq.dam.commons.util.MemoryUtil;
import com.day.cq.dam.commons.watermark.*;
import com.day.cq.dam.commons.watermark.Font;
import com.day.cq.i18n.I18n;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.metadata.MetaDataMap;
import com.day.image.Layer;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.*;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.commons.mime.MimeTypeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.IIOException;
import javax.jcr.*;
import javax.jcr.version.VersionManager;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
*
*/
@Component(metatype = false)
@Service
@Property(name = "process.label", value = "Image Watermarking Process")
public class WaterMarkProcess extends AbstractAssetWorkflowProcess {
/**
* Logger instance for this class.
*/
private static final Logger log = LoggerFactory.getLogger(WaterMarkProcess.class);
private static final String WATERMARKED_RENDITION_NAME = "cq.dam.wm.";
/**
* The available arguments to this process implementation.
*/
public enum Arguments {
PROCESS_ARGS("PROCESS_ARGS"),
TEXT("text"),
SIZE("size"),
COLOR("color"),
POSITION("position"),
OPACITY("opacity"),
ARCHIVE("archive"),
IMAGE("image"),
ORIENTATION("orientation"),
FONT("font"),
VERTICAL("vertical"),
USE_METADATA("useMetadata");
private String argumentName;
Arguments(String argumentName) {
this.argumentName = argumentName;
}
public String getArgumentName() {
return this.argumentName;
}
public String getArgumentPrefix() {
return this.argumentName + ":";
}
}
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaData) throws WorkflowException {
String[] args = buildArguments(metaData);
final Session session = workflowSession.getSession();
final Asset wfAsset = getAssetFromPayload(workItem, session);
Iterator assets = null;
List assetsList = new ArrayList();
//Terminate the process if asset not found in workflow item payload
if (wfAsset == null) {
String wfPayload = workItem.getWorkflowData().getPayload().toString();
try {
final Resource resource = getResourceResolver(workflowSession.getSession()).getResource(wfPayload);
if (null != resource) {
assets = DamUtil.getAssets(resource);
}
}
catch(Exception e) {
String message = "execute: cannot create web enabled image, asset [{" + wfPayload + "}] in payload doesn't exist for workflow [{" + workItem.getId() + "}].";
throw new WorkflowException(message);
}
}
else {
assetsList.add(wfAsset);
assets = assetsList.iterator();
}
if(assets != null) {
while (assets.hasNext()) {
Asset asset = assets.next();
try {
if (isWatermarkable(asset)) {
//Check if system resources can load asset image into memory
if (MemoryUtil.hasEnoughSystemMemory(asset)) {
// retry to load image if there is not enough memory
// currently
// available.
// did not find a more elegant solution by now...
boolean isLoaded = false;
long maxTrials = 100;
while (!isLoaded && maxTrials > 0) {
try {
log.info("Begin water marking [{}]", asset.getName());
createWatermark(workflowSession, asset, args);
isLoaded = true;
} catch (Exception e) {
if (e instanceof IIOException && e.getMessage().contains("Not enough memory")) {
isLoaded = false;
maxTrials--;
log.debug("execute: insufficient memory, reloading image. Free mem [{}]. Asset [{}].",
Runtime.getRuntime().freeMemory(), asset.getPath());
// sleep at least 1250ms and maximal 3750ms
Thread.sleep((long) (2500 * (Math.random() + 0.5)));
} else {
log.error("execute: error while watermarking image for [{}]: ", asset.getPath(), e);
throw new WatermarkingException(e.getMessage());
}
}
}
if (maxTrials == 0) {
log.warn("execute: failed creating thumbnails, insufficient memory even after [{}] trials for [{}].",
100, asset.getPath());
}
} else {
log.warn(
"execute: failed loading image, insufficient memory. Increase heap size up to [{}bytes] for asset [{}].",
MemoryUtil.suggestMaxHeapSize(asset), asset.getPath());
}
}
else {
log.info("not supporting watermarking of any asset other than images. no-op.");
}
} catch (Exception e) {
log.error("execute: error while watermarking asset; work item [{}]: ", workItem.getId(), e);
log.error(e.getMessage());
throw new WorkflowException(e);
}
}
}
}
// ------------< helpers >--------------------------------------------------
/**
* Currently only images can be watermarked.
*
* @param asset
* @return
*/
private boolean isWatermarkable(Asset asset) {
String assetMimeType = asset.getMimeType();
return assetMimeType.contentEquals("image/jpeg") || assetMimeType.contentEquals("image/png");
}
private void createWatermark(WorkflowSession workflowSession, Asset asset, String[] args) throws WatermarkingException {
final Rendition original = asset.getOriginal();
Node assetNode = null;
Layer layer = ImageHelper.createLayer(original);
// if image is still null, try with web rendition. it can be
// null in cases where the original is not image
if (layer == null) {
layer = ImageHelper.createLayer(getThumbnail(asset));
}
if(layer == null) {
throw new WatermarkingException("Unable to create layer from asset image");
}
//-----------------------------------------Begin processing parameters-------------------------------//
String text = TextWatermark.COPYRIGHT;
int size = Font.DEFAULT_SIZE;
Color color = Font.DEFAULT_COLOR;
Location position = Watermark.DEFAULT_LOCATION;
float opacity = Watermark.DEFAULT_OPACITY;
boolean archive = false;
double orientation = Watermark.DEFAULT_ORIENTATION;
String font = Font.DEFAULT_FAMILY;
boolean vertical = false;
boolean useMetadata = true;
//extract process parameters from args
List values = getValuesFromArgs(Arguments.TEXT.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
text = values.get(0);
}
else {
//throw new WatermarkingException("Watermarking TEXT missing");
}
values = getValuesFromArgs(Arguments.SIZE.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
try {
size = Integer.parseInt(values.get(0));
} catch (NumberFormatException e) {
log.warn("Invalid value for font size. Using default {}.");
}
}
values = getValuesFromArgs(Arguments.COLOR.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
try {
//Generate java color object from Hex code
color = Color.decode("0x"+values.get(0));
} catch (NumberFormatException e) {
log.warn("Invalid value for font color. Using default {}.", color);
}
}
values = getValuesFromArgs(Arguments.POSITION.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
try {
position = Location.valueOf(values.get(0));
} catch (IllegalArgumentException e) {
log.warn("Invalid value for watermark position. Using default {}.", position.name());
}
}
values = getValuesFromArgs(Arguments.OPACITY.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
try {
opacity = Float.parseFloat(values.get(0))/100;
} catch (NumberFormatException e) {
log.warn("Invalid value for watermark opacity. Using default {}.", opacity);
}
}
values = getValuesFromArgs(Arguments.ARCHIVE.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
archive = Boolean.parseBoolean(values.get(0));
}
values = getValuesFromArgs(Arguments.ORIENTATION.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
try {
orientation = Double.parseDouble(values.get(0));
} catch (NumberFormatException e) {
log.warn("Invalid value for watermark orientation. Using default {}.", orientation);
}
}
values = getValuesFromArgs(Arguments.FONT.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
font = values.get(0);
}
values = getValuesFromArgs(Arguments.VERTICAL.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
vertical = Boolean.parseBoolean(values.get(0));
}
values = getValuesFromArgs(Arguments.USE_METADATA.getArgumentName(), args);
if(values != null && !values.isEmpty()) {
useMetadata = Boolean.parseBoolean(values.get(0));
}
//-----------------------------------------Finish processing parameters-------------------------------//
//create a watermark object using process params and payload metadata
TextWatermark watermark = new TextWatermark(position, orientation, opacity, text, new Font(size, color, font));
watermark.setVertical(vertical);
//check metadata for existing watermark text
try {
assetNode = workflowSession.getSession().getNode(asset.getPath());
Node metadataNode = assetNode.getNode("jcr:content/metadata");
Value copyright = metadataNode.getProperty("dc:rights").getValue();
if(useMetadata && copyright != null) {
watermark.setText(copyright.getString());
}
} catch (RepositoryException e) {
log.debug("asset [{}] does not have metadata field dc:rights", asset.getPath());
}
// create a new version
try {
if (assetNode.isLocked()) {
log.warn("Version can't be created for the asset ["
+ asset.getPath() + "] as the asset is locked");
} else {
getAssetManager(workflowSession.getSession()).createRevision(
asset, "before_watermarking", "");
}
} catch (Exception e) {
log.debug("error creating version for asset [{}]", asset.getPath());
throw new WatermarkingException(e);
}
log.info("applying text water mark");
//Apply a text watermark on original
WatermarkContext ctx = new WatermarkContext(layer, watermark);
WatermarkUtil.applyWatermark(ctx);
final String mimeType = asset.getMimeType();
String renditionName = "original";
if(archive) {
//Save watermarked image as a new rendition
renditionName = WATERMARKED_RENDITION_NAME + mimeTypeService.getExtension(mimeType);
log.info("saving watermarked image for asset [{}] as rendition [{}]", asset.getPath(), renditionName);
}
else {
//Overwrite original with watermarked image
log.info("saving watermarked image in original node [{}]", asset.getOriginal().getPath());
}
//save watermarked rendition
saveWatermarked(layer, asset, mimeType, renditionName);
//update metadata - add watermarking text to String[] dc:rights
log.info("Adding [{}] to dc:rights metadata.", text);
try {
Node metadataNode = null;
metadataNode = assetNode.getNode("jcr:content/metadata");
Value copyright = workflowSession.getSession().getValueFactory().createValue(text);
metadataNode.setProperty("dc:rights", copyright);
workflowSession.getSession().save();
} catch (RepositoryException e) {
log.debug("error while attempting to update metadata [{}]", e);
throw new WatermarkingException(e);
}
}
private void saveWatermarked(Layer layer, Asset asset, String mimeType, String renditionName) throws WatermarkingException {
double quality = mimeType.equals("image/gif") ? 255 : 1.0;
try {
Node parentNode = asset.getOriginal().adaptTo(Node.class).getParent();
ImageHelper.saveLayer(layer, mimeType, quality, parentNode, renditionName, true);
log.info("saved watermarked image in node [{}]", asset.getRendition(renditionName).getPath());
} catch (RepositoryException e) {
log.debug("error while saving watermarked image for asset [{}] ", asset.getName(), e);
throw new WatermarkingException(e);
} catch (IOException e) {
log.debug("error while saving watermarked image for asset [{}] ", asset.getName(), e);
throw new WatermarkingException(e);
}
}
private String[] buildArguments(MetaDataMap metaData) {
// the 'old' way, ensures backward compatibility
String processArgs = metaData.get(Arguments.PROCESS_ARGS.name(), String.class);
if (processArgs != null && !processArgs.equals("")) {
return processArgs.split(",");
}
// the 'new' way
else {
List arguments = new ArrayList();
for(Arguments arg : Arguments.values()) {
String argName = arg.getArgumentName();
String argValue = metaData.get(argName, String.class);
if (StringUtils.isNotBlank(argValue)) {
StringBuilder builder = new StringBuilder(arg.getArgumentPrefix()).append(argValue);
arguments.add(builder.toString());
}
}
return arguments.toArray(new String[arguments.size()]);
}
}
// get thumbnail, to fix for pdf/non-image or image formats not
private Rendition getThumbnail(Asset asset) {
Rendition rendition = asset.getRendition(DamUtil.getThumbnailName(319, 319));
if (rendition == null) {
return asset.getOriginal();
} else {
return rendition;
}
}
}