JavaData & JavaHow to Use Images in Java

How to Use Images in Java

Images1

abstract boolean

drawImage(Image img, int x, int y, ImageObserver observer)

Draws as much of the specified image as is currently available.

abstract boolean

drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)

Draws as much of the specified image as has already been scaled to fit inside the specified rectangle.

abstract boolean

drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)

Draws as much of the specified image as has already been scaled to fit inside the specified rectangle.

abstract boolean

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)

Draws as much of the specified area of the specified image as is currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.

abstract boolean

drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)

Draws as much of the specified area of the specified image as is currently available, scaling it on the fly to fit inside the specified area of the destination drawable surface.

** Extracted from Java API documentation

This method displays the images passed as a reference. Apart from the coordinates passed as a parameters, the method drawing an image is associated with the ImageObserver interface and Color class. The Color class encapsulates the colors in the RGB color space and an implicit alpha value that specifies the transparency. The ImageObserver interface receives notification as the image is being updated. This is particularly useful to show the progress of image update of a large image or while downloading image from a slow network connection.

BufferedImage vs VolatileImage

As per the Java API documentation and Chet’s VolatileImage Q&A, the concrete subclass BufferedImage uses an accessible data buffer and relies on the image manipulation techniques defined by the methods of java.awt.image.Raster and the color characterization methods of java.awt.image.ColorModel. BufferedImage objects are allocated in an area that is in full control of the application. VolatileImage objects, on the other hand, are created in the limited system resource area, such as VRAM. Such limited resource areas are not in control of the application. As a result, the objects may be garbage collected as a result of optimizing limited resources or due to a proactive call of the flush method. So, the use of the VolatileImages object is unreliable or should be used cautiously. However, when the question of rendering performance arises, VolatileImage has the leverage of hardware rendering, whereas BufferedImage has to remain satisfied with the software rendering performance.

Images that we’ll be using in the code below are as follows.

Name: starburst.jpg

Size: 350×200

Revised2
Figure 2: Starburst image

Name: blob.jpg

Size: 50×50

Images3
Figure 3: A blob

Fundamental Operations

As with working with any basic file, images are loaded from an external file stored in a digital medium or an URL from the network; then, an image is created and finally saved. The following code will show how to do it in a simple manner.

Images need to loaded or created in a GUI component. We’ll be using java.swing.JPanel as a container for our images. The paint method of this component can be overloaded to create the image. The paint method is automatically invoked to render the component on-screen. It takes a Graphics object as a parameter. This object reference is used to create the image.

Here, we’ll be loading two images superimposing one on other, write some text, and finally save the image as a jpg file onto the disk.

package org.mano.example3;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel {
   private static final long serialVersionUID = 1L;
   private BufferedImage image;

   public ImagePanel(BufferedImage image) {
      this.image = image;
   }

   public BufferedImage getImage() {
      return image;
   }

   public void paint(Graphics g) {
      g.drawImage(image, 0, 0, this);
   }

   public void loadOriginalImage(File file) {
      try {
         image = ImageIO.read(file);
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   public void createArtWork() {
      if (image == null)
         return;
      try {
         Graphics g = image.getGraphics();
         g.setColor(Color.red);
         g.drawString("Picture speaks thousand words", 50, 50);
         g.drawImage(ImageIO.read(new File("/home/mano/Pictures/
            cartoons/blob.jpg")), 120, 100, null);
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   public void convertToGrayscale() {
      if (image == null)
         return;
      for (int i = 0; i < image.getHeight(); i++) {
         for (int j = 0; j < image.getWidth(); j++) {
            Color imageColor = new Color(image.getRGB(j, i));
            int rgb = (int) (imageColor.getRed() * 0.299)
               + (int) (imageColor.getGreen() * 0.587)
               + (int) (imageColor.getBlue() * 0.114);
            Color newColor = new Color(rgb, rgb, rgb);
            image.setRGB(j, i, newColor.getRGB());
         }
      }
   }
}


package org.mano.example3;

import java.awt.*;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

public class ImageProcessing extends JFrame {
   private static final long serialVersionUID = 1L;
   private final JPanel buttonPanel;
   private ImagePanel imagePanel;

   private final JButton artButton;
   private final JButton gsButton;
   private final JButton loadButton;
   private final JButton saveButton;

   public ImageProcessing() {
      try {
         imagePanel = new ImagePanel(ImageIO.read(new File
            ("/home/mano/Pictures/cartoons/tangled.jpg")));
      } catch (IOException e) {
         e.printStackTrace();
      }
      buttonPanel = new JPanel();
      buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
      artButton = new JButton("Create Art");
      artButton.addActionListener(new ButtonHandler());
      gsButton = new JButton("Grascale");
      gsButton.addActionListener(new ButtonHandler());
      loadButton = new JButton("Load Image");
      loadButton.addActionListener(new ButtonHandler());
      saveButton = new JButton("Save");
      saveButton.addActionListener(new ButtonHandler());

      buttonPanel.add(artButton);
      buttonPanel.add(gsButton);
      buttonPanel.add(loadButton);
      buttonPanel.add(saveButton);

      getContentPane().add(imagePanel, BorderLayout.CENTER);
      getContentPane().add(buttonPanel, BorderLayout.NORTH);
   }

   private class ButtonHandler implements ActionListener {

      @Override
      public void actionPerformed(ActionEvent e) {
         if (e.getSource() == artButton) {
            imagePanel.createArtWork();
            imagePanel.repaint();
         } else if (e.getSource() == gsButton) {
            imagePanel.convertToGrayscale();
            imagePanel.repaint();
         } else if (e.getSource() == loadButton) 
            File file = null;
            JFileChooser fc = new JFileChooser("/home");
            FileNameExtensionFilter filter = new
               FileNameExtensionFilter("JPG, PNG & GIF Images",
                                       "jpg", "gif", "png");
            fc.setFileFilter(filter);
            int ret = fc.showOpenDialog(null);
            if (ret == JFileChooser.APPROVE_OPTION) {
               file = fc.getSelectedFile();
            }
            if (file != null) {
               imagePanel.loadOriginalImage(file);
               imagePanel.repaint();
            }
         } else if (e.getSource() == saveButton) {
            if (imagePanel.getImage() != null) {
               JFileChooser fc = new JFileChooser("/home");
               fc.setDialogTitle("Save file as JPG");
               int ret = fc.showSaveDialog(null);
               if (ret == JFileChooser.APPROVE_OPTION) {
                  File file = fc.getSelectedFile();
                  try {
                     ImageIO.write(imagePanel.getImage(), "jpg", file);
                  } catch (IOException e1) {
                     e1.printStackTrace();
                  }
               }
            }
         }
      }
   }

   public static void main(String[] args) {
      // start application
      ImageProcessing ip = new ImageProcessing();
      ip.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      ip.setSize(450, 300);
      ip.setVisible(true);
   }
}

Output

Revised4
Figure 4: Starburst image with control buttons and the blob

Conclusion

The imaging classes provided in this are article are just tip of the iceberg. The core API library has several other classes that can be used to have a better control over imaging process and support advanced imaging techniques. Some of the classes are described in package javax.imageio. Other classes such as MediaTracker which enables checking the status of arbitrary number of images in parallel, interfaces such as ImageProducer, ImageConsumer to work with image data, ImageFilter objects can be used to manipulate pixels in the images. In a nutshell, the core API library along with a third party library such as OpenCV can provide almost every need of an image processing programmer.

Latest Posts

Related Stories