Coverage Report

Created: 2025-06-10 06:58

/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
0
{
34
0
    static const char *const enter_pjl_header =
35
0
        "\033%-12345X@PJL SET RENDERMODE=";
36
0
    static const char *const set_staple= "\n@PJL SET FINISH=STAPLE";
37
0
    static const char *const rendermode_gray = "GRAYSCALE";
38
0
    static const char *const rendermode_color = "COLOR";
39
0
    static const char *const pjl_resolution =
40
0
        "\n@PJL SET RESOLUTION=";
41
0
    static const char *const resolution_150 = "150";
42
0
    static const char *const resolution_300 = "300";
43
0
    static const char *const resolution_600 = "600";
44
0
    static const char *const resolution_1200 = "1200";
45
0
    static const char *const resolution_2400 = "2400";
46
0
    static const char *const file_header =
47
0
        "\n@PJL ENTER LANGUAGE = PCLXL\n\
48
0
) HP-PCL XL;1;1;Comment Copyright Artifex Sofware, Inc. 2005-2023\000\n";
49
0
    static const byte stream_header[] = {
50
0
        DA(pxaUnitsPerMeasure),
51
0
        DUB(0), DA(pxaMeasure),
52
0
        DUB(eBackChAndErrPage), DA(pxaErrorReport),
53
0
        pxtBeginSession,
54
0
        DUB(0), DA(pxaSourceType),
55
0
        DUB(eBinaryLowByteFirst), DA(pxaDataOrg),
56
0
        pxtOpenDataSource
57
0
    };
58
59
0
    px_put_bytes(s, (const byte *)enter_pjl_header,
60
0
                 strlen(enter_pjl_header));
61
62
0
    if (dev->color_info.num_components == 1)
63
0
        px_put_bytes(s, (const byte *)rendermode_gray,
64
0
                     strlen(rendermode_gray));
65
0
    else
66
0
        px_put_bytes(s, (const byte *)rendermode_color,
67
0
                     strlen(rendermode_color));
68
69
0
    if(staple)
70
0
        px_put_bytes(s, (const byte *)set_staple,
71
0
                     strlen(set_staple));
72
73
0
    px_put_bytes(s, (const byte *)pjl_resolution,
74
0
                 strlen(pjl_resolution));
75
76
0
    if ((uint) (dev->HWResolution[0] + 0.5) == 150)
77
0
        px_put_bytes(s, (const byte *)resolution_150,
78
0
                     strlen(resolution_150));
79
0
    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
0
    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
0
    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
0
    else
89
0
        px_put_bytes(s, (const byte *)resolution_600,
90
0
                     strlen(resolution_600));
91
0
    if ((uint) (dev->HWResolution[1] + 0.5) !=
92
0
        (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
0
    px_put_bytes(s, (const byte *)file_header,
114
0
                 strlen(file_header) + 2);
115
0
    px_put_usp(s, (uint) (dev->HWResolution[0] + 0.5),
116
0
               (uint) (dev->HWResolution[1] + 0.5));
117
0
    PX_PUT_LIT(s, stream_header);
118
0
    return 0;
119
0
}
120
121
/* Write the page header, including orientation. */
122
int
123
px_write_page_header(stream *s, const gx_device *dev)
124
0
{
125
    /* Orientation is deferred until px_write_select_media... */
126
0
    return 0;
127
0
}
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
0
{
135
0
#define MSD(ms, mstr, res, w, h)                                 \
136
0
    { ms, mstr, (float)((w) * 1.0 / (res)), (float)((h) * 1.0 / res) },
137
0
    static const struct {
138
0
        pxeMediaSize_t ms;
139
0
        const char *media_name;
140
0
        float width, height;
141
0
    } media_sizes[] = {
142
0
        px_enumerate_media(MSD)
143
0
        { pxeMediaSize_next }
144
0
    };
145
0
#undef MSD
146
0
    float w = dev->width / dev->HWResolution[0],
147
0
        h = dev->height / dev->HWResolution[1];
148
0
    int i;
149
0
    pxeMediaSize_t size = eDefaultPaperSize;
150
0
    byte tray = eAutoSelect;
151
0
    byte orientation = ePortraitOrientation;
152
0
    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
0
    for (i = countof(media_sizes) - 2; i > 0; --i)
157
0
        if (fabs(media_sizes[i].width - w) < 0.05 &&
158
0
            fabs(media_sizes[i].height - h) < 0.05 &&
159
0
            media_sizes[i].ms < 22 /* HP uses up to 21; Ricoh uses 201-224 */
160
0
            ) {
161
0
            match_found = true;
162
0
            size = media_sizes[i].ms;
163
0
            break;
164
0
  } else if (fabs(media_sizes[i].height - w) < 0.05 &&
165
0
       fabs(media_sizes[i].width - h) < 0.05 &&
166
0
                   media_sizes[i].ms < 22
167
0
       ) {
168
0
      match_found = true;
169
0
      size = media_sizes[i].ms;
170
0
      orientation = eLandscapeOrientation;
171
0
      break;
172
0
        }
173
    /*
174
     * According to the PCL XL documentation, MediaSize/CustomMediaSize must always
175
     * be specified, but MediaSource is optional.
176
     */
177
0
    px_put_uba(s, orientation, pxaOrientation);
178
0
    if (match_found) {
179
        /* standard media */
180
0
        px_put_uba(s, (byte)size, pxaMediaSize);
181
0
    } else {
182
        /* CustomMediaSize in Inches */
183
0
        px_put_rpa(s, w, h, pxaCustomMediaSize);
184
0
        px_put_uba(s, (byte)eInch, pxaCustomMediaSizeUnits);
185
0
    }
186
187
0
    if (media_source != NULL)
188
0
        tray = *media_source;
189
    /* suppress eAutoSelect if type is set */
190
0
    if (!media_type_set || (tray != eAutoSelect))
191
0
      px_put_uba(s, tray, pxaMediaSource);
192
    /* suppress empty(="plain") type if tray is non-auto */
193
0
    if (media_type_set)
194
0
        if ((tray == eAutoSelect) || strlen(media_type))
195
0
          px_put_ubaa(s, (const byte *)media_type, strlen(media_type), pxaMediaType);
196
197
0
    if_debug2('|', "duplex %d tumble %d\n", Duplex, Tumble);
198
0
    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
0
    else
211
0
      px_put_uba(s, (byte)eSimplexFrontSide, pxaSimplexPageMode);
212
213
0
    if (pms)
214
0
        *pms = size;
215
216
0
    return 0;
217
0
}
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
0
{
226
0
    static const byte file_trailer[] = {
227
0
        pxtCloseDataSource,
228
0
        pxtEndSession,
229
0
        033, '%', '-', '1', '2', '3', '4', '5', 'X'
230
0
    };
231
232
0
    gp_fwrite(file_trailer, 1, sizeof(file_trailer), file);
233
0
    return 0;
234
0
}
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
0
{
242
0
    uint used;
243
244
0
    sputs(s, data, count, &used);
245
0
}
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
0
{
252
0
    sputc(s, pxt_attr_ubyte);
253
0
    sputc(s, (byte)a);
254
0
}
255
void
256
px_put_ac(stream *s, px_attribute_t a, px_tag_t op)
257
0
{
258
0
    px_put_a(s, a);
259
0
    sputc(s, (byte)op);
260
0
}
261
262
void
263
px_put_ub(stream * s, byte b)
264
0
{
265
0
    sputc(s, pxt_ubyte);
266
0
    sputc(s, b);
267
0
}
268
void
269
px_put_uba(stream *s, byte b, px_attribute_t a)
270
0
{
271
0
    px_put_ub(s, b);
272
0
    px_put_a(s, a);
273
0
}
274
275
void
276
px_put_s(stream * s, int i)
277
0
{
278
0
    sputc(s, (byte) i);
279
0
    if (i < 0)
280
0
       i |= 0x8000;
281
0
    sputc(s, (byte) (i >> 8));
282
0
}
283
void
284
px_put_us(stream * s, uint i)
285
0
{
286
0
    sputc(s, pxt_uint16);
287
0
    px_put_s(s, i);
288
0
}
289
void
290
px_put_usa(stream *s, uint i, px_attribute_t a)
291
0
{
292
0
    px_put_us(s, i);
293
0
    px_put_a(s, a);
294
0
}
295
void
296
px_put_u(stream * s, uint i)
297
0
{
298
0
    if (i <= 255)
299
0
        px_put_ub(s, (byte)i);
300
0
    else
301
0
        px_put_us(s, i);
302
0
}
303
304
void
305
px_put_usp(stream * s, uint ix, uint iy)
306
0
{
307
0
    spputc(s, pxt_uint16_xy);
308
0
    px_put_s(s, ix);
309
0
    px_put_s(s, iy);
310
0
}
311
void
312
px_put_usq_fixed(stream * s, fixed x0, fixed y0, fixed x1, fixed y1)
313
0
{
314
0
    spputc(s, pxt_uint16_box);
315
0
    px_put_s(s, fixed2int(x0));
316
0
    px_put_s(s, fixed2int(y0));
317
0
    px_put_s(s, fixed2int(x1));
318
0
    px_put_s(s, fixed2int(y1));
319
0
}
320
321
void
322
px_put_ss(stream * s, int i)
323
0
{
324
0
    sputc(s, pxt_sint16);
325
0
    px_put_s(s, i);
326
0
}
327
void
328
px_put_ssp(stream * s, int ix, int iy)
329
0
{
330
0
    sputc(s, pxt_sint16_xy);
331
0
    px_put_s(s, ix);
332
0
    px_put_s(s, iy);
333
0
}
334
335
void
336
px_put_l(stream * s, ulong l)
337
0
{
338
0
    sputc(s, (byte) l);
339
0
    sputc(s, (byte) (l >> 8));
340
0
    sputc(s, (byte) (l >> 16));
341
0
    sputc(s, (byte) (l >> 24));
342
0
}
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
0
{       /* Convert to single-precision IEEE float. */
377
0
    int exp;
378
0
    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
0
    if (exp < -126)
384
0
        mantissa = 0, exp = 0; /* unnormalized */
385
    /* put the sign bit in the right place */
386
0
    if (mantissa < 0)
387
0
        exp += 128, mantissa = -mantissa;
388
    /* All quantities are little-endian. */
389
0
    spputc(s, (byte) mantissa);
390
0
    spputc(s, (byte) (mantissa >> 8));
391
0
    spputc(s, (byte) (((exp + 126) << 7) + ((mantissa >> 16) & 0x7f)));
392
0
    spputc(s, (byte) ((exp + 126) >> 1));
393
0
}
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
0
{
404
0
    spputc(s, pxt_real32_xy);
405
0
    px_put_r(s, rx);
406
0
    px_put_r(s, ry);
407
0
}
408
409
void
410
px_put_rpa(stream * s, double rx, double ry, px_attribute_t a)
411
0
{
412
0
    px_put_rp(s, rx, ry);
413
0
    px_put_a(s, a);
414
0
}
415
416
/* ubyte_array with attribute */
417
void
418
px_put_ubaa(stream * s, const byte * data, uint count, px_attribute_t a)
419
0
{
420
0
    if ((int)count < 0)
421
0
        return;
422
0
    spputc(s, pxt_ubyte_array);
423
    /* uint16 LE length field */
424
0
    px_put_us(s, count);
425
0
    px_put_bytes(s, data, count);
426
0
    px_put_a(s, a);
427
0
}
428
429
void
430
px_put_data_length(stream * s, uint num_bytes)
431
0
{
432
0
    if (num_bytes > 255) {
433
0
        spputc(s, pxt_dataLength);
434
0
        px_put_l(s, (ulong) num_bytes);
435
0
    } else {
436
0
        spputc(s, pxt_dataLengthByte);
437
0
        spputc(s, (byte) num_bytes);
438
0
    }
439
0
}