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