diff --git a/ccm-cms/src/main/java/org/librecms/assets/Image.java b/ccm-cms/src/main/java/org/librecms/assets/Image.java index 2a6e6f905..8e6f05177 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/Image.java +++ b/ccm-cms/src/main/java/org/librecms/assets/Image.java @@ -27,7 +27,11 @@ import javax.persistence.JoinColumn; import javax.persistence.Table; import com.arsdigita.cms.ui.assets.forms.ImageForm; + import org.hibernate.envers.Audited; +import org.librecms.ui.contentsections.assets.ImageCreateStep; +import org.librecms.ui.contentsections.assets.ImageEditStep; +import org.librecms.ui.contentsections.assets.MvcAssetEditKit; import javax.persistence.OneToOne; @@ -48,6 +52,10 @@ import static org.librecms.assets.AssetConstants.*; labelBundle = ASSETS_BUNDLE, descriptionKey = "image.description", descriptionBundle = ASSETS_BUNDLE) +@MvcAssetEditKit( + createStep = ImageCreateStep.class, + editStep = ImageEditStep.class +) public class Image extends BinaryAsset implements Serializable { private static final long serialVersionUID = -8095106228017573785L; diff --git a/ccm-cms/src/main/java/org/librecms/assets/ImageProperties.java b/ccm-cms/src/main/java/org/librecms/assets/ImageProperties.java new file mode 100644 index 000000000..7eca74666 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/ImageProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.assets; + +/** + * DTO for properties of an image. + * + * @author Jens Pelzetter + */ +public class ImageProperties { + + /** + * The width of the image. + */ + private int width; + + /** + * The height of the image + */ + private int height; + + protected ImageProperties() { + + } + + public int getWidth() { + return width; + } + + protected void setWidth(final int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + protected void setHeight(final int height) { + this.height = height; + } + + + +} diff --git a/ccm-cms/src/main/java/org/librecms/assets/ImageService.java b/ccm-cms/src/main/java/org/librecms/assets/ImageService.java new file mode 100644 index 000000000..eb177061e --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/assets/ImageService.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2021 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.librecms.assets; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.libreccm.core.UnexpectedErrorException; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +import javax.enterprise.context.Dependent; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +/** + * Utility class for working with images (JPEG, PNG, GIF). + * + * @author Jens Pelzetter + */ +@Dependent +public class ImageService { + + private static final Logger LOGGER = LogManager.getLogger( + ImageService.class + ); + + public ImageProperties getImageProperties(final Image image) { + final InputStream inputStream = image.getDataAsInputStream(); + return getImageProperties(inputStream); + } + + public ImageProperties getImageProperties(final InputStream inputStream) { + final BufferedImage bufferedImage; + try { + bufferedImage = ImageIO.read(inputStream); + } catch (IOException ex) { + throw new UnexpectedErrorException(ex); + } + + final ImageProperties imageProperties = new ImageProperties(); + imageProperties.setHeight(bufferedImage.getHeight()); + imageProperties.setWidth(bufferedImage.getWidth()); + + return imageProperties; + } + + public byte[] scaleImage( + final Image image, final int toWidth, final int toHeight + ) { + final InputStream inputStream = image.getDataAsInputStream(); + return scaleImage(inputStream, toWidth, toHeight); + + } + + public byte[] scaleImage( + final InputStream inputStream, final int toWidth, final int toHeight + ) { + final BufferedImage bufferedImage; + + final String imageFormat; + try { + final ImageInputStream imageInputStream = ImageIO + .createImageInputStream(inputStream); + final Iterator readers = ImageIO + .getImageReaders(imageInputStream); + final ImageReader imageReader; + if (readers.hasNext()) { + imageReader = readers.next(); + } else { + LOGGER.error( + "No image reader suitable image reader available"); + throw new UnexpectedErrorException(); + } + imageReader.setInput(imageInputStream); + bufferedImage = imageReader.read(0); + imageFormat = imageReader.getFormatName(); + } catch (IOException ex) { + LOGGER.error("Failed to load image."); + LOGGER.error(ex); + throw new UnexpectedErrorException(); + } + + final java.awt.Image scaledImage = scaleImage( + bufferedImage, toWidth, toHeight + ); + + final ByteArrayOutputStream outputStream + = new ByteArrayOutputStream(); + final BufferedImage bufferedScaledImage = new BufferedImage( + scaledImage.getWidth(null), + scaledImage.getHeight(null), + bufferedImage.getType()); + bufferedScaledImage + .getGraphics() + .drawImage(scaledImage, 0, 0, null); + try { + ImageIO + .write(bufferedScaledImage, imageFormat, outputStream); + } catch (IOException ex) { + LOGGER.error("Failed to render scaled variant of image"); + LOGGER.error(ex); + throw new UnexpectedErrorException( + "Failed to render scaled variant of image" + ); + } + + return outputStream.toByteArray(); + + } + + private java.awt.Image scaleImage( + final BufferedImage image, + final float scaleToWidth, + final float scaleToHeight + ) { + final float originalWidth = image.getWidth(); + final float originalHeight = image.getHeight(); + final float originalAspectRatio = originalWidth / originalHeight; + + if (scaleToWidth > 0 && scaleToHeight > 0) { + //Check if parameters preserve aspectRatio. If not use the smaller + //scale factor. + + final float scaleToAspectRatio = scaleToWidth / scaleToHeight; + if (Math.abs(scaleToAspectRatio - originalAspectRatio) < 0.009f) { + // Scale the image. + + return image.getScaledInstance(Math.round(scaleToWidth), + Math.round(scaleToHeight), + java.awt.Image.SCALE_SMOOTH); + } else { + //Use the scale factor nearer to one for both dimensions + final float scaleFactorWidth = scaleToWidth / originalWidth; + final float scaleFactorHeight = scaleToHeight / originalHeight; + final float differenceWidth = Math.abs(scaleFactorWidth - 1); + final float differenceHeight = Math.abs(scaleFactorHeight - 1); + + final float scaleFactor; + if (differenceWidth < differenceHeight) { + scaleFactor = scaleFactorWidth; + } else { + scaleFactor = scaleFactorHeight; + } + + return scaleImage(image, + originalWidth * scaleFactor, + originalHeight * scaleFactor); + } + + } else if (scaleToWidth > 0 && scaleToHeight <= 0) { + //Calculate the height to which to image is scaled based on the + //scale factor for the width + final float scaleFactor = scaleToWidth / originalWidth; + final float height = originalHeight * scaleFactor; + + return scaleImage(image, scaleToWidth, height); + } else if (scaleToWidth <= 0 && scaleToHeight >= 0) { + //Calculate the width to which to image is scaled based on the + //scale factor for the height + final float scaleFactor = scaleToHeight / originalHeight; + final float width = originalWidth * scaleFactor; + + return scaleImage(image, width, scaleToHeight); + } else { + //Return the image as is. + return image; + } + } + +}