Coverage Report

Created: 2026-07-24 07:44

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