1 /* Copyright (C) 1989, 2000 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: gdevdjet.c,v 1.13 2005/04/07 09:12:15 igor Exp $ */
18 /* HP LaserJet/DeskJet driver for Ghostscript */
19 #include "gdevprn.h"
20 #include "gdevdljm.h"
21
22 /*
23 * Thanks for various improvements to:
24 * Jim Mayer (mayer@wrc.xerox.com)
25 * Jan-Mark Wams (jms@cs.vu.nl)
26 * Frans van Hoesel (hoesel@chem.rug.nl)
27 * George Cameron (g.cameron@biomed.abdn.ac.uk)
28 * Nick Duffek (nsd@bbc.com)
29 * Thanks for the FS-600 driver to:
30 * Peter Schildmann (peter.schildmann@etechnik.uni-rostock.de)
31 * Thanks for the LJIIID duplex capability to:
32 * PDP (Philip) Brown (phil@3soft-uk.com)
33 * Thanks for the OCE 9050 driver to:
34 * William Bader (wbader@EECS.Lehigh.Edu)
35 * Thanks for the LJ4D duplex capability to:
36 * Les Johnson <les@infolabs.com>
37 */
38
39 /*
40 * You may select a default resolution of 75, 100, 150, 300, or
41 * (LJ4 only) 600 DPI in the makefile, or an actual resolution
42 * on the gs command line.
43 *
44 * If the preprocessor symbol A4 is defined, the default paper size is
45 * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
46 *
47 * To determine the proper "margin" settings for your printer, see the
48 * file align.ps.
49 */
50
51 /* Define the default, maximum resolutions. */
52 #ifdef X_DPI
53 # define X_DPI2 X_DPI
54 #else
55 # define X_DPI 300
56 # define X_DPI2 600
57 #endif
58 #ifdef Y_DPI
59 # define Y_DPI2 Y_DPI
60 #else
61 # define Y_DPI 300
62 # define Y_DPI2 600
63 #endif
64
65 /*
66 * For all DeskJet Printers:
67 *
68 * Maximum printing width = 2400 dots = 8"
69 * Maximum recommended printing height = 3100 dots = 10 1/3"
70 *
71 * All Deskjets have 1/2" unprintable bottom margin.
72 * The recommendation comes from the HP Software Developer's Guide for
73 * the DeskJet 500, DeskJet PLUS, and DeskJet printers, version C.01.00
74 * of 12/1/90.
75 *
76 * Note that the margins defined just below here apply only to the DeskJet;
77 * the paper size, width and height apply to the LaserJet as well.
78 */
79
80 /* Margins are left, bottom, right, top. */
81 /* from Frans van Hoesel hoesel@rugr86.rug.nl. */
82 /* A4 has a left margin of 1/8 inch and at a printing width of
83 * 8 inch this give a right margin of 0.143. The 0.09 top margin is
84 * not the actual margin - which is 0.07 - but compensates for the
85 * inexact paperlength which is set to 117 10ths.
86 * Somebody should check for letter sized paper. I left it at 0.07".
87 */
88 #define DESKJET_MARGINS_LETTER (float)0.2, (float)0.45, (float)0.3, (float)0.05
89 #define DESKJET_MARGINS_A4 (float)0.125, (float)0.5, (float)0.143, (float)0.09
90 /* Similar margins for the LaserJet. */
91 /* These are defined in the PCL 5 Technical Reference Manual. */
92 /* Note that for PCL 5 printers, we get the printer to translate the */
93 /* coordinate system: the margins only define the unprintable area. */
94 #define LASERJET_MARGINS_A4 (float)0.167, (float)0.167, (float)0.167, (float)0.167
95 #define LASERJET_MARGINS_LETTER (float)0.167, (float)0.167, (float)0.167, (float)0.167
96
97 /* See gdevdljm.h for the definitions of the PCL_ features. */
98
99 /* The device descriptors */
100 private dev_proc_open_device(hpjet_open);
101 private dev_proc_close_device(hpjet_close);
102 private dev_proc_print_page_copies(djet_print_page_copies);
103 private dev_proc_print_page_copies(djet500_print_page_copies);
104 private dev_proc_print_page_copies(fs600_print_page_copies);
105 private dev_proc_print_page_copies(ljet_print_page_copies);
106 private dev_proc_print_page_copies(ljetplus_print_page_copies);
107 private dev_proc_print_page_copies(ljet2p_print_page_copies);
108 private dev_proc_print_page_copies(ljet3_print_page_copies);
109 private dev_proc_print_page_copies(ljet3d_print_page_copies);
110 private dev_proc_print_page_copies(ljet4_print_page_copies);
111 private dev_proc_print_page_copies(ljet4d_print_page_copies);
112 private dev_proc_print_page_copies(lp2563_print_page_copies);
113 private dev_proc_print_page_copies(oce9050_print_page_copies);
114 private dev_proc_get_params(hpjet_get_params);
115 private dev_proc_put_params(hpjet_put_params);
116
117 private const gx_device_procs prn_hp_procs =
118 prn_params_procs(hpjet_open, gdev_prn_output_page, hpjet_close,
119 hpjet_get_params, hpjet_put_params);
120
121 typedef struct gx_device_hpjet_s gx_device_hpjet;
122
123 struct gx_device_hpjet_s {
124 gx_device_common;
125 gx_prn_device_common;
126 int MediaPosition;
127 bool MediaPosition_set;
128 bool ManualFeed;
129 bool ManualFeed_set;
130 };
131
132 #define HPJET_DEVICE(procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page_copies)\
133 { prn_device_std_margins_body_copies(gx_device_hpjet, procs, dname, \
134 w10, h10, xdpi, ydpi, lm, tm, lm, bm, rm, tm, color_bits, \
135 print_page_copies), \
136 0, false, false, false }
137
138 const gx_device_hpjet gs_deskjet_device =
139 HPJET_DEVICE(prn_hp_procs, "deskjet",
140 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
141 X_DPI, Y_DPI,
142 0, 0, 0, 0, /* margins filled in by hpjet_open */
143 1, djet_print_page_copies);
144
145 const gx_device_hpjet gs_djet500_device =
146 HPJET_DEVICE(prn_hp_procs, "djet500",
147 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
148 X_DPI, Y_DPI,
149 0, 0, 0, 0, /* margins filled in by hpjet_open */
150 1, djet500_print_page_copies);
151
152 const gx_device_hpjet gs_fs600_device =
153 HPJET_DEVICE(prn_hp_procs, "fs600",
154 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
155 X_DPI2, Y_DPI2,
156 0.23, 0.0, 0.23, 0.04, /* margins */
157 1, fs600_print_page_copies);
158
159 const gx_device_hpjet gs_laserjet_device =
160 HPJET_DEVICE(prn_hp_procs, "laserjet",
161 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
162 X_DPI, Y_DPI,
163 0.05, 0.25, 0.55, 0.25, /* margins */
164 1, ljet_print_page_copies);
165
166 const gx_device_hpjet gs_ljetplus_device =
167 HPJET_DEVICE(prn_hp_procs, "ljetplus",
168 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
169 X_DPI, Y_DPI,
170 0.05, 0.25, 0.55, 0.25, /* margins */
171 1, ljetplus_print_page_copies);
172
173 const gx_device_hpjet gs_ljet2p_device =
174 HPJET_DEVICE(prn_hp_procs, "ljet2p",
175 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
176 X_DPI, Y_DPI,
177 0.20, 0.25, 0.25, 0.25, /* margins */
178 1, ljet2p_print_page_copies);
179
180 const gx_device_hpjet gs_ljet3_device =
181 HPJET_DEVICE(prn_hp_procs, "ljet3",
182 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
183 X_DPI, Y_DPI,
184 0.20, 0.25, 0.25, 0.25, /* margins */
185 1, ljet3_print_page_copies);
186
187 const gx_device_hpjet gs_ljet3d_device =
188 HPJET_DEVICE(prn_hp_procs, "ljet3d",
189 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
190 X_DPI, Y_DPI,
191 0.20, 0.25, 0.25, 0.25, /* margins */
192 1, ljet3d_print_page_copies);
193
194 const gx_device_hpjet gs_ljet4_device =
195 HPJET_DEVICE(prn_hp_procs, "ljet4",
196 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
197 X_DPI2, Y_DPI2,
198 0, 0, 0, 0, /* margins */
199 1, ljet4_print_page_copies);
200
201 const gx_device_hpjet gs_ljet4d_device =
202 HPJET_DEVICE(prn_hp_procs, "ljet4d",
203 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
204 X_DPI2, Y_DPI2,
205 0, 0, 0, 0, /* margins */
206 1, ljet4d_print_page_copies);
207
208 const gx_device_hpjet gs_lp2563_device =
209 HPJET_DEVICE(prn_hp_procs, "lp2563",
210 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
211 X_DPI, Y_DPI,
212 0, 0, 0, 0, /* margins */
213 1, lp2563_print_page_copies);
214
215 const gx_device_hpjet gs_oce9050_device =
216 HPJET_DEVICE(prn_hp_procs, "oce9050",
217 24 * 10, 24 * 10, /* 24 inch roll (can print 32" also) */
218 400, 400, /* 400 dpi */
219 0, 0, 0, 0, /* margins */
220 1, oce9050_print_page_copies);
221
222 /* Open the printer, adjusting the margins if necessary. */
223 private int
hpjet_open(gx_device * pdev)224 hpjet_open(gx_device * pdev)
225 { /* Change the margins if necessary. */
226 gx_device_printer *const ppdev = (gx_device_printer *)pdev;
227 const float *m = 0;
228 bool move_origin = true;
229
230 if (ppdev->printer_procs.print_page_copies == djet_print_page_copies ||
231 ppdev->printer_procs.print_page_copies == djet500_print_page_copies
232 ) {
233 static const float m_a4[4] =
234 {DESKJET_MARGINS_A4};
235 static const float m_letter[4] =
236 {DESKJET_MARGINS_LETTER};
237
238 m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
239 m_letter);
240 } else if (ppdev->printer_procs.print_page_copies == oce9050_print_page_copies ||
241 ppdev->printer_procs.print_page_copies == lp2563_print_page_copies
242 );
243 else { /* LaserJet */
244 static const float m_a4[4] =
245 {LASERJET_MARGINS_A4};
246 static const float m_letter[4] =
247 {LASERJET_MARGINS_LETTER};
248
249 m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
250 m_letter);
251 move_origin = false;
252 }
253 if (m != 0)
254 gx_device_set_margins(pdev, m, move_origin);
255 /* If this is a LJIIID, enable Duplex. */
256 if (ppdev->printer_procs.print_page_copies == ljet3d_print_page_copies)
257 ppdev->Duplex = true, ppdev->Duplex_set = 0;
258 if (ppdev->printer_procs.print_page_copies == ljet4d_print_page_copies)
259 ppdev->Duplex = true, ppdev->Duplex_set = 0;
260 return gdev_prn_open(pdev);
261 }
262
263 /* hpjet_close is only here to eject odd numbered pages in duplex mode, */
264 /* and to reset the printer so the ink cartridge doesn't clog up. */
265 private int
hpjet_close(gx_device * pdev)266 hpjet_close(gx_device * pdev)
267 {
268 gx_device_printer *const ppdev = (gx_device_printer *)pdev;
269 int code = gdev_prn_open_printer(pdev, 1);
270
271 if (code < 0)
272 return code;
273 if (ppdev->PageCount > 0) {
274 if (ppdev->Duplex_set >= 0 && ppdev->Duplex)
275 fputs("\033&l0H", ppdev->file);
276
277 fputs("\033E", ppdev->file);
278 }
279
280 return gdev_prn_close(pdev);
281 }
282
283 /* ------ Internal routines ------ */
284
285 /* Make an init string that contains paper tray selection. The resulting
286 init string is stored in buf, so make sure that buf is at least 5
287 bytes larger than str. */
288 private void
hpjet_make_init(gx_device_printer * pdev,char * buf,const char * str)289 hpjet_make_init(gx_device_printer *pdev, char *buf, const char *str)
290 {
291 gx_device_hpjet *dev = (gx_device_hpjet *)pdev;
292 int paper_source = -1;
293 int paper_source_tab[] = { 5, 1 };
294
295 if (dev->ManualFeed_set && dev->ManualFeed) paper_source = 2;
296 else if (dev->MediaPosition_set && dev->MediaPosition >= 0 &&
297 dev->MediaPosition < countof(paper_source_tab))
298 paper_source = paper_source_tab[dev->MediaPosition];
299 if (paper_source >= 0)
300 sprintf(buf, "%s\033&l%dH", str, paper_source);
301 else
302 sprintf(buf, "%s", str);
303 }
304
305 /* The DeskJet can compress (mode 2) */
306 private int
djet_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)307 djet_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
308 int num_copies)
309 {
310 char init[80];
311
312 hpjet_make_init(pdev, init, "\033&k1W\033*b2M");
313 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
314 300, PCL_DJ_FEATURES, init);
315 }
316 /* The DeskJet500 can compress (modes 2&3) */
317 private int
djet500_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)318 djet500_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
319 int num_copies)
320 {
321 char init[80];
322
323 hpjet_make_init(pdev, init, "\033&k1W");
324 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
325 300, PCL_DJ500_FEATURES, init);
326 }
327 /* The Kyocera FS-600 laser printer (and perhaps other printers */
328 /* which use the PeerlessPrint5 firmware) doesn't handle */
329 /* ESC&l#u and ESC&l#Z correctly. */
330 private int
fs600_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)331 fs600_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
332 int num_copies)
333 {
334 int dots_per_inch = (int)pdev->y_pixels_per_inch;
335 char base_init[60];
336 char init[80];
337
338 sprintf(base_init, "\033*r0F\033&u%dD", dots_per_inch);
339 hpjet_make_init(pdev, init, base_init);
340 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
341 dots_per_inch, PCL_FS600_FEATURES,
342 init);
343 }
344 /* The LaserJet series II can't compress */
345 private int
ljet_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)346 ljet_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
347 int num_copies)
348 {
349 char init[80];
350
351 hpjet_make_init(pdev, init, "\033*b0M");
352 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
353 300, PCL_LJ_FEATURES, init);
354 }
355 /* The LaserJet Plus can't compress */
356 private int
ljetplus_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)357 ljetplus_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
358 int num_copies)
359 {
360 char init[80];
361
362 hpjet_make_init(pdev, init, "\033*b0M");
363 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
364 300, PCL_LJplus_FEATURES, init);
365 }
366 /* LaserJet series IIp & IId compress (mode 2) */
367 /* but don't support *p+ or *b vertical spacing. */
368 private int
ljet2p_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)369 ljet2p_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
370 int num_copies)
371 {
372 char init[80];
373
374 hpjet_make_init(pdev, init, "\033*r0F\033*b2M");
375 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
376 300, PCL_LJ2p_FEATURES, init);
377 }
378 /* All LaserJet series IIIs (III,IIId,IIIp,IIIsi) compress (modes 2&3) */
379 /* They also need their coordinate system translated slightly. */
380 private int
ljet3_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)381 ljet3_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
382 int num_copies)
383 {
384 char init[80];
385
386 hpjet_make_init(pdev, init, "\033&l-180u36Z\033*r0F");
387 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
388 300, PCL_LJ3_FEATURES, init);
389 }
390 /* LaserJet IIId is same as LaserJet III, except for duplex */
391 private int
ljet3d_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)392 ljet3d_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
393 int num_copies)
394 {
395 char init[80];
396
397 hpjet_make_init(pdev, init, "\033&l-180u36Z\033*r0F");
398 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
399 300, PCL_LJ3D_FEATURES, init);
400 }
401 /* LaserJet 4 series compresses, and it needs a special sequence to */
402 /* allow it to specify coordinates at 600 dpi. */
403 /* It too needs its coordinate system translated slightly. */
404 private int
ljet4_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)405 ljet4_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
406 int num_copies)
407 {
408 int dots_per_inch = (int)pdev->y_pixels_per_inch;
409 char base_init[60];
410 char init[80];
411
412 sprintf(base_init, "\033&l-180u36Z\033*r0F\033&u%dD", dots_per_inch);
413 hpjet_make_init(pdev, init, base_init);
414 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
415 dots_per_inch, PCL_LJ4_FEATURES,
416 init);
417 }
418 private int
ljet4d_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)419 ljet4d_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
420 int num_copies)
421 {
422 int dots_per_inch = (int)pdev->y_pixels_per_inch;
423 char base_init[60];
424 char init[80];
425
426 sprintf(base_init, "\033&l-180u36Z\033*r0F\033&u%dD", dots_per_inch);
427 hpjet_make_init(pdev, init, base_init);
428 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
429 dots_per_inch, PCL_LJ4D_FEATURES,
430 init);
431 }
432 /* The 2563B line printer can't compress */
433 /* and doesn't support *p+ or *b vertical spacing. */
434 private int
lp2563_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)435 lp2563_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
436 int num_copies)
437 {
438 char init[80];
439
440 hpjet_make_init(pdev, init, "\033*b0M");
441 return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
442 300, PCL_LP2563B_FEATURES, init);
443 }
444 /* The Oce line printer has TIFF compression */
445 /* and doesn't support *p+ or *b vertical spacing. */
446 private int
oce9050_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)447 oce9050_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
448 int num_copies)
449 {
450 int code;
451 char init[80];
452
453 /* Switch to HP_RTL. */
454 fputs("\033%1B", prn_stream); /* Enter HPGL/2 mode */
455 fputs("BP", prn_stream); /* Begin Plot */
456 fputs("IN;", prn_stream); /* Initialize (start plot) */
457 fputs("\033%1A", prn_stream); /* Enter PCL mode */
458
459 hpjet_make_init(pdev, init, "\033*b0M");
460
461 code = dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
462 400, PCL_OCE9050_FEATURES, init);
463
464 /* Return to HPGL/2 mode. */
465 fputs("\033%1B", prn_stream); /* Enter HPGL/2 mode */
466 if (code == 0) {
467 fputs("PU", prn_stream); /* Pen Up */
468 fputs("SP0", prn_stream); /* Pen Select */
469 fputs("PG;", prn_stream); /* Advance Full Page */
470 fputs("\033E", prn_stream); /* Reset */
471 }
472 return code;
473 }
474
475 private int
hpjet_get_params(gx_device * pdev,gs_param_list * plist)476 hpjet_get_params(gx_device *pdev, gs_param_list *plist)
477 {
478 gx_device_hpjet *dev = (gx_device_hpjet *)pdev;
479 int code = gdev_prn_get_params(pdev, plist);
480
481 if (code >= 0)
482 code = param_write_bool(plist, "ManualFeed", &dev->ManualFeed);
483 return code;
484 }
485
486 private int
hpjet_put_params(gx_device * pdev,gs_param_list * plist)487 hpjet_put_params(gx_device *pdev, gs_param_list *plist)
488 {
489 gx_device_hpjet *dev = (gx_device_hpjet *)pdev;
490 int code;
491 bool ManualFeed;
492 bool ManualFeed_set = false;
493 int MediaPosition;
494 bool MediaPosition_set = false;
495
496 code = param_read_bool(plist, "ManualFeed", &ManualFeed);
497 if (code == 0) ManualFeed_set = true;
498 if (code >= 0) {
499 code = param_read_int(plist, "%MediaSource", &MediaPosition);
500 if (code == 0) MediaPosition_set = true;
501 else if (code < 0) {
502 if (param_read_null(plist, "%MediaSource") == 0) {
503 code = 0;
504 }
505 }
506 }
507
508 if (code >= 0)
509 code = gdev_prn_put_params(pdev, plist);
510
511 if (code >= 0) {
512 if (ManualFeed_set) {
513 dev->ManualFeed = ManualFeed;
514 dev->ManualFeed_set = true;
515 }
516 if (MediaPosition_set) {
517 dev->MediaPosition = MediaPosition;
518 dev->MediaPosition_set = true;
519 }
520 }
521
522 return code;
523 }
524