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