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
When I install the package in AEM 6.2 I don't see the step in the "Process" list.
ReplyDeletehttp://screencast.com/t/nxm59m6mc
http://screencast.com/t/dwwOMtLGu