WaterMarkProcess.java 17.4 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.ImageHelper
 *  com.day.cq.dam.api.Asset
 *  com.day.cq.dam.api.AssetManager
 *  com.day.cq.dam.api.Rendition
 *  com.day.cq.dam.api.Revision
 *  com.day.cq.dam.commons.process.AbstractAssetWorkflowProcess
 *  com.day.cq.dam.commons.util.DamUtil
 *  com.day.cq.dam.commons.util.MemoryUtil
 *  com.day.cq.dam.commons.watermark.Font
 *  com.day.cq.dam.commons.watermark.Location
 *  com.day.cq.dam.commons.watermark.TextWatermark
 *  com.day.cq.dam.commons.watermark.Watermark
 *  com.day.cq.dam.commons.watermark.WatermarkContext
 *  com.day.cq.dam.commons.watermark.WatermarkUtil
 *  com.day.cq.dam.commons.watermark.WatermarkingException
 *  com.day.cq.workflow.WorkflowException
 *  com.day.cq.workflow.WorkflowSession
 *  com.day.cq.workflow.exec.WorkItem
 *  com.day.cq.workflow.exec.WorkflowData
 *  com.day.cq.workflow.metadata.MetaDataMap
 *  com.day.image.Layer
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Value
 *  javax.jcr.ValueFactory
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.commons.mime.MimeTypeService
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.dam.core.process;

import com.day.cq.commons.ImageHelper;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.Revision;
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.Font;
import com.day.cq.dam.commons.watermark.Location;
import com.day.cq.dam.commons.watermark.TextWatermark;
import com.day.cq.dam.commons.watermark.Watermark;
import com.day.cq.dam.commons.watermark.WatermarkContext;
import com.day.cq.dam.commons.watermark.WatermarkUtil;
import com.day.cq.dam.commons.watermark.WatermarkingException;
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.metadata.MetaDataMap;
import com.day.image.Layer;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.IIOException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
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.commons.mime.MimeTypeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=0)
@Service
@org.apache.felix.scr.annotations.Property(name="process.label", value={"Image Watermarking Process"})
public class WaterMarkProcess
extends AbstractAssetWorkflowProcess {
    private static final Logger log = LoggerFactory.getLogger(WaterMarkProcess.class);
    private static final String WATERMARKED_RENDITION_NAME = "cq.dam.wm.";

    /*
     * Unable to fully structure code
     * Enabled aggressive exception aggregation
     */
    public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaData) throws WorkflowException {
        args = this.buildArguments(metaData);
        session = workflowSession.getSession();
        wfAsset = this.getAssetFromPayload(workItem, session);
        assets = null;
        assetsList = new ArrayList<Asset>();
        if (wfAsset == null) {
            wfPayload = workItem.getWorkflowData().getPayload().toString();
            try {
                resource = this.getResourceResolver(workflowSession.getSession()).getResource(wfPayload);
                if (null == resource) ** GOTO lbl18
                assets = DamUtil.getAssets((Resource)resource);
            }
            catch (Exception e) {
                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();
        }
lbl18: // 3 sources:
        if (assets != null) {
            while (assets.hasNext()) {
                asset = (Asset)assets.next();
                try {
                    if (this.isWatermarkable(asset)) {
                        if (MemoryUtil.hasEnoughSystemMemory((Asset)asset)) {
                            isLoaded = false;
                            maxTrials = 100;
                            while (!isLoaded && maxTrials > 0) {
                                try {
                                    WaterMarkProcess.log.info("Begin water marking [{}]", (Object)asset.getName());
                                    this.createWatermark(workflowSession, asset, args);
                                    isLoaded = true;
                                    continue;
                                }
                                catch (Exception e) {
                                    if (e instanceof IIOException && e.getMessage().contains("Not enough memory")) {
                                        isLoaded = false;
                                        --maxTrials;
                                        WaterMarkProcess.log.debug("execute: insufficient memory, reloading image. Free mem [{}]. Asset [{}].", (Object)Runtime.getRuntime().freeMemory(), (Object)asset.getPath());
                                        Thread.sleep((long)(2500.0 * (Math.random() + 0.5)));
                                        continue;
                                    }
                                    WaterMarkProcess.log.error("execute: error while watermarking image for [{}]: ", (Object)asset.getPath(), (Object)e);
                                    throw new WatermarkingException(e.getMessage());
                                }
                            }
                            if (maxTrials != 0) continue;
                            WaterMarkProcess.log.warn("execute: failed creating thumbnails, insufficient memory even after [{}] trials for [{}].", (Object)100, (Object)asset.getPath());
                            continue;
                        }
                        WaterMarkProcess.log.warn("execute: failed loading image, insufficient memory. Increase heap size up to [{}bytes] for asset [{}].", (Object)MemoryUtil.suggestMaxHeapSize((Asset)asset), (Object)asset.getPath());
                        continue;
                    }
                    WaterMarkProcess.log.info("not supporting watermarking of any asset other than images. no-op.");
                    continue;
                }
                catch (Exception e) {
                    WaterMarkProcess.log.error("execute: error while watermarking asset; work item [{}]: ", (Object)workItem.getId(), (Object)e);
                    WaterMarkProcess.log.error(e.getMessage());
                    throw new WorkflowException((Throwable)e);
                }
            }
        }
    }

    private boolean isWatermarkable(Asset asset) {
        return DamUtil.isImage((Asset)asset);
    }

    private void createWatermark(WorkflowSession workflowSession, Asset asset, String[] args) throws WatermarkingException {
        Rendition original = asset.getOriginal();
        Node assetNode = null;
        Layer layer = ImageHelper.createLayer((Resource)original);
        if (layer == null) {
            layer = ImageHelper.createLayer((Resource)this.getThumbnail(asset));
        }
        if (layer == null) {
            throw new WatermarkingException("Unable to create layer from asset image");
        }
        String text = "\u00a9";
        int size = 48;
        Color color = Font.DEFAULT_COLOR;
        Location position = Watermark.DEFAULT_LOCATION;
        float opacity = 0.2f;
        boolean archive = false;
        double orientation = 0.0;
        String font = "Serif";
        boolean vertical = false;
        boolean useMetadata = true;
        List values = this.getValuesFromArgs(Arguments.TEXT.getArgumentName(), args);
        if (values != null && !values.isEmpty()) {
            text = (String)values.get(0);
        }
        if ((values = this.getValuesFromArgs(Arguments.SIZE.getArgumentName(), args)) != null && !values.isEmpty()) {
            try {
                size = Integer.parseInt((String)values.get(0));
            }
            catch (NumberFormatException e) {
                log.warn("Invalid value for font size. Using default {}.");
            }
        }
        if ((values = this.getValuesFromArgs(Arguments.COLOR.getArgumentName(), args)) != null && !values.isEmpty()) {
            try {
                color = Color.decode("0x" + (String)values.get(0));
            }
            catch (NumberFormatException e) {
                log.warn("Invalid value for font color. Using default {}.", (Object)color);
            }
        }
        if ((values = this.getValuesFromArgs(Arguments.POSITION.getArgumentName(), args)) != null && !values.isEmpty()) {
            try {
                position = Location.valueOf((String)((String)values.get(0)));
            }
            catch (IllegalArgumentException e) {
                log.warn("Invalid value for watermark position. Using default {}.", (Object)position.name());
            }
        }
        if ((values = this.getValuesFromArgs(Arguments.OPACITY.getArgumentName(), args)) != null && !values.isEmpty()) {
            try {
                opacity = Float.parseFloat((String)values.get(0)) / 100.0f;
            }
            catch (NumberFormatException e) {
                log.warn("Invalid value for watermark opacity. Using default {}.", (Object)Float.valueOf(opacity));
            }
        }
        if ((values = this.getValuesFromArgs(Arguments.ARCHIVE.getArgumentName(), args)) != null && !values.isEmpty()) {
            archive = Boolean.parseBoolean((String)values.get(0));
        }
        if ((values = this.getValuesFromArgs(Arguments.ORIENTATION.getArgumentName(), args)) != null && !values.isEmpty()) {
            try {
                orientation = Double.parseDouble((String)values.get(0));
            }
            catch (NumberFormatException e) {
                log.warn("Invalid value for watermark orientation. Using default {}.", (Object)orientation);
            }
        }
        if ((values = this.getValuesFromArgs(Arguments.FONT.getArgumentName(), args)) != null && !values.isEmpty()) {
            font = (String)values.get(0);
        }
        if ((values = this.getValuesFromArgs(Arguments.VERTICAL.getArgumentName(), args)) != null && !values.isEmpty()) {
            vertical = Boolean.parseBoolean((String)values.get(0));
        }
        if ((values = this.getValuesFromArgs(Arguments.USE_METADATA.getArgumentName(), args)) != null && !values.isEmpty()) {
            useMetadata = Boolean.parseBoolean((String)values.get(0));
        }
        TextWatermark watermark = new TextWatermark(position, orientation, opacity, text, new Font(size, color, font));
        watermark.setVertical(vertical);
        try {
            Value[] copyrights;
            assetNode = workflowSession.getSession().getNode(asset.getPath());
            Node metadataNode = assetNode.getNode("jcr:content/metadata");
            Property property = metadataNode.getProperty("dc:rights");
            String copyright = null;
            copyright = property.isMultiple() ? ((copyrights = property.getValues()).length > 0 ? copyrights[0].getString() : null) : property.getString();
            if (useMetadata && copyright != null) {
                watermark.setText(copyright);
            }
        }
        catch (RepositoryException e) {
            log.debug("asset [{}] does not have metadata field dc:rights", (Object)asset.getPath());
        }
        try {
            if (assetNode.isLocked()) {
                log.warn("Version can't be created for the asset [" + asset.getPath() + "] as the asset is locked");
            } else {
                this.getAssetManager(workflowSession.getSession()).createRevision(asset, "before_watermarking", "");
            }
        }
        catch (Exception e) {
            log.debug("error creating version for asset [{}]", (Object)asset.getPath());
            throw new WatermarkingException((Throwable)e);
        }
        log.info("applying text water mark");
        WatermarkContext ctx = new WatermarkContext(layer, (Watermark)watermark);
        WatermarkUtil.applyWatermark((WatermarkContext)ctx);
        String mimeType = asset.getMimeType();
        String renditionName = "original";
        if (archive) {
            renditionName = "cq.dam.wm." + this.mimeTypeService.getExtension(mimeType);
            log.info("saving watermarked image for asset [{}] as rendition [{}]", (Object)asset.getPath(), (Object)renditionName);
        } else {
            log.info("saving watermarked image in original node [{}]", (Object)asset.getOriginal().getPath());
        }
        this.saveWatermarked(layer, asset, mimeType, renditionName);
        log.info("Adding [{}] to dc:rights metadata.", (Object)text);
        try {
            Node metadataNode = null;
            Value[] copyrights = null;
            try {
                metadataNode = assetNode.getNode("jcr:content/metadata");
                copyrights = metadataNode.getProperty("dc:rights").getValues();
            }
            catch (RepositoryException e) {
                log.debug("asset [{}] does not have metadata field dc:rights", (Object)asset.getPath());
            }
            if (copyrights == null || copyrights.length == 0) {
                copyrights = new Value[1];
            } else {
                Value[] temp = new Value[copyrights.length + 1];
                System.arraycopy(copyrights, 0, temp, 0, copyrights.length);
                copyrights = temp;
            }
            copyrights[copyrights.length - 1] = workflowSession.getSession().getValueFactory().createValue(text);
            metadataNode.setProperty("dc:rights", copyrights);
            workflowSession.getSession().save();
        }
        catch (RepositoryException e) {
            log.debug("error while attempting to update metadata [{}]", (Throwable)e);
            throw new WatermarkingException((Throwable)e);
        }
    }

    private void saveWatermarked(Layer layer, Asset asset, String mimeType, String renditionName) throws WatermarkingException {
        double quality = mimeType.equals("image/gif") ? 255.0 : 1.0;
        try {
            Node parentNode = ((Node)asset.getOriginal().adaptTo(Node.class)).getParent();
            ImageHelper.saveLayer((Layer)layer, (String)mimeType, (double)quality, (Node)parentNode, (String)renditionName, (boolean)true);
            log.info("saved watermarked image in node [{}]", (Object)asset.getRendition(renditionName).getPath());
        }
        catch (RepositoryException e) {
            log.debug("error while saving watermarked image for asset [{}] ", (Object)asset.getName(), (Object)e);
            throw new WatermarkingException((Throwable)e);
        }
        catch (IOException e) {
            log.debug("error while saving watermarked image for asset [{}] ", (Object)asset.getName(), (Object)e);
            throw new WatermarkingException((Throwable)e);
        }
    }

    private String[] buildArguments(MetaDataMap metaData) {
        String processArgs = (String)metaData.get(Arguments.PROCESS_ARGS.name(), String.class);
        if (processArgs != null && !processArgs.equals("")) {
            return processArgs.split(",");
        }
        ArrayList<String> arguments = new ArrayList<String>();
        for (Arguments arg : Arguments.values()) {
            String argName = arg.getArgumentName();
            String argValue = (String)metaData.get(argName, String.class);
            if (!StringUtils.isNotBlank((String)argValue)) continue;
            StringBuilder builder = new StringBuilder(arg.getArgumentPrefix()).append(argValue);
            arguments.add(builder.toString());
        }
        return arguments.toArray(new String[arguments.size()]);
    }

    private Rendition getThumbnail(Asset asset) {
        Rendition rendition = asset.getRendition(DamUtil.getThumbnailName((int)319, (int)319));
        if (rendition == null) {
            return asset.getOriginal();
        }
        return rendition;
    }

    public static 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;

        private Arguments(String argumentName) {
            this.argumentName = argumentName;
        }

        public String getArgumentName() {
            return this.argumentName;
        }

        public String getArgumentPrefix() {
            return this.argumentName + ":";
        }
    }

}