• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   Dithering routines for CUPS.
3  *
4  *   Copyright 2007 by Apple Inc.
5  *   Copyright 1993-2005 by Easy Software Products.
6  *
7  *   These coded instructions, statements, and computer programs are the
8  *   property of Apple Inc. and are protected by Federal copyright
9  *   law.  Distribution and use rights are outlined in the file "COPYING"
10  *   which should have been included with this file.
11  *
12  * Contents:
13  *
14  *   cupsDitherDelete() - Free a dithering buffer.
15  *   cupsDitherLine()   - Dither a line of pixels...
16  *   cupsDitherNew()    - Create a dithering buffer.
17  */
18 
19 /*
20  * Include necessary headers.
21  */
22 
23 #include <config.h>
24 #include "driver.h"
25 
26 
27 /*
28  * 'cupsDitherDelete()' - Free a dithering buffer.
29  *
30  * Returns 0 on success, -1 on failure.
31  */
32 
33 void
cupsDitherDelete(cups_dither_t * d)34 cupsDitherDelete(cups_dither_t *d)	/* I - Dithering buffer */
35 {
36   if (d != NULL)
37     free(d);
38 }
39 
40 
41 /*
42  * 'cupsDitherLine()' - Dither a line of pixels...
43  */
44 
45 void
cupsDitherLine(cups_dither_t * d,const cups_lut_t * lut,const short * data,int num_channels,unsigned char * p)46 cupsDitherLine(cups_dither_t    *d,	/* I - Dither data */
47                const cups_lut_t *lut,	/* I - Lookup table */
48 	       const short      *data,	/* I - Separation data */
49 	       int              num_channels,
50 					/* I - Number of components */
51 	       unsigned char    *p)	/* O - Pixels */
52 {
53   register int	x,			/* Horizontal position in line... */
54 		pixel,			/* Current adjusted pixel... */
55 		e,			/* Current error */
56 		e0,e1,e2;		/* Error values */
57   register int	errval0,		/* First half of error value */
58   		errval1,		/* Second half of error value */
59 		errbase,		/* Base multiplier */
60 		errbase0,		/* Base multiplier for large values */
61 		errbase1,		/* Base multiplier for small values */
62 		errrange;		/* Range of random multiplier */
63   register int	*p0,			/* Error buffer pointers... */
64 		*p1;
65   static char	logtable[16384];	/* Error magnitude for randomness */
66   static char	loginit = 0;		/* Has the table been initialized? */
67 
68 
69   if (!loginit)
70   {
71    /*
72     * Initialize a logarithmic table for the magnitude of randomness
73     * that is introduced.
74     */
75 
76     loginit = 1;
77 
78     logtable[0] = 0;
79     for (x = 1; x < 2049; x ++)
80       logtable[x] = (int)(log(x / 16.0) / log(2.0) + 1.0);
81     for (; x < 16384; x ++)
82       logtable[x] = logtable[2049];
83   }
84 
85   if (d->row == 0)
86   {
87    /*
88     * Dither from left to right:
89     *
90     *       e0   ==        p0[0]
91     *    e1 e2   == p1[-1] p1[0]
92     */
93 
94     p0 = d->errors + 2;
95     p1 = d->errors + 2 + d->width + 4;
96     e0 = p0[0];
97     e1 = 0;
98     e2 = 0;
99 
100    /*
101     * Error diffuse each output pixel...
102     */
103 
104     for (x = d->width;
105 	 x > 0;
106 	 x --, p0 ++, p1 ++, p ++, data += num_channels)
107     {
108      /*
109       * Skip blank pixels...
110       */
111 
112       if (*data == 0)
113       {
114         *p     = 0;
115 	e0     = p0[1];
116 	p1[-1] = e1;
117 	e1     = e2;
118 	e2     = 0;
119 	continue;
120       }
121 
122      /*
123       * Compute the net pixel brightness and brightness error.  Set a dot
124       * if necessary...
125       */
126 
127       pixel = lut[*data].intensity + e0 / 128;
128 
129       if (pixel > CUPS_MAX_LUT)
130 	pixel = CUPS_MAX_LUT;
131       else if (pixel < 0)
132 	pixel = 0;
133 
134       *p = lut[pixel].pixel;
135       e  = lut[pixel].error;
136 
137      /*
138       * Set the randomness factor...
139       */
140 
141       if (e > 0)
142         errrange = logtable[e];
143       else
144         errrange = logtable[-e];
145 
146       errbase  = 8 - errrange;
147       errrange = errrange * 2 + 1;
148 
149      /*
150       * Randomize the error value.
151       */
152 
153       if (errrange > 1)
154       {
155         errbase0 = errbase + (CUPS_RAND() % errrange);
156         errbase1 = errbase + (CUPS_RAND() % errrange);
157       }
158       else
159         errbase0 = errbase1 = errbase;
160 
161      /*
162       *       X   7/16 =    X  e0
163       * 3/16 5/16 1/16 =    e1 e2
164       */
165 
166       errval0 = errbase0 * e;
167       errval1 = (16 - errbase0) * e;
168       e0      = p0[1] + 7 * errval0;
169       e1      = e2 + 5 * errval1;
170 
171       errval0 = errbase1 * e;
172       errval1 = (16 - errbase1) * e;
173       e2      = errval0;
174       p1[-1]  = e1 + 3 * errval1;
175     }
176   }
177   else
178   {
179    /*
180     * Dither from right to left:
181     *
182     *    e0      == p0[0]
183     *    e2 e1   == p1[0] p1[1]
184     */
185 
186     p0   = d->errors + d->width + 1 + d->width + 4;
187     p1   = d->errors + d->width + 1;
188     p    += d->width - 1;
189     data += num_channels * (d->width - 1);
190     e0   = p0[0];
191     e1   = 0;
192     e2   = 0;
193 
194    /*
195     * Error diffuse each output pixel...
196     */
197 
198     for (x = d->width;
199 	 x > 0;
200 	 x --, p0 --, p1 --, p --, data -= num_channels)
201     {
202      /*
203       * Skip blank pixels...
204       */
205 
206       if (*data == 0)
207       {
208         *p    = 0;
209 	e0    = p0[-1];
210 	p1[1] = e1;
211 	e1    = e2;
212 	e2    = 0;
213 	continue;
214       }
215 
216      /*
217       * Compute the net pixel brightness and brightness error.  Set a dot
218       * if necessary...
219       */
220 
221       pixel = lut[*data].intensity + e0 / 128;
222 
223       if (pixel > CUPS_MAX_LUT)
224 	pixel = CUPS_MAX_LUT;
225       else if (pixel < 0)
226 	pixel = 0;
227 
228       *p = lut[pixel].pixel;
229       e  = lut[pixel].error;
230 
231      /*
232       * Set the randomness factor...
233       */
234 
235       if (e > 0)
236         errrange = logtable[e];
237       else
238         errrange = logtable[-e];
239 
240       errbase  = 8 - errrange;
241       errrange = errrange * 2 + 1;
242 
243      /*
244       * Randomize the error value.
245       */
246 
247       if (errrange > 1)
248       {
249         errbase0 = errbase + (CUPS_RAND() % errrange);
250         errbase1 = errbase + (CUPS_RAND() % errrange);
251       }
252       else
253         errbase0 = errbase1 = errbase;
254 
255      /*
256       *       X   7/16 =    X  e0
257       * 3/16 5/16 1/16 =    e1 e2
258       */
259 
260       errval0 = errbase0 * e;
261       errval1 = (16 - errbase0) * e;
262       e0      = p0[-1] + 7 * errval0;
263       e1      = e2 + 5 * errval1;
264 
265       errval0 = errbase1 * e;
266       errval1 = (16 - errbase1) * e;
267       e2      = errval0;
268       p1[1]   = e1 + 3 * errval1;
269     }
270   }
271 
272  /*
273   * Update to the next row...
274   */
275 
276   d->row = 1 - d->row;
277 }
278 
279 
280 /*
281  * 'cupsDitherNew()' - Create an error-diffusion dithering buffer.
282  */
283 
284 cups_dither_t *			/* O - New state array */
cupsDitherNew(int width)285 cupsDitherNew(int width)	/* I - Width of output in pixels */
286 {
287   cups_dither_t	*d;		/* New dithering buffer */
288 
289 
290   if ((d = (cups_dither_t *)calloc(1, sizeof(cups_dither_t) +
291                                    2 * (width + 4) *
292 				       sizeof(int))) == NULL)
293     return (NULL);
294 
295   d->width = width;
296 
297   return (d);
298 }
299 
300