Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpsdu.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/* Common utilities for PostScript and PDF writers */
18
#include "stdio_.h"   /* for FILE for jpeglib.h */
19
#include "jpeglib_.h"   /* for sdct.h */
20
#include "memory_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gdevpsdf.h"
24
#include "strimpl.h"
25
#include "sa85x.h"
26
#include "scfx.h"
27
#include "sdct.h"
28
#include "sjpeg.h"
29
#include "spprint.h"
30
#include "gsovrc.h"
31
#include "gsicc_cache.h"
32
33
/* Structure descriptors */
34
public_st_device_psdf();
35
public_st_psdf_binary_writer();
36
37
/* Standard color command names. */
38
const psdf_set_color_commands_t psdf_set_fill_color_commands = {
39
    "g", "rg", "k", "cs", "sc", "scn"
40
};
41
const psdf_set_color_commands_t psdf_set_stroke_color_commands = {
42
    "G", "RG", "K", "CS", "SC", "SCN"
43
};
44
45
/* Define parameter-setting procedures. */
46
extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
47
48
/* ---------------- Vector implementation procedures ---------------- */
49
50
int
51
psdf_setlinewidth(gx_device_vector * vdev, double width)
52
70.5k
{
53
70.5k
    pprintg1(gdev_vector_stream(vdev), "%g w\n", width);
54
70.5k
    return 0;
55
70.5k
}
56
57
int
58
psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
59
34.4k
{
60
34.4k
    switch (cap) {
61
7.33k
        case gs_cap_butt:
62
33.1k
        case gs_cap_round:
63
34.4k
        case gs_cap_square:
64
34.4k
            pprintd1(gdev_vector_stream(vdev), "%d J\n", cap);
65
34.4k
            break;
66
9
        case gs_cap_triangle:
67
            /* If we get a PCL triangle cap, substitute with a round cap */
68
9
            pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_round);
69
9
            break;
70
0
        default:
71
            /* Ensure we don't write a broken file if we don't recognise the cap */
72
0
            emprintf1(vdev->memory,
73
0
                      "Unknown line cap enumerator %d, substituting butt\n",
74
0
                      cap);
75
0
            pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_butt);
76
0
            break;
77
34.4k
    }
78
34.4k
    return 0;
79
34.4k
}
80
81
int
82
psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join)
83
26.6k
{
84
26.6k
    switch (join) {
85
11.8k
        case gs_join_miter:
86
26.4k
        case gs_join_round:
87
26.5k
        case gs_join_bevel:
88
26.5k
            pprintd1(gdev_vector_stream(vdev), "%d j\n", join);
89
26.5k
            break;
90
5
        case gs_join_none:
91
            /* If we get a PCL triangle join, substitute with a bevel join */
92
5
            pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_bevel);
93
5
            break;
94
0
        case gs_join_triangle:
95
            /* If we get a PCL triangle join, substitute with a miter join */
96
0
            pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter);
97
0
            break;
98
0
        default:
99
            /* Ensure we don't write a broken file if we don't recognise the join */
100
0
            emprintf1(vdev->memory,
101
0
                      "Unknown line join enumerator %d, substituting miter\n",
102
0
                      join);
103
0
            pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter);
104
0
            break;
105
26.6k
    }
106
26.6k
    return 0;
107
26.6k
}
108
109
int
110
psdf_setmiterlimit(gx_device_vector * vdev, double limit)
111
2.16k
{
112
2.16k
    pprintg1(gdev_vector_stream(vdev), "%g M\n", limit);
113
2.16k
    return 0;
114
2.16k
}
115
116
int
117
psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count,
118
             double offset)
119
7.52k
{
120
7.52k
    stream *s = gdev_vector_stream(vdev);
121
7.52k
    int i;
122
123
7.52k
    stream_puts(s, "[ ");
124
15.1k
    for (i = 0; i < count; ++i)
125
7.58k
        pprintg1(s, "%g ", pattern[i]);
126
7.52k
    pprintg1(s, "] %g d\n", offset);
127
7.52k
    return 0;
128
7.52k
}
129
130
int
131
psdf_setflat(gx_device_vector * vdev, double flatness)
132
14.2k
{
133
14.2k
    pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness);
134
14.2k
    return 0;
135
14.2k
}
136
137
int
138
psdf_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
139
              gs_logical_operation_t diff)
140
0
{
141
/****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/
142
0
    return 0;
143
0
}
144
145
int
146
psdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
147
            gx_path_type_t type)
148
500k
{
149
500k
    int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
150
151
500k
    if (code < 0)
152
0
        return code;
153
500k
    pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n",
154
500k
             fixed2float(x0), fixed2float(y0),
155
500k
             fixed2float(x1 - x0), fixed2float(y1 - y0));
156
500k
    return (*vdev_proc(vdev, endpath)) (vdev, type);
157
500k
}
158
159
int
160
psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type)
161
500k
{
162
500k
    return 0;
163
500k
}
164
165
int
166
psdf_moveto(gx_device_vector * vdev, double x0, double y0, double x, double y,
167
            gx_path_type_t type)
168
1.17M
{
169
1.17M
    pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y);
170
1.17M
    return 0;
171
1.17M
}
172
173
int
174
psdf_lineto(gx_device_vector * vdev, double x0, double y0, double x, double y,
175
            gx_path_type_t type)
176
2.78M
{
177
2.78M
    pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y);
178
2.78M
    return 0;
179
2.78M
}
180
181
int
182
psdf_curveto(gx_device_vector * vdev, double x0, double y0,
183
           double x1, double y1, double x2, double y2, double x3, double y3,
184
             gx_path_type_t type)
185
2.56M
{
186
2.56M
    if (x1 == x0 && y1 == y0 && x2 == x3 && y2 == y3)
187
37.1k
        pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x3, y3);
188
2.52M
    else if (x1 == x0 && y1 == y0)
189
26.8k
        pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n",
190
26.8k
                 x2, y2, x3, y3);
191
2.49M
    else if (x3 == x2 && y3 == y2)
192
30.1k
        pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n",
193
30.1k
                 x1, y1, x2, y2);
194
2.46M
    else
195
2.46M
        pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n",
196
2.46M
                 x1, y1, x2, y2, x3, y3);
197
2.56M
    return 0;
198
2.56M
}
199
200
int
201
psdf_closepath(gx_device_vector * vdev, double x0, double y0,
202
               double x_start, double y_start, gx_path_type_t type)
203
289k
{
204
289k
    stream_puts(gdev_vector_stream(vdev), "h\n");
205
289k
    return 0;
206
289k
}
207
208
/* endpath is deliberately omitted. */
209
210
/* ---------------- Utilities ---------------- */
211
212
gx_color_index
213
psdf_adjust_color_index(gx_device_vector *vdev, gx_color_index color)
214
858k
{
215
    /*
216
     * Since gx_no_color_index is all 1's, we can't represent
217
     * a CMYK color consisting of full ink in all 4 components.
218
     * However, this color must be available for registration marks.
219
     * gxcmap.c fudges this by changing the K component to 254;
220
     * undo this fudge here.
221
     */
222
858k
    return (color == (gx_no_color_index ^ 1) ? gx_no_color_index : color);
223
858k
}
224
225
/* Round a double value to a specified precision. */
226
double
227
psdf_round(double v, int precision, int radix)
228
4.07M
{
229
4.07M
    double mul = 1;
230
4.07M
    double w = v;
231
232
4.07M
    if (w <= 0)
233
2.02M
        return w;
234
6.75M
    while (w < precision) {
235
4.70M
        w *= radix;
236
4.70M
        mul *= radix;
237
4.70M
    }
238
2.04M
    return (int)(w + 0.5) / mul;
239
4.07M
}
240
241
/*
242
 * Since we only have 8 bits of color to start with, round the
243
 * values to 3 digits for more compact output.
244
 */
245
static inline double
246
round_byte_color(gx_color_index cv)
247
2.47M
{
248
2.47M
    return (int)((uint)cv * (1000.0 / 255.0) + 0.5) / 1000.0;
249
2.47M
}
250
int
251
psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc,
252
               const psdf_set_color_commands_t *ppscc)
253
869k
{
254
869k
    const char *setcolor;
255
869k
    int num_des_comps, code;
256
869k
    cmm_dev_profile_t *dev_profile;
257
258
869k
    code = dev_proc((gx_device *)vdev, get_profile)((gx_device *)vdev, &dev_profile);
259
869k
    if (code < 0)
260
0
        return code;
261
869k
    num_des_comps = gsicc_get_device_profile_comps(dev_profile);
262
263
869k
    if (!gx_dc_is_pure(pdc))
264
10.8k
        return_error(gs_error_rangecheck);
265
858k
    {
266
858k
        stream *s = gdev_vector_stream(vdev);
267
858k
        gx_color_index color =
268
858k
            psdf_adjust_color_index(vdev, gx_dc_pure_color(pdc));
269
        /*
270
         * Normally we would precompute all of v0 .. v3, but gcc 2.7.2.3
271
         * generates incorrect code for Intel CPUs if we do this.  The code
272
         * below is longer, but does less computation in some cases.
273
         */
274
858k
        double v3 = round_byte_color(color & 0xff);
275
276
858k
        switch (num_des_comps) {
277
0
        case 4:
278
            /* if (v0 == 0 && v1 == 0 && v2 == 0 && ...) */
279
0
            if ((color & 0xffffff00) == 0 && ppscc->setgray != 0) {
280
0
                v3 = 1.0 - v3;
281
0
                goto g;
282
0
            }
283
0
            pprintg4(s, "%g %g %g %g", round_byte_color(color >> 24),
284
0
                     round_byte_color((color >> 16) & 0xff),
285
0
                     round_byte_color((color >> 8) & 0xff), v3);
286
0
            setcolor = ppscc->setcmykcolor;
287
0
            break;
288
858k
        case 3:
289
            /* if (v1 == v2 && v2 == v3 && ...) */
290
858k
            if (!((color ^ (color >> 8)) & 0xffff) && ppscc->setgray != 0)
291
49.5k
                goto g;
292
809k
            pprintg3(s, "%g %g %g", round_byte_color((color >> 16) & 0xff),
293
809k
                     round_byte_color((color >> 8) & 0xff), v3);
294
809k
            setcolor = ppscc->setrgbcolor;
295
809k
            break;
296
0
        case 1:
297
49.5k
        g:
298
49.5k
            pprintg1(s, "%g", v3);
299
49.5k
            setcolor = ppscc->setgray;
300
49.5k
            break;
301
0
        default:    /* can't happen */
302
0
            return_error(gs_error_rangecheck);
303
858k
        }
304
858k
        if (setcolor)
305
858k
            pprints1(s, " %s\n", setcolor);
306
858k
    }
307
0
    return 0;
308
858k
}
309
310
/* ---------------- Binary data writing ---------------- */
311
312
/* Begin writing binary data. */
313
int
314
psdf_begin_binary(gx_device_psdf * pdev, psdf_binary_writer * pbw)
315
376k
{
316
376k
    gs_memory_t *mem = pbw->memory = pdev->v_memory;
317
318
376k
    pbw->target = pdev->strm;
319
376k
    pbw->dev = pdev;
320
376k
    pbw->strm = 0;    /* for GC in case of failure */
321
    /* If not binary, set up the encoding stream. */
322
376k
    if (!pdev->binary_ok) {
323
252k
#define BUF_SIZE 100    /* arbitrary */
324
252k
        byte *buf = gs_alloc_bytes(mem, BUF_SIZE, "psdf_begin_binary(buf)");
325
252k
        stream_A85E_state *ss = (stream_A85E_state *)
326
252k
            s_alloc_state(mem, s_A85E_template.stype,
327
252k
                          "psdf_begin_binary(stream_state)");
328
252k
        stream *s = s_alloc(mem, "psdf_begin_binary(stream)");
329
330
252k
        if (buf == 0 || ss == 0 || s == 0) {
331
0
            gs_free_object(mem, s, "psdf_begin_binary(stream)");
332
0
            gs_free_object(mem, ss, "psdf_begin_binary(stream_state)");
333
0
            gs_free_object(mem, buf, "psdf_begin_binary(buf)");
334
0
            return_error(gs_error_VMerror);
335
0
        }
336
252k
        ss->templat = &s_A85E_template;
337
252k
        s_init_filter(s, (stream_state *)ss, buf, BUF_SIZE, pdev->strm);
338
252k
#undef BUF_SIZE
339
252k
        pbw->strm = s;
340
252k
    } else {
341
124k
        pbw->strm = pdev->strm;
342
124k
    }
343
376k
    return 0;
344
376k
}
345
346
/* Add an encoding filter.  The client must have allocated the stream state, */
347
/* if any, using pdev->v_memory. */
348
int
349
psdf_encode_binary(psdf_binary_writer * pbw, const stream_template * templat,
350
                   stream_state * ss)
351
349k
{
352
349k
    return (s_add_filter(&pbw->strm, templat, ss, pbw->memory) == 0 ?
353
349k
            gs_note_error(gs_error_VMerror) : 0);
354
349k
}
355
356
/*
357
 * Acquire parameters, and optionally set up the filter for, a DCTEncode
358
 * filter.  This is a separate procedure so it can be used to validate
359
 * filter parameters when they are set, rather than waiting until they are
360
 * used.  pbw = NULL means just set up the stream state.
361
 */
362
int
363
psdf_DCT_filter(gs_param_list *plist /* may be NULL */,
364
                stream_state /*stream_DCTE_state*/ *st,
365
                int Columns, int Rows, int Colors,
366
                psdf_binary_writer *pbw /* may be NULL */)
367
6.15k
{
368
6.15k
        stream_DCT_state *const ss = (stream_DCT_state *) st;
369
6.15k
        gs_memory_t *mem = st->memory;
370
6.15k
        jpeg_compress_data *jcdp;
371
6.15k
        gs_c_param_list rcc_list;
372
6.15k
        int code;
373
374
        /*
375
         * "Wrap" the actual Dict or ACSDict parameter list in one that
376
         * sets Rows, Columns, and Colors.
377
         */
378
6.15k
        gs_c_param_list_write(&rcc_list, mem);
379
6.15k
        if ((code = param_write_int((gs_param_list *)&rcc_list, "Rows",
380
6.15k
                                    &Rows)) < 0 ||
381
6.15k
            (code = param_write_int((gs_param_list *)&rcc_list, "Columns",
382
6.15k
                                    &Columns)) < 0 ||
383
6.15k
            (code = param_write_int((gs_param_list *)&rcc_list, "Colors",
384
6.15k
                                    &Colors)) < 0
385
6.15k
            ) {
386
0
            goto rcc_fail;
387
0
        }
388
6.15k
        gs_c_param_list_read(&rcc_list);
389
6.15k
        if (plist)
390
6.15k
            gs_c_param_list_set_target(&rcc_list, plist);
391
        /* Allocate space for IJG parameters. */
392
6.15k
        jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
393
6.15k
           &st_jpeg_compress_data, "zDCTE");
394
6.15k
        if (jcdp == 0)
395
0
            return_error(gs_error_VMerror);
396
6.15k
        jcdp->cinfo.mem = NULL;
397
6.15k
        jcdp->cinfo.client_data = NULL;
398
6.15k
        ss->data.compress = jcdp;
399
6.15k
        jcdp->memory = ss->jpeg_memory = mem; /* set now for allocation */
400
6.15k
        if ((code = gs_jpeg_create_compress(ss)) < 0)
401
0
            goto dcte_fail; /* correct to do jpeg_destroy here */
402
        /* Read parameters from dictionary */
403
6.15k
        code = s_DCTE_put_params((gs_param_list *)&rcc_list, ss);
404
6.15k
        if (code < 0)
405
0
            return code;
406
        /* Create the filter. */
407
6.15k
        jcdp->templat = s_DCTE_template;
408
        /* Make sure we get at least a full scan line of input. */
409
6.15k
        ss->scan_line_size = jcdp->cinfo.input_components *
410
6.15k
            jcdp->cinfo.image_width;
411
        /* Profile not used in pdfwrite output */
412
6.15k
        ss->icc_profile = NULL;
413
6.15k
        jcdp->templat.min_in_size =
414
6.15k
            max(s_DCTE_template.min_in_size, ss->scan_line_size);
415
        /* Make sure we can write the user markers in a single go. */
416
6.15k
        jcdp->templat.min_out_size =
417
6.15k
            max(s_DCTE_template.min_out_size, ss->Markers.size);
418
6.15k
        if (pbw)
419
6.15k
            code = psdf_encode_binary(pbw, &jcdp->templat, st);
420
6.15k
        if (code >= 0) {
421
6.15k
            gs_c_param_list_release(&rcc_list);
422
6.15k
            return 0;
423
6.15k
        }
424
0
    dcte_fail:
425
0
        gs_jpeg_destroy(ss);
426
0
        gs_free_object(mem, jcdp, "setup_image_compression");
427
0
        ss->data.compress = NULL; /* Avoid problems with double frees later */
428
0
    rcc_fail:
429
0
        gs_c_param_list_release(&rcc_list);
430
0
        return code;
431
0
}
432
433
/* Add a 2-D CCITTFax encoding filter. */
434
/* Set EndOfBlock iff the stream is not ASCII85 encoded. */
435
int
436
psdf_CFE_binary(psdf_binary_writer * pbw, int w, int h, bool invert)
437
134k
{
438
134k
    gs_memory_t *mem = pbw->memory;
439
134k
    const stream_template *templat = &s_CFE_template;
440
134k
    stream_CFE_state *st =
441
134k
        gs_alloc_struct(mem, stream_CFE_state, templat->stype,
442
134k
                        "psdf_CFE_binary");
443
134k
    int code;
444
445
134k
    if (st == 0)
446
0
        return_error(gs_error_VMerror);
447
134k
    (*templat->set_defaults) ((stream_state *) st);
448
134k
    st->K = -1;
449
134k
    st->Columns = w;
450
134k
    st->Rows = 0;
451
134k
    st->BlackIs1 = !invert;
452
134k
    st->EndOfBlock = pbw->strm->state->templat != &s_A85E_template;
453
134k
    code = psdf_encode_binary(pbw, templat, (stream_state *) st);
454
134k
    if (code < 0)
455
0
        gs_free_object(mem, st, "psdf_CFE_binary");
456
134k
    return code;
457
134k
}
458
459
/* Finish writing binary data. */
460
int
461
psdf_end_binary(psdf_binary_writer * pbw)
462
226k
{
463
226k
    int status = s_close_filters(&pbw->strm, pbw->target);
464
465
226k
    return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror));
466
226k
}
467
468
/* ---------------- Overprint, Get Bits ---------------- */
469
470
/*
471
 * High level devices cannot perform get_bits_rectangle
472
 * operations, for obvious reasons.
473
 */
474
int
475
psdf_get_bits_rectangle(
476
    gx_device *             dev,
477
    const gs_int_rect *     prect,
478
    gs_get_bits_params_t *  params )
479
0
{
480
0
    emprintf(dev->memory,
481
0
                  "Can't set GraphicsAlphaBits or TextAlphaBits with a vector device.\n");
482
0
    return_error(gs_error_unregistered);
483
0
}
484
485
/*
486
 * Create compositor procedure for PostScript/PDF writer. Since these
487
 * devices directly support overprint (and have access to the gs_gstate),
488
 * no compositor is required for overprint support. Hence, this
489
 * routine just recognizes and discards invocations of the overprint
490
 * compositor.
491
 */
492
int
493
psdf_composite(
494
    gx_device *             dev,
495
    gx_device **            pcdev,
496
    const gs_composite_t *  pct,
497
    gs_gstate             *  pgs,
498
    gs_memory_t *           mem,
499
    gx_device *             cdev)
500
146k
{
501
146k
    if (gs_is_overprint_compositor(pct)) {
502
143k
        *pcdev = dev;
503
143k
        return 0;
504
143k
    }
505
3.14k
    return gx_default_composite(dev, pcdev, pct, pgs, mem, cdev);
506
146k
}