This is ppmdither.c in view mode; [Download] [Up]
/* ppmdither.c - Ordered dithering of a color ppm file to a specified number ** of primary shades. ** ** Copyright (C) 1991 by Christos Zoulas. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "ppm.h" #define NC 256 /* Total number of colors */ #define NS 256 /* Max number of shades in primary */ typedef unsigned char ubyte; static int dith_nr = 5; /* number of red shades */ static int dith_ng = 9; /* number of green shades */ static int dith_nb = 5; /* number of blue shades */ static int dith_nc = 225; /* total number of colors 5 x 9 x 5 */ static int dith_dim = 4; /* dimension of the dither matrix */ static int dith_dm2 = 16; /* dim square */ static int **dith_mat; /* the dithering matrix */ /* prototypes */ static int dith_value ARGS((int y, int x, int size)); static void dith_matrix ARGS((int dim)); void dith_setup ARGS((int dim, int nr, int ng, int nb, pixel *ptab)); int dith_color ARGS((float r, float g, float b)); void dith_dither ARGS((int w, int h, register pixel *t, register pixel *i, register pixel *o)); /* COLOR(): * returns the index in the color table for the * r, g, b values specified. */ #define COLOR(r,g,b) (((r) * dith_ng + (g)) * dith_nb + (b)) /* LEVELS(): * Returns the total number of levels after dithering. */ #define LEVELS(s) (dith_dm2 * ((s) - 1) + 1) /* DITHER(): * Returns the dithered color for a single primary. * p = the input pixel * d = entry in the dither matrix * s = the number of levels of the primary * */ #define DITHER(p,d,s) ((ubyte) ((LEVELS(s) * (p) + (d)) / (dith_dm2 * NS))) /* dith_value(): * Return the value of a dither matrix of size x size at x, y * [graphics gems, p. 714] */ static int dith_value(y, x, size) int y, x, size; { register int d; /* * Think of d as the density. At every iteration, d is shifted * left one and a new bit is put in the low bit based on x and y. * If x is odd and y is even, or visa versa, then a bit is shifted in. * This generates the checkerboard pattern seen in dithering. * This quantity is shifted again and the low bit of y is added in. * This whole thing interleaves a checkerboard pattern and y's bits * which is what you want. */ for (d = 0; size-- > 0; x >>= 1, y >>= 1) d = (d << 2) | (((x & 1) ^ (y & 1)) << 1) | (y & 1); return(d); } /* end dith_value */ /* dith_matrix(): * Form the dithering matrix for the dimension specified * (Scaled by NS) */ static void dith_matrix(dim) int dim; { int x, y, *dat; dith_dim = (1 << dim); dith_dm2 = dith_dim * dith_dim; dith_mat = (int **) malloc((dith_dim * sizeof(int *)) + /* pointers */ (dith_dm2 * sizeof(int))); /* data */ if (dith_mat == NULL) pm_error("out of memory"); dat = (int *) &dith_mat[dith_dim]; for (y = 0; y < dith_dim; y++) dith_mat[y] = &dat[y * dith_dim]; for (y = 0; y < dith_dim; y++) { for (x = 0; x < dith_dim; x++) { dith_mat[y][x] = NS * dith_value(y, x, dim); #ifdef DEBUG (void) fprintf(stderr, "%4d ", dith_mat[y][x]); #endif } #ifdef DEBUG (void) fprintf(stderr, "\n"); #endif } } /* end dith_matrix */ /* dith_setup(): * Setup the dithering parameters, lookup table and dithering matrix */ void dith_setup(dim, nr, ng, nb, ptab) int dim, nr, ng, nb; pixel *ptab; { register int r, g, b, i; dith_nr = nr; dith_ng = ng; dith_nb = nb; dith_nc = nr * ng * nb; if (dith_nc > NC) pm_error("too many shades %d, max %d", dith_nc, NC); if (dith_nr < 2) pm_error("too few shades for red, minimum of 2"); if (dith_ng < 2) pm_error("too few shades for green, minimum of 2"); if (dith_nb < 2) pm_error("too few shades for blue, minimum of 2"); for (r = 0; r < dith_nr; r++) for (g = 0; g < dith_ng; g++) for (b = 0; b < dith_nb; b++) { i = COLOR(r,g,b); PPM_ASSIGN(ptab[COLOR(r,g,b)], (r * (NC-1) / (dith_nr - 1)), (g * (NC-1) / (dith_ng - 1)), (b * (NC-1) / (dith_nb - 1))); } dith_matrix(dim); } /* end dith_setup */ /* dith_color(): * Return the closest color index for the one we ask */ int dith_color(r, g, b) float r, g, b; { int rr, gg, bb; rr = r * (dith_nr - 1); gg = g * (dith_ng - 1); bb = b * (dith_nb - 1); return((int) COLOR(rr, gg, bb)); } /* end dith_color */ /* dith_dither(): * Dither height scanlines at a time */ void dith_dither(w, h, t, i, o) int w, h; register pixel *t; register pixel *i; register pixel *o; { int y, dm = (dith_dim - 1); register int x, d; register int *m; for (y = 0; y < h; y++) for (m = dith_mat[y & dm], x = w; --x >= 0;i++) { d = m[x & dm]; *o++ = t[COLOR(DITHER(PPM_GETR(*i), d, dith_nr), DITHER(PPM_GETG(*i), d, dith_ng), DITHER(PPM_GETB(*i), d, dith_nb))]; } } /* end dith_dither */ int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; pixel ptab[256]; pixel **ipixels, **opixels; int cols, rows; pixval maxval; int argn; char* usage = "[-dim <num>] [-red <num>] [-green <num>] [-blue <num>] [pbmfile]"; ppm_init( &argc, argv ); argn = 1; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-dim", 1) && argn + 1 < argc ) { argn++; if (sscanf(argv[argn], "%d", &dith_dim) != 1) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-red", 1 ) && argn + 1 < argc ) { argn++; if (sscanf(argv[argn], "%d", &dith_nr) != 1) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-green", 1 ) && argn + 1 < argc ) { argn++; if (sscanf(argv[argn], "%d", &dith_ng) != 1) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-blue", 1 ) && argn + 1 < argc ) { argn++; if (sscanf(argv[argn], "%d", &dith_nb) != 1) pm_usage( usage ); } else pm_usage( usage ); ++argn; } if ( argn != argc ) { ifp = pm_openr( argv[argn] ); ++argn; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); ipixels = ppm_readppm( ifp, &cols, &rows, &maxval ); pm_close( ifp ); opixels = ppm_allocarray(cols, rows); maxval = 255; dith_setup(dith_dim, dith_nr, dith_ng, dith_nb, ptab); dith_dither(cols, rows, ptab, &ipixels[0][0], &opixels[0][0]); ppm_writeppm(stdout, opixels, cols, rows, maxval, 0); pm_close(stdout); exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.