From 7b42695f536a88cfc5fed57e98687394e3c42fe9 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 23 Apr 2019 13:43:52 +0200 Subject: [PATCH] Image: perfs improvement --- src/be/nikiroo/utils/Image.java | 32 +++- .../utils/android/ImageUtilsAndroid.java | 5 +- src/be/nikiroo/utils/ui/ImageUtilsAwt.java | 153 +++++++++--------- 3 files changed, 111 insertions(+), 79 deletions(-) diff --git a/src/be/nikiroo/utils/Image.java b/src/be/nikiroo/utils/Image.java index 6edc105..cfcaa74 100644 --- a/src/be/nikiroo/utils/Image.java +++ b/src/be/nikiroo/utils/Image.java @@ -76,14 +76,35 @@ public class Image implements Closeable { IOUtils.write(in, data); } + /** + * Generate an {@link InputStream} for this {@link Image}. + *

+ * This {@link InputStream} will (always) be a new one, and you are + * responsible for it. + *

+ * Note: take care that the {@link InputStream} must not live past + * the {@link Image} life time! + * + * @return the stream + * + * @throws IOException + * in case of I/O error + */ + public InputStream newInputStream() throws IOException { + return new FileInputStream(data); + } + /** * Read the actual image data, as a byte array. + *

+ * Note: if possible, prefer the {@link Image#newInputStream()} method, as + * it can be more efficient. * * @return the image data */ public byte[] getData() { try { - FileInputStream in = new FileInputStream(data); + InputStream in = newInputStream(); try { return IOUtils.toByteArray(in); } finally { @@ -97,11 +118,18 @@ public class Image implements Closeable { /** * Convert the given {@link Image} object into a Base64 representation of * the same {@link Image} object. + *

+ * Note: if possible, prefer the {@link Image#newInputStream()} method, as + * it can be more efficient. * * @return the Base64 representation */ public String toBase64() { - return Base64.encodeBytes(getData()); + try { + return StringUtils.base64(getData(), false); + } catch (IOException e) { + throw new RuntimeException(e); + } } /** diff --git a/src/be/nikiroo/utils/android/ImageUtilsAndroid.java b/src/be/nikiroo/utils/android/ImageUtilsAndroid.java index eb65ff1..f198862 100644 --- a/src/be/nikiroo/utils/android/ImageUtilsAndroid.java +++ b/src/be/nikiroo/utils/android/ImageUtilsAndroid.java @@ -62,8 +62,9 @@ public class ImageUtilsAndroid extends ImageUtils { * in case of IO error */ static public Bitmap fromImage(Image img) throws IOException { - int size = img.getData().length; - Bitmap image = BitmapFactory.decodeByteArray(img.getData(), 0, size); + byte[] array = img.getData(); + int size = array.length; + Bitmap image = BitmapFactory.decodeByteArray(array, 0, size); if (image == null) { String ssize = StringUtils.formatNumber(size); throw new IOException( diff --git a/src/be/nikiroo/utils/ui/ImageUtilsAwt.java b/src/be/nikiroo/utils/ui/ImageUtilsAwt.java index 148f8f5..6e9160f 100644 --- a/src/be/nikiroo/utils/ui/ImageUtilsAwt.java +++ b/src/be/nikiroo/utils/ui/ImageUtilsAwt.java @@ -3,7 +3,6 @@ package be.nikiroo.utils.ui; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -69,88 +68,92 @@ public class ImageUtilsAwt extends ImageUtils { * in case of IO error */ public static BufferedImage fromImage(Image img) throws IOException { - InputStream in = new ByteArrayInputStream(img.getData()); - - int orientation; - try { - orientation = getExifTransorm(in); - } catch (Exception e) { - // no EXIF transform, ok - orientation = -1; - } - - in.reset(); + InputStream in = img.newInputStream(); BufferedImage image; try { - image = ImageIO.read(in); - } catch (IllegalArgumentException e) { - throw e; - } catch (Exception e) { - throw new IOException("Undocumented exception occured, " - + "converting to IOException", e); - } + int orientation; + try { + orientation = getExifTransorm(in); + } catch (Exception e) { + // no EXIF transform, ok + orientation = -1; + } - if (image == null) { - throw new IOException("Failed to convert input to image"); - } + in.reset(); - // Note: this code has been found on Internet; - // thank you anonymous coder. - int width = image.getWidth(); - int height = image.getHeight(); - AffineTransform affineTransform = new AffineTransform(); - - switch (orientation) { - case 1: - affineTransform = null; - break; - case 2: // Flip X - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-width, 0); - break; - case 3: // PI rotation - affineTransform.translate(width, height); - affineTransform.rotate(Math.PI); - break; - case 4: // Flip Y - affineTransform.scale(1.0, -1.0); - affineTransform.translate(0, -height); - break; - case 5: // - PI/2 and Flip X - affineTransform.rotate(-Math.PI / 2); - affineTransform.scale(-1.0, 1.0); - break; - case 6: // -PI/2 and -width - affineTransform.translate(height, 0); - affineTransform.rotate(Math.PI / 2); - break; - case 7: // PI/2 and Flip - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-height, 0); - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - case 8: // PI / 2 - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - default: - affineTransform = null; - break; - } + try { + image = ImageIO.read(in); + } catch (IllegalArgumentException e) { + throw e; + } catch (Exception e) { + throw new IOException("Undocumented exception occured, " + + "converting to IOException", e); + } + + if (image == null) { + throw new IOException("Failed to convert input to image"); + } + + // Note: this code has been found on Internet; + // thank you anonymous coder. + int width = image.getWidth(); + int height = image.getHeight(); + AffineTransform affineTransform = new AffineTransform(); + + switch (orientation) { + case 1: + affineTransform = null; + break; + case 2: // Flip X + affineTransform.scale(-1.0, 1.0); + affineTransform.translate(-width, 0); + break; + case 3: // PI rotation + affineTransform.translate(width, height); + affineTransform.rotate(Math.PI); + break; + case 4: // Flip Y + affineTransform.scale(1.0, -1.0); + affineTransform.translate(0, -height); + break; + case 5: // - PI/2 and Flip X + affineTransform.rotate(-Math.PI / 2); + affineTransform.scale(-1.0, 1.0); + break; + case 6: // -PI/2 and -width + affineTransform.translate(height, 0); + affineTransform.rotate(Math.PI / 2); + break; + case 7: // PI/2 and Flip + affineTransform.scale(-1.0, 1.0); + affineTransform.translate(-height, 0); + affineTransform.translate(0, width); + affineTransform.rotate(3 * Math.PI / 2); + break; + case 8: // PI / 2 + affineTransform.translate(0, width); + affineTransform.rotate(3 * Math.PI / 2); + break; + default: + affineTransform = null; + break; + } - if (affineTransform != null) { - AffineTransformOp affineTransformOp = new AffineTransformOp( - affineTransform, AffineTransformOp.TYPE_BILINEAR); + if (affineTransform != null) { + AffineTransformOp affineTransformOp = new AffineTransformOp( + affineTransform, AffineTransformOp.TYPE_BILINEAR); - BufferedImage transformedImage = new BufferedImage(width, height, - image.getType()); - transformedImage = affineTransformOp - .filter(image, transformedImage); + BufferedImage transformedImage = new BufferedImage(width, + height, image.getType()); + transformedImage = affineTransformOp.filter(image, + transformedImage); - image = transformedImage; + image = transformedImage; + } + // + } finally { + in.close(); } - // return image; } -- 2.27.0