home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
NETWORK
/
netpbm_src.lzh
/
NETPBM
/
PPM
/
ppmdither.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-18
|
7KB
|
263 lines
/* 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);
}