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