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