does Java2D support transparency for images?

just out of curiosity, is there anything very wrong with this?


private Image loadImage(String fileName, Container con, int transparency) {
            logger.loadingImage(getClass(), fileName);

            Image loadedImage = Toolkit.getDefaultToolkit().getImage(fileName);
            Image returnImage = null;

            MediaTracker tracker = new MediaTracker(con);
            tracker.addImage(loadedImage, 0);
            try {
                  tracker.waitForAll();
            }
            catch (InterruptedException e) {
                  logger.error(getClass(), "Error loading image from file: " + fileName);
            }

            returnImage = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(loadedImage.getWidth(null), loadedImage.getHeight(null), transparency);
            returnImage.getGraphics().drawImage(loadedImage, 0, 0, null);

            return returnImage;
      }

EDIT: a typo

Don’t see why not. It’s what my ImageLoader class is currently doing now, except that I force transparency instead of accepting an int for it. The code, in fact, is virtually identical.

yah i have methods like


public Image loadBitmaskedImage(String fileName) {
            return loadImage(fileName, new Container(), Transparency.BITMASK);
      }

i love small and lots of methods. damn that XP!

Abuse,

Just wanted to clarify something about Component.createImage(). When I said earlier that calls to this method will create managed (acceleratable) images, the method I was actually referring to was Component.createImage(w, h), not createImage(ImageProducer). This latter method will not produce a managed image and has the asynchronous problems you pointed out. But the createImage(w,h) version is completely synchronous (we create the image at the time that you call the method) and it creates a managed image. Note that this method does not support the transparency that you would need in a sprite; for that, you have to call GraphicsConfiguration.createCompatibleImage(w, h, Transparency.BITMASK), as mentioned in various posts above.

Sorry for the confusion; there’s just too many ways to create images and it’s easy to get them all confused, especially with our current managed image approach of only hooking into some of these methods for acceleration (just a quick hack while we work on the long term solution of being able to accelerate any image, no matter how it is created).

Chet.
Java2D

[quote]Abuse,

Just wanted to clarify something about Component.createImage(). When I said earlier that calls to this method will create managed (acceleratable) images, the method I was actually referring to was Component.createImage(w, h), not createImage(ImageProducer). This latter method will not produce a managed image and has the asynchronous problems you pointed out. But the createImage(w,h) version is completely synchronous (we create the image at the time that you call the method) and it creates a managed image. Note that this method does not support the transparency that you would need in a sprite; for that, you have to call GraphicsConfiguration.createCompatibleImage(w, h, Transparency.BITMASK), as mentioned in various posts above.

Sorry for the confusion; there’s just too many ways to create images and it’s easy to get them all confused, especially with our current managed image approach of only hooking into some of these methods for acceleration (just a quick hack while we work on the long term solution of being able to accelerate any image, no matter how it is created).

Chet.
Java2D
[/quote]
hehe, my mistake, :smiley:

The line you seem to have picked up on

frame.createImage()

was meant to read

toolkit.createImage()

(which makes what I said immediately after, make alot more sense :D)

as for component.createImage()

I’v already stopped using them in favor of the equivalent GraphicsConfiguration methods.

but I gotta agree, there are way way to many ways to create images :o

maybe for 1.4.2 some1 should go on a deprecation run :wink:

[quote]just out of curiosity, is there anything very wrong with this?


private Image loadImage(String fileName, Container con, int transparency) {
            logger.loadingImage(getClass(), fileName);

            Image loadedImage = Toolkit.getDefaultToolkit().getImage(fileName);
            Image returnImage = null;

            MediaTracker tracker = new MediaTracker(con);
            tracker.addImage(loadedImage, 0);
            try {
                  tracker.waitForAll();
            }
            catch (InterruptedException e) {
                  logger.error(getClass(), "Error loading image from file: " + fileName);
            }

            returnImage = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(loadedImage.getWidth(null), loadedImage.getHeight(null), transparency);
            returnImage.getGraphics().drawImage(loadedImage, 0, 0, null);

            return returnImage;
      }

EDIT: a typo
[/quote]
well, you’ve assumed the target machine only has 1 monitor, and 1 video device.


            Image loadedImage = Toolkit.getDefaultToolkit().getImage(fileName);

should realy read


            Image loadedImage = con.getToolkit().getImage(fileName);

and actually, the Toolkit class recommends that developers don’t use the toolkit.getImage() either, and instead use the createImage version. (and implement their own caching system)
so, I would say this is most correct :-


            Image loadedImage = con.getToolkit().createImage(fileName);

The same goes for


            returnImage = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice ().getDefaultConfiguration().createCompatibleImage(loadedImage.getWidth( null), loadedImage.getHeight(null), transparency);

you are assuming the default screen device, and default GraphicsConfiguration for that device. (hence the ‘compatible’ Image returned may not infact be ‘compatible’ for the Frame on which you intend to render the image!

So, i’d say the line should look like :-


            returnImage = con.getGraphicsConfiguration().createCompatibleImage(loadedImage.getWidth( null), loadedImage.getHeight(null), transparency);

ofcourse for that line to work, you’d also have to change the definition of the method, so ‘con’ was actually a Frame rather than just a Container.
(but it would make more sense passing in a Frame anyway :-
What You want to load (String, would be better as an URL)
Where you intend to render it (The Frame)
How you intend to render it (The transparency type))

P.S.

I was just thinking about the implications of using toolkit.getImage() on a system with multiple display devices (with regard to how the ‘managed image’ version of image would be handled

heres abit of code explaining what I mean :-


Image fred = getTookit().getImage("fred.png");
Image fred2 = getTookit().getImage("fred.png");
//at this point both fred and fred2 (although different objects) may have the same ImageProducer

GraphicsConfiguration gc1 = <a GraphicsConfiguration for device 1>;
GraphicsConfiguration gc2 = <a GraphicsConfiguration for device 2>;
//2 Graphics Configurations for 2 different devices.

Frame f1 = new Frame(gc1);
Frame f2 = new Frame(gc2);
//The 2 destination Frames (displayed on different screen devices)

f1.show();
f2.show();

f1.getGraphics().drawImage(fred);
f2.getGraphics().drawImage(fred2);
// ^ ok, you would need more than 1 draw for the image to be cached in VRAM,
// but, heres my question...
// how would they be cached :S

in that example, how would the automatic images be managed?
2 images sharing the same ImageProducer, while being rendered to 2 different display devices (and hence requiring 2 different VRam copies [potencially in different pixel formats?]) could cause an awful mess, could it not??

Abuse,

You reacted pretty strongly to the ImageIcon.getImage() above, calling it lazy and evil.

I’d like to know why, and I’d like to know what your suggestion for a non-lazy version would be.

(Please don’t take offense at my question, I’m REALLY REALLY tired and perhaps not phrasing it correctly, but also really interested in the answer. Why is it evil???)

[quote]Abuse,

You reacted pretty strongly to the ImageIcon.getImage() above, calling it lazy and evil.

I’d like to know why, and I’d like to know what your suggestion for a non-lazy version would be.
[/quote]
cos its horribly inefficient, if you go through the sourcecode, you’ll find that the little line…

new ImageIcon(String).getImage();

hides a huge amount of unnecessary code.

  1. you create an ImageIcon,

If its your first ImageIcon, then the following static stuff is created…

A) a MediaTracker


protected final static MediaTracker tracker = new MediaTracker(component);

B) and, because a MediaTracker needs an ImageObserver to monitor the loading, a Component is also created to pass into the MediaTrackers constructor.

protected final static Component component = new Component() {};

neither of those objects will ever become disposable (until the Class Loader is destroyed…),
so by simply creating an ImageIcon, you add an extra overhead to your mem. requirements.

  1. ImageIcon uses the toolkit.getImage() variants of the image loading methods rather than createImage(). I don’t know if that is good/bad/indifferent, but, it could potencially introduce some problems.

  2. MediaTracker itself contains all sorts of rubbish.
    For instance, each image added has a ‘MediaEntry’ object created, which as far as i can gather is simply a node for a linkedlist.
    (actually, 'cos its an image, it uses the subclass ‘ImageMediaEntry’!!)

there are 2 alternatives,

  1. the quick and ez path, use ImageIO :smiley:

  2. use toolkit.createImage, toolkit.prepareImage, and an ImageObserver of your own.

So am I :wink:
I always start bitching about Sun code when I get tired ::slight_smile: