package com.psddev.cms.db;
import com.psddev.dari.util.CollectionUtils;
import com.psddev.dari.util.DimsImageEditor;
import com.psddev.dari.util.ImageEditor;
import com.psddev.dari.util.ObjectUtils;
import com.psddev.dari.util.StorageItem;
import com.psddev.dari.util.StringUtils;
import com.psddev.image.HotSpotPoint;
import com.psddev.image.HotSpotRegion;
import com.psddev.image.HotSpots;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class ImageHotSpot {
public static List<Integer> crop(StorageItem item, Integer cropWidth, Integer cropHeight) {
if (item != null
&& item.getMetadata().containsKey("height")
&& item.getMetadata().containsKey("width")
&& ((cropWidth != null && ObjectUtils.to(Integer.class, item.getMetadata().get("width")) > cropWidth)
|| cropHeight != null && ObjectUtils.to(Integer.class, item.getMetadata().get("height")) > cropHeight)) {
List<HotSpotPoint> hotSpots = HotSpots.Data.getHotSpots(item);
if (!ObjectUtils.isBlank(hotSpots)) {
Integer x2 = null;
Integer y2 = null;
Integer imageHeight = ObjectUtils.to(Integer.class, item.getMetadata().get("height"));
Integer imageWidth = ObjectUtils.to(Integer.class, item.getMetadata().get("width"));
Integer originalHeight = CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_HEIGHT_METADATA_PATH) != null
? ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_HEIGHT_METADATA_PATH))
: imageHeight;
Integer originalWidth = CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_WIDTH_METADATA_PATH) != null
? ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_WIDTH_METADATA_PATH))
: imageWidth;
Integer angle = ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/rotate"));
if (angle != null && (angle == 90 || angle == -90)) {
Integer temp = imageHeight;
imageHeight = imageWidth;
imageWidth = temp;
temp = originalHeight;
originalHeight = originalWidth;
originalWidth = temp;
}
if (cropWidth == null) {
double scale = (double) imageHeight / cropHeight;
cropWidth = ((Double) (cropWidth * scale)).intValue();
} else if (cropHeight == null) {
double scale = (double) imageWidth / cropWidth;
cropHeight = ((Double) (cropHeight * scale)).intValue();
} else {
double horzScale = (double) imageWidth / cropWidth;
double vertScale = (double) imageHeight / cropHeight;
if (vertScale < horzScale) {
cropHeight = imageHeight;
cropWidth = ((Double) (cropWidth * vertScale)).intValue();
} else {
cropWidth = imageWidth;
cropHeight = ((Double) (cropHeight * horzScale)).intValue();
}
}
double heightScaleFactor = originalHeight != null && originalHeight > 0 ? (double) imageHeight / originalHeight : 1.0;
double widthScaleFactor = originalWidth != null && originalWidth > 0 ? (double) imageWidth / originalWidth : 1.0;
//rotate bounding box
if (CollectionUtils.getByPath(item.getMetadata(), "cms.edits/rotate") != null) {
if (angle != null && angle == 90) {
for (HotSpotPoint hotSpot : hotSpots) {
Integer x = hotSpot.as(HotSpotPoint.Data.class).getX();
Integer y = hotSpot.as(HotSpotPoint.Data.class).getY();
Integer width = (hotSpot instanceof HotSpotRegion) ? hotSpot.as(HotSpotRegion.Data.class).getWidth() : 0;
hotSpot.as(HotSpotPoint.Data.class).setX(originalHeight - y - width);
hotSpot.as(HotSpotPoint.Data.class).setY(x);
if (hotSpot instanceof HotSpotRegion) {
Integer temp = hotSpot.as(HotSpotRegion.Data.class).getWidth();
hotSpot.as(HotSpotRegion.Data.class).setWidth(hotSpot.as(HotSpotRegion.Data.class).getHeight());
hotSpot.as(HotSpotRegion.Data.class).setHeight(temp);
}
}
}
}
Boolean flipH = ObjectUtils.to(Boolean.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/flipH"));
Boolean flipV = ObjectUtils.to(Boolean.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/flipV"));
if (flipH != null && flipH) {
for (HotSpotPoint hotSpot : hotSpots) {
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setX(originalWidth - hotSpot.as(HotSpotPoint.Data.class).getX() - hotSpot.as(HotSpotRegion.Data.class).getWidth());
} else {
hotSpot.as(HotSpotPoint.Data.class).setX(originalWidth - hotSpot.as(HotSpotPoint.Data.class).getX());
}
}
}
if (flipV != null && flipV) {
for (HotSpotPoint hotSpot : hotSpots) {
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setY(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY() - hotSpot.as(HotSpotRegion.Data.class).getHeight());
} else {
hotSpot.as(HotSpotPoint.Data.class).setY(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY());
}
}
}
//bounding box of hotspots
Integer x1 = null;
Integer y1 = null;
for (HotSpotPoint hotSpot : hotSpots) {
x1 = x1 == null || hotSpot.as(HotSpotPoint.Data.class).getX() < x1 ? hotSpot.as(HotSpotPoint.Data.class).getX() : x1;
y1 = y1 == null || hotSpot.as(HotSpotPoint.Data.class).getY() < y1 ? hotSpot.as(HotSpotPoint.Data.class).getY() : y1;
if (hotSpot instanceof HotSpotRegion) {
x2 = x2 == null || (hotSpot.as(HotSpotPoint.Data.class).getX() + hotSpot.as(HotSpotRegion.Data.class).getWidth()) > x2 ? (hotSpot.as(HotSpotPoint.Data.class).getX() + hotSpot.as(HotSpotRegion.Data.class).getWidth()) : x2;
y2 = y2 == null || (hotSpot.as(HotSpotPoint.Data.class).getY() + hotSpot.as(HotSpotRegion.Data.class).getHeight()) > y2 ? (hotSpot.as(HotSpotPoint.Data.class).getY() + hotSpot.as(HotSpotRegion.Data.class).getHeight()) : y2;
} else {
x2 = x1;
y2 = y1;
}
}
x1 = ((Double) (x1 * widthScaleFactor)).intValue();
x2 = ((Double) (x2 * widthScaleFactor)).intValue();
y1 = ((Double) (y1 * heightScaleFactor)).intValue();
y2 = ((Double) (y2 * heightScaleFactor)).intValue();
int centerX = (x1 + x2) / 2;
int centerY = (y1 + y2) / 2;
x1 = centerX - (cropWidth / 2);
x2 = centerX + (cropWidth / 2);
y1 = centerY - (cropHeight / 2);
y2 = centerY + (cropHeight / 2);
if (x1 < 0) {
x1 = 0;
} else if (x2 > imageWidth) {
x1 = x1 - x2 + imageWidth;
}
if (y1 < 0) {
y1 = 0;
} else if (y2 > cropHeight) {
y1 = y1 - y2 + cropHeight;
}
return Arrays.asList(x1, y1, cropWidth, cropHeight);
}
}
return null;
}
public static List<HotSpotPoint> getReSizedHotSpots(StorageItem item, Object size) throws IOException {
return getReSizedHotSpots(item, size, Boolean.FALSE);
}
public static List<HotSpotPoint> getReSizedHotSpots(StorageItem item, Object size, Boolean disableHotSpotCrop) throws IOException {
StandardImageSize standardImageSize = null;
if (size instanceof StandardImageSize) {
standardImageSize = ((StandardImageSize) size);
} else if (size instanceof String) {
standardImageSize = ImageTag.getStandardImageSizeByName((String) size);
}
if (standardImageSize != null && standardImageSize.getId() != null) {
return getReSizedHotSpots(item, standardImageSize.getWidth(), standardImageSize.getHeight(), standardImageSize.getCropOption(), standardImageSize.getResizeOption(), standardImageSize.getId().toString(), disableHotSpotCrop);
}
return null;
}
public static List<HotSpotPoint> getReSizedHotSpots(StorageItem item, Integer reSizedWidth, Integer reSizedHeight, CropOption cropOption, ResizeOption resizeOption, String standardImageSizeId, Boolean disableHotSpotCrop) throws IOException {
List<HotSpotPoint> originalHotSpots = HotSpots.Data.getHotSpots(item);
if (!ObjectUtils.isBlank(originalHotSpots)
&& item != null
&& item.getMetadata().containsKey("height")
&& item.getMetadata().containsKey("width")) {
ImageCrop crop = null;
Integer originalWidth = ImageTag.findDimension(item, "width");
Integer originalHeight = ImageTag.findDimension(item, "height");
Integer cropX = null;
Integer cropY = null;
Integer cropWidth = null;
Integer cropHeight = null;
boolean usingDimsImageEditor = ImageEditor.Static.getDefault() instanceof DimsImageEditor;
Map<String, ImageCrop> crops = ImageTag.findImageCrops(item);
if (crops != null
&& !StringUtils.isBlank(standardImageSizeId)
&& (crop = crops.get(standardImageSizeId)) != null
&& originalWidth != null && originalHeight != null) {
cropX = (int) (crop.getX() * originalWidth);
cropY = (int) (crop.getY() * originalHeight);
cropWidth = (int) (crop.getWidth() * originalWidth);
cropHeight = (int) (crop.getHeight() * originalHeight);
}
Dimension originalDimension = new Dimension(originalWidth, originalHeight);
if (resizeOption == ResizeOption.ONLY_SHRINK_LARGER) {
if (reSizedWidth != null
&& reSizedWidth > 0
&& reSizedHeight != null && reSizedHeight > 0) {
reSizedWidth = originalDimension.width != null ? Math.min(originalDimension.width, reSizedWidth) : reSizedWidth;
reSizedHeight = originalDimension.height != null ? Math.min(originalDimension.height, reSizedHeight) : reSizedHeight;
} else {
Dimension outputDimension = getResizeDimension(originalDimension.width, originalDimension.height, reSizedWidth, reSizedHeight);
reSizedWidth = outputDimension.width;
reSizedHeight = outputDimension.height;
}
} else if (resizeOption == ResizeOption.ONLY_ENLARGE_SMALLER) {
if (reSizedWidth != null
&& reSizedWidth > 0
&& reSizedHeight != null && reSizedHeight > 0) {
reSizedWidth = originalDimension.width != null ? Math.max(originalDimension.width, reSizedWidth) : reSizedWidth;
reSizedHeight = originalDimension.height != null ? Math.max(originalDimension.height, reSizedHeight) : reSizedHeight;
} else {
Dimension outputDimension = getResizeDimension(originalDimension.width, originalDimension.height, reSizedWidth, reSizedHeight);
reSizedWidth = outputDimension.width;
reSizedHeight = outputDimension.height;
}
}
double vertScale = (double) originalHeight / reSizedHeight;
double horzScale = (double) originalWidth / reSizedWidth;
if (vertScale < horzScale) {
cropHeight = originalHeight;
cropWidth = ((Double) (reSizedWidth * vertScale)).intValue();
} else {
cropWidth = originalWidth;
cropHeight = ((Double) (reSizedHeight * horzScale)).intValue();
}
if (cropX == null
&& cropY == null
&& (cropOption == null || cropOption.equals(CropOption.AUTOMATIC))) {
List<Integer> hotSpotCrop = crop(item, cropWidth, cropHeight);
if (!ObjectUtils.isBlank(hotSpotCrop)
&& hotSpotCrop.size() == 4) {
cropX = hotSpotCrop.get(0);
cropY = hotSpotCrop.get(1);
cropWidth = hotSpotCrop.get(2);
cropHeight = hotSpotCrop.get(3);
}
}
if (resizeOption != null && resizeOption.equals(ResizeOption.IGNORE_ASPECT_RATIO)) {
cropX = 0;
cropY = 0;
cropWidth = originalWidth;
cropHeight = originalHeight;
} else {
if (cropX == null
&& cropY == null
&& cropOption == null
|| cropOption == CropOption.AUTOMATIC) {
if (usingDimsImageEditor) {
cropX = 0;
cropY = 0;
} else if (vertScale < horzScale) {
//width is cut off
cropY = 0;
cropX = (originalWidth / 2) - (cropWidth / 2);
} else {
//height is cut off
cropX = 0;
cropY = (originalHeight / 2) - (cropHeight / 2);
}
} else if (cropOption != null && cropOption == CropOption.NONE) {
cropWidth = null;
cropHeight = null;
}
}
return getReSizedHotSpots(item, cropX, cropY, cropWidth, cropHeight, reSizedWidth, reSizedHeight);
}
return null;
}
public static List<HotSpotPoint> getReSizedHotSpots(StorageItem item, Integer cropX, Integer cropY, Integer cropWidth, Integer cropHeight, Integer reSizedWidth, Integer reSizedHeight) {
List<HotSpotPoint> hotSpots = HotSpots.Data.getHotSpots(item);
if (!ObjectUtils.isBlank(hotSpots)
&& item != null
&& item.getMetadata().containsKey("height")
&& item.getMetadata().containsKey("width")) {
Integer imageHeight = ObjectUtils.to(Integer.class, item.getMetadata().get("height"));
Integer imageWidth = ObjectUtils.to(Integer.class, item.getMetadata().get("width"));
Integer originalHeight = CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_HEIGHT_METADATA_PATH) != null
? ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_HEIGHT_METADATA_PATH))
: imageHeight;
Integer originalWidth = CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_WIDTH_METADATA_PATH) != null
? ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), ImageTag.ORIGINAL_WIDTH_METADATA_PATH))
: imageWidth;
Boolean flipH = ObjectUtils.to(Boolean.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/flipH"));
Boolean flipV = ObjectUtils.to(Boolean.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/flipV"));
if (flipH != null && flipH) {
for (HotSpotPoint hotSpot : hotSpots) {
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setX(originalWidth - hotSpot.as(HotSpotPoint.Data.class).getX() - hotSpot.as(HotSpotRegion.Data.class).getWidth());
} else {
hotSpot.as(HotSpotPoint.Data.class).setX(originalWidth - hotSpot.as(HotSpotPoint.Data.class).getX());
}
}
}
if (flipV != null && flipV) {
for (HotSpotPoint hotSpot : hotSpots) {
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setY(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY());
} else {
hotSpot.as(HotSpotPoint.Data.class).setY(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY() - hotSpot.as(HotSpotRegion.Data.class).getHeight());
}
}
}
if (cropX != null && cropY != null) {
for (HotSpotPoint hotSpot : hotSpots) {
hotSpot.as(HotSpotPoint.Data.class).setX(hotSpot.as(HotSpotPoint.Data.class).getX() - cropX);
hotSpot.as(HotSpotPoint.Data.class).setY(hotSpot.as(HotSpotPoint.Data.class).getY() - cropY);
}
}
if (CollectionUtils.getByPath(item.getMetadata(), "cms.edits/rotate") != null) {
Integer angle = ObjectUtils.to(Integer.class, CollectionUtils.getByPath(item.getMetadata(), "cms.edits/rotate"));
if (angle != null) {
if (angle == 90) {
for (HotSpotPoint hotSpot : hotSpots) {
Integer originalX = hotSpot.as(HotSpotPoint.Data.class).getX();
hotSpot.as(HotSpotPoint.Data.class).setY(originalX);
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setX(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY());
} else {
hotSpot.as(HotSpotPoint.Data.class).setX(originalHeight - hotSpot.as(HotSpotPoint.Data.class).getY() - hotSpot.as(HotSpotRegion.Data.class).getWidth());
hotSpot.as(HotSpotRegion.Data.class).setWidth(hotSpot.as(HotSpotRegion.Data.class).getHeight());
hotSpot.as(HotSpotRegion.Data.class).setHeight(hotSpot.as(HotSpotRegion.Data.class).getWidth());
}
}
} else if (angle == -90) {
for (HotSpotPoint hotSpot : hotSpots) {
Integer originalX = hotSpot.as(HotSpotPoint.Data.class).getX();
hotSpot.as(HotSpotPoint.Data.class).setX(hotSpot.as(HotSpotPoint.Data.class).getY());
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotPoint.Data.class).setY(originalWidth - originalX);
} else {
hotSpot.as(HotSpotPoint.Data.class).setY(originalWidth - originalX - hotSpot.as(HotSpotRegion.Data.class).getHeight());
hotSpot.as(HotSpotRegion.Data.class).setWidth(hotSpot.as(HotSpotRegion.Data.class).getHeight());
hotSpot.as(HotSpotRegion.Data.class).setHeight(hotSpot.as(HotSpotRegion.Data.class).getWidth());
}
}
}
}
}
if (reSizedHeight != null || reSizedWidth != null) {
Double heightScaleFactor;
Double widthScaleFactor;
if (cropHeight == null && cropWidth == null) {
heightScaleFactor = (double) reSizedHeight / imageHeight;
widthScaleFactor = (double) reSizedWidth / imageWidth;
if (widthScaleFactor < heightScaleFactor) {
heightScaleFactor = widthScaleFactor;
} else {
widthScaleFactor = heightScaleFactor;
}
} else {
heightScaleFactor = cropHeight != null && cropHeight > 0 ? (double) reSizedHeight / cropHeight : 1.0;
widthScaleFactor = cropWidth != null && cropWidth > 0 ? (double) reSizedWidth / cropWidth : 1.0;
}
for (HotSpotPoint hotSpot : hotSpots) {
hotSpot.as(HotSpotPoint.Data.class).setX(((Double) (hotSpot.as(HotSpotPoint.Data.class).getX() * widthScaleFactor)).intValue());
hotSpot.as(HotSpotPoint.Data.class).setY(((Double) (hotSpot.as(HotSpotPoint.Data.class).getY() * heightScaleFactor)).intValue());
if (hotSpot instanceof HotSpotRegion) {
hotSpot.as(HotSpotRegion.Data.class).setWidth(((Double) (hotSpot.as(HotSpotRegion.Data.class).getWidth() * widthScaleFactor)).intValue());
hotSpot.as(HotSpotRegion.Data.class).setHeight(((Double) (hotSpot.as(HotSpotRegion.Data.class).getHeight() * heightScaleFactor)).intValue());
}
}
}
}
return hotSpots;
}
private static class Dimension {
public final Integer width;
public final Integer height;
public Dimension(Integer width, Integer height) {
this.width = width;
this.height = height;
}
}
private static Dimension getResizeDimension(Integer originalWidth, Integer originalHeight, Integer requestedWidth, Integer requestedHeight) {
Integer actualWidth = null;
Integer actualHeight = null;
if (originalWidth != null && originalHeight != null
&& (requestedWidth != null || requestedHeight != null)) {
float originalRatio = (float) originalWidth / (float) originalHeight;
if (requestedWidth != null && requestedHeight != null) {
float requestedRatio = (float) requestedWidth / (float) requestedHeight;
if (originalRatio > requestedRatio) {
actualWidth = requestedWidth;
actualHeight = (int) Math.round((float) requestedWidth * originalHeight / originalWidth);
} else if (originalRatio < requestedRatio) {
actualWidth = (int) Math.round((float) requestedHeight * originalWidth / originalHeight);
actualHeight = requestedHeight;
} else {
actualWidth = requestedWidth;
actualHeight = requestedHeight;
}
} else if (requestedWidth == null) {
actualHeight = requestedHeight;
actualWidth = Math.round((float) requestedHeight * originalRatio);
} else if (requestedHeight == null) {
actualWidth = requestedWidth;
actualHeight = Math.round((float) requestedWidth / originalRatio);
}
}
return new Dimension(actualWidth, actualHeight);
}
}