T-Th 9:05
or
T-Th 11:15
in Phillips 101

CS 1110: Introduction to Computing Using Java

Spring 2012

Images

Due to CMS by Thursday, April 19th

This purpose of this assignment is to to learn how images are stored in memory, and write methods to manipulate them (much like Photoshop does). You will also learn a little bit about how graphical applications in Java are structured. You will also learn how to use helper methods and constants to structure your code so that it is much more readable.

Read this entire document carefully. Budget your time wisely. In particular, you should get started on this assignment immediately. This assignment is due two days after the second prelim, and there is no room to grant extensions. So if you wait to the last minute, you will have to deal with this assignment and the prelim at the same time. Do not do this! Pace yourself, working on at least one method a day (there are six in total when you are done).

Reading these Instructions

In the instructions below, we provide a lengthy aside on application design. We refer to certain classes in the application as model, view, or controller. This is the subject of a lecture that has been unfortunately delated until after the second prelim. You may still find this dicussion interesting, which is why it is provided.

With that said, some of you may just find this dicussion more confusing than helpful. It is also extremely long, and you do not need to follow all of it to do this assignment. If you find the section on application design confusing, or you just want to get started with the assignment, feel free to skip over it and start with the discussion of ImageArray instead.

Even skipping over the section on application design, these instructions are quite long. You should spend at least one evening simply reading these instructions while looking over the existing classes. Do not write any code until you understand how everything fits together.


Table of Contents


Before You Get Started

Academic Integrity

We have given this assignment before. It is a good one, and students really like it. Do not share your code with others. Do not obtain or look at a copy of the earlier solution or a version being done by another student. Such cheating helps no one, especially you, and it makes more unnecessary work for us.

As with the last assignment, it is highly unlikely that your code for this assignment will look exactly like someone else's. Once gain, we will actively be using Moss to check for instances of cheating and plagiarism. Anyone caught using files that are obviously from a previous semester will be prosecuted, with the end result perhaps being to fail the course.

Collaboration Policy

You may do this assignment with one other person. If you are going to work together, then form your group on CMS as soon as possible. If you do this assignment with another person, you must work together. It is against the rules for one person to do some programming on this assignment without the other person sitting nearby and helping.

With the exception of your CMS-registered partner, you may not look at anyone else's code or show your code to anyone else, in any form what-so-ever.

Assignment Source Code

The first thing to do in this assignment is to download the zip file A6.zip from this link. You should unzip it and put the contents in a new directory. This zip file contains the following:

ImageGUI.java
This is the primary class for the application. It initializes all of the objects in this application, and links them together (e.g. makes them fields of each other so that they can "talk to each other"). It also has methods that perform actions when you click on the buttons in the application.
In our application design, this is a controller class.
ImageFrame.java
This is a subclass of JFrame with buttons, panels, and other features. It does not do anything with the buttons; it just arranges them on the screen, while ImageGUI has the methods that perform actions when they are clicked.
In our application design, this is a view class.
ImagePanel.java
This is a subclass of JPanel with a single method: paint(). It is used to draw an image to a screen.
In our application design, this is a view class.
ImageProcessor.java
This class has methods for manipulating an image. This is the only class that you will need to modify.
In our application design, this is a controller class.
ImageArray.java
This class contains an array of pixles in an image, in row-major order. It has methods for getting and setting a pixel in an image.
In our application design, this is a model class.

All of these classes are explained in more detail below. The only class that you will need to modify is ImageProcessor. However, feel free to look at the code for the entire project, as it is very illuminating. While the view classes are a bit complicated and hard to read, you should be able to understand the controller and model classes with no problem.

Running the Application

In order to run the application, the only file that you need to open in DrJava is ImageGUI.java. This is the primary controller that starts the application and initializes all of the other objects. If you compile and use this in DrJava, DrJava will automatically use the other classes behind the scenes.

To run the application — once you have opened and compiled ImageGUI.java — type run ImageGUI in the Interations pane. A dialog window will open. Navigate to a folder that contains a JPEG (.jpg) file (or any other kind of image file that Java knows how to read) and select it. A window will open with two versions of the image, some buttons, and a text area.

When you work with this application, the left image will not change; it is the original image. The right image will change as you click buttons. First, see what buttons invert, transpose, and hor reflect do. After any series of clicks on these, you can always click the button restore to get back the original file.

If you wish, you can also try the buttons ver reflect, fuzzify, and put in jail. However, they will not do anything unless you write code to make them work.

We have some sample images, if you need some images to play with. In addition, we have provided you with some output examples so that you can see what each of the buttons should do when you are done with the assignment.

Getting Help

If you do not know where to start, or if you are completely lost, please see someone immediately. This is a slightly more complex assignment than the previous ones. You may talk to the course instructor, a TA, or a consultant. See the staff page for more information. Do not wait until the last minute, particularly since this assignment is due the same week as the second prelim.


Understanding the ImageGui Application

The application ImageGui is a complicated one, and in this section we give you an idea of the various components. However, you do not actually need to understand all of these components to get started. So feel free to skip over to the the discussion of ImageArray if you are impatient.


Advanced Application Design

Real software applications are not made from a single class file. They are often composed of many (perhaps even hundreds) classes. When you have a program that is made up of several classes, it is important to organize the parts of a program in a logical and coherent way, so that it is clear what each part is responsible for and so that interactions between parts are kept reasonable. The larger and more complicated the task of a program, the more important it is to have good organization.

The classic way of organizing applications — particularly those that are sit on a single computer and do not need to connect via the internet — is using what is know as the model-view-controller paradigm. In this paradigm, every single class is categorized as either a model, a view, or a controller. The roles of each are detailed below.

Model

The model is a class that holds the application data. It provides getters and setters to manipulate the data, plus some useful additional methods to perform commonly used tasks on the data.

The AcornProfile, which you worked on for several assignments, is a classic example of a model class.

View

A view is a class that displays a graphical user interface to the screen. It also keeps track of when the user performs any input, such as typing or moving/clicking a mouse. However, it does not tell the program what to do when the user performs input. It only keeps track of the fact that it happened.

A JFrame is a classic example of a view class. It displays graphics, and notifies the program when the user clicks the "close box".

Controller

Controllers are the heavy lifters and they do everything else. They start up the program and instantiate the other classes (e.g. the view and model) with new-expressions. They also provide the methods that do something when the user performs some input. Finally, they also force the view to refresh whenever it should be updated.

While you have not yet written a "pure" controller class in this course yet, the turtle methods in the previous assignment are fairly close to what a controller does.


ImageGui Code Organization

Now that you are introduced to the concept of model-view-controller, the diagram to the right shows how this application is organized. When we draw lines between two classes that means that objects of those classes need to "communicate" (e.g. call methods from one another). If there are no lines between classes, then the objects do not need to communicate. This is another important feature in organizing code.

In this diagram, the primary class is ImageGui. It is the class that you run and is the only one that DrJava needs to open (though you will want to edit ImageProcessor as well). It creates instances of all of the classes with new-expressions and initialzes them so that they can "communicate" with one another. ImageGui also "listens" to button clicks and acts accordingly. It calls the appropriate methods in ImageProcessor, and then calls on ImagePanel to revise its image and repaint the GUI.

This image itself is stored in an object of class java.awt.Image. Our own class ImageArray maintains an Image as a one-dimensional array of pixels. As images are conceptually a two-dimensional array (width x height), the array stores the pixels in row-major order. That is, it first stores the elements of row 0, then the elements of row 1, then the elements of row 2, and so on. As a model class, ImageArray provides methods for manipulating the image, allowing a user to process the pixels of an image row by row, column by column, or without regard to the order.

The class ImageProcessor provides methods for transforming the image, which is maintained as an ImageArray. Because it does not hold the image data, but only manipulates it, this class is categorized as a controller, and not a model. As the lines in the diagram below show, the ImageProcessor knows nothing about the GUI; it simply calculates. It does, however, work with ImageArray, and has fields that contain (the names of) the original and the transformed ImageArray.

Class ImageFrame is a subclass of JFrame and it is a view providing buttons, panels, and other features. The class ImagePanel is of the components of this view. As a subclass of JPanel, it can display an image through its method paint. When an image is changed in any way, it has to be notified to revise the display; updating the image and providing this notification are done by method changeImageTo.


Class Image and Class ImageArray

An instance of class java.awt.Image can contain an image (such as might be read in from a .jpg, .png or other format of image file). Just how the image is stored is not our concern; the class hides such details. Abstractly, the image consists of a rectangular array of pixels (picture elements), where each pixel entry is an integer that describes the color of the pixel. We show a 3-by-4 array below, with 3 rows and 4 columns, where each Eij is a pixel.

      E00  E01  E02  E03
      E10  E11  E12  E13
      E20  E21  E22  E23

We have not talked about two-dimensional arrays in class yet, but an image with r rows and c columns could be placed in an int[][] array b[0..r-1][0..c-1]. Instead (partly because we only know one-dimensional arrays), class ImageArray maintains the pixels in a one-dimensional array rmoArr[0..r*c-1]. For the 3-by-4 image shown above, array rmoArr would contain the elements in row-major order:

      E00, E01, E02, E03, E10, E11, E12, E13, E20, E21, E22, E23

Class ImageArray provides the representation of an image in its array rmoArr, along with methods for dealing with it. You can get the value of an individual pixel with getPixel(row,col). You can change the image using its methods setPixel(row,col,v) and swapPixels(a,b,i,j). Suppose, for a variable im of class ImageArray, you wish to set a pixel to v; instead of writing im[h,k]= v, you write im.setPixel(h,k,v);. You can also reference pixels as a one-dimensional array, using methods getPixel(p) and setPixel(p,v). That is all you need to know in order to manipulate images in this assignment.


Pixels and the RGB System

As we discussed in the previous assignment, your monitor uses the RGB (Red-Green-Blue) color system for images. Each RGB component is given by a number in the range 0..255 (8 bits). Black is represented by (0, 0, 0), red by (255, 0, 0), green by (0, 255, 0), blue by (0, 0, 255), and white by (255, 255, 255). Since this system uses 8 bits for each of the three colors of a pixel, it is called "24-bit RGB color", and the number of distinct colors is 224 = 16,777,216.

A pixel is stored in a 32-bit (4 byte) word (memory location). The red, green, and blue components each take 8 bits. The remaining 8 bits are used for the "alpha channel", which is used as a mask to make certain areas of the image transparent (for those software applications that support transparency). We will not change the alpha channel of a pixel in this assignment. The elements of a pixel are stored in a 32-bit word like this:

8 bits 8 bits 8 bits 8 bits
alpha red green blue

Suppose we have the green component (in binary) g = 01101111 and blue component b = 00000111, and suppose we want to put them next to each other in a single integer, so that it looks like this in binary:

0110111100000111

This number can be computed using g*28 + b, but this calculation is inefficient. Java has an operation that shifts bits to the left, filling the vacated spots with 0's. We give three examples, using 16-bit binary numbers.

0000000001101111 << 1 is 0000000011011110
0000000001101111 << 2 is 0000000110111100
0000000001101111 << 8 is 0110111100000000

Secondly, operation | can be used to "or" individual bits together:

0110111100000000 | and 0011 |
0000000010111110 1010
is 0110111110111110 is 1011

Therefore, we can put an alpha component alpha and red-green-blue components (r, g, b) together into a single int value (which is 32 bits) using this expression:

(alpha << 24) | (r << 16) | (g << 8) | b

To see this in action, take a look at method ImageProcessor.invert. For each pixel, the method extracts the 4 components of the pixel. It then inverts the red, green, and blue components, reconstructs the pixel using the above formula, and stores the new pixel back in the image.


Class ImagePanel

To understand this class, read this section with class ImagePanel open in DrJava. A JPanel is a component that can be placed in a JFrame. We want a JPanel that will contain one Image object. This is the motivation for a class ImagePanel that extends JPanel.

The field image of ImagePanel contains (the name of) the Image object. The constructor places a value in image and also sets the size and "preferred size" of the ImagePanel to the dimensions of the image; this preferred size is used by the system to determine the size of the JFrame when laying out the window.

Method paint is called whenever the system wants to redraw the panel (perhaps it was covered and is now no longer covered); our method paint calls g.drawImage to draw the image. Finally, method changeImageTo is called whenever our program determines that the image has been changed (e.g. after inverting the image). Take a look at the method body.

How does one learn to write all this code properly? When faced with doing something like this, most people will read the API specifications and then start with other programs that do something similar and modify them to fit their needs (as we did).


Class ImageFrame

This class is a JFrame, whichc is associated with a window on your monitor. Since we want a window (that contains two versions of an image), class ImageGUI extends JFrame. This is a somewhat involved class because it lays out all of the visual components. Take a look at the following components of class ImageGUI (there are others, which you need not look at now).

Fields

The fields originalPanel and currentPanel contain the panels for the original and manipulated images.

Constructors

There are two constructors. One is given an image. The other has no parameters; it gets the image using a dialog with the user, where the user can navigate on their hard drive and choose which image to work with. This is similar to obtaining a file to read, which you learned about in lab.

Method setUp

Both constructors call this private method. The method puts the buttons into the JFrame (using two arrays and a loop to streamline some of the repetitive stuff). We will learn about this later in class. It then adds a labeled text area, which you will use later. Next, provided that there is an image, it creates two panels with the image in them and adds them to the JFrame, using the call add(BorderLayout.EAST, imagebox);. Finally, it fixes the window location, makes the JFrame visible, and "packs" and repaints it.

Method setDefaultCloseOperation

The call of this method ear the end of setUp fixes the small buttons in the JFrame so that clicking the "close" button causes the window to disappear and the program to terminate.

Eventually, you may wish to read Chapter 17 of the text for more information on placing components in a JFrame. There is also a lot of information about GUIs in the lectures on the ProgramLive CD.


Class ImageProcessor

This class provides all the methods for manipulating the image given to it as an ImageArray in the constructor. The constructor stores the image in field originalIm and stores a copy of it in currentIm.

As the image is manipulated, object currentIm changes. It can be restored to its original state by copying field originalIm into currentIm. That is what procedure restore (near the end of the class) does.

The other methods in this class implement the various buttons in the application. When a button is clicked, the application calls the appropriate procedure. The procedures invert, hreflect, transpose, and restore are complete. Procedure invert inverts the image (makes a negative out of a positive, and vice versa). Note how it processes each pixel; it retrieves it, then computs what its new color components should be, and finally places the changed pixel back into currentIm.

Your goal in this assignment is to implement the procedures corresponding to the other buttons.


Class ImageGui

Now that you know the other classes, ImageGui actually does very little. It has a method called main. This is the method that Java calls when you use the command run ImageGui. In this method, it creates instances of the classes above and links them together (e.g. makes them fields of one another), so that they can function properly.

This class also links the buttons in ImageFrame with the procedures implementing them in ImageProcessor. It does this by providing a listener. We will talk about listeners later in class. However, you do not need to worry about them right now.


Assignment Instructions

The hardest part of this assignment is simply understanding how all of the classes fit together. However, the only class that you need to modify is ImageProcessor. For this assignment, you need to implement the methods vreflect, putInJail, monochromify, vignette, hide, and reveal. The method fuzzify is not required, though we will award extra credit (for students who earn at least a 90 on the rest of the assignment) for implementing this procedure.

You must write a complete and thorough specification of any method you introduce. It is best to write the specification before you write the method body, because it helps you as you program. This is standard practice in this course. It is a severe error not to do so, and points will be deducted for missing or inappropriate specifications.

You need not write loop invariants, and if you do, we will not grade them. But we encourage you to write them for each loop so that you get used to thinking in terms of the invariant and the four questions discussed in class.


Testing Guidlines

Before you write any code, you should be aware of our guidelines for testing. Using a JUnit testing class is difficult because you can't easily get access a picture. You do not have to use one. But this means you will need other creative ways of testing and debugging your code, such as print statements. You will find the function ImageArray.toString(pixel) to be quite helpful in getting a readable String representation of a pixel.

If you add print statements to your code, please remember to remove them before submitting. We will deduct points if you do not remove them.

For a method that consists of several steps, do not write the whole method and then compile and test. Generally you will have many syntax errors and you will waste time. Instead, compile after every line of code you write, and test what you have done if it is feasible to do so.


1. Method vreflect

This method should reflect the image around its vertical middle. Look at method hreflect to get an idea about how to do it. This should be relatively straight-forward.


2. Method putInJail

To the right you can see the effect of clicking button put in jail. This method draws a red boundary and vertical bars. This will happen when you implement method putInJail according to its specifications.

We have given you helper procedure drawHBar; use it. In the same way, implement a private procedure to draw a vertical bar. Do not forget its specification.

When finished, open a picture, click buttons put in jail, transpose, and then put in jail again for a nice effect.


3. Method monochromify

In this method, you will change the image from color to either grayscale or sepia. The exact one to chooise depends on the vlaue of parameter c, which is either 0 or 1. However, do not NOT use integer constants 0 and 1; instead use the static final fields GRAY and SEPIA (The names of variables holding constants are chosen to be all-capitals by convention). This illustrates the values of constants (e.g. final fields). Using these mnemonic names rather than the actual numbers makes the program more readable.

Which ever change you are to make, you should first convert the image to grayscale. You do this by calculating the overall brightness of each pixel using a combination of the original red, green, and blue values, defined by:

brightness = 0.3 * red + 0.6 * green + 0.1 * blue
Once you have this value, you set each of the three color components (red, green, and blue) to this same brightness value.

To simulate a sepia toned photograph (a process used to increase the longevity of photographic prints), further darken the green and blue channels, setting green to 0.6 * brightness and blue to 0.4 * brightness, producing a reddish-brown tone. As a handy quick test, white pixels stay white for grayscale, and black pixels stay black for both grayscale and sepia tone.

This manipulation requires that you extract the alpha, red, green, and blue components from each pixel, construct the new pixel value, and store it. Look at procedure invert as well as the discussion on RGB to see how this is done.


4. Method vignette

Camera lenses &mdash particularly ones from the early days of photography &mdash block some of the light that should be focused at the edges of a photograph, producing a darkening toward the corners of the image known as "vignetting". This is a distinctive feature of old photographs. In this method, you simulate this effect using a simple formula. Pixel values (in red, green, and blue separately) are multiplied by the following value:

1 - (distance to center)2 / (half of image diagonal)2

Like the monochromification, this requires unpacking and repacking the color components of each pixel. However, for this operation you will also need to know the row and column of the pixel you are processing, so that you can compute its distance from the center of the image.


5. Steganography

The last official part of the assignment is the most involved. Steganography, according to Wikipedia, "is the art and science of writing hidden messages in such a way that no one apart from the intended recipient even realizes there is a hidden message." This is different from cryptography, where the existence of the message is not disguised but the content is obscured. Quite often, steganography deals with messages hidden in pictures.

To hide a message, each character of the message is hidden in one or two pixels of an image by modifying the red, green, and blue values of the pixel(s) so slightly that the change is not noticeable to the eye.

Each character is represented using the American Standard Code for Information Interchange (ASCII) as a three-digit integer. We allow only ASCII characters; all the obvious characters you can type on your keyboard are ASCII characters, but it does not support certain foreign characters or Kanji. For the normal letters, digits, and other keyboard characters like $ and @, you can get its ASCII representation by casting the char to int. For example, (int)'B' evaluates to 66, and (int)'k' evaluates to 107.

We can hide character 'k' in a pixel whose RGB values are 199, 222, and 142 by changing each color component so that its least significant digit contains a digit of the integer representation 107 of 'k':

Original Pixel Pixel with 'k' hidden
Red Green Blue hide 'k', which is 107 Red Green Blue
199 222 142 191 220 147

This change in each pixel is so slight that it will not -cannot- be noticed just by looking at the image.

Decoding the message, the reverse process, requires extracting the last digit of each color value of a pixel and forming the ASCII value of a character from the three extracted values. In the above diagram to the right, extract 1, 0, and 7 to form 107, and cast this integer to char. Extracting the message does not change the image. The message stays in the image forever.

Three Problems for You to Solve

You will write code to hide characters of a message m in the pixels of an image in row-major order, starting with pixel 0, 1, 2, ... Think about the following issues and solve them.

First, you need some way to recognize that the image actually contains a message. Thus, you need to hide characters in pixels 0, 1, 2, ... that have little chance of appearing in a real image. You cannot be sure that an image without a message does not start with the pixels resulting from hiding the characters, but the chances should be extremely small. You should have a beginning marker of at least two pixels that indicates that this file contains a message.

Next, you have to know where the message ends. You can do this in several ways. You can hide the length of the message in the first pixels in some way (how many pixels can that take?). You can hide some unused character at the end of the message. Or you can use some other scheme. You may assume that the message has fewer than one million characters.

Finally, the largest value of a color component (e.g. blue) is 255. Suppose the blue component is 252 and you try to hide 107 in this pixel; the blue component should be changed to 257, but this impossible because a color components are < 255. Think about this problem, and come up with at least two ways to solve the problem; implement one of them.

As you can see, this part of the assignment is less defined than the previous ones. You get to solve some little problems yourself. Part of this assignment will be to document and discuss your solutions.

Documenting Your Approach

You should decide how you will solve the problems mentioned above. As you design and implement this part, write a short essay that documents at least 2 solutions to each of the three problems mentioned above. This essay should discuss their advantages and disadvantages, and indicate what your solutions are. Advantages could be: fewest number of pixels used in hiding an image, least time spent in hiding a message -whatever. When you are finished with this assignment, insert this essay as a comment at the beginning of class ImageProcessor.

In writing this essay, please make it readable. For example, we should not have to scroll horizontally to read it, and it should have paragraphs. Fifteen lines of uninterrupted text is not readable.

Do not explain anything in terms of what if-statements and assignments you would write and the like. Your reasoning should be at a higher level than that. Use English, not code.

At the end of the essay, state precisely the format of a hidden message. Tell us what the beginning marker is, how you encode length, and so on.

You should feel free to discuss this part of the problem with the course staff. They will not tell you how to solve these problems, but they will discuss your ideas with you.

Complete function getPixels(n)

Before you can do any steganography at all, you must complete (and test) function getPixels(n) in class ImageProcessor. The purpose of this extra method is to help you with debugging the method hide. From experience, we know that students who do not test hide properly can have great difficulty with this part of the assignment and do not even complete it correctly. After writing this function, you can type this in the interactions pane to print the first 9 pixels (we also give the output):

ImageGui b= new ImageGUI();
b.getPixels(9)
"pixels of current image: (104, 160, 161) (101, 157, 156) (098, 153, 147) (100, 154, 141) (108, 154, 141) (101, 142, 124) (075, 108, 089) (045, 072, 053) (041, 059, 045)"

You can look at function ImageGUI.getPixels and see that it calls the one you wrote.

Complete function hide and reveal

You should complete the body of procedures hide and reveal in class ImageProcessor. These two methods will hide a message and reveal the message in the image. When you design method reveal, make sure it attempts to extract the message only if its presence is detected. Feel free to introduce other methods as they are needed, but make them private because they are to be called not by a user but only by your program.

Debugging hide and reveal can be difficult. We encourage writing helper methods to keep code simple and short in hide and reveal. You get to decide which ones to write as you design and implement this assignment. Be sure to specify each method appropriately in a comment before it.

Do not assume that you can debug simply by calling hide and then reveal to see whether the message comes out correctly. Instead, debug method hide and then write and debug reveal. Start with short messages to hide (1, 2, or 3 characters) and check that the pixels contain the message.

When hide and reveal are done, try hiding and revealing a long message (e.g. 1,000, 2,000, or 5,000 characters). Notice any difference in the time to hide and the time to reveal? Can you figure out why? We will discuss this in class at the appropriate time.

About the Save Button

Clicking the button Save saves the image in the current directory with name foobar.png (if the file does not exist). You can hide a message, save, and then reload the image with the message still there. If we had used extension jpg, it would not have worked; in the jpg format, file compression may cause the image to be altered when saving it. Procedure writeImage at the end of ImageProcessor.java writes the file.


Extra Credit: fuzzify

You do not have to implement fuzzify. However, we will award extra credit if you do. Extra credit is meant to challenge students that have mastered the rest of the assignment. Therefore, we will only award extra credit if you make at least 90 on the rest of the assignment.

This method works like the blur tool in Photoshop (for those of you familiar with that program). This method replaces each pixel of the current image (except those on the edge) by the average of itself and its 8 neighbors. For example, it replaces the red component by the average of the 9 red components, and similarly for the blue and green components. Do not average the alpha component or otherwise change it. Follow the directions given in the java file. Again, look at method invert to see how to pick out the color components from a pixel and to build a new pixel.

As in transpose, the method will have two nested loops, and each iteration of the inner loop will process one pixel. Do not write all the code to process a pixel in the inner loop; instead, write another, private, procedure that processes the pixel and, in the body of the inner loop, call the new procedure. This is done to keep each method simple and short. Also, you can initially stub in the private method (e.g. have it set the pixel to carnelian, RGB (179, 27, 27) ) to facilitate constructing and testing one part of your code at a time, in a top-down, stepwise-refined fashion.


Finishing the Assignment

The only file that you should modify is ImageProcessor.java. At the very top of this file, you should use non-JavaDoc coments (/* */, not /** */) to provide the following information:

In addition, you should make sure that class A5 is indented properly. Do this by hitting tab on every line in DrJava, so that it will auto-indent for you.

Turning it In

Upload the file ImageProcessor.java onto CMS by the due date: Thursday, April 17th at 11:59PM You do not need to submit any of the other source code files. Do not submit any files with the extension/suffix .java~ (with the tilde) or .class. It will help to set the preferences in your operating system so that extensions always appear.