Thursday, 14 May 2015

Clipping Images (CropImageFilter, MediaTracker) in Java


If you're using Java on the Internet, you'll find that you'll want to crop images more often than you might expect. The reason for this is that there is a fairly significant overhead associated with sending a file from the server to the client. As a result, you can make your applet load faster if you send one file that is 2x pixels on a side instead of four files that are 1x pixels on a side. If you go with one large file, you'll find that theCropImageFilter class will make it easy to cut out pieces of the image. This is a good way to work with multi-frame animations. Put all the animations in a single file and then use CropImageFilter to make a separate image for each cell in the animation.

CropImageFilter Creator

You won't use any of CropImageFilter's methods other than its creator:
new CropImageFilter(int x, int y, int width, int height)
The input parameters define the rectangular region that will be selected. The coordinates are with respect to the upper-left corner of the image, which is set to 0,0.

The applet in Listing 17.33 reads in a GIF file, creates a new image that is the upper-left corner of the original image, and then displays both images,

Listing 17.33. Cropping an image.
import java.applet.Applet;
import java.awt.*;
import java.awt.image.*;


public class crop_image extends Applet implements  Runnable{
    Image the_picture, cropped_picture;
    boolean image_ready;
    Thread the_thread;
    MediaTracker the_tracker;

    public void start() {
        if (the_thread == null) {
            the_thread = new Thread(this);
            the_thread.start();
        }
    }
    public void stop() {
        the_thread.stop();
    }

    public void run() {
        the_thread.setPriority(Thread.MIN_PRIORITY);
        while (true) {
            repaint();
            try {
                the_thread.sleep(3000);
            } catch(InterruptedException e) {};
        }
    }
    public void init()
    {
        CropImageFilter c_i_filter;

        //Define a MediaTracker to monitor the completion status of an image
        //You need to supply a component as the argument.
        //In this case the applet
        // is used
        the_tracker = new MediaTracker(this);
        image_ready = false;
        the_picture = getImage(getDocumentBase(),"test.gif");
        //tell MediaTracker to monitor the progress of the image and
        //assign the image
        //the index of 0--the index value is arbitrary
        the_tracker.addImage(the_picture,0);
        //Define an image cropping filter
        c_i_filter = new CropImageFilter(0,0,32,32);
        //Apply the filter to the image and make a new image of the cropped area
        cropped_picture = createImage(new FilteredImageSource(
                the_picture.getSource(),c_i_filter));
        //Monitor the cropped image to see when it's done
        the_tracker.addImage(cropped_picture,1);

    }
    public void paint(Graphics g)
    {
        //Wait till both images are ready
        if(the_tracker.checkID(0,true) &
                                the_tracker.checkID(1,true)) {
            image_ready = true;
            g.drawImage(the_picture,0,0,this);
            g.drawImage(cropped_picture,70,70,this);
        } else {
            System.out.println("Waiting for image to fully load");
        }
    }
}

MediaTracker

The applet shown in Figure 17.44 also demonstrates how to use the MediaTracker class to monitor images that are being loaded or built. All you have to do is create a new instance of the MediaTrackerclass.
To create a MediaTracker instance to monitor the loading of images associated with the specified component, use this code:
new MediaTracker(Component a_component)
To track images, you'll use these MediaTracker methods:
addImage(Image an_image, int id)
Tells MediaTracker to monitor the specified image. The ID is used in other method calls to identify the image. You can use any value for the ID, and you can assign the same ID to more than one image.
addImage(Image an_image, int id, int width, int height)
Functions like the preceding method, except that it registers a scaled image where width and height are the new dimensions of the image. This is a synchronized method.
boolean, checkAll()
Returns TRUE when the images have loaded or stopped loading due to an error. Use the isErrorAny and/or isErrorID methods to check for problems.
boolean, checkAll(boolean load_flag)
Returns TRUE if all images have finished loading or encountered an error. This is a synchronized method. It forces the images to load if the input parameter is TRUE.
boolean, checkID(int the_id)
Returns TRUE if the specified image (or group of images, if more than one image has the same ID) has finished loading or stopped due to an error.
boolean, checkID(int the_id, boolean load_flag)
Returns TRUE if the images with the specified ID are loaded or have encountered an error. If load_flag is TRUE, this synchronized method starts to load the image if it isn't already loading.
Object[], getErrorsAny()
Returns an array of media objects for those images that encountered errors. This is a synchronized method. You can print these objects by using the .toString method on them.
Object[], getErrorsID(int id)
Returns an array of media objects for the images with the specified ID that encountered an error while loading. This is a synchronized method.
boolean, isErrorAny()
Returns TRUE if any image currently being tracked has a problem. This is a synchronized method.
boolean, isErrorID(int id)
Returns TRUE if any image with the specified ID has received an error while loading. This is a synchronized method.
int, statusAll(boolean load_flag)
Returns the status of the loading of all the images. ANDing the returned value with MediaTracker.ERRORED returns TRUE if there is an error. If the input parameter is TRUE, this method starts loading the images if they haven't already been loaded.
int, statusID(int id, boolean load_flag)
Functions similarly to statusAll, except for a single ID.
waitForAll()
Waits until all images are loaded or encounter an error. If this method is interrupted, it throws the InterruptedException error.
boolean, waitForAll(long time_in_ms)
Functions similarly to waitForAll, except that it will timeout after the specified time. This is  a synchronized method.
waitForID(int id)
Functions similarly to waitForAll, except for a single ID.
boolean, waitForID(int id, long time_in_ms)
Functions similarly to waitForAll, except for a single ID. This is a synchronized method.
As you can see from the applet in Listing 17.33, though, you only need to use a couple of methods to monitor image loading in most circumstances.

Note
Java will not be able to garbage-collect images that have been monitored by MediaTracker, because MediaTracker retains references to them unless the MediaTracker instance itself can be garbage-collected. If you load and then delete images, make sure to set all references to the MediaTracker you used to NULL if you want Java to free up the space used by the images.


No comments:

Post a Comment