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