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