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 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
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); } }