CS 161 Lab E - PhotoShopper

Due Thurs Feb 28 at 11:59pm

Overview

In this lab, you will be complete a program that lets you manipulate a graphical image, similar to the ever-popular Photoshop application. Your program will open an image file, display the image, and allow the user to apply a number of effects to that image. The basic functions you will be implementing are:

Although it sounds complicated, you can do it if you read the lab directions carefully, think, and plan before you code.

When running, your program will look something like this (all examples are made using the eye.jpg file included in the project file):

This lab will be completed in pairs. Be sure to review the pair programming guidelines. You also must work with a different partner than you have before!

Objectives

Necessary Files

You will need to download and extract the BlueJ project from the LabE.zip file. This project will supply you with the following classes:

Fun Fact: These classes demonstrate how to do graphical systems without using the Applet class. You are welcome to look them over and see if you can figure out how they work, but this is not required for this lab.

The lab file also has a couple of images you can use to test your program, though the system will be able to work with any file with a .jpg extension (called a "jay-peg" file).

Details

For this lab, you will be writing a new class called PhotoShopper (make sure to get the capitalization correct!) This class will do the actual image manipulation, such as making a mirror image, flipping the image, etc. When your class is finished, you will be able to construct (right-click in the BlueJ window) a PictureViewer. When the PictureViewer starts, it will look like this:

When you first start the program, you will get a window like this: Each of the buttons in the PictureViewer window will call a method in your PhotoShopper class to manipulate an image. Note that the "Load Image" button is already implemented for you: it opens up a dialog box (called a JFileChooser) that will let you select an image to manipulate. The user can navigate to find the image and select it. Once the image is selected, the PhotoViewer loads it from the file and creates an new BufferedImage object to represent it. Then the PhotoViewer calls the constructor for your PhotoShopper and passes this BufferedImage as an argument.

When the user clicks other buttons, the PhotoViewer calls methods in your PhotoShopper. Each of those methods manipulates the BufferedImage object and returns a new, changed BufferedImage object as the return value. Finally, when the user clicks the "Save Image" button, the PhotoViewer retrieves the image from your PhotoShopper and saves it to the harddrive, so you can share it with your friends!

All of the button interaction is provided for you--you just need to fill in the appropriate methods in the PhotoShopper class. These methods are listed in the documentation at the bottom of the page, and described in more detail below.

Creating the PhotoShopper class

BufferedImages

Your PhotoShopper class will need to have an attribute that is of the type BufferedImage to represent the current image. Be sure to look over the documentation for this class. Some details are below:

A BufferedImage is an object that represents a graphic image. Each image consists of a number of colored points, called 'pixels'. A BufferedImage is a collection of pixels that make up the image. Each pixel has an x and y coordinate and a color. BufferedImages have lots of available methods, but, for this lab, we are mostly interested in finding out what the color of each pixel is, and changing the colors of the pixels.

For each pixel, its color is represented by an integer. The integer (and therefore the color) has three components: a red component, a green component and a blue component. Each component can have a value from 0 to 255. For each pixel, you can specify its color by giving the red, green and blue components values. You can ask each pixel what its red, green and blue components are. If all components are 0, the color ends up being black. If all components are 255, the color is white. Other combinations give other colors. To see what different combinations mean, take a look at this site: http://www.rapidtables.com/web/color/RGB_Color.htm. This method of specifying colors (there are other methods too) is called 'RGB' for "red green blue".

To process a pixel, you need to get the RGB components, change them, and then set them back in the image. The process is not obvious. There are many ways to do it, but a simple way is to first get the RGB int, then make a Color object out of it. From the Color object, you can get the red, green and blue components as separate ints. After manipulating the red, green and blue components, make a new Color object from them and then use the Color object to give you the appropriate int for the pixel, and put it back in the image. Here is the basic idea:

int theRGB     = theImage.getRGB(x,y);     // get the RGB for the current pixel 
Color oldColor = new Color(theRGB);        // make a color so we can extract RGB components

// get the components 
int redComponent   = oldColor.getRed();
int greenComponent = oldColor.getGreen();
int blueComponent  = oldColor.getBlue();
// process the color components here
         ...

Color newColor = new Color(redComponent, greenComponent, blueComponent);// make the new Color
int newRGB = newColor.getRGB(); // get the RGB for it as an int 
newImage.setRGB(x, y, newRGB); // make the pixel that color

Modifying the Image

Each of the methods you will write manipulates the BufferedImage object by changing the pixels that make up the image. It then returns a new manipulated BufferedImage. Write one method at a time and test it. Once you have the first one done, the others will be much easier because most follow the same basic outline. The basic outline for each of these methods is this:

get the dimensions of the image
make a new BufferedImage of the same size
use nested for-loops to process each pixel
return the new BufferedImage

You can use nested for loops to process each pixel by making a for loop that iterates through each x-value. Within that loop, use another for loop to iterate through each y-value. Like this:

for (int x = 0; x < theImageWidth; x = x + 1)
{
    for (int y = 0; y < theImageHeight; y = y + 1)
    {
      // process the pixel
    }
}

eraseImage()

This method should set all of the RGB components to 255 (making the pixel white). This is a great method to write first, since all of the other methods will follow this pattern. After writing this method, hitting the appropriate button should produce an image like:

mirrorImage()

This method should take each pixel from the original image and put it in the corresponding place in the new image by giving it a new x-coordinate. Think about where each pixel needs to go! After writing this method, hitting the appropriate button should produce an image like:

grayScaleImage()

This method should take each pixel from the original image and figure out the average of the red, green, and blue components. Use that average for all of the red, green, and blue components of the corresponding pixel in the new image. After writing this method, hitting the appropriate button should produce an image like:

negativeImage()

This method should take the red component and subtract it from 255 to get the new red component value. Do the same for the green and blue components. After writing this method, hitting the appropriate button should produce an image like:

Optional: blurImage()

undo()

You can implement a simple "Undo" method by saving a copy of the image before changing it (you will need to make the "old image" an attribute so you can remember it!). When the PhotoViewer calls the undo() method, simply make the current image the old image (if there is one) and return it.

getImage()

This is very simple, you just need to return the image (no need to process each pixel!) This method is used by the "Save image" button, and will let your program save the modified image to a file.

Submitting

Important Points

Grading

This assignment will be graded on approximately the following criteria: