Lab 1: PicFilter
Due on Sunday, September 11th at 11:59 PM. This is an individual lab. You are to complete this lab on your own, although you may discuss the lab concepts with your classmates. Remember the Academic Integrity Policy: do not show your code to anyone outside of the course staff and do not look at anyone else’s code for this lab. If you need help, please post on the Piazza forum or contact the instructor or ninjas. If you have any doubts about what is okay and what is not, it’s much safer to ask than to risk violating the Academic Integrity Policy.
Overview
In this lab, you will write a program to apply filters to a particular image file format. You will become familiar with the following in C++:
- Command-line arguments
- Dynamically-allocated arrays
- Organizing your code into separate files
As with the previous lab, you should clone your repository; the URL is git@github.swarthmore.edu:cs35-f16/lab01-<your-username>
.
Images
Image data on a computer is typically stored in a series of units called pixels, each of which represents a single colored dot. The image in the figure, for instance, was originally 8 pixels wide and 7 pixels tall; it has been magnified for demonstration. In reality, the individual pixels on a modern computer monitor are almost too small to see; by packing the colored dots together so tightly in a grid, we can render pictures, text, and so on.
Image data on computers may be stored in a variety of different formats; common formats are JPEG (often abbreviated “.jpg
”), PNG, and GIF. Different image formats have different advantages. This lab will be using the PPM image format, the advantage of which is that it is quite simple.
The PicFilter Program
You will write a program called picfilter
which allows the user to manipulate PPM files from the command line. Your program will read a PPM file into memory as an object, perform a transformation on it, and then save it back to disk in another PPM file. Your program will take the input file, the transformation, and the output file as command-line arguments. For instance,
./picfilter old.ppm flip-horizontal new.ppm
will read the file old.ppm
, flip it horizontally (left to right, as in a mirror), and then save the result as new.ppm
.
Reading PPMs
To read a PPM file, you will pass its filename to three functions:
ppm_width
: Returns anint
describing the number of columns in the image.ppm_height
: Returns anint
describing the number of rows in the image.read_ppm
: Returns anint*
pointing to an appropriately-sized array of pixel data.
The array of pixels may be larger than you’d expect; it will actually be three times the size of the number of pixels in the image. For instance, a 100x100 PPM image would produce an array of size 30,000. This is because each pixel is represented by three numbers: the amount of red, green, and blue light to show for the pixel. Each number ranges from 0 (no light) to 255 (all the light). Here are some example pixel values:
0 0 0
: No red, green, or blue light. This color is black.255 255 255
: All red, green, and blue light. This is bright white.0 255 0
: No red or blue light; all green light. This is a bright neon green.255 255 0
: Red and green light, but no blue light. This winds up looking yellow.128 0 64
: No green light. Some red light and just a little blue light. This color is a dark reddish-purple.
The read_ppm
function takes care of opening a PPM file, reading the image data into it, and giving it back to you in a new array. Once you’ve read the PPM, you can change it and then write it back out into another file using the corresponding write_ppm
function. These functions are defined in ppmio.h
.
Transforming PPMs

Once you’ve read in your PPM as an array of integers, it’s up to you to change those integers in any way you like. You could loop over the entire image and set every number to 255, resulting in a giant white rectangle (since every pixel is now white). You could loop over each position in the first row and set each third number to 0, draining all of the blue light from the top line of the image.
As mentioned above, the user specifies an input file, a transformation, and an output file. Here are the transformations the user is allowed to request:
noRed
: Every pixel’s red value is set to0
.noGreen
: Every pixel’s green value is set to0
.noBlue
: Every pixel’s blue value is set to0
.invert
: All channels are subtracted from255
. For instance,255 128 0
would become0 127 255
.grayscale
: The channels of each pixel are averaged. For instance, the pixel255 128 0
would become127 127 127
(since(255+128+0)/3
is approximately127
).flipHorizontally
: All pixels are moved across the X axis. The first pixel in each row becomes the last pixel in that row, the second pixel in each row becomes the second-to-last pixel in that row, and so on.flipVertically
: All pixels are moved across the Y axis, causing the image to appear upside-down.
For each of these transformations, you will write a void
function of the same name that takes an int*
to a PPM image and makes the appropriate changes. You will then write a main
function which, based upon the command-line arguments to the program, loads the image, calls the right function, and then saves the result. If the user gives an invalid transformation (e.g. flipDiagonal
), your program should generate an appropriate error message and quit without saving a PPM file. You are allowed to ignore errors caused when the user gives non-existent or invalid filenames.
Writing Your Program
Your starter code has been separated into several files:
image.cpp
: This file is where you will write your image transformation functions (e.g.flipHorizontally
).image.h
: You will write headers for your image transformation functions here.picfilter.cpp
: You will write yourmain
function here.ppmio.h
/ppmio.cpp
: These files contain the functionsread_ppm
andwrite_ppm
that let you read and write PPM images. You do not need to change these files.tests.cpp
: This file contains some unit tests for your code. This will allow you to check the correctness of your transformations automatically instead of doing so by hand. You do not need to change this file.
Compiling Your Program
Your starter code also contains a Makefile
. This file contains instructions to compile your code so you don’t have to mess with the details of calling clang++
yourself. You can compile your program by typing make
or make picfilter
; if it compiles successfully, you can then run ./picfilter
. To test your image transformations, type make tests
and then run the program ./tests
.
Getting Started
Remember: you don’t have to write everything all at onec. It’s often best to get a small amount of your code to work and then move on to the next part. You can follow these steps to complete your lab:
-
Start by writing your
main
function. Write the code necessary to receive the filenames, load the PPM image, and save it again. For now, ignore the transformation; just read the file in and then write it back out. See if you can get your program to make a copy of a PPM file this way. -
Write the header and body of a single transformation (e.g.
noRed
) into yourimage.h
andimage.cpp
files. Then, add anif
statement tomain
to call that function if the transformation matches it. If not, theelse
part of yourif
statement should print an error message. Make sure you don’t save an image if you don’t recognize the transformation. For now, e.g.noRed
will be the only transformation you can handle. -
One by one, implement more transformations, adding them to
main
as you complete them. Try each of them out before you move on to the next one. -
Once you’ve finished writing your transformations, run
make tests
and then./tests
to see if the automated testing tools agree that your code is correct.
Survey
When you have completed the lab, please fill out this survey. This is required and is part of your participation grade.
Coding Style Requirements
For this lab, you will be required to observe some good coding practices:

-
You should pick meaningful variable names.
// Good int* pixels = new int[size]; // Bad int* p = new int[size];
-
You should use correct and consistent indentation. Lines of code within a block (that is, surrounded by
{
and}
) should be indented four spaces further than the lines surrounding them.// Good if (condition) { cout << "Test" << endl; } // Bad if (condition) { cout << "Test" << endl; }
-
You should use a block whenever possible, even if it’s not necessary. This helps you avoid subtle or messy bugs in the future.
// Good if (condition) { cout << "Something" << endl; } // Bad if (condition) cout << "Something" << endl;
Creating Your Own PPM Files
You can use ImageMagick, a package installed on the CS network, together with picfilter
to edit your own images! Start by converting your picture to PPM format:
convert my_image.jpg -compress none my_image.ppm
Then, do anything you want with picfilter
:
./picfilter my_image.ppm grayscale my_new_image.ppm
./picfilter my_new_image.ppm invert my_new_image_2.ppm
Finally, convert your new image back to some other format.
convert my_new_image_2.ppm my_new_image_2.jpg
There! You’ve just used your homework assignment to perform photo editing on your own files. :)
Summary
To summarize the requirements of this lab:
- Your program must perform all of the image transformations listed above.
- Your program must take its input from command-line arguments and gracefully handle invalid transformations.
- You should be able to run
make tests
and./tests
on the CS lab machines without any errors. - You must complete the survey above.