WebP Support for AEM On Prem
Working with enterprise CMS like AEM often means balancing between business requirements and platform limitations. Recently , I encountered a scenario where the client needed support for WebP images in the authoring interface.
WebP is a modern image format developed by Google that provides superior lossy and lossless compression for images on the web. The goal of WebP is to create smaller, faster-loading images without sacrificing quality, making it ideal for websites and mobile applications.
When you drag and drop a DAM asset (like a JPEG or PNG) into the OOTB Image component:
- AEM references the original DAM asset, and does not create a new image.
- Renditions (e.g., cq5dam.thumbnail.319.319.png) are automatically created if they don’t already exist.
When you drag and drop a WebP image into the OOTB Image component in AEM, the behavior differs because AEM 6.5 (and earlier) does not support WebP out of the box.
- No renditions are generated automatically for Webp.
- Thumbnail /review in DAM UI is not shown.
However ,To bridge this gap, I developed a custom utility that enables WebP image handling within AEM 6.5, making it seamless for content authors to work with this format.To refer the list of supported images format , please refer the link below
https://experienceleague.adobe.com/en/docs/experience-manager-65/content/assets/administer/assets-formats.
Lets dive into the steps involved to write this custom utility .
Steps –
- Adding 3rd Party Plugins
There are many third party plugins available which can be added to support webp images , we will be using Twelve Monkeys ImageIO plugin in the implementation , which provides extended support for image file formats in Java Platform.
../pom.xml
<dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-core</artifactId> <version>3.10.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-webp</artifactId> <version>3.10.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.twelvemonkeys.imageio</groupId> <artifactId>imageio-psd</artifactId> <version>3.10.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>jmagick</groupId> <artifactId>jmagick</artifactId> <version>6.6.9</version> <scope>provided</scope> </dependency>

bundle with listed dependencies
2. Adding the logic to read webp images and generate renditions of different sizes.
The program can be created in form of :
1. Custom Process Step – Workflow
2. OSGI Service/Servlet
3. or, incorporated with Event Listener
In this blog ,AEM listeners listens/works for any dam asset upload of webp format image and generates the renditions of sizes as per requirement. Content Fragment is used to take inputs for rendition sizes.
Created below is the Event Listener to listen to the event of assets uploaded in the dam.
@Activate @Override public void onEvent(EventIterator events) { try { Map<String, Object> authInfo = Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "getResourceResolver");
try (ResourceResolver resourceResolver = resolverFactory.getServiceResourceResolver(authInfo)) { if (!isListenerEnabled(resourceResolver)) { log.info("WebPAssetListener is disabled via configuration."); return; } List<String> renditionSizes = getRenditionSizes(resourceResolver); while (events.hasNext()) { Event event = events.nextEvent(); String path = event.getPath(); try { webPAssetsRenditionService.generateRenditions(asset, renditionSizes,resourceResolver); log.info("Successfully generated renditions for WebP asset: {}", path); } catch (Exception e) { log.error("Error generating renditions for WebP asset: {}", path, e); } } } } catch (Exception e) { log.error("Error in WebPAssetListener", e); } }
You can generate assets with WebP Image format of different sizes which can be added from any configurable space like a content fragment .
private List<String> getRenditionSizes(ResourceResolver resourceResolver) { Resource configResource = resourceResolver.getResource(ASSET_LISTENER_CONFIGURATION); if (configResource != null) { String[] sizes = configResource.getValueMap().get(RENDITION_SIZES, String[].class); return sizes != null ? Arrays.asList(sizes) : Collections.emptyList(); } return Collections.emptyList(); } }

content fragment to input rendition values
Below is the WebPAssetsRenditionService Implementation where you can add below functionality to generate WebP format Images of the asset uploaded in DAM.
@Activate protected void activate() { IIORegistry registry = IIORegistry.getDefaultInstance(); registry.registerServiceProvider(new WebPImageReaderSpi()); LOGGER.info("WebP Image Reader registered successfully"); }
- IIORegistry registry = IIORegistry.getDefaultInstance();
This gets the default instance of the IIORegistry, which is essentially a registry/database of available image readers, writers, and other services in Java’s Image I/O system. - registry.registerServiceProvider(new WebPImageReaderSpi());
This gets the default instance of the IIORegistry, which is essentially a registry/database of available image readers, writers, and other services in Java’s Image I/O system.
@Override public void generateRenditions(Asset asset, List<String> renditionSizes, ResourceResolver resourceResolver) throws Exception { BufferedImage originalImage; try (InputStream is = asset.getOriginal().getStream()) { originalImage = ImageIO.read(is); } if (originalImage == null) { throw new IOException("Failed to read WebP image"); } for (String size : renditionSizes) { String[] dimensions = size.split(":"); if (dimensions.length != 2) { LOGGER.warn("Invalid size format: {}. Skipping this rendition.", size); continue; } int width = Integer.parseInt(dimensions[0]); int height = Integer.parseInt(dimensions[1]); generateRendition(asset, originalImage, width, height); resourceResolver.commit(); }
Add rendition to the asset by following Logic-
private void generateRendition(Asset asset, BufferedImage originalImage, int width, int height) throws Exception { String renditionName = String.format("cq5dam.thumbnail.%d.%d.png", width, height); BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); resizedImage.createGraphics().drawImage(originalImage.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH), 0, 0, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(resizedImage, "PNG", baos); try (InputStream pngInputStream = new ByteArrayInputStream(baos.toByteArray())) { asset.addRendition(renditionName, pngInputStream, PNG_MIME_TYPE); } LOGGER.info("Generated rendition: {} for asset: {}", renditionName, asset.getPath()); } }
Conclusion-
Basis the above implementation, the renditions are available for webp images, Please find below the screenshots –

result

result