2 |
- |
1 |
/* Copyright (C) 1997, 2000 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: gdevpsds.c,v 1.14 2005/02/26 18:07:43 igor Exp $ */
|
|
|
18 |
/* Image processing streams for PostScript and PDF writers */
|
|
|
19 |
#include "gx.h"
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "gserrors.h"
|
|
|
22 |
#include "gxdcconv.h"
|
|
|
23 |
#include "gdevpsds.h"
|
|
|
24 |
#include "gxbitmap.h"
|
|
|
25 |
#include "gxcspace.h"
|
|
|
26 |
#include "gsdcolor.h"
|
|
|
27 |
#include "gscspace.h"
|
|
|
28 |
#include "gxdevcli.h"
|
|
|
29 |
|
|
|
30 |
/* ---------------- Convert between 1/2/4/12 and 8 bits ---------------- */
|
|
|
31 |
|
|
|
32 |
gs_private_st_simple(st_1248_state, stream_1248_state, "stream_1248_state");
|
|
|
33 |
|
|
|
34 |
/* Initialize an expansion or reduction stream. */
|
|
|
35 |
int
|
|
|
36 |
s_1248_init(stream_1248_state *ss, int Columns, int samples_per_pixel)
|
|
|
37 |
{
|
|
|
38 |
ss->samples_per_row = Columns * samples_per_pixel;
|
|
|
39 |
return ss->template->init((stream_state *)ss);
|
|
|
40 |
}
|
|
|
41 |
|
|
|
42 |
/* Initialize the state. */
|
|
|
43 |
private int
|
|
|
44 |
s_1_init(stream_state * st)
|
|
|
45 |
{
|
|
|
46 |
stream_1248_state *const ss = (stream_1248_state *) st;
|
|
|
47 |
|
|
|
48 |
ss->left = ss->samples_per_row;
|
|
|
49 |
ss->bits_per_sample = 1;
|
|
|
50 |
return 0;
|
|
|
51 |
}
|
|
|
52 |
private int
|
|
|
53 |
s_2_init(stream_state * st)
|
|
|
54 |
{
|
|
|
55 |
stream_1248_state *const ss = (stream_1248_state *) st;
|
|
|
56 |
|
|
|
57 |
ss->left = ss->samples_per_row;
|
|
|
58 |
ss->bits_per_sample = 2;
|
|
|
59 |
return 0;
|
|
|
60 |
}
|
|
|
61 |
private int
|
|
|
62 |
s_4_init(stream_state * st)
|
|
|
63 |
{
|
|
|
64 |
stream_1248_state *const ss = (stream_1248_state *) st;
|
|
|
65 |
|
|
|
66 |
ss->left = ss->samples_per_row;
|
|
|
67 |
ss->bits_per_sample = 4;
|
|
|
68 |
return 0;
|
|
|
69 |
}
|
|
|
70 |
private int
|
|
|
71 |
s_12_init(stream_state * st)
|
|
|
72 |
{
|
|
|
73 |
stream_1248_state *const ss = (stream_1248_state *) st;
|
|
|
74 |
|
|
|
75 |
ss->left = ss->samples_per_row;
|
|
|
76 |
ss->bits_per_sample = 12; /* not needed */
|
|
|
77 |
return 0;
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
/* Process one buffer. */
|
|
|
81 |
#define BEGIN_1248\
|
|
|
82 |
stream_1248_state * const ss = (stream_1248_state *)st;\
|
|
|
83 |
const byte *p = pr->ptr;\
|
|
|
84 |
const byte *rlimit = pr->limit;\
|
|
|
85 |
byte *q = pw->ptr;\
|
|
|
86 |
byte *wlimit = pw->limit;\
|
|
|
87 |
uint left = ss->left;\
|
|
|
88 |
int status;\
|
|
|
89 |
int n
|
|
|
90 |
#define END_1248\
|
|
|
91 |
pr->ptr = p;\
|
|
|
92 |
pw->ptr = q;\
|
|
|
93 |
ss->left = left;\
|
|
|
94 |
return status
|
|
|
95 |
|
|
|
96 |
/* N-to-8 expansion */
|
|
|
97 |
#define FOREACH_N_8(in, nout)\
|
|
|
98 |
status = 0;\
|
|
|
99 |
for ( ; p < rlimit; left -= n, q += n, ++p ) {\
|
|
|
100 |
byte in = p[1];\
|
|
|
101 |
n = min(left, nout);\
|
|
|
102 |
if ( wlimit - q < n ) {\
|
|
|
103 |
status = 1;\
|
|
|
104 |
break;\
|
|
|
105 |
}\
|
|
|
106 |
switch ( n ) {\
|
|
|
107 |
case 0: left = ss->samples_per_row; --p; continue;
|
|
|
108 |
#define END_FOREACH_N_8\
|
|
|
109 |
}\
|
|
|
110 |
}
|
|
|
111 |
private int
|
|
|
112 |
s_N_8_process(stream_state * st, stream_cursor_read * pr,
|
|
|
113 |
stream_cursor_write * pw, bool last)
|
|
|
114 |
{
|
|
|
115 |
BEGIN_1248;
|
|
|
116 |
|
|
|
117 |
switch (ss->bits_per_sample) {
|
|
|
118 |
|
|
|
119 |
case 1:{
|
|
|
120 |
FOREACH_N_8(in, 8)
|
|
|
121 |
case 8:
|
|
|
122 |
q[8] = (byte) - (in & 1);
|
|
|
123 |
case 7:
|
|
|
124 |
q[7] = (byte) - ((in >> 1) & 1);
|
|
|
125 |
case 6:
|
|
|
126 |
q[6] = (byte) - ((in >> 2) & 1);
|
|
|
127 |
case 5:
|
|
|
128 |
q[5] = (byte) - ((in >> 3) & 1);
|
|
|
129 |
case 4:
|
|
|
130 |
q[4] = (byte) - ((in >> 4) & 1);
|
|
|
131 |
case 3:
|
|
|
132 |
q[3] = (byte) - ((in >> 5) & 1);
|
|
|
133 |
case 2:
|
|
|
134 |
q[2] = (byte) - ((in >> 6) & 1);
|
|
|
135 |
case 1:
|
|
|
136 |
q[1] = (byte) - (in >> 7);
|
|
|
137 |
END_FOREACH_N_8;
|
|
|
138 |
}
|
|
|
139 |
break;
|
|
|
140 |
|
|
|
141 |
case 2:{
|
|
|
142 |
static const byte b2[4] =
|
|
|
143 |
{0x00, 0x55, 0xaa, 0xff};
|
|
|
144 |
|
|
|
145 |
FOREACH_N_8(in, 4)
|
|
|
146 |
case 4:
|
|
|
147 |
q[4] = b2[in & 3];
|
|
|
148 |
case 3:
|
|
|
149 |
q[3] = b2[(in >> 2) & 3];
|
|
|
150 |
case 2:
|
|
|
151 |
q[2] = b2[(in >> 4) & 3];
|
|
|
152 |
case 1:
|
|
|
153 |
q[1] = b2[in >> 6];
|
|
|
154 |
END_FOREACH_N_8;
|
|
|
155 |
}
|
|
|
156 |
break;
|
|
|
157 |
|
|
|
158 |
case 4:{
|
|
|
159 |
static const byte b4[16] =
|
|
|
160 |
{
|
|
|
161 |
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
|
|
162 |
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
|
|
|
163 |
};
|
|
|
164 |
|
|
|
165 |
FOREACH_N_8(in, 2)
|
|
|
166 |
case 2:
|
|
|
167 |
q[2] = b4[in & 0xf];
|
|
|
168 |
case 1:
|
|
|
169 |
q[1] = b4[in >> 4];
|
|
|
170 |
END_FOREACH_N_8;
|
|
|
171 |
}
|
|
|
172 |
break;
|
|
|
173 |
|
|
|
174 |
default:
|
|
|
175 |
return ERRC;
|
|
|
176 |
}
|
|
|
177 |
|
|
|
178 |
END_1248;
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
/* 12-to-8 "expansion" */
|
|
|
182 |
private int
|
|
|
183 |
s_12_8_process(stream_state * st, stream_cursor_read * pr,
|
|
|
184 |
stream_cursor_write * pw, bool last)
|
|
|
185 |
{
|
|
|
186 |
BEGIN_1248;
|
|
|
187 |
|
|
|
188 |
n = ss->samples_per_row; /* misuse n to avoid a compiler warning */
|
|
|
189 |
status = 0;
|
|
|
190 |
for (; rlimit - p >= 2; ++q) {
|
|
|
191 |
if (q >= wlimit) {
|
|
|
192 |
status = 1;
|
|
|
193 |
break;
|
|
|
194 |
}
|
|
|
195 |
if (left == 0)
|
|
|
196 |
left = n;
|
|
|
197 |
if ((n - left) & 1) {
|
|
|
198 |
q[1] = (byte)((p[1] << 4) | (p[2] >> 4));
|
|
|
199 |
p += 2, --left;
|
|
|
200 |
} else {
|
|
|
201 |
q[1] = *++p;
|
|
|
202 |
if (!--left)
|
|
|
203 |
++p;
|
|
|
204 |
}
|
|
|
205 |
}
|
|
|
206 |
|
|
|
207 |
END_1248;
|
|
|
208 |
}
|
|
|
209 |
|
|
|
210 |
|
|
|
211 |
/* 8-to-N reduction */
|
|
|
212 |
#define FOREACH_8_N(out, nin)\
|
|
|
213 |
byte out;\
|
|
|
214 |
status = 1;\
|
|
|
215 |
for ( ; q < wlimit; left -= n, p += n, ++q ) {\
|
|
|
216 |
n = min(left, nin);\
|
|
|
217 |
if ( rlimit - p < n ) {\
|
|
|
218 |
status = 0;\
|
|
|
219 |
break;\
|
|
|
220 |
}\
|
|
|
221 |
out = 0;\
|
|
|
222 |
switch ( n ) {\
|
|
|
223 |
case 0: left = ss->samples_per_row; --q; continue;
|
|
|
224 |
#define END_FOREACH_8_N\
|
|
|
225 |
q[1] = out;\
|
|
|
226 |
}\
|
|
|
227 |
}
|
|
|
228 |
private int
|
|
|
229 |
s_8_N_process(stream_state * st, stream_cursor_read * pr,
|
|
|
230 |
stream_cursor_write * pw, bool last)
|
|
|
231 |
{
|
|
|
232 |
BEGIN_1248;
|
|
|
233 |
|
|
|
234 |
switch (ss->bits_per_sample) {
|
|
|
235 |
|
|
|
236 |
case 1:{
|
|
|
237 |
FOREACH_8_N(out, 8)
|
|
|
238 |
case 8:
|
|
|
239 |
out = p[8] >> 7;
|
|
|
240 |
case 7:
|
|
|
241 |
out |= (p[7] >> 7) << 1;
|
|
|
242 |
case 6:
|
|
|
243 |
out |= (p[6] >> 7) << 2;
|
|
|
244 |
case 5:
|
|
|
245 |
out |= (p[5] >> 7) << 3;
|
|
|
246 |
case 4:
|
|
|
247 |
out |= (p[4] >> 7) << 4;
|
|
|
248 |
case 3:
|
|
|
249 |
out |= (p[3] >> 7) << 5;
|
|
|
250 |
case 2:
|
|
|
251 |
out |= (p[2] >> 7) << 6;
|
|
|
252 |
case 1:
|
|
|
253 |
out |= p[1] & 0x80;
|
|
|
254 |
END_FOREACH_8_N;
|
|
|
255 |
}
|
|
|
256 |
break;
|
|
|
257 |
|
|
|
258 |
case 2:{
|
|
|
259 |
FOREACH_8_N(out, 4)
|
|
|
260 |
case 4:
|
|
|
261 |
out |= p[4] >> 6;
|
|
|
262 |
case 3:
|
|
|
263 |
out |= (p[3] >> 6) << 2;
|
|
|
264 |
case 2:
|
|
|
265 |
out |= (p[2] >> 6) << 4;
|
|
|
266 |
case 1:
|
|
|
267 |
out |= p[1] & 0xc0;
|
|
|
268 |
END_FOREACH_8_N;
|
|
|
269 |
}
|
|
|
270 |
break;
|
|
|
271 |
|
|
|
272 |
case 4:{
|
|
|
273 |
FOREACH_8_N(out, 2)
|
|
|
274 |
case 2:
|
|
|
275 |
out |= p[2] >> 4;
|
|
|
276 |
case 1:
|
|
|
277 |
out |= p[1] & 0xf0;
|
|
|
278 |
END_FOREACH_8_N;
|
|
|
279 |
}
|
|
|
280 |
break;
|
|
|
281 |
|
|
|
282 |
default:
|
|
|
283 |
return ERRC;
|
|
|
284 |
}
|
|
|
285 |
|
|
|
286 |
END_1248;
|
|
|
287 |
}
|
|
|
288 |
|
|
|
289 |
const stream_template s_1_8_template = {
|
|
|
290 |
&st_1248_state, s_1_init, s_N_8_process, 1, 8
|
|
|
291 |
};
|
|
|
292 |
const stream_template s_2_8_template = {
|
|
|
293 |
&st_1248_state, s_2_init, s_N_8_process, 1, 4
|
|
|
294 |
};
|
|
|
295 |
const stream_template s_4_8_template = {
|
|
|
296 |
&st_1248_state, s_4_init, s_N_8_process, 1, 2
|
|
|
297 |
};
|
|
|
298 |
const stream_template s_12_8_template = {
|
|
|
299 |
&st_1248_state, s_12_init, s_12_8_process, 1, 2
|
|
|
300 |
};
|
|
|
301 |
|
|
|
302 |
const stream_template s_8_1_template = {
|
|
|
303 |
&st_1248_state, s_1_init, s_8_N_process, 8, 1
|
|
|
304 |
};
|
|
|
305 |
const stream_template s_8_2_template = {
|
|
|
306 |
&st_1248_state, s_2_init, s_8_N_process, 4, 1
|
|
|
307 |
};
|
|
|
308 |
const stream_template s_8_4_template = {
|
|
|
309 |
&st_1248_state, s_4_init, s_8_N_process, 2, 1
|
|
|
310 |
};
|
|
|
311 |
|
|
|
312 |
/* ---------------- Color space conversion ---------------- */
|
|
|
313 |
|
|
|
314 |
/* ------ Convert CMYK to RGB ------ */
|
|
|
315 |
|
|
|
316 |
private_st_C2R_state();
|
|
|
317 |
|
|
|
318 |
/* Initialize a CMYK => RGB conversion stream. */
|
|
|
319 |
int
|
|
|
320 |
s_C2R_init(stream_C2R_state *ss, const gs_imager_state *pis)
|
|
|
321 |
{
|
|
|
322 |
ss->pis = pis;
|
|
|
323 |
return 0;
|
|
|
324 |
}
|
|
|
325 |
|
|
|
326 |
/* Set default parameter values (actually, just clear pointers). */
|
|
|
327 |
private void
|
|
|
328 |
s_C2R_set_defaults(stream_state * st)
|
|
|
329 |
{
|
|
|
330 |
stream_C2R_state *const ss = (stream_C2R_state *) st;
|
|
|
331 |
|
|
|
332 |
ss->pis = 0;
|
|
|
333 |
}
|
|
|
334 |
|
|
|
335 |
/* Process one buffer. */
|
|
|
336 |
private int
|
|
|
337 |
s_C2R_process(stream_state * st, stream_cursor_read * pr,
|
|
|
338 |
stream_cursor_write * pw, bool last)
|
|
|
339 |
{
|
|
|
340 |
stream_C2R_state *const ss = (stream_C2R_state *) st;
|
|
|
341 |
const byte *p = pr->ptr;
|
|
|
342 |
const byte *rlimit = pr->limit;
|
|
|
343 |
byte *q = pw->ptr;
|
|
|
344 |
byte *wlimit = pw->limit;
|
|
|
345 |
|
|
|
346 |
for (; rlimit - p >= 4 && wlimit - q >= 3; p += 4, q += 3) {
|
|
|
347 |
byte bc = p[1], bm = p[2], by = p[3], bk = p[4];
|
|
|
348 |
frac rgb[3];
|
|
|
349 |
|
|
|
350 |
color_cmyk_to_rgb(byte2frac(bc), byte2frac(bm), byte2frac(by),
|
|
|
351 |
byte2frac(bk), ss->pis, rgb);
|
|
|
352 |
q[1] = frac2byte(rgb[0]);
|
|
|
353 |
q[2] = frac2byte(rgb[1]);
|
|
|
354 |
q[3] = frac2byte(rgb[2]);
|
|
|
355 |
}
|
|
|
356 |
pr->ptr = p;
|
|
|
357 |
pw->ptr = q;
|
|
|
358 |
return (rlimit - p < 4 ? 0 : 1);
|
|
|
359 |
}
|
|
|
360 |
|
|
|
361 |
const stream_template s_C2R_template = {
|
|
|
362 |
&st_C2R_state, 0 /*NULL */ , s_C2R_process, 4, 3, 0, s_C2R_set_defaults
|
|
|
363 |
};
|
|
|
364 |
|
|
|
365 |
/* ------ Convert any color space to Indexed ------ */
|
|
|
366 |
|
|
|
367 |
private_st_IE_state();
|
|
|
368 |
private
|
|
|
369 |
ENUM_PTRS_WITH(ie_state_enum_ptrs, stream_IE_state *st) return 0;
|
|
|
370 |
case 0: return ENUM_OBJ(st->Decode);
|
|
|
371 |
case 1: return ENUM_BYTESTRING(&st->Table);
|
|
|
372 |
ENUM_PTRS_END
|
|
|
373 |
private
|
|
|
374 |
RELOC_PTRS_WITH(ie_state_reloc_ptrs, stream_IE_state *st)
|
|
|
375 |
{
|
|
|
376 |
RELOC_VAR(st->Decode);
|
|
|
377 |
RELOC_BYTESTRING_VAR(st->Table);
|
|
|
378 |
}
|
|
|
379 |
RELOC_PTRS_END
|
|
|
380 |
|
|
|
381 |
/* Set defaults. */
|
|
|
382 |
private void
|
|
|
383 |
s_IE_set_defaults(stream_state * st)
|
|
|
384 |
{
|
|
|
385 |
stream_IE_state *const ss = (stream_IE_state *) st;
|
|
|
386 |
|
|
|
387 |
ss->Decode = 0; /* clear pointers */
|
|
|
388 |
gs_bytestring_from_string(&ss->Table, 0, 0);
|
|
|
389 |
}
|
|
|
390 |
|
|
|
391 |
/* Initialize the state. */
|
|
|
392 |
private int
|
|
|
393 |
s_IE_init(stream_state * st)
|
|
|
394 |
{
|
|
|
395 |
stream_IE_state *const ss = (stream_IE_state *) st;
|
|
|
396 |
int key_index = (1 << ss->BitsPerIndex) * ss->NumComponents;
|
|
|
397 |
int i;
|
|
|
398 |
|
|
|
399 |
if (ss->Table.data == 0 || ss->Table.size < key_index)
|
|
|
400 |
return ERRC; /****** WRONG ******/
|
|
|
401 |
/* Initialize Table with default values. */
|
|
|
402 |
memset(ss->Table.data, 0, ss->NumComponents);
|
|
|
403 |
ss->Table.data[ss->Table.size - 1] = 0;
|
|
|
404 |
for (i = 0; i < countof(ss->hash_table); ++i)
|
|
|
405 |
ss->hash_table[i] = key_index;
|
|
|
406 |
ss->next_index = 0;
|
|
|
407 |
ss->in_bits_left = 0;
|
|
|
408 |
ss->next_component = 0;
|
|
|
409 |
ss->byte_out = 1;
|
|
|
410 |
ss->x = 0;
|
|
|
411 |
return 0;
|
|
|
412 |
}
|
|
|
413 |
|
|
|
414 |
/* Process a buffer. */
|
|
|
415 |
private int
|
|
|
416 |
s_IE_process(stream_state * st, stream_cursor_read * pr,
|
|
|
417 |
stream_cursor_write * pw, bool last)
|
|
|
418 |
{
|
|
|
419 |
stream_IE_state *const ss = (stream_IE_state *) st;
|
|
|
420 |
/* Constant values from the state */
|
|
|
421 |
const int bpc = ss->BitsPerComponent;
|
|
|
422 |
const int num_components = ss->NumComponents;
|
|
|
423 |
const int end_index = (1 << ss->BitsPerIndex) * num_components;
|
|
|
424 |
byte *const table = ss->Table.data;
|
|
|
425 |
byte *const key = table + end_index;
|
|
|
426 |
/* Dynamic values from the state */
|
|
|
427 |
uint byte_in = ss->byte_in;
|
|
|
428 |
int in_bits_left = ss->in_bits_left;
|
|
|
429 |
int next_component = ss->next_component;
|
|
|
430 |
uint byte_out = ss->byte_out;
|
|
|
431 |
/* Other dynamic values */
|
|
|
432 |
const byte *p = pr->ptr;
|
|
|
433 |
const byte *rlimit = pr->limit;
|
|
|
434 |
byte *q = pw->ptr;
|
|
|
435 |
byte *wlimit = pw->limit;
|
|
|
436 |
int status = 0;
|
|
|
437 |
|
|
|
438 |
for (;;) {
|
|
|
439 |
uint hash, reprobe;
|
|
|
440 |
int i, index;
|
|
|
441 |
|
|
|
442 |
/* Check for a filled output byte. */
|
|
|
443 |
if (byte_out >= 0x100) {
|
|
|
444 |
if (q >= wlimit) {
|
|
|
445 |
status = 1;
|
|
|
446 |
break;
|
|
|
447 |
}
|
|
|
448 |
*++q = (byte)byte_out;
|
|
|
449 |
byte_out = 1;
|
|
|
450 |
}
|
|
|
451 |
/* Acquire a complete input value. */
|
|
|
452 |
while (next_component < num_components) {
|
|
|
453 |
const float *decode = &ss->Decode[next_component * 2];
|
|
|
454 |
int sample;
|
|
|
455 |
|
|
|
456 |
if (in_bits_left == 0) {
|
|
|
457 |
if (p >= rlimit)
|
|
|
458 |
goto out;
|
|
|
459 |
byte_in = *++p;
|
|
|
460 |
in_bits_left = 8;
|
|
|
461 |
}
|
|
|
462 |
/* An input sample can never span a byte boundary. */
|
|
|
463 |
in_bits_left -= bpc;
|
|
|
464 |
sample = (byte_in >> in_bits_left) & ((1 << bpc) - 1);
|
|
|
465 |
/* Scale the sample according to Decode. */
|
|
|
466 |
sample = (int)((decode[0] +
|
|
|
467 |
(sample / (float)((1 << bpc) - 1) *
|
|
|
468 |
(decode[1] - decode[0]))) * 255 + 0.5);
|
|
|
469 |
key[next_component++] =
|
|
|
470 |
(sample < 0 ? 0 : sample > 255 ? 255 : (byte)sample);
|
|
|
471 |
}
|
|
|
472 |
/* Look up the input value. */
|
|
|
473 |
for (hash = 0, i = 0; i < num_components; ++i)
|
|
|
474 |
hash = hash + 23 * key[i]; /* adhoc */
|
|
|
475 |
reprobe = (hash / countof(ss->hash_table)) | 137; /* adhoc */
|
|
|
476 |
for (hash %= countof(ss->hash_table);
|
|
|
477 |
memcmp(table + ss->hash_table[hash], key, num_components);
|
|
|
478 |
hash = (hash + reprobe) % countof(ss->hash_table)
|
|
|
479 |
)
|
|
|
480 |
DO_NOTHING;
|
|
|
481 |
index = ss->hash_table[hash];
|
|
|
482 |
if (index == end_index) {
|
|
|
483 |
/* The match was on an empty entry. */
|
|
|
484 |
if (ss->next_index == end_index) {
|
|
|
485 |
/* Too many different values. */
|
|
|
486 |
status = ERRC;
|
|
|
487 |
break;
|
|
|
488 |
}
|
|
|
489 |
ss->hash_table[hash] = index = ss->next_index;
|
|
|
490 |
ss->next_index += num_components;
|
|
|
491 |
memcpy(table + index, key, num_components);
|
|
|
492 |
}
|
|
|
493 |
byte_out = (byte_out << ss->BitsPerIndex) + index / num_components;
|
|
|
494 |
next_component = 0;
|
|
|
495 |
if (++(ss->x) == ss->Width) {
|
|
|
496 |
/* Handle input and output padding. */
|
|
|
497 |
in_bits_left = 0;
|
|
|
498 |
if (byte_out != 1)
|
|
|
499 |
while (byte_out < 0x100)
|
|
|
500 |
byte_out <<= 1;
|
|
|
501 |
ss->x = 0;
|
|
|
502 |
}
|
|
|
503 |
}
|
|
|
504 |
out:
|
|
|
505 |
pr->ptr = p;
|
|
|
506 |
pw->ptr = q;
|
|
|
507 |
ss->byte_in = byte_in;
|
|
|
508 |
ss->in_bits_left = in_bits_left;
|
|
|
509 |
ss->next_component = next_component;
|
|
|
510 |
ss->byte_out = byte_out;
|
|
|
511 |
/* For simplicity, always update the record of the table size. */
|
|
|
512 |
ss->Table.data[ss->Table.size - 1] =
|
|
|
513 |
(ss->next_index == 0 ? 0 :
|
|
|
514 |
ss->next_index / ss->NumComponents - 1);
|
|
|
515 |
return status;
|
|
|
516 |
}
|
|
|
517 |
|
|
|
518 |
const stream_template s_IE_template = {
|
|
|
519 |
&st_IE_state, s_IE_init, s_IE_process, 1, 1,
|
|
|
520 |
|
|
|
521 |
};
|
|
|
522 |
|
|
|
523 |
#if 0
|
|
|
524 |
|
|
|
525 |
/* Test code */
|
|
|
526 |
void
|
|
|
527 |
test_IE(void)
|
|
|
528 |
{
|
|
|
529 |
const stream_template *const template = &s_IE_template;
|
|
|
530 |
stream_IE_state state;
|
|
|
531 |
stream_state *const ss = (stream_state *)&state;
|
|
|
532 |
static const float decode[6] = {1, 0, 1, 0, 1, 0};
|
|
|
533 |
static const byte in[] = {
|
|
|
534 |
/*
|
|
|
535 |
* Each row is 3 pixels x 3 components x 4 bits. Processing the
|
|
|
536 |
* first two rows doesn't cause an error; processing all 3 rows
|
|
|
537 |
* does.
|
|
|
538 |
*/
|
|
|
539 |
0x12, 0x35, 0x67, 0x9a, 0xb0,
|
|
|
540 |
0x56, 0x7d, 0xef, 0x12, 0x30,
|
|
|
541 |
0x88, 0x88, 0x88, 0x88, 0x80
|
|
|
542 |
};
|
|
|
543 |
byte table[3 * 5];
|
|
|
544 |
int n;
|
|
|
545 |
|
|
|
546 |
template->set_defaults(ss);
|
|
|
547 |
state.BitsPerComponent = 4;
|
|
|
548 |
state.NumComponents = 3;
|
|
|
549 |
state.Width = 3;
|
|
|
550 |
state.BitsPerIndex = 2;
|
|
|
551 |
state.Decode = decode;
|
|
|
552 |
gs_bytestring_from_bytes(&state.Table, table, 0, sizeof(table));
|
|
|
553 |
for (n = 10; n <= 15; n += 5) {
|
|
|
554 |
stream_cursor_read r;
|
|
|
555 |
stream_cursor_write w;
|
|
|
556 |
byte out[100];
|
|
|
557 |
int status;
|
|
|
558 |
|
|
|
559 |
s_IE_init(ss);
|
|
|
560 |
r.ptr = in; --r.ptr;
|
|
|
561 |
r.limit = r.ptr + n;
|
|
|
562 |
w.ptr = out; --w.ptr;
|
|
|
563 |
w.limit = w.ptr + sizeof(out);
|
|
|
564 |
memset(table, 0xcc, sizeof(table));
|
|
|
565 |
memset(out, 0xff, sizeof(out));
|
|
|
566 |
dprintf1("processing %d bytes\n", n);
|
|
|
567 |
status = template->process(ss, &r, &w, true);
|
|
|
568 |
dprintf3("%d bytes read, %d bytes written, status = %d\n",
|
|
|
569 |
(int)(r.ptr + 1 - in), (int)(w.ptr + 1 - out), status);
|
|
|
570 |
debug_dump_bytes(table, table + sizeof(table), "table");
|
|
|
571 |
debug_dump_bytes(out, w.ptr + 1, "out");
|
|
|
572 |
}
|
|
|
573 |
}
|
|
|
574 |
|
|
|
575 |
#endif
|
|
|
576 |
|
|
|
577 |
/* ---------------- Downsampling ---------------- */
|
|
|
578 |
|
|
|
579 |
/* Return the number of samples after downsampling. */
|
|
|
580 |
int
|
|
|
581 |
s_Downsample_size_out(int size_in, int factor, bool pad)
|
|
|
582 |
{
|
|
|
583 |
return ((pad ? size_in + factor - 1 : size_in) / factor);
|
|
|
584 |
}
|
|
|
585 |
|
|
|
586 |
private void
|
|
|
587 |
s_Downsample_set_defaults(register stream_state * st)
|
|
|
588 |
{
|
|
|
589 |
stream_Downsample_state *const ss = (stream_Downsample_state *)st;
|
|
|
590 |
|
|
|
591 |
s_Downsample_set_defaults_inline(ss);
|
|
|
592 |
}
|
|
|
593 |
|
|
|
594 |
/* ------ Subsample ------ */
|
|
|
595 |
|
|
|
596 |
gs_private_st_simple(st_Subsample_state, stream_Subsample_state,
|
|
|
597 |
"stream_Subsample_state");
|
|
|
598 |
|
|
|
599 |
/* Initialize the state. */
|
|
|
600 |
private int
|
|
|
601 |
s_Subsample_init(stream_state * st)
|
|
|
602 |
{
|
|
|
603 |
stream_Subsample_state *const ss = (stream_Subsample_state *) st;
|
|
|
604 |
|
|
|
605 |
ss->x = ss->y = 0;
|
|
|
606 |
return 0;
|
|
|
607 |
}
|
|
|
608 |
|
|
|
609 |
/* Process one buffer. */
|
|
|
610 |
private int
|
|
|
611 |
s_Subsample_process(stream_state * st, stream_cursor_read * pr,
|
|
|
612 |
stream_cursor_write * pw, bool last)
|
|
|
613 |
{
|
|
|
614 |
stream_Subsample_state *const ss = (stream_Subsample_state *) st;
|
|
|
615 |
const byte *p = pr->ptr;
|
|
|
616 |
const byte *rlimit = pr->limit;
|
|
|
617 |
byte *q = pw->ptr;
|
|
|
618 |
byte *wlimit = pw->limit;
|
|
|
619 |
int spp = ss->Colors;
|
|
|
620 |
int width = ss->WidthIn, height = ss->HeightIn;
|
|
|
621 |
int xf = ss->XFactor, yf = ss->YFactor;
|
|
|
622 |
int xf2 = xf / 2, yf2 = yf / 2;
|
|
|
623 |
int xlimit = (width / xf) * xf, ylimit = (height / yf) * yf;
|
|
|
624 |
int xlast =
|
|
|
625 |
(ss->padX && xlimit < width ? xlimit + (width % xf) / 2 : -1);
|
|
|
626 |
int ylast =
|
|
|
627 |
(ss->padY && ylimit < height ? ylimit + (height % yf) / 2 : -1);
|
|
|
628 |
int x = ss->x, y = ss->y;
|
|
|
629 |
int status = 0;
|
|
|
630 |
|
|
|
631 |
if_debug4('w', "[w]subsample: x=%d, y=%d, rcount=%ld, wcount=%ld\n",
|
|
|
632 |
x, y, (long)(rlimit - p), (long)(wlimit - q));
|
|
|
633 |
for (; rlimit - p >= spp; p += spp) {
|
|
|
634 |
if (((y % yf == yf2 && y < ylimit) || y == ylast) &&
|
|
|
635 |
((x % xf == xf2 && x < xlimit) || x == xlast)
|
|
|
636 |
) {
|
|
|
637 |
if (wlimit - q < spp) {
|
|
|
638 |
status = 1;
|
|
|
639 |
break;
|
|
|
640 |
}
|
|
|
641 |
memcpy(q + 1, p + 1, spp);
|
|
|
642 |
q += spp;
|
|
|
643 |
}
|
|
|
644 |
if (++x == width)
|
|
|
645 |
x = 0, ++y;
|
|
|
646 |
}
|
|
|
647 |
if_debug5('w',
|
|
|
648 |
"[w]subsample: x'=%d, y'=%d, read %ld, wrote %ld, status = %d\n",
|
|
|
649 |
x, y, (long)(p - pr->ptr), (long)(q - pw->ptr), status);
|
|
|
650 |
pr->ptr = p;
|
|
|
651 |
pw->ptr = q;
|
|
|
652 |
ss->x = x, ss->y = y;
|
|
|
653 |
return status;
|
|
|
654 |
}
|
|
|
655 |
|
|
|
656 |
const stream_template s_Subsample_template = {
|
|
|
657 |
&st_Subsample_state, s_Subsample_init, s_Subsample_process, 4, 4,
|
|
|
658 |
|
|
|
659 |
};
|
|
|
660 |
|
|
|
661 |
/* ------ Average ------ */
|
|
|
662 |
|
|
|
663 |
private_st_Average_state();
|
|
|
664 |
|
|
|
665 |
/* Set default parameter values (actually, just clear pointers). */
|
|
|
666 |
private void
|
|
|
667 |
s_Average_set_defaults(stream_state * st)
|
|
|
668 |
{
|
|
|
669 |
stream_Average_state *const ss = (stream_Average_state *) st;
|
|
|
670 |
|
|
|
671 |
s_Downsample_set_defaults(st);
|
|
|
672 |
/* Clear pointers */
|
|
|
673 |
ss->sums = 0;
|
|
|
674 |
}
|
|
|
675 |
|
|
|
676 |
/* Initialize the state. */
|
|
|
677 |
private int
|
|
|
678 |
s_Average_init(stream_state * st)
|
|
|
679 |
{
|
|
|
680 |
stream_Average_state *const ss = (stream_Average_state *) st;
|
|
|
681 |
|
|
|
682 |
ss->sum_size =
|
|
|
683 |
ss->Colors * ((ss->WidthIn + ss->XFactor - 1) / ss->XFactor);
|
|
|
684 |
ss->copy_size = ss->sum_size -
|
|
|
685 |
(ss->padX || (ss->WidthIn % ss->XFactor == 0) ? 0 : ss->Colors);
|
|
|
686 |
ss->sums =
|
|
|
687 |
(uint *)gs_alloc_byte_array(st->memory, ss->sum_size,
|
|
|
688 |
sizeof(uint), "Average sums");
|
|
|
689 |
if (ss->sums == 0)
|
|
|
690 |
return ERRC; /****** WRONG ******/
|
|
|
691 |
memset(ss->sums, 0, ss->sum_size * sizeof(uint));
|
|
|
692 |
return s_Subsample_init(st);
|
|
|
693 |
}
|
|
|
694 |
|
|
|
695 |
/* Release the state. */
|
|
|
696 |
private void
|
|
|
697 |
s_Average_release(stream_state * st)
|
|
|
698 |
{
|
|
|
699 |
stream_Average_state *const ss = (stream_Average_state *) st;
|
|
|
700 |
|
|
|
701 |
gs_free_object(st->memory, ss->sums, "Average sums");
|
|
|
702 |
}
|
|
|
703 |
|
|
|
704 |
/* Process one buffer. */
|
|
|
705 |
private int
|
|
|
706 |
s_Average_process(stream_state * st, stream_cursor_read * pr,
|
|
|
707 |
stream_cursor_write * pw, bool last)
|
|
|
708 |
{
|
|
|
709 |
stream_Average_state *const ss = (stream_Average_state *) st;
|
|
|
710 |
const byte *p = pr->ptr;
|
|
|
711 |
const byte *rlimit = pr->limit;
|
|
|
712 |
byte *q = pw->ptr;
|
|
|
713 |
byte *wlimit = pw->limit;
|
|
|
714 |
int spp = ss->Colors;
|
|
|
715 |
int width = ss->WidthIn;
|
|
|
716 |
int xf = ss->XFactor, yf = ss->YFactor;
|
|
|
717 |
int x = ss->x, y = ss->y;
|
|
|
718 |
uint *sums = ss->sums;
|
|
|
719 |
int status = 0;
|
|
|
720 |
|
|
|
721 |
top:
|
|
|
722 |
if (y == yf || (last && p >= rlimit && ss->padY && y != 0)) {
|
|
|
723 |
/* We're copying averaged values to the output. */
|
|
|
724 |
int ncopy = min(ss->copy_size - x, wlimit - q);
|
|
|
725 |
|
|
|
726 |
if (ncopy) {
|
|
|
727 |
int scale = xf * y;
|
|
|
728 |
|
|
|
729 |
while (--ncopy >= 0)
|
|
|
730 |
*++q = (byte) (sums[x++] / scale);
|
|
|
731 |
}
|
|
|
732 |
if (x < ss->copy_size) {
|
|
|
733 |
status = 1;
|
|
|
734 |
goto out;
|
|
|
735 |
}
|
|
|
736 |
/* Done copying. */
|
|
|
737 |
x = y = 0;
|
|
|
738 |
memset(sums, 0, ss->sum_size * sizeof(uint));
|
|
|
739 |
}
|
|
|
740 |
while (rlimit - p >= spp) {
|
|
|
741 |
uint *bp = sums + x / xf * spp;
|
|
|
742 |
int i;
|
|
|
743 |
|
|
|
744 |
for (i = spp; --i >= 0;)
|
|
|
745 |
*bp++ += *++p;
|
|
|
746 |
if (++x == width) {
|
|
|
747 |
x = 0;
|
|
|
748 |
++y;
|
|
|
749 |
goto top;
|
|
|
750 |
}
|
|
|
751 |
}
|
|
|
752 |
out:
|
|
|
753 |
pr->ptr = p;
|
|
|
754 |
pw->ptr = q;
|
|
|
755 |
ss->x = x, ss->y = y;
|
|
|
756 |
return status;
|
|
|
757 |
}
|
|
|
758 |
|
|
|
759 |
const stream_template s_Average_template = {
|
|
|
760 |
&st_Average_state, s_Average_init, s_Average_process, 4, 4,
|
|
|
761 |
s_Average_release, s_Average_set_defaults
|
|
|
762 |
};
|
|
|
763 |
|
|
|
764 |
/* ---------------- Image compression chooser ---------------- */
|
|
|
765 |
|
|
|
766 |
private_st_compr_chooser_state();
|
|
|
767 |
|
|
|
768 |
/* Initialize the state. */
|
|
|
769 |
private int
|
|
|
770 |
s_compr_chooser_init(stream_state * st)
|
|
|
771 |
{
|
|
|
772 |
stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
|
|
|
773 |
|
|
|
774 |
ss->choice = 0;
|
|
|
775 |
ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
|
|
|
776 |
ss->sample = 0;
|
|
|
777 |
ss->samples_count = 0;
|
|
|
778 |
ss->bits_left = 0;
|
|
|
779 |
ss->packed_data = 0;
|
|
|
780 |
ss->lower_plateaus = ss->upper_plateaus = 0;
|
|
|
781 |
ss->gradients = 0;
|
|
|
782 |
return 0;
|
|
|
783 |
}
|
|
|
784 |
|
|
|
785 |
/* Set image dimensions. */
|
|
|
786 |
int
|
|
|
787 |
s_compr_chooser_set_dimensions(stream_compr_chooser_state * ss, int width,
|
|
|
788 |
int height, int depth, int bits_per_sample)
|
|
|
789 |
{
|
|
|
790 |
ss->width = width;
|
|
|
791 |
ss->height = height;
|
|
|
792 |
ss->depth = depth;
|
|
|
793 |
ss->bits_per_sample = bits_per_sample;
|
|
|
794 |
ss->sample = gs_alloc_bytes(ss->memory, width * depth, "s_compr_chooser_set_dimensions");
|
|
|
795 |
if (ss->sample == 0)
|
|
|
796 |
return_error(gs_error_VMerror);
|
|
|
797 |
return 0;
|
|
|
798 |
}
|
|
|
799 |
|
|
|
800 |
/* Release state. */
|
|
|
801 |
private void
|
|
|
802 |
s_compr_chooser_release(stream_state * st)
|
|
|
803 |
{
|
|
|
804 |
stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
|
|
|
805 |
|
|
|
806 |
gs_free_object(ss->memory, ss->sample, "s_compr_chooser_release");
|
|
|
807 |
}
|
|
|
808 |
|
|
|
809 |
/* Estimate a row for photo/lineart recognition. */
|
|
|
810 |
private void
|
|
|
811 |
s_compr_chooser__estimate_row(stream_compr_chooser_state *const ss, byte *p)
|
|
|
812 |
{
|
|
|
813 |
/* This function uses a statistical algorithm being not well defined.
|
|
|
814 |
|
|
|
815 |
We compute areas covered by gradients,
|
|
|
816 |
separately with small width (line art)
|
|
|
817 |
and with big width (photo).
|
|
|
818 |
Making the choice based on the areas.
|
|
|
819 |
|
|
|
820 |
Note that we deal with horizontal frequencies only.
|
|
|
821 |
Dealing with vertical ones would be too expensive.
|
|
|
822 |
*/
|
|
|
823 |
const int delta = 256 / 16; /* about 1/16 of the color range */
|
|
|
824 |
const int max_lineart_boundary_width = 3; /* pixels */
|
|
|
825 |
const int max_gradient_constant = 10; /* pixels */
|
|
|
826 |
int i, j0 = 0, j1 = 0;
|
|
|
827 |
int w0 = p[0], w1 = p[0], v;
|
|
|
828 |
ulong plateau_count = 0, lower_plateaus = 0;
|
|
|
829 |
ulong upper_plateaus = 0, gradients = 0;
|
|
|
830 |
bool lower = false, upper = false;
|
|
|
831 |
|
|
|
832 |
for (i = 1; i < ss->width; i++) {
|
|
|
833 |
v = p[i];
|
|
|
834 |
if (!lower) {
|
|
|
835 |
if (w1 < v) {
|
|
|
836 |
if (!upper)
|
|
|
837 |
j1 = i - 1;
|
|
|
838 |
w1 = v;
|
|
|
839 |
upper = true;
|
|
|
840 |
} else if (w1 == v && j1 < i - max_gradient_constant)
|
|
|
841 |
j1 = i - max_gradient_constant; /* inner constant plateaw */
|
|
|
842 |
else if (upper && w1 - delta > v) {
|
|
|
843 |
/* end of upper plateau at w1-delta...w1 */
|
|
|
844 |
for (j0 = i - 1; j0 > j1 && w1 - delta <= p[j0]; j0--) DO_NOTHING;
|
|
|
845 |
/* upper plateau j0+1...i-1 */
|
|
|
846 |
if(j0 > 0 && i < ss->width - 1) /* ignore sides */
|
|
|
847 |
upper_plateaus += i - j0;
|
|
|
848 |
plateau_count ++;
|
|
|
849 |
if (j0 > j1) {
|
|
|
850 |
/* upgrade j1...j0 */
|
|
|
851 |
if (j0 > j1 + max_lineart_boundary_width)
|
|
|
852 |
gradients += j0 - j1;
|
|
|
853 |
}
|
|
|
854 |
j1 = i;
|
|
|
855 |
upper = false;
|
|
|
856 |
w0 = w1;
|
|
|
857 |
continue;
|
|
|
858 |
}
|
|
|
859 |
}
|
|
|
860 |
if (!upper) {
|
|
|
861 |
if (w0 > v) {
|
|
|
862 |
if (!lower)
|
|
|
863 |
j1 = i - 1;
|
|
|
864 |
w0 = v;
|
|
|
865 |
lower = true;
|
|
|
866 |
} else if (w0 == v && j1 < i - max_gradient_constant)
|
|
|
867 |
j1 = i - max_gradient_constant; /* inner constant plateaw */
|
|
|
868 |
else if (lower && w0 + delta < v) {
|
|
|
869 |
/* end of lower plateau at w0...w0+delta */
|
|
|
870 |
for (j0 = i - 1; j0 > j1 && w0 + delta >= p[j0]; j0--) DO_NOTHING;
|
|
|
871 |
/* lower plateau j0+1...i-1 */
|
|
|
872 |
if(j0 > 0 && i < ss->width - 1) /* ignore sides */
|
|
|
873 |
lower_plateaus += i - j0;
|
|
|
874 |
plateau_count ++;
|
|
|
875 |
if (j0 > j1) {
|
|
|
876 |
/* downgrade j1...j0 */
|
|
|
877 |
if (j0 > j1 + max_lineart_boundary_width)
|
|
|
878 |
gradients += j0 - j1;
|
|
|
879 |
}
|
|
|
880 |
j1 = i;
|
|
|
881 |
lower = false;
|
|
|
882 |
w1 = w0;
|
|
|
883 |
}
|
|
|
884 |
}
|
|
|
885 |
}
|
|
|
886 |
if (plateau_count > ss->width / 6) {
|
|
|
887 |
/* Possibly a dithering, can't recognize.
|
|
|
888 |
It would be better to estimate frequency histogram rather than
|
|
|
889 |
rough quantity, but we hope that the simpler test can work fine.
|
|
|
890 |
*/
|
|
|
891 |
} else if (!plateau_count) /* a pseudo-constant color through entire row */
|
|
|
892 |
DO_NOTHING; /* ignore such lines */
|
|
|
893 |
else {
|
|
|
894 |
int plateaus;
|
|
|
895 |
ss->lower_plateaus += lower_plateaus;
|
|
|
896 |
ss->upper_plateaus += upper_plateaus;
|
|
|
897 |
ss->gradients += gradients;
|
|
|
898 |
plateaus = min(ss->lower_plateaus, ss->upper_plateaus); /* (fore/back)ground */
|
|
|
899 |
if (ss->gradients >= 10000 && ss->gradients > plateaus / 6)
|
|
|
900 |
ss->choice = 1; /* choice is made : photo */
|
|
|
901 |
else if (plateaus >= 100000 && plateaus / 5000 >= ss->gradients)
|
|
|
902 |
ss->choice = 2; /* choice is made : lineart */
|
|
|
903 |
}
|
|
|
904 |
}
|
|
|
905 |
|
|
|
906 |
/* Recognize photo/lineart. */
|
|
|
907 |
private void
|
|
|
908 |
s_compr_chooser__recognize(stream_compr_chooser_state * ss)
|
|
|
909 |
{
|
|
|
910 |
int i;
|
|
|
911 |
byte *p = ss->sample;
|
|
|
912 |
|
|
|
913 |
for (i = 0; i < ss->depth; i++, p += ss->width)
|
|
|
914 |
s_compr_chooser__estimate_row(ss, p);
|
|
|
915 |
/* todo: make decision */
|
|
|
916 |
}
|
|
|
917 |
|
|
|
918 |
/* Uppack data and recognize photo/lineart. */
|
|
|
919 |
private void
|
|
|
920 |
s_compr_chooser__unpack_and_recognize(stream_compr_chooser_state *const ss,
|
|
|
921 |
const byte *data, int length)
|
|
|
922 |
{
|
|
|
923 |
/*
|
|
|
924 |
* Input samples are packed ABCABCABC..., but the sample[] array of
|
|
|
925 |
* unpacked values is stored AAA...BBB...CCC. i counts samples within
|
|
|
926 |
* a pixel, multiplied by width; j counts pixels.
|
|
|
927 |
*/
|
|
|
928 |
uint i = (ss->samples_count % ss->depth) * ss->width;
|
|
|
929 |
uint j = ss->samples_count / ss->depth;
|
|
|
930 |
const byte *p = data;
|
|
|
931 |
int l = length;
|
|
|
932 |
|
|
|
933 |
while (l) {
|
|
|
934 |
if (ss->bits_left < 8) {
|
|
|
935 |
uint k = (sizeof(ss->packed_data) * 8 - ss->bits_left) / 8;
|
|
|
936 |
|
|
|
937 |
k = min(k, l);
|
|
|
938 |
for (; k; k--, l--, p++, ss->bits_left += 8)
|
|
|
939 |
ss->packed_data = (ss->packed_data << 8) + *p;
|
|
|
940 |
}
|
|
|
941 |
while (ss->bits_left >= ss->bits_per_sample) {
|
|
|
942 |
uint k = ss->bits_left - ss->bits_per_sample;
|
|
|
943 |
ulong v = ss->packed_data >> k;
|
|
|
944 |
|
|
|
945 |
ss->packed_data -= (v << k);
|
|
|
946 |
ss->bits_left -= ss->bits_per_sample;
|
|
|
947 |
if (ss->bits_per_sample > 8)
|
|
|
948 |
v >>= ss->bits_per_sample - 8;
|
|
|
949 |
else
|
|
|
950 |
v <<= 8 - ss->bits_per_sample;
|
|
|
951 |
ss->sample[i + j] = (byte)v; /* scaled to 0...255 */
|
|
|
952 |
i += ss->width;
|
|
|
953 |
if (i >= ss->width * ss->depth)
|
|
|
954 |
i = 0, j++;
|
|
|
955 |
ss->samples_count++;
|
|
|
956 |
if (ss->samples_count >= ss->width * ss->depth) {
|
|
|
957 |
s_compr_chooser__recognize(ss);
|
|
|
958 |
ss->packed_data = 0;
|
|
|
959 |
ss->bits_left = 0;
|
|
|
960 |
ss->samples_count = 0;
|
|
|
961 |
i = j = 0;
|
|
|
962 |
}
|
|
|
963 |
}
|
|
|
964 |
}
|
|
|
965 |
}
|
|
|
966 |
|
|
|
967 |
/* Process a buffer. */
|
|
|
968 |
private int
|
|
|
969 |
s_compr_chooser_process(stream_state * st, stream_cursor_read * pr,
|
|
|
970 |
stream_cursor_write * pw, bool last)
|
|
|
971 |
{
|
|
|
972 |
stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
|
|
|
973 |
int l = pr->limit - pr->ptr;
|
|
|
974 |
|
|
|
975 |
if (ss->width >= 3) /* Can't process narrow images. */
|
|
|
976 |
s_compr_chooser__unpack_and_recognize(ss, pr->ptr + 1, l);
|
|
|
977 |
pr->ptr += l;
|
|
|
978 |
return 0;
|
|
|
979 |
}
|
|
|
980 |
|
|
|
981 |
const stream_template s_compr_chooser_template = {
|
|
|
982 |
&st_compr_chooser_state, s_compr_chooser_init, s_compr_chooser_process, 1, 1,
|
|
|
983 |
s_compr_chooser_release, 0 /* NULL */
|
|
|
984 |
};
|
|
|
985 |
|
|
|
986 |
/* Get choice */
|
|
|
987 |
uint
|
|
|
988 |
s_compr_chooser__get_choice(stream_compr_chooser_state *ss, bool force)
|
|
|
989 |
{
|
|
|
990 |
ulong plateaus = min(ss->lower_plateaus, ss->upper_plateaus);
|
|
|
991 |
|
|
|
992 |
if (ss->choice)
|
|
|
993 |
return ss->choice;
|
|
|
994 |
if (force) {
|
|
|
995 |
if (ss->gradients > plateaus / 12) /* messenger16.pdf, page 3. */
|
|
|
996 |
return 1; /* photo */
|
|
|
997 |
else if (plateaus / 5000 >= ss->gradients)
|
|
|
998 |
return 2; /* lineart */
|
|
|
999 |
}
|
|
|
1000 |
return 0;
|
|
|
1001 |
}
|
|
|
1002 |
|
|
|
1003 |
/* ---------------- Am image color conversion filter ---------------- */
|
|
|
1004 |
|
|
|
1005 |
private_st_image_colors_state();
|
|
|
1006 |
|
|
|
1007 |
/* Initialize the state. */
|
|
|
1008 |
private int
|
|
|
1009 |
s_image_colors_init(stream_state * st)
|
|
|
1010 |
{
|
|
|
1011 |
stream_image_colors_state *const ss = (stream_image_colors_state *) st;
|
|
|
1012 |
|
|
|
1013 |
ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
|
|
|
1014 |
ss->output_bits_buffer = 0;
|
|
|
1015 |
ss->output_bits_buffered = 0;
|
|
|
1016 |
ss->output_depth = 1;
|
|
|
1017 |
ss->output_component_index = ss->output_depth;
|
|
|
1018 |
ss->output_bits_per_sample = 1;
|
|
|
1019 |
ss->output_component_bits_written = 0;
|
|
|
1020 |
ss->raster = 0;
|
|
|
1021 |
ss->row_bits = 0;
|
|
|
1022 |
ss->row_bits_passed = 0;
|
|
|
1023 |
ss->row_alignment_bytes = 0;
|
|
|
1024 |
ss->row_alignment_bytes_left = 0;
|
|
|
1025 |
ss->input_component_index = 0;
|
|
|
1026 |
ss->input_bits_buffer = 0;
|
|
|
1027 |
ss->input_bits_buffered = 0;
|
|
|
1028 |
ss->convert_color = 0;
|
|
|
1029 |
ss->pcs = 0;
|
|
|
1030 |
ss->pdev = 0;
|
|
|
1031 |
ss->pis = 0;
|
|
|
1032 |
return 0;
|
|
|
1033 |
}
|
|
|
1034 |
|
|
|
1035 |
private int
|
|
|
1036 |
s_image_colors_convert_color_to_mask(stream_image_colors_state *ss)
|
|
|
1037 |
{
|
|
|
1038 |
int i, ii;
|
|
|
1039 |
|
|
|
1040 |
for (i = ii = 0; i < ss->depth; i++, ii += 2)
|
|
|
1041 |
if (ss->input_color[i] < ss->MaskColor[ii] ||
|
|
|
1042 |
ss->input_color[i] > ss->MaskColor[ii + 1])
|
|
|
1043 |
break;
|
|
|
1044 |
ss->output_color[0] = (i < ss->depth ? 1 : 0);
|
|
|
1045 |
return 0;
|
|
|
1046 |
}
|
|
|
1047 |
|
|
|
1048 |
private int
|
|
|
1049 |
s_image_colors_convert_to_device_color(stream_image_colors_state * ss)
|
|
|
1050 |
{
|
|
|
1051 |
gs_client_color cc;
|
|
|
1052 |
gx_device_color dc;
|
|
|
1053 |
int i, code;
|
|
|
1054 |
double v0 = (1 << ss->bits_per_sample) - 1;
|
|
|
1055 |
double v1 = (1 << ss->output_bits_per_sample) - 1;
|
|
|
1056 |
|
|
|
1057 |
for (i = 0; i < ss->depth; i++)
|
|
|
1058 |
cc.paint.values[i] = ss->input_color[i] *
|
|
|
1059 |
(ss->Decode[i * 2 + 1] - ss->Decode[i * 2]) / v0 + ss->Decode[i * 2];
|
|
|
1060 |
|
|
|
1061 |
code = ss->pcs->type->remap_color(&cc, ss->pcs, &dc, ss->pis,
|
|
|
1062 |
ss->pdev, gs_color_select_texture);
|
|
|
1063 |
if (code < 0)
|
|
|
1064 |
return code;
|
|
|
1065 |
for (i = 0; i < ss->output_depth; i++) {
|
|
|
1066 |
uint m = (1 << ss->pdev->color_info.comp_bits[i]) - 1;
|
|
|
1067 |
uint w = (dc.colors.pure >> ss->pdev->color_info.comp_shift[i]) & m;
|
|
|
1068 |
|
|
|
1069 |
ss->output_color[i] = (uint)(v1 * w / m + 0.5);
|
|
|
1070 |
}
|
|
|
1071 |
return 0;
|
|
|
1072 |
}
|
|
|
1073 |
|
|
|
1074 |
/* Set masc colors dimensions. */
|
|
|
1075 |
void
|
|
|
1076 |
s_image_colors_set_mask_colors(stream_image_colors_state * ss, uint *MaskColor)
|
|
|
1077 |
{
|
|
|
1078 |
ss->convert_color = s_image_colors_convert_color_to_mask;
|
|
|
1079 |
memcpy(ss->MaskColor, MaskColor, ss->depth * sizeof(MaskColor[0]) * 2);
|
|
|
1080 |
}
|
|
|
1081 |
|
|
|
1082 |
/* Set image dimensions. */
|
|
|
1083 |
void
|
|
|
1084 |
s_image_colors_set_dimensions(stream_image_colors_state * ss,
|
|
|
1085 |
int width, int height, int depth, int bits_per_sample)
|
|
|
1086 |
{
|
|
|
1087 |
ss->width = width;
|
|
|
1088 |
ss->height = height;
|
|
|
1089 |
ss->depth = depth;
|
|
|
1090 |
ss->bits_per_sample = bits_per_sample;
|
|
|
1091 |
ss->row_bits = bits_per_sample * depth * width;
|
|
|
1092 |
ss->raster = bitmap_raster(ss->row_bits);
|
|
|
1093 |
ss->row_alignment_bytes = 0; /* (ss->raster * 8 - ss->row_bits) / 8) doesn't work. */
|
|
|
1094 |
}
|
|
|
1095 |
|
|
|
1096 |
void
|
|
|
1097 |
s_image_colors_set_color_space(stream_image_colors_state * ss, gx_device *pdev,
|
|
|
1098 |
const gs_color_space *pcs, const gs_imager_state *pis,
|
|
|
1099 |
float *Decode)
|
|
|
1100 |
{
|
|
|
1101 |
ss->output_depth = pdev->color_info.num_components;
|
|
|
1102 |
ss->output_component_index = ss->output_depth;
|
|
|
1103 |
ss->output_bits_per_sample = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
|
|
|
1104 |
ss->convert_color = s_image_colors_convert_to_device_color;
|
|
|
1105 |
ss->pdev = pdev;
|
|
|
1106 |
ss->pcs = pcs;
|
|
|
1107 |
ss->pis = pis;
|
|
|
1108 |
memcpy(ss->Decode, Decode, ss->depth * sizeof(Decode[0]) * 2);
|
|
|
1109 |
}
|
|
|
1110 |
|
|
|
1111 |
|
|
|
1112 |
/* Process a buffer. */
|
|
|
1113 |
private int
|
|
|
1114 |
s_image_colors_process(stream_state * st, stream_cursor_read * pr,
|
|
|
1115 |
stream_cursor_write * pw, bool last)
|
|
|
1116 |
{
|
|
|
1117 |
stream_image_colors_state *const ss = (stream_image_colors_state *) st;
|
|
|
1118 |
|
|
|
1119 |
for (;;) {
|
|
|
1120 |
if (pw->ptr >= pw->limit)
|
|
|
1121 |
return 1;
|
|
|
1122 |
if (ss->row_bits_passed >= ss->row_bits) {
|
|
|
1123 |
ss->row_alignment_bytes_left = ss->row_alignment_bytes;
|
|
|
1124 |
ss->input_bits_buffered = 0;
|
|
|
1125 |
ss->input_bits_buffer = 0; /* Just to simplify the debugging. */
|
|
|
1126 |
if (ss->output_bits_buffered) {
|
|
|
1127 |
*(++pw->ptr) = ss->output_bits_buffer;
|
|
|
1128 |
ss->output_bits_buffered = 0;
|
|
|
1129 |
ss->output_bits_buffer = 0;
|
|
|
1130 |
}
|
|
|
1131 |
ss->row_bits_passed = 0;
|
|
|
1132 |
continue;
|
|
|
1133 |
}
|
|
|
1134 |
if (ss->row_alignment_bytes_left) {
|
|
|
1135 |
uint k = pr->limit - pr->ptr;
|
|
|
1136 |
|
|
|
1137 |
if (k > ss->row_alignment_bytes_left)
|
|
|
1138 |
k = ss->row_alignment_bytes_left;
|
|
|
1139 |
pr->ptr += k;
|
|
|
1140 |
ss->row_alignment_bytes_left -= k;
|
|
|
1141 |
if (pr->ptr >= pr->limit)
|
|
|
1142 |
return 0;
|
|
|
1143 |
}
|
|
|
1144 |
if (ss->output_component_index < ss->output_depth) {
|
|
|
1145 |
for (;ss->output_component_index < ss->output_depth;) {
|
|
|
1146 |
uint fitting = (uint)(8 - ss->output_bits_buffered);
|
|
|
1147 |
uint v, w, u, n, m;
|
|
|
1148 |
|
|
|
1149 |
if (pw->ptr >= pw->limit)
|
|
|
1150 |
return 1;
|
|
|
1151 |
v = ss->output_color[ss->output_component_index];
|
|
|
1152 |
n = ss->output_bits_per_sample - ss->output_component_bits_written; /* no. of bits left */
|
|
|
1153 |
w = v - ((v >> n) << n); /* the current component without written bits. */
|
|
|
1154 |
if (fitting > n)
|
|
|
1155 |
fitting = n; /* no. of bits to write. */
|
|
|
1156 |
m = n - fitting; /* no. of bits will left. */
|
|
|
1157 |
u = w >> m; /* bits to write (near lsb). */
|
|
|
1158 |
ss->output_bits_buffer |= u << (8 - ss->output_bits_buffered - fitting);
|
|
|
1159 |
ss->output_bits_buffered += fitting;
|
|
|
1160 |
if (ss->output_bits_buffered >= 8) {
|
|
|
1161 |
*(++pw->ptr) = ss->output_bits_buffer;
|
|
|
1162 |
ss->output_bits_buffered = 0;
|
|
|
1163 |
ss->output_bits_buffer = 0;
|
|
|
1164 |
}
|
|
|
1165 |
ss->output_component_bits_written += fitting;
|
|
|
1166 |
if (ss->output_component_bits_written >= ss->output_bits_per_sample) {
|
|
|
1167 |
ss->output_component_index++;
|
|
|
1168 |
ss->output_component_bits_written = 0;
|
|
|
1169 |
}
|
|
|
1170 |
}
|
|
|
1171 |
ss->row_bits_passed += ss->bits_per_sample * ss->depth;
|
|
|
1172 |
continue;
|
|
|
1173 |
}
|
|
|
1174 |
if (ss->input_bits_buffered < ss->bits_per_sample) {
|
|
|
1175 |
if (pr->ptr >= pr->limit)
|
|
|
1176 |
return 0;
|
|
|
1177 |
ss->input_bits_buffer = (ss->input_bits_buffer << 8) | *++pr->ptr;
|
|
|
1178 |
ss->input_bits_buffered += 8;
|
|
|
1179 |
/* fixme: delay shifting the input ptr until input_bits_buffer is cleaned. */
|
|
|
1180 |
}
|
|
|
1181 |
if (ss->input_bits_buffered >= ss->bits_per_sample) {
|
|
|
1182 |
uint w;
|
|
|
1183 |
|
|
|
1184 |
ss->input_bits_buffered -= ss->bits_per_sample;
|
|
|
1185 |
ss->input_color[ss->input_component_index] = w = ss->input_bits_buffer >> ss->input_bits_buffered;
|
|
|
1186 |
ss->input_bits_buffer &= ~(w << ss->input_bits_buffered);
|
|
|
1187 |
ss->input_component_index++;
|
|
|
1188 |
if (ss->input_component_index >= ss->depth) {
|
|
|
1189 |
int code = ss->convert_color(ss);
|
|
|
1190 |
|
|
|
1191 |
if (code < 0)
|
|
|
1192 |
return ERRC;
|
|
|
1193 |
ss->output_component_index = 0;
|
|
|
1194 |
ss->input_component_index = 0;
|
|
|
1195 |
}
|
|
|
1196 |
}
|
|
|
1197 |
}
|
|
|
1198 |
}
|
|
|
1199 |
|
|
|
1200 |
const stream_template s__image_colors_template = {
|
|
|
1201 |
&st_stream_image_colors_state, s_image_colors_init, s_image_colors_process, 1, 1,
|
|
|
1202 |
NULL, NULL
|
|
|
1203 |
};
|
|
|
1204 |
|