//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
 * 

* 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 *

* * @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 *
     *    |
     *    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; }