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