Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/gdevpxut.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
/* Utilities for PCL XL generation */
18
#include "math_.h"
19
#include "string_.h"
20
#include "gx.h"
21
#include "stream.h"
22
#include "gxdevcli.h"
23
#include "gdevpxat.h"
24
#include "gdevpxen.h"
25
#include "gdevpxop.h"
26
#include "gdevpxut.h"
27
28
/* ---------------- High-level constructs ---------------- */
29
30
/* Write the file header, including the resolution. */
31
int
32
px_write_file_header(stream *s, const gx_device *dev, bool staple)
33
22.3k
{
34
22.3k
    static const char *const enter_pjl_header =
35
22.3k
        "\033%-12345X@PJL SET RENDERMODE=";
36
22.3k
    static const char *const set_staple= "\n@PJL SET FINISH=STAPLE";
37
22.3k
    static const char *const rendermode_gray = "GRAYSCALE";
38
22.3k
    static const char *const rendermode_color = "COLOR";
39
22.3k
    static const char *const pjl_resolution =
40
22.3k
        "\n@PJL SET RESOLUTION=";
41
22.3k
    static const char *const resolution_150 = "150";
42
22.3k
    static const char *const resolution_300 = "300";
43
22.3k
    static const char *const resolution_600 = "600";
44
22.3k
    static const char *const resolution_1200 = "1200";
45
22.3k
    static const char *const resolution_2400 = "2400";
46
22.3k
    static const char *const file_header =
47
22.3k
        "\n@PJL ENTER LANGUAGE = PCLXL\n\
48
22.3k
) HP-PCL XL;1;1;Comment Copyright Artifex Sofware, Inc. 2005-2023\000\n";
49
22.3k
    static const byte stream_header[] = {
50
22.3k
        DA(pxaUnitsPerMeasure),
51
22.3k
        DUB(0), DA(pxaMeasure),
52
22.3k
        DUB(eBackChAndErrPage), DA(pxaErrorReport),
53
22.3k
        pxtBeginSession,
54
22.3k
        DUB(0), DA(pxaSourceType),
55
22.3k
        DUB(eBinaryLowByteFirst), DA(pxaDataOrg),
56
22.3k
        pxtOpenDataSource
57
22.3k
    };
58
59
22.3k
    px_put_bytes(s, (const byte *)enter_pjl_header,
60
22.3k
                 strlen(enter_pjl_header));
61
62
22.3k
    if (dev->color_info.num_components == 1)
63
9.66k
        px_put_bytes(s, (const byte *)rendermode_gray,
64
9.66k
                     strlen(rendermode_gray));
65
12.6k
    else
66
12.6k
        px_put_bytes(s, (const byte *)rendermode_color,
67
12.6k
                     strlen(rendermode_color));
68
69
22.3k
    if(staple)
70
0
        px_put_bytes(s, (const byte *)set_staple,
71
0
                     strlen(set_staple));
72
73
22.3k
    px_put_bytes(s, (const byte *)pjl_resolution,
74
22.3k
                 strlen(pjl_resolution));
75
76
22.3k
    if ((uint) (dev->HWResolution[0] + 0.5) == 150)
77
0
        px_put_bytes(s, (const byte *)resolution_150,
78
0
                     strlen(resolution_150));
79
22.3k
    else if ((uint) (dev->HWResolution[0] + 0.5) == 300)
80
0
        px_put_bytes(s, (const byte *)resolution_300,
81
0
                     strlen(resolution_300));
82
22.3k
    else if ((uint) (dev->HWResolution[0] + 0.5) == 1200)
83
0
        px_put_bytes(s, (const byte *)resolution_1200,
84
0
                     strlen(resolution_1200));
85
22.3k
    else if ((uint) (dev->HWResolution[0] + 0.5) == 2400)
86
0
        px_put_bytes(s, (const byte *)resolution_2400,
87
0
                     strlen(resolution_2400));
88
22.3k
    else
89
22.3k
        px_put_bytes(s, (const byte *)resolution_600,
90
22.3k
                     strlen(resolution_600));
91
22.3k
    if ((uint) (dev->HWResolution[1] + 0.5) !=
92
22.3k
        (uint) (dev->HWResolution[0] + 0.5)) {
93
0
        px_put_bytes(s, (const byte *)"x", strlen("x"));
94
0
        if ((uint) (dev->HWResolution[1] + 0.5) == 150)
95
0
            px_put_bytes(s, (const byte *)resolution_150,
96
0
                         strlen(resolution_150));
97
0
        else if ((uint) (dev->HWResolution[1] + 0.5) == 300)
98
0
            px_put_bytes(s, (const byte *)resolution_300,
99
0
                         strlen(resolution_300));
100
0
        else if ((uint) (dev->HWResolution[1] + 0.5) == 1200)
101
0
            px_put_bytes(s, (const byte *)resolution_1200,
102
0
                         strlen(resolution_1200));
103
0
        else if ((uint) (dev->HWResolution[1] + 0.5) == 2400)
104
0
            px_put_bytes(s, (const byte *)resolution_2400,
105
0
                         strlen(resolution_2400));
106
0
        else
107
0
            px_put_bytes(s, (const byte *)resolution_600,
108
0
                         strlen(resolution_600));
109
0
    }
110
111
    /* We have to add 2 to the strlen because the next-to-last */
112
    /* character is a null. */
113
22.3k
    px_put_bytes(s, (const byte *)file_header,
114
22.3k
                 strlen(file_header) + 2);
115
22.3k
    px_put_usp(s, (uint) (dev->HWResolution[0] + 0.5),
116
22.3k
               (uint) (dev->HWResolution[1] + 0.5));
117
22.3k
    PX_PUT_LIT(s, stream_header);
118
22.3k
    return 0;
119
22.3k
}
120
121
/* Write the page header, including orientation. */
122
int
123
px_write_page_header(stream *s, const gx_device *dev)
124
20.3k
{
125
    /* Orientation is deferred until px_write_select_media... */
126
20.3k
    return 0;
127
20.3k
}
128
129
/* Write the media selection command if needed, updating the media size. */
130
int
131
px_write_select_media(stream *s, const gx_device *dev,
132
                      pxeMediaSize_t *pms, byte *media_source,
133
                      int page, bool Duplex, bool Tumble, int media_type_set, char *media_type)
134
20.3k
{
135
20.3k
#define MSD(ms, mstr, res, w, h)                                 \
136
876k
    { ms, mstr, (float)((w) * 1.0 / (res)), (float)((h) * 1.0 / res) },
137
20.3k
    static const struct {
138
20.3k
        pxeMediaSize_t ms;
139
20.3k
        const char *media_name;
140
20.3k
        float width, height;
141
20.3k
    } media_sizes[] = {
142
876k
        px_enumerate_media(MSD)
143
20.3k
        { pxeMediaSize_next }
144
20.3k
    };
145
20.3k
#undef MSD
146
20.3k
    float w = dev->width / dev->HWResolution[0],
147
20.3k
        h = dev->height / dev->HWResolution[1];
148
20.3k
    int i;
149
20.3k
    pxeMediaSize_t size = eDefaultPaperSize;
150
20.3k
    byte tray = eAutoSelect;
151
20.3k
    byte orientation = ePortraitOrientation;
152
20.3k
    bool match_found = false;
153
154
    /* The default is eDefaultPaperSize (=96), but we'll emit CustomMediaSize */
155
    /* 0.05 = 30@r600 - one of the test files is 36 off and within 5.0/72@600 */
156
850k
    for (i = countof(media_sizes) - 2; i > 0; --i)
157
846k
        if (fabs(media_sizes[i].width - w) < 0.05 &&
158
846k
            fabs(media_sizes[i].height - h) < 0.05 &&
159
846k
            media_sizes[i].ms < 22 /* HP uses up to 21; Ricoh uses 201-224 */
160
846k
            ) {
161
15.4k
            match_found = true;
162
15.4k
            size = media_sizes[i].ms;
163
15.4k
            break;
164
830k
  } else if (fabs(media_sizes[i].height - w) < 0.05 &&
165
830k
       fabs(media_sizes[i].width - h) < 0.05 &&
166
830k
                   media_sizes[i].ms < 22
167
830k
       ) {
168
386
      match_found = true;
169
386
      size = media_sizes[i].ms;
170
386
      orientation = eLandscapeOrientation;
171
386
      break;
172
386
        }
173
    /*
174
     * According to the PCL XL documentation, MediaSize/CustomMediaSize must always
175
     * be specified, but MediaSource is optional.
176
     */
177
20.3k
    px_put_uba(s, orientation, pxaOrientation);
178
20.3k
    if (match_found) {
179
        /* standard media */
180
15.8k
        px_put_uba(s, (byte)size, pxaMediaSize);
181
15.8k
    } else {
182
        /* CustomMediaSize in Inches */
183
4.53k
        px_put_rpa(s, w, h, pxaCustomMediaSize);
184
4.53k
        px_put_uba(s, (byte)eInch, pxaCustomMediaSizeUnits);
185
4.53k
    }
186
187
20.3k
    if (media_source != NULL)
188
20.3k
        tray = *media_source;
189
    /* suppress eAutoSelect if type is set */
190
20.3k
    if (!media_type_set || (tray != eAutoSelect))
191
20.3k
      px_put_uba(s, tray, pxaMediaSource);
192
    /* suppress empty(="plain") type if tray is non-auto */
193
20.3k
    if (media_type_set)
194
1
        if ((tray == eAutoSelect) || strlen(media_type))
195
1
          px_put_ubaa(s, (const byte *)media_type, strlen(media_type), pxaMediaType);
196
197
20.3k
    if_debug2('|', "duplex %d tumble %d\n", Duplex, Tumble);
198
20.3k
    if (Duplex)
199
0
    {
200
0
      if (Tumble)
201
0
        px_put_uba(s, (byte)eDuplexHorizontalBinding, pxaDuplexPageMode);
202
0
      else
203
0
        px_put_uba(s, (byte)eDuplexVerticalBinding, pxaDuplexPageMode);
204
205
0
      if (page & 1)
206
0
        px_put_uba(s, (byte)eFrontMediaSide, pxaDuplexPageSide);
207
0
      else
208
0
        px_put_uba(s, (byte)eBackMediaSide, pxaDuplexPageSide);
209
0
    }
210
20.3k
    else
211
20.3k
      px_put_uba(s, (byte)eSimplexFrontSide, pxaSimplexPageMode);
212
213
20.3k
    if (pms)
214
20.3k
        *pms = size;
215
216
20.3k
    return 0;
217
20.3k
}
218
219
/*
220
 * Write the file trailer.  Note that this takes a gp_file *, not a stream *,
221
 * since it may be called after the stream is closed.
222
 */
223
int
224
px_write_file_trailer(gp_file *file)
225
22.3k
{
226
22.3k
    static const byte file_trailer[] = {
227
22.3k
        pxtCloseDataSource,
228
22.3k
        pxtEndSession,
229
22.3k
        033, '%', '-', '1', '2', '3', '4', '5', 'X'
230
22.3k
    };
231
232
22.3k
    gp_fwrite(file_trailer, 1, sizeof(file_trailer), file);
233
22.3k
    return 0;
234
22.3k
}
235
236
/* ---------------- Low-level data output ---------------- */
237
238
/* Write a sequence of bytes. */
239
void
240
px_put_bytes(stream * s, const byte * data, uint count)
241
43.1M
{
242
43.1M
    uint used;
243
244
43.1M
    sputs(s, data, count, &used);
245
43.1M
}
246
247
/* Utilities for writing data values. */
248
/* H-P printers only support little-endian data, so that's what we emit. */
249
void
250
px_put_a(stream * s, px_attribute_t a)
251
156M
{
252
156M
    sputc(s, pxt_attr_ubyte);
253
156M
    sputc(s, (byte)a);
254
156M
}
255
void
256
px_put_ac(stream *s, px_attribute_t a, px_tag_t op)
257
77.8M
{
258
77.8M
    px_put_a(s, a);
259
77.8M
    sputc(s, (byte)op);
260
77.8M
}
261
262
void
263
px_put_ub(stream * s, byte b)
264
71.3M
{
265
71.3M
    sputc(s, pxt_ubyte);
266
71.3M
    sputc(s, b);
267
71.3M
}
268
void
269
px_put_uba(stream *s, byte b, px_attribute_t a)
270
53.4M
{
271
53.4M
    px_put_ub(s, b);
272
53.4M
    px_put_a(s, a);
273
53.4M
}
274
275
void
276
px_put_s(stream * s, int i)
277
232M
{
278
232M
    sputc(s, (byte) i);
279
232M
    if (i < 0)
280
8.13M
       i |= 0x8000;
281
232M
    sputc(s, (byte) (i >> 8));
282
232M
}
283
void
284
px_put_us(stream * s, uint i)
285
659k
{
286
659k
    sputc(s, pxt_uint16);
287
659k
    px_put_s(s, i);
288
659k
}
289
void
290
px_put_usa(stream *s, uint i, px_attribute_t a)
291
637k
{
292
637k
    px_put_us(s, i);
293
637k
    px_put_a(s, a);
294
637k
}
295
void
296
px_put_u(stream * s, uint i)
297
1.12M
{
298
1.12M
    if (i <= 255)
299
1.12M
        px_put_ub(s, (byte)i);
300
1.21k
    else
301
1.21k
        px_put_us(s, i);
302
1.12M
}
303
304
void
305
px_put_usp(stream * s, uint ix, uint iy)
306
176k
{
307
176k
    spputc(s, pxt_uint16_xy);
308
176k
    px_put_s(s, ix);
309
176k
    px_put_s(s, iy);
310
176k
}
311
void
312
px_put_usq_fixed(stream * s, fixed x0, fixed y0, fixed x1, fixed y1)
313
41.4M
{
314
41.4M
    spputc(s, pxt_uint16_box);
315
41.4M
    px_put_s(s, fixed2int(x0));
316
41.4M
    px_put_s(s, fixed2int(y0));
317
41.4M
    px_put_s(s, fixed2int(x1));
318
41.4M
    px_put_s(s, fixed2int(y1));
319
41.4M
}
320
321
void
322
px_put_ss(stream * s, int i)
323
42.3k
{
324
42.3k
    sputc(s, pxt_sint16);
325
42.3k
    px_put_s(s, i);
326
42.3k
}
327
void
328
px_put_ssp(stream * s, int ix, int iy)
329
23.4M
{
330
23.4M
    sputc(s, pxt_sint16_xy);
331
23.4M
    px_put_s(s, ix);
332
23.4M
    px_put_s(s, iy);
333
23.4M
}
334
335
void
336
px_put_l(stream * s, ulong l)
337
64.5k
{
338
64.5k
    sputc(s, (byte) l);
339
64.5k
    sputc(s, (byte) (l >> 8));
340
64.5k
    sputc(s, (byte) (l >> 16));
341
64.5k
    sputc(s, (byte) (l >> 24));
342
64.5k
}
343
344
/*
345
    The single-precison IEEE float is represented with 32-bit as follows:
346
347
    1      8          23
348
    sign | exponent | matissa_bits
349
350
    switch(exponent):
351
    case 0:
352
        (-1)^sign * 2^(-126) * 0.<matissa_bits>_base2
353
    case 0xFF:
354
        +- infinity
355
    default: (0x01 - 0xFE)
356
        (-1)^sign * 2^(exponent - 127) * 1.<matissa_bits>_base2
357
358
    The "1." part is not coded since it is always "1.".
359
360
    To uses frexp, which returns
361
        0.<matissa_bits>_base2 * 2^exp
362
    We need to think of it as:
363
        1.<matissa_bits,drop_MSB>_base2 * 2^(exp-1)
364
365
    2009: the older version of this code has always been wrong (since 2000),
366
    missing the -1 (the number was wrong by a factor of 2). Checked against
367
    inserting hexdump code and compared with python snipplets (and pxldis):
368
369
    import struct
370
    for x in struct.pack("f", number):
371
        hex(ord(x))
372
*/
373
374
void
375
px_put_r(stream * s, double r)
376
39.7M
{       /* Convert to single-precision IEEE float. */
377
39.7M
    int exp;
378
39.7M
    long mantissa = (long)(frexp(r, &exp) * 0x1000000);
379
380
    /* we can go a bit lower than -126 and represent:
381
           2^(-126) * 0.[22 '0' then '1']_base2 = 2 ^(146) * 0.1_base2
382
       but it is simplier for such small number to be zero. */
383
39.7M
    if (exp < -126)
384
0
        mantissa = 0, exp = 0; /* unnormalized */
385
    /* put the sign bit in the right place */
386
39.7M
    if (mantissa < 0)
387
0
        exp += 128, mantissa = -mantissa;
388
    /* All quantities are little-endian. */
389
39.7M
    spputc(s, (byte) mantissa);
390
39.7M
    spputc(s, (byte) (mantissa >> 8));
391
39.7M
    spputc(s, (byte) (((exp + 126) << 7) + ((mantissa >> 16) & 0x7f)));
392
39.7M
    spputc(s, (byte) ((exp + 126) >> 1));
393
39.7M
}
394
void
395
px_put_rl(stream * s, double r)
396
0
{
397
0
    spputc(s, pxt_real32);
398
0
    px_put_r(s, r);
399
0
}
400
401
void
402
px_put_rp(stream * s, double rx, double ry)
403
19.8M
{
404
19.8M
    spputc(s, pxt_real32_xy);
405
19.8M
    px_put_r(s, rx);
406
19.8M
    px_put_r(s, ry);
407
19.8M
}
408
409
void
410
px_put_rpa(stream * s, double rx, double ry, px_attribute_t a)
411
4.53k
{
412
4.53k
    px_put_rp(s, rx, ry);
413
4.53k
    px_put_a(s, a);
414
4.53k
}
415
416
/* ubyte_array with attribute */
417
void
418
px_put_ubaa(stream * s, const byte * data, uint count, px_attribute_t a)
419
1
{
420
1
    if ((int)count < 0)
421
0
        return;
422
1
    spputc(s, pxt_ubyte_array);
423
    /* uint16 LE length field */
424
1
    px_put_us(s, count);
425
1
    px_put_bytes(s, data, count);
426
1
    px_put_a(s, a);
427
1
}
428
429
void
430
px_put_data_length(stream * s, uint num_bytes)
431
19.2M
{
432
19.2M
    if (num_bytes > 255) {
433
64.5k
        spputc(s, pxt_dataLength);
434
64.5k
        px_put_l(s, (ulong) num_bytes);
435
19.2M
    } else {
436
19.2M
        spputc(s, pxt_dataLengthByte);
437
19.2M
        spputc(s, (byte) num_bytes);
438
19.2M
    }
439
19.2M
}