Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a BufferedImage from raw data

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.

like image 736
viraptor Avatar asked Nov 20 '10 19:11

viraptor


People also ask

How to convert byte to BufferedImage in java?

This article shows how to convert a byte[] to a BufferedImage in Java. InputStream is = new ByteArrayInputStream(bytes); BufferedImage bi = ImageIO. read(is); The idea is puts the byte[] into an ByteArrayInputStream object, and we can use ImageIO.

What is the difference between BufferedImage and image?

List, the difference between Image and BufferedImage is the same as the difference between List and LinkedList. Image is a generic concept and BufferedImage is the concrete implementation of the generic concept; kind of like BMW is a make of a Car. Show activity on this post. Image is an abstract class.


1 Answers

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).

like image 168
Rex Kerr Avatar answered Sep 25 '22 20:09

Rex Kerr