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