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