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
s_1248_init(stream_1248_state * ss,int Columns,int samples_per_pixel)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
s_1_init(stream_state * st)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
s_2_init(stream_state * st)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
s_4_init(stream_state * st)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
s_12_init(stream_state * st)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
s_N_8_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
s_12_8_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
s_8_N_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
s_C2R_init(stream_C2R_state * ss,const gs_imager_state * pis)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
s_C2R_set_defaults(stream_state * st)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
s_C2R_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
RELOC_PTRS_WITH(ie_state_reloc_ptrs,stream_IE_state * st)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
s_IE_set_defaults(stream_state * st)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
s_IE_init(stream_state * st)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
s_IE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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 0 /* NULL */, s_IE_set_defaults
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
s_Downsample_size_out(int size_in,int factor,bool pad)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
s_Downsample_set_defaults(register stream_state * st)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
s_Subsample_init(stream_state * st)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
s_Subsample_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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 0 /* NULL */, s_Downsample_set_defaults
659 };
660
661 /* ------ Average ------ */
662
663 private_st_Average_state();
664
665 /* Set default parameter values (actually, just clear pointers). */
666 private void
s_Average_set_defaults(stream_state * st)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
s_Average_init(stream_state * st)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
s_Average_release(stream_state * st)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
s_Average_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
s_compr_chooser_init(stream_state * st)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
s_compr_chooser_set_dimensions(stream_compr_chooser_state * ss,int width,int height,int depth,int bits_per_sample)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
s_compr_chooser_release(stream_state * st)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
s_compr_chooser__estimate_row(stream_compr_chooser_state * const ss,byte * p)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
s_compr_chooser__recognize(stream_compr_chooser_state * ss)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
s_compr_chooser__unpack_and_recognize(stream_compr_chooser_state * const ss,const byte * data,int length)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
s_compr_chooser_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
s_compr_chooser__get_choice(stream_compr_chooser_state * ss,bool force)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
s_image_colors_init(stream_state * st)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
s_image_colors_convert_color_to_mask(stream_image_colors_state * ss)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
s_image_colors_convert_to_device_color(stream_image_colors_state * ss)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
s_image_colors_set_mask_colors(stream_image_colors_state * ss,uint * MaskColor)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
s_image_colors_set_dimensions(stream_image_colors_state * ss,int width,int height,int depth,int bits_per_sample)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
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)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
s_image_colors_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)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
1205