Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/rtraster.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
/* rtraster.c - raster transfer commands */
18
19
#include "memory_.h"
20
#include "strimpl.h"
21
#include "scfx.h"
22
#include "scf.h"
23
#include "stream.h"
24
#include "gx.h"
25
#include "gsmatrix.h"
26
#include "gscoord.h"
27
#include "gspath.h"
28
#include "gspath2.h"
29
#include "gsimage.h"
30
#include "gsiparam.h"
31
#include "gsiparm4.h"
32
#include "gsdevice.h"
33
#include "gsrop.h"
34
#include "pcstate.h"
35
#include "pcpalet.h"
36
#include "pcpage.h"
37
#include "pcindxed.h"
38
#include "pcwhtidx.h"
39
#include "pcdraw.h"
40
#include "plvalue.h"
41
#include "rtgmode.h"
42
#include "rtrstcmp.h"
43
#include "rtraster.h"
44
45
/*
46
 * The maximum number of planes for which seed rows need to be kept. This is the
47
 * larger of the maximum number of bits per index (for pixel encoding mode 0 -
48
 * indexed by plane) or maximum of the sum over the primaries of the number of
49
 * bits per primary for pixel encoding mode 2 (direct by plane). For all
50
 * current PCL printers, the effective bound is the the former, and is 8.
51
 */
52
#define MAX_PLANES  8
53
54
/*
55
 * Structure to describe a PCL raster
56
 */
57
typedef struct pcl_raster_s
58
{
59
60
    /* memory used to allocate this structure */
61
    gs_memory_t *pmem;
62
63
    byte nplanes;               /* # of planes (seed rows) */
64
    byte bits_per_plane;        /* bits per plane */
65
    byte nsrcs;                 /* # of data sources, 1 or 3 */
66
67
    uint transparent:1;         /* 1 ==> source transparency */
68
    uint src_height_set:1;      /* source height was set */
69
    uint indexed:1;             /* != 0 ==> indexed color space */
70
    uint zero_is_white:1;       /* all planes 0 ==> white */
71
    uint zero_is_black:1;       /* all planes 0 ==> solid color */
72
    uint interpolate:1;         /* enable interpolation */
73
    int wht_indx;               /* white index, for indexed color
74
                                   space only */
75
    const void *remap_ary;      /* remap array, if needed */
76
77
    pcl_state_t *pcs;           /* to avoid n extra operand */
78
    pcl_cs_indexed_t *pindexed; /* color space */
79
80
    gs_image_enum *pen;         /* image enumerator */
81
    uint   plane_index;         /* next plane to be received */
82
    uint   rows_rendered;       /* # of source rows rendered */
83
    uint   src_width;           /* usable raster width */
84
    uint   src_height;          /* remaining usable raster height */
85
86
    /* objects required for opaque source/transparent pattern case */
87
    gs_image_enum *mask_pen;    /* enumerator for mask */
88
    pcl_cs_indexed_t *mask_pindexed;    /* special color space for mask */
89
    ulong white_val;            /* value interpreted as white */
90
    void (*gen_mask_row) (struct pcl_raster_s * prast);
91
92
    /* buffers */
93
    pcl_seed_row_t *pseed_rows; /* seed rows, one per plane */
94
    byte *cons_buff;            /* consolidation buffer */
95
    byte *mask_buff;            /* buffer for mask row, if needed */
96
97
} pcl_raster_t;
98
99
gs_private_st_simple(st_seed_row_t_element, pcl_seed_row_t,
100
                     "PCL seed row array");
101
gs_private_st_simple(st_raster_t, pcl_raster_t, "PCL raster object");
102
103
/* forward declaration */
104
static int process_zero_rows(pcl_raster_t * prast, int nrows);
105
106
/*
107
 * Clear the consolidation buffer, allocating it if it does not already
108
 * exist.
109
 *
110
 * Returns 0 on success, < 0 in the event of an error.
111
 */
112
static int
113
clear_cons_buff(pcl_raster_t * prast)
114
17.1k
{
115
17.1k
    byte *pcons = prast->cons_buff;
116
17.1k
    int npixels = prast->src_width;
117
118
17.1k
    if (pcons == 0) {
119
743
        pcons = gs_alloc_bytes(prast->pmem,
120
743
                               npixels, "PCL raster consolidation buff");
121
743
        if (pcons == 0)
122
0
            return e_Memory;
123
743
        prast->cons_buff = pcons;
124
743
    }
125
17.1k
    memset(pcons, 0, npixels);
126
127
17.1k
    return 0;
128
17.1k
}
129
130
/*
131
 * Clear the mask buffer, allocating it if it does not exist.
132
 *
133
 * Returns 0 on success, < 0 in the event of an error.
134
 */
135
static int
136
clear_mask_buff(pcl_raster_t * prast)
137
0
{
138
0
    byte *pmask = prast->mask_buff;
139
0
    int nbytes = (prast->src_width + 7) / 8;
140
141
0
    if (pmask == 0) {
142
0
        pmask = gs_alloc_bytes(prast->pmem, nbytes, "PCL raster mask buffer");
143
0
        if (pmask == 0)
144
0
            return e_Memory;
145
0
        prast->mask_buff = pmask;
146
0
    }
147
0
    memset(pmask, 0, nbytes);
148
149
0
    return 0;
150
151
0
}
152
153
/*
154
 * Generate a mask row in case there are multiple data sources (in the graphic
155
 * library sense). This code takes much advantage of the knowledge that the
156
 * mutliple source case is always direct and one bit per pixel.
157
 */
158
static void
159
gen_mask_multisrc(pcl_raster_t * prast)
160
0
{
161
0
    byte *ip0 = prast->pseed_rows[0].pdata;
162
0
    byte *ip1 = prast->pseed_rows[1].pdata;
163
0
    byte *ip2 = prast->pseed_rows[2].pdata;
164
0
    byte *op = prast->mask_buff;
165
0
    uint m0 = (prast->white_val >> 16) & 0xff;
166
0
    uint m1 = (prast->white_val >> 8) & 0xff;
167
0
    uint m2 = prast->white_val & 0xff;
168
0
    int nbytes = prast->pseed_rows[0].size;
169
0
    int i;
170
171
0
    for (i = 0; i < nbytes; i++)
172
0
        *op++ = (*ip0++ ^ m0) & (*ip1++ ^ m1) & (*ip2++ ^ m2);
173
0
}
174
175
/*
176
 * Generate a mask from input data that is less than one byte. For PCL rasters
177
 * as implemented by this routine, such situations only occur when an integral
178
 * number of pixels fit within one byte, and this routine takes advantage of
179
 * that situation.
180
 */
181
static void
182
gen_mask_subbyte(pcl_raster_t * prast)
183
0
{
184
0
    byte *ip = prast->pseed_rows[0].pdata;
185
0
    byte *op = prast->mask_buff;
186
0
    int ishift = prast->bits_per_plane;
187
0
    uint targ = prast->white_val;
188
0
    int size = prast->src_width;
189
0
    uint ival, oval, imask, omask;
190
0
    int i;
191
192
0
    for (i = 0, ival = 0, oval = 0, imask = 0, omask = 0x80; i < size; i++) {
193
0
        if ((imask >>= ishift) == 0) {
194
0
            imask = 0xff - (0xff >> ishift);
195
0
            ival = *ip++;
196
0
        }
197
0
        if (((ival ^ targ) & imask) == 0)
198
0
            oval |= omask;
199
0
        if ((omask >>= 1) == 0) {
200
0
            *op++ = oval;
201
0
            omask = 0x80;
202
0
            oval = 0;
203
0
        }
204
0
    }
205
0
    if (omask != 0x80)
206
0
        *op++ = oval;
207
0
}
208
209
/*
210
 * Generate a mask from input data that has one byte per pixel.
211
 */
212
static void
213
gen_mask_1byte(pcl_raster_t * prast)
214
0
{
215
0
    byte *ip = (prast->nplanes == 1 ? prast->pseed_rows[0].pdata
216
0
                : prast->cons_buff);
217
0
    byte *op = prast->mask_buff;
218
0
    uint targ = prast->white_val;
219
0
    int size = prast->src_width;
220
0
    uint oval, omask;
221
0
    int i;
222
223
0
    for (i = 0, oval = 0, omask = 0x80; i < size; i++) {
224
0
        if (*ip++ == targ)
225
0
            oval |= omask;
226
0
        if ((omask >>= 1) == 0) {
227
0
            *op++ = oval;
228
0
            omask = 0x80;
229
0
            oval = 0;
230
0
        }
231
0
    }
232
0
    if (omask != 0x80)
233
0
        *op++ = oval;
234
0
}
235
236
/*
237
 * Generate a mask row in the case that more than one byte is required per
238
 * pixel. The only possible such case in PCL is 8-bits per primary 3 color,
239
 * so this routine handles only that case.
240
 */
241
static void
242
gen_mask_multibyte(pcl_raster_t * prast)
243
0
{
244
0
    byte *ip = prast->pseed_rows[0].pdata;
245
0
    byte *op = prast->mask_buff;
246
0
    int size = prast->src_width;
247
0
    ulong targ = prast->white_val;
248
0
    uint oval, omask;
249
0
    int i;
250
251
0
    for (i = 0, oval = 0, omask = 0x80; i < size; i++, ip += 3) {
252
0
        ulong ival = (((ulong) ip[0]) << 16) | (((ulong) ip[1]) << 8) | ip[2];
253
254
0
        if (ival == targ)
255
0
            oval |= omask;
256
0
        if ((omask >>= 1) == 0) {
257
0
            *op++ = oval;
258
0
            omask = 0x80;
259
0
            oval = 0;
260
0
        }
261
0
    }
262
0
    if (omask != 0x80)
263
0
        *op++ = oval;
264
0
}
265
266
/*
267
 * Consolidate a set of seed rows into the consolidated row buffer.
268
 *
269
 * This routine will only be called if:
270
 *
271
 *      prast->nplanes > 1
272
 *      prast->bits_per_plane = 1
273
 *      prast->nsrcs = 1
274
 *
275
 * The output is always packed 8 bits per pixel, even if ferwer are required.
276
 *
277
 * Returns 0 on success, < 0 in the event of an error.
278
 */
279
static int
280
consolidate_row(pcl_raster_t * prast)
281
17.1k
{
282
17.1k
    byte *pcons;
283
17.1k
    uint nplanes = prast->nplanes;
284
17.1k
    uint npixels = prast->src_width;
285
17.1k
    int code, i;
286
287
    /* clear the consolidation buffer */
288
17.1k
    if ((code = clear_cons_buff(prast)) < 0)
289
0
        return code;
290
17.1k
    pcons = prast->cons_buff;
291
292
    /* for each plane, "or" in the appropriate bit */
293
68.4k
    for (i = 0; i < nplanes; i++) {
294
51.3k
        if (!prast->pseed_rows[i].is_blank) {
295
14.4k
            const byte *ip = prast->pseed_rows[i].pdata;
296
14.4k
            byte *op = pcons;
297
14.4k
            int cnt = npixels;
298
299
1.72M
            for (; cnt >= 8; ip++, op += 8, cnt -= 8) {
300
1.70M
                uint val = *ip;
301
302
                /*
303
                 * cons_buff was allocated with gs_alloc_bytes, so we know
304
                 * it is aligned for (at least) bits32 access.
305
                 */
306
#if ARCH_IS_BIG_ENDIAN
307
                static const bits32 spread[16] = {
308
                    0x00000000, 0x00000001, 0x00000100, 0x00000101,
309
                    0x00010000, 0x00010001, 0x00010100, 0x00010101,
310
                    0x01000000, 0x01000001, 0x01000100, 0x01000101,
311
                    0x01010000, 0x01010001, 0x01010100, 0x01010101
312
                };
313
#else
314
1.70M
                static const bits32 spread[16] = {
315
1.70M
                    0x00000000, 0x01000000, 0x00010000, 0x01010000,
316
1.70M
                    0x00000100, 0x01000100, 0x00010100, 0x01010100,
317
1.70M
                    0x00000001, 0x01000001, 0x00010001, 0x01010001,
318
1.70M
                    0x00000101, 0x01000101, 0x00010101, 0x01010101
319
1.70M
                };
320
1.70M
#endif
321
1.70M
                ((bits32 *) op)[0] |= spread[val >> 4] << i;
322
1.70M
                ((bits32 *) op)[1] |= spread[val & 0xf] << i;
323
1.70M
            }
324
14.4k
            if (cnt) {
325
14.2k
                uint ishift = 7;
326
14.2k
                uint val = *ip;
327
328
40.1k
                do {
329
40.1k
                    *op++ |= ((val >> ishift--) & 0x1) << i;
330
40.1k
                } while (--cnt > 0);
331
14.2k
            }
332
14.4k
        }
333
51.3k
    }
334
335
17.1k
    return 0;
336
17.1k
}
337
338
/*
339
 * Create an enumerator for the mask portion of an image (if required).
340
 *
341
 * Returns 0 on success, < 0 in the event of an error.
342
 */
343
static int
344
create_mask_enumerator(pcl_raster_t * prast)
345
0
{
346
0
    int transparent = prast->transparent;
347
348
    /*
349
     * Most elements of gs_image1_t and gs_image4_t are identical.  The only exception
350
     * that we care about is MaskColor in gs_image_type4_t.
351
     */
352
0
    union
353
0
    {
354
0
        gs_image1_t i1;
355
0
        gs_image4_t i4;
356
0
    } image;
357
358
0
    gs_image_enum *pen = gs_image_enum_alloc(prast->pmem,
359
0
                                             "Create image for PCL raster");
360
0
    int code = 0;
361
0
    const byte *pcolor = 0;
362
0
    gx_image_enum_common_t *pie = 0;
363
0
    pcl_state_t *pcs = prast->pcs;
364
365
0
    if (pen == 0)
366
0
        return e_Memory;
367
368
0
    code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true);
369
0
    if (code < 0)
370
0
        return code;
371
372
    /* generate the special two entry indexed color space required */
373
0
    if (prast->indexed)
374
0
        pcolor = prast->pindexed->palette.data + 3 * prast->wht_indx;
375
0
    else {
376
0
        static const byte cwhite[3] = { 1, 1, 1 };
377
378
0
        pcolor = cwhite;
379
0
    }
380
0
    code = pcl_cs_indexed_build_special(&(prast->mask_pindexed),
381
0
                                        prast->pindexed->pbase,
382
0
                                        pcolor, prast->pmem);
383
384
0
    if (code >= 0) {
385
0
        if (transparent)
386
0
            gs_image4_t_init((gs_image4_t *) & image,
387
0
                             prast->mask_pindexed->pcspace);
388
0
        else
389
0
            gs_image_t_init_adjust((gs_image_t *) & image,
390
0
                                   prast->mask_pindexed->pcspace, 0);
391
0
        image.i1.Width = prast->src_width;
392
0
        image.i1.Height = prast->src_height;
393
394
0
        if (pcs->personality == pcl5e)
395
0
            image.i1.CombineWithColor = false;
396
0
        else
397
0
            image.i1.CombineWithColor = true;
398
0
        image.i1.format = gs_image_format_chunky;
399
0
        image.i1.BitsPerComponent = 1;
400
0
        image.i1.Decode[0] = 0.0;
401
0
        image.i1.Decode[1] = 1.0;
402
0
        if (transparent)
403
0
            image.i4.MaskColor[0] = 0;
404
405
0
        code = gs_image_begin_typed((const gs_image_common_t *)&image,
406
0
                                    pcs->pgs, true, false, &pie);
407
408
0
        if (code >= 0)
409
0
            code = gs_image_common_init(pen,
410
0
                                        pie,
411
0
                                        (gs_data_image_t *) & image,
412
0
                                        gs_currentdevice_inline(pcs->pgs)
413
0
                );
414
0
    }
415
416
0
    if (code < 0)
417
0
        gs_free_object(prast->pmem, pen, "Create image for PCL raster");
418
0
    else
419
0
        prast->mask_pen = pen;
420
421
0
    if (code >= 0)
422
0
        code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true);
423
424
0
    return code;
425
0
}
426
427
/*
428
 * Create the graphic library image object needed to represent a raster.
429
 *
430
 * If the image does not use transparency then we need to use image type 1 processing.
431
 * Otherwise we need to use image type 4.  Most of the setup is the same for both
432
 * cases.  Thus rather than split this into two routines with a lot redundant code
433
 * I am keeping one routine with a union structure (image) and some conditionals.
434
 *
435
 * Returns 0 on success, < 0 in the event of an error.
436
 */
437
static int
438
create_image_enumerator(pcl_raster_t * prast)
439
4.43k
{
440
4.43k
    int nplanes = prast->nplanes;
441
4.43k
    int b_per_p = prast->bits_per_plane;
442
4.43k
    int num_comps = (prast->indexed ? 1 : 3);
443
4.43k
    int nsrcs = prast->nsrcs;
444
445
    /*
446
     * Most elements of gs_image1_t and gs_image4_t are identical.  The only exception
447
     * that we care about is MaskColor in gs_image_type4_t.
448
     */
449
4.43k
    int use_image4 = prast->transparent;
450
451
4.43k
    union
452
4.43k
    {
453
4.43k
        gs_image1_t i1;
454
4.43k
        gs_image4_t i4;
455
4.43k
    } image;
456
4.43k
    gs_image_enum *pen = gs_image_enum_alloc(prast->pmem,
457
4.43k
                                             "Create image for PCL raster");
458
4.43k
    gx_image_enum_common_t *pie = 0;
459
4.43k
    gs_color_space *pcspace = (prast->indexed
460
4.43k
                               ? prast->pindexed->pcspace
461
4.43k
                               : prast->pindexed->pbase->pcspace);
462
4.43k
    int code = 0;
463
464
4.43k
    if (pen == 0)
465
0
        return e_Memory;
466
467
    /*
468
     * There is one more case in which we will not use image type 4 processing.
469
     * If our color specifications are indexed and the wht_index value is greater
470
     * then the largest possible value given the number of index bits, then it is
471
     * not possible to ever get a 'white' (transparent) value.  Thus skip
472
     * transparency in this case.
473
     */
474
4.43k
    if ((prast->indexed) && (prast->wht_indx >= 1 << (nplanes * b_per_p)))
475
0
        use_image4 = 0;
476
477
    /* we also don't use an image type 4 if the user has requested
478
       interpolation */
479
4.43k
    if (prast->interpolate)
480
0
        use_image4 = 0;
481
482
4.43k
    if (use_image4)
483
4.30k
        gs_image4_t_init((gs_image4_t *) & image, pcspace);
484
133
    else
485
133
        gs_image_t_init_adjust((gs_image_t *) & image, pcspace, 0);
486
4.43k
    image.i1.Width = prast->src_width;
487
4.43k
    image.i1.Height = prast->src_height;
488
4.43k
    image.i1.CombineWithColor = true;
489
4.43k
    image.i1.format = (nsrcs > 1 ? gs_image_format_component_planar
490
4.43k
                       : gs_image_format_chunky);
491
492
4.43k
    if (nplanes > nsrcs)
493
743
        image.i1.BitsPerComponent = 8;  /* always 8 bits per pixel if consolidated */
494
3.69k
    else
495
3.69k
        image.i1.BitsPerComponent = (nplanes * b_per_p) / num_comps;
496
497
4.43k
    image.i1.Interpolate = prast->interpolate;
498
499
4.43k
    if (prast->indexed) {
500
4.43k
        if (use_image4)
501
4.30k
            image.i4.MaskColor[0] = prast->wht_indx;
502
4.43k
        image.i1.Decode[0] = 0.0;
503
4.43k
        image.i1.Decode[1] = (float)((1 << image.i1.BitsPerComponent) - 1);
504
4.43k
    } else {
505
0
        int i;
506
507
0
        for (i = 0; i < num_comps; i++) {
508
0
            image.i1.Decode[2 * i] = prast->pindexed->Decode[2 * i];
509
0
            image.i1.Decode[2 * i + 1] = prast->pindexed->Decode[2 * i + 1];
510
511
0
            if (use_image4) {
512
0
                image.i4.MaskColor[i] = (1 << image.i1.BitsPerComponent);
513
0
                if (image.i1.Decode[2 * i] == 1.0)
514
0
                    image.i4.MaskColor[i] = 0;
515
0
                else if (image.i1.Decode[2 * i + 1] == 1.0)
516
0
                    image.i4.MaskColor[i] =
517
0
                        (1 << image.i1.BitsPerComponent) - 1;
518
0
            }
519
0
        }
520
0
    }
521
522
4.43k
    code = gs_image_begin_typed((const gs_image_common_t *)&image,
523
4.43k
                                prast->pcs->pgs, true, false, &pie);
524
4.43k
    if (code >= 0)
525
4.43k
        code = gs_image_common_init(pen,
526
4.43k
                                    pie,
527
4.43k
                                    (gs_data_image_t *) & image,
528
4.43k
                                    gs_currentdevice_inline(prast->pcs->pgs)
529
4.43k
            );
530
4.43k
    if (code < 0) {
531
0
        gs_free_object(prast->pmem, pen, "Create image for PCL raster");
532
0
        return code;
533
0
    }
534
4.43k
    prast->pen = pen;
535
4.43k
    return 0;
536
4.43k
}
537
538
/*
539
 * Close the image being used to represent a raster. If the second argument is
540
 * true, complete the raster as well.
541
 *
542
 * This routine does NOT clear the seed rows, as their content may be needed
543
 * for the next row of the raster.
544
 *
545
 * NB: This routine may re-invoke itself recursively when completing the raster,
546
 *     as this routine will call process_zero_rows, which may once again invoke
547
 *     this routine. The recursion can only extend to one additional level,
548
 *     however, as process_zero_rows will call this routine with complete set
549
 *     set to false.
550
 */
551
static void
552
close_raster(gs_gstate * pgs, pcl_raster_t * prast, bool complete)
553
5.63k
{
554
    /* see if we need to fill in any missing rows */
555
5.63k
    if (complete &&
556
5.63k
        (prast->src_height > prast->rows_rendered) && prast->src_height_set)
557
0
        (void)process_zero_rows(prast,
558
0
                                prast->src_height - prast->rows_rendered);
559
5.63k
    if (prast->pen != 0) {
560
4.43k
        gs_image_cleanup(prast->pen, pgs);
561
4.43k
        gs_free_object(prast->pmem, prast->pen, "Close PCL raster");
562
4.43k
        prast->pen = 0;
563
4.43k
    }
564
5.63k
    if (prast->mask_pen != 0) {
565
0
        gs_image_cleanup(prast->mask_pen, pgs);
566
0
        gs_free_object(prast->pmem, prast->mask_pen, "Close PCL raster");
567
0
        prast->mask_pen = 0;
568
0
    }
569
5.63k
    gs_translate(prast->pcs->pgs, 0.0, (double) (prast->rows_rendered));
570
5.63k
    prast->src_height -= prast->rows_rendered;
571
5.63k
    prast->rows_rendered = 0;
572
5.63k
}
573
574
/*
575
 * Generate the white-mask corresponding to an image scanline. This is
576
 * necessary to implement the opaque source/transparent texture case.
577
 *
578
 * HP's specification of transparency includes one unintuitive case: opaque
579
 * source and transparent texture. In this case, the texture applies only to
580
 * the non-white portion of the source; the white portion should be rendered
581
 * in a solid white.
582
 *
583
 * Since the graphic library does not support mutliple textures in a single
584
 * rendering operation, it is necessary to split objects that have both a
585
 * foreground and a background into two transparent objects: one having just
586
 * the foreground, the other just the background. In the case of rasters it
587
 * is necessary to form a mask object that is the inverse of the background,
588
 * and "paint" it with "white". The following code accomplishes this task.
589
 *
590
 * It is, unfortunately, not possible to use the graphic libraries image mask
591
 * feature to implement the "white mask", because image masks in the graphic
592
 * library are not implemented as mask objects. Rather, they are implemented
593
 * as transparent colored patterns, with the foreground color taken from the
594
 * current color at the time the image mask is begun. Instead, a two entry
595
 * transparent colored image is used, whose foreground color is the current
596
 * white and whose background color is a transparent white.
597
 *
598
 * As always, what is considered "white" is evaluated in the source color space;
599
 * this varies from HP's practice, and can give unexpected results if an
600
 * inverting color lookup table is used.
601
 */
602
static int
603
process_mask_row(pcl_raster_t * prast)
604
0
{
605
0
    int code = clear_mask_buff(prast);
606
0
    gs_image_enum *pen = prast->mask_pen;
607
608
0
    if ((code >= 0) &&
609
0
        ((pen != 0) || ((code = create_mask_enumerator(prast)) >= 0))) {
610
0
        uint dummy;
611
0
        pcl_state_t *pcs = prast->pcs;
612
613
0
        pen = prast->mask_pen;
614
0
        code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true);
615
0
        if (code < 0) return code;
616
0
        prast->gen_mask_row(prast);
617
0
        code = gs_image_next(pen,
618
0
                             prast->mask_buff,
619
0
                             (prast->src_width + 7) / 8, &dummy);
620
0
        if (code < 0) return code;
621
0
        code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true);
622
0
    }
623
0
    return code;
624
0
}
625
626
static int
627
process_zero_mask_rows(pcl_raster_t * prast, int nrows)
628
0
{
629
0
    int code = clear_mask_buff(prast);
630
0
    gs_image_enum *pen = prast->mask_pen;
631
632
0
    if ((code >= 0) &&
633
0
        ((pen != 0) || ((code = create_mask_enumerator(prast)) >= 0))) {
634
0
        uint dummy;
635
0
        pcl_state_t *pcs = prast->pcs;
636
637
0
        int nbytes = (prast->src_width + 7) / 8;
638
639
0
        pen = prast->mask_pen;
640
0
        memset(prast->mask_buff, 0xff, nbytes);
641
0
        code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true);
642
0
        if (code < 0)
643
0
            return code;
644
0
        code = check_rasterops(pcs, (gs_rop3_t) rop3_know_S_1((int)0xff));
645
0
        if (code >= 0) {
646
0
            code = gs_setrasterop(pcs->pgs, (gs_rop3_t) rop3_know_S_1((int)0xff));
647
0
            if (code < 0)
648
0
                return code;
649
0
        }
650
0
        while ((nrows-- > 0) && (code >= 0))
651
0
            code = gs_image_next(pen, prast->mask_buff, nbytes, &dummy);
652
653
0
        if (code < 0)
654
0
            code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true);
655
0
    }
656
0
    return code;
657
0
}
658
659
/*
660
 * Process some number of zero-ed out rows, either as rasters or as a rectangle.
661
 *
662
 * Ideally, any sufficiently large regions of zero value would be rendered as
663
 * a rectangle, but doing so runs afoul of PCL's graphic model. Rectangles are
664
 * mask objects, whose value is provided by the current color/pattern/texture.
665
 * Images are colored objects, whose interaction with the the current color/
666
 * texture/raster is established by the current raster operation.
667
 *
668
 * In many cases, it is possible to emulate the effect of a colored object by
669
 * use of a mask object and modifications to the current pattern/color/texture
670
 * and the current raster operation. For the most part, however, situations in
671
 * which such modifications are useful do not occur often enough to be worth
672
 * special handling.
673
 *
674
 * There is one case that does arise with some frequency and is simple to
675
 * handle: 0 is white, and source transparency is on. In this case, no work
676
 * is necessary: just leave the output as is.
677
 *
678
 * The other case that is likely to arise often enough to be worth special
679
 * handling is when 0 is white but source transparency is off. In this case,
680
 * the current raster operation must be inverted relative to the source
681
 * component and a solid rectangle output. A similar situation with a black
682
 * rectangle does not occur very frequently, but can be handled by the same
683
 * technique (without inverting the raster operation), so it is handled here
684
 * as well.
685
 *
686
 * Zero regions of less than a kilo byte are not given special handling, so
687
 * as to avoid the overhead of closing and then restarting an image.
688
 *
689
 * Returns 0 on success, < 0 in the event of an error.
690
 */
691
static int
692
process_zero_rows(pcl_raster_t * prast, int nrows)
693
3
{
694
3
    int npixels = prast->src_width;
695
3
    int nbytes = (npixels * prast->bits_per_plane + 7) / 8;
696
3
    int nplanes = prast->nplanes;
697
3
    int rem_rows = prast->src_height - prast->rows_rendered;
698
3
    pcl_seed_row_t *pseed_rows = prast->pseed_rows;
699
3
    int code = 0;
700
3
    int i;
701
3
    int moveto_nrows = nrows;
702
703
    /* don't bother going beyond the end of the image */
704
3
    if (nrows > rem_rows) {
705
2
        nrows = rem_rows;
706
2
    }
707
708
    /* if clipping the whole raster, just update rendered rows */
709
3
    if (prast->pcs->raster_state.clip_all) {
710
0
        prast->rows_rendered += nrows;
711
0
        return 0;
712
0
    }
713
714
    /* clear the seed rows */
715
6
    for (i = 0; i < nplanes; i++) {
716
3
        if (!pseed_rows[i].is_blank) {
717
1
            memset(prast->pseed_rows[i].pdata, 0, nbytes);
718
1
            pseed_rows[i].is_blank = true;
719
1
        }
720
3
    }
721
722
    /* render as raster or rectangle */
723
3
    if (((nrows * nbytes > 1024) || (prast->pen == 0)) &&
724
3
        (prast->zero_is_white || prast->zero_is_black)) {
725
3
        gs_gstate *pgs = prast->pcs->pgs;
726
727
3
        close_raster(pgs, prast, false);
728
3
        if ((prast->zero_is_black) || !prast->pcs->source_transparent) {
729
0
            gs_rect tmp_rect;
730
0
            bool invert = prast->zero_is_white;
731
732
0
            tmp_rect.p.x = 0.0;
733
0
            tmp_rect.p.y = 0.0;
734
0
            tmp_rect.q.x = (double)npixels;
735
0
            tmp_rect.q.y = (double)nrows;
736
0
            if (invert) {
737
0
                code = check_rasterops(prast->pcs, (gs_rop3_t)
738
0
                               rop3_invert_S(gs_currentrasterop(pgs)));
739
0
                if (code >= 0) {
740
0
                    code = gs_setrasterop(pgs,
741
0
                                   (gs_rop3_t)
742
0
                                   rop3_invert_S(gs_currentrasterop(pgs))
743
0
                        );
744
0
                    if (code < 0)
745
0
                        return code;
746
0
                }
747
748
0
                code = gs_rectfill(pgs, &tmp_rect, 1);
749
0
                if (code < 0)
750
0
                    return code;
751
752
0
                code = check_rasterops(prast->pcs, (gs_rop3_t)
753
0
                               rop3_invert_S(gs_currentrasterop(pgs)));
754
0
                if (code >= 0) {
755
0
                    code = gs_setrasterop(pgs,
756
0
                                   (gs_rop3_t)
757
0
                                   rop3_invert_S(gs_currentrasterop(pgs))
758
0
                        );
759
0
                    if (code < 0)
760
0
                        return code;
761
0
                } else
762
0
                    code = 0;
763
0
            } else {
764
0
                code = gs_rectfill(pgs, &tmp_rect, 1);
765
0
                if (code < 0)
766
0
                    return code;
767
0
            }
768
769
0
        }
770
771
3
        prast->src_height -= nrows;
772
        /* NB HP bug CET21.04 pg 7 */
773
        /* NB text cap move to moveto_nrows, but raster cap moveto nrows */
774
3
        gs_translate(pgs, 0.0, (double) moveto_nrows);
775
776
3
        return 0;
777
778
3
    } else {
779
0
        int nsrcs = prast->nsrcs;
780
0
        gs_image_enum *pen = prast->pen;
781
0
        int cnt = 0;
782
0
        uint size = 0;
783
0
        const byte *pb;
784
785
0
        if (pen == 0) {
786
0
            if ((code = create_image_enumerator(prast)) < 0)
787
0
                return code;
788
0
            pen = prast->pen;
789
0
        }
790
791
0
        if (nplanes > nsrcs) {
792
0
            if ((code = clear_cons_buff(prast)) < 0)
793
0
                return code;
794
0
            cnt = nrows;
795
0
            size = npixels;
796
0
            pb = prast->cons_buff;
797
0
        } else {
798
0
            cnt = nrows * nsrcs;
799
0
            size = nbytes;
800
0
            pb = prast->pseed_rows[0].pdata;
801
0
        }
802
803
0
        for (i = 0; i < cnt; i++) {
804
0
            uint dummy;
805
806
0
            if ((code = gs_image_next(pen, pb, size, &dummy)) < 0)
807
0
                return code;
808
0
        }
809
0
        prast->rows_rendered += nrows;
810
811
0
        if (prast->gen_mask_row != 0)
812
0
            code = process_zero_mask_rows(prast, nrows);
813
814
0
        return code;
815
0
    }
816
3
}
817
818
/*
819
 * Process the next raster row.
820
 *
821
 * The compression mode is provided to allow this routine to fill in any
822
 * missing rows. For adaptive compression (mode 5), this will be 0.
823
 */
824
static int
825
process_row(pcl_raster_t * prast, int comp_mode /* modified compression mode */
826
    )
827
78.4k
{
828
78.4k
    int nplanes = prast->nplanes;
829
78.4k
    gs_image_enum *pen = prast->pen;
830
78.4k
    int i;
831
78.4k
    int code = 0;
832
833
    /* check if there is anything to do */
834
78.4k
    if (prast->rows_rendered >= prast->src_height)
835
2.02k
        return 0;
836
76.3k
    else if (prast->pcs->raster_state.clip_all) {
837
6.02k
        prast->rows_rendered++;
838
6.02k
        return 0;
839
6.02k
    }
840
841
    /* handle any planes not provided */
842
104k
    for (i = prast->plane_index; i < nplanes; i++) {
843
34.2k
        static const byte dummy = 0;
844
845
34.2k
        (void)pcl_decomp_proc[comp_mode] (prast->pseed_rows + i, &dummy, 0);
846
34.2k
    }
847
848
    /* create the image enumerator if it does not already exist */
849
70.3k
    if (pen == 0) {
850
4.43k
        if ((code = create_image_enumerator(prast)) < 0)
851
0
            return code;
852
4.43k
        pen = prast->pen;
853
4.43k
    }
854
855
    /* update the raster parameters */
856
70.3k
    prast->rows_rendered++;
857
70.3k
    prast->plane_index = 0;
858
859
70.3k
    if (prast->nsrcs == 1) {
860
70.3k
        byte *pb;
861
70.3k
        int nbytes, b_per_p;
862
70.3k
        uint dummy;
863
864
        /* consolidate the planes if necessary */
865
70.3k
        if (nplanes > prast->nsrcs) {
866
17.1k
            if ((code = consolidate_row(prast)) < 0)
867
0
                return code;
868
17.1k
            pb = prast->cons_buff;
869
17.1k
            b_per_p = 8;
870
17.1k
            nbytes = prast->src_width;
871
53.2k
        } else {
872
53.2k
            pb = prast->pseed_rows[0].pdata;
873
53.2k
            nbytes = prast->pseed_rows[0].size;
874
53.2k
            b_per_p = prast->bits_per_plane;
875
53.2k
        }
876
877
        /*
878
         * Remap the planes, if this is required.
879
         *
880
         * Remapping is only required for indexed color spaces. The indexed
881
         * by plane case will have been collapsed to an indexed by pixel case
882
         * by this point.
883
         *
884
         */
885
70.3k
        if (prast->remap_ary)
886
0
            pcl_cmap_apply_remap_ary(prast->remap_ary,
887
0
                                     pb, b_per_p, prast->src_width);
888
889
70.3k
        code = gs_image_next(pen, pb, nbytes, &dummy);
890
891
70.3k
    } else {
892
0
        uint dummy;
893
0
        int nsrcs = prast->nsrcs;
894
895
0
        for (i = 0; (i < nsrcs) && (code >= 0); i++)
896
0
            code = gs_image_next(pen,
897
0
                                 prast->pseed_rows[i].pdata,
898
0
                                 prast->pseed_rows[i].size, &dummy);
899
0
    }
900
901
70.3k
    if ((prast->gen_mask_row != 0) && (code >= 0))
902
0
        code = process_mask_row(prast);
903
70.3k
    prast->pcs->page_marked = true;
904
70.3k
    return code;
905
70.3k
}
906
907
/*
908
 * Process an input data buffer using no compression with blocks (multiple rows)
909
 */
910
911
static int
912
process_block_nocompress(gs_gstate * pgs,
913
                         pcl_raster_t * prast, const byte * pin, uint insize)
914
0
{
915
0
    uint32 row_bytes, nrows;
916
0
    pcl_seed_row_t *pseed_row = prast->pseed_rows;
917
0
    byte *p;
918
919
    /* the size of the rows are stored in the first 4 bytes */
920
0
    if (insize < 4) {
921
0
        return gs_throw(e_Range, "Size of raster cannot be determined\n");
922
0
    }
923
924
0
    row_bytes = (pl_get_uint32(pin) * prast->bits_per_plane + 7) / 8;
925
926
    /* the remaining data after the row size should be divisible by
927
       the row length to have equal sized rows */
928
0
    if (row_bytes == 0 || ((insize - 4) % row_bytes))
929
0
        return gs_throw(e_Range, "Non integral number of rows in raster\n");
930
931
0
    nrows = insize / row_bytes;
932
933
0
    for (p = (byte *) pin + 4; nrows > 0; p += row_bytes, nrows--) {
934
0
        int code;
935
936
0
        pcl_decomp_proc[0] (pseed_row, p, row_bytes);
937
0
        prast->plane_index = 1;
938
0
        code = process_row(prast, 0);
939
0
        if (code < 0)
940
0
            return gs_rethrow(code, "Raster row processing failed\n");
941
0
    }
942
0
    return 0;
943
0
}
944
945
static int
946
pcl_ccitt_error(stream_state * st, const char *str)
947
0
{
948
0
    (void)gs_throw1(-1, "%s", str);
949
0
    return 0;
950
0
}
951
952
953
static int
954
process_ccitt_compress(gs_gstate * pgs,
955
                       pcl_raster_t * prast,
956
                       const byte * pin,
957
                       uint insize, pcl_rast_buff_type_t comp)
958
4
{
959
4
    stream_CFD_state state;
960
4
    stream_cursor_read scr;
961
4
    stream_cursor_write scw;
962
4
    pcl_seed_row_t *pout = prast->pseed_rows;
963
4
    uint wrsize;
964
4
    byte *temp_buffer;
965
966
4
    if (insize < 4)
967
0
        return gs_throw(e_Range, "raster row size not specified");
968
969
4
    if ((int)pl_get_uint32(pin) < 0)
970
0
        return gs_throw(e_Range, "Image columns overflow CFD filter");
971
972
4
    s_init_state((stream_state *) & state, &s_CFD_template, prast->pmem);
973
4
    state.report_error = pcl_ccitt_error;
974
4
    s_CFD_template.set_defaults((stream_state *) & state);
975
4
    state.BlackIs1 = true;
976
4
    state.EndOfLine = false;
977
4
    state.EndOfBlock = false;
978
4
    state.Columns = pl_get_uint32(pin);
979
4
    if (state.Columns == 0 || state.Columns > cfe_max_width)
980
0
        return_error(e_Range);
981
4
    state.Rows = 0;             /* undetermined */
982
4
    if (comp == CCITT_GR3_1D_COMPRESS)
983
0
        state.K = 0;
984
4
    else if (comp == CCITT_GR3_2D_COMPRESS)
985
0
        state.K = 1;
986
4
    else
987
4
        state.K = -1;
988
4
    s_CFD_template.init((stream_state *) & state);
989
4
    scr.ptr = pin + 4 - 1;
990
4
    scr.limit = scr.ptr + insize - 4;
991
992
4
    wrsize = (state.Columns + 7) / 8;
993
4
    temp_buffer = gs_alloc_bytes(prast->pmem, wrsize, "CCITT temp_buffer");
994
4
    if (temp_buffer == 0)
995
0
        return_error(e_Memory);
996
4
    memset(temp_buffer, 0, wrsize);
997
998
4
    scw.ptr = temp_buffer - 1;
999
4
    scw.limit = scw.ptr + wrsize;
1000
1001
8
    while (1) {
1002
8
        int code =
1003
8
            s_CFD_template.process((stream_state *) & state, &scr, &scw,
1004
8
                                   true);
1005
8
        switch (code) {
1006
1007
4
            case 1:            /* need output, process the scanline and continue. */
1008
4
                memcpy(pout->pdata, temp_buffer, min(pout->size, wrsize));
1009
4
                code = process_row(prast, 0);
1010
4
                if (code < 0) {
1011
0
                    s_CFD_template.release((stream_state *) & state);
1012
0
                    return gs_rethrow(code, "CCITT decompression failed\n");
1013
0
                }
1014
4
                memset(temp_buffer, 0, wrsize);
1015
4
                scw.ptr = temp_buffer - 1;
1016
4
                scw.limit = scw.ptr + wrsize;
1017
4
                break;
1018
0
            case EOFC:         /* all done */
1019
0
                s_CFD_template.release((stream_state *) & state);
1020
0
                return 0;
1021
1
            case 0:            /* need input is an error - we've given it all the data */
1022
4
            case ERRC:         /* error */
1023
4
                s_CFD_template.release((stream_state *) & state);
1024
4
                return gs_rethrow(e_Range, "CCITT decompression failed\n");
1025
0
            default:
1026
0
                return gs_throw(e_Range,
1027
8
                                "unknown code CCITT decompression\n");
1028
8
        }
1029
8
    }
1030
    /* not reached */
1031
0
    return -1;
1032
4
}
1033
1034
1035
1036
1037
/*
1038
 * Process an input data buffer using adpative compression.
1039
 */
1040
static int
1041
process_adaptive_compress(pcl_raster_t * prast, const byte * pin, uint insize, bool mono)
1042
34
{
1043
34
    pcl_seed_row_t *pseed_row = prast->pseed_rows;
1044
34
    byte *pdata = pseed_row->pdata;
1045
34
    uint row_size = pseed_row->size;
1046
34
    int code = 0;
1047
34
    int cmd = NO_COMPRESS;
1048
34
    uint param = 0;
1049
1050
34
    prast->plane_index = 0;
1051
229
    while ((insize >= 3) && (code >= 0)) {
1052
205
        cmd = *pin++;
1053
205
        param = *pin++;
1054
1055
205
        param = (param << 8) + *pin++;
1056
205
        insize -= 3;
1057
205
        if (cmd <= 3) {
1058
193
            uint cnt = min(insize, param);
1059
1060
193
            pcl_decomp_proc[cmd] (pseed_row, pin, cnt);
1061
193
            insize -= cnt;
1062
193
            pin += cnt;
1063
193
            prast->plane_index = 1;
1064
193
            code = process_row(prast, 0);
1065
193
        } else if (cmd == 4)
1066
2
            code = process_zero_rows(prast, param);
1067
10
        else if (cmd == 5) {
1068
0
            uint rem_rows = prast->src_height - prast->rows_rendered;
1069
0
            gs_image_enum *pen = prast->pen;
1070
1071
0
            if (param > rem_rows)
1072
0
                param = rem_rows;
1073
1074
            /* if clipping the raster, just update lines rendered */
1075
0
            if (prast->pcs->raster_state.clip_all) {
1076
0
                prast->rows_rendered += param;
1077
0
                continue;
1078
0
            }
1079
1080
            /* create the image enumerator if it does not already exist */
1081
0
            if (pen == 0) {
1082
0
                if ((code = create_image_enumerator(prast)) < 0)
1083
0
                    return code;
1084
0
                pen = prast->pen;
1085
0
            }
1086
1087
0
            if (prast->nplanes == 1) {
1088
0
                prast->rows_rendered += param;
1089
0
                while ((param-- > 0) && (code >= 0)) {
1090
0
                    uint dummy;
1091
1092
0
                    code = gs_image_next(pen, pdata, row_size, &dummy);
1093
0
                    if ((prast->gen_mask_row != 0) && (code >= 0))
1094
0
                        code = process_mask_row(prast);
1095
0
                }
1096
0
            } else {
1097
0
                prast->plane_index = 1;
1098
0
                while ((param-- > 0) && ((code = process_row(prast, 0) >= 0)))
1099
0
                    prast->plane_index = 1;
1100
0
                prast->plane_index = 0;
1101
0
            }
1102
0
        } else
1103
10
            break;
1104
205
    }
1105
1106
    /* On monochrome printers tested HP clears the seed row of delta
1107
       row compression after each block, color printers leave it
1108
       intact. */
1109
34
    if (mono) {
1110
34
        memset(pdata, 0, row_size);
1111
34
        pseed_row->is_blank = true;
1112
34
    }
1113
1114
34
    return code;
1115
34
}
1116
1117
/*
1118
 * Add a raster plane. The bool end_row operand indicates whether or not this is the
1119
 * final plane of a row.
1120
 */
1121
static int
1122
add_raster_plane(const byte * pdata,
1123
                 uint nbytes, bool end_row, pcl_state_t * pcs)
1124
78.3k
{
1125
78.3k
    pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster;
1126
78.3k
    int comp_mode = pcs->raster_state.compression_mode;
1127
78.3k
    int nplanes = 0;
1128
78.3k
    int plane_index = 0;
1129
78.3k
    int code = 0;
1130
1131
    /* enter raster mode implicitly if not already there */
1132
78.3k
    if (prast == 0) {
1133
4.38k
        if ((code = pcl_enter_graphics_mode(pcs, IMPLICIT)) != 0)
1134
49
            return code;
1135
4.33k
        prast = (pcl_raster_t *) pcs->raster_state.pcur_raster;
1136
4.33k
    }
1137
1138
    /*
1139
     * Adaptive compression (mode 5) is only available for single-plane
1140
     * encodings, and then only if used with a transfer row (ESC * b # W)
1141
     * command. The latter behavior matches that of the HP Color LaserJet 5/5M,
1142
     * but not that of the DeskJet 1600C/CM, which has somewhat erratic
1143
     * behavior in this case.
1144
     */
1145
78.2k
    nplanes = prast->nplanes;
1146
78.2k
    if ((comp_mode == ADAPTIVE_COMPRESS) && !end_row)
1147
0
        return e_Range;
1148
1149
    /*
1150
     * If all the rows that can be output have already been rendered, just
1151
     * return.
1152
     */
1153
78.2k
    if (prast->rows_rendered >= prast->src_height)
1154
2.02k
        return 0;
1155
1156
    /*
1157
     * If all planes for this row have been entered, just ignore the current
1158
     * data (but don't return yet, as we may still need to output the current
1159
     * raster row).
1160
     */
1161
76.2k
    plane_index = prast->plane_index;
1162
76.2k
    if (plane_index < nplanes) {
1163
70.9k
        pcl_seed_row_t *pseed = prast->pseed_rows + plane_index;
1164
1165
70.9k
        prast->plane_index++;
1166
70.9k
        if (!PCL_BLOCK_COMP(comp_mode))
1167
70.8k
            (void)pcl_decomp_proc[comp_mode] (pseed, pdata, nbytes);
1168
38
        else if (comp_mode == NO_COMPRESS_BLOCK)
1169
0
            return process_block_nocompress(pcs->pgs, prast, pdata, nbytes);
1170
38
        else if (comp_mode == ADAPTIVE_COMPRESS)
1171
34
            return process_adaptive_compress(prast, pdata, nbytes, pcs->personality == pcl5e);
1172
4
        else
1173
4
            return process_ccitt_compress(pcs->pgs, prast, pdata, nbytes,
1174
4
                                          comp_mode);
1175
1176
70.9k
    }
1177
76.1k
    return 0;
1178
76.2k
}
1179
1180
/*
1181
 * Create a PCL raster object. This procedure is called when entering graphics
1182
 * mode.
1183
 *
1184
 * Note that a raster must be considered "transparent" if either source or
1185
 * pattern transparency is in effect. If only pattern transparency is set, an
1186
 * addition mask object must be created to fill the "white" regions of the
1187
 * raster. This object does not use the current texture; it sets the texture
1188
 * to opaque white when it is rendered. This is in conformance with HP's
1189
 * somewhat unintuitive interpretation of the opaque source/transparent
1190
 * pattern situation.
1191
 *
1192
 * Returns 0 on success, < 0 in the event of an error.
1193
 */
1194
int
1195
pcl_start_raster(uint src_width, uint src_height, pcl_state_t * pcs)
1196
5.63k
{
1197
5.63k
    pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster;
1198
5.63k
    pcl_palette_t *ppalet = pcs->ppalet;
1199
5.63k
    pcl_cs_indexed_t *pindexed = ppalet->pindexed;
1200
5.63k
    pcl_encoding_type_t penc = pcl_cs_indexed_get_encoding(pindexed);
1201
5.63k
    pcl_seed_row_t *pseed_rows = 0;
1202
5.63k
    int pattern_could_be_transparent =
1203
5.63k
            pcs->pattern_transparent &&
1204
5.07k
            pcs->pattern_type != pcl_pattern_solid_frgrnd;
1205
1206
    /* there can only be one raster object present at a time */
1207
5.63k
    if (prast != 0)
1208
0
        pcl_complete_raster(pcs);
1209
1210
5.63k
    prast = gs_alloc_struct(pcs->memory,
1211
5.63k
                            pcl_raster_t, &st_raster_t, "start PCL raster");
1212
5.63k
    if (prast == 0)
1213
0
        return e_Memory;
1214
1215
5.63k
    prast->pmem = pcs->memory;
1216
1217
5.63k
    if (pcs->source_transparent || pattern_could_be_transparent)
1218
5.46k
        prast->transparent = true;
1219
165
    else
1220
165
        prast->transparent = false;
1221
1222
5.63k
    prast->interpolate = pcs->interpolate;
1223
5.63k
    prast->src_height_set = pcs->raster_state.src_height_set;
1224
5.63k
    prast->pcs = pcs;
1225
5.63k
    pcl_cs_indexed_init_from(prast->pindexed, pindexed);
1226
1227
5.63k
    prast->pen = 0;
1228
5.63k
    prast->plane_index = 0;
1229
5.63k
    prast->rows_rendered = 0;
1230
5.63k
    prast->src_width = src_width;
1231
5.63k
    prast->src_height = src_height;
1232
5.63k
    prast->mask_pen = 0;
1233
5.63k
    prast->mask_pindexed = 0;
1234
5.63k
    prast->gen_mask_row = 0;
1235
1236
    /* the conslidation and mask buffers are created when first needed */
1237
5.63k
    prast->cons_buff = 0;
1238
5.63k
    prast->mask_buff = 0;
1239
1240
5.63k
    if (penc <= pcl_penc_indexed_by_pixel) {
1241
5.63k
        int b_per_i = pcl_cs_indexed_get_bits_per_index(pindexed);
1242
1243
5.63k
        if (penc == pcl_penc_indexed_by_plane) {
1244
5.63k
            prast->nplanes = b_per_i;
1245
5.63k
            prast->bits_per_plane = 1;
1246
5.63k
        } else {                /* penc == pcl_penc_indexed_by_pixel */
1247
0
            prast->nplanes = 1;
1248
0
            prast->bits_per_plane = b_per_i;
1249
0
        }
1250
5.63k
        prast->nsrcs = 1;
1251
5.63k
        prast->indexed = true;
1252
5.63k
        prast->zero_is_white = pcl_cs_indexed_0_is_white(pindexed);
1253
5.63k
        prast->zero_is_black = pcl_cs_indexed_0_is_black(pindexed);
1254
5.63k
        prast->remap_ary = pcl_cmap_create_remap_ary(pcs, &(prast->wht_indx));
1255
1256
5.63k
    } else {                    /* penc >= pcl_penc_direct_by_plane */
1257
0
        int b_per_primary = pcl_cs_indexed_get_bits_per_primary(pindexed, 0);
1258
1259
0
        if (penc == pcl_penc_direct_by_plane) {
1260
0
            prast->nplanes = 3;
1261
0
            prast->bits_per_plane = b_per_primary;
1262
0
            prast->nsrcs = 3;
1263
0
        } else {                /* penc == pcl_penc_direct_by_pixel */
1264
0
            prast->nplanes = 1;
1265
0
            prast->bits_per_plane = 3 * b_per_primary;
1266
0
            prast->nsrcs = 1;
1267
0
        }
1268
0
        prast->indexed = false;
1269
0
        prast->zero_is_white = false;
1270
0
        prast->zero_is_black = true;
1271
0
        prast->wht_indx = 1;    /* not significant */
1272
0
        prast->remap_ary = 0;
1273
0
    }
1274
1275
    /* allocate the seed row buffers */
1276
5.63k
    pseed_rows = gs_alloc_struct_array(prast->pmem,
1277
5.63k
                                       prast->nplanes,
1278
5.63k
                                       pcl_seed_row_t,
1279
5.63k
                                       &st_seed_row_t_element,
1280
5.63k
                                       "start PCL raster");
1281
5.63k
    if (pseed_rows != 0) {
1282
5.63k
        size_t seed_row_bytes = ((size_t)prast->src_width * prast->bits_per_plane + 7)
1283
5.63k
            / 8;
1284
1285
5.63k
        int nplanes = prast->nplanes;
1286
5.63k
        int i, j;
1287
12.9k
        for (i = 0; i < nplanes; i++) {
1288
7.31k
            byte *pdata = gs_alloc_bytes(prast->pmem,
1289
7.31k
                                         seed_row_bytes,
1290
7.31k
                                         "start PCL raster");
1291
1292
7.31k
            if (pdata == 0)
1293
0
                break;
1294
7.31k
            pseed_rows[i].size = seed_row_bytes;
1295
7.31k
            pseed_rows[i].pdata = pdata;
1296
7.31k
            memset(pseed_rows[i].pdata, 0, seed_row_bytes);
1297
7.31k
            pseed_rows[i].is_blank = true;
1298
7.31k
        }
1299
1300
        /* check if everything was successful */
1301
5.63k
        if (i < nplanes) {
1302
1303
            /* memory exhaustion; release the already allocated seed rows */
1304
0
            for (j = 0; j < i; j++)
1305
0
                gs_free_object(prast->pmem,
1306
0
                               pseed_rows[j].pdata, "start PCL raster");
1307
0
            gs_free_object(prast->pmem, pseed_rows, "start PCL raster");
1308
0
            pseed_rows = 0;
1309
0
        }
1310
5.63k
    }
1311
1312
    /* check for memory exhaustion */
1313
5.63k
    if (pseed_rows == 0) {
1314
0
        pcl_cs_indexed_release(prast->pindexed);
1315
0
        gs_free_object(prast->pmem, prast, "start PCL raster");
1316
0
        return e_Memory;
1317
0
    }
1318
1319
5.63k
    prast->pseed_rows = pseed_rows;
1320
5.63k
    pcs->raster_state.pcur_raster = (pcl_raster_type *) prast;
1321
1322
    /* see if a mask is required */
1323
5.63k
    if (!pcs->source_transparent &&
1324
165
        pattern_could_be_transparent &&
1325
0
        (!prast->indexed ||
1326
0
         (prast->wht_indx < (1 << prast->nplanes * prast->bits_per_plane)))) {
1327
1328
0
        if (!prast->indexed) {
1329
0
            ulong white_val = 0UL;
1330
1331
            /* direct by plane or by pixel, one or 8 bits per primary */
1332
0
            prast->gen_mask_row = (prast->nsrcs > 1 ? gen_mask_multisrc
1333
0
                                   : gen_mask_multibyte);
1334
0
            if (prast->pindexed->Decode[1] == 1.0)
1335
0
                white_val |= ((ulong) 0xff) << 16;
1336
0
            if (prast->pindexed->Decode[3] == 1.0)
1337
0
                white_val |= ((ulong) 0xff) << 8;
1338
0
            if (prast->pindexed->Decode[5] == 1.0)
1339
0
                white_val |= 0xff;
1340
0
            prast->white_val = white_val;
1341
1342
0
        } else if ((prast->nplanes > 1) || (prast->bits_per_plane == 8)) {
1343
1344
            /* indexed by plane or direct by pixel, 8 bits per pixel */
1345
0
            prast->gen_mask_row = gen_mask_1byte;
1346
0
            prast->white_val = prast->wht_indx;
1347
1348
0
        } else {
1349
0
            ulong white_val = prast->wht_indx;
1350
0
            int n = 8 / prast->bits_per_plane;
1351
1352
            /* indexed by pixel, < 8 bits per pixel */
1353
0
            prast->gen_mask_row = gen_mask_subbyte;
1354
0
            while (n-- > 0)
1355
0
                white_val |= (white_val << prast->bits_per_plane);
1356
0
            prast->white_val = white_val;
1357
0
        }
1358
0
    }
1359
1360
5.63k
    return 0;
1361
5.63k
}
1362
1363
/*
1364
 * Complete a raster. This is called when exiting graphics mode.
1365
 */
1366
void
1367
pcl_complete_raster(pcl_state_t * pcs)
1368
10.1k
{
1369
10.1k
    pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster;
1370
10.1k
    int i;
1371
1372
    /* if already in raster mode, ignore */
1373
10.1k
    if (prast == 0)
1374
4.52k
        return;
1375
1376
    /* close the current raster */
1377
5.63k
    close_raster(pcs->pgs, prast, true);
1378
1379
    /* free associated objects */
1380
5.63k
    if (prast->remap_ary != 0) {
1381
0
        gs_free_object(prast->pmem,
1382
0
                       (void *)prast->remap_ary, "Complete PCL raster");
1383
0
        prast->remap_ary = 0;
1384
0
    }
1385
1386
5.63k
    if (prast->pindexed != 0) {
1387
5.63k
        pcl_cs_indexed_release(prast->pindexed);
1388
5.63k
        prast->pindexed = 0;
1389
5.63k
    }
1390
5.63k
    if (prast->mask_pindexed != 0) {
1391
0
        pcl_cs_indexed_release(prast->mask_pindexed);
1392
0
        prast->mask_pindexed = 0;
1393
0
    }
1394
1395
5.63k
    if (prast->pseed_rows != 0) {
1396
12.9k
        for (i = 0; i < prast->nplanes; i++) {
1397
7.31k
            if (prast->pseed_rows[i].pdata != 0)
1398
7.31k
                gs_free_object(prast->pmem,
1399
7.31k
                               prast->pseed_rows[i].pdata,
1400
7.31k
                               "Complete PCL raster");
1401
7.31k
        }
1402
5.63k
        gs_free_object(prast->pmem, prast->pseed_rows, "Complete PCL raster");
1403
5.63k
        prast->pseed_rows = 0;
1404
5.63k
    }
1405
1406
5.63k
    if (prast->cons_buff != 0)
1407
743
        gs_free_object(prast->pmem, prast->cons_buff, "Complete PCL raster");
1408
5.63k
    if (prast->mask_buff != 0)
1409
0
        gs_free_object(prast->pmem, prast->mask_buff, "Complete PCL raster");
1410
1411
    /* free the PCL raster robject itself */
1412
5.63k
    gs_free_object(prast->pmem, prast, "Complete PCL raster");
1413
5.63k
    pcs->raster_state.pcur_raster = 0;
1414
5.63k
}
1415
1416
/*
1417
 * ESC * b # V
1418
 *
1419
 * Add a plane buffer to the current set.
1420
 */
1421
static int
1422
transfer_raster_plane(pcl_args_t * pargs, pcl_state_t * pcs)
1423
10
{
1424
#ifdef DEBUG
1425
    if (gs_debug_c('i')) {
1426
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
1427
    }
1428
#endif
1429
10
    return add_raster_plane(arg_data(pargs), arg_data_size(pargs), false,
1430
10
                            pcs);
1431
10
}
1432
1433
/*
1434
 * <esc> * b # W
1435
 *
1436
 * Add a plane buffer to the current buffered set, and complete the current
1437
 * raster row.
1438
 */
1439
static int
1440
transfer_raster_row(pcl_args_t * pargs, pcl_state_t * pcs)
1441
78.3k
{
1442
78.3k
    const byte *pdata = arg_data(pargs);
1443
78.3k
    int comp_mode = pcs->raster_state.compression_mode;
1444
78.3k
    int code = 0;
1445
1446
#ifdef DEBUG
1447
    if (gs_debug_c('i')) {
1448
        pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs));
1449
    }
1450
#endif
1451
1452
78.3k
    code = add_raster_plane(pdata, arg_data_size(pargs), true, pcs);
1453
1454
    /* complete the row (execpt for adaptive compression) */
1455
78.3k
    if (!PCL_BLOCK_COMP(comp_mode) && code == 0)
1456
78.2k
        code =
1457
78.2k
            process_row((pcl_raster_t *) pcs->raster_state.pcur_raster,
1458
78.2k
                        comp_mode);
1459
1460
78.3k
    if (code < 0)
1461
0
        (void)pcl_grestore(pcs);
1462
1463
78.3k
    return code;
1464
78.3k
}
1465
1466
/*
1467
 * <esc> * b # Y
1468
 *
1469
 * Skip (zero-fill) a number of raster rows. This command is ignored outside
1470
 * of raster mode.
1471
 *
1472
 * Note that any incomplete plane data for the current row is discarded by this
1473
 * command.
1474
 */
1475
static int
1476
raster_y_offset(pcl_args_t * pargs, pcl_state_t * pcs)
1477
7
{
1478
7
    pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster;
1479
1480
    /* ignored outside of graphics mode */
1481
7
    if ((prast != 0) && (uint_arg(pargs) > 0)) {
1482
1
        return process_zero_rows(prast, uint_arg(pargs));
1483
1
    } else
1484
6
        return 0;
1485
7
}
1486
1487
/*
1488
 * ESC * b <direction> L
1489
 *
1490
 * set raster print direction
1491
 */
1492
static int
1493
set_line_path(pcl_args_t * pargs, pcl_state_t * pcs)
1494
28
{
1495
28
    uint i = uint_arg(pargs);
1496
1497
28
    if (i <= 1)
1498
21
        pcs->raster_state.y_advance = (i == 1 ? -1 : 1);
1499
28
    return 0;
1500
28
}
1501
1502
/*
1503
 * There is no specific copy code for this module, as both entry to and exit
1504
 * from a macro must end graphics mode (and thus are handled by the parser).
1505
 * There is also no explicit reset routine, as the required work is handled
1506
 * at a higher level.
1507
 */
1508
static int
1509
raster_do_registration(pcl_parser_state_t * pcl_parser_state, gs_memory_t * pmem        /* ignored */
1510
    )
1511
8.97k
{
1512
8.97k
    DEFINE_CLASS('*') {
1513
8.97k
        'b', 'V',
1514
8.97k
            PCL_COMMAND("Transfer Raster Plane",
1515
8.97k
                        transfer_raster_plane,
1516
8.97k
                        pca_raster_graphics | pca_bytes | pca_in_rtl)
1517
8.97k
    }, {
1518
8.97k
        'b', 'W',
1519
8.97k
            PCL_COMMAND("Transfer Raster Row",
1520
8.97k
                        transfer_raster_row,
1521
8.97k
                        pca_raster_graphics | pca_bytes | pca_in_rtl)
1522
8.97k
    }, {
1523
8.97k
        'b', 'Y',
1524
8.97k
            PCL_COMMAND("Raster Y Offset",
1525
8.97k
                        raster_y_offset,
1526
8.97k
                        pca_raster_graphics | pca_neg_ok | pca_big_clamp |
1527
8.97k
                        pca_in_rtl)
1528
8.97k
    }, {
1529
        /* NB this command should *only* be exectuted in rtl but we
1530
           use it in both rtl and pcl5 */
1531
8.97k
        'b', 'L',
1532
8.97k
            PCL_COMMAND("Line Path",
1533
8.97k
                        set_line_path,
1534
8.97k
                        pca_neg_ok | pca_big_ignore | pca_in_rtl)
1535
8.97k
    }, END_CLASS return 0;
1536
8.97k
}
1537
1538
static int
1539
raster_do_reset(pcl_state_t * pcs, pcl_reset_type_t type)
1540
35.3k
{
1541
35.3k
    if ((type & pcl_reset_initial) != 0)
1542
8.97k
        pcs->raster_state.pcur_raster = 0;
1543
35.3k
    return 0;
1544
35.3k
}
1545
1546
const pcl_init_t rtraster_init =
1547
    { raster_do_registration, raster_do_reset, 0 };