6

I'm trying to convert a Buffered image into a ByteBuffer but i get this exception

java.awt.image.DataBufferInt cannot be cast to java.awt.image.DataBufferByte

can someone please help me out and suggest a good method of conversion.

Source:

public static ByteBuffer convertImageData(BufferedImage bi) 
{
    byte[] pixelData = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
    //        return ByteBuffer.wrap(pixelData);
    ByteBuffer buf = ByteBuffer.allocateDirect(pixelData.length);
    buf.order(ByteOrder.nativeOrder());
    buf.put(pixelData);
    buf.flip();
    return buf;
}

this is my object

 ByteBuffer buf = convertImageData(image);
Harald K
  • 26,314
  • 7
  • 65
  • 111
Sumal Perera
  • 297
  • 1
  • 3
  • 6
  • 1
    When you create a buffered image, you can give it a constant that dictates the colour space of the image. It looks like you are mixing int and byte type images. For example, http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#TYPE_BYTE_INDEXED . You can also use http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType%28%29 to find out the type of an existing image – BretC Mar 27 '15 at 13:51

2 Answers2

5

You can't just cast an arbitrary databuffer to DataBufferByte, you need to make sure it actually is the right type:

ByteBuffer byteBuffer;
DataBuffer dataBuffer = bi.getRaster().getDataBuffer();

if (dataBuffer instanceof DataBufferByte) {
    byte[] pixelData = ((DataBufferByte) dataBuffer).getData();
    byteBuffer = ByteBuffer.wrap(pixelData);
}
else if (dataBuffer instanceof DataBufferUShort) {
    short[] pixelData = ((DataBufferUShort) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 2);
    byteBuffer.asShortBuffer().put(ShortBuffer.wrap(pixelData));
}
else if (dataBuffer instanceof DataBufferShort) {
    short[] pixelData = ((DataBufferShort) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 2);
    byteBuffer.asShortBuffer().put(ShortBuffer.wrap(pixelData));
}
else if (dataBuffer instanceof DataBufferInt) {
    int[] pixelData = ((DataBufferInt) dataBuffer).getData();
    byteBuffer = ByteBuffer.allocate(pixelData.length * 4);
    byteBuffer.asIntBuffer().put(IntBuffer.wrap(pixelData));
}
else {
    throw new IllegalArgumentException("Not implemented for data buffer type: " + dataBuffer.getClass());
}

If your BufferedImage is one of the standard types (BufferedImage.TYPE_* other than TYPE_CUSTOM) the above should work.

Note that special DatBuffer subclasses may exist, and may store pixels in multiple banks, with different byte order, might be channel interleaved (rather than the standard pixel interleaved) etc. So the above code is still not completely general.

If you are to pass these ByteBuffers to native code, using allocateDirect(..) and copying the pixels over might be faster, otherwise I think using wrap(..) will make for both simpler code and be more efficient.

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Is it possible to avoid copying large amounts of bytes from place to place? – Dims Mar 17 '17 at 07:38
  • Since we apparently can't avoid copying, I used `ImageIO` solution, because it is native for images. – Dims Mar 17 '17 at 11:53
  • @Dims If it works for your use case, sure. Using `ImageIO` to encode the data in a file format is always going to be slower than just copying bytes though. – Harald K Mar 17 '17 at 12:09
3

If you want to encode the image data, you may want to use the ImageIO here. Something like this:

public static ByteBuffer convertImageData(BufferedImage bi) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        ImageIO.write(bi, "png", out);
        return ByteBuffer.wrap(out.toByteArray());
    } catch (IOException ex) {
        //TODO
    }
    return null;
}

Here is the list of supported formats.

eeq
  • 2,108
  • 12
  • 21
  • 4
    While your code will compile and run, it really does something completely different than what the OP was trying to achieve in his code block. The code seems to expect a byte buffer containing "raw" pixels, what he will get here, is a buffer containing a PNG file. – Harald K Mar 30 '15 at 08:47