Resizing TYPE_CUSTOM BufferedImages? - java

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.

Related

JAI Add Alpha Channel to RenderedImage

I have two RenderedImages. I want to do an Overlay Operation with these two images and therefore they need to match in data type and the number of bands.
The problem I have is that one image has 3 bands (RGB) and the second image has 4 bands (ARGB).
My question is how can I add an Alpha Channel to the first image so I can do the Overlay Operation?
EDIT
Ok, I found a method of adding an Alpha Channel to the first image. Below is the code. I simply created a single banded constant image and merged it with my first image.
ParameterBlock pb = new ParameterBlock();
pb.add(new Float(finalImage.getWidth())).add(new Float(finalImage.getHeight()));
pb.add(new Byte[] {new Byte((byte)0xFF)});
RenderedImage alpha = JAI.create("constant", pb);
finalImage = BandMergeDescriptor.create(finalImage, alpha, null);
The problem I have now is that everytime I add an overlay the image changes colors. All the colors become nuances of red or pink. When I add a second overlay, the image becomes normal again, but the first overlay changes colors. All black areas become white.
Also the background of the overlay is not transparent. It is grey.
Below are examples of the images, so you see how the change colors:
As you can see, the picture and overlays change colors and the background of the overlay isn't transparent.
Can you help me solve this problem, so that the image is always displayed correctly? Thanks!
You can try to create a new BufferedImage with ARGB-model, and just paint the non-transparent background picture into this new BufferedImage. Then you have a BufferedImage with alpha-channel (although all of the pixels are opaque), so the Composition should hopefully work.
im not sure about TYPE_4BYTE_ARGB as I usually work with BufferedImages of TYPE_INT_ARGB but I have often used the method of drawing a RGB BufferedImage to a new ARGB BufferedImage and then drawing that onto other things without problem. the change in color would suggest an unwanted change is being made to the other channels in the overlay process as it doesn't seem to be specific to a specific image. If your overlay operation is similar to drawing one image onto another with alpha I would probably suggest using the Graphics.drawImage()/drawRenderedImage() method for the overlay itself not to mention the background should not even need alpha in this case.
the code:
public RenderedImage overlay(RenderedImage back, RenderedImage front, AffineTransform overlayTransformation)
{
BufferedImage newBack = new BufferedImage(back.getWidth(), back.getHeight(), TYPE_3BYTE_RGB);
newBack.setData(back.getData());
Graphics2D graphics = (Graphics2D)(newBack.getGraphics());
graphics.drawRenderedImage(front, overlayTransformation);
return newBack;
}
you may want to ensure the original back Raster is not modified though.

hasAlpha vs getAlphaRaster

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.

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.

Difference between the Image and BufferedImage in Java

What is the difference between Image and BufferedImage?
Can I create a BufferedImage directly from an Image source "image.png"?
If you are familiar with Java's util.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.
Image is an abstract class. You can't instantiate Image directly. BufferedImage is a descendant, and you can instantiate that one. So, if you understand abstract classes and inheritance, you'll understand when to use each.
For example, if you were using more than one Image descendant, they're going to share some common properties, which are inherited from Image.
If you wanted to write a function that would take either kind of descendant as a parameter you could do something like this:
function myFunction(Image myImage) {
int i = myImage.getHeight();
...
}
You could then call the function by passing it a BufferedImage or a VolatileImage.
BufferedImage myBufferedImage;
VolatileImage myVolatileImage;
...
myFunction(myVolatileImage);
myFunction(myBufferedImage);
You won't convert an Image to a BufferedImage because you'll never have an Image.
What is the difference between Image and BufferedImage?
As stated in the Oracle Java tutorial for working with Images
The java.awt.Image class is the superclass that represents graphical images as rectangular arrays of pixels.
The java.awt.image.BufferedImage class, which extends the Image class to allow the application to operate directly with image data (for example, retrieving or setting up the pixel color). Applications can directly construct instances of this class.
The BufferedImage class is a cornerstone of the Java 2D immediate-mode imaging API. It manages the image in memory and provides methods for storing, interpreting, and obtaining pixel data. Since BufferedImage is a subclass of Image it can be rendered by the Graphics and Graphics2D methods that accept an Image parameter.
A BufferedImage is essentially an Image with an accessible data buffer. It is therefore more efficient to work directly with BufferedImage. A BufferedImage has a ColorModel and a Raster of image data. The ColorModel provides a color interpretation of the image's pixel data.
Can I create a BufferedImage directly from an Image source "image.png"?
Sure.
BufferedImage img = ImageIO.read(getClass().getResource("/path/to/image"));

Categories