Image : Java Glossary


Image
An Image is a virtual raster picture in the form of a bit map, e.g. *.png, *.gif, *.jpg or a bit image in RAM (Random Access Memory).
Image Formats Raw Byte Images GUI-less Images
Creating Images MediaTracker Under The Hood
ImageIcon vs Image AWT ImageViewer The Cast
Image Stages Swing ImageViewer VolatileImage
File Images Double Buffering Debugging
Server Images Saving Images to Disk Learning More
Resource Jar Images Transparency Links
Other Jar Images Getting Fancy

Image Formats

The four main image formats supported in HTML (Hypertext Markup Language) are *.gif, *.png, *.jpg and *.svg. There is a new format call WebP, but it is not yet supported in many browsers.
Image Format Properties
formatcompactlossytransparent backgroundsvariable transparencyphotos animationwide supportnotes
gif Oldest. Many variants. Patent has expired.
jpg Specialised for photos
png Creates feathered smooth transition to a background. Good for logos and icons.
svg It is a very compact vector format. Like PostScript, it is a set of mathematical descriptions of the picture which can be perfectly scaled to any size.
WebPeither Actually a suite of techniques bundled under one format.

Technically WebP would be the best format for HTML use because of its excellent compression, 30% better than jpg. The catch is, browser makers, and Java, have conspired against it because it Google created it. Compression is very important because it translates into snappier response since less has to be transmitted. Snappier response means happier visitors.

Creating Images

Usually the first question that comes up, even before wanting to know exactly what an Image is), is How do I create one? You will note that there is no constructor to let you use new Image. Not to worry, this is just a cheat-sheet summary. I will be going into more detail later. Here are some of the ways you can create an Image and its close relatives:

ImageIcon vs Image

ImageIcon is like an Image with an automatic MediaTracker built into load the Image from disk. Unfortunately, ImageIcon is not a subclass of Image, though internally it contains a reference to an Image. Some methods take an Image, some an ImageIcon.

Just to confuse matters, there is also the Icon interface that ImageIcon implements. Whenever you see a method taking a Icon, you can feed it an ImageIcon.

ImageIcon.getImage will convert an ImageIcon to an Image. The constructor new ImageIcon( Image image ) will convert an Image to an ImageIcon.

The ImageIcon class and the Icon interface have nothing whatsoever to do with Windows *.ico icon format that supports multiple resolutions in one file. Java ImageIcons don’t have to be magic sizes. They don’t have to be square. They can be *.png, *.gif or *.jpg just like Images.

Image Stages

The image goes through five stages making it to the screen:
  1. Images are often downloaded over the Internet or read from disk. Sometimes they are created out of raw bytes in some well known format in RAM.
  2. Then the image has to be converted from gif or compressed jpg to standard internal linear bit map format.
  3. The image may have to be scaled. Programmers using drawImage often inadvertently scale when they meant to clip or resize.
  4. Then the image has to be converted to native video card bit map format.
  5. Finally the image has to be copied into the REGEN (Regenerate) buffer of the video card.
Many threads can be working simultaneously on different parts of the image, each at different stages. Dealing with synchronising all this is a major stumbling block for new Java programmers. Trying to discover out which classes and methods do which work is difficult. The whole system does its best to hide the details from you. Even if you don’t understand the details, it certainly helps to understand in general terms how it works.

You can think of the scheme as like an assembly line. At each stage, the image consumer asks the previous stage image producer for a chunk of the partly processed image to work on. The producer gives it as much as it can, and the consumer then asks again later for the remaining bits. With this scheme, you do not have to wait until all the image has completely arrived before getting on with the later stages of processing, e.g. getting at least part of the image up there on the screen. The details of how it all works are mind boggling, but surprisingly, you can write code even if you have only the vaguest understanding of how they work.

You can just close you eyes to those complexities at first, but you will have to understand them once you start fine tuning your apps when you want to get rid of strange behaviours and flicker.

The Image class is abstract. You can’t instantiate an Image with a constructor. Part of the problem is Image is associated with some very platform dependent code. Besides the terrifying ways of dealing with ImageProducers, ImageConsumers and ImageObservers, there are some simple techniques to create an Image.

Saving an image in gif or jpg format is referred to as encoding.

Getting Images From A File

Another easy way to get an Image from the local hard disk is with, surprise,

It works with *.gif, *.jpg and in Java 1.4+, *.png files.

Getting Images From a Server

There is a variant of getImage that works in Applets or Applications to get the file from  One of the ways you can get that URL (Uniform Resource Locator) is with Applet. getResource.

Getting Images From The Archive Jar

To fish a gif or *.jpg out of a jar, you can use code like this: The code above will also work to find free-standing files lying about outside the jar on the classpath.

Class.getResource makes these changes to the resource name: if the resource name starts with /, it is unchanged; otherwise, the package name is prepended to the resource name after converting . to /. This allows you to use either dots or slashes to separate the components of the name. The name is case-sensitive. Double check the case by studying your jar files with WinZip.

Getting Images From Other Jars

You can read local jars with ZipFile using the InputStream. You can construct absolute URLs to them, similar to the ones getResource composes. It may be most efficient to download remote jars and process them locally. See the FileTransfer classes.

Getting Images from raw bytes

If you loaded contents of a jpg or gif in a socket stream, you would have the image in the form of raw bytes. You can convert it to an Image like this:
Toolkit.getDefaultToolkit().createImage( rawByteArray , start, length );

MediaTracker: Ensuring Images Are Fully Loaded Before Use

Unfortunately, getImage does not start downloading the image right away. It procrastinates until you do your first drawImage. Until then you can’t find out its size. You have to use prepareImage to trigger an early download. Much easier though is to use MediaTracker, since it provides a way of simultaneously downloading all your images, and letting you know when they all have arrived. Here is a minimalist example of using a MediaTracker. You must download the *.gif, *.png, or *.jpg over the Internet or read it from disk, which could be very time-consuming. That is why, by default, Java starts painting the Image even before it has completely arrived. However, it also has to be converted from *.gif, *.png or *.jpg format to standard format then to whatever native format the video card uses. That too is time consuming. MediaTracker does not ensure that process is complete. It only ensures the file in fully loaded into RAM. Oddly, even when you create Images from raw bytes already in RAM, you still need a MediaTracker.

AWT (Advanced Windowing Toolkit) ImageViewer

Once you have an Image, you can paint it onto a Canvas with Graphics.drawImage. This is pretty clumsy. See Canvas for how. You just want to be able to treat the Image as if it were a Component, e.g. a Button or Label.

There is no Component in Java version 1.6 or later that simply displays an Image. I have written one here called ImageViewer which is a greatly simplified version of the one that ships with Café. The component automatically sizes itself to fit the size of the Image you feed it. You can attach a standard MouseListener to it to trigger some action when somebody clicks it. Here is the source

You can download the latest source, and a fancier one called ResizingImageViewer as part of the Canadian Mind Products Business package

Swing ImageViewer

Here is the same ImageViewer with minor modifications to make it work under Swing instead.

Double Buffering

Double buffering is meticulously preparing an image offscreen, and when it is ready, blasting it instantaneously onto the screen. This way, the user is not distracted by all the tedious construction.

Without Swing, you have to handle double buffering yourself. With Swing, all you need is Component.setDoubleBuffered( true ). If you don’t use double buffering you paint directly to the screen. Double buffering is not always faster. In  Java version 1.2 or later Swing components, double buffering is applied by default. Sometimes you have to turn double buffering off to avoid strange ghosting effects. A simple offscreen drawing technique works like this:

I have experimented with Component.createImage( width, height). It is a tricky mechanism. It behaves differently in different JVMs (Java Virtual Machines) and different browsers. The problem is it uses the current Component’s (e.g. the Applet’s) peer object to create the offscreen Image object. createImage is an instance method of the current Component, not an independent static method as you might expect. That is how it finds the Component’s peer object in the native GUI (Graphic User Interface) that knows the details of the image format used by the particular video card we are using.

That peer does not get created until the last minute when Component.setVisible ( true ). Since you are presumably using createImage to eventually create that screen image, you have a minor catch-22. You can’t create the Image well ahead of time. You somehow must postpone any use of createImage until the Component’s addNotify method has been called assigning it a peer object in the native GUI that knows the native format for images on that particular video card. Hooking your code into the addNotify is an essay in itself.

In Java version 1.2 Component.isDisplayAble was introduced that lets you know if the peer object is ready yet for createImage to work. It definitely won’t work in static init. It sometimes works in init. Best to put it in an overriding addNotify method which is used to create the peer object. When it returns from super.addNotify is the earliest possible time you can use the peer.

public void addNotify()
   {
   super.addNotify();
   offScreenImage = createImage ( width, height );
   }

Encoding: Saving Images to Disk

Unfortunately, saving an image to disk in *.gif or *.jpg format is not so easy. There are no built-in ways to do it prior to Java 1.4. See JPEG-encoder and GIF-encoder. Part of the problem is the Unisys patent on the LZV (Logistik Zentrum Verden) compression algorithm used in the *.gif format. Read more on that issue.

png format bypasses the patent problem, but it is not as widely supported. Java did not support it until version 1.4. The easiest way is to use an external screen capture utility such as PaintShop Pro. if you want to do it under java program control, you have to look for third party image-savers. See Peter van der Linden’s FAQ for some options. You can of course serialize the Image, but you can’t reconstitute it on a different platform because the format of the pickled (serialized) Image is platform-dependent. For speed, Images are stored in a ColorModel (internal format) matching or closely matching the local video card.

See the source code for Cropper to see how to load, crop, scale and save a *.png, *.jpg or *.gif file.

Don’t try to send serialized Images over RMI (Remote Method Invocation) either for the same reason. One way to do it is to use uk.co.demon.windsong.image.ZipImage to convert the Image to a device Independent GZIPOutputStream, and the companion uk.co.demon.windsong.image.ImageProducer to reconstitute it.

Transparency

gif images can have a transparent background. Java honours it. *.jpg images do not have that feature. *.png images have a sophisticated transparent background scheme so that image looks good no matter what the colour the background. *.png supports gradual fades to the background colour. *.png now seems to be fully supported by Java and the most recent crop of browsers. I am gradually flipping over from gif to png for all my graphics.

Getting Fancy

Use java.awt.image.PixelGrabber to extract an array of RGB (Red Green Blue) ints from some rectangle in an image. MemoryImageSource is used to go the other way. It gives you an ImageProducer from an array RGBs (Red Green Blues). You can paint over top of an image by using Image.getGraphics. You can use a JPEG-encoder to save an image as a *.jpg file. drawImage comes in a version where you specify both the source and destination rectangles. This lets you paint part of an image, scaling it if necessary. There are many different flavours of Image object. One type of BufferedImage, for example, stores the image in a platform-independent format as an array of ints, packed with 8-bit RGB. You can convert traditional Images to this RGB type with Graphics.getRGB. You can convert an RGB array into a Image source with the MemoryImageSource constructor. MemoryImageSource.setAnimated and MemoryImageSource.newPixels let you create an animated image that updates the screen as you change that data backing it.

When you want animation speed/smoothness, look into VolatileImage available since Java version 1.4 which is implemented where possible inside the video hardware. BitBlts on such images would be done with the 128-bit GPU (Graphics Processing Unit) (graphics processing unit) which is much better designed than the CPU (Central Processing Unit) for shovelling misaligned bits around. You build your images in the offscreen part of the hardware video REGEN buffer. Then when you blast them to the screen, they go instantaneously, since the BitBlt video hardware moves it without having to cross the blood-brain boundary to the video hardware memory buffer. It is a high speed double buffering technique.

Manipulating Image Files Without a GUI

You will discover that many Image-handling methods need a Component or ImageObserver. If you are trying to do things like find the sizes of images in a non-GUI context what can you do?

Under the Hood

In your AWT paint method or equivalent Swing paintComponent method you use you use the drawImage method typically with code like

What is all this?

g is the Graphics object. It represents the place where we are painting to, usually the screen, but it could be printer or offscreen image. It knows what sort of image format the video card likes. It is passed as a parameter to your paint or paintComponent method.

image is the usually-MediaTracked image more or less ready to draw. It may be part way through the conversion process to internal format.

x,y is where on screen you want to paint the Image.

width, height is how much of the Image you want to copy, usually the whole thing.

this is the Canvas or other Component we are painting on. It is used to reschedule work that cannot be completed now.

done is true if drawImage was able to complete the work.

If done is false then things get interesting. The work is left unfinished and your paint method completes.

When more of the Image is ready, the ImageProducer will use the Component’s ImageObserver interface to call its default Component.updateImage method. That method then calls repaint with a clip region describing the uncompleted part of the work.

repaint schedules a repaint event, which eventually ends up calling your paint or paintComponent again, but this time with Graphics object with a reduced clip region so you don’t have to bother redoing the completed work if you are clever.

This process repeats until eventually drawImage returns true.

The key point to understand is that your paint or paintComponent method may be called several times to complete the drawing from an initial repaint request. You can write your paint method oblivious to this madness. The Graphics object automatically clips everything you draw to the uncompleted region. However, ideally you should avoid excessive painting outside the clip region.

The Cast

Image Processing Tools
Class or Method Purpose
BufferedImage A subclass of Image, that gives you additional ability to study and manipulate its bits. With ImageIO you can efficiently create them from images or disk or in RAM. You can actually instantiate an BufferedImage, unlike an abstract Image. You can examine and set individual bits with getRGB and setRGB. When you create a BufferedImage you decide the ColorModel it will use, e.g. how will pack the image and its colours into bits. BufferedImage is only available in Java version 1.2 or later.
Class.getResource get file in jar.
ColorModel abstract class that describes an internal bit map format. It is merely a set of methods for unpacking a single pixel coded as an int into alpha, red, green and blue. It does not know how to pack it up again. They are used by ImageConsumers to unpack the raw bytes and raw ints that ImageProducers throw at them.
Component.createImage creates empty Image, or creates an Image given any ImageProducer. Cannot be used until after addNotify. Similar to Toolkit.createImage.
Component.prepareImage starts the file loading, but does not ensure completion.
Component.updateImage ImageObserver interface to reschedule incomplete drawing. The ImageProducer notifies of the progress in preparing the Image by repeatedly calling Component.updateImage.
Graphics.drawImage copies bits from an Image to the screen or to another Image.
Image abstract class for plugging ImageProducers and ImageConsumers together. Much to my surprise, I discovered Image objects do not actually contain any bits of the picture. Image objects contain a reference to the ImageProducer, but not the ImageConsumer. The ImageProducers track all their ImageConsumers. getScaledInstance can be used to create a larger or smaller version of an image in one step. There are two concrete implement ions of the Image abstract class: BufferedImage and VolatileImage.
ImageConsumer interface capable of accepting image bits in one of Java’s standard internal formats (ColorModels) It may not necessarily receive them at once, or even in order. Graphics objects have ImageConsumers. They accept bits and convert them to the native GUI format for the video card. Other Graphics objects created by offscreen Image.getGraphics simply store the bits fed them in RAM somewhere, usually in one of Java’s standard formats. A VolatileImage.createGraphics stores its bits in native video card format right inside the video card’s private memory. ImageConsumers passively accept whatever bits the ImageProducers send to them. I don’t even see a way they can provide a clip region to the ImageProducer. On the other hand they are just passed the address of the bits. They are not obligated to copy any of them, so ImageConsumerss can do their own clipping fairly efficiently. You can write ImageFilters that act both as ImageConsumer and ImageProducer. They could clip, change colors, change ColorModels etc.
ImageIcon a wrapper class consisting of a reference an Image, a built-in MediaTracker and a text description. It is a convenient way to package an Image to hand to a JComponent such as a JButton to decorate it.
ImageProducer interface capable of providing image bits in one of Java’s standard internal formats. It does not have to provide them all at once, or even in order. It might be a method like URL.getContent that can fetch files off disk or the Internet and decompress the jpg format into standard Java internal bitmap format. Whenever it has more bits prepared, it hands them off to the ImageConsumer via ImageConsumer.setPixels.
ImageObserver interface used to reschedule incomplete painting. It gets notified of progress in preparing the Image via its ImageObserver.imageUpdate method.
MediaTracker Ensures a group of Images are fully loaded in RAM.
PixelGrabber captures pixels from any ImageProducer, and converts them into an array of pixel ints. It gives you direct access to the raw bits behind an Image for bulk import/export. You can change individual bits more easily with BufferedImage. getRGB and BufferedImage. setRGB. Pixels are stored in arrays and are subject to the Integer. MAX_VALUE addressing limit. This limit will bite you sooner than you think. The biggest square of pixels you can address is 46,340 × 46,340.
ToolKit.createImage create an image Image out of raw bytes, an URL a file or any ImageProducer. Similar to Component.createImage.
ToolKit.getImage get an Image from local hard disk. Beware. getImage caches results. Use createImage to bypass the caching. If you change the disk file of the image, and refetch you will likely get the old version again. Where do you get your Toolkit? from Component.getToolkit or Toolkit.getDefaultToolkit. If you get it from a Component, it must have a peer, e.g. after super.addNotify has returned. However, this is preferable since the Component will be automatically repainted as parts of the Image dribble in.
VolatileImage A Image living on borrowed time inside the regen buffer — video card’s private offscreen memory, already converted to the video card’s native internal format. It can be copied to the onscreen part of the REGEN by the video card 128-bit hardware in a twinkling.
WriteableRaster Lets you modify individual pixels in a BufferedImage.

Debugging

Working with Images is very frustrating. Your code compiles without error, and it generates no exceptions, but there you are, staring at a blank screen with no clue as to why nothing painted. Check the following:

Learning More

Oracle’s Javadoc on Image class : available:
Oracle’s Javadoc on BufferedImage class : available:
Oracle’s Javadoc on WritableRaster class : available:
Oracle’s Javadoc on VolatileImage class : available:
Oracle’s Javadoc on PixelGrabber class : available:
Oracle’s Javadoc on Graphics2D class : available:

This page is posted
on the web at:

http://mindprod.com/jgloss/image.html

Optional Replicator mirror
of mindprod.com
on local hard disk J:

J:\mindprod\jgloss\image.html
logo
Please the feedback from other visitors, or your own feedback about the site.
Contact Roedy. Please feel free to link to this page without explicit permission.
Blog
IP:[65.110.21.43]
Your face IP:[54.227.12.4]
You are visitor number