Motivation:
My goal is to convert AWT BufferedImage
to SWT ImageData
in the most efficient way. Typical answer to this question is pixel by pixel conversion of the whole picture, that is O(n^2) complexity. Much more efficient would be if they could exchange whole pixel matrix as it is. BufferedImage
seems to be very flexible in determining in detail how colors and alpha are encoded.
To provide you with a wider context, I wrote a SVG icon on demand rasterizer, using Apache Batik, but it is for SWT (Eclipse) application. Batik renders only to a java.awt.image.BufferedImage
, but SWT components require org.eclipse.swt.graphics.Image
.
Their backing raster objects: java.awt.image.Raster
and org.eclipse.swt.graphics.ImageData
represent exactly same thing, they are just wrapper around a 2D array of byte values representing pixels. If I can make one or the other to use came color encoding, voila, I can reuse the backing array as it is.
I got pretty far, this works:
// defined blank "canvas" for Batik Transcoder for SVG to be rasterized there
public BufferedImage createCanvasForBatik(int w, int h) {
new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
}
// convert AWT's BufferedImage to SWT's ImageData to be made into SWT Image later
public ImageData convertToSWT(BufferedImage bufferedImage) {
DataBuffer db = bufferedImage.getData().getDataBuffer();
byte[] matrix = ((DataBufferByte) db).getData();
PaletteData palette =
new PaletteData(0x0000FF, 0x00FF00, 0xFF0000); // BRG model
// the last argument contains the byte[] with the image data
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
ImageData swtimgdata = new ImageData(w, h, 32, palette);
swtimgdata.data = matrix; // ImageData has all field public!!
// ImageData swtimgdata = new ImageData(w, h, 32, palette, 4, matrix); ..also works
return swtimgdata;
}
It all works except transparency :(
It looks like ImageData
requires (always?) alpha to be a separate raster, see ImageData.alphaData
from color raster, see ImageData.data
; both are byte[]
types.
Is there a way how to make ImageData
to accept ARGB
model? That is alpha mixed with other colors? I doubt so I went the other way. To make BufferedImage
to use separate arrays (aka rasters or "band") for colors and alpha. The ComponentColorModel
and BandedRaster
seem to intended exactly for these things.
So far I got here:
public BufferedImage createCanvasForBatik(int w, int h) {
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
int[] nBits = {8, 8, 8, 8}; // ??
ComponentColorModel colorModel = new ComponentColorModel(cs, nBits, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createBandedRaster(
DataBuffer.TYPE_BYTE, w, h, 4, new Point(0,0));
isPremultiplied = false;
properties = null;
return new BufferedImage(colorModel, raster, isPremultiplied, properties);
}
That creates a separate raster (band) for alpha but also for every color separately, so I end up with 4 bands (4 rasters) which is again unusable for SWT Image. Is it possible to create a banded raster with 2 bands: one for colors in RGB or BRG, and one for alpha only?