X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fui%2FImageUtilsAwt.java;h=c273e0d45879628543dcab75f2c7c88f133224d9;hb=844d50dbf3ceb3480b0effc9085752de503856aa;hp=148f8f57451141805c508de08e8254b0f3e2d407;hpb=354666447f9c71a7fb2e15d9c50ed62ce27d7108;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/ui/ImageUtilsAwt.java b/src/be/nikiroo/utils/ui/ImageUtilsAwt.java index 148f8f5..c273e0d 100644 --- a/src/be/nikiroo/utils/ui/ImageUtilsAwt.java +++ b/src/be/nikiroo/utils/ui/ImageUtilsAwt.java @@ -1,17 +1,20 @@ 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; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; 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; /** * This class offer some utilities based around images and uses java.awt. @@ -19,6 +22,29 @@ import be.nikiroo.utils.ImageUtils; * @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 + ImageIO.getCacheDirectory(); + return true; + } + @Override public void saveAsImage(Image img, File target, String format) throws IOException { @@ -69,89 +95,240 @@ 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; - } + return fromImage(img, Rotation.NONE); + } - in.reset(); + /** + * 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 { - 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) { + 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(data, "UTF-8"); + } catch (Exception e) { + extra = ", content unavailable"; + } + } + String ssize = StringUtils.formatNumber(img.getSize()); + throw new IOException( + "Failed to convert input to image, size was: " + ssize + + extra); + } - if (affineTransform != null) { - AffineTransformOp affineTransformOp = new AffineTransformOp( - affineTransform, AffineTransformOp.TYPE_BILINEAR); + // Note: this code has been found on Internet; + // thank you anonymous coder. + int width = image.getWidth(); + int height = image.getHeight(); + AffineTransform affineTransform = new AffineTransform(); - BufferedImage transformedImage = new BufferedImage(width, height, - image.getType()); - transformedImage = affineTransformOp - .filter(image, transformedImage); + 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 (rotation == null) + rotation = Rotation.NONE; + + switch (rotation) { + case RIGHT: + if (affineTransform == null) { + affineTransform = new AffineTransform(); + } + affineTransform.translate(height, 0); + affineTransform.rotate(Math.PI / 2); + + int tmp = width; + width = height; + height = tmp; + + break; + case LEFT: + if (affineTransform == null) { + affineTransform = new AffineTransform(); + } + affineTransform.translate(0, width); + affineTransform.rotate(3 * Math.PI / 2); + + int temp = width; + width = height; + height = temp; + + 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( + affineTransform, AffineTransformOp.TYPE_BILINEAR); - image = transformedImage; + BufferedImage transformedImage = new BufferedImage(width, + height, image.getType()); + transformedImage = affineTransformOp.filter(image, + transformedImage); + + image = transformedImage; + } + // + } finally { + in.close(); } - // return image; } + + /** + * Scale a dimension. + * + * @param imageSize + * the actual image size + * @param areaSize + * the base size of the target to get snap sizes for + * @param zoom + * the zoom factor (ignored on snap mode) + * @param snapMode + * NULL for no snap mode, TRUE to snap to width and FALSE for + * snap to height) + * + * @return the scaled (minimum is 1x1) + */ + public static Dimension scaleSize(Dimension imageSize, Dimension areaSize, + double zoom, Boolean snapMode) { + Integer[] sz = scaleSize(imageSize.width, imageSize.height, + areaSize.width, areaSize.height, zoom, snapMode); + return new Dimension(sz[0], sz[1]); + } + + /** + * Resize the given image. + * + * @param image + * the image to resize + * @param areaSize + * the base size of the target dimension for snap sizes + * @param zoom + * the zoom factor (ignored on snap mode) + * @param snapMode + * NULL for no snap mode, TRUE to snap to width and FALSE for + * snap to height) + * + * @return a new, resized image + */ + public static BufferedImage scaleImage(BufferedImage image, + Dimension areaSize, double zoom, Boolean snapMode) { + Dimension scaledSize = scaleSize( + new Dimension(image.getWidth(), image.getHeight()), areaSize, + zoom, snapMode); + + return scaleImage(image, scaledSize); + } + + /** + * Resize the given image. + * + * @param image + * the image to resize + * @param targetSize + * the target size + * + * @return a new, resized image + */ + public static BufferedImage scaleImage(BufferedImage image, + Dimension targetSize) { + BufferedImage resizedImage = new BufferedImage(targetSize.width, + targetSize.height, BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D g = resizedImage.createGraphics(); + try { + g.drawImage(image, 0, 0, targetSize.width, targetSize.height, null); + } finally { + g.dispose(); + } + + return resizedImage; + } }