1

I am trying to compare an embedded image located in a MP3 file with the exact same image saved as a JPG. If the images are identical then I would like to perform some further processing, however, when I compare the 2 images (RGB comparison) I keep getting false.

I am sure that the images are identical because I extracted the image from the same MP3 to originally create the JPG using the following code.

Artwork aw = tag.getFirstArtwork();

ByteArrayInputStream bis = new ByteArrayInputStream(aw.getBinaryData());
BufferedImage imgA = ImageIO.read(bis);

File outputfile = new File("expectedImage.jpg");
ImageIO.write(imgA, "jpg", outputfile);


After I ran that to get the image I just commented out that section, now I have the following code in place to compare the MP3 embedded image with the JPG

Extract the MP3 image and call the comparison method

try {
    Artwork aw = tag.getFirstArtwork();

    ByteArrayInputStream bis = new ByteArrayInputStream(aw.getBinaryData());
    BufferedImage imgA = ImageIO.read(bis);

    File expectedImageFile = new File("expectedImage.jpg");
    BufferedImage imgB = ImageIO.read(expectedImageFile);

    if(compareImages(imgA, imgB)) {
        System.out.println("The Images Match.");
    }else {
        System.out.println("The Images Do Not Match.");
    }
} 
catch (IOException e) {
    e.printStackTrace();
}


Compare The Images
The method fails when comparing the pixels for equality on the first pass through the loop.

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;
} 
oznomal
  • 439
  • 2
  • 8
  • 22
  • 1
    You are not reading the binary data and saving it, you’re creating an image and saving it. This results in a different image since JPEG is lossy and the result will depend on the encoder and settings, for example. You need to save the actual binary data directly to be able to get the same decoded result. – Sami Kuhmonen Jul 29 '18 at 20:19

2 Answers2

0

I try you code and read the @Sami Kuhmonen comment and I understand.

When you use ImageIO.write(imgA, "jpg", outputfile) you pass by an other encoder and you can loss data.

You need change this by the standard technique.

Example [UPDATED]

public static void main(String[] args) {

    try {
        //Write the picture to BAOS
        ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
        byteBuffer.write(aw.getBinaryData(), 0, 1);

        //New file target
        File outputfile = new File("expectedImage.jpg");
        OutputStream outputStream = new FileOutputStream(outputfile);
        byteBuffer.writeTo(outputStream);
        outputStream.close();


        File expectedImageFile = new File("expectedImage.jpg");

        ByteArrayInputStream bis = new ByteArrayInputStream(aw.getBinaryData());
        BufferedImage imgA = ImageIO.read(bis);
        FileInputStream fis = new FileInputStream(expectedImageFile);
        BufferedImage imgB = ImageIO.read(fis);

        if(compareImages(imgA, imgB)) {
            System.out.println("The Images Match.");
        }else {
            System.out.println("The Images Do Not Match.");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }


}

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;
}
Crammeur
  • 678
  • 7
  • 17
  • 1
    I understand the concept of why its not working based on the comment, however, I tried this snippet and it doesn't work. The File Object that was created for imgB ends up throwing a NPE in the compareImages method. – oznomal Jul 29 '18 at 23:17
  • Can you check if the `output file` is 0kb. Because I think is this cause the NPE. – Crammeur Jul 29 '18 at 23:23
  • I think this can help you https://stackoverflow.com/questions/9943962/imageio-read-returns-null-with-no-errors – Crammeur Jul 29 '18 at 23:43
0

I've been a little busy lately, but I finally got a chance to look back into this today and based on what was said above I figured that the main issue was that the image was being compressed in one case and in the other it wasn't. I am sure there is a better solution but a quick dirty fix was to just save a temporary JPEG version of the image that I would like to check for, then do the comparison using 2 buffered images, one that reads in the JPEG file I have saved to the directory and one that reads in the temp JPEG I just created and when the test is complete just use the File.delete() to remove the temp file.

Extract the MP3 image and call the comparison method
The Compare method is the same as originally stated

Artwork aw = tag.getFirstArtwork();
ByteArrayInputStream bis = new ByteArrayInputStream(aw.getBinaryData());

BufferedImage tempImg = ImageIO.read(bis);

File tempFile = new File("temp.jpg");
ImageIO.write(tempImg, "jpg", tempFile);

BufferedImage imgA = ImageIO.read(tempFile);

File expectedImageFile = new File("imgToCheckAgainst.jpg");
BufferedImage imgB = ImageIO.read(expectedImageFile);

if(compareImages(imgA, imgB)) {
    System.out.println("The Images Match");
}else {
    System.out.println("The images do not match.");
}

tempFile.delete();
oznomal
  • 439
  • 2
  • 8
  • 22