Coverage Report

Created: 2026-02-14 07:09

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
5.80k
{
934
5.80k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
935
936
5.80k
    ss->choice = 0;
937
5.80k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
938
5.80k
    ss->sample = 0;
939
5.80k
    ss->samples_count = 0;
940
5.80k
    ss->bits_left = 0;
941
5.80k
    ss->packed_data = 0;
942
5.80k
    ss->lower_plateaus = ss->upper_plateaus = 0;
943
5.80k
    ss->gradients = 0;
944
5.80k
    return 0;
945
5.80k
}
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
5.80k
{
952
5.80k
    ss->width = width;
953
5.80k
    ss->height = height;
954
5.80k
    ss->depth = depth;
955
5.80k
    ss->bits_per_sample = bits_per_sample;
956
5.80k
    ss->sample = gs_alloc_bytes(ss->memory, (size_t)width * depth,
957
5.80k
                                "s_compr_chooser_set_dimensions");
958
5.80k
    if (ss->sample == 0)
959
0
        return_error(gs_error_VMerror);
960
5.80k
    return 0;
961
5.80k
}
962
963
/* Release state. */
964
static void
965
s_compr_chooser_release(stream_state * st)
966
5.80k
{
967
5.80k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
968
969
5.80k
    gs_free_object(ss->memory, ss->sample, "s_compr_chooser_release");
970
5.80k
}
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
819k
{
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
819k
    const int delta = 256 / 16; /* about 1/16 of the color range */
987
819k
    const int max_lineart_boundary_width = 3; /* pixels */
988
819k
    const int max_gradient_constant = 10; /* pixels */
989
819k
    int i, j0 = 0, j1 = 0;
990
819k
    int w0 = p[0], w1 = p[0], v;
991
819k
    ulong plateau_count = 0, lower_plateaus = 0;
992
819k
    ulong upper_plateaus = 0, gradients = 0;
993
819k
    bool lower = false, upper = false;
994
995
186M
    for (i = 1; i < ss->width; i++) {
996
185M
        v = p[i];
997
185M
        if (!lower) {
998
168M
            if (w1 < v) {
999
2.94M
                if (!upper)
1000
1.25M
                    j1 = i - 1;
1001
2.94M
                w1 = v;
1002
2.94M
                upper = true;
1003
165M
            } else if (w1 == v && j1 < i - max_gradient_constant)
1004
145M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1005
19.4M
            else if (upper && w1 - delta > v) {
1006
                /* end of upper plateau at w1-delta...w1 */
1007
6.30M
                for (j0 = i - 1; j0 > j1 && w1 - delta <= p[j0]; j0--) DO_NOTHING;
1008
                /* upper plateau j0+1...i-1 */
1009
904k
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1010
886k
                    upper_plateaus += i - j0;
1011
904k
                plateau_count ++;
1012
904k
                if (j0 > j1) {
1013
                    /* upgrade j1...j0 */
1014
210k
                    if (j0 > j1 + max_lineart_boundary_width)
1015
75.7k
                        gradients += j0 - j1;
1016
210k
                }
1017
904k
                j1 = i;
1018
904k
                upper = false;
1019
904k
                w0 = w1;
1020
904k
                continue;
1021
904k
            }
1022
168M
        }
1023
184M
        if (!upper) {
1024
148M
            if (w0 > v) {
1025
2.86M
                if (!lower)
1026
1.26M
                    j1 = i - 1;
1027
2.86M
                w0 = v;
1028
2.86M
                lower = true;
1029
145M
            } else if (w0 == v && j1 < i - max_gradient_constant)
1030
7.10M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1031
138M
            else if (lower && w0 + delta < v) {
1032
                /* end of lower plateau at w0...w0+delta */
1033
7.92M
                for (j0 = i - 1; j0 > j1 && w0 + delta >= p[j0]; j0--) DO_NOTHING;
1034
                /* lower plateau j0+1...i-1 */
1035
1.14M
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1036
1.12M
                    lower_plateaus += i - j0;
1037
1.14M
                plateau_count ++;
1038
1.14M
                if (j0 > j1) {
1039
                    /* downgrade j1...j0 */
1040
199k
                    if (j0 > j1 + max_lineart_boundary_width)
1041
72.3k
                        gradients += j0 - j1;
1042
199k
                }
1043
1.14M
                j1 = i;
1044
1.14M
                lower = false;
1045
1.14M
                w1 = w0;
1046
1.14M
            }
1047
148M
        }
1048
184M
    }
1049
819k
    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
805k
    } else if (!plateau_count) /* a pseudo-constant color through entire row */
1055
805k
        DO_NOTHING; /* ignore such lines */
1056
428k
    else {
1057
428k
        int plateaus;
1058
428k
        ss->lower_plateaus += lower_plateaus;
1059
428k
        ss->upper_plateaus += upper_plateaus;
1060
428k
        ss->gradients += gradients;
1061
428k
        plateaus = min(ss->lower_plateaus, ss->upper_plateaus); /* (fore/back)ground */
1062
428k
        if (ss->gradients >= 10000 && ss->gradients > plateaus / 6)
1063
1.04k
            ss->choice = 1; /* choice is made : photo */
1064
427k
        else if (plateaus >= 100000 && plateaus / 5000 >= ss->gradients)
1065
702
            ss->choice = 2; /* choice is made : lineart */
1066
428k
    }
1067
819k
}
1068
1069
/* Recognize photo/lineart. */
1070
static void
1071
s_compr_chooser__recognize(stream_compr_chooser_state * ss)
1072
280k
{
1073
280k
    int i;
1074
280k
    byte *p = ss->sample;
1075
1076
1.09M
    for (i = 0; i < ss->depth; i++, p += ss->width)
1077
819k
        s_compr_chooser__estimate_row(ss, p);
1078
    /* todo: make decision */
1079
280k
}
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
732k
{
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
732k
    uint i = (ss->samples_count % ss->depth) * ss->width;
1092
732k
    uint j = ss->samples_count / ss->depth;
1093
732k
    const byte *p = data;
1094
732k
    int l = length;
1095
1096
47.3M
    while (l) {
1097
46.6M
        if (ss->bits_left <= 8) {
1098
46.6M
            uint k = (sizeof(ss->packed_data) * 8 - ss->bits_left) / 8;
1099
1100
46.6M
            k = min(k, l);
1101
233M
            for (; k; k--, l--, p++, ss->bits_left += 8)
1102
186M
                ss->packed_data = (ss->packed_data << 8) + *p;
1103
46.6M
        }
1104
233M
        while (ss->bits_left >= ss->bits_per_sample) {
1105
186M
            uint k = ss->bits_left - ss->bits_per_sample;
1106
186M
            ulong v = ss->packed_data >> k;
1107
1108
186M
            ss->packed_data -= (v << k);
1109
186M
            ss->bits_left -= ss->bits_per_sample;
1110
186M
            if (ss->bits_per_sample > 8)
1111
0
                v >>= ss->bits_per_sample - 8;
1112
186M
            else
1113
186M
                v <<= 8 - ss->bits_per_sample;
1114
186M
            ss->sample[i + j] = (byte)v;  /* scaled to 0...255 */
1115
186M
            i += ss->width;
1116
186M
            if (i >= ss->width * ss->depth)
1117
63.9M
                i = 0, j++;
1118
186M
            ss->samples_count++;
1119
186M
            if (ss->samples_count >= ss->width * ss->depth) {
1120
280k
                s_compr_chooser__recognize(ss);
1121
280k
                ss->packed_data = 0;
1122
280k
                ss->bits_left = 0;
1123
280k
                ss->samples_count = 0;
1124
280k
                i = j = 0;
1125
280k
            }
1126
186M
        }
1127
46.6M
    }
1128
732k
}
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
732k
{
1135
732k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
1136
732k
    int l = pr->limit - pr->ptr;
1137
1138
732k
    if (ss->width >= 3) /* Can't process narrow images. */
1139
732k
        s_compr_chooser__unpack_and_recognize(ss, pr->ptr + 1, l);
1140
732k
    pr->ptr += l;
1141
732k
    return 0;
1142
732k
}
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
189k
{
1153
189k
    ulong plateaus = min(ss->lower_plateaus, ss->upper_plateaus);
1154
1155
189k
    if (ss->choice)
1156
819
        return ss->choice;
1157
188k
    if (force) {
1158
483
        if (ss->gradients > plateaus / 12) /* messenger16.pdf, page 3. */
1159
423
            return 1; /* photo */
1160
60
        else if (plateaus && plateaus / 5000 >= ss->gradients)
1161
14
            return 2; /* lineart */
1162
483
    }
1163
188k
    return 0;
1164
188k
}
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.33k
{
1174
1.33k
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1175
1176
1.33k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
1177
1.33k
    ss->output_bits_buffer = 0;
1178
1.33k
    ss->output_bits_buffered = 0;
1179
1.33k
    ss->output_depth = 1;
1180
1.33k
    ss->output_component_index = ss->output_depth;
1181
1.33k
    ss->output_bits_per_sample = 1;
1182
1.33k
    ss->output_component_bits_written = 0;
1183
1.33k
    ss->raster = 0;
1184
1.33k
    ss->row_bits = 0;
1185
1.33k
    ss->row_bits_passed = 0;
1186
1.33k
    ss->row_alignment_bytes = 0;
1187
1.33k
    ss->row_alignment_bytes_left = 0;
1188
1.33k
    ss->input_component_index = 0;
1189
1.33k
    ss->input_bits_buffer = 0;
1190
1.33k
    ss->input_bits_buffered = 0;
1191
1.33k
    ss->convert_color = 0;
1192
1.33k
    ss->pcs = 0;
1193
1.33k
    ss->pdev = 0;
1194
1.33k
    ss->pgs = 0;
1195
1.33k
    return 0;
1196
1.33k
}
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
32.8M
{
1214
32.8M
    gs_client_color cc;
1215
32.8M
    gx_device_color dc;
1216
32.8M
    int i, code;
1217
32.8M
    double v0 = (1 << ss->bits_per_sample) - 1;
1218
32.8M
    double v1 = (1 << ss->output_bits_per_sample) - 1;
1219
32.8M
    gx_device *target;
1220
1221
32.8M
    target = ss->pdev;
1222
32.8M
    while(target->child)
1223
0
        target = target->child;
1224
1225
70.8M
    for (i = 0; i < ss->depth; i++)
1226
38.0M
        cc.paint.values[i] = ss->input_color[i] *
1227
38.0M
                (ss->Decode[i * 2 + 1] - ss->Decode[i * 2]) / v0 + ss->Decode[i * 2];
1228
1229
32.8M
    code = ss->pcs->type->remap_color(&cc, ss->pcs, &dc, ss->pgs,
1230
32.8M
                              target, gs_color_select_texture);
1231
32.8M
    if (code < 0)
1232
0
        return code;
1233
131M
    for (i = 0; i < ss->output_depth; i++) {
1234
98.6M
        uint m = (1 << target->color_info.comp_bits[i]) - 1;
1235
98.6M
        uint w = (dc.colors.pure >> target->color_info.comp_shift[i]) & m;
1236
1237
98.6M
        ss->output_color[i] = (uint)(v1 * w / m + 0.5);
1238
98.6M
    }
1239
32.8M
    return 0;
1240
32.8M
}
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.33k
{
1256
1.33k
    ss->width = width;
1257
1.33k
    ss->height = height;
1258
1.33k
    ss->depth = depth;
1259
1.33k
    ss->bits_per_sample = bits_per_sample;
1260
1.33k
    ss->row_bits = bits_per_sample * depth * input_width;
1261
1.33k
    ss->raster = bitmap_raster(ss->row_bits);
1262
1.33k
    ss->row_alignment_bytes = 0; /* (ss->raster * 8 - ss->row_bits) / 8) doesn't work. */
1263
1.33k
}
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.33k
{
1270
1.33k
    ss->output_depth = pdev->color_info.num_components;
1271
1.33k
    ss->output_component_index = ss->output_depth;
1272
1.33k
    ss->output_bits_per_sample = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
1273
1.33k
    ss->convert_color = s_image_colors_convert_to_device_color;
1274
1.33k
    ss->pdev = pdev;
1275
1.33k
    while(ss->pdev->parent)
1276
0
        ss->pdev = ss->pdev->parent;
1277
1278
1.33k
    ss->pcs = pcs;
1279
1.33k
    ss->pgs = pgs;
1280
1.33k
    memcpy(ss->Decode, Decode, ss->depth * sizeof(Decode[0]) * 2);
1281
1.33k
}
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
907k
{
1288
907k
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1289
1290
71.8M
    for (;;) {
1291
71.8M
        if (pw->ptr >= pw->limit)
1292
513k
            return 1;
1293
71.3M
        if (ss->row_bits_passed >= ss->row_bits) {
1294
56.8k
            ss->row_alignment_bytes_left = ss->row_alignment_bytes;
1295
56.8k
            ss->input_bits_buffered = 0;
1296
56.8k
            ss->input_bits_buffer = 0; /* Just to simplify the debugging. */
1297
56.8k
            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
56.8k
            ss->row_bits_passed = 0;
1303
56.8k
            continue;
1304
56.8k
        }
1305
71.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
71.2M
        if (ss->output_component_index < ss->output_depth) {
1316
131M
            for (;ss->output_component_index < ss->output_depth;) {
1317
98.8M
                uint fitting = (uint)(8 - ss->output_bits_buffered);
1318
98.8M
                uint v, w, u, n, m;
1319
1320
98.8M
                if (pw->ptr >= pw->limit)
1321
256k
                    return 1;
1322
98.6M
                v = ss->output_color[ss->output_component_index];
1323
98.6M
                n = ss->output_bits_per_sample - ss->output_component_bits_written; /* no. of bits left */
1324
98.6M
                w = v - ((v >> n) << n); /* the current component without written bits. */
1325
98.6M
                if (fitting > n)
1326
0
                    fitting = n; /* no. of bits to write. */
1327
98.6M
                m = n - fitting; /* no. of bits will left. */
1328
98.6M
                u = w >> m;  /* bits to write (near lsb). */
1329
98.6M
                ss->output_bits_buffer |= u << (8 - ss->output_bits_buffered - fitting);
1330
98.6M
                ss->output_bits_buffered += fitting;
1331
98.6M
                if (ss->output_bits_buffered >= 8) {
1332
98.6M
                    *(++pw->ptr) = ss->output_bits_buffer;
1333
98.6M
                    ss->output_bits_buffered = 0;
1334
98.6M
                    ss->output_bits_buffer = 0;
1335
98.6M
                }
1336
98.6M
                ss->output_component_bits_written += fitting;
1337
98.6M
                if (ss->output_component_bits_written >= ss->output_bits_per_sample) {
1338
98.6M
                    ss->output_component_index++;
1339
98.6M
                    ss->output_component_bits_written = 0;
1340
98.6M
                }
1341
98.6M
            }
1342
32.8M
            ss->row_bits_passed += ss->bits_per_sample * ss->depth;
1343
32.8M
            continue;
1344
33.1M
        }
1345
38.1M
        if (ss->input_bits_buffered < ss->bits_per_sample) {
1346
35.0M
            if (pr->ptr >= pr->limit)
1347
137k
                return 0;
1348
34.8M
            ss->input_bits_buffer = (ss->input_bits_buffer << 8) | *++pr->ptr;
1349
34.8M
            ss->input_bits_buffered += 8;
1350
            /* fixme: delay shifting the input ptr until input_bits_buffer is cleaned. */
1351
34.8M
        }
1352
38.0M
        if (ss->input_bits_buffered >= ss->bits_per_sample) {
1353
38.0M
            uint w;
1354
1355
38.0M
            ss->input_bits_buffered -= ss->bits_per_sample;
1356
38.0M
            ss->input_color[ss->input_component_index] = w = ss->input_bits_buffer >> ss->input_bits_buffered;
1357
38.0M
            ss->input_bits_buffer &= ~(w << ss->input_bits_buffered);
1358
38.0M
            ss->input_component_index++;
1359
38.0M
            if (ss->input_component_index >= ss->depth) {
1360
32.8M
                int code = ss->convert_color(ss);
1361
1362
32.8M
                if (code < 0)
1363
0
                    return ERRC;
1364
32.8M
                ss->output_component_index = 0;
1365
32.8M
                ss->input_component_index = 0;
1366
32.8M
            }
1367
38.0M
        }
1368
38.0M
    }
1369
907k
}
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
};