Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpsds.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, 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
8.63k
{
934
8.63k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
935
936
8.63k
    ss->choice = 0;
937
8.63k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
938
8.63k
    ss->sample = 0;
939
8.63k
    ss->samples_count = 0;
940
8.63k
    ss->bits_left = 0;
941
8.63k
    ss->packed_data = 0;
942
8.63k
    ss->lower_plateaus = ss->upper_plateaus = 0;
943
8.63k
    ss->gradients = 0;
944
8.63k
    return 0;
945
8.63k
}
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
8.63k
{
952
8.63k
    ss->width = width;
953
8.63k
    ss->height = height;
954
8.63k
    ss->depth = depth;
955
8.63k
    ss->bits_per_sample = bits_per_sample;
956
8.63k
    ss->sample = gs_alloc_bytes(ss->memory, (size_t)width * depth,
957
8.63k
                                "s_compr_chooser_set_dimensions");
958
8.63k
    if (ss->sample == 0)
959
0
        return_error(gs_error_VMerror);
960
8.63k
    return 0;
961
8.63k
}
962
963
/* Release state. */
964
static void
965
s_compr_chooser_release(stream_state * st)
966
8.63k
{
967
8.63k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
968
969
8.63k
    gs_free_object(ss->memory, ss->sample, "s_compr_chooser_release");
970
8.63k
}
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
1.27M
{
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
1.27M
    const int delta = 256 / 16; /* about 1/16 of the color range */
987
1.27M
    const int max_lineart_boundary_width = 3; /* pixels */
988
1.27M
    const int max_gradient_constant = 10; /* pixels */
989
1.27M
    int i, j0 = 0, j1 = 0;
990
1.27M
    int w0 = p[0], w1 = p[0], v;
991
1.27M
    ulong plateau_count = 0, lower_plateaus = 0;
992
1.27M
    ulong upper_plateaus = 0, gradients = 0;
993
1.27M
    bool lower = false, upper = false;
994
995
125M
    for (i = 1; i < ss->width; i++) {
996
124M
        v = p[i];
997
124M
        if (!lower) {
998
108M
            if (w1 < v) {
999
1.45M
                if (!upper)
1000
831k
                    j1 = i - 1;
1001
1.45M
                w1 = v;
1002
1.45M
                upper = true;
1003
107M
            } else if (w1 == v && j1 < i - max_gradient_constant)
1004
86.8M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1005
20.3M
            else if (upper && w1 - delta > v) {
1006
                /* end of upper plateau at w1-delta...w1 */
1007
2.46M
                for (j0 = i - 1; j0 > j1 && w1 - delta <= p[j0]; j0--) DO_NOTHING;
1008
                /* upper plateau j0+1...i-1 */
1009
285k
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1010
278k
                    upper_plateaus += i - j0;
1011
285k
                plateau_count ++;
1012
285k
                if (j0 > j1) {
1013
                    /* upgrade j1...j0 */
1014
58.2k
                    if (j0 > j1 + max_lineart_boundary_width)
1015
20.6k
                        gradients += j0 - j1;
1016
58.2k
                }
1017
285k
                j1 = i;
1018
285k
                upper = false;
1019
285k
                w0 = w1;
1020
285k
                continue;
1021
285k
            }
1022
108M
        }
1023
123M
        if (!upper) {
1024
96.3M
            if (w0 > v) {
1025
1.44M
                if (!lower)
1026
840k
                    j1 = i - 1;
1027
1.44M
                w0 = v;
1028
1.44M
                lower = true;
1029
94.9M
            } else if (w0 == v && j1 < i - max_gradient_constant)
1030
8.45M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1031
86.4M
            else if (lower && w0 + delta < v) {
1032
                /* end of lower plateau at w0...w0+delta */
1033
6.86M
                for (j0 = i - 1; j0 > j1 && w0 + delta >= p[j0]; j0--) DO_NOTHING;
1034
                /* lower plateau j0+1...i-1 */
1035
778k
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1036
759k
                    lower_plateaus += i - j0;
1037
778k
                plateau_count ++;
1038
778k
                if (j0 > j1) {
1039
                    /* downgrade j1...j0 */
1040
56.5k
                    if (j0 > j1 + max_lineart_boundary_width)
1041
21.5k
                        gradients += j0 - j1;
1042
56.5k
                }
1043
778k
                j1 = i;
1044
778k
                lower = false;
1045
778k
                w1 = w0;
1046
778k
            }
1047
96.3M
        }
1048
123M
    }
1049
1.27M
    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
1.27M
    } else if (!plateau_count) /* a pseudo-constant color through entire row */
1055
1.27M
        DO_NOTHING; /* ignore such lines */
1056
543k
    else {
1057
543k
        int plateaus;
1058
543k
        ss->lower_plateaus += lower_plateaus;
1059
543k
        ss->upper_plateaus += upper_plateaus;
1060
543k
        ss->gradients += gradients;
1061
543k
        plateaus = min(ss->lower_plateaus, ss->upper_plateaus); /* (fore/back)ground */
1062
543k
        if (ss->gradients >= 10000 && ss->gradients > plateaus / 6)
1063
174
            ss->choice = 1; /* choice is made : photo */
1064
543k
        else if (plateaus >= 100000 && plateaus / 5000 >= ss->gradients)
1065
372
            ss->choice = 2; /* choice is made : lineart */
1066
543k
    }
1067
1.27M
}
1068
1069
/* Recognize photo/lineart. */
1070
static void
1071
s_compr_chooser__recognize(stream_compr_chooser_state * ss)
1072
430k
{
1073
430k
    int i;
1074
430k
    byte *p = ss->sample;
1075
1076
1.71M
    for (i = 0; i < ss->depth; i++, p += ss->width)
1077
1.27M
        s_compr_chooser__estimate_row(ss, p);
1078
    /* todo: make decision */
1079
430k
}
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
498k
{
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
498k
    uint i = (ss->samples_count % ss->depth) * ss->width;
1092
498k
    uint j = ss->samples_count / ss->depth;
1093
498k
    const byte *p = data;
1094
498k
    int l = length;
1095
1096
32.0M
    while (l) {
1097
31.5M
        if (ss->bits_left <= 8) {
1098
31.5M
            uint k = (sizeof(ss->packed_data) * 8 - ss->bits_left) / 8;
1099
1100
31.5M
            k = min(k, l);
1101
157M
            for (; k; k--, l--, p++, ss->bits_left += 8)
1102
126M
                ss->packed_data = (ss->packed_data << 8) + *p;
1103
31.5M
        }
1104
157M
        while (ss->bits_left >= ss->bits_per_sample) {
1105
125M
            uint k = ss->bits_left - ss->bits_per_sample;
1106
125M
            ulong v = ss->packed_data >> k;
1107
1108
125M
            ss->packed_data -= (v << k);
1109
125M
            ss->bits_left -= ss->bits_per_sample;
1110
125M
            if (ss->bits_per_sample > 8)
1111
0
                v >>= ss->bits_per_sample - 8;
1112
125M
            else
1113
125M
                v <<= 8 - ss->bits_per_sample;
1114
125M
            ss->sample[i + j] = (byte)v;  /* scaled to 0...255 */
1115
125M
            i += ss->width;
1116
125M
            if (i >= ss->width * ss->depth)
1117
42.5M
                i = 0, j++;
1118
125M
            ss->samples_count++;
1119
125M
            if (ss->samples_count >= ss->width * ss->depth) {
1120
430k
                s_compr_chooser__recognize(ss);
1121
430k
                ss->packed_data = 0;
1122
430k
                ss->bits_left = 0;
1123
430k
                ss->samples_count = 0;
1124
430k
                i = j = 0;
1125
430k
            }
1126
125M
        }
1127
31.5M
    }
1128
498k
}
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
498k
{
1135
498k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
1136
498k
    int l = pr->limit - pr->ptr;
1137
1138
498k
    if (ss->width >= 3) /* Can't process narrow images. */
1139
498k
        s_compr_chooser__unpack_and_recognize(ss, pr->ptr + 1, l);
1140
498k
    pr->ptr += l;
1141
498k
    return 0;
1142
498k
}
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
382k
{
1153
382k
    ulong plateaus = min(ss->lower_plateaus, ss->upper_plateaus);
1154
1155
382k
    if (ss->choice)
1156
258
        return ss->choice;
1157
382k
    if (force) {
1158
209
        if (ss->gradients > plateaus / 12) /* messenger16.pdf, page 3. */
1159
205
            return 1; /* photo */
1160
4
        else if (plateaus && plateaus / 5000 >= ss->gradients)
1161
0
            return 2; /* lineart */
1162
209
    }
1163
382k
    return 0;
1164
382k
}
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
1.30k
{
1174
1.30k
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1175
1176
1.30k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
1177
1.30k
    ss->output_bits_buffer = 0;
1178
1.30k
    ss->output_bits_buffered = 0;
1179
1.30k
    ss->output_depth = 1;
1180
1.30k
    ss->output_component_index = ss->output_depth;
1181
1.30k
    ss->output_bits_per_sample = 1;
1182
1.30k
    ss->output_component_bits_written = 0;
1183
1.30k
    ss->raster = 0;
1184
1.30k
    ss->row_bits = 0;
1185
1.30k
    ss->row_bits_passed = 0;
1186
1.30k
    ss->row_alignment_bytes = 0;
1187
1.30k
    ss->row_alignment_bytes_left = 0;
1188
1.30k
    ss->input_component_index = 0;
1189
1.30k
    ss->input_bits_buffer = 0;
1190
1.30k
    ss->input_bits_buffered = 0;
1191
1.30k
    ss->convert_color = 0;
1192
1.30k
    ss->pcs = 0;
1193
1.30k
    ss->pdev = 0;
1194
1.30k
    ss->pgs = 0;
1195
1.30k
    return 0;
1196
1.30k
}
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
40.7M
{
1214
40.7M
    gs_client_color cc;
1215
40.7M
    gx_device_color dc;
1216
40.7M
    int i, code;
1217
40.7M
    double v0 = (1 << ss->bits_per_sample) - 1;
1218
40.7M
    double v1 = (1 << ss->output_bits_per_sample) - 1;
1219
40.7M
    gx_device *target;
1220
1221
40.7M
    target = ss->pdev;
1222
40.7M
    while(target->child)
1223
0
        target = target->child;
1224
1225
96.0M
    for (i = 0; i < ss->depth; i++)
1226
55.3M
        cc.paint.values[i] = ss->input_color[i] *
1227
55.3M
                (ss->Decode[i * 2 + 1] - ss->Decode[i * 2]) / v0 + ss->Decode[i * 2];
1228
1229
40.7M
    code = ss->pcs->type->remap_color(&cc, ss->pcs, &dc, ss->pgs,
1230
40.7M
                              target, gs_color_select_texture);
1231
40.7M
    if (code < 0)
1232
0
        return code;
1233
163M
    for (i = 0; i < ss->output_depth; i++) {
1234
122M
        uint m = (1 << target->color_info.comp_bits[i]) - 1;
1235
122M
        uint w = (dc.colors.pure >> target->color_info.comp_shift[i]) & m;
1236
1237
122M
        ss->output_color[i] = (uint)(v1 * w / m + 0.5);
1238
122M
    }
1239
40.7M
    return 0;
1240
40.7M
}
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
1.30k
{
1256
1.30k
    ss->width = width;
1257
1.30k
    ss->height = height;
1258
1.30k
    ss->depth = depth;
1259
1.30k
    ss->bits_per_sample = bits_per_sample;
1260
1.30k
    ss->row_bits = bits_per_sample * depth * input_width;
1261
1.30k
    ss->raster = bitmap_raster(ss->row_bits);
1262
1.30k
    ss->row_alignment_bytes = 0; /* (ss->raster * 8 - ss->row_bits) / 8) doesn't work. */
1263
1.30k
}
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
1.30k
{
1270
1.30k
    ss->output_depth = pdev->color_info.num_components;
1271
1.30k
    ss->output_component_index = ss->output_depth;
1272
1.30k
    ss->output_bits_per_sample = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
1273
1.30k
    ss->convert_color = s_image_colors_convert_to_device_color;
1274
1.30k
    ss->pdev = pdev;
1275
1.30k
    while(ss->pdev->parent)
1276
0
        ss->pdev = ss->pdev->parent;
1277
1278
1.30k
    ss->pcs = pcs;
1279
1.30k
    ss->pgs = pgs;
1280
1.30k
    memcpy(ss->Decode, Decode, ss->depth * sizeof(Decode[0]) * 2);
1281
1.30k
}
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
1.15M
{
1288
1.15M
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1289
1290
97.3M
    for (;;) {
1291
97.3M
        if (pw->ptr >= pw->limit)
1292
636k
            return 1;
1293
96.6M
        if (ss->row_bits_passed >= ss->row_bits) {
1294
71.4k
            ss->row_alignment_bytes_left = ss->row_alignment_bytes;
1295
71.4k
            ss->input_bits_buffered = 0;
1296
71.4k
            ss->input_bits_buffer = 0; /* Just to simplify the debugging. */
1297
71.4k
            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
71.4k
            ss->row_bits_passed = 0;
1303
71.4k
            continue;
1304
71.4k
        }
1305
96.5M
        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
96.5M
        if (ss->output_component_index < ss->output_depth) {
1316
163M
            for (;ss->output_component_index < ss->output_depth;) {
1317
122M
                uint fitting = (uint)(8 - ss->output_bits_buffered);
1318
122M
                uint v, w, u, n, m;
1319
1320
122M
                if (pw->ptr >= pw->limit)
1321
318k
                    return 1;
1322
122M
                v = ss->output_color[ss->output_component_index];
1323
122M
                n = ss->output_bits_per_sample - ss->output_component_bits_written; /* no. of bits left */
1324
122M
                w = v - ((v >> n) << n); /* the current component without written bits. */
1325
122M
                if (fitting > n)
1326
0
                    fitting = n; /* no. of bits to write. */
1327
122M
                m = n - fitting; /* no. of bits will left. */
1328
122M
                u = w >> m;  /* bits to write (near lsb). */
1329
122M
                ss->output_bits_buffer |= u << (8 - ss->output_bits_buffered - fitting);
1330
122M
                ss->output_bits_buffered += fitting;
1331
122M
                if (ss->output_bits_buffered >= 8) {
1332
122M
                    *(++pw->ptr) = ss->output_bits_buffer;
1333
122M
                    ss->output_bits_buffered = 0;
1334
122M
                    ss->output_bits_buffer = 0;
1335
122M
                }
1336
122M
                ss->output_component_bits_written += fitting;
1337
122M
                if (ss->output_component_bits_written >= ss->output_bits_per_sample) {
1338
122M
                    ss->output_component_index++;
1339
122M
                    ss->output_component_bits_written = 0;
1340
122M
                }
1341
122M
            }
1342
40.7M
            ss->row_bits_passed += ss->bits_per_sample * ss->depth;
1343
40.7M
            continue;
1344
41.0M
        }
1345
55.5M
        if (ss->input_bits_buffered < ss->bits_per_sample) {
1346
51.9M
            if (pr->ptr >= pr->limit)
1347
203k
                return 0;
1348
51.7M
            ss->input_bits_buffer = (ss->input_bits_buffer << 8) | *++pr->ptr;
1349
51.7M
            ss->input_bits_buffered += 8;
1350
            /* fixme: delay shifting the input ptr until input_bits_buffer is cleaned. */
1351
51.7M
        }
1352
55.3M
        if (ss->input_bits_buffered >= ss->bits_per_sample) {
1353
55.3M
            uint w;
1354
1355
55.3M
            ss->input_bits_buffered -= ss->bits_per_sample;
1356
55.3M
            ss->input_color[ss->input_component_index] = w = ss->input_bits_buffer >> ss->input_bits_buffered;
1357
55.3M
            ss->input_bits_buffer &= ~(w << ss->input_bits_buffered);
1358
55.3M
            ss->input_component_index++;
1359
55.3M
            if (ss->input_component_index >= ss->depth) {
1360
40.7M
                int code = ss->convert_color(ss);
1361
1362
40.7M
                if (code < 0)
1363
0
                    return ERRC;
1364
40.7M
                ss->output_component_index = 0;
1365
40.7M
                ss->input_component_index = 0;
1366
40.7M
            }
1367
55.3M
        }
1368
55.3M
    }
1369
1.15M
}
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
};