VirtualTransformedRenditionMetadata.java
/*
* #%L
* wcm.io
* %%
* Copyright (C) 2014 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;
import java.io.InputStream;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.day.cq.dam.api.Rendition;
import com.day.image.Layer;
import io.wcm.handler.media.CropDimension;
import io.wcm.handler.media.Dimension;
import io.wcm.handler.media.UriTemplate;
import io.wcm.handler.media.UriTemplateType;
import io.wcm.handler.media.format.Ratio;
import io.wcm.handler.media.impl.ImageFileServlet;
import io.wcm.handler.media.impl.ImageFileServletSelector;
import io.wcm.handler.media.impl.ImageTransformation;
import io.wcm.handler.media.impl.MediaFileServletConstants;
import io.wcm.handler.mediasource.dam.AssetRendition;
import io.wcm.handler.mediasource.dam.impl.dynamicmedia.DynamicMediaPath;
import io.wcm.handler.mediasource.dam.impl.weboptimized.WebOptimizedImageDeliveryParams;
/**
* Virtual rendition that is cropping and/or rotating and downscaling from an existing rendition.
*/
class VirtualTransformedRenditionMetadata extends RenditionMetadata {
private final long width;
private final long height;
private final String enforceOutputFileExtension;
private final CropDimension cropDimension;
private final Integer rotation;
private final Double imageQualityPercentage;
VirtualTransformedRenditionMetadata(@NotNull Rendition rendition, long width, long height,
@Nullable String enforceOutputFileExtension, @Nullable CropDimension cropDimension, @Nullable Integer rotation,
@Nullable Double imageQualityPercentage) {
super(rendition);
this.width = width;
this.height = height;
this.enforceOutputFileExtension = enforceOutputFileExtension;
this.cropDimension = cropDimension;
this.rotation = rotation;
this.imageQualityPercentage = imageQualityPercentage;
}
@Override
public String getFileName(boolean contentDispositionAttachment) {
// replace extension based on the format supported by ImageFileServlet for rendering for this rendition
return ImageFileServlet.getImageFileName(super.getFileName(contentDispositionAttachment), enforceOutputFileExtension);
}
@Override
public long getFileSize() {
// no size for virutal renditions
return 0L;
}
@Override
public long getWidth() {
return this.width;
}
@Override
public long getHeight() {
return this.height;
}
public CropDimension getCropDimension() {
return this.cropDimension;
}
public Integer getRotation() {
return this.rotation;
}
@Override
public @NotNull String getMediaPath(boolean contentDispositionAttachment) {
return buildMediaPath(getRendition().getPath()
+ "." + ImageFileServletSelector.build(getWidth(), getHeight(),
this.cropDimension, this.rotation, this.imageQualityPercentage, contentDispositionAttachment)
+ "." + MediaFileServletConstants.EXTENSION, getFileName(contentDispositionAttachment));
}
@Override
public @Nullable String getDynamicMediaPath(boolean contentDispositionAttachment, DamContext damContext) {
// render virtual rendition with dynamic media (we ignore contentDispositionAttachment here)
return DynamicMediaPath.buildImage(damContext, getWidth(), getHeight(), this.cropDimension, this.rotation);
}
@Override
public @Nullable String getWebOptimizedImageDeliveryPath(DamContext damContext) {
return damContext.getWebOptimizedImageDeliveryUrl(new WebOptimizedImageDeliveryParams()
.width(getWidth()).cropDimension(this.cropDimension).rotation(this.rotation));
}
@Override
protected Layer getLayer() {
Layer layer = super.getLayer();
if (layer != null) {
if (cropDimension != null) {
layer.crop(cropDimension.getRectangle());
if (width <= layer.getWidth() && height <= layer.getHeight()) {
layer.resize((int)width, (int)height);
}
}
if (rotation != null) {
layer.rotate(rotation);
}
}
return layer;
}
@Override
protected InputStream getInputStream() {
// currently not supported for virtual renditions
return null;
}
@Override
public @NotNull UriTemplate getUriTemplate(@NotNull UriTemplateType type, @NotNull DamContext damContext) {
if (!isImage() || isVectorImage()) {
throw new UnsupportedOperationException("Unable to build URI template for rendition: " + getRendition().getPath());
}
Dimension dimension = cropDimension;
if (dimension == null) {
dimension = AssetRendition.getDimension(getRendition());
}
if (dimension == null) {
throw new IllegalArgumentException("Unable to get dimension for rendition: " + getRendition().getPath());
}
dimension = ImageTransformation.rotateMapDimension(dimension, rotation);
return new DamUriTemplate(type, dimension, getRendition(), cropDimension, rotation, Ratio.get(dimension), damContext);
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(this.getRendition().getPath())
.append(width)
.append(height)
.append(cropDimension)
.append(rotation)
.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
VirtualTransformedRenditionMetadata other = (VirtualTransformedRenditionMetadata)obj;
return new EqualsBuilder()
.append(this.getRendition().getPath(), other.getRendition().getPath())
.append(this.width, other.width)
.append(this.height, other.height)
.append(this.cropDimension, other.cropDimension)
.append(this.rotation, other.rotation)
.build();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
sb.append(" -> ").append(Long.toString(this.width)).append("x").append(Long.toString(this.height));
if (cropDimension != null) {
sb.append(", ").append(cropDimension.toString());
}
if (rotation != null) {
sb.append(", rotation:").append(Integer.toString(rotation));
}
return sb.toString();
}
}