Image Processing Basics 1

           Java Image processing basically involves Java awt packages i.e  Abstract Window Toolkit. Hence make sure you have awt jar files before you begin this tutorial.

         Firstly i will cover the basic example of how to render an image. I am going to use Eclipse IDE. You are free to use any IDE. Make sure Java path is set in environment variables.

      We will brush up some important concepts  before starting actual code. 10 important things to look up are listed below. Just go through once to get some idea. If you didn't understand completely  don't worry as we will learn each of them separately in future examples.
1) java.awt.Frame  :-

                A Frame is a top-level window with a title and a border.The size of the frame includes any area designated for the border. The dimensions of the border area may be obtained using the getInsets method, however, since these dimensions are platform-dependent, a valid insets value cannot be obtained until the frame is made displayable by either calling pack or show. Since the border area is included in the overall size of the frame, the border effectively obscures a portion of the frame, constraining the area available for rendering and/or displaying subcomponents to the rectangle which has an upper-left corner location of (insets.left, insets.top), and has a size of width - (insets.left + insets.right) by height - (insets.top + insets.bottom).

Frames are capable of generating the following types of WindowEvents:
  • WINDOW_OPENED
  • WINDOW_CLOSING
  • WINDOW_CLOSED
  • WINDOW_ICONIFIED
  • WINDOW_DEICONIFIED
  • WINDOW_ACTIVATED
  • WINDOW_DEACTIVATED
  • WINDOW_GAINED_FOCUS
  • WINDOW_LOST_FOCUS
  • WINDOW_STATE_CHANGED
2) java.awt.image :-

The abstract class Image is the superclass of all classes that represent graphical images. The image must be obtained in a platform-specific manner. 

3) java.awt.toolkit :-



This class is the abstract superclass of all actual implementations of the Abstract Window Toolkit. Subclasses of Toolkit are used to bind the various components to particular native toolkit implementations.
Many GUI operations may be performed asynchronously. This means that if you set the state of a component, and then immediately query the state, the returned value may not yet reflect the requested change. This includes, but is not limited to:
  • Scrolling to a specified position.
  • Moving the focus from one component to another.
  • Making a top-level container visible.
  • Setting the size or location of a top-level container.
Most applications should not call any of the methods in this class directly. The methods defined by Toolkit are the "glue" that joins the platform-independent classes in the java.awt package with their counterparts in java.awt.peer. Some methods defined by Toolkit query the native operating system directly.

4) Java.awt.event.WindowEvent :-

A low-level event that indicates that a window has changed its status. This low-level event is generated by a Window object when it is opened, closed, activated, deactivated, iconified, or deiconified, or when focus is transfered into or out of the Window.
The event is passed to every WindowListener or WindowAdapter object which registered to receive such events using the window's addWindowListener method.  Each such listener object gets this WindowEvent when the event occurs.

5) java.awt.Toolkit.getDefaultToolkit() :-

Gets the default toolkit.
If a system property named "java.awt.headless" is set to true then the headless implementation of Toolkit is used. If there is no "java.awt.headless" or it is set to false and there is a system property named "awt.toolkit", that property is treated as the name of a class that is a subclass of Toolkit; otherwise the default platform-specific implementation of Toolkit is used. Also loads additional classes into the VM, using the property 'assistive_technologies' specified in the Sun reference implementation by a line in the 'accessibility.properties' file. The form is "assistive_technologies=..." where the "..." is a comma-separated list of assistive technology classes to load. Each class is loaded in the order given and a single instance of each is created using Class.forName(class).newInstance(). This is done just after the AWT toolkit is created. All errors are handled via an AWTError exception.
                                                                    
6)   getImage(String filename) :-

Returns an image which gets pixel data from the specified file, whose format can be either GIF, JPEG or PNG. The underlying toolkit attempts to resolve multiple requests with the same filename to the same returned Image. Since the mechanism required to facilitate this sharing of Image objects may continue to hold onto images that are no longer in use for an indefinite period of time, developers are encouraged to implement their own caching of images by using the createImage  variant wherever available. If the image data contained in the specified file changes, the Image object returned from this method may still contain stale information which was loaded from the file after a prior call. Previously loaded image data can be manually discarded by calling the flush method on the returned image. This method first checks if there is a security manager installed. If so, the method calls the security manager's chekRead method with the file specified to ensure that the access to the image is allowed.

7) paint(Graphics g) :-

Paints the container. This forwards the paint to any lightweight components that are children of this container. If this method is reimplemented, super.paint(g) should be called so that lightweight components are properly rendered. If a child component is entirely clipped by the current clipping setting in g, paint() will not be forwarded to that child.

8) java.wat.Graphics :-




The Graphics class is the abstract base class for all graphics contexts that allow an application to draw onto components that are realized on various devices, as well as onto off-screen images. 
A Graphics object encapsulates state information needed for the basic rendering operations that Java supports. This state information includes the following properties: 


  • The Component object on which to draw.
  • A translation origin for rendering and clipping coordinates.
  • The current clip.
  • The current color.
  • The current font.
  • The current logical pixel operation function (XOR or Paint).
  • The current XOR alternation color 
9) java.awt.MediaTracker :-


The MediaTracker class is a utility class to track the status of a number of media objects. Media objects could include audio clips as well as images, though currently only images are supported.
To use a media tracker, create an instance of MediaTracker and call its addImage method for each image to be tracked. In addition, each image can be assigned a unique identifier. This identifier controls the priority order in which the images are fetched. It can also be used to identify unique subsets of the images that can be waited on independently. Images with a lower ID are loaded in preference to those with a higher ID number.
Tracking an animated image might not always be useful due to the multi-part nature of animated image loading and painting, but it is supported. MediaTracker treats an animated image as completely loaded when the first frame is completely loaded. At that point, the MediaTracker signals any waiters that the image is completely loaded. If no ImageObservers are observing the image when the first frame has finished loading, the image might flush itself to conserve resources 

10) drawImage() :-

Draws as much of the specified image as has already been scaled to fit inside the specified rectangle.The image is drawn inside the specified rectangle of this graphics context's coordinate space, and is scaled if necessary. Transparent pixels do not affect whatever pixels are already there.This method returns immediately in all cases, even if the entire image has not yet been scaled, dithered, and converted for the current output device. If the current output representation is not yet complete, then drawImage returns false. As more of the image becomes available, the process that loads the image notifies the image observer by calling its imageUpdate method.A scaled version of an image will not necessarily be available immediately just because an unscaled version of the image has been constructed for this output device. Each size of the image may be cached separately and generated from the original data in a separate image production sequence.

Now lets see one example where an image is rendered. It does nothing other than accepting an image input and displaying. 

LoadImage Interface :-



import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public interface LoadImage {

public void loadImage();
 
}




Actual Class :- 

import java.awt.*;
import java.awt.event.*;

class ImageProcess extends Frame implements LoadImage {
private static final long serialVersionUID = 1L;
Image image;

public static void main(String[] args) {
ImageProcess img = new ImageProcess();
img.loadImage();
}
public void loadImage() {
image = Toolkit.getDefaultToolkit().getImage("c:\\Sunset.jpg");

this.setVisible(true);

this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}

public void paint(Graphics g) {
System.out.println("Processing...");
g.translate(this.getInsets().left, this.getInsets().top);

MediaTracker tracker = new MediaTracker(this);
tracker.addImage(image, 1, 100, 100);
try {
tracker.waitForID(1, 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
g.drawImage(image, 120, 30, image.getWidth(this), image.getHeight(this), this);
}

}

Now lets see some key aspects of this program.

1) Inside loadImeage() method setVisible is set to true because by default it is false and the image gets hidden. So make sure you set this as true otherwise you wont be able to see any image.

2) WindowListener Events are present because once the image is displayed, you need to close the window for exit. If this event listener is not present you wont be able to close the windoe. Actually you can experiment it.

3) Normally paint is the inbuilt method that is called innumerable times in the program. Whenever there is a small change ,the paint method is called. We don't need to call this method as this is done internally. Println will show you how many times it is called. Remember whenever there is a small change in dimension of image, paint is called. In fact paint is called to render the image first time also. 
But here since MediaTracker is used paint() is called only once. MediaTracker internally implements threads which waits for other threads to finish job.
Now you might have a question of how it calls paint automatically? Answer is ImageObserver interface. I have explained that to you at the end of this post.

4) Use of translate method is to Translates the origin of the graphics context to the point (xy) in the current coordinate system. Modifies this graphics context so that its new origin corresponds to the point (xy) in this graphics context's original coordinate system. All coordinates used in subsequent rendering operations on this graphics context will be relative to this new origin.
public abstract void translate(int x, int y)

Parameters:
x - the x coordinate.
y - the y coordinate                                                                                                               

5) public Insets getInsets() :-

Determines the insets of this container, which indicate the size of the container's border. A Frame object, for example, has a top inset that corresponds to the height of the frame's title bar.

g.translate(this.getInsets().left, this.getInsets().top);

6) addImage :- 
Adds a scaled image to the list of images being tracked by this media tracker. The image will eventually be rendered at the indicated width and height.

public void addImage(Image image,
int id,
int w,
int h)

addImage parameter has one important thing i.e ID. This ID is associated with image. Whenever you will refer tracker and image use this ID. Following code will help you to understand better.

tracker.waitForID(1, 1000);


public boolean waitForID(int id,
long ms)

Starts loading all images tracked by this media tracker with the specified 
identifier. This method waits until all the images with the specified identifier 
have finished loading, or until the length of time specified in milliseconds by 
the ms argument has passed. If there is an error while loading or scaling an image, then that image is 
considered to have finished loading. Use the statusID, 
isErrorID, and isErrorAny methods to check for errors.

7) And lastly dont forget to draw the image 

g.drawImage(image, 120, 30, image.getWidth(this), image.getHeight(this), this);

ImageObserver interface is the last argument in drawImage() method. When an object implements it, call to drawImage starts a new thread automatically which loads requested image. It looks after the process  of image loading. This thread notifies ImageObserver whenever new data arrives or any modifications take place.When we are writing paint actually we are overriding  some component class paint() method. Hence we can use this safely.

8) Compile and run the program. I have added how the output looks. Enjoy.

The real funny part is when you resize image you will understand how many times paint() method is being called.Resize it using mouse and observe the console where processing... is gets printed.

Any questions or clarifications or feedbacks are warmly welcomed.

Thank You

Output Screen :-



Comments

Post a Comment

Popular posts from this blog

Mini Project for Image Processing Beginners

Program to convert image byte array to PDF

Program to convert base64 to Image and vice versa