diff --git a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/ParameterMap.java b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/ParameterMap.java index 5bb84713..d642579a 100644 --- a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/ParameterMap.java +++ b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/ParameterMap.java @@ -61,7 +61,8 @@ private ParameterMap() { } @NotNull - static Map build(@NotNull Asset asset, @NotNull WebOptimizedImageDeliveryParams params) { + static Map build(@NotNull Asset asset, @NotNull WebOptimizedImageDeliveryParams params, + @NotNull WebOptimizedImageDeliveryCropOption cropOption) { String path = asset.getPath(); String seoName = FilenameUtils.getBaseName(asset.getName()); String format = StringUtils.toRootLowerCase(FilenameUtils.getExtension(asset.getName())); @@ -85,7 +86,7 @@ static Map build(@NotNull Asset asset, @NotNull WebOptimizedImag map.put(PARAM_WIDTH, width.toString()); } if (cropDimension != null) { - map.put(PARAM_CROP, createCroppingString(asset, cropDimension)); + map.put(PARAM_CROP, createCroppingString(asset, cropDimension, cropOption)); } if (rotation != null && rotation != 0) { map.put(PARAM_ROTATE, rotation.toString()); @@ -96,13 +97,15 @@ static Map build(@NotNull Asset asset, @NotNull WebOptimizedImag return map; } - private static @NotNull String createCroppingString( - @NotNull Asset asset, - @NotNull CropDimension cropDimension) { - Dimension imageDimension = loadImageDimension(asset); - return imageDimension == null || imageDimension.getWidth() <= 0 || imageDimension.getHeight() <= 0 - ? cropDimension.getCropStringWidthHeight() - : createRelativeCroppingString(imageDimension, cropDimension); + private static @NotNull String createCroppingString(@NotNull Asset asset, @NotNull CropDimension cropDimension, + @NotNull WebOptimizedImageDeliveryCropOption cropOption) { + if (cropOption == WebOptimizedImageDeliveryCropOption.RELATIVE_PARAMETERS) { + Dimension imageDimension = loadImageDimension(asset); + if (imageDimension != null && imageDimension.getWidth() > 0 && imageDimension.getHeight() > 0) { + return createRelativeCroppingString(imageDimension, cropDimension); + } + } + return cropDimension.getCropStringWidthHeight(); } private static @Nullable Dimension loadImageDimension(@NotNull Asset asset) { diff --git a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryCropOption.java b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryCropOption.java new file mode 100644 index 00000000..785d3be2 --- /dev/null +++ b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryCropOption.java @@ -0,0 +1,39 @@ +/* + * #%L + * wcm.io + * %% + * Copyright (C) 2024 wcm.io + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package io.wcm.handler.mediasource.dam.impl.weboptimized; + +/** + * Choose how to calculate/apply cropping parameter when using Web-Optimized image delivery. + */ +public enum WebOptimizedImageDeliveryCropOption { + + /** + * Crop renditions using relative percentage values as parameters (e.g. crop=0.0p,5.0p,100.0p,80.0p), + * based on the original image dimensions. + */ + RELATIVE_PARAMETERS, + + /** + * Crop renditions using absolute pixel values as parameters (e.g. crop=0,10,200,100), + * based on the original image dimensions. + */ + ABSOLUTE_PARAMETERS + +} diff --git a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryService.java b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryService.java index 049c58c3..b8d7370e 100644 --- a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryService.java +++ b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryService.java @@ -36,6 +36,12 @@ public interface WebOptimizedImageDeliveryService { */ boolean isEnabled(); + /** + * Cropping option to use. + * @return Cropping option + */ + WebOptimizedImageDeliveryCropOption getCropOption(); + /** * Get delivery URL for a rendition of an asset. * @param asset Asset diff --git a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImpl.java b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImpl.java index 42b3a604..e2ddd3d2 100644 --- a/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImpl.java +++ b/src/main/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImpl.java @@ -55,16 +55,24 @@ public class WebOptimizedImageDeliveryServiceImpl implements WebOptimizedImageDe description = "Enable support for Web-Optimized Image Delivery (if available).") boolean enabled() default true; + @AttributeDefinition( + name = "Cropping Option", + description = "Use relative cropping parameters (e.g. crop=0.0p,5.0p,100.0p,80.0p) " + + "or absolute cropping paremters (e.g. crop=0,10,200,100), both based on the original image dimensions.") + WebOptimizedImageDeliveryCropOption cropOption() default WebOptimizedImageDeliveryCropOption.RELATIVE_PARAMETERS; + } @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY) private AssetDelivery assetDelivery; private boolean enabled; + private WebOptimizedImageDeliveryCropOption cropOption; @Activate private void activate(Config config) { this.enabled = config.enabled(); + this.cropOption = config.cropOption(); } @Override @@ -72,13 +80,18 @@ public boolean isEnabled() { return enabled && this.assetDelivery != null; } + @Override + public WebOptimizedImageDeliveryCropOption getCropOption() { + return cropOption; + } + @Override public @Nullable String getDeliveryUrl(@NotNull Asset asset, @NotNull WebOptimizedImageDeliveryParams params) { if (!isEnabled()) { return null; } Resource resource = AdaptTo.notNull(asset, Resource.class); - Map parameterMap = ParameterMap.build(asset, params); + Map parameterMap = ParameterMap.build(asset, params, cropOption); return assetDelivery.getDeliveryURL(resource, parameterMap); } diff --git a/src/test/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImplTest.java b/src/test/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImplTest.java index c8771696..61279763 100644 --- a/src/test/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImplTest.java +++ b/src/test/java/io/wcm/handler/mediasource/dam/impl/weboptimized/WebOptimizedImageDeliveryServiceImplTest.java @@ -25,6 +25,9 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -37,9 +40,6 @@ import io.wcm.testing.mock.aem.junit5.AemContextExtension; import io.wcm.wcm.commons.contenttype.ContentType; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - @ExtendWith(AemContextExtension.class) class WebOptimizedImageDeliveryServiceImplTest { @@ -97,6 +97,8 @@ void testGetDeliveryUrl_relativeCropping() { Asset asset = context.create().asset("/content/dam/Test_1.jpg", 1920, 604, ContentType.JPEG); String assetId = MockAssetDelivery.getAssetId(asset); + assertEquals(WebOptimizedImageDeliveryCropOption.RELATIVE_PARAMETERS, underTest.getCropOption()); + String cropping = URLEncoder.encode(createRelativeCroppingString(0.54, 0, 0.42, 1), StandardCharsets.UTF_8); assertEquals("/adobe/dynamicmedia/deliver/" + assetId + "/test-1.jpg?c=" + cropping + "&preferwebp=true&width=806", underTest.getDeliveryUrl(asset, new WebOptimizedImageDeliveryParams() @@ -104,4 +106,21 @@ void testGetDeliveryUrl_relativeCropping() { .cropDimension(new CropDimension(1028, 0, 806, 604)))); } + @Test + void testGetDeliveryUrl_absoluteCropping() { + context.registerInjectActivateService(MockAssetDelivery.class); + WebOptimizedImageDeliveryService underTest = context.registerInjectActivateService(WebOptimizedImageDeliveryServiceImpl.class, + "cropOption", WebOptimizedImageDeliveryCropOption.ABSOLUTE_PARAMETERS.name()); + Asset asset = context.create().asset("/content/dam/Test_1.jpg", 1920, 604, ContentType.JPEG); + String assetId = MockAssetDelivery.getAssetId(asset); + + assertEquals(WebOptimizedImageDeliveryCropOption.ABSOLUTE_PARAMETERS, underTest.getCropOption()); + + String cropping = URLEncoder.encode("1028,0,806,604", StandardCharsets.UTF_8); + assertEquals("/adobe/dynamicmedia/deliver/" + assetId + "/test-1.jpg?c=" + cropping + "&preferwebp=true&width=806", + underTest.getDeliveryUrl(asset, new WebOptimizedImageDeliveryParams() + .width(806L) + .cropDimension(new CropDimension(1028, 0, 806, 604)))); + } + }