/* * This software is copyrighted as noted below. It may be freely copied, * modified, and redistributed, provided that the copyright notice is * preserved on all copies. * * There is no warranty or other guarantee of fitness for this software, * it is provided solely "as is". Bug reports or fixes may be sent * to the author, who may or may not act on them as he desires. * * You may not include this software in a program or other software product * without supplying the source, or without informing the end-user that the * source is available for no extra charge. * * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. */ /* * dither.c - dithering on images. * * Author: Raul Rivero * Mathematics Dept. * University of Oviedo * Date: Tue Feb 11 1992 * Copyright (c) 1992, Raul Rivero * */ #include #include #define DMAP(v,x,y) (modN[v] > dithermatrix[x][y] ? \ divN[v] + 1 : divN[v]) extern int LUGverbose; void create_dithermap(); void create_square(); dither_image(inbitmap, outbitmap, levels, gamma) bitmap_hdr *inbitmap; bitmap_hdr *outbitmap; int levels; double gamma; { register int i, j; int total_size; byte *r, *g, *b; byte *rout; int divN[256], modN[256]; int dithermatrix[16][16]; int col, row; if ( inbitmap->magic != LUGUSED ) error( 19 ); if ( levels < 2 || levels > 6 ) error( 11 ); if ( inbitmap->depth <= 8 ) error( 10 ); /* Fill new header */ outbitmap->magic = LUGUSED; outbitmap->xsize = inbitmap->xsize; outbitmap->ysize = inbitmap->ysize; total_size = outbitmap->xsize * outbitmap->ysize; outbitmap->depth = no_bits( levels*levels*levels ) + 1; outbitmap->colors = ( 1 << outbitmap->depth ); outbitmap->cmap = (byte *) Malloc( 3 * outbitmap->colors ); rout = outbitmap->r = (byte *) Malloc( total_size ); /* Pointers to in image */ r = inbitmap->r; g = inbitmap->g; b = inbitmap->b; /* * Init the cmap of the dithered image ( and other * parameters ). */ create_dithermap( levels, gamma, (color_map *) outbitmap->cmap, divN, modN, dithermatrix); /* * Dither each pixels across the dither matrix. */ VPRINTF(stderr, "Dithering the image\n"); VPRINTF(stderr, "Cutting to %d leves, %d colors\n", levels, levels*levels*levels ); for ( i = 0; i < outbitmap->ysize; i++ ) { row = i % 16; for ( j = 0; j < outbitmap->xsize; j++ ) { col = j % 16; *rout++ = DMAP(*r, col, row) + DMAP(*g, col, row) * levels + DMAP(*b, col, row) * levels*levels; r++, g++, b++; } } } /* * Functions for RGB color dithering. * * Author: Spencer W. Thomas * Computer Science Dept. * University of Utah * Date: Mon Feb 2 1987 * Copyright (c) 1987, University of Utah * * From Graphics Gems II and Utah Raster Toolkit. * * The functions name have been changed ( dithermap --> create_... and * make_square --> create_square ) due to problems with the RLE header * definitions. * */ static int magic4x4[4][4] = { 0, 14, 3, 13, 11, 5, 8, 6, 12, 2, 15, 1, 7, 9, 4, 10 }; void create_dithermap( levels, gamma, rgbmap, divN, modN, magic ) int levels; double gamma; byte rgbmap[][3]; int divN[256]; int modN[256]; int magic[16][16]; { double N; register int i; int levelsq, levelsc; byte gammamap[256]; for ( i = 0; i < 256; i++ ) gammamap[i] = (byte) (.5 + 255. * pow( i / 255., 1./gamma )); levelsq = levels*levels; /* squared */ levelsc = levels*levelsq; /* and cubed */ N = 255. / (levels - 1.); /* Get size of each step */ /* * Set up the color map entries. */ for(i = 0; i < levelsc; i++) { rgbmap[i][0] = gammamap[(int)(.5 + (i%levels) * N)]; rgbmap[i][1] = gammamap[(int)(.5 + ((i/levels)%levels) * N)]; rgbmap[i][2] = gammamap[(int)(.5 + ((i/levelsq)%levels) * N)]; } create_square( N, divN, modN, magic ); } void create_square( N, divN, modN, magic ) double N; int divN[256]; int modN[256]; int magic[16][16] ; { register int i, j, k, l; double magicfact; for ( i = 0; i < 256; i++ ) { divN[i] = (int)(i / N); modN[i] = i - (int)(N * divN[i]); } modN[255] = 0; /* always */ /* * Expand 4x4 dither pattern to 16x16. 4x4 leaves obvious patterning, * and doesn't give us full intensity range (only 17 sublevels). * * magicfact is (N - 1)/16 so that we get numbers in the matrix from 0 to * N - 1: mod N gives numbers in 0 to N - 1, don't ever want all * pixels incremented to the next level (this is reserved for the * pixel value with mod N == 0 at the next level). */ magicfact = (N - 1) / 16.; for ( i = 0; i < 4; i++ ) for ( j = 0; j < 4; j++ ) for ( k = 0; k < 4; k++ ) for ( l = 0; l < 4; l++ ) magic[4*k+i][4*l+j] = (int)(0.5 + magic4x4[i][j] * magicfact + (magic4x4[k][l] / 16.) * magicfact); }