xref: /plan9-contrib/sys/src/cmd/gs/src/gdevbj10.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 1990, 1995, 1997, 2000 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevbj10.c,v 1.9 2004/08/04 19:36:12 stefan Exp $*/
183ff48bf5SDavid du Colombier /* Canon Bubble Jet BJ-10e, BJ200, and BJ300 printer driver */
197dd7cddfSDavid du Colombier #include "gdevprn.h"
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier /*
227dd7cddfSDavid du Colombier  * The following is taken from the BJ200 Programmer's manual.  The top
237dd7cddfSDavid du Colombier  * margin is 3mm (0.12"), and the bottom margin is 6.4mm (0.25").  The
247dd7cddfSDavid du Colombier  * left and right margin depend on the type of paper -- US letter or
257dd7cddfSDavid du Colombier  * A4 -- but ultimately rest on a print width of 203.2mm (8").  For letter
267dd7cddfSDavid du Colombier  * paper, the left margin (and hence the right) is 6.4mm (0.25"), while
277dd7cddfSDavid du Colombier  * for A4 paper, both are 3.4mm (0.13").
287dd7cddfSDavid du Colombier  *
297dd7cddfSDavid du Colombier  * The bottom margin requires a bit of care.  The image is printed
307dd7cddfSDavid du Colombier  * as strips, each about 3.4mm wide.  We can only attain the bottom
317dd7cddfSDavid du Colombier  * margin if the final strip coincides with it.  Note that each strip
327dd7cddfSDavid du Colombier  * is generated using only 48 of the available 64 jets, and the absence
337dd7cddfSDavid du Colombier  * of those bottom 16 jets makes our bottom margin, in effect, about
347dd7cddfSDavid du Colombier  * 1.1mm (0.04") larger.
357dd7cddfSDavid du Colombier  *
367dd7cddfSDavid du Colombier  * The bj200 behaves, in effect, as though the origin were at the first
377dd7cddfSDavid du Colombier  * printable position, rather than the top left corner of the page, so
387dd7cddfSDavid du Colombier  * we add a translation to the initial matrix to compensate for this.
397dd7cddfSDavid du Colombier  *
407dd7cddfSDavid du Colombier  * Except for the details of getting the margins correct, the bj200 is
417dd7cddfSDavid du Colombier  * no different from the bj10e, and uses the same routine to print each
427dd7cddfSDavid du Colombier  * page.
437dd7cddfSDavid du Colombier  *
447dd7cddfSDavid du Colombier  * NOTE:  The bj200 has a DIP switch called "Text scale mode" and if
457dd7cddfSDavid du Colombier  * set, it allows the printer to get 66 lines on a letter-sized page
467dd7cddfSDavid du Colombier  * by reducing the line spacing by a factor of 14/15.  If this DIP
477dd7cddfSDavid du Colombier  * switch is set, the page image printed by ghostscript will also be
487dd7cddfSDavid du Colombier  * similarly squeezed.  Thus text scale mode is something ghostscript
497dd7cddfSDavid du Colombier  * would like to disable.
507dd7cddfSDavid du Colombier  *
517dd7cddfSDavid du Colombier  * According to the bj200 manual, which describes the bj10 commands,
527dd7cddfSDavid du Colombier  * the printer can be reset either to the settings determined by the
537dd7cddfSDavid du Colombier  * DIP switches, or to the factory defaults, and then some of those
547dd7cddfSDavid du Colombier  * settings can be specifically overriden.  Unfortunately, the text
557dd7cddfSDavid du Colombier  * scale mode and horizontal print position (for letter vs A4 paper)
567dd7cddfSDavid du Colombier  * can not be overriden.  On my bj200, the factory settings are for
577dd7cddfSDavid du Colombier  * no text scaling and letter paper, thus using the factory defaults
587dd7cddfSDavid du Colombier  * also implies letter paper.  I don't know if this is necessarily
597dd7cddfSDavid du Colombier  * true for bj200's sold elsewhere, or for other printers that use
607dd7cddfSDavid du Colombier  * the same command set.
617dd7cddfSDavid du Colombier  *
627dd7cddfSDavid du Colombier  * If your factory defaults are in fact the same, you can compile
637dd7cddfSDavid du Colombier  * the driver with USE_FACTORY_DEFAULTS defined, in which case the
647dd7cddfSDavid du Colombier  * printer will be reset to the factory defaults for letter paper,
657dd7cddfSDavid du Colombier  * and reset to the DIP switch settings for A4 paper.  In this case,
667dd7cddfSDavid du Colombier  * with letter-sized paper, the text scale mode will be disabled.
677dd7cddfSDavid du Colombier  * Further, by leaving the horizontal print position DIP switch set
687dd7cddfSDavid du Colombier  * for A4 paper, gs will be able to print on either A4 or letter
697dd7cddfSDavid du Colombier  * paper without changing the DIP switch.  Since it's not clear that
707dd7cddfSDavid du Colombier  * the factory defaults are universal, the default behaviour is not
717dd7cddfSDavid du Colombier  * to define USE_FACTORY_DEFAULTS, and the printer will always be
727dd7cddfSDavid du Colombier  * reset to the DIP switch defaults.
737dd7cddfSDavid du Colombier  */
747dd7cddfSDavid du Colombier 
753ff48bf5SDavid du Colombier /*
763ff48bf5SDavid du Colombier  * According to md@duesti.fido.de (Matthias Duesterhoeft):
773ff48bf5SDavid du Colombier 
783ff48bf5SDavid du Colombier It is possible to use the printer Canon BJ-300 (and 330) with Ghostscript if
793ff48bf5SDavid du Colombier you use the driver for the Canon BJ-200. The Printer has to be set to
803ff48bf5SDavid du Colombier Proprinter Mode. Although it is possible to set the print quality with a DIP
813ff48bf5SDavid du Colombier switch, you should add the following to the already existing init-string:
823ff48bf5SDavid du Colombier 1B 5B 64 01 00 80  (all numbers in hex)
833ff48bf5SDavid du Colombier This sets the print quality to letter quality.
843ff48bf5SDavid du Colombier 
853ff48bf5SDavid du Colombier The minimum margins are the following:
863ff48bf5SDavid du Colombier 
873ff48bf5SDavid du Colombier Portrait:
883ff48bf5SDavid du Colombier B5/A4: min. left and right margin: 3.4 mm (0.13")
893ff48bf5SDavid du Colombier Letter: min. left and right margin: 6.4 mm (0.25")
903ff48bf5SDavid du Colombier 
913ff48bf5SDavid du Colombier Landscape:
923ff48bf5SDavid du Colombier B4: min. left and right margin: 9.3 mm (0.37")
933ff48bf5SDavid du Colombier A3: min. left and right margin: 37.3 mm (1.47")
943ff48bf5SDavid du Colombier 
953ff48bf5SDavid du Colombier The recommended top margin is 12.7 mm (0.5"), although the printer is capable
963ff48bf5SDavid du Colombier to start at 0 mm. The recommended bottom margin is 25.4 mm (1"), but 12.7 mm
973ff48bf5SDavid du Colombier (0.5") are possible, too. If you ask me, don't use the recommended top and
983ff48bf5SDavid du Colombier bottom margins, use 0" and 0.5".
993ff48bf5SDavid du Colombier 
1003ff48bf5SDavid du Colombier  */
1013ff48bf5SDavid du Colombier 
1027dd7cddfSDavid du Colombier #define BJ200_TOP_MARGIN		0.12
1037dd7cddfSDavid du Colombier #define BJ200_BOTTOM_MARGIN		0.29
1047dd7cddfSDavid du Colombier #define BJ200_LETTER_SIDE_MARGIN	0.25
1057dd7cddfSDavid du Colombier #define BJ200_A4_SIDE_MARGIN		0.13
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier private dev_proc_open_device(bj200_open);
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier private dev_proc_print_page(bj10e_print_page);
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier private gx_device_procs prn_bj200_procs =
1127dd7cddfSDavid du Colombier   prn_procs(bj200_open, gdev_prn_output_page, gdev_prn_close);
1137dd7cddfSDavid du Colombier 
1143ff48bf5SDavid du Colombier const gx_device_printer far_data gs_bj200_device =
1157dd7cddfSDavid du Colombier   prn_device(prn_bj200_procs, "bj200",
1167dd7cddfSDavid du Colombier 	DEFAULT_WIDTH_10THS,
1177dd7cddfSDavid du Colombier 	DEFAULT_HEIGHT_10THS,
1187dd7cddfSDavid du Colombier 	360,				/* x_dpi */
1197dd7cddfSDavid du Colombier 	360,				/* y_dpi */
1207dd7cddfSDavid du Colombier 	0, 0, 0, 0,			/* margins filled in by bj200_open */
1217dd7cddfSDavid du Colombier 	1, bj10e_print_page);
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier /*
1247dd7cddfSDavid du Colombier  * (<simon@pogner.demon.co.uk>, aka <sjwright@cix.compulink.co.uk>):
125*593dc095SDavid du Colombier  * My bj10ex, which as far as I can tell is just like a bj10e, needs a
126*593dc095SDavid du Colombier  * bottom margin of 0.4" (actually, you must not print within 0.5" of
127*593dc095SDavid du Colombier  * the bottom; somewhere, an extra 0.1" is creeping in).
128*593dc095SDavid du Colombier  *
129*593dc095SDavid du Colombier  * (<jim.hague@acm.org>):
130*593dc095SDavid du Colombier  * I have a BJ10sx and the BJ10sx manual. This states that the top and
131*593dc095SDavid du Colombier  * bottom margins for the BJ10sx are 0.33" and 0.5". The latter may
132*593dc095SDavid du Colombier  * explain Simon's finding. The manual also instructs Win31 users to
133*593dc095SDavid du Colombier  * select 'BJ10e' as their driver, so presumably the margins will be
134*593dc095SDavid du Colombier  * identical and thus also correct for BJ10e. The values for the side
135*593dc095SDavid du Colombier  * margins given are identical to those above.
136*593dc095SDavid du Colombier  *
137*593dc095SDavid du Colombier  * As of 2nd Nov 2001 the BJ10 sx manual is at
138*593dc095SDavid du Colombier  * http://www.precision.com/Printer%20Manuals/Canon%20BJ-10sx%20Manual.pdf.
1397dd7cddfSDavid du Colombier  */
1407dd7cddfSDavid du Colombier 
141*593dc095SDavid du Colombier #define BJ10E_TOP_MARGIN		0.33
142*593dc095SDavid du Colombier #define BJ10E_BOTTOM_MARGIN		(0.50 + 0.04)
143*593dc095SDavid du Colombier 
144*593dc095SDavid du Colombier private dev_proc_open_device(bj10e_open);
145*593dc095SDavid du Colombier 
146*593dc095SDavid du Colombier private gx_device_procs prn_bj10e_procs =
147*593dc095SDavid du Colombier   prn_procs(bj10e_open, gdev_prn_output_page, gdev_prn_close);
148*593dc095SDavid du Colombier 
1493ff48bf5SDavid du Colombier const gx_device_printer far_data gs_bj10e_device =
150*593dc095SDavid du Colombier   prn_device(prn_bj10e_procs, "bj10e",
1517dd7cddfSDavid du Colombier 	DEFAULT_WIDTH_10THS,
1527dd7cddfSDavid du Colombier 	DEFAULT_HEIGHT_10THS,
1537dd7cddfSDavid du Colombier 	360,				/* x_dpi */
1547dd7cddfSDavid du Colombier 	360,				/* y_dpi */
1557dd7cddfSDavid du Colombier 	0,0,0,0,			/* margins */
1567dd7cddfSDavid du Colombier 	1, bj10e_print_page);
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier /*
1597dd7cddfSDavid du Colombier  * Notes on the BJ10e/BJ200 command set.
1607dd7cddfSDavid du Colombier  *
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier According to the BJ200 manual, the "set initial condition" sequence (ESC [
1637dd7cddfSDavid du Colombier K) has 2 bytes which can override the DIP switches -- these are the last 2
1647dd7cddfSDavid du Colombier bytes.  Several bits are listed as "reserved" -- one or more may possibly
1657dd7cddfSDavid du Colombier affect the sheet feeder.  The first is referred to as <P1>, with the
1667dd7cddfSDavid du Colombier following meaning:
1677dd7cddfSDavid du Colombier 				1		0
1687dd7cddfSDavid du Colombier bit 7	ignore/process P1	ignore		process
1697dd7cddfSDavid du Colombier bit 6	reserved
1707dd7cddfSDavid du Colombier bit 5	alarm			disabled	enabled
1717dd7cddfSDavid du Colombier bit 4	automatic CR		CR+LF		CR
1727dd7cddfSDavid du Colombier bit 3	automatic LF		CR+LF		LF
1737dd7cddfSDavid du Colombier bit 2	page length		12 inches	11 inches
1747dd7cddfSDavid du Colombier bit 1	style for zero		slashed		not slashed
1757dd7cddfSDavid du Colombier bit 0	character set		set 2		set 1
1767dd7cddfSDavid du Colombier 
1777dd7cddfSDavid du Colombier The last byte is <P2>, with the following meaning:
1787dd7cddfSDavid du Colombier 				1		0
1797dd7cddfSDavid du Colombier bit 7	ignore/process P2	ignore		process
1807dd7cddfSDavid du Colombier bit 6	code page		850		437
1817dd7cddfSDavid du Colombier bit 5	reserved
1827dd7cddfSDavid du Colombier bit 4	reserved
1837dd7cddfSDavid du Colombier bit 3	reserved
1847dd7cddfSDavid du Colombier bit 2	reserved
1857dd7cddfSDavid du Colombier bit 1	reserved
1867dd7cddfSDavid du Colombier bit 0	reserved
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier The automatic CR setting is important to gs, but the rest shouldn't matter
1897dd7cddfSDavid du Colombier (gs doesn't print characters or send LF, and it explicitly sets the page
1907dd7cddfSDavid du Colombier length).  The sequence ESC 5 <n> controls automatic CR -- if <n> is 0x00,
1917dd7cddfSDavid du Colombier it is turned off (CR only) and if <n> is 0x01, it is turned on (CR + LF).
1927dd7cddfSDavid du Colombier So we do following: Change the initialization string to so that the last 2
1937dd7cddfSDavid du Colombier of the 9 bytes are \200 rather than \000.  Then add
1947dd7cddfSDavid du Colombier 	|* Turn off automatic carriage return, otherwise we get line feeds. *|
1957dd7cddfSDavid du Colombier 	fwrite("\0335\000", 1, 3, prn_stream);
1967dd7cddfSDavid du Colombier after the initialization.  (Actually, instead of setting the last 2 bytes
1977dd7cddfSDavid du Colombier to \200, we suppress them altogether by changing the byte count from \004
1987dd7cddfSDavid du Colombier to \002 (the byte count is the 4th (low 8 bits) and 5th (high 8 bits) bytes
1997dd7cddfSDavid du Colombier in the initialization sequence).)
2007dd7cddfSDavid du Colombier 
2017dd7cddfSDavid du Colombier */
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier /* Open the printer, and set the margins. */
2067dd7cddfSDavid du Colombier private int
bj200_open(gx_device * pdev)2077dd7cddfSDavid du Colombier bj200_open(gx_device *pdev)
2087dd7cddfSDavid du Colombier {
2097dd7cddfSDavid du Colombier 	/* Change the margins according to the paper size.
2107dd7cddfSDavid du Colombier 	   The top and bottom margins don't seem to depend on the
2117dd7cddfSDavid du Colombier 	   page length, but on the paper handling mechanism;
2127dd7cddfSDavid du Colombier 	   The side margins do depend on the paper width, as the
2137dd7cddfSDavid du Colombier 	   printer centres the 8" print line on the page. */
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier 	static const float a4_margins[4] =
216*593dc095SDavid du Colombier 	 {	(float)BJ200_A4_SIDE_MARGIN, (float)BJ200_BOTTOM_MARGIN,
217*593dc095SDavid du Colombier 		(float)BJ200_A4_SIDE_MARGIN, (float)BJ200_TOP_MARGIN
2187dd7cddfSDavid du Colombier 	 };
2197dd7cddfSDavid du Colombier 	static const float letter_margins[4] =
220*593dc095SDavid du Colombier 	 {	(float)BJ200_LETTER_SIDE_MARGIN, (float)BJ200_BOTTOM_MARGIN,
221*593dc095SDavid du Colombier 		(float)BJ200_LETTER_SIDE_MARGIN, (float)BJ200_TOP_MARGIN
222*593dc095SDavid du Colombier 	 };
223*593dc095SDavid du Colombier 
224*593dc095SDavid du Colombier 	gx_device_set_margins(pdev,
225*593dc095SDavid du Colombier 		(pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
226*593dc095SDavid du Colombier 		 a4_margins : letter_margins),
227*593dc095SDavid du Colombier 		true);
228*593dc095SDavid du Colombier 	return gdev_prn_open(pdev);
229*593dc095SDavid du Colombier }
230*593dc095SDavid du Colombier 
231*593dc095SDavid du Colombier private int
bj10e_open(gx_device * pdev)232*593dc095SDavid du Colombier bj10e_open(gx_device *pdev)
233*593dc095SDavid du Colombier {
234*593dc095SDavid du Colombier         /* See bj200_open() */
235*593dc095SDavid du Colombier 	static const float a4_margins[4] =
236*593dc095SDavid du Colombier 	 {	(float)BJ200_A4_SIDE_MARGIN, (float)BJ10E_BOTTOM_MARGIN,
237*593dc095SDavid du Colombier 		(float)BJ200_A4_SIDE_MARGIN, (float)BJ10E_TOP_MARGIN
238*593dc095SDavid du Colombier 	 };
239*593dc095SDavid du Colombier 	static const float letter_margins[4] =
240*593dc095SDavid du Colombier 	 {	(float)BJ200_LETTER_SIDE_MARGIN, (float)BJ10E_BOTTOM_MARGIN,
241*593dc095SDavid du Colombier 		(float)BJ200_LETTER_SIDE_MARGIN, (float)BJ10E_TOP_MARGIN
2427dd7cddfSDavid du Colombier 	 };
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	gx_device_set_margins(pdev,
2457dd7cddfSDavid du Colombier 		(pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
2467dd7cddfSDavid du Colombier 		 a4_margins : letter_margins),
2477dd7cddfSDavid du Colombier 		true);
2487dd7cddfSDavid du Colombier 	return gdev_prn_open(pdev);
2497dd7cddfSDavid du Colombier }
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier /* Send the page to the printer. */
2527dd7cddfSDavid du Colombier private int
bj10e_print_page(gx_device_printer * pdev,FILE * prn_stream)2537dd7cddfSDavid du Colombier bj10e_print_page(gx_device_printer *pdev, FILE *prn_stream)
2547dd7cddfSDavid du Colombier {	int line_size = gx_device_raster((gx_device *)pdev, 0);
255*593dc095SDavid du Colombier 	int xres = (int)pdev->x_pixels_per_inch;
256*593dc095SDavid du Colombier 	int yres = (int)pdev->y_pixels_per_inch;
2577dd7cddfSDavid du Colombier 	int mode = (yres == 180 ?
2587dd7cddfSDavid du Colombier 			(xres == 180 ? 11 : 12) :
2597dd7cddfSDavid du Colombier 			(xres == 180 ? 14 : 16));
2607dd7cddfSDavid du Colombier 	int bytes_per_column = (yres == 180) ? 3 : 6;
2617dd7cddfSDavid du Colombier 	int bits_per_column = bytes_per_column * 8;
2627dd7cddfSDavid du Colombier 	int skip_unit = bytes_per_column * 3;
263*593dc095SDavid du Colombier 	byte *in = (byte *)gs_malloc(pdev->memory, 8, line_size, "bj10e_print_page(in)");
264*593dc095SDavid du Colombier 	byte *out = (byte *)gs_malloc(pdev->memory, bits_per_column, line_size, "bj10e_print_page(out)");
2657dd7cddfSDavid du Colombier 	int lnum = 0;
2667dd7cddfSDavid du Colombier 	int skip = 0;
2677dd7cddfSDavid du Colombier 	int code = 0;
2687dd7cddfSDavid du Colombier 	int last_row = dev_print_scan_lines(pdev);
2697dd7cddfSDavid du Colombier 	int limit = last_row - bits_per_column;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	if ( in == 0 || out == 0 )
2727dd7cddfSDavid du Colombier 	{	code = gs_note_error(gs_error_VMerror);
2737dd7cddfSDavid du Colombier 		goto fin;
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	/* Initialize the printer. */
2777dd7cddfSDavid du Colombier #ifdef USE_FACTORY_DEFAULTS
2787dd7cddfSDavid du Colombier 	/* Check for U.S. letter vs. A4 paper. */
2797dd7cddfSDavid du Colombier 	fwrite(( pdev->width / pdev->x_pixels_per_inch <= 8.4 ?
2807dd7cddfSDavid du Colombier 		"\033[K\002\000\000\044"	/*A4--DIP switch defaults*/ :
2817dd7cddfSDavid du Colombier 		"\033[K\002\000\004\044"	/*letter--factory defaults*/ ),
2827dd7cddfSDavid du Colombier 	       1, 7, prn_stream);
2837dd7cddfSDavid du Colombier #else
2847dd7cddfSDavid du Colombier 	fwrite("\033[K\002\000\000\044", 1, 7, prn_stream);
2857dd7cddfSDavid du Colombier #endif
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	/* Turn off automatic carriage return, otherwise we get line feeds. */
2887dd7cddfSDavid du Colombier 	fwrite("\0335\000", 1, 3, prn_stream);
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	/* Set vertical spacing. */
2917dd7cddfSDavid du Colombier 	fwrite("\033[\\\004\000\000\000", 1, 7, prn_stream);
2927dd7cddfSDavid du Colombier 	fputc(yres & 0xff, prn_stream);
2937dd7cddfSDavid du Colombier 	fputc(yres >> 8, prn_stream);
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier 	/* Set the page length.  This is the printable length, in inches. */
2967dd7cddfSDavid du Colombier 	fwrite("\033C\000", 1, 3, prn_stream);
2977dd7cddfSDavid du Colombier 	fputc((last_row + yres - 1)/yres, prn_stream);
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	/* Transfer pixels to printer.  The last row we can print is defined
3007dd7cddfSDavid du Colombier 	   by "last_row".  Only the bottom of the print head can print at the
3017dd7cddfSDavid du Colombier 	   bottom margin, and so we align the final printing pass.  The print
3027dd7cddfSDavid du Colombier 	   head is kept from moving below "limit", which is exactly one pass
3037dd7cddfSDavid du Colombier 	   above the bottom margin.  Once it reaches this limit, we make our
3047dd7cddfSDavid du Colombier 	   final printing pass of a full "bits_per_column" rows. */
3057dd7cddfSDavid du Colombier 	while ( lnum < last_row )
3067dd7cddfSDavid du Colombier 	   {
3077dd7cddfSDavid du Colombier 		byte *in_data;
3087dd7cddfSDavid du Colombier 		byte *in_end = in + line_size;
3097dd7cddfSDavid du Colombier 		byte *out_beg = out;
3107dd7cddfSDavid du Colombier 		byte *out_end = out + bytes_per_column * pdev->width;
3117dd7cddfSDavid du Colombier 		byte *outl = out;
3127dd7cddfSDavid du Colombier 		int bnum;
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 		/* Copy 1 scan line and test for all zero. */
3157dd7cddfSDavid du Colombier 		code = gdev_prn_get_bits(pdev, lnum, in, &in_data);
3167dd7cddfSDavid du Colombier 		if ( code < 0 ) goto xit;
3177dd7cddfSDavid du Colombier 		/* The mem... or str... functions should be faster than */
3187dd7cddfSDavid du Colombier 		/* the following code, but all systems seem to implement */
3197dd7cddfSDavid du Colombier 		/* them so badly that this code is faster. */
3207dd7cddfSDavid du Colombier 		   {	register const long *zip = (const long *)in_data;
3217dd7cddfSDavid du Colombier 			register int zcnt = line_size;
3227dd7cddfSDavid du Colombier 			register const byte *zipb;
3237dd7cddfSDavid du Colombier 			for ( ; zcnt >= 4 * sizeof(long); zip += 4, zcnt -= 4 * sizeof(long) )
3247dd7cddfSDavid du Colombier 			   {	if ( zip[0] | zip[1] | zip[2] | zip[3] )
3257dd7cddfSDavid du Colombier 					goto notz;
3267dd7cddfSDavid du Colombier 			   }
3277dd7cddfSDavid du Colombier 			zipb = (const byte *)zip;
3287dd7cddfSDavid du Colombier 			while ( --zcnt >= 0 )
3297dd7cddfSDavid du Colombier 			   {
3307dd7cddfSDavid du Colombier 				if ( *zipb++ )
3317dd7cddfSDavid du Colombier 					goto notz;
3327dd7cddfSDavid du Colombier 			   }
3337dd7cddfSDavid du Colombier 			/* Line is all zero, skip */
3347dd7cddfSDavid du Colombier 			lnum++;
3357dd7cddfSDavid du Colombier 			skip++;
3367dd7cddfSDavid du Colombier 			continue;
3377dd7cddfSDavid du Colombier notz:			;
3387dd7cddfSDavid du Colombier 		   }
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 		/* Vertical tab to the appropriate position.  Note here that
3417dd7cddfSDavid du Colombier 		   we make sure we don't move below limit. */
3427dd7cddfSDavid du Colombier 		if ( lnum > limit )
3437dd7cddfSDavid du Colombier 		    {	skip -= (lnum - limit);
3447dd7cddfSDavid du Colombier 			lnum = limit;
3457dd7cddfSDavid du Colombier 		    }
3467dd7cddfSDavid du Colombier 		while ( skip > 255 )
3477dd7cddfSDavid du Colombier 		   {	fputs("\033J\377", prn_stream);
3487dd7cddfSDavid du Colombier 			skip -= 255;
3497dd7cddfSDavid du Colombier 		   }
3507dd7cddfSDavid du Colombier 		if ( skip )
3517dd7cddfSDavid du Colombier 			fprintf(prn_stream, "\033J%c", skip);
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier 		/* If we've printed as far as "limit", then reset "limit"
3547dd7cddfSDavid du Colombier 		   to "last_row" for the final printing pass. */
3557dd7cddfSDavid du Colombier 		if ( lnum == limit )
3567dd7cddfSDavid du Colombier 			limit = last_row;
3577dd7cddfSDavid du Colombier 		skip = 0;
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier 		/* Transpose in blocks of 8 scan lines. */
3607dd7cddfSDavid du Colombier 		for ( bnum = 0; bnum < bits_per_column; bnum += 8 )
3617dd7cddfSDavid du Colombier 		   {	int lcnt = min(8, limit - lnum);
3627dd7cddfSDavid du Colombier 			byte *inp = in;
3637dd7cddfSDavid du Colombier 			byte *outp = outl;
3647dd7cddfSDavid du Colombier 		   	lcnt = gdev_prn_copy_scan_lines(pdev,
3657dd7cddfSDavid du Colombier 				lnum, in, lcnt * line_size);
3667dd7cddfSDavid du Colombier 			if ( lcnt < 0 )
3677dd7cddfSDavid du Colombier 			   {	code = lcnt;
3687dd7cddfSDavid du Colombier 				goto xit;
3697dd7cddfSDavid du Colombier 			   }
3707dd7cddfSDavid du Colombier 			if ( lcnt < 8 )
3717dd7cddfSDavid du Colombier 				memset(in + lcnt * line_size, 0,
3727dd7cddfSDavid du Colombier 				       (8 - lcnt) * line_size);
3737dd7cddfSDavid du Colombier 			for ( ; inp < in_end; inp++, outp += bits_per_column )
3747dd7cddfSDavid du Colombier 			   {	gdev_prn_transpose_8x8(inp, line_size,
3757dd7cddfSDavid du Colombier 					outp, bytes_per_column);
3767dd7cddfSDavid du Colombier 			   }
3777dd7cddfSDavid du Colombier 			outl++;
3787dd7cddfSDavid du Colombier 			lnum += lcnt;
3797dd7cddfSDavid du Colombier 			skip += lcnt;
3807dd7cddfSDavid du Colombier 		   }
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier 		/* Send the bits to the printer.  We alternate horizontal
3837dd7cddfSDavid du Colombier 		   skips with the data.  The horizontal skips are in units
3847dd7cddfSDavid du Colombier 		   of 1/120 inches, so we look at the data in groups of
3857dd7cddfSDavid du Colombier 		   3 columns, since 3/360 = 1/120, and 3/180 = 2/120.  */
3867dd7cddfSDavid du Colombier 		outl = out;
3877dd7cddfSDavid du Colombier 		do
3887dd7cddfSDavid du Colombier 		   {	int count;
3897dd7cddfSDavid du Colombier 			int n;
3907dd7cddfSDavid du Colombier 			byte *out_ptr;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 			/* First look for blank groups of columns. */
3937dd7cddfSDavid du Colombier 			while(outl < out_end)
3947dd7cddfSDavid du Colombier 			   {	n = count = min(out_end - outl, skip_unit);
3957dd7cddfSDavid du Colombier 				out_ptr = outl;
3967dd7cddfSDavid du Colombier 				while ( --count >= 0 )
3977dd7cddfSDavid du Colombier 				   {	if ( *out_ptr++ )
3987dd7cddfSDavid du Colombier 						break;
3997dd7cddfSDavid du Colombier 				   }
4007dd7cddfSDavid du Colombier 				if ( count >= 0 )
4017dd7cddfSDavid du Colombier 					break;
4027dd7cddfSDavid du Colombier 				else
4037dd7cddfSDavid du Colombier 					outl = out_ptr;
4047dd7cddfSDavid du Colombier 			   }
4057dd7cddfSDavid du Colombier 			if (outl >= out_end)
4067dd7cddfSDavid du Colombier 				break;
4077dd7cddfSDavid du Colombier 			if (outl > out_beg)
4087dd7cddfSDavid du Colombier 			   {	count = (outl - out_beg) / skip_unit;
4097dd7cddfSDavid du Colombier 				if ( xres == 180 ) count <<= 1;
4107dd7cddfSDavid du Colombier 				fprintf(prn_stream, "\033d%c%c",
4117dd7cddfSDavid du Colombier 					count & 0xff, count >> 8);
4127dd7cddfSDavid du Colombier 			   }
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 			/* Next look for non-blank groups of columns. */
4157dd7cddfSDavid du Colombier 			out_beg = outl;
4167dd7cddfSDavid du Colombier 			outl += n;
4177dd7cddfSDavid du Colombier 			while(outl < out_end)
4187dd7cddfSDavid du Colombier 			   {	n = count = min(out_end - outl, skip_unit);
4197dd7cddfSDavid du Colombier 				out_ptr = outl;
4207dd7cddfSDavid du Colombier 				while ( --count >= 0 )
4217dd7cddfSDavid du Colombier 				   {	if ( *out_ptr++ )
4227dd7cddfSDavid du Colombier 						break;
4237dd7cddfSDavid du Colombier 				   }
4247dd7cddfSDavid du Colombier 				if ( count < 0 )
4257dd7cddfSDavid du Colombier 					break;
4267dd7cddfSDavid du Colombier 				else
4277dd7cddfSDavid du Colombier 					outl += n;
4287dd7cddfSDavid du Colombier 			   }
4297dd7cddfSDavid du Colombier 			count = outl - out_beg + 1;
4307dd7cddfSDavid du Colombier 			fprintf(prn_stream, "\033[g%c%c%c",
4317dd7cddfSDavid du Colombier 				count & 0xff, count >> 8, mode);
4327dd7cddfSDavid du Colombier 			fwrite(out_beg, 1, count - 1, prn_stream);
4337dd7cddfSDavid du Colombier 			out_beg = outl;
4347dd7cddfSDavid du Colombier 			outl += n;
4357dd7cddfSDavid du Colombier 		   }
4367dd7cddfSDavid du Colombier 		while ( out_beg < out_end );
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 		fputc('\r', prn_stream);
4397dd7cddfSDavid du Colombier 	   }
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier 	/* Eject the page */
4427dd7cddfSDavid du Colombier xit:	fputc(014, prn_stream);	/* form feed */
4437dd7cddfSDavid du Colombier 	fflush(prn_stream);
4447dd7cddfSDavid du Colombier fin:	if ( out != 0 )
445*593dc095SDavid du Colombier 		gs_free(pdev->memory, (char *)out, bits_per_column, line_size,
4467dd7cddfSDavid du Colombier 			"bj10e_print_page(out)");
4477dd7cddfSDavid du Colombier 	if ( in != 0 )
448*593dc095SDavid du Colombier 		gs_free(pdev->memory, (char *)in, 8, line_size, "bj10e_print_page(in)");
4497dd7cddfSDavid du Colombier 	return code;
4507dd7cddfSDavid du Colombier }
451