Skip to content

Commit

Permalink
smart crops from local asset
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanseifert committed Jun 20, 2024
1 parent e359626 commit fdcb3d8
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ static final class RepositoryMetadata {

@JsonIgnoreProperties(ignoreUnknown = true)
static final class SmartCrop {
public double normalizedWidth;
public double normalizedHeight;
public double left;
public double top;
public double normalizedWidth;
public double normalizedHeight;
}

@JsonIgnoreProperties(ignoreUnknown = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,27 @@
*/
package io.wcm.handler.mediasource.ngdm.impl.metadata;

import static com.day.cq.commons.jcr.JcrConstants.JCR_CONTENT;
import static com.day.cq.dam.api.DamConstants.ASSET_STATUS_PROPERTY;
import static com.day.cq.dam.api.DamConstants.RENDITIONS_FOLDER;
import static io.wcm.handler.mediasource.dam.impl.dynamicmedia.SmartCrop.PN_LEFT;
import static io.wcm.handler.mediasource.dam.impl.dynamicmedia.SmartCrop.PN_NORMALIZED_HEIGHT;
import static io.wcm.handler.mediasource.dam.impl.dynamicmedia.SmartCrop.PN_NORMALIZED_WIDTH;
import static io.wcm.handler.mediasource.dam.impl.dynamicmedia.SmartCrop.PN_TOP;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -52,16 +64,12 @@ public final class NextGenDynamicMediaMetadata {
private final List<SmartCrop> smartCrops;

private static final JsonMapper OBJECT_MAPPER = new JsonMapper();
static final String RT_RENDITION_SMARTCROP = "dam/rendition/smartcrop";

NextGenDynamicMediaMetadata(@Nullable String mimeType, long width, long height,
NextGenDynamicMediaMetadata(@Nullable String mimeType, @Nullable Dimension dimension,
@Nullable String assetStatus, @Nullable List<SmartCrop> smartCrops) {
this.mimeType = mimeType;
if (width > 0 && height > 0) {
this.dimension = new Dimension(width, height);
}
else {
this.dimension = null;
}
this.dimension = dimension;
this.assetStatus = assetStatus;
if (smartCrops != null) {
this.smartCrops = smartCrops;
Expand Down Expand Up @@ -123,95 +131,93 @@ public String toString() {
RepositoryMetadata respositoryMetadata = response.repositoryMetadata;
AssetMetadata assetMetadata = response.assetMetadata;

long width = 0;
long height = 0;
String assetStatus = null;
if (assetMetadata != null) {
width = assetMetadata.tiffImageWidth;
height = assetMetadata.tiffImageLength;
assetStatus = assetMetadata.assetStatus;
}
Dimension dimension = toDimension(width, height);

String mimeType = null;
List<SmartCrop> smartCrops = null;
if (respositoryMetadata != null) {
mimeType = respositoryMetadata.dcFormat;
if (respositoryMetadata.smartCrops != null) {
if (respositoryMetadata.smartCrops != null && dimension != null) {
smartCrops = respositoryMetadata.smartCrops.entrySet().stream()
.map(entry -> new SmartCrop(entry.getKey(), entry.getValue()))
.filter(entry -> isSmartCropDefinitionValid(entry.getKey(), entry.getValue()))
.map(entry -> new SmartCrop(entry.getKey(), entry.getValue(), dimension))
.collect(Collectors.toList());
}
}

long width = 0;
long height = 0;
String assetStatus = null;
if (assetMetadata != null) {
width = assetMetadata.tiffImageWidth;
height = assetMetadata.tiffImageLength;
assetStatus = assetMetadata.assetStatus;
}
return new NextGenDynamicMediaMetadata(mimeType, dimension, assetStatus, smartCrops);
}

return new NextGenDynamicMediaMetadata(mimeType, width, height, assetStatus, smartCrops);
private static @Nullable Dimension toDimension(long width, long height) {
if (width > 0 && height > 0) {
return new Dimension(width, height);
}
return null;
}

/**
* Gets metadata from DAM asset.
* @param asset Asset
* @return Metadata object
*/
@SuppressWarnings("null")
public static @NotNull NextGenDynamicMediaMetadata fromAsset(@NotNull Asset asset) {
String mimeType = asset.getMimeType();

long width = 0;
long height = 0;
Dimension dimension = AssetRendition.getDimension(asset.getOriginal());
if (dimension != null) {
width = dimension.getWidth();
height = dimension.getHeight();
}
String assetStatus = asset.getMetadataValueFromJcr(ASSET_STATUS_PROPERTY);
List<SmartCrop> smartCrops = null;

return new NextGenDynamicMediaMetadata(mimeType, width, height, assetStatus, Collections.emptyList());
}

/**
* Named smart cropping definition.
*/
public static class SmartCrop {
private final String name;
private final double normalizedWidth;
private final double normalizedHeight;
private final double left;
private final double top;

SmartCrop(String name, double normalizedWidth, double normalizedHeight, double left, double top) {
this.name = name;
this.normalizedWidth = normalizedWidth;
this.normalizedHeight = normalizedHeight;
this.left = left;
this.top = top;
}

SmartCrop(String name, MetadataResponse.SmartCrop smartCrop) {
this(name, smartCrop.normalizedWidth, smartCrop.normalizedHeight, smartCrop.left, smartCrop.top);
}

public String getName() {
return name;
}

public double getNormalizedWidth() {
return normalizedWidth;
if (dimension != null) {
smartCrops = getRenditionResources(asset)
.filter(rendition -> rendition.isResourceType(RT_RENDITION_SMARTCROP))
.map(rendition -> Map.entry(rendition.getName(), renditionToSmartCropDefinition(rendition)))
.filter(entry -> isSmartCropDefinitionValid(entry.getKey(), entry.getValue()))
.map(entry -> new SmartCrop(entry.getKey(), entry.getValue(), dimension))
.collect(Collectors.toList());
}

public double getNormalizedHeight() {
return normalizedHeight;
}
return new NextGenDynamicMediaMetadata(mimeType, dimension, assetStatus, smartCrops);
}

public double getLeft() {
return left;
private static Stream<Resource> getRenditionResources(@NotNull Asset asset) {
Resource assetResource = asset.adaptTo(Resource.class);
if (assetResource != null) {
Resource renditionsFolder = assetResource.getChild(JCR_CONTENT + "/" + RENDITIONS_FOLDER);
if (renditionsFolder != null) {
return StreamSupport.stream(renditionsFolder.getChildren().spliterator(), false);
}
}
return Stream.empty();
}

public double getTop() {
return top;
}
private static boolean isSmartCropDefinitionValid(@NotNull String name, @NotNull MetadataResponse.SmartCrop smartCop) {
return StringUtils.isNotBlank(name)
&& smartCop.normalizedWidth > 0
&& smartCop.normalizedHeight > 0
&& smartCop.left >= 0
&& smartCop.top >= 0;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);
private static @NotNull MetadataResponse.SmartCrop renditionToSmartCropDefinition(Resource rendition) {
MetadataResponse.SmartCrop result = new MetadataResponse.SmartCrop();
Resource content = rendition.getChild(JCR_CONTENT);
if (content != null) {
ValueMap props = content.getValueMap();
result.left = props.get(PN_LEFT, 0d);
result.top = props.get(PN_TOP, 0d);
result.normalizedWidth = props.get(PN_NORMALIZED_WIDTH, 0d);
result.normalizedHeight = props.get(PN_NORMALIZED_HEIGHT, 0d);
}
return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* #%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.ngdm.impl.metadata;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import io.wcm.handler.media.CropDimension;
import io.wcm.handler.media.Dimension;
import io.wcm.handler.media.format.Ratio;

/**
* Named smart cropping definition.
*/
public class SmartCrop {
private final String name;
private final CropDimension cropDimension;
private final double ratio;

SmartCrop(String name,
double leftPercentage, double topPercentage, double widthPercentage, double heightPercentage,
Dimension originalDimension) {

// calculate actual cropping dimension
long originalWidth = originalDimension.getWidth();
long originalHeight = originalDimension.getHeight();
long left = Math.round(originalWidth * leftPercentage);
long top = Math.round(originalHeight * topPercentage);
long width = Math.round(originalWidth * widthPercentage);
long height = Math.round(originalHeight * heightPercentage);

this.name = name;
this.cropDimension = new CropDimension(left, top, width, height, true);
this.ratio = Ratio.get(width, height);
}

SmartCrop(String name, MetadataResponse.SmartCrop smartCrop, Dimension originalDimension) {
this(name, smartCrop.left, smartCrop.top, smartCrop.normalizedWidth, smartCrop.normalizedHeight,
originalDimension);
}

public String getName() {
return name;
}

public CropDimension getCropDimension() {
return this.cropDimension;
}

public double getRatio() {
return this.ratio;
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public final class MetadataSample {
+ " \"height\": \"180\","
+ " \"left\": \"0.0\","
+ " \"manualCrop\": \"true\","
+ " \"normalizedHeight\": \"0.4226\","
+ " \"normalizedHeight\": \"0.84375\","
+ " \"normalizedWidth\": \"1.0\","
+ " \"width\": \"320\","
+ " \"top\": \"0.5774\""
Expand All @@ -46,7 +46,16 @@ public final class MetadataSample {
+ " \"left\": \"0.16792180740265983\","
+ " \"manualCrop\": \"false\","
+ " \"normalizedHeight\": \"0.9980170652565797\","
+ " \"normalizedWidth\": \"0.6666399615446242\","
+ " \"normalizedWidth\": \"0.3326723533333333\","
+ " \"width\": \"100\","
+ " \"top\": \"0.0\""
+ " },"
+ " \"Invalid\": {"
+ " \"height\": \"200\","
+ " \"left\": \"-0.16792180740265983\","
+ " \"manualCrop\": \"false\","
+ " \"normalizedHeight\": \"-0.9980170652565797\","
+ " \"normalizedWidth\": \"-0.6666399615446242\","
+ " \"width\": \"100\","
+ " \"top\": \"0.0\""
+ " }"
Expand Down
Loading

0 comments on commit fdcb3d8

Please sign in to comment.