0

I have a byte array containing data of the raw grayscale 8bit image, which I need to convert to a BufferedImage. I've tried doing:

BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));

However, the resulting image object is null which means I'm doing something wrong here.

What's the correct way of making such a conversion?

3 Answers 3

5

There are two good ways to do this, depending on your use case.

Either create a new, gray image, and copy the data into it. This will keep the image "managed", which may lead to better rendering performance (ie. on screen). But it will need twice as much memory, and copy the data from your input to the image.

The other, is to create the gray image directly "around" your existing pixel data. This will be faster, and use almost no extra heap, as it avoids copying the pixel data. But the image will not be managed (as the backing array is exposed and mutable).

Both options are demonstrated below:

int w = 640;
int h = 480;

byte[] imageBytes = new byte[w * h];

// 1 Keeps the image "managed" at the expense of twice the memory + a large array copy
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
image.getRaster().setDataElements(0, 0, w, h, imageBytes);

System.out.println("image: " + image);

// 2 Faster, and uses less memory, but will make the image "unmanaged"
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(new DataBufferByte(imageBytes, imageBytes.length), w, h, w, 1, new int[]{0}, null);
BufferedImage image2 = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);

System.out.println("image2: " + image2);

If the image data isn't in linear gray color space, one could use an IndexColorModel to map the input into whatever range you want:

// Alternate, using IndexColorModel, if your input isn't in linear gray color space
int[] cmap = new int[256]; // TODO: Add ARGB packed colors here...
IndexColorModel icm = new IndexColorModel(8, 256, cmap, 0, false, -1, DataBuffer.TYPE_BYTE);

// As 1
BufferedImage image3 = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED, icm);
image3.getRaster().setDataElements(0, 0, w, h, imageBytes);
System.out.println("image3: " + image3);

// As 2
BufferedImage image4 = new BufferedImage(icm, raster, cm.isAlphaPremultiplied(), null);

System.out.println("image4: " + image4);
Sign up to request clarification or add additional context in comments.

Comments

0

Java

 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
 image.getRaster().setDataElements(0, 0, width, height, array));

Kotlin

val image = BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY)
image.raster.setDataElements(0, 0, width, height, byteArray )

Comments

0

I've managed to do the conversion for the 640x480 resolution the following way:

BufferedImage image = new BufferedImage(640,480,BufferedImage.TYPE_BYTE_INDEXED);

int i = 0;
for(int y = 0; y < 480; y++)
{
    for(int x = 0; x < 640; x++)
    {
        int g = imageBytes[i++] & 0xFF;
        image.setRGB(x,y,new Color(g,g,g).getRGB());
    }
}

EDIT: removed useless code (thanks to Marco13)

4 Comments

Why not TYPE_BYTE_GRAY?
What should the round call accomplish here?
@rustyx It worked for me as well, though the contrast level was too low and due to that, some areas of the image were super dark. With the TYPE_BYTE_INDEXED everything looks OK (I used http://rawpixels.net/ to make a comparison).
Using TYPE_BYTE_INDEXED without an explicit IndexColorModel parameter, will give you a default model, which is the 216 web safe colors + 40 grays. You will certainly lose some fidelity here. Also, the inverse lookup that happens using setRGB on a BufferedImage with IndexColorModel is really slow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.