Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
dither.c
Go to the documentation of this file.
1 /*
2  * This software is copyrighted as noted below. It may be freely copied,
3  * modified, and redistributed, provided that the copyright notice is
4  * preserved on all copies.
5  *
6  * There is no warranty or other guarantee of fitness for this software,
7  * it is provided solely "as is". Bug reports or fixes may be sent
8  * to the author, who may or may not act on them as he desires.
9  *
10  * You may not include this software in a program or other software product
11  * without supplying the source, or without informing the end-user that the
12  * source is available for no extra charge.
13  *
14  * If you modify this software, you should include a notice giving the
15  * name of the person performing the modification, the date of modification,
16  * and the reason for such modification.
17  *
18  * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
19  * to have all "void" functions so declared.
20  */
21 /*
22  * dither.c - Functions for RGB color dithering.
23  *
24  * Author: Spencer W. Thomas
25  * Computer Science Dept.
26  * University of Utah
27  * Date: Mon Feb 2 1987
28  * Copyright (c) 1987, University of Utah
29  */
30 static char rcsid[] = "$Header: /l/spencer/src/urt/lib/RCS/dither.c,v 3.0.1.2 1992/04/30 14:07:02 spencer Exp $";
31 
32 #include <math.h>
33 
34 #ifdef USE_PROTOTYPES
35 void make_square( double, int [256], int [256], int [16][16] );
36 #else
37 void make_square();
38 #endif
39 
40 static int magic4x4[4][4] = {
41 { 0, 14, 3, 13},
42 { 11, 5, 8, 6},
43 { 12, 2, 15, 1},
44 { 7, 9, 4, 10}
45 };
46 
47 /* basic dithering macro */
48 #define DMAP(v,x,y) (modN[v]>magic[x][y] ? divN[v] + 1 : divN[v])
49 
50 
51 /*****************************************************************
52  * TAG( dithermap )
53  *
54  * Create a color dithering map with a specified number of intensity levels.
55  * Inputs:
56  * levels: Intensity levels per primary.
57  * gamma: Display gamma value.
58  * Outputs:
59  * rgbmap: Generated color map.
60  * divN: "div" function for dithering.
61  * modN: "mod" function for dithering.
62  * Assumptions:
63  * rgbmap will hold levels^3 entries.
64  * Algorithm:
65  * Compute gamma compensation map.
66  * N = 255.0 / (levels - 1) is number of pixel values per level.
67  * Compute rgbmap with red ramping fastest, green slower, and blue
68  * slowest (treat it as if it were rgbmap[levels][levels][levels][3]).
69  * Call make_square to get divN, modN, and magic
70  *
71  * Note:
72  * Call dithergb( x, y, r, g, b, levels, divN, modN, magic ) to get index
73  * into rgbmap for a given color/location pair, or use
74  * row = y % 16; col = x % 16;
75  * DMAP(v,col,row) =def (divN[v] + (modN[v]>magic[col][row] ? 1 : 0))
76  * DMAP(r,col,row) + DMAP(g,col,row)*levels + DMAP(b,col,row)*levels^2
77  * if you don't want function call overhead.
78  */
79 void
81 int levels;
82 double gamma;
83 int rgbmap[][3];
84 int divN[256];
85 int modN[256];
86 int magic[16][16];
87 {
88  double N;
89  register int i;
90  int levelsq, levelsc;
91  int gammamap[256];
92 
93  for ( i = 0; i < 256; i++ )
94  gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
95 
96  levelsq = levels*levels; /* squared */
97  levelsc = levels*levelsq; /* and cubed */
98 
99  N = 255.0 / (levels - 1); /* Get size of each step */
100 
101  /*
102  * Set up the color map entries.
103  */
104  for(i = 0; i < levelsc; i++) {
105  rgbmap[i][0] = gammamap[(int)(0.5 + (i%levels) * N)];
106  rgbmap[i][1] = gammamap[(int)(0.5 + ((i/levels)%levels) * N)];
107  rgbmap[i][2] = gammamap[(int)(0.5 + ((i/levelsq)%levels) * N)];
108  }
109 
110  make_square( N, divN, modN, magic );
111 }
112 
113 
114 /*****************************************************************
115  * TAG( bwdithermap )
116  *
117  * Create a color dithering map with a specified number of intensity levels.
118  * Inputs:
119  * levels: Intensity levels.
120  * gamma: Display gamma value.
121  * Outputs:
122  * bwmap: Generated black & white map.
123  * divN: "div" function for dithering.
124  * modN: "mod" function for dithering.
125  * Assumptions:
126  * bwmap will hold levels entries.
127  * Algorithm:
128  * Compute gamma compensation map.
129  * N = 255.0 / (levels - 1) is number of pixel values per level.
130  * Compute bwmap for levels entries.
131  * Call make_square to get divN, modN, and magic.
132  * Note:
133  * Call ditherbw( x, y, val, divN, modN, magic ) to get index into
134  * bwmap for a given color/location pair, or use
135  * row = y % 16; col = x % 16;
136  * divN[val] + (modN[val]>magic[col][row] ? 1 : 0)
137  * if you don't want function call overhead.
138  * On a 1-bit display, use
139  * divN[val] > magic[col][row] ? 1 : 0
140  */
141 void
143 int levels;
144 double gamma;
145 int bwmap[];
146 int divN[256];
147 int modN[256];
148 int magic[16][16];
149 {
150  double N;
151  register int i;
152  int gammamap[256];
153 
154  for ( i = 0; i < 256; i++ )
155  gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
156 
157  N = 255.0 / (levels - 1); /* Get size of each step */
158 
159  /*
160  * Set up the color map entries.
161  */
162  for(i = 0; i < levels; i++)
163  bwmap[i] = gammamap[(int)(0.5 + i * N)];
164 
165  make_square( N, divN, modN, magic );
166 }
167 
168 
169 /*****************************************************************
170  * TAG( make_square )
171  *
172  * Build the magic square for a given number of levels.
173  * Inputs:
174  * N: Pixel values per level (255.0 / levels).
175  * Outputs:
176  * divN: Integer value of pixval / N
177  * modN: Integer remainder between pixval and divN[pixval]*N
178  * magic: Magic square for dithering to N sublevels.
179  * Assumptions:
180  *
181  * Algorithm:
182  * divN[pixval] = (int)(pixval / N) maps pixval to its appropriate level.
183  * modN[pixval] = pixval - (int)(N * divN[pixval]) maps pixval to
184  * its sublevel, and is used in the dithering computation.
185  * The magic square is computed as the (modified) outer product of
186  * a 4x4 magic square with itself.
187  * magic[4*k + i][4*l + j] = (magic4x4[i][j] + magic4x4[k][l]/16.0)
188  * multiplied by an appropriate factor to get the correct dithering
189  * range.
190  */
191 void
193 double N;
194 int divN[256];
195 int modN[256];
196 int magic[16][16] ;
197 {
198  register int i, j, k, l;
199  double magicfact;
200 
201  for ( i = 0; i < 256; i++ )
202  {
203  divN[i] = (int)(i / N);
204  modN[i] = i - (int)(N * divN[i]);
205  }
206  modN[255] = 0; /* always */
207 
208  /*
209  * Expand 4x4 dither pattern to 16x16. 4x4 leaves obvious patterning,
210  * and doesn't give us full intensity range (only 17 sublevels).
211  *
212  * magicfact is (N - 1)/16 so that we get numbers in the matrix from 0 to
213  * N - 1: mod N gives numbers in 0 to N - 1, don't ever want all
214  * pixels incremented to the next level (this is reserved for the
215  * pixel value with mod N == 0 at the next level).
216  */
217  magicfact = (N - 1) / 16.;
218  for ( i = 0; i < 4; i++ )
219  for ( j = 0; j < 4; j++ )
220  for ( k = 0; k < 4; k++ )
221  for ( l = 0; l < 4; l++ )
222  magic[4*k+i][4*l+j] =
223  (int)(0.5 + magic4x4[i][j] * magicfact +
224  (magic4x4[k][l] / 16.) * magicfact);
225 }
226 
227 
228 /*****************************************************************
229  * TAG( dithergb )
230  *
231  * Return dithered RGB value.
232  * Inputs:
233  * x: X location on screen of this pixel.
234  * y: Y location on screen of this pixel.
235  * r, g, b: Color at this pixel (0 - 255 range).
236  * levels: Number of levels in this map.
237  * divN, modN: From dithermap.
238  * magic: Magic square from dithermap.
239  * Outputs:
240  * Returns color map index for dithered pixelv value.
241  * Assumptions:
242  * divN, modN, magic were set up properly.
243  * Algorithm:
244  * see "Note:" in dithermap comment.
245  */
246 int
248 int x, y, r, g, b, levels;
249 int divN[256];
250 int modN[256];
251 int magic[16][16];
252 {
253  int col = x % 16, row = y % 16;
254 
255  return DMAP(r, col, row) +
256  DMAP(g, col, row) * levels +
257  DMAP(b, col, row) * levels*levels;
258 }
259 
260 
261 /*****************************************************************
262  * TAG( ditherbw )
263  *
264  * Return dithered black & white value.
265  * Inputs:
266  * x: X location on screen of this pixel.
267  * y: Y location on screen of this pixel.
268  * val: Intensity at this pixel (0 - 255 range).
269  * divN, modN: From dithermap.
270  * magic: Magic square from dithermap.
271  * Outputs:
272  * Returns color map index for dithered pixel value.
273  * Assumptions:
274  * divN, modN, magic were set up properly.
275  * Algorithm:
276  * see "Note:" in bwdithermap comment.
277  */
278 int
280 int x, y, val;
281 int divN[256];
282 int modN[256];
283 int magic[16][16];
284 {
285  int col = x % 16, row = y % 16;
286 
287  return DMAP(val, col, row);
288 }
void make_square(double N, divN, modN, magic)
Definition: dither.c:192
void dithermap(int levels, double gamma, rgbmap, divN, modN, magic)
Definition: dither.c:80
static char rcsid[]
Definition: dither.c:30
int ditherbw(int x, int y, int val, divN, modN, magic)
Definition: dither.c:279
static int magic4x4[4][4]
Definition: dither.c:40
#define DMAP(v, x, y)
Definition: get_orion.c:310
int dithergb(int x, int y, int r, int g, int b, int levels, divN, modN, magic)
Definition: dither.c:247
void bwdithermap(int levels, double gamma, bwmap, divN, modN, magic)
Definition: dither.c:142