Images

Peter Komisar ©  Conestoga College   latest version   5.8 /  2010


Computer Images


"A picture paints a thousand words".  

Images are an intrinsic part of the information processed
by computers whether located locally on a PC storage
device, or in the sense of a PC being an extension of the
larger domain known as the Internet.

Images as Programming Objects

Images in a Java sense are programming objects used
to retrieve, store, display and manipulate image files,
whether they are captured from the Internet, scanned
into a computer or obtained from stored files. 

HTML and the Internet have established wide spread
support for two common
image file types, the GIF and
JPEG file formats. Java also has supports these file

formats for processing images. Around JDK 1.3.x
support for PNG image files was added to Java.


The GIF file format

GIF is an abbreviation for Graphics Interchange Format.
This file format was
developed by CompuServe. It uses
8-bits to store the color information for
a single pixel
(picture element). GIF files use a ''lossless'' compression
system originally patented by Unisys based on
the LZW
or Lempel-Ziv-Welch algorithm.

GIF files are a low quality picture format which might have
been become less popular except they are well
suited for
creating simple drawings, like backgrounds, cartoon
images and simple diagrams that do
not require highly
granular color descriptions. Their small size make
them
economical to store in memory and to send over the
Internet. Also considering the small file size, the quality is
quite good due to the 'lossless' compression method that
is used.

// Apparently the LZW patent has now expired so GIF, & TIFF-LZW
// files now
should be free of royalty entanglement


The PNG Format

 Following is information found at the PNG web site.


The PNG Web Site

http://www.libpng.org/pub/png/pngintro.html

The Portable Network Graphics (PNG) format was created
in 1995 to provide a patent free replacement for the GIF
format and to some extent the more complex TIFF format. 

Unlike GIF, PNG offers support for transparency, ('alpha
channel') cross-platform control of image brightness, and
two-dimensional interlacing. Also, PNG generally compresses
better than GIF in almost every case.

// interlacing draws to screen in two fields, odd and even number fields.
// Whole image appears and subsequently is filled in with detail

PNG comes in two varieties. PNG-8 holds 8 bits of color
information (comparable to GIF), and PNG-24 based on
24 bits of color (comparable to JPEG).

PNG's compression is fully 'lossless'. Saving and restoring
will not degrade image quality, unlike standard JPEG (even
at its highest quality settings).

 
The JPEG File Format

The JPEG file format was created by the Joint Photographic
Experts
Group and is an accepted ISO / ITU standard. The
JPEG format ( pronounced
jay-peg ) supplies highly detailed
photographic quality. At the same time it provides a very high
compression capability. The format allows a controlled trade
off between photo quality and storage capacity where image
quality can be specified as a percentage.

At it's highest quality, JPEG files store color information at
24 bits per pixel which is a perfect impedance match for
Java which stores red, green, blue values in 24 bits, one byte
per color.

The JPEG file format uses mathematical algorithms called
'discrete cosine transforms' to provide
what is called ''lossy''
compression. Lossy compression gets it's name from the
fact
that information is lost when very high compression
ratios are used, in the order
of 100:1 or higher.

The actual JPEG compression algorithm is very complex, however
the following short explanation gives some idea of how the down
sizing is accomplished. 


Quote from the 'Video Compression Tutorial',
The Wave Report
http://www.wave-report.com/tutorials/VC.htm

"Discrete cosine transform is a 'lossy' compression algorithm that samples an image at regular intervals, analyzes the frequency components present in the sample, and discards those frequencies which do not affect the image as the human eye perceives it.  . . .

In the JPEG algorithm, the image is sampled in 8 by 8 pixel blocks, and each sample is transformed via DCT into component basis cosine functions. By comparing the coefficients of these functions to a set coefficient, the algorithm identifies frequencies in the samples that are undetectable to the human eye--frequencies that will not affect the image quality if missing. By setting these values to zero, the amount of data that needs to be stored to recreate the image is greatly reduced."


The format is very efficient, as relatively high compression ratios
of 10 or 20 to one will often not appear to show any visible loss of
information. 

The motion picture industry uses a variation of the JPEG file called
MPEG for
releasing motion pictures to digital video formats.

Review of ImageIcon

Before we proceed, we should note we already have one very
effective ways of showing images in Java, involving the Icon
interface and the ImageIcon class. The fact that the image is
serialized into the component may have some advantages if
the class needs to be sent over the wire perhaps as an applet.


ImageIcon Example

import javax.swing.*;
import java.awt.*;

class IconPix extends JFrame{
      ImageIcon icon;     
    
      IconPix(String s){
         super(s);
         icon =new ImageIcon("flower.jpg");
         JLabel label=new JLabel(icon);
         add(label);
         setSize(500,500);
         setVisible(true);
         }
 public static void main(String[] args){
        new IconPix("Flower");
        }
}


Aside from ImageIcon, the general story of images continues
as follows, and is based on working with images within the
graphics context.


Stream the Image Data In and Draw it to Screen

There are really only two things that need to be done to work with
images in a Java program. First, the image has to be brought into
the application. This entails streaming the bytes that describe the
image from the storage file and into the Java program.

Second, when inside the program, the byte collection will need to
be processed and represented as an object of the Image class.
The image object then can be drawn to screen via a call on the
'graphics context', usually from inside the paint( )  method.



The getImage( ) method


The first step, where a raw image is input into the Java program
is accomplished using one of many getImage( ) methods defined
by various classes in the Java hierarchy.

For instance, TexturePaint and ImageIcon define no-args versions
of getImage( ).
The abstract Toolkit class, AppletContext and Applet
all define getImage( )
methods that take a URL object. The Toolkit
class also defines a getImage( )
method. It takes a String object that
repres
ent an image file. Applet has a getImage( ) method that takes
a URL with a String object describing path.
 
// Check the Java Documentation Method Index

Various Classes Having getImage( ) Methods


Applet uses URLs to get images, partly because Uniform
Resource Locators are the standard way to locate files on
the Internet, but also to work around security restrictions posed
by the applet 'sandbox' which prohibits an applet from reading
system files without permission. 

A reminder, an applet by default has security access to the
machine from which it originates, so if an applet is created
and run on a client locally, the file system will be available for
it's use. 


Toolkit     // images in applications

The way computers render graphics to screen is a low-level
process that
will be done uniquely on each platform, whether
Windows or Linux on an IBM
machine or on a Mac running
one of the Apple operating systems.

Java takes an
object-oriented approach to tackle this problem
by describing an abstract Toolkit class. The abstract class is
then used as a base to return platform specific versions
of the
class so Java can render graphics on each of the different
platforms the program is running on.


Toolkit Interfaces the Java API to Platform Native Calls

The concrete
Toolkit implementation for each platform
communicates with their native platform's peer objects.

The Java
documentation describes the Toolkit interface
as being the 'glue' that joins the platform
independent
Java classes to the native classes that are represented
in the java.awt.peer
package.

// the java.awt.peer package contains interface definitions
 
As we have seen, we can get a handle to the concrete
Toolkit
implementation via Toolkit's static method
getDefaultToolkit( ) .

// getDefaultToolkit( ) returns the native windowing toolkit

The following code shows Toolkit's getImage( ) method
being used.The image used was located on the web at
a print sales shop. The image has been located inside an
HTML page at www.sentex.net/~pkomisar/Cezanne.html
so you can access it and save it to the local directory that
you are running this code in.

Newer JDK Note

Recently the fillRect( ) call has been added to code samples
as newer JDKs have transparent backgrounds.  Note the
following is a regular Java application working from the
command line and not an applet.


Code Sample

import java.awt.*;
import javax.swing.*;

// portrait class gets and draws an image

public class Portrait extends JFrame {
       Image i;
            Portrait( String s ){
               super(s);
               Toolkit tools=Toolkit.getDefaultToolkit( );
                i=tools.getImage("cezanne.jpg");
                setBackground(Color.darkGray);
               setSize(800,400);
               setVisible(true);
               }
        // overridden paint method draws image
        public void paint(Graphics g){
          g.fillRect(0,0,getWidth( ),getHeight( ) );
          g.drawImage( i, 85, 70, this);
          }

 static public void main(String a[]) {
    new Portrait("  Apples and Oranges               - by Cezanne" );
   }

  } 


Often the getImage( ) and getDefaultToolkit( ) methods
are used in a single step as in the following example.

Example     

i = Toolkit.getDefaultToolkit( ).getImage("cezanne.jpg");



Using getImage( ) in Applets


Images are loaded into applets by referencing Uniform
Resource Locators or URLs. In their default form, applets
are restricted from reading and writing to the local file
system for security purposes.

On the other hand, applets are free, as are browsers, to
access images on the Internet so Applet's getImage( )
methods are defined as taking URL objects.

If your applet has the SecurityManager class' permission
to read and write to the local file system you can use
the
Applet class getImage( ) method to read that file locally
but as a rule this is not allowed.

// Applets are limited from importing images via URL on the college
// machines To work around, find image and save it to the local directory.
// As of 2010 this security limitation is being applied on this home machine
// as well. 


Following are the getImage methods defined in Applet.


Applet's getImage( ) methods

Image  getImage(URL url)                          
// takes a url and returns an Image object


Image  getImage(URL url, String name)
 
// takes a url to a directory where name is located

 

The URL class

The Uniform Resource Locator or URL is one of the
component parts of the HTTP protocol that
is used by
the World Wide Web. Java encapsulates the URL for it's
own use in the
Java class, URL located in the java.net
package.

Importing the .net Package

import java.net.*;


Applets are able to load URLs, both from the
String literals
describing the URL and from a URL object representing
a web URL address.

Following are examples of URL objects being created
passing in standard URLs as String
literals.

Example

URL u1 = new URL("http://www.mars.com/inhabitants/marsians.jpg");

Example   

URL u2 = new URL("file:///c:/jupiter/moon/europa/"ocean.jpg");


The following examples show the two forms of the Applet's
getImage( ) method being
used. The first takes a single
URL. The second takes a URL to a base directory where
an image file is located and referenced by the second
String argument to the method.


Example 1
 
Image j = getImage("http://Venus/Clouds.jpg");

// A URL described inside a string

Example 2

Image k = getImage("http://Venus/ ", "Clouds.jpg");

// a URL representing a path to a directory, and a file name

 

An Old Caution Regarding Using Applets with Images

The Java textbook, 'Just Java'  point out that there is a potential
weakness in rendering images in applets.
This has something
to do with how calls are made on the
native system that requires
the component to be 'realized' before the image is painted.

The suggestion to avoid problems boils down to making
sure the Image reference is declared in class scope
before it is returned an image from either the getImage( )
or createImage( ) method. You can experiment with this
to see if the caution remains relevant.


Code Sample

//<applet code="PortraitApplet.class" width=300 height=300></applet>

import java.awt.*;
import java.applet.*;
import java.net.*;

public class PortraitApplet extends Applet {
   Image image;
       URL url;
            public void init( ){
               try{
                  url=new URL("http://www.sentex.net/~pkomisar/cezanne.jpg");
                } catch(MalformedURLException me){
                  System.out.println("URL not formed correctly");
                 }
                image=getImage(url);
               setBackground(Color.darkGray);

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

  }

// As of 2010 or earlier The above applet is being blocked for making
// the URL connection by Java's security manager, even on the home
// machine. The URL call does work in the context of an applet loaded
// to a web server as is shown in the link below.

The above applet is set in an HTML page and is may
be viewed at:
 
http://www.sentex.net/~pkomisar/Portrait.html

// worked off campus, Nov. 2009

Images as Resources

An alternate method, which is a 'recommended' way' of
loading
images is to treat image files as 'resources'. 

When loading resources, the class loader is more flexible,
checking more path locations than Applet's getImage( )

method does. Also resources are able to be extracted
from archive files such
as 'gif' and 'jar' files.

The class, Class in the java.lang package, provides
getResource( String )
which returns a URL object.
It also provides the getResourceAsStream( String )
method which returns
an InputStream.

The following code sample shows this formula which is
more convoluted than earlier examples. The class Class
getResource( ) method is used to derive a URL object.
This object in turn uses it's getContent( ) method which
returns an object which is cast to an ImageProducer type.
Toolkit's createImage( ) method is called using the
ImageProducer as a argument. The image returned by
this method is then drawn to screen.

(We talk more about the ImageProducer class later in
the note.)


Code Sample

/* Image objects are managed by ImageProducers */

//<applet code=ImageResource.class width="400" height="300" ></applet>

import java.net.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;

// import java.io for IOException!
// Why other examples just catch Exception


public class ImageResource extends JApplet {
      URL url;  
      ImageProducer producer;
      Image image;
            public ImageResource( ){
               Toolkit tools=Toolkit.getDefaultToolkit( );
               // will use Toolkit's createImage() method
               url = getClass( ).getResource("Cezanne.jpg");                                  
            try{
               producer = (ImageProducer)url.getContent( );
               }
            catch(IOException io){
               System.out.println("IOException");
               }

               image = tools.createImage(producer);       
        
               setBackground(Color.darkGray);
               }
      
        public void paint(Graphics g){
          g.drawImage( image, 85, 70, this);
          }
 
  }


Drawing Images


ImageObserver

A call to getImage( ) returns immediately after receiving
a reference to the image file.
This method returns when
it recognizes it has a handle on it's target image. It is not
yet ready for viewing and still needs to be streamed into
the program. Soon after, a thread is started to read the
image file as it downloads from over the
Internet. This
incoming image is an observable event.

The Component class (and all it's descendants) implement
the 'ImageObserver' interface to act as an
observer for this
type of event. This is convenient as any Component subclass,
that is all the non-menu AWT components and all the Swing
components can
act as an ImageObserver.

While for other listeners the hearing metaphor was used,
it was natural to call the listener for an image an 'observer',
borrowing nomenclature from the classic 'Observer' design
pattern. The use of this in the method
is a convenient way
to pass the image observer chores to 'this', the container.

Example 

g.drawImage(image2,15, 220, 400,180, this);
 

Drawing Images

Once an image has been brought into a Java program
one must go about drawing it. This is done with one of
Java's variations of the drawImage( ) method.

Other drawImage( ) Locations

Swing introduces a DebugGraphics class for debugging
graphics. This class has a number of drawImage( )
methods as does the new Graphics2D class.

// Swing has a DebugGraphics class

The four drawImage( ) methods we focus on here are the
overloaded versions of drawImage( ) found in the Graphics
class. The first takes an image, x and y coordinates and
an ImageObserver object that we described earlier.

The second method adds two int values that can be used
to scale the image provided to a predetermined size. This
version is handy for making a group of images the same
size.

The third version allows specifying a background color for
the image. This might be useful if there was a time delay
before the image was rendered. The final version permits
both scaling and setting the  background color. Following
are the signatures for the four variations of drawImage( ).

The Graphics class' four variations of drawImage( )

public boolean drawImage
(Image img, int x, int y, ImageObserver observer);

// image drawn to original size

public boolean drawImage
(Image img, int x, int y, int width, int height, ImageObserver obsvr);

// scales image to fit specified width and height

public boolean drawImage
(Image img, int x, int y, Color bgcolor, ImageObserver observer);

// sets background color and draws with, no scaling

public boolean drawImage
(Image img, int x, int y,int width, int height,Color bgcolor, ImageObserver observer);
// sets background color and scales image


The second code sample shows the variation a drawImage( )
variation being used.
 

Variation of the drawImage( ) method Code Sample

// <applet code=UrlEx.class height=400 width=500 ></applet>

 import java.awt.*;
 import java.applet.*;
 import java.net.*;

 public class UrlEx extends Applet {
  Image image,image2;
  URL u1;

 public void init( ){
  image2=getImage(getCodeBase( ),"OttawaR.gif");
  // put your own .gif into this line
 try{
  u1=new URL("http://mars.sgi.com/mgs/msss/camera/images/"
  + "3_10_99_global/moc2_86_msss_icon.jpg");     // Marsian Globes
   }catch(Exception e) {System.exit(0);}
   image=getImage(u1);
  }
 public void paint(Graphics g){
   g.drawImage(image,15,15,this);
   g.drawImage(image2,15,220,400,180,this);
 // Note this version scales the gif (See below)
   }
 } 

Graphics2D drawImage( ) Methods    // for reference


The drawImage( ) methods of Graphics2D class offer enhanced Image handling capabilities.

public abstract void drawImage
(BufferedImage img,
BufferedImageOp op, int x, int y)

// BufferedImage describes an Image with an accessible buffer
// of image data.


public abstract boolean drawImage
(Image img,
AffineTransform xform, ImageObserver obs)

// "The AffineTransform class represents a 2D affine transform that
// performs a linear mapping from 2D coordinates to other 2D

// coordinates that preserves the "straightness" and "parallelness"
// of lines." - Java Documentation



imageUpdate( )

Component also has an imageUpdate( ) method. This method
is called as information about a requested image becomes
available. The imageUpdate(  ) method has the following
signature. This method  schedules a call to paint when an image
has changed. This includes when more bits of the image come
available for painting.
 

imageUpdate( ) method signature

public boolean imageUpdate(Image img,
                           int infoflags,
                           int x,
                           int y,
                           int w,
                           int h)

// The infoflags argument is the bitwise inclusive OR of the flags;
//
WIDTH, HEIGTH, PROPERTIES, SOMEBITS,  FRAMEBITS, ALLBITS, ERROR, ABORT


David Greary in his book, 'Graphic Java', Volume 1, AWT',
shows how the imageUpdate( ) method can be overridden
to display an image only when it is fully loaded and ready
for display. It can also be overridden to display bits every time
imageUpdate( ) is called. This may be useful for very large
images. The latter form of the overridden method is shown
here.

Overriding imageUpdate( )

Following is the partial form of an imageUpdate method
found in David Greary's book, 'Graphic Java', Volume 1,
AWT'. It shows how the call to repaint( ) can change the
painting behavior of the method.  Whether an incremental
paint is performed or an 'all at once' paint is done, depends
on where you locate the call to repaint( ) early in the method,
or in the else clause.

Code Sample
// adapted from 'Graphic Java' Volume 1, AWT', Dave Greary

 public boolean imageUpdate
( Image image, int infoflags, int x, int y, int w, int h){
   repaint( );    
// repaint( ) located here results in every line painted to display

   if((flags & ALLBITS) ==0)
      return true;  // needs more updates
  else
      return false: // image is fully loaded , 
// repaint( )
// in else clause paints image when fully loaded

      }


In the alternate form where the image is painted only when
all the bits are available, the call to repaint happens in the
else clause.         

While ((flags & ALLBITS) == 0) The method returns true
indicating the image still needs to load. Only when the else
clause executes does 'false' get returned indicating the
image is complete and updates are no longer needed.
 

'incrementaldraw' & 'redrawrate'

The systems behavior for drawing images can also be
controlled by System properties which provide another
technique of effected the
action of imageUpdate( ).

incrementaldraw - If awt.image.incrementalDraw is not
defined or has a boolean value of true, an image will be
drawn incrementally. If the property has any other value,
the image is not be painted until completely loaded.

redrawrate If incrementaldraw is set to true, then the
redrawrate is interpreted as an integer to allow the
maximum redraw rate. The redraw rate specifies the a
minimum time between repaints. If the System property
is missing or cannot be interpreted as an integer, the
redraw rate defaults to once every 100ms.


MediaTracker

MediaTracker provides another method for controlling when
images are shown to screen. It has the enhanced ability of
tracking a set of images which makes it particularly useful
in the creation of animations.

To use MediaTracker, create an instance of the class, specify
the images to be tracked using addImage( ), Inside a 'try catch'
block, call waitForID( ). The default behavior of this class is to
wait for the image to be fully available for screening before the
program continues to execute. ( An overloaded version of
waitForID( ), waitForID(int id, long ms), takes an id and a long
value that limits the time the program waits until it begins to
display the image.


MediaTracker Class Constructor

MediaTracker (Component comp)

// Creates a media tracker to track images for a given component.
// The Component argument is where the image(s) will be drawn.


Example From P.Linden's Just Java, Example page 575

public void init( ) {
   MediaTracker t=new MediaTracker(this); 
   Image i = getImage( getDocumentBase( ) , "spots.gif" ); 
    t.addImage( i , 1 );
   try{ t.waitForID(1); }
   catch(InterruptedException ie) {return;}
   // image is now in memory ready to draw
  }


The following page shows MediaTracker being used to control
the display of a number of Hubble telescope images in an
animation.

http://www.sentex.net/~pkomisar/Hubble/Hubble_Slide_Code.html



Creating & Manipulating Images


Java can also create images from scratch or manipulate the
bits of an image to provide different renderings of an image.
One of the key methods we will see used in this context is
createImage( ).

createImage( )

There are also several versions of the createImage( ) method
in the Component and Toolkit class. These can take an array,
a part of an array, an ImageProducer object or just a blank with
width and height values that is used for double buffering. There
are also versions that takes either a String or a URL object that
represents a file that contains a set of pixels. The following
example is from code we look at the end of the note.

Example  

Image img = createImage
                      (new MemoryImageSource(w, h, pix, 0, w));

// MemoryImageSource is an implementation of the ImageProducer interface


PixelGrabber  
// implements the ImageConsumer interface

PixelGrabber does what it says and takes the pixels of an image
and stores them in array form. PixelGrabber class implements
the ImageConsumer interface. The constructors
of PixelGrabber
may be passed an Image object or an ImageProducer object.

A PixelGrabber object can be built on all or part of the image
object it is passed.
The grabPixel( ) method instigates streaming
the pixels of the image into an array
which has been passed as
an argument to the PixelGrabber constructor.

 

PixelGrabber Constructors

where    img -        is the image to retrieve pixels from
             x & y -     are the upper left hand corner coordinates
             w & h -    are the width and height of the rectangle of pixels to retrieve
             pix  -        is the array of integers used to hold the RGB values
             off -          is the offset into the array of where to store the first pixel
             scansize - is the number of pixels associated with each array row

 


Bitwise Manipulation of Pixel Values

An int can be right shifted to isolate the transparency value or the
red, green and
blue component. For instance the red value is stored
in the upper 3rd byte. Right
shifting 16 locations moves these bits to
the bottom byte of an int.

Logically 'ANDING' with 256 which is all ones in the lowest bytes
and zeros above causes any values
in the upper 3 bytes being
'filtered away'. 0xff is 256 in hexadecimal representation.
The
following example shows the steps that occur at the binary level.

Example 

       10000001  11100111  10000001 10000001  >> 16

       // After  right shifting 16 bits  the binary becomes

         00000000  00000000  10000001 11100111 & 0xff

 // Then logically 'anding' with 256 gets rid of all but the lowest byte

       00000000  00000000  00000000 11111111

         00000000  00000000  00000000 11100111

         //  The red value isolated and stored in an int

The following method is an example from the Java
documentation that shows
the process of isolating the
alpha, red, green and blue values of a color stored
in
an int.

Example   

public void handlesinglepixel(int x, int y, int pixel) {
                  int alpha = (pixel >> 24) & 0xff;
                  int red   = (pixel >> 16) & 0xff;
                  int green = (pixel >>  8) & 0xff;
                  int blue  = (pixel      ) & 0xff;
                  // Deal with the pixel as necessary...
                 }

Following is another example from the Java Development
Kit documentation.
The getStatus( ) method is used in
combination with the ImageObserver.ABORT
constant to
check if the images were grabbed without error.

Method Example

public void handlepixels(Image img, int x, int y, int w, int h)
{
   int[] pixels = new int[w * h];  
   // yields the required number of pixels for image
   PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
 try
   {
   pg.grabPixels( );
   }
 catch(InterruptedException e)
   {
   System.err.println("interrupted waiting for pixels!");
   return;
   }
 if ((pg.getStatus( ) & ImageObserver.ABORT) != 0)
   {
   System.err.println("image fetch aborted or errored");
   return;
   }
   for (int j = 0; j < h; j++)
     {
      for (int i = 0; i < w; i++)
        {
        handlesinglepixel(x+i, y+j, pixels[j * w + i]);
        }
     }
}


Steps Summarizing the use of PixelGrabber
 

1) Instantiate PixelGrabber using an Image object (or an
ImageProducer), width & height dimensions, and an int
array as arguments.

Example          

PixelGrabber pg = new PixelGrabber( lots of arguments );

2) Call grabPixel( ) to fill the int array with pixels from the
image.

Example             

pg.grabPixels( );


3) Check the status to see if bits were grabbed successfully
.
    if (pg.status( ) & ImageObserver.ALLBITS) !=0)

// all bits grabbed successfully
    

Sample Code Showing PixelGrabber

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.applet.*;

//<applet code=PixT.class width=635 height=510></applet>
// need a Van Gogh image
public class PixT extends Applet{
Image Vince, Vince2;
int width, height;

public void init(){
  setBackground(Color.black);
  Vince=getImage(getDocumentBase( ),"FourSunFlowers.jpg");
   width=750;
   height=443;

  try{
  Vince2=filteredImage(Vince);
  }
  catch(InterruptedException ie){ }

repaint();
  }

/* filter method takes the image apart modifies the
   individual pixel values then puts it back together */

public Image filteredImage(Image image)throws InterruptedException{
     int[ ] pixels=new int[width*height];
     PixelGrabber pg=new PixelGrabber(image,0,0,width,height,pixels,0,width);
     int i=0;
 if (pg.grabPixels( )  && (  ( pg.status( ) & ImageObserver.ALLBITS) !=0 )  ){

    for(int y=0;y<height;y++)  {
      for(int x=0;x<width;x++){
         i=y*width+x;

         int a=    (pixels[i] & 0xff000000) >> 24;
         int red=  (pixels[i] & 0x00ff0000) >> 16;
         int green=(pixels[i] & 0x0000ff00) >>  8;
         int blue= (pixels[i] & 0x000000ff);

         // the red,green and blue values are averaged to get a gray equivalent
         // which passed back in for the red green and blue values.

         int average=(red+green+blue)/3;
         red=average;
         green=average;
         blue=average;
         pixels[i]= (a<<24) | (red<<16) | (green<<8) | blue ;
         }
      }
    }
     image=createImage(new MemoryImageSource(width,height,pixels,0,width));
     return image;
     }

public void paint(Graphics g){
    g.drawImage(Vince,20,20,375,222,this);
    g.drawImage(Vince2,240,270,375,222,this);
    g.setColor(Color.white);
    g.drawString( "'Four Cut Sunflowers' by Van Gogh",10,300);
    g.setColor(Color.gray);
    g.drawString( "-image from www.vangoghgallery.com",10,315);
    }
 }



MemoryImageSource


MemoryImageSource serves the reverse function of
PixelGrabber, reading an array
of pixels and returning
an image. An instance of MemoryImageSource is
created.
MemoryImageSource is a concrete extension
of the abstract ImageProducer class.
An instance of
MemoryImageSource may be supplied to Component's
createImage( )
method which returns an Image object.

The least complex of six constructors of the class
MemoryImageSource is shown below.

Simplest MemoryImageSource Constructor

public MemoryImageSource(int w, int h, int pix[], int off, int scan)

// other constructors use Hashtables and ColorModels

The following source code shows pixels being created
based on the manipulation of int values. An array of
these values is passed into the MemoryImageSource
constructor to create an image that can be viewed from
inside an applet. The following source code is from an
example supplied in the JDK documentation.
 

MemoryImageSource Code Sample

//<applet code="Pixels.class" width=200 height=150></applet>

import java.awt.image.*;
import java.applet.*;
import java.awt.*;

public class Pixels extends Applet{
 Image img;
public void init( ){
  int w = 100;
  int h = 100;
  int pix[] = new int[w * h];
  int index = 0;
  for (int y = 0; y < h; y++) {
    int red = (y * 255) / (h - 1);
    for (int x = 0; x < w; x++) {
        int blue = (x * 255) / (w - 1);
        pix[index++] = (255 << 24) | (red << 16) | blue;
        }
     }
   img = createImage(new MemoryImageSource(w, h, pix, 0, w));
   }
public void paint(Graphics g){
   g.drawImage(img,10,10,this);
   }
 }

Before you go too far inventing different types of image
filters, you should know that the Java library has many
classes like CropImageFilter and RGBImageFilter already
built for your use. You can investigate these should you
need them.


Saving Images to Image File Format 
// just for reference

It came up in class that we were missing a piece. How do
we save images to image files. Without investigating this
a great deal, and I am sure there are other approaches to
this, it appears that Java readily supplies a way to write an
image as represented in a 'BufferedImage' object to file via
the ImageIO class.

Example

 try
          {
           ImageIO.write(bufferedImage, "png", file);
          }
          //
          catch (IOException ex)
          {
          ex.printStackTrace();
          }

The getWriterFormatNames( )  Method

The getWriterFormatNames( )  method of the ImageIO
class will return strings that represent different file format
types as shown in the following example.

Example

import javax.imageio.*;

class FileNames{
  public static void main(String[]args){
     String[] names=ImageIO.getWriterFormatNames();
     for(int i=0;i<names.length;i++){
System.out.println(names[i]);
     }
  }
}

OUTPUT

>java FileNames
BMP
bmp
jpg
JPG
wbmp
jpeg
png
PNG
JPEG
WBMP
GIF
gif


Writing to File Via BufferedImage

In order write the image created in the above 'Pixels' code to
file, one
approach would have been to draw the image directly
to a BufferImage object.

In our
case though we used MemoryImageSource to create
an Image object. Fortunately we can draw our image to a
BufferedImage object.

The draw method of the Graphics2D class is used here. It 

involves using the AffineTransform class.  We can use the
no-args constructor for the AffineTransform class
which
represents the Identity transformation. 

// Matrix math's equivalent of multiplying by one

The following code shows this, writing the image created earlier
to a file
called numbersgraphic.png. The code extends Component
to provide an
Observer object for the draw methods.

Example

import java.awt.image.*;
import java.applet.*;
import java.awt.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.awt.geom.AffineTransform;


public class ImageToFile extends Component{

 Image img;
 Toolkit toolkit;
 ImageToFile()
  {
    int w = 100;
    int h = 100;
    int pix[] = new int[w * h];
    int index = 0;

  for (int y = 0; y < h; y++)
    {
      int red = (y * 255) / (h - 1);
    for (int x = 0; x < w; x++)
        {
          int blue = (x * 255) / (w - 1);
          pix[index++] = (255 << 24) | (red << 16) | blue;
        }
    }
     toolkit = Toolkit.getDefaultToolkit();
   
   img = toolkit.createImage(new MemoryImageSource(w, h, pix, 0, w));

   // write image to BufferedImage
 
        File file =new File("numbergraphic.png");
        BufferedImage bufferedImage =
        new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D buffG2D = (Graphics2D)bufferedImage.createGraphics( ); 
        buffG2D.drawImage(img,new AffineTransform( ),this);
       
        try
          {
           ImageIO.write(bufferedImage, "png", file);
          }   

          catch (IOException ex)
          {
          ex.printStackTrace();
          }

    }
 
public static void main(String[] args){
  new ImageToFile();
  System.out.println("DIR for file: numbergraphic.png");
  } 
}



Self Test                                  Self Test With Answers


1) Regarding the GIF file format which of the following statements is not correct?

a) GIF is an abbreviation for Graphics Interchange Format.
b) This file format was developed by CompuServe.
c) It uses 8-bits to store the color information for each color component of a pixel
d) GIF files use a compression system based of the Lempel-Ziv-Welch algorithm


2) Which of the following statements is not correct?

a) A Toolkit object can be obtained via a getDefaultToolkit( ) call.
b) TexturePaint and ImageIcon define versions of getImage( ).
c) The awt package URL class encapsulates a standard url in java.
d) getImage( ) returns an Image object.        


3) The drawImage( ) method does not take one of the following number or parameters?
a) 3
b) 4
c) 5
d) 6                                                          


4) Which of the following methods is typically called in response to a change
    in an image.

a) getImage( )
b) drawImage( )
c) updateImage( )
d) createImage( )                                        


5) To isolate the green component of a color stored in an int one would do a

a) right shift 8 places and logically and with the binary equivalent of the number 256
b) right shift 16 places and logically and the binary equivalent of then number 256
c) right shift 8 places and logically OR with the binary equivalent of the number 256
d) right shift 16 places and logically OR with the binary equivalent of then number 256

                                                                      

6) To create an image from an array of pixels and show the image which of
     the following would not be useful?

a) a MemoryPixelSource constructor
b) the createImage( ) method
c) an int array
d) the drawImage( ) method                          



Exercise


1) Create an applet that shows two JPG files that you captured from
    the  Internet.

2) Recreate the applet built in Q1. Use PixelGrabber to set the pixels
    to an array and filter down the green component by a half. Use
    MemoryImageSource to recreate an image based on the modified
    array and set the modified image to another location on the applet.

3) Use a purely mathematical technique to produce a shaded pattern.
    Set the array you build to an image and display it in a third applet.

    // You can model this code on the MemoryImageSource sample