"DAM Update Asset" is a default workflow which is triggered whenever any asset is uploaded into the DAM. This workflow helps to limit the size and the quality of the image displayed.
Why Image Renditions are required:
- Using different size images on the websites.
- Images for different devices or viewPort.
- Reducing the page load time.
Existing Workflow Scenario:
Steps to create Custom Rendition:
- Go to the "DAM update asset" workflow
- Select "Process Thumbnails" Step.
Fig- Select and edit the Process Thumbnail Step |
- Add custom renditions as per your requirements
Fig - Add the Size of Rendition in Thumbnail Multifield |
Cropping:
To achieve this, follow below steps:
- Add Custom process(Rendition Image Cropping) step after “Process Thumbnail”.
- Edit the Rendition Image Cropping process step.
- Select the Process Tab.
- Add the WorkFlow Process (Image Rendition Cropping Workflow Process).
Fig- Add the New Process Step and Select the Custom Image Rendition Workflow process in the Process Tab |
- In the Process tab Configure the rendition size in Arguments field.
Fig- Configure The rendition size in the Arguments Section |
Example: Let’s suppose the original size of image is "2200*1200" and the required image size is "640*360" .
- Reduce the image from left and right equally ( 780px) to make the width as 640.
- Reduce the image from top and bottom equally ( 420px) to make the height as 320.
Fig- Sample Image showing the cropping concept |
Check the below code for Image Rendition Process:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.aem.sgaem.project.process; | |
import com.adobe.granite.workflow.WorkflowSession; | |
import com.adobe.granite.workflow.exec.WorkItem; | |
import com.adobe.granite.workflow.exec.WorkflowProcess; | |
import com.adobe.granite.workflow.metadata.MetaDataMap; | |
import com.aem.sgaem.project.services.ResourceResolverUtil; | |
import com.aem.sgaem.project.utils.StringUtil; | |
import com.day.cq.commons.ImageHelper; | |
import com.day.image.Layer; | |
import java.awt.Rectangle; | |
import java.util.List; | |
import javax.jcr.Node; | |
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.Service; | |
import org.apache.sling.api.resource.Resource; | |
import org.apache.sling.api.resource.ResourceResolver; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
@Component(immediate = true, enabled = true, metatype = true) | |
@Service(value = WorkflowProcess.class) | |
@Property(name = "process.label", value = "Cropping Image Rendition Process", propertyPrivate = true) | |
public class ImageRenditionProcess implements WorkflowProcess { | |
private static final String PROCESS_ARGS = "PROCESS_ARGS"; | |
private static final String EMPTY = ""; | |
private static final String JCR_CONTENT = "/jcr:content"; | |
private static final String CQ5_DAM_THUMBNAIL = "cq5dam.thumbnail."; | |
private static final String JPEG_EXTENSION = ".jpeg"; | |
private static final String JPEG_MIME_TYPE = "image/jpeg"; | |
private final Logger LOGGER = LoggerFactory.getLogger(ImageRenditionProcess.class); | |
@Reference | |
private ResourceResolverUtil resourceResolverUtil; | |
private int requiredWidth; | |
private int requiredHeight; | |
private int originalWidth; | |
private int originalHeight; | |
private int cropWidth; | |
private int cropHeight; | |
/* This execute method crop the images as per the workflow Arguments */ | |
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap metaDataMap) { | |
LOGGER.debug("START OF execute METHOD"); | |
ResourceResolver resourceResolver = resourceResolverUtil.getResourceResolver(); | |
String payload = workItem.getWorkflowData().getPayload().toString(); | |
String processArgument = metaDataMap.get(PROCESS_ARGS, EMPTY); | |
Resource dataResource = resourceResolver.getResource(payload + JCR_CONTENT); | |
if (dataResource != null) { | |
Resource parentOfParentRes = getExactParent(dataResource, 2); | |
if (parentOfParentRes != null) { | |
Node node = parentOfParentRes.adaptTo(Node.class); | |
if (node != null) { | |
Double quality = 90.0; | |
try { | |
if (!EMPTY.equals(processArgument)) { | |
List<String> args = StringUtil.splitWithNewLine(processArgument); | |
for (String arg : args) { | |
Layer originalLayer = ImageHelper.createLayer(dataResource); | |
ImageHelper.saveLayer(getLayer(originalLayer, payload, arg), JPEG_MIME_TYPE, | |
quality, node, CQ5_DAM_THUMBNAIL + arg + JPEG_EXTENSION, true); | |
} | |
} | |
} catch (Exception exception) { | |
LOGGER.error(exception.getCause().toString()); | |
} finally { | |
resourceResolverUtil.closeResourceResolver(resourceResolver); | |
} | |
} | |
} | |
} | |
LOGGER.debug("END OF execute METHOD"); | |
} | |
private Layer getLayer(Layer layer, String payload, String size) { | |
LOGGER.debug("START OF getLayer METHOD"); | |
String[] splitSize = size.split("\\."); | |
requiredWidth = (EMPTY).equals(splitSize[0]) ? 0 : Integer.parseInt(splitSize[0]); | |
requiredHeight = (EMPTY).equals(splitSize[1]) ? 0 : Integer.parseInt(splitSize[1]); | |
originalWidth = layer.getWidth(); | |
originalHeight = layer.getHeight(); | |
requiredWidth = originalWidth > requiredWidth ? requiredWidth : originalWidth; | |
requiredHeight = originalHeight > requiredHeight ? requiredHeight : originalHeight; | |
cropWidth = originalWidth > requiredWidth ? (originalWidth - requiredWidth) / 2 : 0; | |
cropHeight = originalHeight > requiredHeight ? (originalHeight - requiredHeight) / 2 : 0; | |
if (originalWidth > requiredWidth || originalHeight > requiredHeight) { | |
layer = cropImage(layer, payload); | |
} | |
LOGGER.debug("END OF getLayer METHOD"); | |
return layer; | |
} | |
private Layer cropImage(Layer layer, String payload) { | |
LOGGER.debug("START OF cropImage METHOD"); | |
String rectCSV = "0,0," + (requiredWidth + cropWidth) + "," + (requiredHeight + cropHeight); | |
Rectangle rect = ImageHelper.getCropRect(rectCSV, payload); | |
layer.crop(rect); | |
layer.rotate(180.00); | |
rectCSV = "0,0," + requiredWidth + "," + requiredHeight; | |
rect = ImageHelper.getCropRect(rectCSV, payload); | |
layer.crop(rect); | |
layer.rotate(180.00); | |
LOGGER.debug("END OF cropImage METHOD"); | |
return layer; | |
} | |
private Resource getExactParent(Resource resource, int level) { | |
for (int i = 0; i < level; i++) { | |
resource = resource.getParent(); | |
} | |
return resource; | |
} | |
} |
You can see all the renditions like this:
Fig - Renditions Created Under Dam Hierarchy |
Demo Video:
You can install the package directly from here.
find the Git Repository
find the Git Repository
Mail us at sgaem.blog02@gmail.comg for any query or suggestion.
Hope it will help you guys !!👍
Thanks and Happy Learning 😊