package com.gorillalogic.monkeytalk.utils; import java.awt.Color; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; /** * Helper class for comparing images. */ public class ImageUtils { public static int DEFAULT_TOLERANCE = 5; public static int MIN_TOLERANCE = 0; public static int MAX_TOLERANCE = 255; /** * Load the image from the given path. * * @param path * path to the image file * @return the image as a BufferedImage */ public static BufferedImage getImageFromFile(String path) throws IOException { return getImageFromFile(new File(path)); } /** * Load the image from the given file. * * @param file * the file containing the image * @return the image as a BufferedImage */ public static BufferedImage getImageFromFile(File file) throws IOException { BufferedImage image = ImageIO.read(file); return image; } /** * Save the given image as a PNG file. * * @param filename * the filename of the new image * @param image * the image to save * @return true if save was successful, otherwise false */ public static boolean savePNG(String filename, BufferedImage image) { boolean success = true; try { File outputfile = new File(filename); ImageIO.write(image, "png", outputfile); } catch (IOException ioe) { ioe.printStackTrace(); success = false; } return success; } /** * Get the dimensions of the given image. * * @param image * the image * @return the image dimensions */ public static Dimension getDimensions(BufferedImage image) { Dimension dimension = null; if (image != null) { dimension = new Dimension(image.getWidth(null), image.getHeight(null)); } return dimension; } /** * Crop the given rectangle out of the original image and return it. * * @param uncroppedImage * the original (uncropped) image * @param x * crop rectangle top left x * @param y * crop rectangle top left y * @param w * crop rectangle width * @param h * crop rectangle height * @return the cropped image */ public static BufferedImage cropImage(BufferedImage uncroppedImage, int x, int y, int w, int h) { return uncroppedImage.getSubimage(x, y, w, h); } /** * Compare two BufferedImage objects pixel-by-pixel for each byte of color (R,G,B,A). Returns * true if and only if the images are an exact match (aka tolerance=0). Immediately returns * false if images are different dimensions. * * @param img1 * first image * @param img2 * second image * @return true if they are perfectly equal, otherwise false */ public static boolean compare(BufferedImage img1, BufferedImage img2) { return compare(img1, img2, DEFAULT_TOLERANCE); } /** * Compare two BufferedImage objects pixel-by-pixel for each byte of color (R,G,B,A) using the * given tolerance. Immediately returns false if images are different dimensions. * * @param img1 * first image * @param img2 * second image * @param tolerance * the amount each byte of color can vary * @return true if they are equal within the tolerance, otherwise false */ public static boolean compare(BufferedImage img1, BufferedImage img2, int tolerance) { int width = img1.getWidth(); int height = img1.getHeight(); if (width != img2.getWidth() || height != img2.getHeight()) { return false; } for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (!equalsWithTolerance(img1.getRGB(j, i), img2.getRGB(j, i), tolerance)) { return false; } } } return true; } /** * Helper to compare two colors (including alpha) with the given tolerance. * * @param pixel1 * color one * @param pixel2 * color two * @param tolerance * the amount each color can vary * @return true if they are equal within the tolerance, otherwise false */ private static boolean equalsWithTolerance(int pixel1, int pixel2, int tolerance) { Color color1 = new Color(pixel1, true); Color color2 = new Color(pixel2, true); if (color1.getRed() > (color2.getRed() + tolerance)) { return false; } if (color1.getRed() < (color2.getRed() - tolerance)) { return false; } if (color1.getGreen() > (color2.getGreen() + tolerance)) { return false; } if (color1.getGreen() < (color2.getGreen() - tolerance)) { return false; } if (color1.getBlue() > (color2.getBlue() + tolerance)) { return false; } if (color1.getBlue() < (color2.getBlue() - tolerance)) { return false; } if (color1.getAlpha() > (color2.getAlpha() + tolerance)) { return false; } if (color1.getAlpha() < (color2.getAlpha() - tolerance)) { return false; } return true; } }