Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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