Go Back

#include <fstream.h>

// Named after Russ Cox of Harvard; a little safety mechanism
// to prevent reaching beyond the limits of an array.
#define RUSS_FACTOR 5

#define RED 0
#define GREEN 1
#define BLUE 2

typedef struct image image;
struct image
{
  // image variables: the names are self-explanatory.
  char type[2+RUSS_FACTOR];
  int width, height, colorscale;
  int *rdata, *gdata, *bdata;

  // Create an image from file.
  void load(char *file)
  {
    int i, j, k;
    unsigned char r, g, b;
    // The dummy variables are for the purpose of wasting the header.
    char dummy, dummyl[128];

    ifstream infile(file, ios::in | ios::binary);

    infile >> type;
    while (infile.peek() <= 13) infile.get(dummy);
    while (infile.peek() == '#') infile.getline(dummyl,128,'\n');

    infile >> width >> height;
    infile >> colorscale;

    // Create a place to store the color data.
    rdata = new int[width*height+RUSS_FACTOR];
    gdata = new int[width*height+RUSS_FACTOR];
    bdata = new int[width*height+RUSS_FACTOR];

    for (j = 0; j < height; j++)
      for (i = 0; i < width; i++)
      {
	k = pos(i,j);
	// If P3, read in ASCII values.
	if (type[1]=='3')
          infile >> rdata[k]
                 >> gdata[k]
                 >> bdata[k];
	// If P6, read in binary chars and convert to ASCII.
	else
	{
	  // Yes, I could just do infile >> b etc., but
	  // this is left over from when I was not opening
	  // the file as binary but wanted to include the
	  // hard return character as valid data.
	  b = infile.peek();
	  infile.ignore(1);
	  r = infile.peek();
	  infile.ignore(1);
	  g = infile.peek();
	  infile.ignore(1);

	  rdata[k] = int(r);
	  gdata[k] = int(g);
	  bdata[k] = int(b);
	}
      }

    infile.close();
  }

  // Given a column and row number, return the absolute position
  // of the pixel in the data arrays.
  long pos(int w, int h)
  {
    return (width*long(h))+long(w);
  }

  // Given a point at (i, j) and an attribute, return the scaled
  // value of the attribute (0.0 - 1.0)
  double getColor(int i, int j, int rgb)
  {
    int k = pos(i, j);
    switch (rgb)
    {
    case RED: return double(rdata[k])/double(colorscale);
    case GREEN: return double(gdata[k])/double(colorscale);
    case BLUE: return double(bdata[k])/double(colorscale);
    default: return 0;
    };
  }

  int differ(int a, int b, float factor)
  {
    // A helper function for outline. If the ratio of the attributes
    // for two pixels are out of a certain range, return 1/12 the
    // maximum possible attribute value. Since this function is
    // called 12 times per pixel, if a pixel is completely different
    // from the four surrounding it the corresponding new pixel will
    // be black. If it's the same as the others, it will be white, and
    // otherwise it will be some intermediate shade of gray.
    double ratio = double(a)/double(b);
    if (ratio >= (1+factor) || ratio <= 1/(1+factor))
      return (colorscale/12);
    else return 0;
  }
  void outline(float dfactor)
  {
    int i, j, k;
    int *bw = new int[width*height+RUSS_FACTOR];

    // We only need one array; for grayscale images, all RGB components
    // are the same. Initialize all values to 0 (black).
    for (k = 0; k < width*height+RUSS_FACTOR; k++)
      bw[k]=0;

    for (i = 0; i < width; i++)
    {
      for (j = 0; j < height; j++)
      {
	k = pos(i,j);
	// Check all three attributes to the left
	if (i > 0)
	{
	  bw[k] += differ(rdata[k],rdata[k-1],dfactor);
	  bw[k] += differ(gdata[k],gdata[k-1],dfactor);
	  bw[k] += differ(bdata[k],bdata[k-1],dfactor);
        }
	// and to the right
	if (i < width-1)
	{
	  bw[k] += differ(rdata[k],rdata[k+1],dfactor);
	  bw[k] += differ(gdata[k],gdata[k+1],dfactor);
	  bw[k] += differ(bdata[k],bdata[k+1],dfactor);
        }
	// and up one row
	if (j > 0)
	{
	  bw[k] += differ(rdata[k],rdata[k-width],dfactor);
	  bw[k] += differ(gdata[k],gdata[k-width],dfactor);
	  bw[k] += differ(bdata[k],bdata[k-width],dfactor);
        }
	// and down one row.
	if (j < height-1)
	{
	  bw[k] += differ(rdata[k],rdata[k+width],dfactor);
	  bw[k] += differ(gdata[k],gdata[k+width],dfactor);
	  bw[k] += differ(bdata[k],bdata[k+width],dfactor);
        }
      }
    }

    // Set all RGB components to the grayscale value.
    for (k = 0; k < width*height; k++)
      rdata[k] = gdata[k] = bdata[k] = (colorscale-bw[k]);

    // Free unneeded memory.
    delete bw;
  }
};

My Supercomp front page.
This page was created by Gary Sivek for 7th Period Supercomp.