]> git.ipfire.org Git - thirdparty/cups.git/blame - driver/dither.c
Merge changes from CUPS 1.5.1-r9875.
[thirdparty/cups.git] / driver / dither.c
CommitLineData
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
36void
37cupsDitherDelete(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
48void
49cupsDitherLine(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
287cups_dither_t * /* O - New state array */
288cupsDitherNew(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 */