Search code examples
javaawt

Is there a simple way to compare BufferedImage instances?


I am working on part of a Java application that takes an image as a byte array, reads it into a java.awt.image.BufferedImage instance and passes it to a third-party library for processing.

For a unit test, I want to take an image (from a file on disk) and assert that it is equal to the same image that has been processed by the code.

  • My expected BufferedImage is read from a PNG file on disk using ImageIO.read(URL).
  • My test code reads the same file into a BufferedImage and writes that to a byte array as PNG to provide to the system under test.

When the system under test writes the byte array to a new BufferedImage I want to assert that the two images are equal in a meaningful way. Using equals() (inherited from Object) doesn’t work (of course). Comparing BufferedImage.toString() values also doesn’t work because the output string includes object reference information.

Does anybody know any shortcuts? I would prefer not to bring in a third-party library for a single unit test in a small part of a large application.


Solution

  • This is the best approach. No need to keep a variable to tell whether the image is still equal. Simply return false immediately when the condition if false. Short-circuit evaluation helps save time looping over pixels after the comparison fails as is the case in trumpetlick's answer.

    /**
     * Compares two images pixel by pixel.
     *
     * @param imgA the first image.
     * @param imgB the second image.
     * @return whether the images are both the same or not.
     */
    public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
      // The images must be the same size.
      if (imgA.getWidth() != imgB.getWidth() || imgA.getHeight() != imgB.getHeight()) {
        return false;
      }
    
      int width  = imgA.getWidth();
      int height = imgA.getHeight();
    
      // Loop over every pixel.
      for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
          // Compare the pixels for equality.
          if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
            return false;
          }
        }
      }
    
      return true;
    }