2

I'm trying to read in an image file, convert it into a bytes array, process the individual bytes, and then convert it back into an image file and export it.

I've tried working on it, but it seems that ImageIO.read can't read the ByteInputArrayStream - it returns null.

Here's what I've tried so far (and the line that throws the error)

public static void RGBToGrayManual2(BufferedImage original) {
    byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();

    /*
     *  Code to process pixels
     */

    ByteArrayInputStream grayscaleByteInputStream = new ByteArrayInputStream(pixels);
    BufferedImage convertedGrayscale = null;


    try {
        // below line throws the error
        convertedGrayscale = ImageIO.read(grayscaleByteInputStream);

        ImageIO.write(convertedGrayscale, "jpg", new File("converted-grayscale-002.jpg"));
    } catch (IOException e) {
        System.err.println("IOException: " + e);
    }   
}

And the error message

Exception in thread "main" java.lang.IllegalArgumentException: image == null! at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925) at javax.imageio.ImageIO.getWriter(ImageIO.java:1591) at javax.imageio.ImageIO.write(ImageIO.java:1520) at project2.ImageProcessing.RGBToGrayManual2(ImageProcessing.java:252) at project2.ImageProcessing.main(ImageProcessing.java:284)

I've also looked at a similar post - Null returned from ImageIO.read(new ByteArrayInputStream(bs)); - and the accepted answer seems to suggest it's a problem with the encoding.

I've looked at this other post - Which Java library provides base64 encoding/decoding? - to decode the bytes array, but I don't think I'm doing it right.

Here's what I tried:

String encodedPixelsString = DatatypeConverter.printBase64Binary(pixels);
byte[] decodedPixelsString = DatatypeConverter.parseBase64Binary(encodedPixelsString);
ByteArrayInputStream pixelsStreamInputStream = new ByteArrayInputStream(decodedPixelsString);

And passed in the decoded array's ByteArrayInputStream as an argument

    convertedGrayscale = ImageIO.read(pixelStreamInputStream);

However it yielded the exact same error message.

My thoughts on two possible directions to solve this problem - but I'm not sure about the details:

  1. Find out the problem with ImageIO.read method
  2. Try exposing the bytes array of the image file in a different way

This is an assignment we have to do, but I've never worked with image processing before and as such, I'm a bit lost as to what to do. I would really appreciate any pointers

Community
  • 1
  • 1
Code Apprentice
  • 522
  • 2
  • 7
  • 19

1 Answers1

10

First of all, the exception is not from the ImageIO.read(...) method. It returns null, as it should. The exception happens because of that though, when you invoke ImageIO.write(...) with the null image.

Now, the reason ImageIO.read(...) returns null for your input is simply because ImageIO reads and writes images from/to file formats. Your pixels byte array is not in a file format, it is raw pixel data (and, no, this has nothing to do with Base64 or other string encodings).

Now, assuming that your pixel array is 8 bits/pixel gray scale format (important, the below code won't work if this assumption is wrong, but you haven't provided enough information for others to determine this, so you might need to modify the code to fit your data), you can easily re-create the BufferedImage:

byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();

/*
 *  Code to process pixels (just as before)
 */

// Replace the ImageIO.read invocation with the following code
// Note that *pixels* must be in 8 bits/pixel (grayscale) for this to work,
// it is not cheating! :-)
BufferedImage convertedGrayscale = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayScale.getRaster().setDataElements(0, 0, width, height, pixels);

try {
    ImageIO.write(convertedGrayscale, "jpg", new File("converted-grayscale-002.jpg"));
} 
catch (IOException e) {
    System.err.println("IOException: " + e);
}
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • @heraldK I was actually thinking of something along those lines - so I was thinking of using that as input to construct a File object, but I'm not sure how to do it. Your assumption is correct :) The pixel data is 8 bits / pixel. I can't, however, construct a new BufferedImage with TYPE_BYTE_GRAY - our task is to write a method that processes the image on a pixel level. – Code Apprentice Dec 17 '15 at 06:33
  • @heraldK I'm sorry I forgot to add - if you could point out how to construct a File object from a ByteArrayInputStream to use as an argument for the ImageIO.read() method, and it works, I'll mark this answer as correct. Thanks :) – Code Apprentice Dec 17 '15 at 07:51
  • @CodeApprentice ?? And why is that? Your problem was reading the image *after* processing, and I solved that problem. You should not and can not read this using `ImageIO.read()`, because it's raw pixel data. The processing part I leave to you, this is an assignment. But when you construct the new `BufferedImage` using the code in my answer, you can pass that image to `ImageIO.write(convGray, "JPEG", new File(...))`. – Harald K Dec 17 '15 at 07:55
  • @heraldK Ah - I see! So the train of thought here is to construct a new image of the type TYPE_BYTE_GRAY and then set the pixels to the processed pixels. I misunderstood. Thanks for being patient! :) – Code Apprentice Dec 17 '15 at 08:33