]>
Commit | Line | Data |
---|---|---|
ac884b6a MS |
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 | */ |