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