When working with the BufferedImage
class in Java, I usually use the constructor with parameters int width, int height, int type
. For a certain application, though, I wanted an image which would store the color data using bytes in the order ARGB, which can't be done in that way (it has only TYPE_4BYTE_ABGR
).
I found the following solution, which worked fine:
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 4, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{8,8,8,8}, true, false, ColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
img = new BufferedImage(colorModel, raster, false, new Hashtable<>());
I don't understand why this works?
Though - I understand that the WritableRaster
is the data structure that holds the pixel data of the picture, but past that I am lost. Which of these two objects - the Raster, or the ColorModel - determines that the pixel data is in the order RGBA? And how could I simulate any of the types in BufferedImage's (int, int, int)
constructor using the (ColorModel, WritableRaster, boolean, HashTable)
constructor?
It's the method
...that specifies the byte order. It does so implicitly, by assuming for 4 bands, you want the band offsets to be
0, 1, 2, 3
(which corresponds to RGBA; see the source for details). For RGB color space, band 0 = Red, 1 = Green, 2 = Blue and 3 = Alpha.If you wanted a different order, you could have used a different factory method, for instance to create a raster with ARGB order:
Both of these methods will create an instance of
PixelInterleavedSampleModel
for you, and it's thisSampleModel
that really controls the sample order.For how the
BufferedImage(int, int, int)
constructor works, and how you could do similar things, I think the best would be to just look at the source code for yourself. It's basically one bigswitch
statement, where for each constantTYPE_*
it creates aWritableRaster
and aColorModel
similar to how you do it above.For example:
...will create an image with type
TYPE_INT_ARGB
(the way this reverse lookup actually works is somewhat nasty, but it works... :-)). If no corresponding type exists inBufferedImage
the type will beTYPE_CUSTOM
(0
).