• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Jeanne Boyarsky
  • Liutauras Vilda
Sheriffs:
  • Rob Spoor
  • Bear Bibeault
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:
  • Frits Walraven
  • Himai Minh

Weird AWT transparency problem

 
Ranch Hand
Posts: 133
1
Mac OS X
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I searched through the answers here and found nothing relevant to my problem, likely because my problem is so weird.

About five years ago I wrote a little program (only about 2,000 lines long). For rather complicated reasons, I confined my graphics code to AWT. I got everything working just fine.

This morning I resurrected the program to show to somebody else. But now it doesn't draw properly. Specifically, this line of code inside the paint() method malfunctions:


myGraphics2D.drawImage(myBufferedImage, myX, myY, new Color(0,0,0,0), null);

(I've revised the code to be more readable.) As I wrote earlier, this line has always worked fine. But now, five years later, it fails to apply the alpha value -- which is 0 -- to the drawing. Instead, it draws black for the pixels that are transparent in the BufferedImage. If I change "new Color(0,0,0,0)" to "new Color(255,0,0,0)", then it draws red where it should be transparent.

No, I'm not using setOpaque(boolean) anywhere, because that's a method in the JComponent class, and I am not using any kind of JComponent. Indeed, my import statements do not include anything from Swing.

Here is a complete list of every single type of drawing method my program uses:

setFont
setRenderingHint
setColor
setStroke
fillRect
drawString
drawImage
drawLine

That's all I'm using to draw to the window. I have tried a number of experiments, none of which have proven to be illuminating. I don't think that the use of "null" for the required ImageObserver parameter inside the drawImage call is the source of the problem, because other things work well.

I realize that you would like to see the entire program, but it's 2,000 lines long, and has a complex structure that would take some time to understand. I've tried to think of a way to boil it down to the absolute bare minimum, but there's a lot of cross-dependency in the drawing routines, so I doubt that this approach would be useful.

Does anybody have any ideas as to why I have lost transparency that I once had? Did Java AWT change sometime in the last five years?
 
Rancher
Posts: 3242
30
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Not sure about your attempt to use a transparent background color when painting an image.

I know there are problems when you try to do this when using a transparent background when painting a Swing component.

See Backgrounds With Transparency for the problem when painting a Swing component.

I would guess the problem is somehow related.
 
Chris Crawford
Ranch Hand
Posts: 133
1
Mac OS X
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the fast response! As it happens, I had already stumbled upon the "Backgrounds with Transparency" page to which you linked. It seemed closest to my problem, but it relies on method "setOpaque(boolean)", which cannot be applied anywhere in my program, because I don't use any Swing components -- it's all AWT.

I double-checked the Graphics2D.drawImage(Image, int, int, Color, ImageObserver) and its description has one oddity; it states:

"Transparent pixels are drawn in the specified background color."

My assumption has been that the specified background color can also contain an alpha value, and so can be set to be transparent. That's certainly what the definition of the class Color says. Yet for some reason, Graphics.drawImage(...) refuses to implement the alpha channel of the specified background color.

What's especially frustrating is that this code worked perfectly back in 2013. I have screen shots showing it functioning exactly as intended. And yet something has changed in the five years since then. Perhaps Java is undergoing the same kind of creeping senility that I've been experiencing for the last few years.

Another frustration is the transparency is implemented properly for all the drawing methods. It seems to be refusing to recognize transparency only with drawImage.

I'll keep trying various experiments. Perhaps implementing a real ImageObserver will help. I'll also try drawing that fragment offscreen and then simply pasting it into the main image.
 
Rob Camick
Rancher
Posts: 3242
30
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

"Transparent pixels are drawn in the specified background color."  



I take this to mean that the transparent pixels of the image are drawn in the specified background color.

So, what sense does it make to fill in a transparent pixel of the image with another transparent pixel? Maybe this is why the alpha channel is ignored?

Why can't you just paint the BufferedImage and let the background of the parent component show through?

In other words set the background of the parent component to be whatever (non transparent) color you want.
 
Saloon Keeper
Posts: 4510
166
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I took the liberty of writing a short program that shows the problem. It does seem like the g2d.drawImage(buf, x, y, transparantcolor, null) is not working for a non-type ARGB. You can try one of the g2d.drawImage, and you can set the type of the BufferedImage either to ARGB or RGB.
I have no idea why something that used to work, now doesn't work anymore. As Rob said, you can simply draw your image without the extra color parameter. By yhe way: the only way for me to set the background to transparant, is to use
 
Chris Crawford
Ranch Hand
Posts: 133
1
Mac OS X
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the suggestions. It appears that I have not made myself clear. Here's an image showing what the program previously produced and what it now produces:



On the left is the original result; on the right is the current result. As you can see, the image of the face has its transparent pixels drawn properly on the left, but on the right, it substitutes black pixels. This, again, is the culpable line of code:

myGraphics2D.drawImage(myImage, myX, myY, new Color(0,0,0,0), null);

I greatly appreciate Piet for reassuring me that I haven't lost my mind. I will attempt to try other definitions of the transparent Color, then I'll try drawing using the background blue color. My reticence for doing this is that in different situations I must draw different background colors, and transferring that information to this drawing method will be a bit of a bother.

Thanks again for the help, and I'll report back with results!
 
Chris Crawford
Ranch Hand
Posts: 133
1
Mac OS X
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I stumbled on the solution, and it's ridiculously simple: replace this

myGraphics2D.drawImage(myImage, myX, myY, new Color(0,0,0,0), null);

with this:

myGraphics2D.drawImage(myImage, myX, myY, null);

In other words, simply refuse to specify any background color. It does make more sense this way; Rob's observation was on the mark. Earlier, the Java people had created a possibly confusing situation by permitting the upper version of drawImage code to function EXACTLY as described. Or perhaps I should say that their specification for the performance of the method permitted two possible interpretations. That is, until recently, specifying a transparent background color drew the transparent pixels as transparent. However, the lower version of drawImage was also in place, and it specified that it would draw transparent pixels as transparent. There were thus two ways to get a transparent background, and apparently somebody objected to the double meaning. I don't see a problem here; I think that they should have left it alone. But instead they decided to modify the upper version of drawImage so that it ignores the alpha channel in the specified background color. Perhaps they did so because, in their minds, it made no sense. In any case, I'm sure that some older Java apps will be tripped up over this.

Problem solved. Thanks so much for all the help!
 
Rob Camick
Rancher
Posts: 3242
30
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

I stumbled on the solution ...
In other words, simply refuse to specify any background color.



Sorry if I wasn't clear, that is what I meant when I said:

"Why can't you just paint the BufferedImage..."

I have never used the Color parameter before when using the drawImage(...) method, so I wasn't sure why you were trying to do that, especially since you where also trying to make this Color transparent?

And as Piet said:

"As Rob said, you can simply draw your image without the extra color parameter."
 
Piet Souris
Saloon Keeper
Posts: 4510
166
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
All's well that ends well!

But I have to revise my opinion. The call 'g2d.drawImage(buf, x, y, transparantColor, null)' does work as the API promises. I added to the code above a simple timer, that sets that color parameter. See for yourself:
(by the way: it might seem strange that I do not call 'super.paintComponent(g)'. But that is not needed in this case, since the next thing I do is overwrite the complete background with a GradientPaint)
 
You showed up just in time for the waffles! And this tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic