2 |
- |
1 |
/* Copyright (C) 1998, 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: gdevclj.c,v 1.4 2002/02/21 22:24:51 giles Exp $ */
|
|
|
18 |
/*
|
|
|
19 |
* H-P Color LaserJet 5/5M device; based on the PaintJet.
|
|
|
20 |
*/
|
|
|
21 |
#include "math_.h"
|
|
|
22 |
#include "gx.h"
|
|
|
23 |
#include "gsparam.h"
|
|
|
24 |
#include "gdevprn.h"
|
|
|
25 |
#include "gdevpcl.h"
|
|
|
26 |
|
|
|
27 |
typedef struct gx_device_clj_s gx_device_clj;
|
|
|
28 |
struct gx_device_clj_s {
|
|
|
29 |
gx_device_common;
|
|
|
30 |
gx_prn_device_common;
|
|
|
31 |
bool rotated;
|
|
|
32 |
};
|
|
|
33 |
|
|
|
34 |
#define pclj ((gx_device_clj *)pdev)
|
|
|
35 |
|
|
|
36 |
/*
|
|
|
37 |
* The HP Color LaserJet 5/5M provides a rather unexpected speed/performance
|
|
|
38 |
* tradeoff.
|
|
|
39 |
*
|
|
|
40 |
* When generating rasters, only the fixed (simple) color spaces provide
|
|
|
41 |
* reasonable performance (in this case, reasonable != good). However, in
|
|
|
42 |
* these modes, certain of the fully-saturated primary colors (cyan, blue,
|
|
|
43 |
* green, and red) are rendered differently as rasters as opposed to colored
|
|
|
44 |
* geometric objects. Hence, the color of the output will be other than what
|
|
|
45 |
* is expected.
|
|
|
46 |
*
|
|
|
47 |
* Alternatively, the direct color, 1-bit per pixel scheme can be used. This
|
|
|
48 |
* will produce the expected colors, but performance will deteriorate
|
|
|
49 |
* significantly (observed printing time will be about 3 times longer than
|
|
|
50 |
* when using the simple color mode).
|
|
|
51 |
*
|
|
|
52 |
* Note that when using the latter mode to view output from the PCL
|
|
|
53 |
* interpreter, geometric objects and raster rendered with other than
|
|
|
54 |
* geometric color spaces will have the same appearance as if sent directly
|
|
|
55 |
* to the CLJ, but rasters generated from simple color spaces will have a
|
|
|
56 |
* different appearance. To make the latter rasters match in appearance, the
|
|
|
57 |
* faster printing mode must be used (in which the case the other objects
|
|
|
58 |
* will not have the same appearance).
|
|
|
59 |
*/
|
|
|
60 |
#define USE_FAST_MODE
|
|
|
61 |
|
|
|
62 |
/* X_DPI and Y_DPI must be the same */
|
|
|
63 |
#define X_DPI 300
|
|
|
64 |
#define Y_DPI 300
|
|
|
65 |
|
|
|
66 |
/*
|
|
|
67 |
* Array of paper sizes, and the corresponding offsets.
|
|
|
68 |
*/
|
|
|
69 |
typedef struct clj_paper_size_s {
|
|
|
70 |
uint tag; /* paper type tag */
|
|
|
71 |
int orient; /* logical page orientation to use */
|
|
|
72 |
float width, height; /* in pts; +- 5 pts */
|
|
|
73 |
gs_point offsets; /* offsets in the given orientation */
|
|
|
74 |
} clj_paper_size;
|
|
|
75 |
|
|
|
76 |
/*
|
|
|
77 |
* The Color LaserJet prints page sizes up to 11.8" wide (A4 size) in
|
|
|
78 |
* long-edge-feed (landscape) orientation. Only executive, letter, and
|
|
|
79 |
* A4 size are supported for color, so we don't bother to list the others.
|
|
|
80 |
*/
|
|
|
81 |
private const clj_paper_size clj_paper_sizes[] = {
|
|
|
82 |
/* U.S. letter size comes first so it will be the default. */
|
|
|
83 |
{ 2, 1, 11.00 * 72.0, 8.50 * 72.0, { .200 * 72.0, 0.0 } },
|
|
|
84 |
{ 1, 1, 10.50 * 72.0, 7.25 * 72.0, { .200 * 72.0, 0.0 } },
|
|
|
85 |
{ 26, 1, 11.69 * 72.0, 8.27 * 72.0, { .197 * 72.0, 0.0 } }
|
|
|
86 |
};
|
|
|
87 |
|
|
|
88 |
/*
|
|
|
89 |
* The supported set of resolutions.
|
|
|
90 |
*
|
|
|
91 |
* The Color LaserJet 5/5M is actually a pseudo-contone device, with hardware
|
|
|
92 |
* capable of providing about 16 levels of intensity. The current code does
|
|
|
93 |
* not take advantage of this feature, because it is not readily controllable
|
|
|
94 |
* via PCL. Rather, the device is modeled as a bi-level device in each of
|
|
|
95 |
* three color planes. The maximum supported resolution for such an arrangement
|
|
|
96 |
* is 300 dpi.
|
|
|
97 |
*
|
|
|
98 |
* The CLJ does support raster scaling, but to invoke that scaling, even for
|
|
|
99 |
* integral factors, involves a large performance penalty. Hence, only those
|
|
|
100 |
* resolutions that can be supported without invoking raster scaling are
|
|
|
101 |
* included here. These resolutions are always the same in the fast and slow
|
|
|
102 |
* scan directions, so only a single value is listed here.
|
|
|
103 |
*
|
|
|
104 |
* All valuse are in dots per inch.
|
|
|
105 |
*/
|
|
|
106 |
private const float supported_resolutions[] = { 75.0, 100.0, 150.0, 300.0 };
|
|
|
107 |
|
|
|
108 |
|
|
|
109 |
/* indicate the maximum supported resolution and scan-line length (pts) */
|
|
|
110 |
#define CLJ_MAX_RES 300.0
|
|
|
111 |
#define CLJ_MAX_SCANLINE (12.0 * 72.0)
|
|
|
112 |
|
|
|
113 |
|
|
|
114 |
/*
|
|
|
115 |
* Determine a requested resolution pair is supported.
|
|
|
116 |
*/
|
|
|
117 |
private bool
|
|
|
118 |
is_supported_resolution(
|
|
|
119 |
const float HWResolution[2]
|
|
|
120 |
)
|
|
|
121 |
{
|
|
|
122 |
int i;
|
|
|
123 |
|
|
|
124 |
for (i = 0; i < countof(supported_resolutions); i++) {
|
|
|
125 |
if (HWResolution[0] == supported_resolutions[i])
|
|
|
126 |
return HWResolution[0] == HWResolution[1];
|
|
|
127 |
}
|
|
|
128 |
return false;
|
|
|
129 |
}
|
|
|
130 |
|
|
|
131 |
/* ---------------- Standard driver ---------------- */
|
|
|
132 |
|
|
|
133 |
/*
|
|
|
134 |
* Find the paper size information corresponding to a given pair of dimensions.
|
|
|
135 |
* If rotatep != 0, *rotatep is set to true if the page must be rotated 90
|
|
|
136 |
* degrees to fit.
|
|
|
137 |
*
|
|
|
138 |
* A return value of 0 indicates the paper size is not supported.
|
|
|
139 |
*
|
|
|
140 |
* Note that for the standard driver, rotation is not allowed.
|
|
|
141 |
*/
|
|
|
142 |
private const clj_paper_size *
|
|
|
143 |
get_paper_size(
|
|
|
144 |
const float MediaSize[2],
|
|
|
145 |
bool * rotatep
|
|
|
146 |
)
|
|
|
147 |
{
|
|
|
148 |
static const float tolerance = 5.0;
|
|
|
149 |
float width = MediaSize[0];
|
|
|
150 |
float height = MediaSize[1];
|
|
|
151 |
const clj_paper_size * psize = 0;
|
|
|
152 |
int i;
|
|
|
153 |
|
|
|
154 |
for (i = 0, psize = clj_paper_sizes; i < countof(clj_paper_sizes); i++, psize++) {
|
|
|
155 |
if ( (fabs(width - psize->width) <= tolerance) &&
|
|
|
156 |
(fabs(height - psize->height) <= tolerance) ) {
|
|
|
157 |
if (rotatep != 0)
|
|
|
158 |
*rotatep = false;
|
|
|
159 |
return psize;
|
|
|
160 |
} else if ( (fabs(width - psize->height) <= tolerance) &&
|
|
|
161 |
(fabs(height - psize->width) <= tolerance) ) {
|
|
|
162 |
if (rotatep != 0)
|
|
|
163 |
*rotatep = true;
|
|
|
164 |
return psize;
|
|
|
165 |
}
|
|
|
166 |
}
|
|
|
167 |
|
|
|
168 |
return 0;
|
|
|
169 |
}
|
|
|
170 |
|
|
|
171 |
/*
|
|
|
172 |
* Get the (PostScript style) default matrix for the current page size.
|
|
|
173 |
*
|
|
|
174 |
* For all of the supported sizes, the page will be printed with long-edge
|
|
|
175 |
* feed (the CLJ does support some additional sizes, but only for monochrome).
|
|
|
176 |
* As will all HP laser printers, the printable region marin is 12 pts. from
|
|
|
177 |
* the edge of the physical page.
|
|
|
178 |
*/
|
|
|
179 |
private void
|
|
|
180 |
clj_get_initial_matrix( gx_device *pdev, gs_matrix *pmat)
|
|
|
181 |
{
|
|
|
182 |
floatp fs_res = pdev->HWResolution[0] / 72.0;
|
|
|
183 |
floatp ss_res = pdev->HWResolution[1] / 72.0;
|
|
|
184 |
const clj_paper_size *psize;
|
|
|
185 |
|
|
|
186 |
psize = get_paper_size(pdev->MediaSize, NULL);
|
|
|
187 |
/* if the paper size is not recognized, not much can be done */
|
|
|
188 |
/* This shouldn't be possible since clj_put_params rejects */
|
|
|
189 |
/* unknown media sizes. */
|
|
|
190 |
if (psize == 0) {
|
|
|
191 |
pmat->xx = fs_res;
|
|
|
192 |
pmat->xy = 0.0;
|
|
|
193 |
pmat->yx = 0.0;
|
|
|
194 |
pmat->yy = -ss_res;
|
|
|
195 |
pmat->tx = 0.0;
|
|
|
196 |
pmat->ty = pdev->MediaSize[1] * ss_res;
|
|
|
197 |
return;
|
|
|
198 |
}
|
|
|
199 |
|
|
|
200 |
if (pclj->rotated) {
|
|
|
201 |
pmat->xx = 0.0;
|
|
|
202 |
pmat->xy = ss_res;
|
|
|
203 |
pmat->yx = fs_res;
|
|
|
204 |
pmat->yy = 0.0;
|
|
|
205 |
pmat->tx = -psize->offsets.x * fs_res;
|
|
|
206 |
pmat->ty = -psize->offsets.y * ss_res;
|
|
|
207 |
} else {
|
|
|
208 |
pmat->xx = fs_res;
|
|
|
209 |
pmat->xy = 0.0;
|
|
|
210 |
pmat->yx = 0.0;
|
|
|
211 |
pmat->yy = -ss_res;
|
|
|
212 |
pmat->tx = -psize->offsets.x * fs_res;
|
|
|
213 |
pmat->ty = pdev->height + psize->offsets.y * ss_res;
|
|
|
214 |
}
|
|
|
215 |
}
|
|
|
216 |
|
|
|
217 |
/*
|
|
|
218 |
* Get parameters, including InputAttributes for all supported page sizes.
|
|
|
219 |
* We associate each page size with a different "media source", since that
|
|
|
220 |
* is currently the only way to register multiple page sizes.
|
|
|
221 |
*/
|
|
|
222 |
private int
|
|
|
223 |
clj_get_params(gx_device *pdev, gs_param_list *plist)
|
|
|
224 |
{
|
|
|
225 |
gs_param_dict mdict;
|
|
|
226 |
int code = gdev_prn_get_params(pdev, plist);
|
|
|
227 |
int ecode = code;
|
|
|
228 |
int i;
|
|
|
229 |
|
|
|
230 |
code = gdev_begin_input_media(plist, &mdict, countof(clj_paper_sizes));
|
|
|
231 |
if (code < 0)
|
|
|
232 |
ecode = code;
|
|
|
233 |
else {
|
|
|
234 |
for (i = 0; i < countof(clj_paper_sizes); ++i) {
|
|
|
235 |
code = gdev_write_input_page_size(i, &mdict,
|
|
|
236 |
clj_paper_sizes[i].width,
|
|
|
237 |
clj_paper_sizes[i].height);
|
|
|
238 |
if (code < 0)
|
|
|
239 |
ecode = code;
|
|
|
240 |
}
|
|
|
241 |
code = gdev_end_input_media(plist, &mdict);
|
|
|
242 |
if (code < 0)
|
|
|
243 |
ecode = code;
|
|
|
244 |
}
|
|
|
245 |
return ecode;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
/*
|
|
|
249 |
* Get the media size being set by put_params, if any. Return 0 if no media
|
|
|
250 |
* size is being set, 1 (and set mediasize[]) if the size is being set, <0
|
|
|
251 |
* on error.
|
|
|
252 |
*/
|
|
|
253 |
private int
|
|
|
254 |
clj_media_size(float mediasize[2], gs_param_list *plist)
|
|
|
255 |
{
|
|
|
256 |
gs_param_float_array fres;
|
|
|
257 |
gs_param_float_array fsize;
|
|
|
258 |
gs_param_int_array hwsize;
|
|
|
259 |
int have_pagesize = 0;
|
|
|
260 |
|
|
|
261 |
if ( (param_read_float_array(plist, "HWResolution", &fres) == 0) &&
|
|
|
262 |
!is_supported_resolution(fres.data) )
|
|
|
263 |
return_error(gs_error_rangecheck);
|
|
|
264 |
|
|
|
265 |
if ( (param_read_float_array(plist, "PageSize", &fsize) == 0) ||
|
|
|
266 |
(param_read_float_array(plist, ".MediaSize", &fsize) == 0) ) {
|
|
|
267 |
mediasize[0] = fsize.data[0];
|
|
|
268 |
mediasize[1] = fsize.data[1];
|
|
|
269 |
have_pagesize = 1;
|
|
|
270 |
}
|
|
|
271 |
|
|
|
272 |
if (param_read_int_array(plist, "HWSize", &hwsize) == 0) {
|
|
|
273 |
mediasize[0] = ((float)hwsize.data[0]) / fres.data[0];
|
|
|
274 |
mediasize[1] = ((float)hwsize.data[1]) / fres.data[1];
|
|
|
275 |
have_pagesize = 1;
|
|
|
276 |
}
|
|
|
277 |
|
|
|
278 |
return have_pagesize;
|
|
|
279 |
}
|
|
|
280 |
|
|
|
281 |
/*
|
|
|
282 |
* Special put_params routine, to make certain the desired MediaSize and
|
|
|
283 |
* HWResolution are supported.
|
|
|
284 |
*/
|
|
|
285 |
private int
|
|
|
286 |
clj_put_params(
|
|
|
287 |
gx_device * pdev,
|
|
|
288 |
gs_param_list * plist
|
|
|
289 |
)
|
|
|
290 |
{
|
|
|
291 |
float mediasize[2];
|
|
|
292 |
bool rotate = false;
|
|
|
293 |
int have_pagesize = clj_media_size(mediasize, plist);
|
|
|
294 |
|
|
|
295 |
if (have_pagesize < 0)
|
|
|
296 |
return have_pagesize;
|
|
|
297 |
if (have_pagesize) {
|
|
|
298 |
if (get_paper_size(mediasize, &rotate) == 0 || rotate)
|
|
|
299 |
return_error(gs_error_rangecheck);
|
|
|
300 |
}
|
|
|
301 |
return gdev_prn_put_params(pdev, plist);
|
|
|
302 |
}
|
|
|
303 |
|
|
|
304 |
/*
|
|
|
305 |
* Pack and then compress a scanline of data. Return the size of the compressed
|
|
|
306 |
* data produced.
|
|
|
307 |
*
|
|
|
308 |
* Input is arranged with one byte per pixel, but only the three low-order bits
|
|
|
309 |
* are used. These bits are in order ymc, with yellow being the highest order
|
|
|
310 |
* bit.
|
|
|
311 |
*
|
|
|
312 |
* Output is arranged in three planes, with one bit per pixel per plane. The
|
|
|
313 |
* Color LaserJet 5/5M does support more congenial pixel encodings, but use
|
|
|
314 |
* of anything other than the fixed palettes seems to result in very poor
|
|
|
315 |
* performance.
|
|
|
316 |
*
|
|
|
317 |
* Only compresion mode 2 is used. Compression mode 1 (pure run length) has
|
|
|
318 |
* an advantage over compression mode 2 only in cases in which very long runs
|
|
|
319 |
* occur (> 128 bytes). Since both methods provide good compression in that
|
|
|
320 |
* case, it is not worth worrying about, and compression mode 2 provides much
|
|
|
321 |
* better worst-case behavior. Compression mode 3 requires considerably more
|
|
|
322 |
* effort to generate, so it is useful only when it is known a prior that
|
|
|
323 |
* scanlines repeat frequently.
|
|
|
324 |
*/
|
|
|
325 |
private void
|
|
|
326 |
pack_and_compress_scanline(
|
|
|
327 |
const byte * pin,
|
|
|
328 |
int in_size,
|
|
|
329 |
byte * pout[3],
|
|
|
330 |
int out_size[3]
|
|
|
331 |
)
|
|
|
332 |
{
|
|
|
333 |
#define BUFF_SIZE \
|
|
|
334 |
( ((int)(CLJ_MAX_RES * CLJ_MAX_SCANLINE / 72.0) + sizeof(ulong) - 1) \
|
|
|
335 |
/ sizeof(ulong) )
|
|
|
336 |
|
|
|
337 |
ulong buff[3 * BUFF_SIZE];
|
|
|
338 |
byte * p_c = (byte *)buff;
|
|
|
339 |
byte * p_m = (byte *)(buff + BUFF_SIZE);
|
|
|
340 |
byte * p_y = (byte *)(buff + 2 * BUFF_SIZE);
|
|
|
341 |
ulong * ptrs[3];
|
|
|
342 |
byte c_val = 0, m_val = 0, y_val = 0;
|
|
|
343 |
ulong mask = 0x80;
|
|
|
344 |
int i;
|
|
|
345 |
|
|
|
346 |
/* pack the input for 4-bits per index */
|
|
|
347 |
for (i = 0; i < in_size; i++) {
|
|
|
348 |
uint ival = *pin++;
|
|
|
349 |
|
|
|
350 |
if (ival != 0) {
|
|
|
351 |
if ((ival & 0x4) != 0)
|
|
|
352 |
y_val |= mask;
|
|
|
353 |
if ((ival & 0x2) != 0)
|
|
|
354 |
m_val |= mask;
|
|
|
355 |
if ((ival & 0x1) != 0)
|
|
|
356 |
c_val |= mask;
|
|
|
357 |
}
|
|
|
358 |
|
|
|
359 |
if ((mask >>= 1) == 0) {
|
|
|
360 |
/* NB - write out in byte units */
|
|
|
361 |
*p_c++ = c_val;
|
|
|
362 |
c_val = 0L;
|
|
|
363 |
*p_m++ = m_val;
|
|
|
364 |
m_val = 0L;
|
|
|
365 |
*p_y++ = y_val;
|
|
|
366 |
y_val = 0L;
|
|
|
367 |
mask = 0x80;
|
|
|
368 |
}
|
|
|
369 |
}
|
|
|
370 |
if (mask != 0x80) {
|
|
|
371 |
/* NB - write out in byte units */
|
|
|
372 |
*p_c++ = c_val;
|
|
|
373 |
*p_m++ = m_val;
|
|
|
374 |
*p_y++ = y_val;
|
|
|
375 |
}
|
|
|
376 |
|
|
|
377 |
/* clear to up a longword boundary */
|
|
|
378 |
while ((((ulong)p_c) & (sizeof(ulong) - 1)) != 0) {
|
|
|
379 |
*p_c++ = 0;
|
|
|
380 |
*p_m++ = 0;
|
|
|
381 |
*p_y++ = 0;
|
|
|
382 |
}
|
|
|
383 |
|
|
|
384 |
ptrs[0] = (ulong *)p_c;
|
|
|
385 |
ptrs[1] = (ulong *)p_m;
|
|
|
386 |
ptrs[2] = (ulong *)p_y;
|
|
|
387 |
|
|
|
388 |
for (i = 0; i < 3; i++) {
|
|
|
389 |
ulong * p_start = buff + i * BUFF_SIZE;
|
|
|
390 |
ulong * p_end = ptrs[i];
|
|
|
391 |
|
|
|
392 |
/* eleminate trailing 0's */
|
|
|
393 |
while ((p_end > p_start) && (p_end[-1] == 0))
|
|
|
394 |
p_end--;
|
|
|
395 |
|
|
|
396 |
if (p_start == p_end)
|
|
|
397 |
out_size[i] = 0;
|
|
|
398 |
else
|
|
|
399 |
out_size[i] = gdev_pcl_mode2compress(p_start, p_end, pout[i]);
|
|
|
400 |
}
|
|
|
401 |
|
|
|
402 |
#undef BUFF_SIZE
|
|
|
403 |
}
|
|
|
404 |
|
|
|
405 |
/*
|
|
|
406 |
* Send the page to the printer. Compress each scan line.
|
|
|
407 |
*/
|
|
|
408 |
private int
|
|
|
409 |
clj_print_page(
|
|
|
410 |
gx_device_printer * pdev,
|
|
|
411 |
FILE * prn_stream
|
|
|
412 |
)
|
|
|
413 |
{
|
|
|
414 |
gs_memory_t *mem = pdev->memory;
|
|
|
415 |
bool rotate;
|
|
|
416 |
const clj_paper_size * psize = get_paper_size(pdev->MediaSize, &rotate);
|
|
|
417 |
int lsize = pdev->width;
|
|
|
418 |
int clsize = (lsize + (lsize + 255) / 128) / 8;
|
|
|
419 |
byte * data = 0;
|
|
|
420 |
byte * cdata[3];
|
|
|
421 |
int blank_lines = 0;
|
|
|
422 |
int i;
|
|
|
423 |
floatp fs_res = pdev->HWResolution[0] / 72.0;
|
|
|
424 |
floatp ss_res = pdev->HWResolution[1] / 72.0;
|
|
|
425 |
int imageable_width, imageable_height;
|
|
|
426 |
|
|
|
427 |
/* no paper size at this point is a serious error */
|
|
|
428 |
if (psize == 0)
|
|
|
429 |
return_error(gs_error_unregistered);
|
|
|
430 |
|
|
|
431 |
/* allocate memory for the raw and compressed data */
|
|
|
432 |
if ((data = gs_alloc_bytes(mem, lsize, "clj_print_page(data)")) == 0)
|
|
|
433 |
return_error(gs_error_VMerror);
|
|
|
434 |
if ((cdata[0] = gs_alloc_bytes(mem, 3 * clsize, "clj_print_page(cdata)")) == 0) {
|
|
|
435 |
gs_free_object(mem, data, "clj_print_page(data)");
|
|
|
436 |
return_error(gs_error_VMerror);
|
|
|
437 |
}
|
|
|
438 |
cdata[1] = cdata[0] + clsize;
|
|
|
439 |
cdata[2] = cdata[1] + clsize;
|
|
|
440 |
|
|
|
441 |
|
|
|
442 |
/* Imageable area is without the margins. Note that the actual rotation
|
|
|
443 |
* of page size into pdev->width & height has been done. We just use
|
|
|
444 |
* rotate to access the correct offsets. */
|
|
|
445 |
if (pclj->rotated) {
|
|
|
446 |
imageable_width = pdev->width - (2 * psize->offsets.x) * fs_res;
|
|
|
447 |
imageable_height = pdev->height - (2 * psize->offsets.y) * ss_res;
|
|
|
448 |
}
|
|
|
449 |
else {
|
|
|
450 |
imageable_width = pdev->width - (2 * psize->offsets.y) * ss_res;
|
|
|
451 |
imageable_height = pdev->height - (2 * psize->offsets.x) * fs_res;
|
|
|
452 |
}
|
|
|
453 |
|
|
|
454 |
/* start the page. The pcl origin (0, 150 dots by default, y
|
|
|
455 |
increasing down the long edge side of the page) needs to be
|
|
|
456 |
offset such that it coincides with the offsets of the imageable
|
|
|
457 |
area. This calculation should be independant of rotation but
|
|
|
458 |
only the rotated case has been tested with a real device. */
|
|
|
459 |
fprintf( prn_stream,
|
|
|
460 |
"\033E\033&u300D\033&l%da1x%dO\033*p0x0y+50x-100Y\033*t%dR"
|
|
|
461 |
#ifdef USE_FAST_MODE
|
|
|
462 |
"\033*r-3U"
|
|
|
463 |
#else
|
|
|
464 |
"\033*v6W\001\002\003\001\001\001"
|
|
|
465 |
#endif
|
|
|
466 |
"\033*r0f%ds%dt1A\033*b2M",
|
|
|
467 |
psize->tag,
|
|
|
468 |
pclj->rotated,
|
|
|
469 |
(int)(pdev->HWResolution[0]),
|
|
|
470 |
imageable_width,
|
|
|
471 |
imageable_height
|
|
|
472 |
);
|
|
|
473 |
|
|
|
474 |
/* process each scanline */
|
|
|
475 |
for (i = 0; i < imageable_height; i++) {
|
|
|
476 |
int clen[3];
|
|
|
477 |
|
|
|
478 |
gdev_prn_copy_scan_lines(pdev, i, data, lsize);
|
|
|
479 |
|
|
|
480 |
/* The 'lsize' bytes of data have the blank margin area at the end due */
|
|
|
481 |
/* to the 'initial_matrix' offsets that are applied. */
|
|
|
482 |
pack_and_compress_scanline(data, imageable_width, cdata, clen);
|
|
|
483 |
if ((clen[0] == 0) && (clen[1] == 0) && (clen[2] == 0))
|
|
|
484 |
++blank_lines;
|
|
|
485 |
else {
|
|
|
486 |
if (blank_lines != 0) {
|
|
|
487 |
fprintf(prn_stream, "\033*b%dY", blank_lines);
|
|
|
488 |
blank_lines = 0;
|
|
|
489 |
}
|
|
|
490 |
fprintf(prn_stream, "\033*b%dV", clen[0]);
|
|
|
491 |
fwrite(cdata[0], sizeof(byte), clen[0], prn_stream);
|
|
|
492 |
fprintf(prn_stream, "\033*b%dV", clen[1]);
|
|
|
493 |
fwrite(cdata[1], sizeof(byte), clen[1], prn_stream);
|
|
|
494 |
fprintf(prn_stream, "\033*b%dW", clen[2]);
|
|
|
495 |
fwrite(cdata[2], sizeof(byte), clen[2], prn_stream);
|
|
|
496 |
}
|
|
|
497 |
}
|
|
|
498 |
|
|
|
499 |
/* PCL will take care of blank lines at the end */
|
|
|
500 |
fputs("\033*rC\f", prn_stream);
|
|
|
501 |
|
|
|
502 |
/* free the buffers used */
|
|
|
503 |
gs_free_object(mem, cdata[0], "clj_print_page(cdata)");
|
|
|
504 |
gs_free_object(mem, data, "clj_print_page(data)");
|
|
|
505 |
|
|
|
506 |
return 0;
|
|
|
507 |
}
|
|
|
508 |
|
|
|
509 |
/* CLJ device methods */
|
|
|
510 |
#define CLJ_PROCS(get_params, put_params)\
|
|
|
511 |
gdev_prn_open, /* open_device */\
|
|
|
512 |
clj_get_initial_matrix, /* get_initial matrix */\
|
|
|
513 |
NULL, /* sync_output */\
|
|
|
514 |
gdev_prn_output_page, /* output_page */\
|
|
|
515 |
gdev_prn_close, /* close_device */\
|
|
|
516 |
gdev_pcl_3bit_map_rgb_color, /* map_rgb_color */\
|
|
|
517 |
gdev_pcl_3bit_map_color_rgb, /* map_color_rgb */\
|
|
|
518 |
NULL, /* fill_rectangle */\
|
|
|
519 |
NULL, /* tile_rectangle */\
|
|
|
520 |
NULL, /* copy_mono */\
|
|
|
521 |
NULL, /* copy_color */\
|
|
|
522 |
NULL, /* obsolete draw_line */\
|
|
|
523 |
NULL, /* get_bits */\
|
|
|
524 |
get_params, /* get_params */\
|
|
|
525 |
put_params, /* put_params */\
|
|
|
526 |
NULL, /* map_cmyk_color */\
|
|
|
527 |
NULL, /* get_xfont_procs */\
|
|
|
528 |
NULL, /* get_xfont_device */\
|
|
|
529 |
NULL, /* map_rgb_alpha_color */\
|
|
|
530 |
gx_page_device_get_page_device /* get_page_device */
|
|
|
531 |
|
|
|
532 |
private gx_device_procs cljet5_procs = {
|
|
|
533 |
CLJ_PROCS(clj_get_params, clj_put_params)
|
|
|
534 |
};
|
|
|
535 |
|
|
|
536 |
/* CLJ device structure */
|
|
|
537 |
#define CLJ_DEVICE_BODY(procs, dname, rotated)\
|
|
|
538 |
prn_device_body(\
|
|
|
539 |
gx_device_clj,\
|
|
|
540 |
procs, /* procedures */\
|
|
|
541 |
dname, /* device name */\
|
|
|
542 |
110, /* width - will be overridden subsequently */\
|
|
|
543 |
85, /* height - will be overridden subsequently */\
|
|
|
544 |
X_DPI, Y_DPI, /* resolutions - current must be the same */\
|
|
|
545 |
0.167, 0.167, /* margins (left, bottom, right, top */\
|
|
|
546 |
0.167, 0.167,\
|
|
|
547 |
3, /* num_components - 3 colors, 1 bit per pixel */\
|
|
|
548 |
8, /* depth - pack into bytes */\
|
|
|
549 |
1, 1, /* max_gray=max_component=1 */\
|
|
|
550 |
2, 2, /* dithered_grays=dithered_components=2 */ \
|
|
|
551 |
clj_print_page /* routine to output page */\
|
|
|
552 |
),\
|
|
|
553 |
rotated /* rotated - may be overridden subsequently */
|
|
|
554 |
|
|
|
555 |
gx_device_clj gs_cljet5_device = {
|
|
|
556 |
CLJ_DEVICE_BODY(cljet5_procs, "cljet5", 0 /*false*/)
|
|
|
557 |
};
|
|
|
558 |
|
|
|
559 |
/* ---------------- Driver with page rotation ---------------- */
|
|
|
560 |
|
|
|
561 |
/*
|
|
|
562 |
* For use with certain PCL interpreters, which don't implement
|
|
|
563 |
* setpagedevice, we provide a version of this driver that attempts to
|
|
|
564 |
* handle page rotation at the driver level. This version breaks an
|
|
|
565 |
* invariant that all drivers must obey, namely, that drivers are not
|
|
|
566 |
* allowed to change the parameters passed by put_params (they can only
|
|
|
567 |
* accept or reject them). Consequently, this driver must not be used in
|
|
|
568 |
* any context other than these specific PCL interpreters. We support this
|
|
|
569 |
* hack only because these PCL interpreters can't be changed to handle page
|
|
|
570 |
* rotation properly.
|
|
|
571 |
*/
|
|
|
572 |
|
|
|
573 |
/*
|
|
|
574 |
* Special get_params routine, to fake MediaSize, width, and height if
|
|
|
575 |
* we were in a 'rotated' state.
|
|
|
576 |
*/
|
|
|
577 |
private int
|
|
|
578 |
clj_pr_get_params( gx_device *pdev, gs_param_list *plist )
|
|
|
579 |
{
|
|
|
580 |
int code;
|
|
|
581 |
|
|
|
582 |
/* First un-rotate the MediaSize, etc. if we were in a rotated mode */
|
|
|
583 |
if (pclj->rotated) {
|
|
|
584 |
float ftmp;
|
|
|
585 |
int itmp;
|
|
|
586 |
|
|
|
587 |
ftmp = pdev->MediaSize[0];
|
|
|
588 |
pdev->MediaSize[0] = pdev->MediaSize[1];
|
|
|
589 |
pdev->MediaSize[1] = ftmp;
|
|
|
590 |
itmp = pdev->width;
|
|
|
591 |
pdev->width = pdev->height;
|
|
|
592 |
pdev->height = itmp;
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
/* process the parameter list */
|
|
|
596 |
code = gdev_prn_get_params(pdev, plist);
|
|
|
597 |
|
|
|
598 |
/* Now re-rotate the page size if needed */
|
|
|
599 |
if (pclj->rotated) {
|
|
|
600 |
float ftmp;
|
|
|
601 |
int itmp;
|
|
|
602 |
|
|
|
603 |
ftmp = pdev->MediaSize[0];
|
|
|
604 |
pdev->MediaSize[0] = pdev->MediaSize[1];
|
|
|
605 |
pdev->MediaSize[1] = ftmp;
|
|
|
606 |
itmp = pdev->width;
|
|
|
607 |
pdev->width = pdev->height;
|
|
|
608 |
pdev->height = itmp;
|
|
|
609 |
}
|
|
|
610 |
|
|
|
611 |
return code;
|
|
|
612 |
}
|
|
|
613 |
|
|
|
614 |
/*
|
|
|
615 |
* Special put_params routine, to intercept changes in the MediaSize, and to
|
|
|
616 |
* make certain the desired MediaSize and HWResolution are supported.
|
|
|
617 |
*
|
|
|
618 |
* This function will rotate MediaSize if it is needed by the device in
|
|
|
619 |
* order to print this size page.
|
|
|
620 |
*/
|
|
|
621 |
private int
|
|
|
622 |
clj_pr_put_params(
|
|
|
623 |
gx_device * pdev,
|
|
|
624 |
gs_param_list * plist
|
|
|
625 |
)
|
|
|
626 |
{
|
|
|
627 |
float mediasize[2];
|
|
|
628 |
int code = 0;
|
|
|
629 |
bool rotate = false;
|
|
|
630 |
int have_pagesize = clj_media_size(mediasize, plist);
|
|
|
631 |
|
|
|
632 |
if (have_pagesize < 0)
|
|
|
633 |
return have_pagesize;
|
|
|
634 |
if (have_pagesize) {
|
|
|
635 |
if (get_paper_size(mediasize, &rotate) == 0)
|
|
|
636 |
return_error(gs_error_rangecheck);
|
|
|
637 |
if (rotate) {
|
|
|
638 |
/* We need to rotate the requested page size, so synthesize a new */
|
|
|
639 |
/* parameter list in front of the requestor's list to force the */
|
|
|
640 |
/* rotated page size. */
|
|
|
641 |
gs_param_float_array pf_array;
|
|
|
642 |
gs_c_param_list alist;
|
|
|
643 |
float ftmp = mediasize[0];
|
|
|
644 |
|
|
|
645 |
mediasize[0] = mediasize[1];
|
|
|
646 |
mediasize[1] = ftmp;
|
|
|
647 |
pf_array.data = mediasize;
|
|
|
648 |
pf_array.size = 2;
|
|
|
649 |
pf_array.persistent = false;
|
|
|
650 |
|
|
|
651 |
gs_c_param_list_write(&alist, pdev->memory);
|
|
|
652 |
code = param_write_float_array((gs_param_list *)&alist, ".MediaSize", &pf_array);
|
|
|
653 |
gs_c_param_list_read(&alist);
|
|
|
654 |
|
|
|
655 |
/* stick this synthesized parameter on the front of the existing list */
|
|
|
656 |
gs_c_param_list_set_target(&alist, plist);
|
|
|
657 |
if ((code = gdev_prn_put_params(pdev, (gs_param_list *)&alist)) >= 0)
|
|
|
658 |
pclj->rotated = true;
|
|
|
659 |
gs_c_param_list_release(&alist);
|
|
|
660 |
} else {
|
|
|
661 |
if ((code = gdev_prn_put_params(pdev, plist)) >= 0)
|
|
|
662 |
pclj->rotated = false;
|
|
|
663 |
}
|
|
|
664 |
} else
|
|
|
665 |
code = gdev_prn_put_params(pdev, plist);
|
|
|
666 |
|
|
|
667 |
return code;
|
|
|
668 |
}
|
|
|
669 |
|
|
|
670 |
/* CLJ device methods -- se above for CLJ_PROCS */
|
|
|
671 |
private gx_device_procs cljet5pr_procs = {
|
|
|
672 |
CLJ_PROCS(clj_pr_get_params, clj_pr_put_params)
|
|
|
673 |
};
|
|
|
674 |
|
|
|
675 |
/* CLJ device structure -- see above for CLJ_DEVICE_BODY */
|
|
|
676 |
gx_device_clj gs_cljet5pr_device = {
|
|
|
677 |
CLJ_DEVICE_BODY(cljet5pr_procs, "cljet5pr", 1 /*true*/)
|
|
|
678 |
};
|