Using IntBuffer for BufferedImage

丶灬走出姿态 提交于 2021-02-10 13:15:30

问题


As the title aleady says, it want to create a BufferedImage that is backed by a specific (already existing) IntBuffer.

Up to this point, I have the following code:

final IntBuffer buf = ...;
DataBuffer dbuf = new DataBuffer(DataBuffer.TYPE_INT,size) {
    public void setElem(int bank, int i, int val) {
        buf.put(i,val);
    }
    public int getElem(int bank, int i) {
        return buf.get(i);
    }
};
ColorModel cm = ColorModel.getRGBdefault();
SampleModel sm = cm.createCompatibleSampleModel(dim.width,dim.height);
WritableRaster raster = WritableRaster.createWritableRaster(sm,dbuf,null);
BufferedImage img = new BufferedImage(cm,raster,false,new Hashtable<>());

This code however shows the following error:

Exception in thread "main" java.awt.image.RasterFormatException: IntegerComponentRasters must haveinteger DataBuffers
at sun.awt.image.IntegerComponentRaster.<init>(Unknown Source)
at sun.awt.image.IntegerInterleavedRaster.<init>(Unknown Source)
at sun.awt.image.IntegerInterleavedRaster.<init>(Unknown Source)
at java.awt.image.Raster.createWritableRaster(Unknown Source)
at test.Test.main(Test.java:100)

(The line is the one where the WritableRaster is created.) It is very important to me that the data doesn´t have to be copied, because I´ll use BufferedImage mainly as a comfortable interface to write to the underlying IntBuffer (with some few exceptions).


回答1:


I had a very similar problem, trying to create a DataBuffer backed by a nio ByteBuffer. What you are trying to do is possible, but not using the Raster.createWritableRaster methods (I think it's a bug, but it's been like that for ages, so don't expect it to be fixed any time soon). You need to directly create an instance of a writable raster.

Either:

WritableRaster = new sun.awt.image.SunWritableRaster(...);

Or, create your own subclass of WritableRaster (it's trivial, you don't actually need to override any methods, except maybe toString to aid debugging).

class GenericWritableRaster extends WritableRaster {
    public GenericWritableRaster(SampleModel model, DataBuffer buffer, Point origin) {
        super(model, buffer, origin);
    }
}

WritableRaster = new GenericWritableRaster(...);

For some inspiration, you can have a look at my GenericWritableRaster implementation, and
the MappedImageFactory class for how to use it.

The resulting images will always be of type BufferedImage.TYPE_CUSTOM (and thus probably slow from Java), but this is probably no problem for you if you have a library that already holds the images in the graphics card's RAM.


Update, here's an SSCCE PoC based on your code:

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

        final IntBuffer buf = IntBuffer.wrap(new int[size]);

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

            public int getElem(int bank, int i) {
                return buf.get(i);
            }
        };
        ColorModel cm = ColorModel.getRGBdefault();
        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);
    }
}

Prints:

img: BufferedImage@234441b6: type = 0 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000 com.twelvemonkeys.image.BufferTest$2@563625d0



回答2:


I had a look at the bytecode of IntegerComponentRaster, which throws your exception, and it explicitly checks whether the DataBuffer instance you pass in is a subclass of DataBufferInt. Unfortunately, you cannot easily extend this class, as it's declared final. So I'm afraid you can't do what you need.

As an alternative, maybe you can create the DataBuffer first, and then wrap its contents in a IntBuffer? Something like this:

DataBufferInt dbuf = new DataBufferInt(size);
IntBuffer buf = IntBuffer.wrap(dbuf.getData());
// Fill the IntBuffer etc...


来源:https://stackoverflow.com/questions/20025596/using-intbuffer-for-bufferedimage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!