| In the discussion of BufferedImage 
              class, we noted that it offers much more access to and control of 
              the image data than the Image class. Internally the BufferedImage 
              consists of the ColorModel, 
               Raster, 
               DataBuffer, 
              and SampleModel 
              objects, which allow for a wide variety of image types and packing 
              arrangements for the pixel data.  However, for routine pixel handling tasks, you don't need to delve 
              into the details of these classes to work with images at the pixel 
              level. For example, you can easily create an image from a pixel 
              array packed with ARGB 
              pixel data as follows:  
               buffered_image 
                = new BufferedImage (width, height, bufferedImage.TYPE_INT_ARGB);
 buffered_image.setRGB (0, 0, width, height, pixels, 0, width);
  The constructor parameters specify the dimensions of the image 
              and the type of image. In setRGB() 
              the first four parameters specify the top left corner position and 
              the width and height of the area of the image to be filled by the 
              pixels array. The last two parameters give the offset into the pixel 
              array where the data begins and the scan size for a row of pixels 
              (usually just set to the image width).  Conversely, the ARGB pixel data for an image can be obtained via 
              
               int[] pixels 
                = buffered_image.getRGB (0, 0, width, height, array, 
                0, width);
  This method returns an array with the ARGB data for the area of 
              the image specified by the first four parameters. If not null, the 
              fifth parameter should be an int 
              array large enough to hold the pixel data. The next to last parameter 
              specifies the offset into the pixel array where the filling should 
              begin and the last parameter is again the scan size.  To deal with other types of images, a little more work must be 
              done. The following GrayBufImagePanel 
              class creates a byte array with values from 0 to 255 that represent 
              gray levels. A BufferedImage 
              of the TYPE_BYTE_GRAY 
              is created. To fill it with our byte array we need to get the raster 
              for the image and it must be a WritableRaster 
              type than allows us to modify the pixels.  This obtained is obtained with  
               WritableRaster 
                wr = fBufferedImage.getRaster ();
 Then the pixel data is set with.
  wr.setDataElements 
                (0, 0, fWidth, fHeight, fPixels); The program CreateBufferedGrayImageApplet 
              shown below displays an instance of the GrayBufImagePanel. 
              
  
              
                 
                  | CreateBufferedGrayImageApplet
 |   
                  |  import 
                      javax.swing.*;import java.awt.*;
 import java.awt.image.*;
 
 /** Display the DrawingPanel with BufferedImage on the applet.**/
 public class CreateBufferedGrayImageApplet extends 
                      JApplet
 {
 GrayBufImagePanel fBufImagePanel = null;
 public void init ()   {
 Container content_pane = getContentPane 
                      ();
 
 // Create an instance of BufImagePanel
 fBufImagePanel = new GrayBufImagePanel 
                      ();
 
 // Add the BufImagePanel to the 
                      contentPane.
 content_pane.add (fBufImagePanel);
 } // init
 
 // Invoke the init method in BufImagePanel to 
                      build the image.
 public void start () {
 fBufImagePanel.makeImage ();
 }
 } // class CreateBufferedGrayImageApplet
 
 /** Create an image from a pixel array using BufferedImage. 
                      **/
 class GrayBufImagePanel extends JPanel
 {
 BufferedImage fBufferedImage = null;
 int fWidth = 0, fHeight = 0;
 byte [] fPixels = null;
 
 /** Build a BufferedImage from a pixel array. 
                      **/
 void makeImage () {
 
 fWidth  = getSize ().width;
 fHeight = getSize ().height;
 fPixels = new byte [fWidth * fHeight];
 
 // Create an array of pixels with 
                      varying aRGB components
 int i=0;
 int half_width = fWidth/2;
 for  (int y = 0; y < fHeight; 
                      y++){
 for ( int x = 0; x < 
                      fWidth; x++){
 
 // Peak 
                      white in middle
 int gray 
                      = (255 * x)/half_width;
 if (x > 
                      half_width) gray = 510 - gray;
 fPixels[i++] 
                      = (byte) gray;
 }
 }
 // Create a BufferedIamge of the 
                      gray values in bytes.
 fBufferedImage =
 new BufferedImage (fWidth, 
                      fHeight, BufferedImage.TYPE_BYTE_GRAY);
 
 // Get the writable raster so that 
                      data can be changed.
 WritableRaster wr = fBufferedImage.getRaster();
 
 // Now write the byte data to the 
                      raster
 wr.setDataElements (0, 0, fWidth, 
                      fHeight, fPixels);
 }
 
 /** Draw the image on the panel. **/
 public void paintComponent (Graphics g) {
 super.paintComponent (g);
 if (fBufferedImage != null)
 g.drawImage (fBufferedImage, 
                      0, 0, this );
 } // makeImage
 
 } // class GrayBufImagePanel
 |  Animations with BufferedImage  In Chapter 11: 
              Java: Pixel Handling we showed how to create animations with 
              the Image 
              class directly from modifications to the pixel data with the aid 
              of the MemoryImageSource 
              class.With the BufferedImage 
              we can also create an animation by altering the pixel array for 
              each frame, invoking the setRGB() 
              method to reload the pixel data, and then invoking repaint(). 
             A more sophisticated approach, which more closely resembles the 
               MemoryImageSource 
              animation technique, is to build the BufferedImage 
              with a DataBufferInt 
              object that holds the pixels plus a RGB ColorModel 
              and a WritableRaster 
              that allows direct modification of the raster data. For each frame 
              of the animation, you modify the pixel array and then invoke repaint(). The program AnimationWritableRasterApplet 
              and the class DrawingPanelWR 
              shown below illustrate this approach. A BufferedImage 
              object is created with a WritableRaster 
              and made big enough to cover the panel. A loop in a thread modifies 
              the pixel data and when the image is repainted, it will use the 
              new pixels.   
              
                 
                  | AnimationWriteableRasterApplet
 |   
                  |  import 
                      javax.swing.*;import java.awt.*;
 import java.awt.image.*;
 
 /**
 * Demonstrate animation of a BufferedImage object 
                      by direct
 * modification of its pixel data.
 **/
 public class AnimationWritableRasterApplet extends 
                      JApplet
 implements Runnable
 {
 // Will use thread reference as a flag
 Thread fThread;
 //msecs of sleep time between frames
 int fDeltaT = 10;
 // Need a reference to the panel for the thread 
                      loop.
 DrawingPanelWR fDrawingPanel;
 
 /**
 * Add an instance of the DrawingPanelWR 
                      on which
 * the animation will take place.
 **/
 public void init () {
 // Create an instance of DrawingPanel
 fDrawingPanel = new DrawingPanelWR 
                      ();
 
 // Add the DrawingPanel to the JApplet 
                      pane.
 add (fDrawingPanel);
 
 } // init
 
 /** Called by browser when web page and applet 
                      loaded. **/
 public void start () {
 // Tell the panel to create the 
                      image source.
 fDrawingPanel.init ();
 
 // If the thread reference not null 
                      then a
 // thread is already running. Otherwise, 
                      create
 // a thread and start it.
 if (fThread == null) {
 fThread 
                      = new Thread (this);
 fThread.start 
                      ();
 }
 }
 
 /**  Called by browser when web page 
                      and applet unloaded. **/
 public void stop () {
 // Setting thread to null will 
                      cause loop in
 // run () to finish and the process 
                      return from
 // run () thus killing the thread.
 fThread = null;
 } // stop
 
 public void run ()  {
 // Loop through sleep periods until
 // thread stopped by setting thread
 // reference to null.
 while (fThread != null) {
 try {
 Thread.sleep 
                      (fDeltaT);
 }
 catch (InterruptedException 
                      e)
 { }
 
 // Send request for 
                      create new image
 fDrawingPanel.newFrame 
                      ();
 
 // Repaint now that 
                      the pixel data has changed.
 repaint ();
 }
 } // run
 
 } // class AnimationWritableRasterApplet
 
 /** A JPanel subclass on which a BufferedImage animation 
                      will be
 * displayed. Use a WritableRaster to modify 
                      the pixel data.
 **/
 class DrawingPanelWR extends JPanel
 {
 BufferedImage fBufferedImage;
 int width, height;
 int [] fPixels;
 
 int frame=0;
 
 /**
 * Build a BufferedImage the size 
                      of the panel. Create
 * it with a WriteableRaster so that 
                      we can modify the
 * pixel data for each frame of an 
                      animation.
 **/
 void init ()  {
 width  = getSize ().width;
 height = getSize ().height;
 int numPixels = width * height;
 
 fPixels = new int [numPixels];
 
 // Create an integer data buffer 
                      to hold the pixel array
 DataBuffer data_buffer = new DataBufferInt 
                      (fPixels, numPixels);
 
 // Need bit masks for the color 
                      bands for the ARGB color model
 int [] band_masks = {0xFF0000, 0xFF00, 
                      0xff, 0xff000000};
 
 // Create a WritableRaster that 
                      will modify the image
 // when the pixels are modified.
 WritableRaster write_raster =
 Raster.createPackedRaster 
                      (data_buffer, width, height, width,
 band_masks, null);
 
 // Create a RGB color model
 ColorModel color_model = ColorModel.getRGBdefault 
                      ();
 
 // Finally, build the image from 
                      the
 fBufferedImage =
 new BufferedImage (color_model,write_raster,false,null);
 
 } // init
 
 
 /** Modify the pixels for each frame. **/
 void newFrame () {
 int index = 0;
 byte mask =  (byte)(frame 
                      & 0xff);
 int alpha = 255;
 
 for (int y = 0; y < height; y++){
 for (int 
                      x = 0; x < width; x++) {
 // 
                      Modify the color components each frame.
 int 
                      red =  (y * 255) / (width - 1);
 red 
                      = red & mask;
 
 int 
                      green =  (x * 255) / (height - 1);
 green 
                      = green & mask;
 
 int 
                      blue = 255 -  (255 * (x - width))/width;
 blue 
                      = blue & mask;
 
 fPixels[index++] 
                      =
 (alpha << 24) | (red << 16) | (green << 8) | blue;
 }
 }
 frame++;
 } // new Frame
 
 /** Just draw the image. **/
 public void paintComponent (Graphics g) {
 g.drawImage (fBufferedImage, 0, 
                      0, this);
 }
 
 } // class DrawingPanelWR
 |    
 References & Web Resources 
                Latest update: May 24, 2006 |