I'm trying to get a BufferedImage from raw samples, but I get exceptions about trying to read past the available data range which I just don't understand. What I'm trying to do is:
val datasize = image.width * image.height
val imgbytes = image.data.getIntArray(0, datasize)
val datamodel = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, image.width, image.height, Array(image.red_mask.intValue, image.green_mask.intValue, image.blue_mask.intValue))
val buffer = datamodel.createDataBuffer
val raster = Raster.createRaster(datamodel, buffer, new Point(0,0))
datamodel.setPixels(0, 0, image.width, image.height, imgbytes, buffer)
val newimage = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB)
newimage.setData(raster)
Unfortunately I get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 32784
at java.awt.image.SinglePixelPackedSampleModel.setPixels(SinglePixelPackedSampleModel.java:689)
at screenplayer.Main$.ximage_to_swt(Main.scala:40)
at screenplayer.Main$.main(Main.scala:31)
at screenplayer.Main.main(Main.scala)
The data is standard RGB with 1 byte padding (so that 1 pixel == 4 bytes) and the image size is 1366x24 px.
I finally got the code to run with the suggestion below. The final code is:
val datasize = image.width * image.height
val imgbytes = image.data.getIntArray(0, datasize)
val raster = Raster.createPackedRaster(DataBuffer.TYPE_INT, image.width, image.height, 3, 8, null)
raster.setDataElements(0, 0, image.width, image.height, imgbytes)
val newimage = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB)
newimage.setData(raster)
If it can be improved, I'm open to suggestions of course, but in general it works as expected.
setPixels
assumes that the image data is not packed. So it's looking for an input of length image.width*image.height*3, and running off the end of the array.
Here are three options for how to fix the problem.
(1) Unpack imgbytes
so it is 3x longer, and do it the same way as above.
(2) Manually load the buffer from imgbytes
instead of using setPixels
:
var i=0
while (i < imgbytes.length) {
buffer.setElem(i, imgbytes(i))
i += 1
}
(3) Don't use createDataBuffer
; if you already know that your data has the proper formatting you can create the appropriate buffer yourself (in this case, a DataBufferInt
):
val buffer = new DataBufferInt(imgbytes, imgbytes.length)
(you may need to do imgbytes.clone
if your original copy could get mutated by something else).