Project 3 - RGBFileFormat
SeamCarver
and other graphics algorithms, a more human-readable file format would be helpful.Categories:
6 minute read
Objectives
- Read and write text files representing 2D arrays.
- Throw exceptions with specific error messages.
Introduction
For this project you will implement saving and loading images in a format that supports debugging graphics algorithms by being more human-readable.
When testing applications like SeamCarver
, creating small images can be helpful.
The “RGB File Format” is a simple way to create your own images in plain text files.
See the .txt files below for examples of the RGB file format.
Each line of the file is a tab-delimited sequence of pixels in the format (r, g, b)
where r
, g
, and b
are integers in the range 0 to 255.
Space characters before/after the parentheses and commas are optional (all spaces should be ignored).
Provided Image Files
-
3x4.txt – 3x4.png in RGB format
-
3x4.bad – 3x4.txt missing a comma
-
6x5.txt – 6x5.png in RGB format
-
6x5.bad – 6x5.txt missing a parenthesis
Provided Source Files
- Picture.java – for loading images (originally found at https://introcs.cs.princeton.edu/java/stdlib/Picture.java )
- RGBException.java – custom exception class
- RGBFileFormatTest.java – example JUnit tests
- RGBFileFormat.java – stubs for Part A
- Convert.java – stubs for Part B
Part A: RGBFileFormat.java
Your first task is to implement the RGBFileFormat
class in the UML diagram below. Each of its methods throws a FileNotFoundException
when applicable. In addition, the load()
method throws RGBException
(with a specific error message and location) if the file format is incorrect.
classDiagram
class RGBFileFormat
RGBFileFormat: +load(path String)$ Picture
RGBFileFormat: +save(path String, picture Picture)$
load()
This method reads an RGB file and returns a corresponding Picture
object.
You will need to determine the width and height of the picture based on the file contents.
Read the file line by line, construct a Color
object for each pixel, and set the corresponding (x, y) of the picture.
Your load
method should be robust enough to read a “sloppier” version of a picture file than your own very clean save
method would produce. Specifically, (as mentioned in the introduction) your load
method should ignore space characters
. Therefore, you should be able to load files when the numbers have not been padded to a width of 3 characters (which is required of your own save
method).
You may assume that the number of tab characters (\t
) between pixels on the same line is exactly 1
and that the line will not have any other tab characters.
Warning
Your solution may NOT use regular expressions . Files containing the wordssplit
or regex
will automatically be rejected.
You will need to write your own private methods for parsing the file contents manually.
Your code must be able to handle the following error conditions:
- If the file is empty, throw an
RGBException
with the message"empty file"
. - If any line is blank, throw an
RGBException
with the message"blank line"
. - If the file has an inconsistent number of columns, throw an
RGBException
with the message"ragged"
. - If a pixel does not begin with
'('
or end with')'
, throw anRGBException
with the message"parens"
. - If a pixel does not have exactly two commas, throw an
RGBException
with the message"commas"
. - If a number does not parse as an integer, throw an
RGBException
with the message"number"
. - If a number is not in the range 0 to 255, throw an
RGBException
with the message"range"
.
When throwing an RGBException
, the x
and y
values should correspond to the location of the corresponding pixel.
In the case of empty file, blank line, and ragged, the x
value should be 0
and the y
value should be the relevant location. In the case of an empty file, y
should be 0
.
save()
This method writes a Picture
object to an RGB file. Each line of the file represents a row of the picture.
Pixels on the same line should be separated by tab characters and use the format (r, g, b)
with exactly one space after each comma.
As shown in 3x4.txt and 6.5.txt, each integer should be 3 characters wide (with leading spaces), so that all pixels are 15 characters wide.
Each line of the file should end with a newline character.
Unit Testing
RGBFileFormatTest
is provided as a starting point to test your load
and save
methods.
You should create additional .bad
files of your own to test the other error conditions.
These files and other test code will not be submitted; feel free to make any changes you like.
What unit tests should you write? Consider:
- What is the simplest example you can think of where you expect a certain outcome for some part of the code (a method or a small number of methods)?
- Write a unit test that asserts your expectation is the result of calling those methods.
- What is an example where the same code should perhaps behave differently?
- Maybe different “branch” or condition has been satisfied and so the behavior should be different according to the specs?
- Maybe it’s an erroneous situation and the expectation is that a certain exception is thrown?
- Might there be unexpected interactions between different methods?
Part B: Convert.java
Implement an application that uses your RGBFileFormat
class to convert images to/from other formats.
This application will be run from the command line as follows:
- To convert a png/jpg file to RGB format:
java Convert filename.png filename.txt
- To convert an RGB file to png/jpg format:
java Convert filename.txt filename.png
As shown above, the main
method must have exactly two arguments: the source filename and the destination filename.
If the application is not run with two arguments, main
should print the following message to System.err
and exit with status code 1:
Usage: java Convert SRC DST
Exactly one of the command-line arguments must end with ".txt"
; this argument is the file in RGB format.
If neither argument ends with ".txt"
, main
should print the following message to System.err
and exit with status code 1:
One of the images must end with .txt
The other argument must end with either ".jpg"
or ".png"
; this argument is the image to convert to/from.
If any other extension is found, main
should print the following message to System.err
and exit with status code 1:
Unsupported file format: FILENAME
where FILENAME is the invalid argument.
After validating the command-line arguments, the main
method should perform the requested conversion.
For example, use RGBFileFormat
to load the image and Picture
to save the image, or vice versa.
Note
As shown in the providedConvert.java
stubs, the main
method throws Exception
.
This means you don’t have to handle FileNotFoundException
and RGBException
.
Your main
method should not have any try-catch
blocks.
Submission and Grading
For this project, you will submit each part separately on Gradescope:
- For Part A, submit only
RGBFileFormat.java
. It will be autograded with a longer version ofRGBFileFormatTest
that is more comprehensive than the provided code. - For Part B, submit only
Convert.java
. It will be autograded with the solution forRGBFileFormat
. That way, you can get full credit for Part B even if you don’t finish Part A.
You may submit up to 10 times without penalty. Additional submissions (if any) will receive a penalty of 3 points each. You are strongly encouraged to test your code offline before submitting.
As in previous assignments, your code must pass Checkstyle to receive any points. Submissions that don’t pass Checkstyle count toward the limit of 10 submissions. You are strongly encouraged to run Checkstyle offline before submitting.
Project Part | Weight |
---|---|
RGBFileFormat (via autograder) | 60% |
Convert (via autograder) | 20% |
Code Review | 20% |