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 . Using the JDK 1.0.2, can I clear or reset a clipping rectangle that either I or the system has created?

Ans : 

In the JDK 1.0.2 you can't; for a given Graphics instance, the drawable region represented by the clipping rectangle can only get smaller as new clipping rectangles are specified (this restriction is no longer true in the JDK 1.1).

A Graphics instance provides a drawing space to your program in two parts:

  • a coordinate space to locate the pixels affected by your graphics operations
  • a clipping rectangle outside of which your graphics operations have no effect
You can change the coordinate space with the Graphics translate method, and you can change the clipping rectangle with the Graphics clipRect method.
     The clipRect method, however, does not simply set a new clipping rectangle. Instead, the rectangle you specify as the argument to clipRect is intersected with the existing rectangle to yield the new drawable region. Each new clipping rectangle is contained wholly within the previous one. This ensures, for example, that components cannot draw outside the bounds of their containers, all the way up the containment chain. Similarly, no part of an applet can ever draw outside its bounds onto the rest of the web page.
     If you need more freedom in using multiple clipping rectangles within your program, you can create separate "throwaway" graphics objects as children of your main Graphics instance. Below is an example of this cumbersome workaround:
     /* using JDK 1.0.2: */
     public void paint(Graphics g) {
         Graphics ng;
         int x, y, width, height;
         // ... set x, y, width, and height as needed
         ng = g.create(x, y, width, height);
         ng.drawSomething();
         ng.dispose();

         // ... set new values for x, y, width, and height
         ng = g.create(x, y, width, height);
         ng.drawSomethingElse();
         ng.dispose();
         // ... and so on
     }
The Graphics create(x, y, w, h) method creates a new Graphics instance with the clipping rectangle (x, y, w, h) based on the old Graphics instance. The origin (0, 0) in the new Graphics instance corresponds to (x, y) in the parent Graphics context. Also, any clipping rectangle in the child will still be constrained to lie completely within the parent's clipping rectangle.
     The JDK 1.1 provides direct support for resettable clipping rectangles, which removes the need for the above workaround
Q . Using the JDK 1.0.2, can I copy a subarea of one image into another image?

Ans : 

Yes, but it's not as easy as it should be (and this is fixed in the JDK 1.1); the trick in the JDK 1.0.2 is to use the clipping rectangle of the receiving image to delimit the subarea of the source image.

     Like all drawing methods in the Graphics class, drawImage honors the current clipping rectangle of the Graphicsinstance. In other words, the only part of the image that shows up is the part within the Graphics clipping rectangle. The following code fragment illustrates how to take advantage of this clipping behavior—it loads one image from a file, creates a second image that is one-half as long on each edge, and then draws a portion of the main image into the smaller image.

     String srcImageName = ...;
     int size = ...;
     Image srcImage = getImage(getDocumentBase(), srcImageName);
     Image dstImage = createImage(size/2, size/2);
     Graphics dstImageGraphics = dstImage.getGraphics();
     // ... select x, y to indicate the upper-left corner
     //     of the subarea (e.g., size/4, size/4)
     dstImageGraphics.drawImage(srcImage, -x, -y, this);
Understanding the last line of this code fragment is the key. That line tells the dstImageGraphics instance to render a copy of srcImage such that point (0, 0) of srcImage aligns with point (-x, -y) in the dstImage's coordinate space.
     Now, which part of srcImage gets copied into dstImage? Only the part that falls within dstImageGraphics's clipping rectangle: from (0, 0) in the top-left corner to (size/2, size/2) in the bottom-right corner. Table 8.4 shows the key correspondences that map from dstImage's clipping rectangle into srcImage's coordinates:

 

Table 8.4: Coordinate Correspondences
dstImage srcImage
(-x, -y) (0, 0)
(0, 0) (x, y)
(size/2, size/2) (x + size/2, y + size/2)

Thus, in srcImage's coordinates, the subarea that gets copied ranges from (x, y) in the top-left corner to (x + size/2, y + size/2) in the bottom-right corner.
     If you want to get fancier and draw the image subarea to a specific point in the second image, you need to restrict the clipping rectangle on the target rectangle. The following code, for example, copies srcImage's subarea (srcX, srcY, w, h) to point (dstX, dstY) in dstImage:

     dstImageGraphics.clipRect(dstX, dstY, w, h);
     dstImageGraphics.drawImage(srcImage, dstX - srcX, dstY - srcY,
                                this);
provides further information on setting clipping rectangles in conjunction with temporary Graphics objects.  Note: The JDK 1.1 provides a much simpler way to handle subarea copying
Q . How do I control animation with MemoryImageSource?

Ans : 

Use the new MemoryImageSource methods in the JDK 1.1: setAnimated, setFullBufferupdates, and newPixels.

 The MemoryImageSource class converts arrays of pixel values into a data source for Image instances . In the JDK 1.0.2, MemoryImageSource was designed for one-time image creation. Such images displayed quickly, but they did not automatically consult the original array data for each display. To update the image after the underlying array had changed required flushing the old image data (using Image's flush method) and essentially creating an entirely new image. This model did not work well for animation.      The JDK 1.1 enhances MemoryImageSource with a family of methods designed for animation, as outlined in Table 8.5.

 

Table 8.5: Animation Methods in MemoryImageSource—JDK1.1
setAnimated(boolean) specifies whether the image can receive dynamic updates for changes in the data
setFullBufferupdates(boolean) specifies whether the image updates should always send a full buffer of pixel data
newPixels() newPixels(int, int, int, int)... signals to any consumers of the image data that a new bufferful (or region) of pixel data is ready

     The setAnimated and setFullBufferupdates methods are used to prepare a MemoryImageSource instance for animation. The right place to invoke them is before you create an Image instance from the MemoryImageSource instance. For example:

     int width = ...;
     int height = ...;
     int[] pixels = new int[width * height];
     Image myImage;
     MemoryImageSource imageSource;

     Image buildAnimatedImage() {
         for (int i = 0; i < width * height; ++i) {
             pixels[i] = ...;
         }
         imageSource = new MemoryImageSource(width, height, pixels,
                                             0, width);
         /* Enable animation and subregion updates.*/
         imageSource.setAnimated(true);
         imageSource.setFullBufferUpdates(false);
         return createImage(imageSource);
     }
     These steps prepare the image for animation, but you must still invoke one of the newPixels methods to trigger an image update. The following code fragment continues from the above example:
     Thread animation = ...;
     public void run() {
         while (Thread.currentThread() == animation) {
             int x = ...;  // 0 <= x <= width
             int y = ...;  // 0 <= y <= height
             int index = y * width + x;
             pixels[index] = previousValue;  // change just one pixel
             imageSource.newPixels(x, y, 1, 1);
             // ... wait or sleep for a bit
         }
     }
And, finally, the image itself must be displayed:
     public void paint(Graphics g) {
         g.drawImage(myImage, 0, 0, 240, 240, this);
     }
Q . Does Java support animated GIFs?

Ans : 

Java 1.0.2 and earlier releases use GIF and JPEG formats, and do not use the GIF89 animated GIF format. (An animated GIF is one that contains successive frames of an image, so when they are displayed in quick sequence the image appears to contain movement). When you display an animated GIF in Java 1.0.2, you will just get the first frame. There doesn't appear to be any easy way to get other frames from the image. The advantage of an animated GIF file is that there is only one file to download, and it is simple to do simple animations. The advantage of programmatic control over individual frames is that you control the rate and order of displaying them.
Here's a surprise: JDK 1.1 supports the animated display of animated GIFs. For simple animations animated GIFs are a lot easier and lighter-weight than coding an animation explicitly.

Q . How do I create animated GIFs?

Ans :  

Use GIFanimator from ULead (said to be the best) , or GIF Construction Set from Alchemy Mindworks

Q . How do I prevent animated GIFs from flashing while displaying?

Ans : 

The problem is most likely that in your paint method you have

          g.drawImage(img, ix, iy, this);


You should change this to

         g.drawImage(img, ix, iy, getBackground(), this);

This will change all the transparent regions of the image to the background color before painting to the screen. If you paint transparent images directly to the screen they flicker. If that does not solve it then check that imageUpdate is

public boolean imageUpdate(Image img, int flags, int x, int y,
   int width, int height) {
      if ((flags & (FRAMEBITS|ALLBITS))!= 0) repaint();
      return (flags & (ALLBITS|ABORT)) == 0;
}

update is

public void update(Graphics g) { paint(g); }

If you have a background Image behind the partly transparent animated GIF you will have to double buffer. You can crop the backgound image so you won't have to double buffer the full app and waste too much memory.

Q . Does Java support transparent GIFs?

Ans : 

GIF89a images with a transparent background show up as transparent without further filtering. This has been supported from 1.0 on. Java correctly displays both animated GIFs and transparent GIFs.
Even better, you can fill the transparent pixels with a color (so they appear non-transparent in Java). Just pass the fill color explicitly:

drawImage(img, x, y, w, h, fillcolor, this);

Further, you can filter the pixels of an Image to turn any bits you wish transparent. However, the most you can do is reveal what is underneath the image. You cannot reveal what is underneath the applet
(i.e. on the browser itself). By default applets have a plain grey background.

Q . How can I save an Image file to disk in JPG or GIF format?

Ans : 

o If you have an Image and you want a JPG in a file, download James Weeks's code from http://www.obrador.com/essentialjpeg/ 
o Sean Breslin also wrote a program that compresses a Java Image into a JPEG file. http://www.afu.com/jpeg.txt
o If you just want to convert some file, a non-Java solution is to use the standard IJG 'cjpeg' utility. It supports GIF, PPM, BMP, PNG and Targa input files.
o If you have an Image and you want a GIF or PPM in a file, download Jef Poskanzer's abstract ImageEncoder class at http://www.acme.com/java/software/ Also try the Java Image Management Interface (JIMI), which is free for non-commercial use. JIMI is a toolkit that lets your Java programs read and write many graphics file formats (PNG, JPG, BMP, GIF etc). JIMI is written in 100% Java, and best of all, it's a breeze to get started with. See  http://www.activated.com/jimi.html 

Q . How can I convert between GIF and JPEG formats?

Ans :   

In a word: don't.
There's hardly any overlap between the set of images that JPEG works well on and the set that GIF works well on. Sometimes, with enough care, you can get an acceptable conversion...but most of the time GIF<->JPEG conversion will just turn your image to mush. It's better to pick the right format in the first place.
Other sites:
o If you're determined to convert formats anyway, try the GBM (Generalized Bitmap Module). The package is GNU licensed, in C and is very good. Find it at http://www.interalpha.net/customer/nyangau/ 
GBM does a good job converting to JPEG, and 'lossiness' is adjustable to 0%. It also converts to/from about 20 other formats, does cropping, sizing, color mapping, gamma correction, halftoning, everything you could want. GBM source doesn't support JPEG directly, but utilizes JPEG source from IJG called jpeg-6a and found at ftp://sun2.urz.uni-heidelberg.de/pub/simtel/graphics/jpegsr6a.zip 
o For more info see the JPEG FAQ at http://www.faqs.org/faqs/jpeg-faq/ 

Q . Using the JDK 1.1, how do I reset a clipping rectangle?

Ans :  

Invoke one of the setClip methods; setClip establishes a new clipping region that is independent of previous calls to setClip.

     The JDK 1.1 distinguishes between two kinds of clipping regions to limit your program's drawing space:

  • a system-supplied clipping region set by the AWT as part of the Graphics argument in invocations of paint  and update 
  • a user-defined clipping region, lying within the system-supplied region, determined by the most recent invocation of setClip on the current Graphics object
The overall drawable space is strictly bounded by the AWT-supplied clipping region, but you are free to set and reset a local clipping region within that space as much as you like. These temporary clipping regions are very useful for controlling individual rendering operations.
     The new JDK 1.1 methods for controlling the clipping region are shown in Table 8.6.

 

Table 8.6: Methods for Getting and Setting the Clip Region—JDK 1.1
Shape getClip() returns the current clipping region as a Shape object
Shape getClipBounds() returns the smallest rectangle that completely encloses the current clipping region
void setClip(Shape) sets the current clipping region to the specified Shape object (e.g., a Rectangle instance)
void setClip(int, int, int, int) sets the current clipping region to a rectangle with the specified x, y, width, and height values

     The JDK 1.1 supports only rectangular clipping regions, but, in anticipation of future implementations, the above methods are designed around the Shape interface (which has just one method, getBounds).
     The following code fragment recasts the sample code of  in terms of the JDK 1.1 methods:

     /* using JDK 1.1: */
     public void paint(Graphics g) {
         int x, y, width, height;
         // ... set x, y, width, and height as needed
         g.setClip(x, y, width, height);
         g.drawSomething();
         // ... set new values for x, y, width, and height
         g.setClip(x, y, width, height);
         g.drawSomethingElse();
         // ... and so on
     }
You can also use the getClip method to save a clipping region so that you can restore it later. For example:
         Shape originalClip = g.getClip();
         g.setClip(x, y, width, height);
         // ... draw using new clipping region
         g.setClip(originalClip);
         // ... draw using original clipping region
Q . What's the best way in JDK 1.1 to draw just a subarea of an image?

Ans :  

Use the new drawImage methods (starting with JDK 1.1), which let you specify a rectangular subarea of the image to draw.

     The JDK 1.0.2 provides drawImage methods that let you specify how a full image will be rendered into a target graphics context, but you have to work indirectly to achieve the effect of drawing just a portion of the image. The JDK 1.1 adds two new drawImage methods that let you specify a mapping from a rectangle in the image to a rectangle in the target graphics context. This mapping provides two capabilities not present in the JDK 1.0.2:

  • you can specify a subarea of the source image to render
  • you can flip the image horizontally, vertically, or both
Here's how it works. The two new drawImage methods specify rectangles differently from the rest of the AWT: they specify a logical top-left point and a logical bottom-right point for each rectangle, 

To draw a subarea of an image, provide the subimage rectangle in the two-point format just described. For example:

     /* using JDK 1.1: */
     Image myImage = ...;
     public void paint(Graphics g) {
         g.drawImage(myImage,
                     0, 0, 200, 100,    // points (0,0) and (200,100)
                                        // of destination rectangle
                    50, 50, 150, 100,   // points (50,50) and (150,100)
                                        // of source rectangle
                       Color.black,     // draw image on black background
                       this);  // use this instance as the image observer
         // ...
     }
This code takes an image subarea 100 units wide by 50 high, at location (50, 50), and draws it into the graphics area 200 units wide by 100 high, located at (0, 0). The following diagram shows the two rectangles, and how the two points defining the image source rectangle map to the two points defining the target graphics context rectangle:

The drawImage methods also let you flip images vertically, horizontally, or both. The following drawImage invocation modifies the previous example to flip the image vertically:

     g.drawImage(myImage,
                 0, 0, 200, 100,   // points (0,0) and (200,100)
                                   // of destination rectangle
                 50, 100, 150, 50, // points (50,100) and (150,50)
                                   // of source rectangle
                 Color.black,      // draw image on black background
                 this);  // use this instance as the image observer

 

Copyright © 2000 javafaq.com. All rights reserved