The Source for Java Technology Collaboration
User: Password:



Chet Haase

Chet Haase's Blog

BufferedImage as Good as Butter

Posted by chet on August 14, 2003 at 01:59 PM | Comments (4)

Recently there was a brief discussion on the java2d interest list. We were talking about some of uses of BufferedImage and someone replied to the group with their epiphany on these objects with just a brief: "BufferedImage as good as butter!"

The Java2D team has spent the last few days trying to understand and come to terms with this phrase. Was it praise? Irony? Sarcasm? An epigram? A typo? Does it mean that BufferedImage is yellow? Or creamy? Or that it spreads well if left out of the fridge, but melts if it is too hot outside? Is it a condiment? Does it go well with bread? Is it a substitute for vegetable oil?

I have decided it was actually one of those opaque philosophical phrases that you might see in a fortune cookie (albeit one that you got from a very geeky restaurant). I do not yet understand its true meaning, but I hope to walk far enough on the path to enlightenment to one day glean its essence.

In the meantime, I will arbitrarily choose one possible meaning for the purposes of this article: BufferedImages are slick.

One of the things that we and our developers run up against again and again (and again) is the vast array of possibilities when dealing with images and image operations in our APIs. In particular, confusion appears to reign when developers first learned Java in the 1.0/1.1 days (whose APIs are still working and prevalent in some browsers' implementations of Java) but they are now trying to apply that knowledge in the current API and implementation.

So, for example, someone could easily assume that ImageProducer/ImageConsumer is still the way to deal with creating and using images. Or that PixelGrabber is a great way to get at the actual pixel data in an image. Or that MediaTracker is a really cool way to ensure that an image is loaded before you use it.

Then these developers run into the new (as of 1.4) ImageIO APIs and wonder how they get from their Image to a BufferedImage.

Might we suggest, instead, trying to use BufferedImage for most, if not all, of your condiment image needs. There are very few situations where you really want or need to use the old Image APIs and thus translating between that world and the new world of BufferedImage is really unnecessary. ImageProducer/Consumer is an interesting way of dealing with Images that are coming over the net and won't arrive until some nondeterministic time in the future, but if you have the image on disk and simply want to load it in, that's a pile of work to go through (and some pretty non-obvious API calls) just to get your hands on the data. Or if you want an image that you can access the pixel data on, you can sure use PixelGrabber, but wouldn't it make more sense to simply call get/setRGB on a BufferedImage? Or if you want an offscreen image, wouldn't it be nice to simply be able to create an image of a specific type (or one compatible with the display) and simply give it the width and height to use?

In particular, check out the simple commands like:

new BufferedImage(int width, int height, int type)
that give you an image of the width/height/type you require, synchronously (that is, after the method returns, that image does exist; no need to send it through MediaTracker to await its imminent arrival). You can then get at the data directly (getRGB, setRGB), grab the Raster object (which allows more ways of getting at the pixel data), get the ColorModel, and all sorts of other complex and interesting stuff. But you don't have to do anything complicated with it to take advantage of this API; you can just create that image, get the Graphics object, render to it, and away you go.

Or how about:

GraphicsConfiguration.createCompatibleImage(int width, int height)
This retuns an opaque BufferedImage (there is another variation in which you can specify a non-opaque type) of the given width/height that should be in the same format as the screen. This means that operations to/from the screen or other compatible images should be optimized (and sometimes hardware accelerated).

Then there's always the entire ImageIO package, which deals exclusively in BufferedImage objects. Instead of using the old Toolkit APIs to load an Image, you can use ImageIO to read images of more varied types (such as PNG) which will then return a BufferedImage.

And remember too that converting from one image type to another is usually as easy as a simple copy command. So, for example, if you happen to have one of these old Image objects lying around and you really want to get at the pixels, or use ImageIO, or just revel in the power and glory of having a BufferedImage representation of that image, you can always do something like this:

// your other image type
Image img;

// new, cool representation of that image, created by one
// of the means above, with width/height equal to img's
BufferedImage bImg;

// Get the Graphics object for the BufferedImage
Graphics g = bImg.getGraphics();

// Copy the old image into the new BufferedImage object
g.drawImage(img, 0, 0, null);

So store it in the fridge, keep it out on the counter, spread it on your favorite wheat products and applications; BufferedImage is as good as butter ... and maybe even better.

ps: Did you notice I didn't touch on that hot "performance" topic anywhere in this article? Stay tuned for the next article, in which I'll talk about some of the performance implications and implementation details of BufferedImages.


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • J2ME
    Us J2ME develpers already knew these tricks and this BufferedImage revelation :)

    Posted by: shareme on August 14, 2003 at 02:58 PM

  • Severe bottleneck
    One of the most common bottleneck's in code is when people use BufferedImage badly. Generally you should avoid:

    new BufferedImage(...)

    in favor of the:

    GraphicsConfiguration.createCompatibleImage(...);

    since the type of BufferedImage you create is almost guaranteed to not be the best choice for each platform and it can make a massive difference in speed. Often you will only notice the speed hit when moving to a different OS - typically OS X since INT_RGB types require a lot of work to get them into a native format. This can really make your app slow, but is a very simple change to restore performance.

    Naturally, if you're not blitting to screen or some other device that goes through the OS's imaging routines then it may avoid the slowdown but I would always favor createCompatibleImage over new BufferedImage until actual profilling data shows new BufferedImage is faster.

    Otherwise yes, BufferedImage is in fact better than butter.

    Posted by: ajsutton on August 14, 2003 at 04:22 PM

  • Severe bottleneck
    Agreed; unless you have a reason to use a BufferedImage of a specific type, the best default for performance purposes is definitely the BufferedImage provided by createCompatibleImage(). Tune in next time for more performance info about BufferedImages in current and future releases.

    Posted by: chet on August 14, 2003 at 06:01 PM

  • but when you render it...
    it seems to me that ImageWriters are singletons, and they are forced to be stateful by API. so your big powerful server can only render one image at a time:

    synchronized(writer){
    writer.setOutput(...);
    writer.write(...);
    }

    Posted by: zhong on August 14, 2003 at 06:03 PM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds