Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 9 ImageIO read\write gives a different result than Java 8

The following test fails on Java 9 while passes in Java 8:

@Test
public void getImage_SetValueUsingConstructor_ShouldReturnCorrectValue() throws Exception {
        String base64ImageString = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAEUlEQVR42mNgQAP/wQAbBw4ANwsL9Zo6V30AAAAASUVORK5CYII=";
    byte[] rawImageBytes = Base64.getDecoder().decode(base64ImageString);

    ByteArrayInputStream bis = new ByteArrayInputStream(rawImageBytes);
    RenderedImage image = ImageIO.read(bis);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ImageIO.write(image, "PNG", bos);
    byte[] imageBytesFromImage = bos.toByteArray();

    assertArrayEquals(imageBytesFromImage, rawImageBytes);
}

Java 9 output: arrays first differed at element [42]; Expected :94 Actual :-38

Can anyone help me understand what was changed in Java 9, and is there a way to write this code so that it will work for both Java 8 & 9?

like image 459
AntonKam Avatar asked Sep 12 '25 11:09

AntonKam


1 Answers

As @Holger has pointed out in the comments, it is really the test that is flawed. While identical Base64 representations will give identical images, different Base64 representations does not mean the image data is different. It could mean only that the same image data is encoded differently, and will decode to the exact same image (which is the case here).

The reason your test used to pass without error, is probably that you used the Java 8 PNGImageWriter (or earlier, it hasn't really changed much since Java 1.4), which is the writer plugin used if you do ImageIO.write(image, "PNG", output), to encode the image and created the Base64 representation from it. If you had created the Base64 representation of the bytes from a file created by a different program/library, it would almost certainly be different.

You should rewrite your test, it is however not really clear to me what you are trying to test here.

If you only care about pixel data, you could just loop over the pixels and test for equality:

BufferedImage original = ImageIO.read(..);
BufferedImage current = ImageIO.read(..);

assertEquals(original.getWidth(), current.getWidth());
assertEquals(original.getHeight(), current.getHeight());

for (int y = 0; y < original.getHeight(); y++) {
    for (int x = 0; x < original.getWidth(); x++) {
        assertEquals(original.getRGB(x, y), current.getRGB(x, y));
    }
}

If you also need the metadata to be preserved, you also need to test for equality there. But PNG doesn't really contain much interesting metadata, so I doubt you need that.

like image 112
Harald K Avatar answered Sep 16 '25 07:09

Harald K