Please support my sponors and make this site possible!!!
Please support our sponsors!

 

Home > Core Java FAQ > Drawing FAQ
Drawing 
Drawing AWT Components (10)  *  Loading and Drawing Images (17)  *  Images (11) 
 
Q . How do I load an image from the net into my applet?

Ans : 

You first invoke getImage to establish a pointer to the image's data source, and then invoke another method, such as drawImage, to actually start pulling the image data across the network.

     The primary function of the AWT Image class is to bridge the gap between a source of image data and a specific output format for rendering that data:

 
image data source => Image instance => rendering (pixels) in specific format

Correspondingly, loading an image from a network data source happens in two stages. You first create a connection to a source of image data via a URL. Then you fetch and convert the image data to match your rendering target.
     For the simple case of displaying an image on screen in your applet, the two loading stages translate to the following method calls:

  1. Invoke getImage (from the Applet class) to register a URL as the data source for the image.

  2. Invoke drawImage on a Graphics instance to render the image at a given location, and optionally, scaled to a given size.
     Step 1, invoking getImage, merely specifies a data source. The drawImage method in step 2 initiates the real work. It starts a combined process of transferring, converting, and rendering the image data. Because this process can take some time, the AWT handles it in a separate thread.
     The following sample applet loads and displays an image file:
     import java.awt.*;
     public class LoadImageExample extends java.applet.Applet {
         Image myImage;
         public void init() {
             myImage = getImage(getDocumentBase(), "beach.gif");
         }
         public void paint(Graphics g) {
             g.drawImage(myImage, 0, 0, this);
         }
     }
Q . How do I load an image from a file in a stand-alone Java application, rather than in an applet?

Ans : 

Use one of the getImage methods in the AWT Toolkit class.

     Applet is the only Component subclass that provides its own getImage method. To load an image outside of an applet, you need the Toolkit class. Toolkit is an all-purpose utility class for AWT functionality not belonging to any Component in particular. Toolkit provides two getImage methods, one taking a file name as an argument, and the other taking a URL instance:

  • getImage(String)
  • getImage(URL)
     If the image file is on your local file system, you can invoke getImage with a string that represents the file name. For example:
     myImage = getToolkit().getImage("beach.gif");
The getToolkit method returns a Toolkit instance, on which you can then invoke getImage to create an Image instance. That Image instance is connected to the specified file as its source of data.
     To access a remote file, you need to invoke getImage with a URL argument. This requires the extra step of creating the URL instance:
     String urlString = "http://somemachine.com/somedir/somefile.gif";
     try {
         URL imageUrl = new URL(urlString);
         myImage = getToolkit().getImage(imageUrl);
     } catch (MalformedURLException e) {
         // ... recover from bad URL string
     }
Q . When is an image actually loaded--why not immediately?

Ans : 

The AWT seeks smarter and more efficient data transfer by waiting as long as possible before starting to load images.

     As mentioned in, the two main steps for image loading are: (1) to associate an Image instance with its data source (using getImage) and (2) to fetch and convert the image data.
     The AWT defers the second step until you invoke some method that specifically triggers the loading. These methods are listed in Table. The central idea is to wait to fetch the image data until the data is really needed. At this point, there is often enough information, such as target size, to make the process more efficient. The following scenarios illustrate the savings in time and space.

Table : Methods that Trigger Image Loading

Class Methods
Component prepareImage(Image, ImageObserver), prepareImage(Image, int, int, ImageObserver)
Graphics drawImage [family of four methods]
Image getWidth(), getHeight(), getProperty()
PixelGrabber grabPixels(), grabPixels(long)
MediaTracker wait, check, and status family of methods

     Scenario 1—loading a large image for use at a smaller scale. Suppose your source image is a GIF file that expands to 1 million pixels (1000´1000), each requiring 4 bytes of storage. If you automatically prefetch image data, your program must hold the full 4 megabytes in memory before deciding what to do with it. If all you want is a 200´200 version of the image, you can call drawImage and pass in the desired width and height as arguments:

     // ... set x and y as desired
     g.drawImage(myImage, x, y, 200, 200, this);
This triggers the actual image loading. Your Image instance will rescale the image as it fetches it, and the image data takes only 160,000 bytes of final storage (1/25th of the full-scale image).
     Scenario 2—loading/filtering a small portion of a large image. From the same-size image source as Scenario 1 (1 million pixels), you might want to display only a portion. The CropImageFilter class can extract a subarea from a larger source image, and it does so without requiring the full image data ever to be stored in memory.
     Scenario 3—faster web-page loading. Since an applet is usually just one among many occupants on a web page, it is a good strategy to invoke only getImage in your applet's init method. This allows your applet to initialize quickly and not hinder the rest of the page from loading. Your applet should wait until its start method to initiate potentially lengthy image loads. By this point, the rest of the web page will be available to the reader, and waiting for images will be less irksome.
     Delayed image loading provides substantial benefits, but also has its share of surprising twists that must be learned carefully. The drawImage method, for instance, returns immediately without waiting for the image to be completely loaded. Similarly, invoking getWidth or getHeight methods on an image before it is fully loaded will return the impossible value of -1. The AWT MediaTracker class  provides a key tool for overseeing the loading process and for ensuring that valid data is available from an image.
Q . How can I make sure that my images are completely loaded before I check for their data or parameters?

Ans : 

Use the MediaTracker class.

     The AWT MediaTracker class lets you monitor how your program loads images. (As the class's name suggests, MediaTracker may handle other media objects in the future, such as sound.) MediaTracker supports four kinds of operations for tracking images:

  • specifying groups of images to track
  • waiting for images to finish loading
  • checking for errors in the image-loading process
  • checking the current status of images being loaded
     A single MediaTracker instance can track any number of images, either all together or in separate groups. After creating a MediaTracker instance and as many Image instances as you need, you can add each image to a tracking group by invoking addImage on your MediaTracker instance. For example:
     /* code in an Applet subclass: */
     MediaTracker imageTracker = new MediaTracker(this);
     Image smallImage = getImage(getDocumentBase(), "small.gif");
     Image bigImage1 = getImage(getDocumentBase(), "big1.gif");
     Image bigImage2 = getImage(getDocumentBase(), "big2.gif");
     imageTracker.addImage(smallImage, 4);  // 1 image in group 4
     imageTracker.addImage(bigImage1, 8);   // 2 images in a group 8,
     imageTracker.addImage(bigImage2, 8);   //   e.g., for animation
This code fragment starts with a MediaTracker constructor, which requires that you specify a component that will be the ultimate consumer of the image data. The next three lines create Image instances, and the final three lines specify that one image belongs to group 4 and the other two belong to group 8. You can choose whatever numbers you like for your image groups—MediaTracker merely uses the number as a tag for the group as a whole. Note that the JDK 1.0.2 provides methods only for adding images to tracking groups; the JDK 1.1 provides a matching set of methods for removing images from tracking groups.
     The grouping of images allows other MediaTracker methods to apply to either a specific image group or to all images that the MediaTracker instance knows about. This distinction pervades the rest of the MediaTracker methods, as shown in Table.
Table : MediaTracker Methods
Method family Apply to images in specified group Apply to all images
wait for loading to complete waitForID(int) waitForAll()
waitForID(int, long) waitForAll(long)
check for loading errors isErrorID(int) isErrorAny()
getErrorsID(int) getErrorsAny()
check loading status checkID(int) checkAll()
checkID(int, boolean) checkAll(boolean)
statusID(int, boolean) statusAll(boolean)

     Methods in the wait... family do not return until all images in the specified set of images have either finished loading or encountered an error. (The optional long parameter specifies a maximum number of milliseconds to wait, rather than waiting indefinitely.) These methods also trigger loading of any images that haven't already started loading. Continuing the example just started, you could use the following code to wait for all images in group 8 to complete loading:

     try {
         imageTracker.waitForID(8);
     } catch (InterruptedException e) {
         // ... handle exception
     }
Note that waitForID, like several other methods that potentially suspend a thread's execution for a period of time, can throw an InterruptedException.
     The isError... and getErrors... methods check whether any errors have yet occurred while loading the specified set of images. The isError... methods return a boolean value indicating whether an error occurred. The getErrors... methods return an Object array indicating specifically which images had errors (or null if none of the specified images had an error).
     Finally, the loading status family of methods, check... and status..., report on the loading progress of the specified set of images. The check... methods return a boolean value indicating whether the images have finished loading. The status... methods report more specifically what states the images are in: not started, LOADING, COMPLETE, ERRORED, or ABORTED. The optional boolean parameter in the loading status methods specifies whether the method should also trigger loading for any images in the set that haven't yet started loading.
Q . Why does my call to Graphics's drawImage method fail to show the image?

Ans : 

The Graphic's drawImage method returns immediately, whether or not the image data is available; you need to check the image status by other means.

     The drawImage method in the Graphics class has two main tasks: it triggers the loading of image data across the network if the image data isn't already present, and it issues a request to start the drawing of the image. The method itself, however, is asynchronous—it issues requests to start this activity, but it returns immediately without waiting to see that everything has properly finished. If either the loading or drawing process goes astray, some other part of your program needs to detect and handle the situation.
     Two different objects can track the progress of image loading and rendering. First, all versions of drawImage require an ImageObserver object, that is, an object that implements the ImageObserver interface. The AWT invokes the imageupdate method on the ImageObserver object whenever the image's status changes—typically either additional data to render or trouble in loading.
     Instances of any component subclass, including an applet, can serve as an ImageObserver, by using their imageupdate method to monitor images being drawn onto them. However, the default imageupdate method in component does not check for image errors; it merely repaints the component periodically to reflect any newly available image data. If you want to catch errors with an ImageObserver object, you need to override imageupdate to check explicitly for error status in the method's flags argument.
     Another way to catch image failures is to use a MediaTracker instance. After registering your images with a MediaTracker object, you can wait for the images to finish loading and then check whether any images were stopped with an error. For example:

     Object[] imageErrorList;

     public void start() {
         // ...
         try {
             imageTracker.waitForAll();
             imageErrorList = imageTracker.getErrorsAny();
         } catch (InterruptedException e) {
             // ... handle exception;
         }

     public void paint(Graphics g) {
         g.drawImage(backImage, 0, 0, this);
         g.drawImage(foreImage, 130, 115, this);
         g.drawImage(bogusImage, 10, 10, this);
         if (imageErrorList != null) {
             String errors = imageErrorList.length
                             + " image(s) could not be loaded.";
             g.setColor(Color.red);
             g.drawString(errors, 10, 255);
         }
     }
Q . Can I force Applet's getImage method to make a new connection for each image rather than reusing a cached version of the image?

Ans : 

Yes; use the flush method in the Image class.

     Although the default behavior for getImage is to try first to use a cached image copy, you can cancel this by invoking flush on the Image instance:

     // ... myImage instance already created
     myImage.flush();
     // ... any use of myImage will now trigger a fresh download
This clears the Image instance so that it must be recreated from scratch or refetched across the net.
Q . How do I draw text over a background image?

Ans : 

Use the Graphics class's drawString method and draw the text directly on top of the image.

     The drawString method in the Graphics class draws only the pixels that make up the letter shapes. All other space amidst the text is transparent and lets the underlying image show through.
     You might be tempted to place a Label component on top of your image, but the effect will be quite unsatisfactory. Label instances always have a background color; the Label provides the text but also covers the image with an opaque background rectangle.

Q . How do I load and display a transparent GIF image over a background image?

Ans : 

Use the same steps as for any other image.

     Loading and displaying an image with transparency involves the same programming steps as a fully opaque image. The difference is just in how the image is rendered. The AWT doesn't paint anything for the transparent pixels of an image. Displaying a transparent image over a background image requires only that you draw the foreground image on top of the background image:

     public void paint(Graphics g) {
         // ... set x and y to position foregroundImage
         g.drawImage(backgroundImage, 0, 0, this);
         g.drawImage(foregroundImage, x, y, this);
     }
Q . How can I create an image from a buffer of raw image data (red, green, and blue values for each pixel)?

Ans :   

Use the MemoryImageSource class in the java.awt.image package.

The MemoryImageSource class uses an array of ints to produce pixel values for an image. In the default color model, shown in Table 8.3, int values carry four channels of information:

Table 8.3: Default Color Model—32-bit int Value
top 8 bits (0xFF << 24) alpha (opacity) value
2nd 8 bits (0xFF << 16) red value
3rd 8 bits (0xFF << 8) green value
bottom 8 bits (0xFF) blue value

Each 8 bits is interpreted as an unsigned value ranging from 0 to 255, with 255 indicating full presence of the color or full opacity.
     The array of int elements provides one-dimensional storage for a conceptually two-dimensional grid of values. The array index progresses from left to right in a row and then back to the start of the next row down. For example, a grid with four rows by six columns would yield the following arrangement of indices:

      0  1  2  3  4  5
      6  7  8  9 10 11
     12 13 14 15 16 17
     18 19 20 21 22 23
     Once you've created your int array, build a MemoryImageSource object from that, and then create an Image instance from the MemoryImageSource object:
     int width, height;
     int[] pixels;
     // ... set values for width, height, and pixels as desired
     Image myImage = createImage(new MemoryImageSource(width, height,
                                                       pixels, 0,
                                                       width));
     Running animation from a MemoryImageSource object is clumsy in JDK 1.0.2, but significantly easier in JDK 1.1
Q . What is double buffering--how can I create and draw to an offscreen image?

Ans :  

Double buffering is a drawing optimization in which you draw off screen first to create a complete image and then copy that image onto the screen all at once.

     Using an offscreen image for drawing is only a little more complicated than drawing directly to onscreen components. The two extra steps are: (1) to create an offscreen Image instance and (2) to get a reference to its Graphics instance. For example:

     int offscreenWidth = ...;
     int offscreenHeight = ...;
     Image offscreenImage = createImage(offscreenWidth, offscreenHeight);
     Graphics offscreenGraphics = offscreenImage.getGraphics();
At this point you can draw or place images using this new Graphics instance the same way as with any other Graphics instance. The following code continues from the previous example and draws a series of green squares onto a black background within the graphics context of the offscreen image:
     public void init() {
         // ...
         int offScreenSize = Math.min(offscreenWidth, offscreenHeight);
         offscreenGraphics.setColor(Color.black);
         offscreenGraphics.fillRect(0, 0,
                                    offscreenSize, offscreenSize);
         offscreenGraphics.setColor(Color.green);
         for (int i = 1; i < offscreenSize; i += 6) {
             int x = (offscreenSize - i) / 3;
             int y = (offscreenSize - i) / 3;
             offscreenGraphics.drawRect(x, y, i, i);
         }
     }
Finally, you can render the offscreen image onto the screen:
     public void paint(Graphics g) {
         // ... set x and y to position the top-left corner
         //     of the image
         g.drawImage(offscreenImage, x, y, this);
     }
     Using offscreen images has the main advantage that a complex image can be created once out of view of the user and then rendered on screen as many times as needed. This technique usually results in smoother animation, less flicker, and greater efficiency.
Q . How can I get at the raw data of an image, such as the pixel value at a given coordinate?

Ans :  

The PixelGrabber class (in the java.awt.image package) lets you extract pixel values from all or part of an image.

     Creating an AWT Image instance does not immediately create an array of pixel values for the image; it specifies a connection to a data source for the image but defers loading the image data until some specific operation requires it. What an Image instance really represents, thus, is a conduit for obtaining image data rather than a stocked data repository. PixelGrabber is a convenience class that obtains pixel data from an Image instance and makes that data available for your inspection at the pixel level.
     To use PixelGrabber, you specify all the important information up front in the PixelGrabber constructor. After that, you invoke grabPixels on the PixelGrabber instance (and provide for the InterruptedException that the method might throw). For example:

     // ... set width and height as desired
     Image myImage = ...
     int[] pixels = new int[width * height];
     PixelGrabber pg = new PixelGrabber(myImage,
                                        x, y, width, height,
                                        pixels,
                                        0, width);
     try {
         pg.grabPixels();
     } catch (InterruptedException e) {
         // ... handle exception
     }
     In this example, the x, y, width, and height arguments in the PixelGrabber constructor determine a rectangular region in the image: the region's top-left point (x, y) and its size (width, height). The grabPixels method pulls pixel values from this region and stores them as int values in the pixels array.
     The int values in the pixel array encode colors following the AWT default color model, which allots 1 byte each for opacity (alpha), red, green, and blue values . To obtain Color instances corresponding to the extracted pixel values, use the Color(int) constructor:
     // ... set index as desired
     Color pixelColor = new Color(pixels[index]);
     Unlike many other image-related methods, grabPixels is synchronous, so you can't be sure how long it takes to return. For robust applets, you should avoid calling grabPixels in any of the methods called within a system thread, such as init, start, and paint
Q . If you have an InputStream (rather than a file) that contains an Image, how can you display it?

Ans :  

Use this method, and some adroit shuffling.

Toolkit.getImage(URL url)

Create a thread that pretends to be an http server. Make it listen to some port (8765 for example) for incoming requests. When the thread gets a request, it should simply whisk up the appropriate http headers and follow it by the InputStream. Thus the component that has the input stream and wants to do the getImage(url) can now invoke:

Toolkit.getImage("localhost:8765/")

The thread will act as a stream-to-url adapter, and send back the data It saves you from having to read 200K of JPEG data before you can begin drawing anything.

Q . I loaded an Image file from a JPEG/GIF file using the Toolkit/Applet.createImage(URL/String) method, and (the height and width are -1 / it will not draw to the screen). What is wrong?

Ans :  

The behaviour of the AWT on creating images in this way is to do nothing at all.
When the image is first drawn using Component.drawImage(), or its size is requested, the image begins to load in a different Thread. As the image loads, the ImageObserver specified in the drawImage()/getHeight() call is periodically notified of the loading status of the image, by calls to its imageUpdate() method. In the case of Component.drawImage() call, the default behavior of
Component.imageUpdate() is to schedule *another* repaint() call when the image has fully loaded. This means that, in particular the following code will not work:

class MyComponent extends Component {
    ...
   public void paint(Graphics g) {
           ImageFilter cropper=new CropImageFilter(0,0,16,16);
           Image cropped_image=createImage(new
           FilteredImageSource(image.getSource(),cropper));
           g.drawImage(image,10,400,this); // this line works
          // this line doesn't -
          g.drawImage(cropped_image,400,15,this);
    }
}

The cropped_image will not be created in time to be painted, and whenit is finally created, another call will be scheduled to paint, which will try to draw another one, etc. (Note also that creating objects like this in paint() methods isgenerally a very poor idea in Java, since they are called very frequently, and you will strongly offend the garbage collector. In order to get round this problem, you may i) add all such Images to a MediaTracker, and call the waitForAll() method. ii) implement your own ImageObserver interface, and wait for the imageUpdate() method to be called with the ALLBITS/FRAMEBITS value. i) is easier, but ii) is recommended, since there are reports of MediaTracker not working in some environments.

Q . Does Java support PNG?

Ans :  

Yes. PNG - Portable Network Graphics - provides a patent-free replacement for GIF and TIFF. If you save a GIF, don't forget to pay the royalty to Unisys - see Unisys's web page at . That patent is why GIFs are a poor choice for internet images.
The PNG format is specified in RFCs 1950, 1951, and 2083, and is unencumbered by licenses or patents. See also the PNG-1.1 specification at ftp://swrinde.nde.swri.edu/pub/png/documents.

The PNG format is supported by the Java Advanced Imaging API which is part of the 1.2 media APIs.

Q . Why didn't my text display in my GUI? Is the Inset wrong?

Ans :  

The most common Inset problem is not an Inset problem at all, but rather that people just assume the x,y location of a Graphics.drawString() actually refers to the top left part of the string image. In fact it refers to the baseline. So you'll need to take the font metrics into account:

g.drawString("Hello World",0,getFontMetrics(getFont()).getAscent());

Q . Why did my polygon come out the wrong shape?

Ans :  This question and answer comes directly off comp.lang.java.programmer, and deserves to be immortalized for posterity.
When I use fillPolygon with the following points I get two inverted triangles instead of a rectangle. Why?

int xPoints[] = {71, 78, 71, 78};
int yPoints[] = {147, 147, 130, 130};
g.fillPolygon(xPoints, ypoints, xPoints.length);

Developer Felix Pahl supplied the answer in limerick form:
o A developer (for details bored her) didn't follow the polygon's border so instead of right angles
she got two triangles 'cause the endpoints were in the wrong order!

You must put the points in the order you would encounter them in if you went round the polygon's border. The filling algorithm is doing the right thing! Try drawing the points on paper to see:

71,130 78,130
O--------O
|           |
|           |
|           |
O--------O
71,147 78,147

Under JDK1.1, the two endpoints are connected automatically and you would order the array elements as:

int xPoints[] = { 71, 78, 78, 71};
int yPoints[] = {130, 130, 147, 147};

Under JDK1.0.2, you have to explicitly connect the two endpoints, and you would write the array elements as:

int xPoints[] = { 71, 78, 78, 71, 71};
int yPoints[] = {130, 130, 147, 147, 130};

Q . Do DrawRect and FillRect work on rectangles of the same size?

Ans :  

No. java.awt.Graphics.drawRect draws a rectangle that's 1 pixel wider and 1 pixel taller than a rectangle drawn by fillRect.

 

Copyright © 2000 javafaq.com. All rights reserved