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