xref: /plan9/sys/src/cmd/gs/src/gdevpxut.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpxut.c,v 1.8 2005/07/11 22:08:30 stefan Exp $ */
18 /* Utilities for PCL XL generation */
19 #include "math_.h"
20 #include "string_.h"
21 #include "gx.h"
22 #include "stream.h"
23 #include "gxdevcli.h"
24 #include "gdevpxat.h"
25 #include "gdevpxen.h"
26 #include "gdevpxop.h"
27 #include "gdevpxut.h"
28 #include <assert.h>
29 
30 /* ---------------- High-level constructs ---------------- */
31 
32 /* Write the file header, including the resolution. */
33 int
px_write_file_header(stream * s,const gx_device * dev)34 px_write_file_header(stream *s, const gx_device *dev)
35 {
36     static const char *const enter_pjl_header =
37         "\033%-12345X@PJL SET RENDERMODE=";
38     static const char *const rendermode_gray = "GRAYSCALE";
39     static const char *const rendermode_color = "COLOR";
40     static const char *const file_header =
41 	"\n@PJL ENTER LANGUAGE = PCLXL\n\
42 ) HP-PCL XL;1;1;Comment Copyright artofcode LLC 2005\000\n";
43     static const byte stream_header[] = {
44 	DA(pxaUnitsPerMeasure),
45 	DUB(0), DA(pxaMeasure),
46 	DUB(eBackChAndErrPage), DA(pxaErrorReport),
47 	pxtBeginSession,
48 	DUB(0), DA(pxaSourceType),
49 	DUB(eBinaryLowByteFirst), DA(pxaDataOrg),
50 	pxtOpenDataSource
51     };
52 
53     px_put_bytes(s, (const byte *)enter_pjl_header,
54 		 strlen(enter_pjl_header));
55 
56     if (dev->color_info.num_components == 1)
57 	px_put_bytes(s, (const byte *)rendermode_gray,
58 		     strlen(rendermode_gray));
59     else
60 	px_put_bytes(s, (const byte *)rendermode_color,
61 		     strlen(rendermode_color));
62 
63     /* We have to add 2 to the strlen because the next-to-last */
64     /* character is a null. */
65     px_put_bytes(s, (const byte *)file_header,
66 		 strlen(file_header) + 2);
67     px_put_usp(s, (uint) (dev->HWResolution[0] + 0.5),
68 	       (uint) (dev->HWResolution[1] + 0.5));
69     PX_PUT_LIT(s, stream_header);
70     return 0;
71 }
72 
73 /* Write the page header, including orientation. */
74 int
px_write_page_header(stream * s,const gx_device * dev)75 px_write_page_header(stream *s, const gx_device *dev)
76 {
77     static const byte page_header_1[] = {
78 	DUB(ePortraitOrientation), DA(pxaOrientation)
79     };
80 
81     PX_PUT_LIT(s, page_header_1);
82     return 0;
83 }
84 
85 /* Write the media selection command if needed, updating the media size. */
86 int
px_write_select_media(stream * s,const gx_device * dev,pxeMediaSize_t * pms,byte * media_source)87 px_write_select_media(stream *s, const gx_device *dev,
88 		      pxeMediaSize_t *pms, byte *media_source)
89 {
90 #define MSD(ms, res, w, h)\
91   { ms, (float)((w) * 1.0 / (res)), (float)((h) * 1.0 / res) },
92     static const struct {
93 	pxeMediaSize_t ms;
94 	float width, height;
95     } media_sizes[] = {
96 	px_enumerate_media(MSD)
97 	{ pxeMediaSize_next }
98     };
99 #undef MSD
100     float w = dev->width / dev->HWResolution[0],
101 	h = dev->height / dev->HWResolution[1];
102     int i;
103     pxeMediaSize_t size;
104     byte tray = eAutoSelect;
105 
106     /* The default is eLetterPaper, media size 0. */
107     for (i = countof(media_sizes) - 2; i > 0; --i)
108 	if (fabs(media_sizes[i].width - w) < 5.0 / 72 &&
109 	    fabs(media_sizes[i].height - h) < 5.0 / 72
110 	    )
111 	    break;
112     size = media_sizes[i].ms;
113     /*
114      * According to the PCL XL documentation, MediaSize must always
115      * be specified, but MediaSource is optional.
116      */
117     px_put_uba(s, (byte)size, pxaMediaSize);
118 
119     if (media_source != NULL)
120 	tray = *media_source;
121     px_put_uba(s, tray, pxaMediaSource);
122     if (pms)
123 	*pms = size;
124 
125     return 0;
126 }
127 
128 /*
129  * Write the file trailer.  Note that this takes a FILE *, not a stream *,
130  * since it may be called after the stream is closed.
131  */
132 int
px_write_file_trailer(FILE * file)133 px_write_file_trailer(FILE *file)
134 {
135     static const byte file_trailer[] = {
136 	pxtCloseDataSource,
137 	pxtEndSession,
138 	033, '%', '-', '1', '2', '3', '4', '5', 'X'
139     };
140 
141     fwrite(file_trailer, 1, sizeof(file_trailer), file);
142     return 0;
143 }
144 
145 /* ---------------- Low-level data output ---------------- */
146 
147 /* Write a sequence of bytes. */
148 void
px_put_bytes(stream * s,const byte * data,uint count)149 px_put_bytes(stream * s, const byte * data, uint count)
150 {
151     uint used;
152 
153     sputs(s, data, count, &used);
154 }
155 
156 /* Utilities for writing data values. */
157 /* H-P printers only support little-endian data, so that's what we emit. */
158 void
px_put_a(stream * s,px_attribute_t a)159 px_put_a(stream * s, px_attribute_t a)
160 {
161     sputc(s, pxt_attr_ubyte);
162     sputc(s, (byte)a);
163 }
164 void
px_put_ac(stream * s,px_attribute_t a,px_tag_t op)165 px_put_ac(stream *s, px_attribute_t a, px_tag_t op)
166 {
167     px_put_a(s, a);
168     sputc(s, (byte)op);
169 }
170 
171 void
px_put_ub(stream * s,byte b)172 px_put_ub(stream * s, byte b)
173 {
174     sputc(s, pxt_ubyte);
175     sputc(s, b);
176 }
177 void
px_put_uba(stream * s,byte b,px_attribute_t a)178 px_put_uba(stream *s, byte b, px_attribute_t a)
179 {
180     px_put_ub(s, b);
181     px_put_a(s, a);
182 }
183 
184 void
px_put_s(stream * s,uint i)185 px_put_s(stream * s, uint i)
186 {
187     sputc(s, (byte) i);
188     sputc(s, (byte) (i >> 8));
189 }
190 void
px_put_us(stream * s,uint i)191 px_put_us(stream * s, uint i)
192 {
193     sputc(s, pxt_uint16);
194     px_put_s(s, i);
195 }
196 void
px_put_usa(stream * s,uint i,px_attribute_t a)197 px_put_usa(stream *s, uint i, px_attribute_t a)
198 {
199     px_put_us(s, i);
200     px_put_a(s, a);
201 }
202 void
px_put_u(stream * s,uint i)203 px_put_u(stream * s, uint i)
204 {
205     if (i <= 255)
206 	px_put_ub(s, (byte)i);
207     else
208 	px_put_us(s, i);
209 }
210 
211 void
px_put_usp(stream * s,uint ix,uint iy)212 px_put_usp(stream * s, uint ix, uint iy)
213 {
214     spputc(s, pxt_uint16_xy);
215     px_put_s(s, ix);
216     px_put_s(s, iy);
217 }
218 void
px_put_usq_fixed(stream * s,fixed x0,fixed y0,fixed x1,fixed y1)219 px_put_usq_fixed(stream * s, fixed x0, fixed y0, fixed x1, fixed y1)
220 {
221     spputc(s, pxt_uint16_box);
222     px_put_s(s, fixed2int(x0));
223     px_put_s(s, fixed2int(y0));
224     px_put_s(s, fixed2int(x1));
225     px_put_s(s, fixed2int(y1));
226 }
227 
228 void
px_put_ss(stream * s,int i)229 px_put_ss(stream * s, int i)
230 {
231     sputc(s, pxt_sint16);
232     px_put_s(s, (uint) i);
233 }
234 void
px_put_ssp(stream * s,int ix,int iy)235 px_put_ssp(stream * s, int ix, int iy)
236 {
237     sputc(s, pxt_sint16_xy);
238     px_put_s(s, (uint) ix);
239     px_put_s(s, (uint) iy);
240 }
241 
242 void
px_put_l(stream * s,ulong l)243 px_put_l(stream * s, ulong l)
244 {
245     px_put_s(s, (uint) l);
246     px_put_s(s, (uint) (l >> 16));
247 }
248 
249 void
px_put_r(stream * s,floatp r)250 px_put_r(stream * s, floatp r)
251 {				/* Convert to single-precision IEEE float. */
252     int exp;
253     long mantissa = (long)(frexp(r, &exp) * 0x1000000);
254 
255     if (exp < -126)
256 	mantissa = 0, exp = 0;	/* unnormalized */
257     if (mantissa < 0)
258 	exp += 128, mantissa = -mantissa;
259     /* All quantities are little-endian. */
260     spputc(s, (byte) mantissa);
261     spputc(s, (byte) (mantissa >> 8));
262     spputc(s, (byte) (((exp + 127) << 7) + ((mantissa >> 16) & 0x7f)));
263     spputc(s, (byte) ((exp + 127) >> 1));
264 }
265 void
px_put_rl(stream * s,floatp r)266 px_put_rl(stream * s, floatp r)
267 {
268     spputc(s, pxt_real32);
269     px_put_r(s, r);
270 }
271 
272 void
px_put_data_length(stream * s,uint num_bytes)273 px_put_data_length(stream * s, uint num_bytes)
274 {
275     if (num_bytes > 255) {
276 	spputc(s, pxt_dataLength);
277 	px_put_l(s, (ulong) num_bytes);
278     } else {
279 	spputc(s, pxt_dataLengthByte);
280 	spputc(s, (byte) num_bytes);
281     }
282 }
283