Advertisement

PLAYING WITH IMAGES USING JAVA

 

Java provides a powerful imaging API which can be leveraged for image manipulation operations requiring automation. The imaging API in Java is powerful enough to load most of the popular image formats, grab each pixel from the image and set the value of each pixel as we wish. This article describes the ways of performing the most common image manipulation operations like blur, sharpen, transparency, flip, rotate and scale. This can help in applying automated changes to multiple images at one go.

INTRODUCTION
Manipulating images is usually relegated to highly professional software packages like Adobe Photoshop, GNU Image Manipulating Program and Corel Draw. Java provides programmers with an easy API which can handle images of almost all encoding formats.

Images are encoded into several formats like JPG or JPEG (Joint Photographic Experts Group), PNG (Portable Network Graphics), GIF (Graphics Interchange Format), TIFF (Tagged Image File Format), DIB (Device Independent Bitmap), BMP (Bitmap) and WBMP (Wireless Bitmap). All image formats (except those using bitmap) compress images using a zipping algorithm to reduce the file size. Java can load, edit and save most of the image formats mentioned above.

With the availability of javax.imageio.ImageIO class, reading and writing images can be done at the cost of a single line of code. Learning to carry out image manipulation operations like blur, sharpen, transparency, flip, rotate and scaling is a good investment of time, since a massive set of images can be processed in batches from Java programs.

Java provides methods for creating images in memory and setting each pixel of the image as we wish. The class java.awt.image.BufferedImage is a handy one for working with images. This article explains the procedure to handle images using Java and introduces some easy image manipulation operations.

COLOUR AND TRANSPARENCY SYSTEMS
An image is composed of small dots called pixels. Each pixel can store information on the colour and transparency to be displayed at that particular point. Transparency (allowing background to be seen) or opacity (block vision through the layer) is determined by a constant value called alpha and its value ranges from 0 to 255. Alpha value of 0 means that the pixel is completely transparent and 255 means that the pixel completely blocks vision through its layer.

Colour is usually specified in any one of the following systems: i) Red, Green and Blue (RGB) system, ii) Hue-Saturation-Brightness (HSB) system or iii) Cyan-Magenta-Yellow-Black (CMYK) system. In most of the cases, it is easier to work with the RGB system, since we know the basics fairly well. The first two systems are used for generating display on screen, while the third system is used for printing on paper.

Each pixel has a colour which combines the red, green and blue values. Each of one of the three colours can take a value from 0 to 255. A value of 0 means the colour component is absent and a value of 255 means it is fully present. All colours can be produced as a combination of the three basic colours in different levels.

Usually, it is better to deal with colour using the ARGB (Alpha, Red, Green and Blue) system. Each pixel of the image has got an integer (4 bytes) allotted for colour values. The integer value is divided into four bytes to store the values of blue (0 to 7 bits), green (8 to 15 bits), red (16 to 23 bits) and alpha (24 to 31 bits). Fig.1.a shows the pictorial representation of colour values within a bit and Fig.1.b shows a sample bit pattern for storing alpha=120, red=85, green=200 and blue=170.




EXTRACTING INDIVIDUAL COLOUR VALUES FROM PIXEL
Extracting component values from the pixel and assembling individual colour values into a complete colour value back on a pixel are performed using bit manipulations. Individual bits of a number can be moved to left or moved to right using the left shif (<<) or right shift (>>) operators. Bit values can be checked and set using AND (&), OR (|) or XOR (^) operations.

In the present case, we use a right shift followed by AND operation to extract individual colour components. For extracting blue, simply perform AND operation using 0xFF (255 in decimal notation). For extracting green colour, perform right shift operation by 8 bits and AND operation using 0xFF. For red component, right shift by 16 bits and perform AND operation using 0xFF. For alpha component, right shift by 24 and perform AND using 0xFF. If the pixel value is available in a variable called pix, the extraction operations are shown by the following piece of code.

blue = pix & 0xFF;
green = (pix>>8) & 0xFF;
red = (pix>>16) & 0xFF;
alpha = (pix>>24) & 0xFF;

Similarly, setting colour values requires shifting the colour components to the left side and performing OR operation on pixel value initialized to zero. Following code shows the procedure for setting four component values into the pixel value.

pix = 0;
pix = pix | blue;
pix = pix | (green <<8);
pix = pix | (red <<16);
pix = pix | (alpha <<24);

Knowing how to handle colour values paves the way for performing the usual image manipulation operations.

IMAGE MANIPULATION PROCEDURES
The procedures for performing blur, sharpen, grey, transparency, flip, rotate and scale operations are presented in this section. 

Blur
In blur operation, the colour value of each pixel is set to the average colour value of the surrounding pixels. Surrounding pixels for interior pixel are 9, for pixel at left (or right) top (or bottom) corner are 4 and for pixels on boundary other than corner are 6. Figs.2a to 2c show the arrangement of surrounding pixels for taking average value.



Sharpen
Sharpening an image means that the light pixels should be made much lighter and bright pixels should be made brighter. This results in sharper difference in colour between two pixels. If the colour value is less than 128, each colour component should be divided by sharpness factor (usually greater than 1) to make it less intense. Otherwise, each colour component of the pixel should be multiplied by sharpness factor to make it brighter.

Grey Scale
Grey image are produced by making red, green and blue values equal for each pixel. The new grey pixel is obtained by adding the red, green and blue components of the pixel and dividing the sum by three. This average value is set into the red, green and blue components of the new pixel (three equal colour components result in grey images with tonal differences).

Flip
Flip is similar to taking mirror image of the object. Flip can be horizontal, where left and right pixels are interchanged or it can be vertical, where top and bottom pixels are interchanged. To get a horizontal flip, pixels in each row should be interchanged from left to right, i.e., pixel at location 0 goes to location width-1, at location 1 goes to width-2, etc. This creates a mirror image of the object.

Flipping in vertical direction is carried out by moving the top pixels to bottom and the bottom ones to top. This is carried out column-wise. Pixel 0 in the column goes to location height-1, pixel 1 in the column goes to location height-2 and vice versa. Hence, flipping is the interchange of pixels either along the row (horizontal flip) or along the column (vertical flip).

Transparency
Transparency for an image is controlled by the alpha value of each pixel in the image. Normally, alpha value is 255, which means the image is completely opaque (non-transparent). When the alpha value is zero, the image becomes 100% transparent and thus disappears. Alpha values ranging from 0 to 255 result in various levels of transparency for the image.

For setting a particular transparency value for the image, the alpha component of each pixel should be set to the desired value.

Rotate
Rotating an image is the operation by which pixels transfer themselves from one location to another location by a calculated distance. This requires calculation of the new location of each pixel based on angle of rotation. The exact formulation for rotation is a bit tedious and is not presented here (to save you from a handful of equations).

The simplest rotation is to turn the image by 90o. This can be accomplished by creating a new image with width of original image as height and height of original image as width. The pixels should be read row-wise from the original image and set column-wise on the new image. After completing this operation, the new image is a rotated version of the original image.

Scale
Scaling is the enlargement or reduction of the size of the image. It results in loss of precision and loss of quality of the image. But, the java.awt.Image class provides a convenient method called getScalledInstance which returns a scaled version of image.

IMAGE MANIPULATION API

The packages java.awt.image and javax.imageio provide the basic functionality required for loading images from disk, working with individual pixels and then saving the image on the disk. The methods often used for image operations are shown in Table 1.

Table 1 Common Toolkit for Image Manipulation

Sl. No.

Name of Class

Method

Purpose

1.

javax.imageio.ImageIO

read(File f)

read(InputStream is)

read(URL u)

Reads an image from either a disk file, input stream or URL (network). It returns an instance of java.awt.image.BufferedImage.

2.

javax.imageio.ImageIO

write(RenderedImage img, String format, File target)

write(RenderedImage img, String format, ImageOutputStream target)

write(RenderedImage img, String format, OutputStream target)

Writes an image to the specified File or OutputStream (which may be a disk file or network connection).

3.

Java.awt.image.PixelGrabber

grabPixels()

Grabs individual pixels from an image. The pixels are stored in one dimensional array.

4.

Java.awt.image.Image

getScaledInstance(int width, int height, int algorithm)

Returns scaled version of an image, using appropriate scale factor.

5.

Java.awt.image.BufferedImage

getRGB(int row, int column)

Returns the specified pixel denoted by the row and column numbers.

6.

Java.awt.image.BufferedImage

setRGB(int row, int column, int pixel)

Sets the pixel value at given row and column location.

7.

java.awt.image.BufferedImage

setSubimage(int x, int y, int width, int height)

Returns the portion of image contained within the boundaries specified by the four arguments of the method. Return types is also a BufferedImage.

PixelGrabber class provides three constructors. All of them take either an Image or an ImageProducer as first argument. The next four arguments are the starting x value, starting y value, width of grab and height of grab. The fifth argument is a Boolean (true or false – strict RGB or not) for one constructor and one dimensional integer array of required length (width x height) for other two constructors. The sixth argument is an integer specifying start point within the one dimensional array (offset). The last argument is the scan size, which is the distance between two successive pixels on the same column. In other words, it is the width of image meant for grabbing. The grabbed pixel array should be accessed by multiplying the row number using total width of image and adding the column number to the value.

The method getScaledInstance takes width and height of the scaled image as the first two arguments and a choice of scaling algorithm as the third argument. Scaling can be accomplished using several algorithms, each having a specific advantage. The algorithm for scaling can be chosen using predefined constant values (SCALE_AREA_AVERAGING, SCALE_DEFAULT, SCALE_FAST, SCALE_REPLICATE and SCALE_SMOOTH) defined in the java.awt.Image class.

Now that we know about pixel, colour storage format and manipulation of images, it is time to provide a Java implementation of the same.

IMPLEMENTATION OF IMAGE MANIPULATIONS
Image manipulation procedures mentioned above are implemented in a Java program named ImageManipulation.java. All the methods are static methods to enable direct access without instantiation.

//ImageManipulation.java
1. import java.awt.image.*;
2. import java.awt.*;
3. import javax.imageio.*;
4. import java.io.*;
5. import java.util.*;
6. 
7. public class ImageManipulation
8. {
9. public static BufferedImage blurImage(BufferedImage bi) {
10. int w = bi.getWidth(), h = bi.getHeight(), alpha = 0, red, green, blue, newPix;
11. int pix[] = null;
12. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
13. for(int i=0,j=0; i<w; i++) {
14. for(j=0; j<h; j++) {
15. pix = getSurroundingPixels(bi, i>0?i-1:0,i<w-1?i+1:w-1,j>0?j-1:0,j<h-1?j+1:h-1);
16. red = green = blue = 0;
17. for(int k=0; k<pix.length; k++) {
18. red += (pix[k]>>16) & 0xFF;
19. green += (pix[k]>>8) & 0xFF;
20. blue += (pix[k]) & 0xFF;
21. }
22. alpha = (bi.getRGB(i,j)>>24) & 0xFF;
23. red /= pix.length;
24. green /= pix.length;
25. blue /= pix.length;
26. newPix = ((alpha<<24) | (red<<16) | (green<<8) | blue);
27. newImage.setRGB(i,j, newPix);
28. }
29. }
30. return newImage;
31. }
32. public static BufferedImage sharpenImage(BufferedImage bi, double fact) {
33. int w = bi.getWidth(), h = bi.getHeight(), alpha = 0, red, green, blue, newPix;
34. int pix = 0;
35. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
36. for(int i=0,j=0; i<w; i++) {
37. for(j=0; j<h; j++) {
38. pix = bi.getRGB(i, j);
39. alpha = (pix>>24) & 0xFF;
40. red = (pix>>16) & 0xFF;
41. green = (pix>>8) & 0xFF;
42. blue = pix & 0xFF;
43. red = (int)(red<128 ? red/fact:red*fact>255?255:red*fact);
44. green =(int)(green<128 ? green/fact:green*fact>255?255:green*fact);
45. blue = (int)(blue<128 ? blue/fact:blue*fact>255?255:blue*fact);
46. newPix = ((alpha<<24) | (red<<16) | (green<<8) | blue);
47. newImage.setRGB(i,j, newPix);
48. }
49. }
50. return newImage;
51. }
52. public static BufferedImage grayImage(BufferedImage bi) {
53. int w = bi.getWidth(), h = bi.getHeight(), alpha = 0, red, green, blue, newPix;
54. int pix = 0;
55. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
56. for(int i=0,j=0; i<w; i++) {
57. for(j=0; j<h; j++) {
58. pix = bi.getRGB(i, j);
59. alpha = (pix>>24) & 0xFF;
60. red = (pix>>16) & 0xFF;
61. green = (pix>>8) & 0xFF;
62. blue = pix & 0xFF;
63. red = green = blue = (red+green+blue)/3;
64. newPix = ((alpha<<24) | (red<<16) | (green<<8) | blue);
65. newImage.setRGB(i, j, newPix);
66. }
67. }
68. return newImage;
69. }
70. public static BufferedImage transparentImage(BufferedImage bi, int trans) {
71. int w = bi.getWidth(), h = bi.getHeight(), red, green, blue, newPix;
72. int pix = 0;
73. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
74. for(int i=0,j=0; i<w; i++) {
75. for(j=0; j<h; j++) {
76. pix = bi.getRGB(i, j);
77. red = (pix>>16) & 0xFF;
78. green = (pix>>8) & 0xFF;
79. blue = pix & 0xFF;
80. newPix = ((trans<<24) | (red<<16) | (green<<8) | blue);
81. newImage.setRGB(i, j, newPix);
82. }
83. }
84. return newImage;
85. }
86. public static BufferedImage invertImage(BufferedImage bi) {
87. int w = bi.getWidth(), h = bi.getHeight(), alpha = 0, red, green, blue, newPix;
88. int pix = 0;
89. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
90. for(int i=0,j=0; i<w; i++) {
91. for(j=0; j<h; j++) { 
92. pix = bi.getRGB(i, j);
93. alpha = (pix>>24) & 0xFF;
94. red = 255 - (pix>>16) & 0xFF;
95. green = 255 - (pix>>8) & 0xFF;
96. blue = 255 - pix & 0xFF; 
97. newPix = ((alpha<<24) | (red<<16) | (green<<8) | blue);
98. newImage.setRGB(i, j, newPix);
99. }
100. }
101. return newImage;
102. }
103. public static BufferedImage scaleImage(BufferedImage original, double f) {
104. try { 
105. Image img = original.getScaledInstance((int)(original.getWidth()*f),
106. (int)(original.getHeight()*f), original.SCALE_DEFAULT);
107. int w = img.getWidth(null), h = img.getHeight(null);
108. int pix[] = new int[w*h];
109. PixelGrabber pg = new PixelGrabber(img,0,0,w,h,pix,0,w);
110. pg.grabPixels();
111. BufferedImage rendered = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
112. for(int i=0; i<w; i++)
113. for(int j=0;j<h;j++)
114. rendered.setRGB(i,j,pix[i+j*w]);
115. return rendered;
116. }
117. catch(Exception ex) {ex.printStackTrace();}
118. return null;
119. }
120. public static BufferedImage flipHorizontal(BufferedImage bi) {
121. int w = bi.getWidth(), h = bi.getHeight();
122. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
123. for(int i=0,j=0; i<w; i++)
124. for(j=0; j<h; j++)
125. newImage.setRGB(w-i-1, j, bi.getRGB(i, j));
126. return newImage;
127. }
128. public static BufferedImage flipVertical(BufferedImage bi) {
129. int w = bi.getWidth(), h = bi.getHeight();
130. BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
131. for(int i=0,j=0; i<w; i++)
132. for(j=0; j<h; j++)
133. newImage.setRGB(i, h-j-1, bi.getRGB(i, j));
134. return newImage;
135. }
136. public static BufferedImage rotate(BufferedImage bi) {
137. int w = bi.getWidth(), h = bi.getHeight();
138. BufferedImage newImage = new BufferedImage(h, w, BufferedImage.TYPE_INT_ARGB);
139. for(int i=0,j=0; i<w; i++)
140. for(j=0; j<h; j++)
141. newImage.setRGB(j, i, bi.getRGB(i, j));
142. return newImage;
143. }
144. private static int[] getSurroundingPixels(BufferedImage bi, int startx, int endx, int starty, int endy) {
145. int pix[] = new int[(endx+1-startx)*(endy+1-starty)];
146. for(int i=startx, index=0; i<=endx; i++)
147. for(int j=starty; j<= endy; j++)
148. pix[index++] = bi.getRGB(i,j);
149. return pix;
150. }
151. }


The method named blurImage creates a new image and each pixel of the new image as the average of the surrounding pixels of the original image. The colour extraction and setting techniques used in the method have already been introduced.

The method named sharpenImage creates a new image and sets the colour value of each new pixel richer if it is already rich (greater than or equal to 128) and poorer if it is already poor (less than 128). A sharpness factor (whose value is greater than 1) is used for multiplication or division of the existing pixel colour component to get the sharper colour component. 

The method greyImage creates a new image of the same size as the original image. Gray images are produced when red, green and blue components of a pixel are all equal. Hence, each pixel of the new image is set to average of red, blue and green values of the original image, without altering the alpha values.

The method transparentImage creates a copy of the image using same colour components for each pixel, but with specified alpha (transparency) component, which varies from 0 to 255. An image with alpha value of 0 is 100% transparent while another with alpha value of 255 is 100% opaque (blocking light) – intermediate values result in partial transparency for the image.

The method invertImage creates a new image and sets colour component of each pixel as the complement (after subtracting from 255) of the original colour component. i.e., a pixel having RGB values of 200-120-85 will result in a new pixel having RGB values of 55-135-170. It is the photo- negative of the original image.

The method scaleImage (returning java.awt.image.BufferedImage) is a front end to getScaledInstance (returning java.awt.Image) of java.awt.Image class. The job of scaleImage is to get scaled instance of java.awt.Image type from getScaledInstance, grab the pixels using java.awt.image.PixelGrabber and set the pixel values into the new BufferedImage instance.

Horizontal flipping operation is carried out by transposing the extreme left pixel as the extreme right pixel, second pixel as the last but one pixel etc. This results in left-right interchange of pixels of the image. The method flipHorizontal takes care of these operations.

Vertical flipping is carried out by transposing the top most pixel as the bottom most pixel, second pixel of the column as last but one pixel of the flipped image etc. This results in top-bottom interchange of pixels of the image. The method flipVertical takes care of these operations.

Rotation of image is carried out using a pretty rudimentary algorithm, which turns the image by 90o. It is accomplished by creating a new image with width of the original image as height and height of the original image as width. The pixels of the new image are matrix transpose of the original image. The pixel at row 2, column 5 on the original image would be placed at row 5 and column 2 on the rotated image. Arbitrary rotation takes more effort and is not presented here.

TESTING IMAGE MANIPULATIONS
The methods defined within ImageManipulation.java are ready for testing. A program called ImageTester.java is created to provide a front end for the image manipulation routines we created in the previous section. The code creates two JLabels, one for displaying original image and the other for displaying modified version of the image. Buttons are arranged on top of the window for loading source image, saving modified image, blur, sharpen, gray, invert, transparent, flip horizontal, flip vertical, rotate and scaling of the original image. The button with double less than (<<) sends the modified image to the left side, thus making it the target for further modifications. The source code is shown below:

//ImageTester.java
1. import javax.swing.*;
2. import javax.imageio.*;
3. import java.awt.event.*;
4. import java.awt.*;
5. import java.awt.image.*;
6. 
7. class ImageTester extends JFrame implements ActionListener
8. {
9. BufferedImage original = null, rendered = null;
10. JFileChooser fc = new JFileChooser();
11. JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
12. JLabel originalLabel = new JLabel(), renderedLabel = new JLabel();
13. 
14. public ImageTester() {
15. super("Image Tester");
16. createToolBar();
17. sp.setContinuousLayout(true);
18. sp.setOneTouchExpandable(true);
19. sp.setLeftComponent(new JScrollPane(originalLabel));
20. sp.setRightComponent(new JScrollPane(renderedLabel));
21. this.getContentPane().add(sp, BorderLayout.CENTER);
22. 
23. javax.swing.filechooser.FileFilter ff = new javax.swing.filechooser.FileFilter(){
24. String ext[] = ImageIO.getReaderFileSuffixes();
25. public boolean accept(java.io.File f) {
26. String name = f.getName().toLowerCase();
27. if(f.isDirectory())
28. return true;
29. for(int i=0; i<ext.length; i++)
30. if(name.endsWith(ext[i].toLowerCase()))
31. return true;
32. return false;
33. }
34. public String getDescription() { 
35. StringBuilder sb = new StringBuilder("Image (");
36. for(int i=0;i<ext.length; i++)
37. sb.append("*."+ext[i]);
38. sb.append(")");
39. return sb.toString();
40. }
41. };
42. fc.setAcceptAllFileFilterUsed(false);
43. fc.setFileFilter(ff);
44. 
45. originalLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
46. renderedLabel.setAlignmentX(JLabel.LEFT_ALIGNMENT);
47. originalLabel.setAlignmentY(JLabel.TOP_ALIGNMENT);
48. renderedLabel.setAlignmentY(JLabel.TOP_ALIGNMENT);
49. 
50. this.setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());
51. this.setDefaultCloseOperation(EXIT_ON_CLOSE);
52. this.setVisible(true);
53. sp.setDividerLocation(0.5);
54. this.validate();
55. 
56. MouseSelection ms = new MouseSelection();
57. originalLabel.addMouseListener(ms);
58. originalLabel.addMouseMotionListener(ms); 
59. }
60. private void createToolBar() {
61. JToolBar tb = new JToolBar();
62. JButton b[] = {
63. new JButton("Open"),new JButton("Save"),
64. new JButton("Blur"), new JButton("Sharpen"),new JButton("Gray"),
65. new JButton("Invert"),new JButton("Transparent"),
66. new JButton("Flip Horizontal"),new JButton("Flip Vertical"),
67. new JButton("Rotate"), new JButton("Scale"), new JButton("<<")
68. };
69. for(int i=0; i<b.length; i++) {
70. b[i].addActionListener(this);
71. tb.add(b[i]);
72. if(i==1 || i==6) tb.add(new JSeparator());
73. }
74. this.getContentPane().add(tb, BorderLayout.NORTH);
75. }
76. public void actionPerformed(ActionEvent ae) {
77. String com = ae.getActionCommand();
78. if(com.equals("Open") && fc.showOpenDialog(this) == fc.APPROVE_OPTION) {
79. openFile(fc.getSelectedFile());
80. return;
81. }
82. else if(com.equals("Save") && fc.showSaveDialog(this) == fc.APPROVE_OPTION) {
83. saveFile(fc.getSelectedFile());
84. return;
85. }
86. else if(com.equals("Blur"))
87. rendered = ImageManipulation.blurImage(original);
88. else if(com.equals("Sharpen"))
89. rendered = ImageManipulation.sharpenImage(original, 
90. Double.parseDouble(JOptionPane.showInputDialog(this,"Enter sharpness factor","1.2")));
91. else if(com.equals("Gray"))
92. rendered = ImageManipulation.grayImage(original);
93. else if(com.equals("Invert"))
94. rendered = ImageManipulation.invertImage(original);
95. else if(com.equals("Transparent"))
96. rendered = ImageManipulation.transparentImage(original, 
97. Integer.parseInt(JOptionPane.showInputDialog(this,"Enter transparency (0..255)","255")));
98. else if(com.equals("Flip Horizontal"))
99. rendered = ImageManipulation.flipHorizontal(original);
100. else if(com.equals("Flip Vertical"))
101. rendered = ImageManipulation.flipVertical(original);
102. else if(com.equals("Rotate"))
103. rendered = ImageManipulation.rotate(original);
104. else if(com.equals("Scale")) {
105. double f = Double.parseDouble(JOptionPane.showInputDialog(this,"Enter scale factor","1"));
106. rendered = ImageManipulation.scaleImage(original, f);
107. }
108. else if(com.equals("<<")) {
109. original = rendered;
110. originalLabel.setIcon(new ImageIcon(original));
111. rendered = null;
112. }
113. renderedLabel.setIcon(new ImageIcon(rendered));
114. this.validate();
115. }
116. private void openFile(java.io.File f) {
117. try {
118. original = ImageIO.read(f);
119. originalLabel.setIcon(new ImageIcon(original));
120. }
121. catch(Exception ex) {ex.printStackTrace();}
122. }
123. private void saveFile(java.io.File f) {
124. try {
125. String ext = f.getName().toLowerCase();
126. ext = ext.substring(ext.lastIndexOf(".")+1).toUpperCase();
127. ImageIO.write(rendered, ext, f);
128. }
129. catch(Exception ex) {ex.printStackTrace();}
130. }
131. class MouseSelection extends MouseAdapter implements MouseMotionListener {
132. boolean active = false;
133. Point start = null, end = null;
134. public void mousePressed(MouseEvent me) { 
135. start = end = me.getPoint();
136. active = true;
137. }
138. public void mouseReleased(MouseEvent me) {
139. end = me.getPoint();
140. active = false;
141. int y = (originalLabel.getBounds().height-original.getHeight())/2;
142. start.y -= y;
143. end.y -= y;
144. rendered = original.getSubimage(start.x<=end.x?start.x:end.x, 
145. start.y<=end.y?start.y:end.y, (int)Math.abs(end.x-start.x), (int)Math.abs(end.y-start.y));
146. renderedLabel.setIcon(new ImageIcon(rendered));
147. originalLabel.repaint();
148. ImageTester.this.validate();
149. }
150. public void mouseDragged(MouseEvent me) {
151. end = me.getPoint();
152. if(active && start != null && end != null)
153. originalLabel.getGraphics().drawRect(start.x<=end.x?start.x:end.x, 
154. start.y<=end.y?start.y:end.y, (int)Math.abs(end.x-start.x), (int)Math.abs(end.y-start.y));
155. }
156. public void mouseMoved(MouseEvent me) { }
157. }
158. public static void main(String arg[]) {
159. try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
160. catch(Exception ex) {}
161. new ImageTester();
162. }
163. }


The program loads source image on left side and modified image on right side. Screenshots obtained from the test code are shown in Figs.3 to 16. The above code provides for mouse listener which can select a region of the original image and bring that selection to the right side.





HAPPY PLAY TIME
Since Java provides many sophisticated capabilities for processing images, it is easy for the programmer create a custom program for performing certain operations on a large set of images without human intervention. Since the bare-bones image processor demonstrated here could be improved to include complex selection techniques and processing capabilities, the possibilities for creating interactive programs is also unlimited. Happy play time with imaging API in Java!

About Author
V. Nagaradjane is a freelance programmer. He may be contacted at nagaradjanev@rediffmail.com.








Added on October 7, 2010 Comment

Comments

#1

Raman Kumar commented on October 7, 2010 at 7:30 p.m.

Nice article. It works perfectly. Good.

#2

Paul Alexander commented on October 8, 2010 at 9:05 p.m.

Your website looks like it is developed using Django. I need to develop my website in Django. Provide me contact details.

Thanks

#3

Ashok commented on October 11, 2010 at 2:57 p.m.

hellooooooooooooooooooooo

#4

Amrish Patudi commented on October 17, 2010 at 8:24 a.m.

Sir / Madam,

I am pursuing MCA - Sem 3rd in "Atmiya Institute of Technology & Science, Rajkot". I will like to contribute artice for your magazine. What is the procedure for that?

#5

Crystal Green commented on October 20, 2010 at 7:42 p.m.

My name is Crystal Green. I am from Canada. I would like to subscribe your magazine. Send me your subscription cost. This is my id. chrystal_green@hotmail.com

#6

Dean Aaron commented on April 22, 2014 at 10:04 a.m.

What a nice share!

Another java imaging project I appreciate:
http://www.rasteredge.com/java-imaging/

#7

Rajesh Patil commented on March 13, 2015 at 5:38 p.m.

How to make it work for tiff images

Post a comment