CS140 -- Lab 4


Take a look at pgm.h. This is a header file that defines a type Pgm to be a (void *). It then gives prototypes for 6 procedures that let you read/write/manipulate pgm files. Your job is going to be to write those procedures in a file called pgm.c. This is going to be much like tokengen.c from the (void *) lecture. You'll have to define your own struct for pgm files in pgm.c, and use that in your routines. However, when you pass it to other programs that include pgm.h, you will cast it to a Pgm. When you accept such an argument from a program that includes pgm.h, you'll have to cast it from a Pgm to your own struct. Note, this is exactly what goes on in tokengen.c, so if you are confused, go over the the (void *) lecture. until you understand it completely.

Part 1: pgm.c

Now, your job is to implement the following procedures in pgm.c:

A simple example: neg.c

Here's an example of writing neg.c to use pgm.h/pgm.c:
#include <stdio.h>
#include "pgm.h"

  Pgm p;
  int i, rows, cols;
  int *pixels;

  p = read_pgm(0);
  if (p == 0) exit(1);

  rows = pgm_rows(p);
  cols = pgm_cols(p);
  pixels = pgm_pixels(p);

  foi (i = 0; i < rows * cols; i++) {
      pixels[i] = 255 - pixels[i];

  write_pgm(p, 0);

More Example PGM Files

These are available in /home/plank/cs140/Fall-2004/labs/lab4, and they have comments in them. Thematically, they compose the PGM listing of Dr. Plank's most formative role models (although they are missing bridge pro Chuck Said, whose picture I could not get...). See if you can figure out why.....

Red Foreman.

Mr. Hand (the one on the right, not Sean Penn).

Sir Charles.

Sir Rodney.

The Amazing Kai.

The Thunder Queen.

Big Dave.

Big Peg.

The original Dr. Plank.

The Reverend.

"Deadlock? Deadlock? Perhaps we should move on."
Chuck Said's
picture will
be here.

Part 2: pad

Use pgm.h and pgm.o to write pad.c. This takes the following command line arguments:
UNIX> pad padding padgray 
Pad takes a pgm file on standard input, and creates a pgm file on standard output that adds padding extra pixels of padding around the border of the input pgm file, and puts the output on outputfile. The grayness of the padding is specified by padgray, and should be a number from 0 to 255.

If that specification seems ambiguous, try out my example executable, and make sure you match its output.

Part 3: crop

Use pgm.h and pgm.o to write crop.c. This takes the following command line arguments:
UNIX> crop rows cols left top 
Crop takes a pgm file on standard input, and creates a pgm file on standard output that crops the pgm file. It creates a new file that has rows rows, and cols columns, and contains the portion of the picture of those dimensions starting left pixels from the left edge of the picture, and top pixels from the top of the picture. If left+cols is greater than the number of columns of the input picture, or if top+rows is greater than the number of rows of the input picture, crop should flag an error.

Again, use the example executable as a guide if you have questions on how your program should work.

A fun example

UNIX> shade 1 1 little.pgm
UNIX> pad 20 0 < little.pgm | pad 20 255 | pad 20 0 | pad 20 255 | pad 20 0 | pad 20 255 | crop 121 121 0 0 | pad 5 255 | pad 5 0 > junk.pgm
UNIX> convert junk.pgm junk.gif
This makes the following file: