Omer Hassan Alam
Omer Hassan Alam

Reputation: 13

Create a bufferedImage backed by a ByteBuffer

I want to create a BufferedImage that uses a pre-allocated ByteBuffer as its storage or is "backed" by it.

I've read about people suggesting to write a custom WritableRaster but I've seen no proper example involving ByteBuffers. Most of these web pages are defunct now as well.

How would I go about doing this?

Upvotes: 0

Views: 688

Answers (2)

leftbit
leftbit

Reputation: 838

Stumbled upon this question trying to solve the same problem. Strangely, the following code seems to run faster than the accepted solution. Can't figure out why - this looks so ineffective...

final ByteBuffer pImageBuffer = ByteBuffer.allocateDirect((int) size);
final byte[] buffer = new byte[pImageBuffer.capacity()];
while (capturing) {
  // populate pImageBuffer via JNI
  pImageBuffer.rewind();
  for (int n = 0; n < pImageBuffer.capacity(); ++n) {
    buffer[n] = pImageBuffer.get(n);
  }
  pImageBuffer.clear();

  final BufferedImage retrievedImage = new BufferedImage(captureWidth, captureHeight, BufferedImage.TYPE_4BYTE_ABGR);
  retrievedImage.getRaster().setDataElements(0, 0, captureWidth, captureHeight, buffer);
}

Upvotes: 0

Harald K
Harald K

Reputation: 27113

Have a look at my MappedImageFactory and MappedFileBuffer classes here. They are made for using memory-mapped file buffers, but as they use the same interface (java.nio.Buffer), you should easily be able to modify them to use pre-allocated ByteBuffers.

These images probably won't be super-fast to render and display, but may be "good enough".

See this answer, using IntBuffers for more ideas. Here's that code modified for ByteBuffer:

public class ByteBufferTest {
    public static void main(String[] args) {
        Dimension dim = new Dimension(100, 100);
        int size = dim.width * dim.height * 4;

        final ByteBuffer buf = ByteBuffer.allocate(size);

        DataBuffer dbuf = new DataBuffer(DataBuffer.TYPE_BYTE, size) {
            @Override
            public void setElem(int bank, int i, int val) {
                buf.put(i, (byte) val);
            }

            @Override
            public int getElem(int bank, int i) {
                return buf.get(i);
            }
        };

        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
        ColorModel cm = new ComponentColorModel(cs, new int[]{8, 8, 8, 8}, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);

        SampleModel sm = cm.createCompatibleSampleModel(dim.width, dim.height);
        WritableRaster raster = new WritableRaster(sm, dbuf, new Point()) {};
        BufferedImage img = new BufferedImage(cm, raster, false, null);

        System.err.println("img: " + img);
    }
}

Output:

img: BufferedImage@4f3f5b24: type = 0 ColorModel: #pixelBits = 32 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@15aeb7ab transparency = 1 has alpha = true isAlphaPre = false ByteBufferTest$2@7b23ec81

If your ByteBuffers are allocated using Java arrays (heap), you could probably also use completely standard BufferedImages, by creating a normal DataBubfferByte around the buffer's array().

Upvotes: 2

Related Questions