问题
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