Next: Image Display Up: Image Previous: Fundamentals

Image Representation

Color Map

Data Structure

typedef struct CMap {
  Pixel r[256];
  Pixel g[256];
  Pixel b[256];
} CMap;

Grayscale CMap

void cmap_bw(CMap *m)
{
  int i;

  for (i = 0; i < 256; i++)
    m->r[i] = m->g[i] = m->b[i] = i;
}

Standard Color CMap

void cmap_rgb(CMap *m)
{
  int k;

  for (k = 0; k < 256; k++) {
    INDEX_TO_RGB(k, m->r[k], m->g[k], m->b[k]);
  }
}

Loading a CMap

void cmap_read(CMap *m, int maplength, int fd)
{
  read(fd, m->r, maplength/3);
  read(fd, m->g, maplength/3);
  read(fd, m->b, maplength/3);
}

Image Data Structure

Image Type and Constructor

typedef unsigned char Byte;

typedef struct Bcolor {
  Byte z, y, x;
} Bcolor;

typedef struct Image {
  int type;
  int w, h;
  CMap  *m;
  union {
    Byte   *b;
    Bcolor *c;
  } u;
} Image;

#define IMG_MONOCOL 0
#define IMG_MAPPCOL 1
#define IMG_TRUECOL 2

#define img_type(_) (_)->type
#define img_cmap(_) (_)->m

Image *img_init(int type, int w, int h)
{
  Image *i = NEWSTRUCT(Image);
  
  i->w = w; i->h = h; i->m = NULL;
  switch (i->type = type) {
  case IMG_TRUECOL:
    i->u.c = NEWTARRAY(w*h, Bcolor);
    break;
  case IMG_MAPPCOL:
    cmap_rgb(i->m = NEWSTRUCT(CMap));
  case IMG_MONOCOL:
    i->u.b = NEWTARRAY(w*h, Byte);
    break;
  default:
    error("(img init) wrong type");
  }
  img_clear(i, C_BLACK);
  return i;
}

void img_free(Image *i)
{
  efree(i->u.c); efree(i->m); efree(i);
}

void img_clear(Image *i, Color c)
{
  int u, v, k;

  switch (img_type(i)) {
  case IMG_MONOCOL: k = rgb_to_y(c); break;
  case IMG_MAPPCOL: k = cm_closest(i->m,c); break;
  case IMG_TRUECOL: default:
  }
  for (v = 0; v < i->h; v++)
    for (u = 0; u < i->w; u++)
      if (img_type(i) == IMG_TRUECOL)
        img_putc(i,u,v,c);
      else
        img_puti(i,u,v,k);
}

Implementation Choices

Pixel Access

Addressing Scheme

#define PIXVAL(I,U,V) I->u.b[U + (((I->h - 1) - (V)) * I->w)]

#define PIXRED(I,U,V) I->u.c[U + (((I->h - 1) - (V)) * I->w)].x
#define PIXGRN(I,U,V) I->u.c[U + (((I->h - 1) - (V)) * I->w)].y
#define PIXBLU(I,U,V) I->u.c[U + (((I->h - 1) - (V)) * I->w)].z

#define PIX_MIN 0
#define PIX_MAX 255

Accessing Color Indices

void img_puti(Image *i, int u, int v, int c)
{
  if (u >= 0 && u < i->w && v >= 0 && v < i->h)
    switch (img_type(i)) {
    case IMG_TRUECOL:
      PIXRED(i,u,v) = PIXGRN(i,u,v) = PIXBLU(i,u,v) = CLAMP(c,PIX_MIN,PIX_MAX);
      break;
    case IMG_MAPPCOL: case IMG_MONOCOL:
      PIXVAL(i,u,v) = CLAMP(c, PIX_MIN, PIX_MAX);
      break;
    }
}

int img_geti(Image *i, int u, int v)
{
  if (u >= 0 && u < i->w && v >= 0 && v < i->h) 
    switch (img_type(i)) {
    case IMG_TRUECOL:
      return (PIXRED(i,u,v) + PIXGRN(i,u,v) + PIXBLU(i,u,v)) / 3;
    case IMG_MAPPCOL: case IMG_MONOCOL:
      return PIXVAL(i,u,v);
    }
  else return PIX_MIN;
}

Accessing Colors

void img_putc(Image *i, int u, int v, Color c)
{
  switch (img_type(i)) {
  case IMG_TRUECOL:
    if (u >= 0 && u < i->w && v >= 0 && v < i->h) {
      PIXRED(i,u,v) = CLAMP(RED(c), PIX_MIN, PIX_MAX); 
      PIXGRN(i,u,v) = CLAMP(GRN(c), PIX_MIN, PIX_MAX); 
      PIXBLU(i,u,v) = CLAMP(BLU(c), PIX_MIN, PIX_MAX);
    }
    break;
  case IMG_MAPPCOL:
    img_puti(i, u, v, cm_closest(i->m,c)); break;
  case IMG_MONOCOL:
    img_puti(i, u, v, rgb_to_y(c)); break;
  }
}

Color img_getc(Image *i, int u, int v)
{
  int k;
  switch (img_type(i)) {
  case IMG_TRUECOL:
    if (u >= 0 && u < i->w && v >= 0 && v < i->h)
      return c_make(PIXRED(i,u,v),PIXGRN(i,u,v),PIXBLU(i,u,v));
    else
      return C_BLACK;
  case IMG_MAPPCOL:
    k = img_geti(i, u, v);
    return c_make(i->m->r[k], i->m->g[k], i->m->b[k]);
    break;
  case IMG_MONOCOL: 
    k = img_geti(i, u, v);
    return c_make(k, k, k);
  }
}



Luiz Velho
Wed Apr 7 12:17:01 "EST 1999