Many image file formats encode image data as a 2-D matrix or raster of pixel colors. The amount of available color information is fixed by the image's width and height|its resolution. If the resolution is too small, you will have problems trying to scale the image to a poster or an 8" by 10" photograph. Too little color information maps to too large an area on the scaled image. One can ll in color information by averaging the four nearest colors, but the result is blurry. Another solution is to increase the resolution at which pictures are taken, but this also increases the file size. For images containing text and mathematically-designed graphics, an even better solution exists. Instead of storing the color information in a fixed grid, the elements of the image are stored parametrically. For instance, if a circle is to appear at the center of the image and have a radius of 1/4 of the image's width, an image file might contain the command:
circle 0.5 0.5 [url removed, login to view]
Now, since the image content is defined using coordinates relative to the image size, the image can be scaled to any size without a loss of quality. Images which are encoded in this way are called scalable vector graphics (SVG).
2 Your Job
Your job in this assignment is to learn about 2-D arrays, inheritance, polymorphism, files, command-line arguments, and exceptions. You will do this by implementing a system for reading scalable vector graphics commands from a le and plotting these shapes into a conventional 2-D grid of color data. The program you write will produce an image file in the Portable Pixmap (PPM) format, a human-readable image format that can be read by image editing software like Photoshop, IrfanView, and The GIMP. You are responsible for turning in source code for classes PortablePixmap, Shape, Ring, Circle, Rectangle, Square, SVG, SVGFormatException, and SVGExporter.
PortablePixmap is a class that represents a 2-D grid of color data that can have its individual pixels colored and can be written to a file using the PPM format. It has the following interface:
A constructor that takes in a width and height as int arguments (in that order) and creates a completely white image having the specied dimensions.
Methods getWidth and getHeight that return the image's width and height.
A method setPixel that takes in three arguments: an int row, an int column, and a Color instance and sets the pixel at the position specified by the row and column to the specied color.
A method writeToFile that takes a single String argument representing the name of the file to store the image in using the PPM format. The method throws a FileNotFoundException if the file cannot be opened for writing.
3.1 [url removed, login to view]
Each pixel in the 2-D image should be an instance of the class Color, dened in the package java.awt. Colors are represented by a combination of red, green, and blue intensities. One of the many constructors of Color takes in three ints with intensities between 0 and 255. Following is a list of 8 typical colors and intensities that combine to produce them:
red ! new Color(255, 0, 0)
green ! new Color(0, 255, 0)
blue ! new Color(0, 0, 255)
yellow ! new Color(255, 255, 0)
magenta ! new Color(255, 0, 255)
cyan ! new Color(0, 255, 255)
white ! new Color(255, 255, 255)
black ! new Color(0, 0, 0)
3.2 PPM File Format
When you write a PortablePixmap instance to a file, use the PPM format. In this format, the first line of the file contains the text P3. On the next line, the image's width and height are listed. Next is the image's maximum intensity value|which should always be 255 in this case. And lastly, the color information appears with one pixel's color on each line. The 2-D array is flattened such that the color information is stored in row major format. This means that the color of row 0, column 0 appears rst; then row 0, column 1; then row 0, column 2; ...; row 0, column width &#1048576; 1; row 1, column 0; etc. An example le is found in Figure 1.
255 0 0
0 255 0
0 0 255
255 255 0
255 0 255
0 255 255
255 255 255
0 0 0
Figure 1: An example PPM image file. Note that the Color at row 0, column 0 in the array corresponds to the upper left pixel in the image. Thus, the coordinate system of an image has its origin in the upper left corner with the positive y-axis pointing toward the bottom of the image. You are advised to test your implementation of PortablePixmap on its own before advancing to the next classes. With setPixel, you can procedurally generate images, save them to a file, and view them in an image editing program.
A handful of shapes may appear in an SVG image: Rings, Circles, Rectangles, and Squares. All classes should be organized into an inheritance hierarchy to avoid repeating code. At the root of this hierarchy create an abstract class named Shape to manage the state common to all four shape types. Shape may contain protected methods and instance variables, but its public interface consists only of:
A constructor: public Shape(Color c, double originX, double originY).
An abstract method draw that takes in a single PortablePixmap argument and returns nothing. Your four non-abstract shape classes must implement the draw method so that the appropriate shape is drawn into the pixmap. Exploit inheritance where possible, i.e., don't implement a method or create instance variables in a subclass when such code is better suited in a superclass. Each of these should have its own constructor whose arguments follow the order they appear in the SVG file as defined in Section 5.2. The signature for Square's constructor, for example, is public Square(Color c, double originX, double originY, double size)
To draw a shape into a pixmap, visit each pixel in the image and determine if the pixel is part of the shape. If so, color it according to the shape's color. To determine a pixel's membership to a shape, you will have to first convert the shape's relative parameters to actual pixel coordinates. Relative coordinate (0; 0) maps to the upper-left corner of the image. If multiple shapes are drawn to the same pixel, retain only the color of the shape drawn last. If a shape extends beyond the bounds of the image, clamp the pixel coordinates accordingly to avoid an ArrayIndexOutOfBoundsException. The origin for Rings and Circles represents the center of these two shapes. Testing whether a pixel belongs to either of these shapes involves comparing the radii with the distance between the pixel and the origin. The origin for Rectangles and Squares represents the upper left coordinate of these shapes, which extend down and to the right of their origins.
It's worth your time to test each shape in isolation with PortablePixmap.
The class SVG stores an unbounded collection of Shapes and can plot them to a PortablePixmap. It's interface is:
A constructor taking no arguments that creates an SVG with no shapes.
A constructor taking a String argument representing the name of an SVG-encoded image file. All shapes are read from this file and added to the SVG. If the file cannot be found, a FileNotFoundException is thrown. If the file is improperly formatted, an SVGFormatException is thrown.
A method addShape that takes a single Shape argument and adds it to its collection.
A method drawPixmap that takes a single PortablePixmap argument and plots the shapes into the pixmap.
After your shape, SVG, and PortablePixmap classes are implemented, you can test them in isolation before moving on. Create various shape instances, add them to an SVG instance, make a 2-D pixmap, draw the shapes into the pixmap, and save the result to a file.
Create SVGFormatException to be a checked exception. You do not need to need to add or override any methods.
5.2 SVG Encoding
Each line in an SVG image file has the form <shape> <red> <green> <blue> <x-origin> <y-origin> [shape-specific fields] where <shape> is any one of square, rectangle, ring, or circle; <red>, <green>, and <blue> are numbers between 0 and 255 that represent the shape's color; and <x-origin> and <y-origin> are the relative coordinate values in [0, 1] representing the shape's origin. Squares have an extra field representing their side length proportional to the image's width, Rectangles have two extra fields representing their width proportional to the image width and height proportional to the image height, Rings have two extra fields for their outer and inner radii (radiuses) proportional to the image's width, and Circles have one extra field for their radius proportional to the image's width. An example of all four shape types is found in Figure 2.
square 0 0 0 0.1 0.2 0.3
rectangle 255 0 0 0.5 0.1 0.5 0.8
ring 255 255 0 0.5 0.5 0.2 [url removed, login to view]
circle 255 0 255 0.9 0.9 0.1 [url removed, login to view]
Figure 2: An example shape command file and its corresponding pixmap. A border has been added around the pixmap to illustrate its dimensions.
This final class contains just a main method that glues all your other classes together into a working application. It expects four command-line arguments in this order: the name of file containing shape commands, an int width, an int height, and the name of an output file with a .ppm extension. If any command-line arguments are malformed or missing, print a usage statement indicating proper program invocation and exit. Otherwise, after reading in the file, the shapes aare plotted to a pixmap of the specied width and height. The pixmap is then saved to the output file.[/code]