hasAlpha vs getAlphaRaster - java

In Java, is it expected to be able to have a BufferedImage such that getColorModel().hasAlpha() will return true, but getAlphaRaster() will return null?
I ask because there's a library I'm using (PDFBox specifically, in the PDJpeg class) that breaks on such an image.
In this particular case I'm creating the image very simply using:
BufferedImage bi = ImageIO.read(new FileInputStream("/Users/dan/Downloads/test.png"));
I've attached the particular image that's failing for me below this question.
Is there some sort of parameter I can pass to ImageIO or some kind of transformation I can do to my BufferedImage after it's loaded so that it won't run into this problem?
I'm running Java 1.7.0_40 if it matters.
Stack trace for completeness:
java.lang.NullPointerException
at java.awt.image.ComponentColorModel.isCompatibleRaster(ComponentColorModel.java:2787)
at java.awt.image.BufferedImage.<init>(BufferedImage.java:629)
at org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg.createImageStream(PDJpeg.java:159)
at org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg.<init>(PDJpeg.java:133)

Yes. As the JavaDoc states:
This method assumes that for all ColorModel objects other than IndexColorModel, if the ColorModel supports alpha, there is a separate alpha channel which is stored as the last band of image data. If the image uses an IndexColorModel that has alpha in the lookup table, this method returns null since there is no spatially discrete alpha channel.
Your image is a palette PNG with a transparent index. ImageIO will read this into a BufferedImage with IndexColorModel (ie., no discrete alpha channel).
You can convert the image to a different BufferedImage type (like TYPE_INT_RGB), by creating a blank image of the same size, getting its graphics, and draw the original onto it:
BufferedImage origininal = ...;
BufferedImage copy = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = copy.createGraphics();
try {
g.drawImage(original, 0, 0, null);
}
finally {
g.dispose();
}
You can probably also pass the image type as an ImageTypeSpecifier on the ImageReadParam passed to the ImageReader. But it requires quite a bit more code for the reading part.

Related

How to create BufferedImage with BITMASK Transparency?

The BufferedImage class implements Transparency, which has three values:
OPAQUE means no transparency.
TRANSLUCENT means every pixel has an Alpha value between 0 and 1.
BITMASK means every pixel is either opaque or completely transparent.
I can check this value with the getTransparency() method. In my case, I have a PNG file with transparency:
pic = ImageIO.read(new File(filename));
int transparency = pic.getTransparency(); // returns Transparency.TRANSLUCENT
Now I read that images with Transparency.BITMASK can be drawn much faster than those with Transparency.TRANSLUCENT and in my case BITMASK would be enough. I would just color all transparent pixels in one specific color and then save the png without transparency.
Question: How to create a BufferedImage object, which has Transparency.BITMASK from an existing BufferedImage by just defining one color as transparent?
You mean something like...
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
BufferedImage bimage = gc.createCompatibleImage(width, height, Transparency.BITMASK);
Things to note:
If you're PNG contains alpha values > 0 and < 255, they are likely to be rounded to either 0 or 1, possibly making the PNG appear jagged...
If you use Transparency.TRANSLUCENT instead, the color mode of the BufferedImage will be compatible with the GraphicsDevice, making it faster to render
I did an animated sequence a few years ago which was made up of 5 separate images, layered on top of each other and played back at separate speeds all on top of a transparent window...When I first tried running it the, the playback was terrible and jumped about the place.
After some playing around, I found that using Transparency.TRANSLUCENT to convert the images to a compatible color model for the GraphicsDevice worked like a charm...
Nothing wrong with the accepted answer, just providing an alternative for completeness (and I think it will work in headless mode). :-)
The transparency of a BufferedImage is controlled by its ColorModel.
So to create a BufferedImage with a given Transparency constant, you can use code like this:
// Use default RGB color space, no discrete alpha channel,
ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
ColorModel colorModel = new ComponentColorModel(cs, true, false, Transparency.BITMASK, DataBuffer.TYPE_BYTE);
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 4, null);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);

How to set a pixel in a BufferedImage To Transparent

I'm Currently making a Game, and I need to set a couple Pixels of a BufferedImage (loaded using ImageIO.read) to be transparent in the fastest, best way.
I can't really find any other topic with this question, and If I do the answer Doesn't really help/fit What I need.
Thanks :)
Use Color(red, green, blue, alpha) with values 0-255. Where alpha is the opacity.
Buffed image being of type with an Alpha channel (RGBA, BGRA)
Color halfTransparant = new Color(0x76, 0x54, 0x32, 128);
With setRGB on arrays this still is not fast, you might access the raster data.
But why using dynamically generated images in time critical situations.
The smart way is to create your image with correct alpha from the start (using an image format with transparency, e.g. PNG and your favorite imaging application e.g. GIMP).
Otherwise you can directly alter pixels in the BufferedImage returned by ImageIO using the BufferedImage API: setRGB(int ARGB) and its bulk manipulation cousins in the BufferedImage's Raster.
One way that should work with all image types (as long as they support alpha), is very fast, and will not disable hardware acceleration of the image is:
BufferedImage image = ...; // From somewhere
Graphics2D g = destination.createGraphics();
try {
g.setComposite(AlphaComposite.Clear);
g.fillRect(x, y, w, h); // Area to make transparent
}
finally {
g.dispose();
}

How do I determine an image's color space in Java?

I am trying to determine an image's color space in Java. I believe this is referred to as "imageType" in the BufferedImage class. This is the line of code which causes me trouble - I don't know what to put as the third argument:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
I'm going to stitch several images together into the BufferedImage using the class Graphics2D. Some images I use may be in RGB format, others in ARGB, 4-byte ARGB etc...
Is there any way I can programatically determine the color spaces of the images? Or if not, is there a way of converting all images into the same color space before stitching?
The ColorConvertOp class can be used to convert an image from one ColorSpace to another.
BufferedImage.getType() can be used to determine the color space used by the image.

Using data in BufferedImage that is drawn by Graphics

I have the method below:
private Graphics getBufferedImage(Image image) {
// Create empty BufferedImage, sized to Image
buffImage =
new BufferedImage(
image.getWidth(null),
image.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
// Draw Image into BufferedImage
Graphics wholeImage = buffImage.getGraphics();
return wholeImage;
}
It takes an Image and tries to generate the BufferedImage with a Graphics object.
What can I do with this Graphics (or BufferedImage) to actually let me use it? I'm using GIF files.
Would it be easier to use a byte array to transfer Image data over?
Cheers,
Alex
You can get OutputStream object using method ImageIO.write(...). Now you can transfer it over the network or save to file or store to array or something else.
You can use Graphics.drawImage to draw the original image in the new image. In fact you can use any operation that Graphics offers, as well as cast it to Graphics2D (because that's what it is) and use those operations too.

Resizing TYPE_CUSTOM BufferedImages?

When I read a JPEG from disk, Java sometimes gives me a BufferedImage whose getType() returns TYPE_CUSTOM -- that is, it has a custom color model. I'd like to resize this BufferedImage but I'm not sure how to construct the destination object. Can someone please provide sample code for using the following constructor?
BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable properties)
I would like to create a BufferedImage of the same type as the source, just bigger, and transfer the contents over. Any ideas?
Answering my own question, it looks like ImageTypeSpecifier is the answer. Specifically:
Invoke ImageTypeSpecifier.createFromRenderedImage(RenderedImage image) to get back an ImageTypeSpecifier from the image with the custom color model.
Invoke ImageTypeSpecifier.createBufferedImage(int width, int height) on the ImageTypeSpecifier from step 1 to create a new image with the same color model as the original image.

Categories