1 /* Copyright (C) 1989, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16  */
17 
18 /*$Id: gdevdjet.c,v 1.6.8.1 2003/01/17 00:49:00 giles Exp $ */
19 /* HP LaserJet/DeskJet driver for Ghostscript */
20 #include "gdevprn.h"
21 #include "gdevdljm.h"
22 
23 /*
24  * Thanks for various improvements to:
25  *      Jim Mayer (mayer@wrc.xerox.com)
26  *      Jan-Mark Wams (jms@cs.vu.nl)
27  *      Frans van Hoesel (hoesel@chem.rug.nl)
28  *      George Cameron (g.cameron@biomed.abdn.ac.uk)
29  *      Nick Duffek (nsd@bbc.com)
30  * Thanks for the FS-600 driver to:
31  *	Peter Schildmann (peter.schildmann@etechnik.uni-rostock.de)
32  * Thanks for the LJIIID duplex capability to:
33  *      PDP (Philip) Brown (phil@3soft-uk.com)
34  * Thanks for the OCE 9050 driver to:
35  *      William Bader (wbader@EECS.Lehigh.Edu)
36  * Thanks for the LJ4D duplex capability to:
37  *	Les Johnson <les@infolabs.com>
38  */
39 
40 /*
41  * You may select a default resolution of 75, 100, 150, 300, or
42  * (LJ4 only) 600 DPI in the makefile, or an actual resolution
43  * on the gs command line.
44  *
45  * If the preprocessor symbol A4 is defined, the default paper size is
46  * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
47  *
48  * To determine the proper "margin" settings for your printer, see the
49  * file align.ps.
50  */
51 
52 /* Define the default, maximum resolutions. */
53 #ifdef X_DPI
54 #  define X_DPI2 X_DPI
55 #else
56 #  define X_DPI 300
57 #  define X_DPI2 600
58 #endif
59 #ifdef Y_DPI
60 #  define Y_DPI2 Y_DPI
61 #else
62 #  define Y_DPI 300
63 #  define Y_DPI2 600
64 #endif
65 
66 /*
67  * For all DeskJet Printers:
68  *
69  *  Maximum printing width               = 2400 dots = 8"
70  *  Maximum recommended printing height  = 3100 dots = 10 1/3"
71  *
72  * All Deskjets have 1/2" unprintable bottom margin.
73  * The recommendation comes from the HP Software Developer's Guide for
74  * the DeskJet 500, DeskJet PLUS, and DeskJet printers, version C.01.00
75  * of 12/1/90.
76  *
77  * Note that the margins defined just below here apply only to the DeskJet;
78  * the paper size, width and height apply to the LaserJet as well.
79  */
80 
81 /* Margins are left, bottom, right, top. */
82 /* from Frans van Hoesel hoesel@rugr86.rug.nl. */
83 /* A4 has a left margin of 1/8 inch and at a printing width of
84  * 8 inch this give a right margin of 0.143. The 0.09 top margin is
85  * not the actual margin - which is 0.07 - but compensates for the
86  * inexact paperlength which is set to 117 10ths.
87  * Somebody should check for letter sized paper. I left it at 0.07".
88  */
89 #define DESKJET_MARGINS_LETTER  0.2, 0.45, 0.3, 0.05
90 #define DESKJET_MARGINS_A4	0.125, 0.5, 0.143, 0.09
91 /* Similar margins for the LaserJet. */
92 /* These are defined in the PCL 5 Technical Reference Manual. */
93 /* Note that for PCL 5 printers, we get the printer to translate the */
94 /* coordinate system: the margins only define the unprintable area. */
95 #define LASERJET_MARGINS_A4	0.167, 0.167, 0.167, 0.167
96 #define LASERJET_MARGINS_LETTER	0.167, 0.167, 0.167, 0.167
97 
98 /* See gdevdljm.h for the definitions of the PCL_ features. */
99 
100 /* The device descriptors */
101 private dev_proc_open_device(hpjet_open);
102 private dev_proc_close_device(hpjet_close);
103 private dev_proc_print_page_copies(djet_print_page_copies);
104 private dev_proc_print_page_copies(djet500_print_page_copies);
105 private dev_proc_print_page_copies(fs600_print_page_copies);
106 private dev_proc_print_page_copies(ljet_print_page_copies);
107 private dev_proc_print_page_copies(ljetplus_print_page_copies);
108 private dev_proc_print_page_copies(ljet2p_print_page_copies);
109 private dev_proc_print_page_copies(ljet3_print_page_copies);
110 private dev_proc_print_page_copies(ljet3d_print_page_copies);
111 private dev_proc_print_page_copies(ljet4_print_page_copies);
112 private dev_proc_print_page_copies(ljet4d_print_page_copies);
113 private dev_proc_print_page_copies(lp2563_print_page_copies);
114 private dev_proc_print_page_copies(oce9050_print_page_copies);
115 
116 private const gx_device_procs prn_hp_procs =
117 prn_params_procs(hpjet_open, gdev_prn_output_page, hpjet_close,
118 		 gdev_prn_get_params, gdev_prn_put_params);
119 
120 const gx_device_printer gs_deskjet_device =
121 prn_device_copies(prn_hp_procs, "deskjet",
122 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
123 		  X_DPI, Y_DPI,
124 		  0, 0, 0, 0,		/* margins filled in by hpjet_open */
125 		  1, djet_print_page_copies);
126 
127 const gx_device_printer gs_djet500_device =
128 prn_device_copies(prn_hp_procs, "djet500",
129 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
130 		  X_DPI, Y_DPI,
131 		  0, 0, 0, 0,		/* margins filled in by hpjet_open */
132 		  1, djet500_print_page_copies);
133 
134 const gx_device_printer gs_fs600_device =
135 prn_device_copies(prn_hp_procs, "fs600",
136 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
137 		  X_DPI2, Y_DPI2,
138 		  0.23, 0.0, 0.23, 0.04,      /* margins */
139 		  1, fs600_print_page_copies);
140 
141 const gx_device_printer gs_laserjet_device =
142 prn_device_copies(prn_hp_procs, "laserjet",
143 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
144 		  X_DPI, Y_DPI,
145 		  0.05, 0.25, 0.55, 0.25,	/* margins */
146 		  1, ljet_print_page_copies);
147 
148 const gx_device_printer gs_ljetplus_device =
149 prn_device_copies(prn_hp_procs, "ljetplus",
150 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
151 		  X_DPI, Y_DPI,
152 		  0.05, 0.25, 0.55, 0.25,	/* margins */
153 		  1, ljetplus_print_page_copies);
154 
155 const gx_device_printer gs_ljet2p_device =
156 prn_device_copies(prn_hp_procs, "ljet2p",
157 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
158 		  X_DPI, Y_DPI,
159 		  0.20, 0.25, 0.25, 0.25,	/* margins */
160 		  1, ljet2p_print_page_copies);
161 
162 const gx_device_printer gs_ljet3_device =
163 prn_device_copies(prn_hp_procs, "ljet3",
164 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
165 		  X_DPI, Y_DPI,
166 		  0.20, 0.25, 0.25, 0.25,	/* margins */
167 		  1, ljet3_print_page_copies);
168 
169 const gx_device_printer gs_ljet3d_device =
170 prn_device_copies(prn_hp_procs, "ljet3d",
171 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
172 		  X_DPI, Y_DPI,
173 		  0.20, 0.25, 0.25, 0.25,	/* margins */
174 		  1, ljet3d_print_page_copies);
175 
176 const gx_device_printer gs_ljet4_device =
177 prn_device_copies(prn_hp_procs, "ljet4",
178 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
179 		  X_DPI2, Y_DPI2,
180 		  0, 0, 0, 0,		/* margins */
181 		  1, ljet4_print_page_copies);
182 
183 const gx_device_printer gs_ljet4d_device =
184 prn_device_copies(prn_hp_procs, "ljet4d",
185 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
186 		  X_DPI2, Y_DPI2,
187 		  0, 0, 0, 0,		/* margins */
188 		  1, ljet4d_print_page_copies);
189 
190 const gx_device_printer gs_lp2563_device =
191 prn_device_copies(prn_hp_procs, "lp2563",
192 		  DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
193 		  X_DPI, Y_DPI,
194 		  0, 0, 0, 0,		/* margins */
195 		  1, lp2563_print_page_copies);
196 
197 const gx_device_printer gs_oce9050_device =
198 prn_device_copies(prn_hp_procs, "oce9050",
199 		  24 * 10, 24 * 10,	/* 24 inch roll (can print 32" also) */
200 		  400, 400,		/* 400 dpi */
201 		  0, 0, 0, 0,		/* margins */
202 		  1, oce9050_print_page_copies);
203 
204 /* Open the printer, adjusting the margins if necessary. */
205 private int
hpjet_open(gx_device * pdev)206 hpjet_open(gx_device * pdev)
207 {				/* Change the margins if necessary. */
208     gx_device_printer *const ppdev = (gx_device_printer *)pdev;
209     const float *m = 0;
210     bool move_origin = true;
211 
212     if (ppdev->printer_procs.print_page_copies == djet_print_page_copies ||
213 	ppdev->printer_procs.print_page_copies == djet500_print_page_copies
214 	) {
215 	static const float m_a4[4] =
216 	{DESKJET_MARGINS_A4};
217 	static const float m_letter[4] =
218 	{DESKJET_MARGINS_LETTER};
219 
220 	m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
221 	     m_letter);
222     } else if (ppdev->printer_procs.print_page_copies == oce9050_print_page_copies ||
223 	       ppdev->printer_procs.print_page_copies == lp2563_print_page_copies
224 	);
225     else {			/* LaserJet */
226 	static const float m_a4[4] =
227 	{LASERJET_MARGINS_A4};
228 	static const float m_letter[4] =
229 	{LASERJET_MARGINS_LETTER};
230 
231 	m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 :
232 	     m_letter);
233 	move_origin = false;
234     }
235     if (m != 0)
236 	gx_device_set_margins(pdev, m, move_origin);
237     /* If this is a LJIIID, enable Duplex. */
238     if (ppdev->printer_procs.print_page_copies == ljet3d_print_page_copies)
239 	ppdev->Duplex = true, ppdev->Duplex_set = 0;
240     if (ppdev->printer_procs.print_page_copies == ljet4d_print_page_copies)
241 	ppdev->Duplex = true, ppdev->Duplex_set = 0;
242     return gdev_prn_open(pdev);
243 }
244 
245 /* hpjet_close is only here to eject odd numbered pages in duplex mode, */
246 /* and to reset the printer so the ink cartridge doesn't clog up. */
247 private int
hpjet_close(gx_device * pdev)248 hpjet_close(gx_device * pdev)
249 {
250     gx_device_printer *const ppdev = (gx_device_printer *)pdev;
251     int code = gdev_prn_open_printer(pdev, 1);
252 
253     if (code < 0)
254 	return code;
255     if (ppdev->Duplex_set >= 0 && ppdev->Duplex)
256 	fputs("\033&l0H", ppdev->file);
257     fputs("\033E", ppdev->file);
258     return gdev_prn_close(pdev);
259 }
260 
261 /* ------ Internal routines ------ */
262 
263 /* The DeskJet can compress (mode 2) */
264 private int
djet_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)265 djet_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
266 		       int num_copies)
267 {
268     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
269 					300, PCL_DJ_FEATURES,
270 					"\033&k1W\033*b2M");
271 }
272 /* The DeskJet500 can compress (modes 2&3) */
273 private int
djet500_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)274 djet500_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
275 			  int num_copies)
276 {
277     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
278 					300, PCL_DJ500_FEATURES,
279 					"\033&k1W");
280 }
281 /* The Kyocera FS-600 laser printer (and perhaps other printers */
282 /* which use the PeerlessPrint5 firmware) doesn't handle        */
283 /* ESC&l#u and ESC&l#Z correctly.                               */
284 private int
fs600_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)285 fs600_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
286 			int num_copies)
287 {
288     int dots_per_inch = (int)pdev->y_pixels_per_inch;
289     char real_init[60];
290 
291     sprintf(real_init, "\033*r0F\033&u%dD", dots_per_inch);
292     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
293 					dots_per_inch, PCL_FS600_FEATURES,
294 					real_init);
295 }
296 /* The LaserJet series II can't compress */
297 private int
ljet_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)298 ljet_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
299 		       int num_copies)
300 {
301     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
302 					300, PCL_LJ_FEATURES,
303 					"\033*b0M");
304 }
305 /* The LaserJet Plus can't compress */
306 private int
ljetplus_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)307 ljetplus_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
308 			   int num_copies)
309 {
310     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
311 					300, PCL_LJplus_FEATURES,
312 					"\033*b0M");
313 }
314 /* LaserJet series IIp & IId compress (mode 2) */
315 /* but don't support *p+ or *b vertical spacing. */
316 private int
ljet2p_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)317 ljet2p_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
318 			 int num_copies)
319 {
320     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
321 					300, PCL_LJ2p_FEATURES,
322 					"\033*r0F\033*b2M");
323 }
324 /* All LaserJet series IIIs (III,IIId,IIIp,IIIsi) compress (modes 2&3) */
325 /* They also need their coordinate system translated slightly. */
326 private int
ljet3_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)327 ljet3_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
328 			int num_copies)
329 {
330     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
331 					300, PCL_LJ3_FEATURES,
332 					"\033&l-180u36Z\033*r0F");
333 }
334 /* LaserJet IIId is same as LaserJet III, except for duplex */
335 private int
ljet3d_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)336 ljet3d_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
337 			 int num_copies)
338 {
339     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
340 					300, PCL_LJ3D_FEATURES,
341 					"\033&l-180u36Z\033*r0F");
342 }
343 /* LaserJet 4 series compresses, and it needs a special sequence to */
344 /* allow it to specify coordinates at 600 dpi. */
345 /* It too needs its coordinate system translated slightly. */
346 private int
ljet4_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)347 ljet4_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
348 			int num_copies)
349 {
350     int dots_per_inch = (int)pdev->y_pixels_per_inch;
351     char real_init[60];
352 
353     sprintf(real_init, "\033&l-180u36Z\033*r0F\033&u%dD", dots_per_inch);
354     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
355 					dots_per_inch, PCL_LJ4_FEATURES,
356 					real_init);
357 }
358 private int
ljet4d_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)359 ljet4d_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
360 			 int num_copies)
361 {
362     int dots_per_inch = (int)pdev->y_pixels_per_inch;
363     char real_init[60];
364 
365     sprintf(real_init, "\033&l-180u36Z\033*r0F\033&u%dD", dots_per_inch);
366     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
367 					dots_per_inch, PCL_LJ4D_FEATURES,
368 					real_init);
369 }
370 /* The 2563B line printer can't compress */
371 /* and doesn't support *p+ or *b vertical spacing. */
372 private int
lp2563_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)373 lp2563_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
374 			 int num_copies)
375 {
376     return dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
377 					300, PCL_LP2563B_FEATURES,
378 					"\033*b0M");
379 }
380 /* The Oce line printer has TIFF compression */
381 /* and doesn't support *p+ or *b vertical spacing. */
382 private int
oce9050_print_page_copies(gx_device_printer * pdev,FILE * prn_stream,int num_copies)383 oce9050_print_page_copies(gx_device_printer * pdev, FILE * prn_stream,
384 			  int num_copies)
385 {
386     int code;
387 
388     /* Switch to HP_RTL. */
389     fputs("\033%1B", prn_stream);	/* Enter HPGL/2 mode */
390     fputs("BP", prn_stream);	/* Begin Plot */
391     fputs("IN;", prn_stream);	/* Initialize (start plot) */
392     fputs("\033%1A", prn_stream);	/* Enter PCL mode */
393 
394     code = dljet_mono_print_page_copies(pdev, prn_stream, num_copies,
395 					400, PCL_OCE9050_FEATURES,
396 					"\033*b3M");
397 
398     /* Return to HPGL/2 mode. */
399     fputs("\033%1B", prn_stream);	/* Enter HPGL/2 mode */
400     if (code == 0) {
401 	fputs("PU", prn_stream);	/* Pen Up */
402 	fputs("SP0", prn_stream);	/* Pen Select */
403 	fputs("PG;", prn_stream);	/* Advance Full Page */
404 	fputs("\033E", prn_stream);	/* Reset */
405     }
406     return code;
407 }
408