import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
class ImgMod3 extends Frame implements MouseListener {
String msg = "";
int mX = 0;
int mY = 0;
Image rawImg;
int imgCols;//Number of horizontal pixels
int imgRows;//Number of rows of pixels
Image modImg;//Reference to modified image
//Inset values for the Frame
int inTop;
int inLeft;
//To add only one picture at a time
int ig = 1;
//This program will be executed to process the
// if the name of another program is not
// entered on the command line.
static String theProcessingClass = "PrintMouse";
// This image file will be processed if another file name is
// not entered on the command line.
static String theImgFile = "white.gif";
MediaTracker tracker;
Display display = new Display();//A Canvas
Button replotButton = new Button("Replot");
//References to arrays that store pixel data.
int[][][] threeDPix;
int[][][] threeDPixMod;
int[] oneDPix;
//Reference to the image-processing object.
ImgIntfc02 imageProcessingObject;
//-------------------------------------------//
public static void main(String[] args){
// Program supports gif files and jpg files
// and possibly some other file types as well.
if(args.length == 0){
//Use default processing class and default image file. No code required here.
// Class and file names were specified above.
}else if(args.length == 1){
theProcessingClass = args[0];
//Use default image file
}else if(args.length == 2){
theProcessingClass = args[0];
theImgFile = args[1];
}else{
System.out.println("Invalid args");
System.exit(1);
}//end else
//Display name of processing program and
// image file.
System.out.println("Processing program: " + theProcessingClass);
System.out.println("Image file: " + theImgFile);
//Instantiate an object of this class
ImgMod3 obj = new ImgMod3();
}//end main
//-------------------------------------------//
public ImgMod3(){//constructor
//Get an image from the specified file. Can
// be in a different directory if the path
// was entered with the file name on the command line.
rawImg = Toolkit.getDefaultToolkit().getImage(theImgFile);
//Use a MediaTracker object to block until
// the image is loaded or ten seconds has elapsed.
tracker = new MediaTracker(this);
tracker.addImage(rawImg,1);
try{
if(!tracker.waitForID(1,10000)){
System.out.println("Load error.");
System.exit(1);
}//end if
}catch(InterruptedException e){
e.printStackTrace();
System.exit(1);
}//end catch
//Make certain that the file was successfully
// loaded.
if((tracker.statusAll(false) & MediaTracker.ERRORED & MediaTracker.ABORTED) != 0){
System.out.println("Load errored or aborted");
System.exit(1);
}//end if
//Raw image has been loaded. Get width and
// height of the raw image.
imgCols = rawImg.getWidth(this);
imgRows = rawImg.getHeight(this);
this.setTitle("Copyright 2004, Baldwin");
this.setBackground(Color.YELLOW);
this.add(display);
this.add(replotButton,BorderLayout.SOUTH);
//Make it possible to get insets and the
// height of the button.
setVisible(true);
//Get and store inset data for the Frame and
// the height of the button.
inTop = this.getInsets().top;
inLeft = this.getInsets().left;
int buttonHeight = replotButton.getSize().height;
//Size the frame so that a small amount of
// yellow background will show on the right
// and on the bottom when both images are
// displayed, one above the other. Also, the
// placement of the images on the Canvas
// causes a small amount of background to
// show between the images.
this.setSize(inLeft+imgCols + 1,inTop + buttonHeight + imgRows + 7);
addMouseListener(this);
//=========================================//
//Anonymous inner class listener for replot
// button. This actionPerformed method is
// invoked when the user clicks the Replot
// button. It is also invoked at startup
// when this program posts an ActionEvent to
// the system event queue attributing the
// event to the Replot button.
replotButton.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
//Pass a 3D array of pixel data to the
// processing object and get a modified 3D array of pixel data back.
threeDPixMod = imageProcessingObject.processImg(threeDPix,imgRows,imgCols);
//Convert the modified pixel data to a
// 1D array of pixel data.
oneDPix = convertToOneDim(threeDPixMod,imgCols,imgRows);
//Use the createImage() method to
// create a new image from the 1D array of pixel data.
modImg = createImage(new MemoryImageSource(imgCols,imgRows,oneDPix,0,imgCols));
//Repaint the image display frame with
// the original image at the top and
// the modified pixel data at the bottom.
display.repaint();
}//end actionPerformed
}//end ActionListener
);//end addActionListener
//End anonymous inner class.
//=========================================//
//Create a 1D array object to receive the
// pixel representation of the image
oneDPix = new int[imgCols * imgRows];
//Convert the rawImg to numeric pixel
// representation. Note that grapPixels()
// throws InterruptedException
try{
//Instantiate a PixelGrabber object
// specifying oneDPix as the array in which
// to put the numeric pixel data.
PixelGrabber pgObj = new PixelGrabber(rawImg,0,0,imgCols,imgRows, oneDPix,0,imgCols);
//Invoke the grabPixels() method on the
// PixelGrabber object to extract the pixel
// data from the image into an array of
// numeric pixel data stored in oneDPix.
if(pgObj.grabPixels() && ((pgObj.getStatus() & ImageObserver.ALLBITS)!= 0)){
//Convert the pixel byte data in the 1D
// array to int data in a 3D array to
// make it easier to work with the pixel
// data later. Recall that pixel data is
// unsigned byte data and Java does not
// support unsigned arithmetic.
threeDPix = convertToThreeDim(oneDPix,imgCols,imgRows);
//Instantiate a new object of the image
// processing class. Note that this
// object is instantiated using the
// newInstance method of the class named
// Class. This approach does not support
// the use of a parameterized
// constructor.
try{
imageProcessingObject = (ImgIntfc02)Class.forName(theProcessingClass).newInstance();
//Post counterfeit ActionEvent to the
// system event queue and attribute it
// to the Replot button. Posting this event causes
// the image-processing method to be
// invoked, passing the 3D array of pixel data to the method, and receiving a 3D array of modified
// pixel data back from the method.
Toolkit.getDefaultToolkit().
getSystemEventQueue().postEvent(new ActionEvent(replotButton, ActionEvent.ACTION_PERFORMED, "Replot"));
//At this point, the modified image
// have been displayed.
}catch(Exception e){
System.out.println(e);
}//end catch
}//end if statement on grabPixels
else System.out.println("Pixel grab not successful");
}catch(InterruptedException e){
e.printStackTrace();
}//end catch
//Cause the composite of the frame, the
// canvas, and the button to become visible.
this.setVisible(true);
//=========================================//
//Anonymous inner class listener to terminate
// program.
this.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);//terminate the program
}//end windowClosing()
}//end WindowAdapter
);//end addWindowListener
//=========================================//
}//end constructor
//===========================================//
public void mouseClicked(MouseEvent me) {
mX = 0;
mY = 10;
msg = "Mouse clicked";
//repaint();
System.out.println("mY = " + mY);
}
public void mouseEntered(MouseEvent me) {
mX = 0;
mY = 10;
msg = "Mouse entered";
repaint();
}
public void mouseExited(MouseEvent me) {
mX = 0;
mY = 10;
msg = "Mouse exited";
repaint();
}
public void mousePressed(MouseEvent me) {
mX = me.getX();
mY = me.getY();
msg = "Down";
repaint();
}
public void mouseReleased(MouseEvent me) {
mX = me.getX();
mY = me.getY();
msg = "Up";
repaint();
}
public void paint(Graphics g) {
g.drawString(msg + " " + mX + " " + mY, mX, mY);
}
///Inner class for canvas object on which to
// display the two images.
class Display extends Canvas
{
//Override the paint method to display both
// the rawImg and the modImg on the same
// Canvas object, separated by one row of
// pixels in the background color.
public void paint(Graphics g)
{
//First confirm that the image has been
// completely loaded and neither image
// reference is null.
if (tracker.statusID(1, false) == MediaTracker.COMPLETE)
{
if ((rawImg != null) && ig==1)
{
g.drawImage(rawImg, 0, 0, this);
ig = 2;
//g.drawImage(modImg, 0, imgRows + 1, this);
}//end if
else if((modImg!=null) && ig==2)
{
g.drawImage(modImg, 0, 0, this);
}
}//end if
}//end paint()
}//end class myCanvas
//=============================================//
//Save pixel values as type int to make
// arithmetic easier later.
//The purpose of this method is to convert the
// data in the int oneDPix array into a 3D
// array of ints.
int[][][] convertToThreeDim(
int[] oneDPix,int imgCols,int imgRows){
//Create the new 3D array to be populated
// with color data.
int[][][] data = new int[imgRows][imgCols][4];
for(int row = 0;row < imgRows;row++){
//Extract a row of pixel data into a
// temporary array of ints
int[] aRow = new int[imgCols];
for(int col = 0; col < imgCols;col++){
int element = row * imgCols + col;
aRow[col] = oneDPix[element];
}//end for loop on col
//Move the data into the 3D array. Note
// the use of bitwise AND and bitwise right
// shift operations to mask all but the
// correct set of eight bits.
for(int col = 0;col < imgCols;col++){
//Alpha data
data[row][col][0] = (aRow[col] >> 24) & 0xFF;
//Red data
data[row][col][1] = (aRow[col] >> 16) & 0xFF;
//Green data
data[row][col][2] = (aRow[col] >> 8) & 0xFF;
//Blue data
data[row][col][3] = (aRow[col]) & 0xFF;
}//end for loop on col
}//end for loop on row
return data;
}//end convertToThreeDim
//-------------------------------------------//
//The purpose of this method is to convert the
// data in the 3D array of ints back into the
// 1d array of type int. This is the reverse
// of the method named convertToThreeDim.
int[] convertToOneDim(int[][][] data,int imgCols,int imgRows){
//Create the 1D array of type int to be
// populated with pixel data, one int value
// per pixel, with four color and alpha bytes
// per int value.
int[] oneDPix = new int[imgCols * imgRows * 4];
//Move the data into the 1D array. Note the
// use of the bitwise OR operator and the
// bitwise left-shift operators to put the
// four 8-bit bytes into each int.
for(int row = 0,cnt = 0;row < imgRows;row++){
for(int col = 0;col < imgCols;col++){
oneDPix[cnt] = ((data[row][col][0] << 24) & 0xFF000000) | ((data[row][col][1] << 16)
& 0x00FF0000) | ((data[row][col][2] << 8) & 0x0000FF00)
| ((data[row][col][3]) & 0x000000FF);
cnt++;
}//end for loop on col
}//end for loop on row
return oneDPix;
}//end convertToOneDim
}//end ImgMod3.java class
//=============================================//