From b3424395dbdc159c445aea4c465131a269b61535 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 3 May 2020 17:54:38 +0200 Subject: [PATCH] ImageUtils: scale and rotation options --- ImageUtils.java | 47 ++++++++++++++++++ ui/ImageUtilsAwt.java | 108 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 1 deletion(-) diff --git a/ImageUtils.java b/ImageUtils.java index fb86929..c0e1232 100644 --- a/ImageUtils.java +++ b/ImageUtils.java @@ -41,6 +41,53 @@ public abstract class ImageUtils { public abstract void saveAsImage(Image img, File target, String format) throws IOException; + /** + * Scale a dimension. + * + * @param areaWidth + * the base width of the target dimension for snap sizes + * @param areaHeight + * the base height of the target dimension for snap sizes + * @param imageWidth + * the actual image width + * @param imageHeight + * the actual image height + * @param zoom + * the zoom factor, or -1 for snap size + * @param zoomSnapWidth + * if snap size, TRUE to snap to width (and FALSE, snap to + * height) + * + * @return the scaled size, width is [0] and height is [1] (minimum is 1x1) + */ + protected static Integer[] scaleSize(int areaWidth, int areaHeight, + int imageWidth, int imageHeight, double zoom, boolean zoomSnapWidth) { + int width; + int height; + if (zoom > 0) { + width = (int) Math.round(imageHeight * zoom); + height = (int) Math.round(imageHeight * zoom); + } else { + if (zoomSnapWidth) { + width = areaWidth; + height = (int) Math.round( + (((double) areaWidth) / imageWidth) * imageHeight); + } else { + height = areaHeight; + width = (int) Math.round( + (((double) areaHeight) / imageHeight) * imageWidth); + + } + } + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + return new Integer[] { width, height }; + } + /** * Return the EXIF transformation flag of this image if any. * diff --git a/ui/ImageUtilsAwt.java b/ui/ImageUtilsAwt.java index 4cf12c0..9412c93 100644 --- a/ui/ImageUtilsAwt.java +++ b/ui/ImageUtilsAwt.java @@ -1,5 +1,7 @@ package be.nikiroo.utils.ui; +import java.awt.Dimension; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; @@ -9,6 +11,7 @@ import java.io.InputStream; import javax.imageio.ImageIO; +import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.Image; import be.nikiroo.utils.ImageUtils; import be.nikiroo.utils.StringUtils; @@ -19,6 +22,21 @@ import be.nikiroo.utils.StringUtils; * @author niki */ public class ImageUtilsAwt extends ImageUtils { + /** + * A rotation to perform on an image. + * + * @author niki + */ + public enum Rotation { + /** No rotation */ + NONE, + /** Rotate the image to the right */ + RIGHT, + /** Rotate the image to the left */ + LEFT, + /** Rotate the image by 180° */ + UTURN + } @Override protected boolean check() { // Will not work if ImageIO is not available @@ -76,6 +94,25 @@ public class ImageUtilsAwt extends ImageUtils { * in case of IO error */ public static BufferedImage fromImage(Image img) throws IOException { + return fromImage(img, Rotation.NONE); + } + + /** + * Convert the given {@link Image} into a {@link BufferedImage} object, + * respecting the EXIF transformations if any. + * + * @param img + * the {@link Image} + * @param rotation + * the rotation to apply, if any (can be null, same as + * {@link Rotation#NONE}) + * + * @return the {@link Image} object + * + * @throws IOException + * in case of IO error + */ + public static BufferedImage fromImage(Image img, Rotation rotation) throws IOException { InputStream in = img.newInputStream(); BufferedImage image; try { @@ -102,8 +139,15 @@ public class ImageUtilsAwt extends ImageUtils { String extra = ""; if (img.getSize() <= 2048) { try { + byte[] data = null; + InputStream inData = img.newInputStream(); + try { + data = IOUtils.toByteArray(inData); + } finally { + inData.close(); + } extra = ", content: " - + new String(img.getData(), "UTF-8"); + + new String(data, "UTF-8"); } catch (Exception e) { extra = ", content unavailable"; } @@ -158,6 +202,35 @@ public class ImageUtilsAwt extends ImageUtils { affineTransform = null; break; } + + if (rotation == null) + rotation = Rotation.NONE; + + switch (rotation) { + case LEFT: + if (affineTransform == null) { + affineTransform = new AffineTransform(); + } + affineTransform.translate(height, 0); + affineTransform.rotate(Math.PI / 2); + break; + case RIGHT: + if (affineTransform == null) { + affineTransform = new AffineTransform(); + } + affineTransform.translate(0, width); + affineTransform.rotate(3 * Math.PI / 2); + break; + case UTURN: + if (affineTransform == null) { + affineTransform = new AffineTransform(); + } + affineTransform.translate(width, height); + affineTransform.rotate(Math.PI); + break; + default: + break; + } if (affineTransform != null) { AffineTransformOp affineTransformOp = new AffineTransformOp( @@ -177,4 +250,37 @@ public class ImageUtilsAwt extends ImageUtils { return image; } + + /** + * Resize the given image. + * + * @param areaSize + * the base size of the target dimension for snap sizes + * @param image + * the image to resize + * @param zoom + * the zoom factor or -1 for snap size + * @param zoomSnapWidth + * if snap size, TRUE to snap to width (and FALSE, snap to + * height) + * + * @return a new, resized image + */ + public static BufferedImage scaleImage(Dimension areaSize, + BufferedImage image, double zoom, boolean zoomSnapWidth) { + Integer scaledSize[] = scaleSize(areaSize.width, areaSize.height, + image.getWidth(), image.getHeight(), zoom, zoomSnapWidth); + int width = scaledSize[0]; + int height = scaledSize[1]; + BufferedImage resizedImage = new BufferedImage(width, height, + BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D g = resizedImage.createGraphics(); + try { + g.drawImage(image, 0, 0, width, height, null); + } finally { + g.dispose(); + } + + return resizedImage; + } } -- 2.27.0