xref: /plan9/sys/src/cmd/gs/src/gdevpsds.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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