I've got two BufferedImages: one is TYPE_INT_ARGB, and the other is TYPE_BYTE_GRAY. How to replace the entire color image's alpha band with the grayscale image using API only, and without disturbing the RGB values?
final int width = 200;
final int height = 200;
final BufferedImage colorImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final BufferedImage grayscaleImg = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g = colorImg.createGraphics();
// flip some mystical switches
// g.drawImage( grayscaleImg into colorImg's alpha band )
g.dispose();
I can do it manually by masking and copying bytes like this:
WritableRaster clrRaster = colorImg.getRaster();
DataBufferInt clrBuffer = (DataBufferInt) clrRaster.getDataBuffer();
int[] clrData = clrBuffer.getData();
WritableRaster grayRaster = grayscaleImg.getRaster();
DataBufferByte grayBuffer = (DataBufferByte) grayRaster.getDataBuffer();
byte[] grayData = grayBuffer.getData();
int pixel, alphaBits;
for(int i = 0; i < clrData.length; i++) {
pixel = clrData[i] & 0x00ffffff;
alphaBits = (int)grayData[i] << 24;
clrData[i] = pixel | alphaBits;
}
However what's the API way?
UPDATE #1
Sample images: input grayscale alpha, input color cat, and output color cat with hole.



The resulting image has the grayscale in the output color's alpha. View the resulting image in a photo editor, and you will see the hole in the middle is actually transparent.
private void injectAlphaIntoColor() {
try {
// BEWARE: this code does not check if both images are the same
// width and height. May get out of bounds exception if w&h are
// different.
BufferedImage cat = ImageIO.read(new File("s:/temp/cat5.png"));
BufferedImage gray = ImageIO.read(new File("s:/temp/layermask.png"));
// convert color cat to TYPE_INT_ARGB
BufferedImage color = new BufferedImage(cat.getWidth(), cat.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = color.createGraphics();
g.drawImage(cat, 0, 0, null);
g.dispose();
final WritableRaster clrRaster = color.getRaster();
final DataBufferInt clrBuffer = (DataBufferInt) clrRaster.getDataBuffer();
final int[] clrData = clrBuffer.getData();
final WritableRaster grayRaster = gray.getRaster();
final DataBufferByte grayBuffer = (DataBufferByte) grayRaster.getDataBuffer();
final byte[] grayData = grayBuffer.getData();
int pixel, alphaBits;
// manually put each grayscale pixel into each color pixel's alpha
for(int i = 0; i < clrData.length; i++) {
pixel = clrData[i] & 0x00ffffff;
alphaBits = (int)grayData[i] << 24;
clrData[i] = pixel | alphaBits;
}
ImageIO.write(color, "png", new File("s:/temp/3rd_output.png"));
}
catch (IOException ex) {
System.out.println(ex.getMessage());
}
}
To restate my original objective, what is the Java API way to doing what the above code does?


My thanks and credit to @Hovercraft Full Of Eels for suggesting
BufferedImageOp, which lead toBandCombineOp. When fed with a suitable matrix, the class can manipulate any or all the bands. Lighten, darken, move, and copy bands without ever accessingDataBufferor manipulating bits.How to put an image into the alpha band
BufferedImage.TYPE_BYTE_GRAYBufferedImage.TYPE_INT_ARGB. The color bands will contain near identical copies of the grayscale.BandCombineOp. SeetoAlpha()for matrix.This is the better way to move/copy a band over coding bit manipulations because it's mathematically elegant, and API may take advantage of video acceleration hardware (if present and supported by Java.)
Sample Java app: Embed alpha
An app is included to demonstrate the procedure. Select a color source and alpha source, and the app will composite them into one image. The two source images, intermediate images, and the composite are displayed for sanity. Right-click on any image to save.
Color source: cat
Alpha source: bird
Alpha source: green band copied to alpha band
Composite
To run the app: (1) create a JavaFX project named
embedalpha, (2) delete the contents of the auto-generated .java file, (3) paste my code, and (4) run.To trace the procedure, put a breakpoint in method
handleBuildComposite(). IgnoreappendGallery().toAlpha()does the band copy.