|
Replies:
5
-
Last Post:
Sep 2, 2008 10:34 AM
by: Jim Graham
|
Threads:
[
Previous
|
Next
]
|
|
|
|
|
|
drawImage() and isAlphaPremultiplied()
Posted:
Aug 14, 2008 10:35 AM
|
|
|
When copying an image using Graphics2D.drawImage(),I'm suprised to find that the isAlphaPremultiplied() property of the two images is not taken into account. I believe the pixels are copied directly without respect to color model.
A little example is below. I would expect the normalized (sRGB) pixel for each image to be the same, but instead the "real" pixel value is the same and the interpretation and normalized data differ.
Is this a bug or am I misunderstanding how these things should work?
Thanks much, michael
public static void main(String[] args) {
BufferedImage premultiplied = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
BufferedImage notpremultiplied = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
premultiplied.coerceData(true);
notpremultiplied.coerceData(false);
Graphics2D preG = premultiplied.createGraphics();
preG.setColor(new Color(0, 40, 0, 120));
preG.fillRect(0, 0, 10, 10);
preG.dispose();
// prints:
// real: pixel:2013276160 120,0,85,0
// normalized: pixel:2013287680 120,0,85,0
printOriginPixel(premultiplied);
Graphics2D notG = notpremultiplied.createGraphics();
notG.drawImage(premultiplied, 0, 0, 10, 10, null);
notG.dispose();
// prints:
// real: pixel:2013276160 120,0,40,0
// normalized: pixel:2013276160 120,0,40,0
printOriginPixel(notpremultiplied);
}
public static void printOriginPixel(BufferedImage image) {
int defaultColorSpacePixel = image.getRGB(0, 0);
int realPixel = ((int[]) image.getRaster().getDataElements(0, 0, null))[0];
System.out.println("real: pixel:"+ realPixel + " "
+ image.getColorModel().getAlpha(realPixel)
+ ","
+ image.getColorModel().getRed(realPixel)
+ ","
+ image.getColorModel().getGreen(realPixel)
+ ","
+ image.getColorModel().getBlue(realPixel));
System.out.println("normalized: pixel:" + defaultColorSpacePixel + " "
+ ColorModel.getRGBdefault().getAlpha(defaultColorSpacePixel)
+ ","
+ ColorModel.getRGBdefault().getRed(defaultColorSpacePixel)
+ ","
+ ColorModel.getRGBdefault().getGreen(defaultColorSpacePixel)
+ ","
+ ColorModel.getRGBdefault().getBlue(defaultColorSpacePixel));
}
|
|
|
|
|
|
|
Re: [JAVA2D] drawImage() and isAlphaPremultiplied()
Posted:
Aug 14, 2008 4:26 PM
in response to: kazoobrewer
|
|
|
Hi Michael,
I think you are getting confused by some under-documented APIs that never had a useful purpose for developers and, in consequence, that have some undiscovered bugs in them.
coerceData is not the way to make a premultiplied image. Even worse, it can have dangerous effects on an existing image. It is used internally to munge raster data in the constructor that takes a raw raster and colormodel, but it is not meant to be used in any other cases, or its behavior in other cases is questionable at best, and buggy as you've discovered at worst.
If you want a premultiplied raster, then use the TYPE_INT_ARGB_PRE image type, don't use coerceData.
The dangerous thing that coerceData is doing is that it is replacing the ColorModel in the image with a new one that doesn't match its declared type. When we go to render into/out of it we end up believing its type and we do the wrong thing.
Unfortunately, I'm not sure how to deal with that bug in the coerceData method now - a BufferedImage is not supposed to ever change its type, but this method can cause it to change its nature. I believe the right thing for us to do is to gut the method and deprecate it and move the functionality of what it currently does into the custom constructor.
In any case, simply create your images using TYPE_INT_ARGB (for non-premultiplied) and TYPE_INT_ARGB_PRE (for premultiplied) and you should be good to go...
...jim
java2d@JAVADESKTOP.ORG wrote: > When copying an image using Graphics2D.drawImage(),I'm suprised to find that the isAlphaPremultiplied() property of the two images is not taken into account. I believe the pixels are copied directly without respect to color model. > > A little example is below. I would expect the normalized (sRGB) pixel for each image to be the same, but instead the "real" pixel value is the same and the interpretation and normalized data differ. > > Is this a bug or am I misunderstanding how these things should work? > > Thanks much, > michael > > > public static void main(String[] args) {
> BufferedImage premultiplied = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
> BufferedImage notpremultiplied = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
>
> premultiplied.coerceData(true);
> notpremultiplied.coerceData(false);
>
> Graphics2D preG = premultiplied.createGraphics();
> preG.setColor(new Color(0, 40, 0, 120));
> preG.fillRect(0, 0, 10, 10);
> preG.dispose();
>
> // prints:
> // real: pixel:2013276160 120,0,85,0
> // normalized: pixel:2013287680 120,0,85,0
> printOriginPixel(premultiplied);
>
> Graphics2D notG = notpremultiplied.createGraphics();
> notG.drawImage(premultiplied, 0, 0, 10, 10, null);
> notG.dispose();
>
> // prints:
> // real: pixel:2013276160 120,0,40,0
> // normalized: pixel:2013276160 120,0,40,0
> printOriginPixel(notpremultiplied);
> }
>
> public static void printOriginPixel(BufferedImage image) {
> int defaultColorSpacePixel = image.getRGB(0, 0);
> int realPixel = ((int[]) image.getRaster().getDataElements(0, 0, null))[0];
>
> System.out.println("real: pixel:"+ realPixel + " "
> + image.getColorModel().getAlpha(realPixel)
> + ","
> + image.getColorModel().getRed(realPixel)
> + ","
> + image.getColorModel().getGreen(realPixel)
> + ","
> + image.getColorModel().getBlue(realPixel));
> System.out.println("normalized: pixel:" + defaultColorSpacePixel + " "
> + ColorModel.getRGBdefault().getAlpha(defaultColorSpacePixel)
> + ","
> + ColorModel.getRGBdefault().getRed(defaultColorSpacePixel)
> + ","
> + ColorModel.getRGBdefault().getGreen(defaultColorSpacePixel)
> + ","
> + ColorModel.getRGBdefault().getBlue(defaultColorSpacePixel));
> }
>
> [Message sent by forum member 'kazoobrewer' (kazoobrewer)] > > http://forums.java.net/jive/thread.jspa?messageID=293378 > > =========================================================================== > To unsubscribe, send email to listserv@java.sun.com and include in the body > of the message "signoff JAVA2D-INTEREST". For general help, send email to > listserv@java.sun.com and include in the body of the message "help".
=========================================================================== To unsubscribe, send email to listserv@java.sun.com and include in the body of the message "signoff JAVA2D-INTEREST". For general help, send email to listserv@java.sun.com and include in the body of the message "help".
|
|
|
|
|
|
|
|
Re: [JAVA2D] drawImage() and isAlphaPremultiplied()
Posted:
Aug 18, 2008 12:56 PM
in response to: Jim Graham
|
|
|
Jim, thanks very much for your reply.
I'm swimming through these issues right now, trying to avoid instances of coerceData and figure out where to be using ARGB vs ARGB_PRE, and have the following concerns. Any thoughts on these, or on further resources to look at, would be most appreciated.
Is there a preferred way to get premultiplied data from an ARGB image (I'm currently thinking create a new ARGB_PRE and call drawImage())?
What effect does using the different BufferedImage type have on graphics performance, e.g. managed vs. unmanaged images? Any reason a PRE image can't be accelerated? Any reason to prefer one to the other for drawing to the screen?
Again, thanks, michael
|
|
|
|
|
|
|
|
Re: [JAVA2D] drawImage() and isAlphaPremultiplied()
Posted:
Aug 18, 2008 1:07 PM
in response to: kazoobrewer
|
|
|
Hi Michael,
All BufferedImage types should be equally "manageable" as we make a copy in VRAM in whatever format is necessary for display regardless of the source image type. If the graphics card wants PRE images then the accelerated copy will be PRE, or not as the case may be.
Working on premultiplied data is usually considered a win for the blending operations since it avoids the need to have to multiply the color components by the alpha. Unfortunately, the picture isn't that simple since, while it avoids the "need" to do the multiply, the various other math operations that the blending requires can sometimes absorb the alpha multiplier into other operations and the effect ends up being minimal in practice. It would be better to benchmark the specific operations you are doing to see if there is any performance advantage.
The most straightforward way to turn an ARGB image into an ARGB_PRE image would be to render it into a different image. You might be able to use the constructor that takes a ColorModel and a Raster to do the job for you, but keep in mind that the Raster for the original image would be altered forever. It may save you the allocation of a new buffer, but I'm not sure that the implicit coercion of data that happens in that constructor (which uses coerceData in an arguably appropriate way) is as fast as rendering from one image to the other. Benchmark to see if it makes a difference one way or the other...
...jim
java2d@JAVADESKTOP.ORG wrote: > Jim, thanks very much for your reply. > > I'm swimming through these issues right now, trying to avoid instances of coerceData and figure out where to be using ARGB vs ARGB_PRE, and have the following concerns. Any thoughts on these, or on further resources to look at, would be most appreciated. > > Is there a preferred way to get premultiplied data from an ARGB image (I'm currently thinking create a new ARGB_PRE and call drawImage())? > > What effect does using the different BufferedImage type have on graphics performance, e.g. managed vs. unmanaged images? Any reason a PRE image can't be accelerated? Any reason to prefer one to the other for drawing to the screen? > > Again, thanks, > michael > [Message sent by forum member 'kazoobrewer' (kazoobrewer)] > > http://forums.java.net/jive/thread.jspa?messageID=294014 > > =========================================================================== > To unsubscribe, send email to listserv@java.sun.com and include in the body > of the message "signoff JAVA2D-INTEREST". For general help, send email to > listserv@java.sun.com and include in the body of the message "help".
=========================================================================== To unsubscribe, send email to listserv@java.sun.com and include in the body of the message "signoff JAVA2D-INTEREST". For general help, send email to listserv@java.sun.com and include in the body of the message "help".
|
|
|
|
|
|
|
|
Re: [JAVA2D] drawImage() and isAlphaPremultiplied()
Posted:
Sep 2, 2008 4:13 AM
in response to: Jim Graham
|
|
|
Hi Jim,
I also have a question related to the coerceData() method. It may be out of place here, just let me know. I've tried other forums (see below) with limited success.
It has to do with writing a BufferedImage out as a TIFF format file (using the class com.sun.media.jai.codec.TIFFEncodeParam). In the JAI forum I was advised to use the "coerceData(true)" in order to guarantee that the alpha channel of the image would be written out as "assoc alpha" rather than "unassoc alpha" -- in the latter case most image packages won't recognize it as the transparency channel, hence making the TIFF file not very useful. But I've noticed that "coerceData(true)" seems to have the sort of unintended consequences referred to in your post, making the saved files also useless. So, my question: is there another known way to make sure the TIFF file gets written out with the "assoc alpha" flag turned out, short of calling "coerceData(true)"? Simply allocating an image of type TYPE_INT_ARGB_PRE doesn't seem to do so.
It appears that I can save the images as PNG files and get the alpha channel saved as transparency information, so I can live without this, but the TIFF format has certain advantages that I'm reluctant to forgo.
(This topic may be too far afield from this discussion, please let me know.)
Charles
|
|
|
|
|
|
|
|
Re: [JAVA2D] drawImage() and isAlphaPremultiplied()
Posted:
Sep 2, 2008 10:34 AM
in response to: charlesgunn
|
|
|
Hi Charles,
This is really a question for JAI since I believe they own the TIFF writer. I forwarded your question on to Brian Burkhalter for more information. He may draw the question off onto a JAI list as well. Either way you should hear from him...
...jim
java2d@JAVADESKTOP.ORG wrote: > Hi Jim, > > I also have a question related to the coerceData() method. It may be out of place here, just let me know. I've tried other forums (see below) with limited success. > > It has to do with writing a BufferedImage out as a TIFF format file (using the class com.sun.media.jai.codec.TIFFEncodeParam). In the JAI forum I was advised to use the "coerceData(true)" in order to guarantee that the alpha channel of the image would be written out as "assoc alpha" rather than "unassoc alpha" -- in the latter case most image packages won't recognize it as the transparency channel, hence making the TIFF file not very useful. But I've noticed that "coerceData(true)" seems to have the sort of unintended consequences referred to in your post, making the saved files also useless. So, my question: is there another known way to make sure the TIFF file gets written out with the "assoc alpha" flag turned out, short of calling "coerceData(true)"? Simply allocating an image of type TYPE_INT_ARGB_PRE doesn't seem to do so. > > It appears that I can save the images as PNG files and get the alpha channel saved as transparency information, so I can live without this, but the TIFF format has certain advantages that I'm reluctant to forgo. > > (This topic may be too far afield from this discussion, please let me know.) > > Charles > [Message sent by forum member 'charlesgunn' (charlesgunn)] > > http://forums.java.net/jive/thread.jspa?messageID=296668 > > =========================================================================== > To unsubscribe, send email to listserv@java.sun.com and include in the body > of the message "signoff JAVA2D-INTEREST". For general help, send email to > listserv@java.sun.com and include in the body of the message "help".
=========================================================================== To unsubscribe, send email to listserv@java.sun.com and include in the body of the message "signoff JAVA2D-INTEREST". For general help, send email to listserv@java.sun.com and include in the body of the message "help".
|
|
|
|
|