//import java.awt.*; import javax.swing.*; import java.awt.Image; import java.awt.Graphics; import java.awt.image.*; import java.awt.Dimension; import java.awt.MediaTracker; import java.util.*; import java.io.*; import java.net.*; import java.awt.event.*; import java.awt.BorderLayout; /** *
* Class for manipulating graphics images * originally developed in C++ * revision history for C++ version ** * @author Owen Astrachan * */ public class Pixmap extends JPanel implements ActionListener { /** * create a pixmap (by reading a local file), the pixmap is added * to a PixApp, and displayed in a frame * * @param app the Application to which this pixmap will be added * @param filename complete pathname of the local file that can * be read by getImage() */ public Pixmap(PixController control, String filename) { myName = filename; myControl = control; // start loading the image and wait until completed MediaTracker tracker = new MediaTracker(this); try { myImage = this.getToolkit().getImage( new URL("file:" + filename)); } catch (MalformedURLException e) { System.err.println("Bad URL!"); } tracker.addImage(myImage,0); // wait for image to load try { tracker.waitForID(0); } catch (InterruptedException e){ System.out.println("image loading interrupted"); return; } // initialize dimensions of pixmap myIcon = null; myRows = myImage.getHeight(this); myCols = myImage.getWidth(this); myD = new Dimension(myCols,myRows); setSize(myCols,myRows); // add to application and then display myControl.addPixmap(this); display(); } /** * redisplays this pixmap as the active pixmap * @param ev the action event causing the redisplay */ public void actionPerformed(ActionEvent ev) { myControl.setActiveMap(this); display(); } /** * @return the PixIcon associated with this Pixmap */ public PixIcon getIcon() { if (myIcon == null) { myIcon = new PixIcon(myImage,myName); myIcon.addActionListener(this); } return myIcon; } /** * overrides Component.getPreferredSize() */ public Dimension getPreferredSize() { return myD; } /** * overrides JComponent.paintComponent() */ public void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(myImage, 0, 0, this); } private void grabPixels() { // create room to store all the pixels,than grab // them from the image myPixels = new int[myRows * myCols]; PixelGrabber pg = new PixelGrabber(myImage, 0, 0, myCols, myRows, myPixels, 0, myCols); try { pg.grabPixels(); } catch (InterruptedException e) { System.out.println("pixel grab interrupted!"); return; } } private int getPixel(int row, int col) { return myPixels[row*myCols + col]; } private void setPixel(int row, int col, int pixValue) { myPixels[row*myCols + col] = pixValue; } private void resetImage() { myImage = this.createImage( new MemoryImageSource(myCols, myRows, myPixels, 0, myCols)); repaint(); } /** * reflect this vertically (which means through a * vertical line drawn through the middle of the * Pixmap) ---> | <--- * */ public void vertReflect() { grabPixels(); // loop over each row, reflecting left half to right int k; for(k=0; k < myRows; k++) { int j; int limit = myCols/2; for(j=0; j < limit; j++) { int temp = getPixel(k,j); setPixel(k,j,getPixel(k,myCols-j-1)); setPixel(k,myCols-j-1,temp); } } // reset the image tothe pixel array and repaint it resetImage(); } /** * reflect this horizontally (which means through a * horizontal line drawn through the middle of the Pixmap ** Modified: 3/21/94 * 11/29/94 * 4/13/95 *
* Ported: 10/16/1996 to Java (Syam Gadde) * re-implemented, ported to 1.1 6/1/97 (Owen Astrachan) *
* * this class represents an image that supports * manipulation, i.e., reflection, expansion, inversion, etc. * It has an analog in C++ for comparison between the two languages * although there is more support in Java for images than there is * in C++. *
* * Creating a pixmap requires a filename that should be a gif or jpg * image (or others if getImage() supports them). Currently the * filename represents a local image, but changing the URL to support * network retrievable images should be straightforward *
* |
* v
* ----
* ^
* |
*
*
*/
public void horizReflect()
{
grabPixels();
// loop over each column, reflecting top half to bottom
int k;
for(k=0; k < myCols; k++)
{
int j;
int limit = myRows/2; // stop swapping halfway
for(j=0; j < limit; j++)
{
int temp = getPixel(j,k);
setPixel(j,k,getPixel(myRows-j-1,k));
setPixel(myRows-j-1,k,temp);
}
}
// reset the image to the pixel array and repaint it
resetImage();
}
public void expand(int rowExpand,int colExpand)
{
int newRows = myRows * rowExpand;
int newCols = myCols * colExpand;
// create room to store all the pixels,than grab
// them from the image
myPixels = new int[newRows * newCols];
PixelGrabber pg = new PixelGrabber(myImage,
0, 0, myCols, myRows,
myPixels, 0, myCols);
try {
pg.grabPixels();
}
catch (InterruptedException e) {
System.out.println("Expand: pixel grab interrupted!");
return;
}
int k;
for(k=newRows-1; k >= 0; k--)
{
int j;
int oldRow = k/rowExpand;
for(j=newCols-1; j >= 0; j--)
{
myPixels[k*newCols+j] = myPixels[oldRow*myCols+(j/colExpand)] ;
}
}
// reset image to pixel array and repaint it
myImage = this.createImage(
new MemoryImageSource(newCols,newRows,myPixels,0,newCols));
myRows = newRows;
myCols = newCols;
myD = new Dimension(myCols,myRows);
setSize(myCols,myRows);
myIcon.setImage(myImage);
display();
}
/**
* turn all pixels to there 'opposite color'. Black to white,
* white to black, and invert RGB pixel by taking negative
* relative to 255 (max RGB value), i.e., red = 255 - red, and
* similarly for blue and green pixel values
*
*/
public void invert()
{
// get instance of inverter filter, use it and repaint
ImageFilter inverter = InvertFilter.getInstance();
myImage = createImage(new
FilteredImageSource(myImage.getSource(),
inverter));
repaint();
}
/**
* displays this in its associated frame
* and updates its application that active pixmap
* has changed (for use in re-displaying thumbnail and
* original image)
*/
private void display()
{
repaint();
ourFrame.setTitle("Pixmap: " + myName);
ourFrame.getContentPane().removeAll();
ourFrame.getContentPane().add(this,BorderLayout.CENTER);
((JComponent)ourFrame.getContentPane()).revalidate();
((JComponent)ourFrame.getContentPane()).repaint();
ourFrame.pack();
ourFrame.setVisible(true);
}
private Image myImage = null; // the actual image for this
private int myRows = 0; // # rows in image
private int myCols = 0; // # columns in image
private PixController myControl; // associated controller
private PixIcon myIcon; // iconified (thumbnail) image
private String myName; // filename source of image
private Dimension myD; // dimension for getPreferredSize()
private int myPixels[];
// frame in which image displayed, one per app
private static JFrame ourFrame = new JFrame("Pixmap image");
}
/**
* package accessible class for filtering images
* (could be a nested class for Pixmap in jdk1.1.1)
*
* this class uses a Singleton pattern (see Design Patterns by
* Gamma, Helm, Johnson, Vlissides) which ensures that only
* one instance of the filter is created
* to use an InvertFilter call the getInstance() method (which
* will create the filter the first time it's called)
*/
class InvertFilter extends RGBImageFilter
{
/**
* return the single instance of the InvertFilter
*
*/
public static InvertFilter getInstance()
{
if (ourInstance == null)
{
ourInstance = new InvertFilter();
}
return ourInstance;
}
/**
* private constructor enforces Singleton Pattern
*/
private InvertFilter()
{
canFilterIndexColorModel = true;
}
/**
* overrides RGBImageFilter.filterRGB
*/
public int filterRGB(int x, int y, int rgb)
{
// get the color model for use with Java and this app
DirectColorModel dm = (DirectColorModel)
ColorModel.getRGBdefault();
// invert all pixels (leave alpha/transparency value alone)
int red = 255 - dm.getRed(rgb);
int blue = 255 - dm.getBlue(rgb);
int green = 255 - dm.getGreen(rgb);
int alpha = dm.getAlpha(rgb);
// construct a pixel/int with rgb in appropriate bytes
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
private static InvertFilter ourInstance = null;
}