Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/vector/gdevpsdu.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
99.9k
{
53
99.9k
    pprintg1(gdev_vector_stream(vdev), "%g w\n", width);
54
99.9k
    return 0;
55
99.9k
}
56
57
int
58
psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
59
47.7k
{
60
47.7k
    switch (cap) {
61
3.44k
        case gs_cap_butt:
62
46.8k
        case gs_cap_round:
63
47.7k
        case gs_cap_square:
64
47.7k
            pprintd1(gdev_vector_stream(vdev), "%d J\n", cap);
65
47.7k
            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
47.7k
    }
78
47.7k
    return 0;
79
47.7k
}
80
81
int
82
psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join)
83
13.5k
{
84
13.5k
    switch (join) {
85
4.61k
        case gs_join_miter:
86
13.2k
        case gs_join_round:
87
13.4k
        case gs_join_bevel:
88
13.4k
            pprintd1(gdev_vector_stream(vdev), "%d j\n", join);
89
13.4k
            break;
90
4
        case gs_join_none:
91
            /* If we get a PCL triangle join, substitute with a bevel join */
92
4
            pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_bevel);
93
4
            break;
94
3
        case gs_join_triangle:
95
            /* If we get a PCL triangle join, substitute with a miter join */
96
3
            pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter);
97
3
            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
13.5k
    }
106
13.5k
    return 0;
107
13.5k
}
108
109
int
110
psdf_setmiterlimit(gx_device_vector * vdev, double limit)
111
2.48k
{
112
2.48k
    pprintg1(gdev_vector_stream(vdev), "%g M\n", limit);
113
2.48k
    return 0;
114
2.48k
}
115
116
int
117
psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count,
118
             double offset)
119
13.8k
{
120
13.8k
    stream *s = gdev_vector_stream(vdev);
121
13.8k
    int i;
122
123
13.8k
    stream_puts(s, "[ ");
124
22.5k
    for (i = 0; i < count; ++i)
125
8.73k
        pprintg1(s, "%g ", pattern[i]);
126
13.8k
    pprintg1(s, "] %g d\n", offset);
127
13.8k
    return 0;
128
13.8k
}
129
130
int
131
psdf_setflat(gx_device_vector * vdev, double flatness)
132
3.62k
{
133
3.62k
    pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness);
134
3.62k
    return 0;
135
3.62k
}
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
551k
{
149
551k
    int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
150
151
551k
    if (code < 0)
152
0
        return code;
153
551k
    pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n",
154
551k
             fixed2float(x0), fixed2float(y0),
155
551k
             fixed2float(x1) - fixed2float(x0), fixed2float(y1) - fixed2float(y0));
156
551k
    return (*vdev_proc(vdev, endpath)) (vdev, type);
157
551k
}
158
159
int
160
psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type)
161
551k
{
162
551k
    return 0;
163
551k
}
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.23M
{
169
1.23M
    pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y);
170
1.23M
    return 0;
171
1.23M
}
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
3.08M
{
177
3.08M
    pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y);
178
3.08M
    return 0;
179
3.08M
}
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
3.19M
{
186
3.19M
    if (x1 == x0 && y1 == y0 && x2 == x3 && y2 == y3)
187
37.6k
        pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x3, y3);
188
3.15M
    else if (x1 == x0 && y1 == y0)
189
45.4k
        pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n",
190
45.4k
                 x2, y2, x3, y3);
191
3.11M
    else if (x3 == x2 && y3 == y2)
192
49.9k
        pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n",
193
49.9k
                 x1, y1, x2, y2);
194
3.06M
    else
195
3.06M
        pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n",
196
3.06M
                 x1, y1, x2, y2, x3, y3);
197
3.19M
    return 0;
198
3.19M
}
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
193k
{
204
193k
    stream_puts(gdev_vector_stream(vdev), "h\n");
205
193k
    return 0;
206
193k
}
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
151k
{
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
151k
    return (color == (gx_no_color_index ^ 1) ? gx_no_color_index : color);
223
151k
}
224
225
/* Round a double value to a specified precision. */
226
double
227
psdf_round(double v, int precision, int radix)
228
4.34M
{
229
4.34M
    double mul = 1;
230
4.34M
    double w = v;
231
232
4.34M
    if (w <= 0)
233
2.37M
        return w;
234
6.56M
    while (w < precision) {
235
4.59M
        w *= radix;
236
4.59M
        mul *= radix;
237
4.59M
    }
238
1.97M
    return (int)(w + 0.5) / mul;
239
4.34M
}
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
427k
{
248
427k
    return (int)((uint)cv * (1000.0 / 255.0) + 0.5) / 1000.0;
249
427k
}
250
int
251
psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc,
252
               const psdf_set_color_commands_t *ppscc)
253
704k
{
254
704k
    const char *setcolor;
255
704k
    int num_des_comps, code;
256
704k
    cmm_dev_profile_t *dev_profile;
257
258
704k
    code = dev_proc((gx_device *)vdev, get_profile)((gx_device *)vdev, &dev_profile);
259
704k
    if (code < 0)
260
0
        return code;
261
704k
    num_des_comps = gsicc_get_device_profile_comps(dev_profile);
262
263
704k
    if (!gx_dc_is_pure(pdc))
264
552k
        return_error(gs_error_rangecheck);
265
151k
    {
266
151k
        stream *s = gdev_vector_stream(vdev);
267
151k
        gx_color_index color =
268
151k
            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
151k
        double v3 = round_byte_color(color & 0xff);
275
276
151k
        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
151k
        case 3:
289
            /* if (v1 == v2 && v2 == v3 && ...) */
290
151k
            if (!((color ^ (color >> 8)) & 0xffff) && ppscc->setgray != 0)
291
13.6k
                goto g;
292
137k
            pprintg3(s, "%g %g %g", round_byte_color((color >> 16) & 0xff),
293
137k
                     round_byte_color((color >> 8) & 0xff), v3);
294
137k
            setcolor = ppscc->setrgbcolor;
295
137k
            break;
296
0
        case 1:
297
13.6k
        g:
298
13.6k
            pprintg1(s, "%g", v3);
299
13.6k
            setcolor = ppscc->setgray;
300
13.6k
            break;
301
0
        default:    /* can't happen */
302
0
            return_error(gs_error_rangecheck);
303
151k
        }
304
151k
        if (setcolor)
305
151k
            pprints1(s, " %s\n", setcolor);
306
151k
    }
307
0
    return 0;
308
151k
}
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
378k
{
316
378k
    gs_memory_t *mem = pbw->memory = pdev->v_memory;
317
318
378k
    pbw->target = pdev->strm;
319
378k
    pbw->dev = pdev;
320
378k
    pbw->strm = 0;    /* for GC in case of failure */
321
    /* If not binary, set up the encoding stream. */
322
378k
    if (!pdev->binary_ok) {
323
166k
#define BUF_SIZE 100    /* arbitrary */
324
166k
        byte *buf = gs_alloc_bytes(mem, BUF_SIZE, "psdf_begin_binary(buf)");
325
166k
        stream_A85E_state *ss = (stream_A85E_state *)
326
166k
            s_alloc_state(mem, s_A85E_template.stype,
327
166k
                          "psdf_begin_binary(stream_state)");
328
166k
        stream *s = s_alloc(mem, "psdf_begin_binary(stream)");
329
330
166k
        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
166k
        ss->templat = &s_A85E_template;
337
166k
        s_init_filter(s, (stream_state *)ss, buf, BUF_SIZE, pdev->strm);
338
166k
#undef BUF_SIZE
339
166k
        pbw->strm = s;
340
211k
    } else {
341
211k
        pbw->strm = pdev->strm;
342
211k
    }
343
378k
    return 0;
344
378k
}
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
340k
{
352
340k
    return (s_add_filter(&pbw->strm, templat, ss, pbw->memory) == 0 ?
353
340k
            gs_note_error(gs_error_VMerror) : 0);
354
340k
}
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
11.7k
{
368
11.7k
        stream_DCT_state *const ss = (stream_DCT_state *) st;
369
11.7k
        gs_memory_t *mem = st->memory;
370
11.7k
        jpeg_compress_data *jcdp;
371
11.7k
        gs_c_param_list rcc_list;
372
11.7k
        int code;
373
374
        /*
375
         * "Wrap" the actual Dict or ACSDict parameter list in one that
376
         * sets Rows, Columns, and Colors.
377
         */
378
11.7k
        gs_c_param_list_write(&rcc_list, mem);
379
11.7k
        if ((code = param_write_int((gs_param_list *)&rcc_list, "Rows",
380
11.7k
                                    &Rows)) < 0 ||
381
11.7k
            (code = param_write_int((gs_param_list *)&rcc_list, "Columns",
382
11.7k
                                    &Columns)) < 0 ||
383
11.7k
            (code = param_write_int((gs_param_list *)&rcc_list, "Colors",
384
11.7k
                                    &Colors)) < 0
385
11.7k
            ) {
386
0
            goto rcc_fail;
387
0
        }
388
11.7k
        gs_c_param_list_read(&rcc_list);
389
11.7k
        if (plist)
390
11.7k
            gs_c_param_list_set_target(&rcc_list, plist);
391
        /* Allocate space for IJG parameters. */
392
11.7k
        jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
393
11.7k
           &st_jpeg_compress_data, "zDCTE");
394
11.7k
        if (jcdp == 0)
395
0
            return_error(gs_error_VMerror);
396
11.7k
        jcdp->cinfo.mem = NULL;
397
11.7k
        jcdp->cinfo.client_data = NULL;
398
11.7k
        ss->data.compress = jcdp;
399
11.7k
        jcdp->memory = ss->jpeg_memory = mem; /* set now for allocation */
400
11.7k
        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
11.7k
        code = s_DCTE_put_params((gs_param_list *)&rcc_list, ss);
404
11.7k
        if (code < 0)
405
0
            return code;
406
        /* Create the filter. */
407
11.7k
        jcdp->templat = s_DCTE_template;
408
        /* Make sure we get at least a full scan line of input. */
409
11.7k
        ss->scan_line_size = jcdp->cinfo.input_components *
410
11.7k
            jcdp->cinfo.image_width;
411
        /* Profile not used in pdfwrite output */
412
11.7k
        ss->icc_profile = NULL;
413
11.7k
        jcdp->templat.min_in_size =
414
11.7k
            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
11.7k
        jcdp->templat.min_out_size =
417
11.7k
            max(s_DCTE_template.min_out_size, ss->Markers.size);
418
11.7k
        if (pbw)
419
11.7k
            code = psdf_encode_binary(pbw, &jcdp->templat, st);
420
11.7k
        if (code >= 0) {
421
11.7k
            gs_c_param_list_release(&rcc_list);
422
11.7k
            return 0;
423
11.7k
        }
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
76.9k
{
438
76.9k
    gs_memory_t *mem = pbw->memory;
439
76.9k
    const stream_template *templat = &s_CFE_template;
440
76.9k
    stream_CFE_state *st =
441
76.9k
        gs_alloc_struct(mem, stream_CFE_state, templat->stype,
442
76.9k
                        "psdf_CFE_binary");
443
76.9k
    int code;
444
445
76.9k
    if (st == 0)
446
0
        return_error(gs_error_VMerror);
447
76.9k
    (*templat->set_defaults) ((stream_state *) st);
448
76.9k
    st->K = -1;
449
76.9k
    st->Columns = w;
450
76.9k
    st->Rows = 0;
451
76.9k
    st->BlackIs1 = !invert;
452
76.9k
    st->EndOfBlock = pbw->strm->state->templat != &s_A85E_template;
453
76.9k
    code = psdf_encode_binary(pbw, templat, (stream_state *) st);
454
76.9k
    if (code < 0)
455
0
        gs_free_object(mem, st, "psdf_CFE_binary");
456
76.9k
    return code;
457
76.9k
}
458
459
/* Finish writing binary data. */
460
int
461
psdf_end_binary(psdf_binary_writer * pbw)
462
187k
{
463
187k
    int status = s_close_filters(&pbw->strm, pbw->target);
464
465
187k
    return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror));
466
187k
}
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
245k
{
501
245k
    if (gs_is_overprint_compositor(pct)) {
502
244k
        *pcdev = dev;
503
244k
        return 0;
504
244k
    }
505
1.41k
    return gx_default_composite(dev, pcdev, pct, pgs, mem, cdev);
506
245k
}