AEM 61 - Extract Illustrator Artboards as PDF Assets in DAM Update Asset Workflow

Goal


Add a workflow step in DAM Update Asset workflow to extract the Artboards of an Illustrator file and save them as PDFs. For ootb extraction and page viewer check documentation

Demo | Package Install | Source code

Thanks to my fantastic Adobe colleagues for code snippets


Artboards in Illustrator 



Artboards extracted as AEM PDF Assets



Solution


1) Create a workflow Process Step apps.experienceaem.pdf.CreatePDFRendition and add the code below

package apps.experienceaem.pdf;

import com.adobe.internal.io.ByteReader;
import com.adobe.internal.io.ByteWriter;
import com.adobe.internal.io.InputStreamByteReader;
import com.adobe.internal.io.RandomAccessFileByteWriter;
import com.adobe.internal.pdftoolkit.core.exceptions.PDFException;
import com.adobe.internal.pdftoolkit.pdf.document.PDFDocument;
import com.adobe.internal.pdftoolkit.pdf.document.PDFOpenOptions;
import com.adobe.internal.pdftoolkit.pdf.document.PDFSaveFullOptions;
import com.adobe.internal.pdftoolkit.pdf.page.PDFPage;
import com.adobe.internal.pdftoolkit.pdf.page.PDFPageTree;
import com.adobe.internal.pdftoolkit.services.manipulations.PMMOptions;
import com.adobe.internal.pdftoolkit.services.manipulations.PMMService;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.AssetManager;
import com.day.cq.dam.commons.util.DamUtil;
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.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.*;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.Session;
import java.io.*;

@Component
@Service
@Properties({@Property(name = "process.label", value = "Experience AEM - Generate PDF Assets Process")})
public class CreatePDFRendition implements WorkflowProcess {
    private static final Logger log = LoggerFactory.getLogger(CreatePDFRendition.class);

    @Reference(policy = ReferencePolicy.STATIC)
    private JcrResourceResolverFactory jcrResolverFactory;

    public void execute(WorkItem workItem, WorkflowSession workflowSession,
                        MetaDataMap metaDataMap) throws WorkflowException {
        long startTime = System.currentTimeMillis();

        Asset asset = getAssetFromPayload(workItem, workflowSession.getSession());

        try{
            if(asset != null && asset.getName().endsWith(".ai")){
                addPDFRendition(asset);
            }
        }catch(Exception e){
            log.warn("Error generating pdf", e);
        }

        long endTime = System.currentTimeMillis();

        log.info("CreatePDFRendition took {} seconds" , (endTime - startTime) / 1000);
    }

    private void addPDFRendition(Asset asset) throws Exception{
        File tmpFile = null;
        ByteWriter tmpFileWriter = null;

        FileInputStream tmpFileReader = null;
        InputStream assetOrigIS = null;

        PDFDocument pdfDocument = null;
        PDFDocument vectorFile = null;
        PDFPage pdfPage = null;

        try {
            assetOrigIS = asset.getOriginal().getStream();

            vectorFile = parseDocument(assetOrigIS);

            PMMService pmmService = new PMMService(vectorFile);

            PDFPageTree pages = vectorFile.requirePages();

            int count = pages.getCount();

            for(int i = 0; i < count; i++){
                pdfPage = pages.getPage(i);

                pdfDocument = pmmService.extractPages(pdfPage, 1,
                        PMMOptions.newInstance(PMMOptions.AllOptions),
                        PDFOpenOptions.newInstance());

                tmpFile = File.createTempFile(asset.getName(), ".pdf");

                tmpFileWriter = getTempFileWriter(tmpFile);

                pdfDocument.save(tmpFileWriter, PDFSaveFullOptions.newInstance());

                tmpFileWriter.close();

                tmpFileReader = new FileInputStream(tmpFile);

                AssetManager assetMgr = asset.getOriginal().getResourceResolver()
                        .adaptTo(AssetManager.class);

                String folder = asset.adaptTo(Node.class).getParent().getPath();

                assetMgr.createAsset( folder + "/" + asset.getName() + "-"
                        + pdfPage.getPageNumber() + ".pdf",
                        tmpFileReader, "application/pdf", true);

                pdfDocument.close();
                tmpFileWriter.close();
                tmpFileReader.close();
            }
        }catch(Exception e){
            log.warn("Error generating pdf for - " + asset.getPath(), e);
        }finally{
            if (pdfDocument != null) {
                pdfDocument.close();
            }

            if (tmpFileWriter != null) {
                tmpFileWriter.close();
            }

            if(tmpFileReader !=null ){
                tmpFileReader.close();
            }

            if(assetOrigIS != null){
                assetOrigIS.close();
            }
        }
    }

    private static PDFDocument parseDocument(InputStream input) throws Exception {
        ByteReader byteReader = null;
        PDFDocument pdfDoc = null;

        byteReader = new InputStreamByteReader(input);

        try {
            pdfDoc = PDFDocument.newInstance(byteReader, PDFOpenOptions.newInstance());
        } catch (PDFException e) {
            log.warn("Error while reading vector file", e);
            throw e;
        }

        return pdfDoc;
    }

    private ByteWriter getTempFileWriter(File file) throws IOException {
        file.delete();

        File parent = file.getParentFile();

        if (parent != null) {
            parent.mkdirs();
        }

        file.createNewFile();

        return new RandomAccessFileByteWriter(new RandomAccessFile(file, "rw"));
    }

    private Asset getAssetFromPayload(WorkItem item, Session session) {
        Asset asset = null;

        if(item.getWorkflowData().getPayloadType().equals("JCR_PATH")) {
            String path = item.getWorkflowData().getPayload().toString();
            Resource resource = getResourceResolver(session).getResource(path);

            if(null != resource) {
                asset = DamUtil.resolveToAsset(resource);
            } else {
                log.error("getAssetFromPaylod: asset [{}] in payload of workflow [{}] does not exist.", path, item.getWorkflow().getId());
            }
        }

        return asset;
    }

    private ResourceResolver getResourceResolver(final Session session) {
        return jcrResolverFactory.getResourceResolver(session);
    }
}


2) #85 to #106 loop through pages, write the page stream to a temp file and create pdf asset by reading from the temp file

3) For compilation, Gibson libraries (com.adobe.internal.pdftoolkit) are not available on Adobe public maven repo Nexus; so create a private repo - eaemrepo and add the location in repositories section of project pom.xml (the jars can be found in CQ install eg. author\crx-quickstart\launchpad\felix\bundle446\data\install\pdfcore-3.0.568820.jar or you can get them from this sample's source code)

    <repositories>
        <repository>
            <id>eaemrepo</id>
            <name>Experience AEM Internal Repo</name>
            <url>file://${project.basedir}/../libs</url>
        </repository>

        <repository>
            <id>adobe</id>
            <name>Adobe Public Repository</name>
            <url>http://repo.adobe.com/nexus/content/groups/public/</url>
            <layout>default</layout>
        </repository>
    </repositories>


4) Add the Process step apps.experienceaem.pdf.CreatePDFRendition to DAM Update Asset workflow. For demonstration purposes, the workflow step was added to ootb DAM Update Asset workflow (/etc/workflow/models/dam/update_asset), but in real world it is always recommended to copy and create a new workflow model for adding any additional workflow steps




1 comment:

  1. When I install the package in AEM 6.2 I don't see the step in the "Process" list.
    http://screencast.com/t/nxm59m6mc
    http://screencast.com/t/dwwOMtLGu

    ReplyDelete