Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/devices/vector/gdevpsds.c
Line
Count
Source (jump to first uncovered line)
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
10.7k
{
934
10.7k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
935
936
10.7k
    ss->choice = 0;
937
10.7k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
938
10.7k
    ss->sample = 0;
939
10.7k
    ss->samples_count = 0;
940
10.7k
    ss->bits_left = 0;
941
10.7k
    ss->packed_data = 0;
942
10.7k
    ss->lower_plateaus = ss->upper_plateaus = 0;
943
10.7k
    ss->gradients = 0;
944
10.7k
    return 0;
945
10.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
10.7k
{
952
10.7k
    ss->width = width;
953
10.7k
    ss->height = height;
954
10.7k
    ss->depth = depth;
955
10.7k
    ss->bits_per_sample = bits_per_sample;
956
10.7k
    ss->sample = gs_alloc_bytes(ss->memory, (size_t)width * depth,
957
10.7k
                                "s_compr_chooser_set_dimensions");
958
10.7k
    if (ss->sample == 0)
959
0
        return_error(gs_error_VMerror);
960
10.7k
    return 0;
961
10.7k
}
962
963
/* Release state. */
964
static void
965
s_compr_chooser_release(stream_state * st)
966
10.7k
{
967
10.7k
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
968
969
10.7k
    gs_free_object(ss->memory, ss->sample, "s_compr_chooser_release");
970
10.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
2.47M
{
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
2.47M
    const int delta = 256 / 16; /* about 1/16 of the color range */
987
2.47M
    const int max_lineart_boundary_width = 3; /* pixels */
988
2.47M
    const int max_gradient_constant = 10; /* pixels */
989
2.47M
    int i, j0 = 0, j1 = 0;
990
2.47M
    int w0 = p[0], w1 = p[0], v;
991
2.47M
    ulong plateau_count = 0, lower_plateaus = 0;
992
2.47M
    ulong upper_plateaus = 0, gradients = 0;
993
2.47M
    bool lower = false, upper = false;
994
995
748M
    for (i = 1; i < ss->width; i++) {
996
745M
        v = p[i];
997
745M
        if (!lower) {
998
666M
            if (w1 < v) {
999
10.4M
                if (!upper)
1000
6.24M
                    j1 = i - 1;
1001
10.4M
                w1 = v;
1002
10.4M
                upper = true;
1003
655M
            } else if (w1 == v && j1 < i - max_gradient_constant)
1004
577M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1005
77.8M
            else if (upper && w1 - delta > v) {
1006
                /* end of upper plateau at w1-delta...w1 */
1007
24.9M
                for (j0 = i - 1; j0 > j1 && w1 - delta <= p[j0]; j0--) DO_NOTHING;
1008
                /* upper plateau j0+1...i-1 */
1009
5.50M
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1010
5.47M
                    upper_plateaus += i - j0;
1011
5.50M
                plateau_count ++;
1012
5.50M
                if (j0 > j1) {
1013
                    /* upgrade j1...j0 */
1014
358k
                    if (j0 > j1 + max_lineart_boundary_width)
1015
129k
                        gradients += j0 - j1;
1016
358k
                }
1017
5.50M
                j1 = i;
1018
5.50M
                upper = false;
1019
5.50M
                w0 = w1;
1020
5.50M
                continue;
1021
5.50M
            }
1022
666M
        }
1023
740M
        if (!upper) {
1024
631M
            if (w0 > v) {
1025
10.4M
                if (!lower)
1026
6.57M
                    j1 = i - 1;
1027
10.4M
                w0 = v;
1028
10.4M
                lower = true;
1029
620M
            } else if (w0 == v && j1 < i - max_gradient_constant)
1030
33.3M
                j1 = i - max_gradient_constant; /* inner constant plateaw */
1031
587M
            else if (lower && w0 + delta < v) {
1032
                /* end of lower plateau at w0...w0+delta */
1033
45.3M
                for (j0 = i - 1; j0 > j1 && w0 + delta >= p[j0]; j0--) DO_NOTHING;
1034
                /* lower plateau j0+1...i-1 */
1035
6.29M
                if(j0 > 0 && i < ss->width - 1) /* ignore sides */
1036
5.93M
                    lower_plateaus += i - j0;
1037
6.29M
                plateau_count ++;
1038
6.29M
                if (j0 > j1) {
1039
                    /* downgrade j1...j0 */
1040
285k
                    if (j0 > j1 + max_lineart_boundary_width)
1041
101k
                        gradients += j0 - j1;
1042
285k
                }
1043
6.29M
                j1 = i;
1044
6.29M
                lower = false;
1045
6.29M
                w1 = w0;
1046
6.29M
            }
1047
631M
        }
1048
740M
    }
1049
2.47M
    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
2.46M
    } else if (!plateau_count) /* a pseudo-constant color through entire row */
1055
2.46M
        DO_NOTHING; /* ignore such lines */
1056
1.24M
    else {
1057
1.24M
        int plateaus;
1058
1.24M
        ss->lower_plateaus += lower_plateaus;
1059
1.24M
        ss->upper_plateaus += upper_plateaus;
1060
1.24M
        ss->gradients += gradients;
1061
1.24M
        plateaus = min(ss->lower_plateaus, ss->upper_plateaus); /* (fore/back)ground */
1062
1.24M
        if (ss->gradients >= 10000 && ss->gradients > plateaus / 6)
1063
2.78k
            ss->choice = 1; /* choice is made : photo */
1064
1.24M
        else if (plateaus >= 100000 && plateaus / 5000 >= ss->gradients)
1065
5.63k
            ss->choice = 2; /* choice is made : lineart */
1066
1.24M
    }
1067
2.47M
}
1068
1069
/* Recognize photo/lineart. */
1070
static void
1071
s_compr_chooser__recognize(stream_compr_chooser_state * ss)
1072
1.44M
{
1073
1.44M
    int i;
1074
1.44M
    byte *p = ss->sample;
1075
1076
3.91M
    for (i = 0; i < ss->depth; i++, p += ss->width)
1077
2.47M
        s_compr_chooser__estimate_row(ss, p);
1078
    /* todo: make decision */
1079
1.44M
}
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
2.11M
{
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
2.11M
    uint i = (ss->samples_count % ss->depth) * ss->width;
1092
2.11M
    uint j = ss->samples_count / ss->depth;
1093
2.11M
    const byte *p = data;
1094
2.11M
    int l = length;
1095
1096
137M
    while (l) {
1097
135M
        if (ss->bits_left <= 8) {
1098
135M
            uint k = (sizeof(ss->packed_data) * 8 - ss->bits_left) / 8;
1099
1100
135M
            k = min(k, l);
1101
676M
            for (; k; k--, l--, p++, ss->bits_left += 8)
1102
541M
                ss->packed_data = (ss->packed_data << 8) + *p;
1103
135M
        }
1104
884M
        while (ss->bits_left >= ss->bits_per_sample) {
1105
749M
            uint k = ss->bits_left - ss->bits_per_sample;
1106
749M
            ulong v = ss->packed_data >> k;
1107
1108
749M
            ss->packed_data -= (v << k);
1109
749M
            ss->bits_left -= ss->bits_per_sample;
1110
749M
            if (ss->bits_per_sample > 8)
1111
0
                v >>= ss->bits_per_sample - 8;
1112
749M
            else
1113
749M
                v <<= 8 - ss->bits_per_sample;
1114
749M
            ss->sample[i + j] = (byte)v;  /* scaled to 0...255 */
1115
749M
            i += ss->width;
1116
749M
            if (i >= ss->width * ss->depth)
1117
495M
                i = 0, j++;
1118
749M
            ss->samples_count++;
1119
749M
            if (ss->samples_count >= ss->width * ss->depth) {
1120
1.44M
                s_compr_chooser__recognize(ss);
1121
1.44M
                ss->packed_data = 0;
1122
1.44M
                ss->bits_left = 0;
1123
1.44M
                ss->samples_count = 0;
1124
1.44M
                i = j = 0;
1125
1.44M
            }
1126
749M
        }
1127
135M
    }
1128
2.11M
}
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
2.11M
{
1135
2.11M
    stream_compr_chooser_state *const ss = (stream_compr_chooser_state *) st;
1136
2.11M
    int l = pr->limit - pr->ptr;
1137
1138
2.11M
    if (ss->width >= 3) /* Can't process narrow images. */
1139
2.11M
        s_compr_chooser__unpack_and_recognize(ss, pr->ptr + 1, l);
1140
2.11M
    pr->ptr += l;
1141
2.11M
    return 0;
1142
2.11M
}
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
862k
{
1153
862k
    ulong plateaus = min(ss->lower_plateaus, ss->upper_plateaus);
1154
1155
862k
    if (ss->choice)
1156
2.72k
        return ss->choice;
1157
859k
    if (force) {
1158
1.54k
        if (ss->gradients > plateaus / 12) /* messenger16.pdf, page 3. */
1159
716
            return 1; /* photo */
1160
829
        else if (plateaus && plateaus / 5000 >= ss->gradients)
1161
514
            return 2; /* lineart */
1162
1.54k
    }
1163
858k
    return 0;
1164
859k
}
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.53k
{
1174
1.53k
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1175
1176
1.53k
    ss->width = ss->height = ss->depth = ss->bits_per_sample = 0;
1177
1.53k
    ss->output_bits_buffer = 0;
1178
1.53k
    ss->output_bits_buffered = 0;
1179
1.53k
    ss->output_depth = 1;
1180
1.53k
    ss->output_component_index = ss->output_depth;
1181
1.53k
    ss->output_bits_per_sample = 1;
1182
1.53k
    ss->output_component_bits_written = 0;
1183
1.53k
    ss->raster = 0;
1184
1.53k
    ss->row_bits = 0;
1185
1.53k
    ss->row_bits_passed = 0;
1186
1.53k
    ss->row_alignment_bytes = 0;
1187
1.53k
    ss->row_alignment_bytes_left = 0;
1188
1.53k
    ss->input_component_index = 0;
1189
1.53k
    ss->input_bits_buffer = 0;
1190
1.53k
    ss->input_bits_buffered = 0;
1191
1.53k
    ss->convert_color = 0;
1192
1.53k
    ss->pcs = 0;
1193
1.53k
    ss->pdev = 0;
1194
1.53k
    ss->pgs = 0;
1195
1.53k
    return 0;
1196
1.53k
}
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
76.7M
{
1214
76.7M
    gs_client_color cc;
1215
76.7M
    gx_device_color dc;
1216
76.7M
    int i, code;
1217
76.7M
    double v0 = (1 << ss->bits_per_sample) - 1;
1218
76.7M
    double v1 = (1 << ss->output_bits_per_sample) - 1;
1219
76.7M
    gx_device *target;
1220
1221
76.7M
    target = ss->pdev;
1222
76.7M
    while(target->child)
1223
0
        target = target->child;
1224
1225
173M
    for (i = 0; i < ss->depth; i++)
1226
96.2M
        cc.paint.values[i] = ss->input_color[i] *
1227
96.2M
                (ss->Decode[i * 2 + 1] - ss->Decode[i * 2]) / v0 + ss->Decode[i * 2];
1228
1229
76.7M
    code = ss->pcs->type->remap_color(&cc, ss->pcs, &dc, ss->pgs,
1230
76.7M
                              target, gs_color_select_texture);
1231
76.7M
    if (code < 0)
1232
0
        return code;
1233
307M
    for (i = 0; i < ss->output_depth; i++) {
1234
230M
        uint m = (1 << target->color_info.comp_bits[i]) - 1;
1235
230M
        uint w = (dc.colors.pure >> target->color_info.comp_shift[i]) & m;
1236
1237
230M
        ss->output_color[i] = (uint)(v1 * w / m + 0.5);
1238
230M
    }
1239
76.7M
    return 0;
1240
76.7M
}
1241
1242
/* Set mask colors dimensions. */
1243
void
1244
s_image_colors_set_mask_colors(stream_image_colors_state * ss, uint *MaskColor)
1245
0
{
1246
0
    ss->convert_color = s_image_colors_convert_color_to_mask;
1247
0
    memcpy(ss->MaskColor, MaskColor, ss->depth * sizeof(MaskColor[0]) * 2);
1248
0
}
1249
1250
/* Set image dimensions. */
1251
void
1252
s_image_colors_set_dimensions(stream_image_colors_state * ss,
1253
                              int width, int height, int input_width,
1254
                              int depth, int bits_per_sample)
1255
1.53k
{
1256
1.53k
    ss->width = width;
1257
1.53k
    ss->height = height;
1258
1.53k
    ss->depth = depth;
1259
1.53k
    ss->bits_per_sample = bits_per_sample;
1260
1.53k
    ss->row_bits = bits_per_sample * depth * input_width;
1261
1.53k
    ss->raster = bitmap_raster(ss->row_bits);
1262
1.53k
    ss->row_alignment_bytes = 0; /* (ss->raster * 8 - ss->row_bits) / 8) doesn't work. */
1263
1.53k
}
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.53k
{
1270
1.53k
    ss->output_depth = pdev->color_info.num_components;
1271
1.53k
    ss->output_component_index = ss->output_depth;
1272
1.53k
    ss->output_bits_per_sample = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
1273
1.53k
    ss->convert_color = s_image_colors_convert_to_device_color;
1274
1.53k
    ss->pdev = pdev;
1275
1.53k
    while(ss->pdev->parent)
1276
0
        ss->pdev = ss->pdev->parent;
1277
1278
1.53k
    ss->pcs = pcs;
1279
1.53k
    ss->pgs = pgs;
1280
1.53k
    memcpy(ss->Decode, Decode, ss->depth * sizeof(Decode[0]) * 2);
1281
1.53k
}
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
2.11M
{
1288
2.11M
    stream_image_colors_state *const ss = (stream_image_colors_state *) st;
1289
1290
175M
    for (;;) {
1291
175M
        if (pw->ptr >= pw->limit)
1292
1.19M
            return 1;
1293
174M
        if (ss->row_bits_passed >= ss->row_bits) {
1294
97.5k
            ss->row_alignment_bytes_left = ss->row_alignment_bytes;
1295
97.5k
            ss->input_bits_buffered = 0;
1296
97.5k
            ss->input_bits_buffer = 0; /* Just to simplify the debugging. */
1297
97.5k
            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
97.5k
            ss->row_bits_passed = 0;
1303
97.5k
            continue;
1304
97.5k
        }
1305
173M
        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
173M
        if (ss->output_component_index < ss->output_depth) {
1316
307M
            for (;ss->output_component_index < ss->output_depth;) {
1317
230M
                uint fitting = (uint)(8 - ss->output_bits_buffered);
1318
230M
                uint v, w, u, n, m;
1319
1320
230M
                if (pw->ptr >= pw->limit)
1321
599k
                    return 1;
1322
230M
                v = ss->output_color[ss->output_component_index];
1323
230M
                n = ss->output_bits_per_sample - ss->output_component_bits_written; /* no. of bits left */
1324
230M
                w = v - ((v >> n) << n); /* the current component without written bits. */
1325
230M
                if (fitting > n)
1326
0
                    fitting = n; /* no. of bits to write. */
1327
230M
                m = n - fitting; /* no. of bits will left. */
1328
230M
                u = w >> m;  /* bits to write (near lsb). */
1329
230M
                ss->output_bits_buffer |= u << (8 - ss->output_bits_buffered - fitting);
1330
230M
                ss->output_bits_buffered += fitting;
1331
230M
                if (ss->output_bits_buffered >= 8) {
1332
230M
                    *(++pw->ptr) = ss->output_bits_buffer;
1333
230M
                    ss->output_bits_buffered = 0;
1334
230M
                    ss->output_bits_buffer = 0;
1335
230M
                }
1336
230M
                ss->output_component_bits_written += fitting;
1337
230M
                if (ss->output_component_bits_written >= ss->output_bits_per_sample) {
1338
230M
                    ss->output_component_index++;
1339
230M
                    ss->output_component_bits_written = 0;
1340
230M
                }
1341
230M
            }
1342
76.7M
            ss->row_bits_passed += ss->bits_per_sample * ss->depth;
1343
76.7M
            continue;
1344
77.3M
        }
1345
96.5M
        if (ss->input_bits_buffered < ss->bits_per_sample) {
1346
81.7M
            if (pr->ptr >= pr->limit)
1347
319k
                return 0;
1348
81.3M
            ss->input_bits_buffer = (ss->input_bits_buffer << 8) | *++pr->ptr;
1349
81.3M
            ss->input_bits_buffered += 8;
1350
            /* fixme: delay shifting the input ptr until input_bits_buffer is cleaned. */
1351
81.3M
        }
1352
96.2M
        if (ss->input_bits_buffered >= ss->bits_per_sample) {
1353
96.2M
            uint w;
1354
1355
96.2M
            ss->input_bits_buffered -= ss->bits_per_sample;
1356
96.2M
            ss->input_color[ss->input_component_index] = w = ss->input_bits_buffer >> ss->input_bits_buffered;
1357
96.2M
            ss->input_bits_buffer &= ~(w << ss->input_bits_buffered);
1358
96.2M
            ss->input_component_index++;
1359
96.2M
            if (ss->input_component_index >= ss->depth) {
1360
76.7M
                int code = ss->convert_color(ss);
1361
1362
76.7M
                if (code < 0)
1363
0
                    return ERRC;
1364
76.7M
                ss->output_component_index = 0;
1365
76.7M
                ss->input_component_index = 0;
1366
76.7M
            }
1367
96.2M
        }
1368
96.2M
    }
1369
2.11M
}
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
};