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
is_supported_resolution(const float HWResolution[2])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 *
get_paper_size(const float MediaSize[2],bool * rotatep)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
clj_get_initial_matrix(gx_device * pdev,gs_matrix * pmat)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
clj_get_params(gx_device * pdev,gs_param_list * plist)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
clj_media_size(float mediasize[2],gs_param_list * plist)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
clj_put_params(gx_device * pdev,gs_param_list * plist)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
pack_and_compress_scanline(const byte * pin,int in_size,byte * pout[3],int out_size[3])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
clj_print_page(gx_device_printer * pdev,FILE * prn_stream)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
clj_pr_get_params(gx_device * pdev,gs_param_list * plist)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
clj_pr_put_params(gx_device * pdev,gs_param_list * plist)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 };
679