Coverage Report

Created: 2022-10-31 07:00

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