Problem description

For this assignment, you will write an image-editing program that works with Portable Pixel Map (PPM) files.

PPM Image Format

Most file formats are variants of the organization shown below: see image.

The PPM image format uses this same structure, but it is in human-readable ASCII text. For those of you who wish to have the experience of reading real documentation, the formal image specification can be found here. The following is a very simple PPM file:

Sample PPM file:

P3
# comment (optional)
4 4
255
0 0 0 100 0 0 0 0 0 255 0 255
0 0 0 0 255 175 0 0 0 0 0 0
0 0 0 0 0 0 0 15 175 0 0 0
255 0 255 0 0 0 0 0 0 255 255 255

Image Header

As you can see, the file consists of two parts: a header and a data segment. The header consists of the following entries:

ng entries:
P3 -- magic number
# comment -- comment lines begin with #
# another comment -- any number of comment lines
4 4 -- image width and height
# another comment! -- comments may appear in the header after P3
255 -- max color value

P3 is a "magic number." It indicates what type of PPM image this is (e.g., full color, ASCII encoding). For this assignment, it will always be P3. This is a required entry.

One or more comment lines may appear anywhere after the magic number but before the image data. Comments always begin with a hash (or pound) character. Comments are optional. Your images may or may not have comments.

Next comes the number of columns and the number of rows in the image (4 x 4). This is a required entry.

Finally, we have the maximum color value 255. This can be any value, but a common value is 255. This is a required entry.

The way you see the header presented is how it should be formatted!

Image Data

The image data contains the actual picture information. The data block begins with the first pixel of the top line of the image (upper left-hand corner), and the data is stored in order from left to right giving the red, green, and blue values for each pixel. Each pixel of the image is a tiny, colored square. The color is determined by how much red, green, and blue are present. So, 0 0 0 is the first color of the image, which is black, and the last pixel in the image is 255 255 255, which is white. By varying the levels of the RGB values, you can come up with any color in between. (The RGB color space provides for 16,777,216 different color variations.)

Note that color values must be separated by at least one space, but after that additional whitespace is ignored by the image viewer. In the sample ppm above we used additional whitespace to format the image so that it is easy for a human to understand, but the computer doesn't care if everything is on one line, if there is one line per line of the image, or some other combination.

Putting it all together

The sample PPM image from above would look something like this: see image.

Keep in mind, each square is one pixel, so the real thing is much smaller (the rendered image was blown up by 5000%).

How to view PPM files

While PPM files are easy to view as text (you can use geany, for instance) and easy to work with in code, they are highly inefficient. Most modern image formats use some kind of compression to make their size reasonable while preserving the image appearance (PPM files are quite large). PPM files are commonly used as an intermediate format when converting images from one type to another. Remember your storage quota is set at 100mb on the bellagio server.

On bellagio, you can view a PPM file 2 using the display program:

$ display /home/shared/cs135/demo.ppm &

And you can convert your own images using the convert program:

$ convert compress none myImage.png myImage.ppm

Your Assignment

That may sound like a lot of work, but it's really pretty simple. To make it easy to code, I've broken the program into three phases. In the first phase, you are reading the whole image and writing it to a file without making any changes to the image in the process. Believe it or not, at this point you've written most of the program! In phase two, we add some effects, and in phase III we add a menu for the user. You will submit phase III.

Phase I:

The user will specify the name of the image file. The file will be a text file in PPM format as described in the discussion above.

If the image file cannot be opened, the program should report that fact and end.

If the input file contains comments in the header, discard them. (Hint: Read a single character; if it's a hash character, consume and discard the line. If it's not a hash character, unget the character.) The user will specify an output file name. The purpose of the program is to make an exact copy of the input file as the output file. The "catch" is that you are limited to one array large enough to hold the largest image your program can process. Specifically, your program should handle images of up to 1920 x 1080 pixels. For example, if the image is sized 640x480, you would use only a portion of the array rather than the array's entire capacity.

The header must be formatted as described above, the image data portion of your output file can be formatted as you like, except lines should be limited to 70 characters. Whitespace includes newline characters, so you can put them in wherever you wish. The format specification allows for it.

Example interaction with the user:

Portable Pixel Map (PPM) Image Editor!
Enter name of image file: in.ppm
Enter name of output file: out.ppm
out.ppm created.

The output will be in a file called out.ppm and will be identical to in.ppm., excluding comments and formatting. Add a single line comment to your output file containing the original name of the file and your name.

Note: Your program is not responsible for displaying the image in the file! It should only manipulate the pixels and create an output file in the proper PPM format.

Test this with small files and large files. You can check to see if they are identical by loading them both into Notepad and comparing number by number.

Phase II:

Write a function called grayscale that will change the picture into a gray scale image. This is done by averaging the values of all three colors for a pixel (red, green and blue) anthen replacing them all by that average. So, if the three colors were 25, 75 and 250, the average would be 116, and all three numbers would become 116.

When you have this function written, insert it into Phase I so that every pixel of the picture has been converted to grayscale. View this image does it look as you expected?

Write a function called sepia_tone that will give the picture a hue resembling the effect of aging in old photographs. This is done by applying the following transformations to each pixel:

outputRed = (inputRed * .393) + (inputGreen * .769) + (inputBlue * .189)
outputGreen = (inputRed * .349) + (inputGreen * .686) + (inputBlue * .168)
outputBlue = (inputRed * .272) + (inputGreen * .534) + (inputBlue * .131)

Write a function called flip_horizontal that will flip the picture horizontally. That is, the pixel that is on the far-right end of the row ends up on the far left of the row and vice versa (remember to preserve RGB order!).

Write a function called flip_vertical that will flip the picture vertically. That is, the pixel that is in the top left corner ends up in the bottom left corner and vice versa.

Write a function called rotate_right that rotates an image 90 clockwise. 4 That is, the pixel that is in top left corner ends up in the top right corner, and the pixel that is in the top right corner ends up in the bottom right corner, and so on. Not that if the image is not square, the width and height dimensions will change.

Phase III:

The last part of the problem is to add a menu so that the user can decide which of these effects will be applied to an image.

Example of user interaction:

Portable Pixel Map (PPM) Image Editor!
Enter name of image file: in.ppm
Enter name of output file: out.ppm
Here are your choices:
[1] convert to grayscale
[2] convert to sepia tone
[3] flip horizontally
[4] flip vertically
[5] rotate image right
Do you want [1]? (y/n) y
Do you want [2]? (y/n) n
Do you want [3]? (y/n) y
Do you want [4]? (y/n) n
Do you want [5]? (y/n) y
out.ppm created.

You should apply the desired effects to the image one at a time.

Notes:

Your input routine should avoid reading from a failed input stream. What if the file is not as large as the row and column numbers indicate it will be? Does your code handle that gracefully (without falling into infinite loops, for example)? Your input routine should skip blank lines.

Your manipulations should not allow a color value to be less than 0 or larger than the maximum color depth specified in file.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.