ImageUtils: scale and rotation options
authorNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 15:54:38 +0000 (17:54 +0200)
committerNiki Roo <niki@nikiroo.be>
Sun, 3 May 2020 15:54:38 +0000 (17:54 +0200)
src/be/nikiroo/utils/ImageUtils.java
src/be/nikiroo/utils/ui/ImageUtilsAwt.java

index fb869294f2029bd1c0fd7f4a64680259ca4bc4b0..c0e123280cd5aa846bd57e08324a81df253c9de4 100644 (file)
@@ -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.
         * 
index 4cf12c04cd0573629d90ed6e376be7c5ca6e7155..9412c93cd93b52c00d4fbc33cc93dc8c9860c17a 100644 (file)
@@ -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;
+       }
 }