Comp 170 Lab 10: Extending ImageViewer, December 3

You are to add the following features to the final ImageViewer project (available here). All changes are to the ImageViewer class, or your new Redden class.

Redden

For the redden filter, the idea is to get the old red, green, and blue levels:

        Color p = image.getPixel(x,y);
int blue = p.getBlue();
int red = p.getRed();
int green = p.getGreen();
and then tweak the red level, by taking a weighted average of the old level and 255 (the max level):
        double weight = 0.4;
red = (int) ( red*(1-weight) + 255*weight);
(Note the cast back to int; the casts are annoying here but essential for dealing with mixed int/double calculations.) Any value of weight in the range 0<weight<1 will mean moving the color closer to 255; the larger the weight the greater the color shift. 

Finally, convert back to a color object, and reset the pixel to that color:

	Color np = new Color(red, green, blue);
image.setPixel(x, y, np);

To create the redden filter, create a new class and copy DarkerFilter into it; then edit.

The redden filter should be installed like the other filters; see the example in ImageViewer.java of a series of calls of the form "filterlist.add(...)".

Rotate

For rotate, you will first create a method rotate() in class ImageViewer in which you create a new OFImage and set all the pixels; as a first draft we will just reverse x and y from the original. You'll have for loops for x and y, and do something like:

        newImage.setPixel(y,x,currentImage.getPixel(x,y));		// note reversed y,x
Model the loop, and the overall method, after  makeSmaller() or makeLarger().

Actually, reversing x and y just "flips" the image with respect to the y=x diagonal axis. A (clockwise) rotation actually sets the new pixel at (x,y) to the old pixel at (y, oldHeight-1-x), where oldHeight = newWidth is the height of the original image.

You should create a button for "Rotate" below the existing button "Larger". Copy the example of the creation of the ActionListener for that button (with appropriate changes). To add buttons, you will have to:

Undo

Finally, for undo, add a field prevImage to ImageViewer, and make sure that before each change to currentImage you set prevImage = currentImage. You will have to identify every place the image can be changed. That's (superficially) easy for filters (just set prevImage in ImageViewer.applyFilter()), but each button method (makeSmaller(), makeLarger(), rotate()) will have to be modified separately. The undo command then simply replaces currentImage with prevImage.

There is one problem with filters: the filters modify the image "in place"; you will have to set prevImage to a copy of currentImage. I did this by writing a copyImage method, modeled again after makeSmaller, which made prevImage a copy of currentImage (but did not make it the "current" image). There's a start to copyImage in the file; you will have to complete it by adding the copy loop.

The Save operation isn't undoable. The best solution for undoing an Undo operation is to simply redo it; that is, have undo() also set prevImage = currentImage. A nice touch is to be sure nothing happens if prevImage==null.

There are also a couple other things you have to do after setting currentImage, involving setImage and frame.pack. See the tail end of makeSmaller for an example.

You can create a button or menu item for Undo. For a button, model it after the rotate button. A nice touch (but harder) is to create an Edit menu to put the Undo item in; after all, that is the standard location.

Email me your project as usual.