1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 /* Canon LBP-8II and LIPS III driver */
17 #include "gdevprn.h"
18 
19 /*
20   Modifications:
21     2.2.97  Lauri Paatero
22             Changed CSI command into ESC [. DCS commands may still need to be changed
23             (to ESC P).
24     4.9.96  Lauri Paatero
25             Corrected LBP-8II margins again. Real problem was that (0,0) is NOT
26                 in upper left corner.
27             Now using relative addressing for vertical addressing. This avoids
28 problems
29                 when printing to paper with wrong size.
30     18.6.96 Lauri Paatero, lauri.paatero@paatero.pp.fi
31             Corrected LBP-8II margins.
32             Added logic to recognize (and optimize away) long strings of 00's in data.
33             For LBP-8II removed use of 8-bit CSI (this does not work if 8-bit character
34                 set has been configured in LBP-8II. (Perhaps this should also be done
35                 for LBP-8III?)
36   Original versions:
37     LBP8 driver: Tom Quinn (trq@prg.oxford.ac.uk)
38     LIPS III driver: Kenji Okamoto (okamoto@okamoto.cias.osakafu-u.ac.jp)
39 */
40 
41 #define X_DPI 300
42 #define Y_DPI 300
43 
44 /* The device descriptors */
45 static dev_proc_print_page(lbp8_print_page);
46 #ifdef NOCONTRIB
47 static dev_proc_print_page(lips3_print_page);
48 #endif
49 
50 const gx_device_printer far_data gs_lbp8_device =
51   prn_device(prn_bg_procs, "lbp8",	/* The print_page proc is compatible with allowing bg printing */
52         DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
53         X_DPI, Y_DPI,
54         0.16, 0.2, 0.32, 0.21,		/* margins: left, bottom, right, top */
55         1, lbp8_print_page);
56 
57 #ifdef NOCONTRIB
58 const gx_device_printer far_data gs_lips3_device =
59   prn_device(prn_bg_procs, "lips3",	/* The print_page proc is compatible with allowing bg printing */
60         82,				/* width_10ths, 8.3" */
61         117,				/* height_10ths, 11.7" */
62         X_DPI, Y_DPI,
63         0.16, 0.27, 0.23, 0.27,		/* margins */
64         1, lips3_print_page);
65 #endif
66 
67 /* ------ Internal routines ------ */
68 
69 #define ESC (char)0x1b
70 #define CSI '\233'
71 #define DCS '\220'
72 #define ST '\234'
73 
74 static const char lbp8_init[] = {
75   ESC, ';', ESC, 'c', ESC, ';', /* reset, ISO */
76   ESC, '[', '2', '&', 'z',	/* fullpaint mode */
77   ESC, '[', '1', '4', 'p',	/* select page type (A4) */
78   ESC, '[', '1', '1', 'h',	/* set mode */
79   ESC, '[', '7', ' ', 'I',	/* select unit size (300dpi)*/
80   ESC, '[', '6', '3', 'k', 	/* Move 63 dots up (to top of printable area) */
81 };
82 
83 #ifdef NOCONTRIB
84 static const char lips3_init[] = {
85   ESC, '<', /* soft reset */
86   DCS, '0', 'J', ST, /* JOB END */
87   DCS, '3', '1', ';', '3', '0', '0', ';', '2', 'J', ST, /* 300dpi, LIPS3 JOB START */
88   ESC, '<',  /* soft reset */
89   DCS, '2', 'y', 'P', 'r', 'i', 'n', 't', 'i', 'n', 'g', '(', 'g', 's', ')', ST,  /* Printing (gs) display */
90   ESC, '[', '?', '1', 'l',  /* auto cr-lf disable */
91   ESC, '[', '?', '2', 'h', /* auto ff disable */
92   ESC, '[', '1', '1', 'h', /* set mode */
93   ESC, '[', '7', ' ', 'I', /* select unit size (300dpi)*/
94   ESC, '[', 'f' /* move to home position */
95 };
96 
97 static const char lips3_end[] = {
98   DCS, '0', 'J', ST  /* JOB END */
99 };
100 #endif
101 
102 /* Send the page to the printer.  */
103 static int
can_print_page(gx_device_printer * pdev,gp_file * prn_stream,const char * init,int init_size,const char * end,int end_size)104 can_print_page(gx_device_printer *pdev, gp_file *prn_stream,
105   const char *init, int init_size, const char *end, int end_size)
106 {
107         char *data;
108         char *out_data;
109         int last_line_nro = 0;
110         int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
111         int code = 0;
112 
113         data = (char *)gs_alloc_bytes(pdev->memory,
114                                       line_size*2,
115                                       "lbp8_line_buffer");
116         if (data == NULL)
117             return_error(gs_error_VMerror);
118 
119         gp_fwrite(init, init_size, 1, prn_stream);		/* initialize */
120 
121         /* Send each scan line in turn */
122         {
123             int lnum;
124             byte rmask = (byte)(0xff << (-pdev->width & 7));
125 
126             for ( lnum = 0; lnum < pdev->height; lnum++ ) {
127                 char *end_data = data + line_size;
128                 code = gdev_prn_copy_scan_lines(pdev, lnum,
129                                                (byte *)data, line_size);
130                 if (code < 0)
131                     goto xit;
132                 /* Mask off 1-bits beyond the line width. */
133                 end_data[-1] &= rmask;
134                 /* Remove trailing 0s. */
135                 while ( end_data > data && end_data[-1] == 0 )
136                         end_data--;
137                 if ( end_data != data ) {
138                     int num_cols = 0;
139                     int out_count;
140                     int zero_count;
141                     out_data = data;
142 
143                     /* move down */
144                     gp_fprintf(prn_stream, "%c[%de",
145                                ESC, lnum-last_line_nro );
146                     last_line_nro = lnum;
147 
148                     while (out_data < end_data) {
149                         /* Remove leading 0s*/
150                         while(out_data < end_data && *out_data == 0) {
151                             num_cols += 8;
152                             out_data++;
153                         }
154 
155                         out_count = end_data - out_data;
156                         zero_count = 0;
157 
158                         /* if there is a lot data, find if there is sequence of zeros */
159                         if (out_count>22) {
160 
161                                 out_count = 1;
162 
163                                 while(out_data+out_count+zero_count < end_data) {
164                                         if (out_data[zero_count+out_count] != 0) {
165                                                 out_count += 1+zero_count;
166                                                 zero_count = 0;
167                                         }
168                                         else {
169                                                 zero_count++;
170                                                 if (zero_count>20)
171                                                         break;
172                                         }
173                                 }
174 
175                         }
176 
177                         if (out_count==0)
178                                 break;
179 
180                         /* move down and across*/
181                         gp_fprintf(prn_stream, "%c[%d`",
182                                    ESC, num_cols );
183                         /* transfer raster graphic command */
184                         gp_fprintf(prn_stream, "%c[%d;%d;300;.r",
185                                    ESC, out_count, out_count);
186 
187                         /* send the row */
188                         gp_fwrite(out_data, sizeof(char),
189                                   out_count, prn_stream);
190 
191                         out_data += out_count+zero_count;
192                         num_cols += 8*(out_count+zero_count);
193                     }
194                 }
195             }
196         }
197 
198         /* eject page */
199         gp_fprintf(prn_stream, "%c=", ESC);
200 
201         /* terminate */
202         if (end != NULL)
203             (void)gp_fwrite(end, end_size, 1, prn_stream);
204 
205 xit:
206         gs_free_object(pdev->memory, data, "lbp8_line_buffer");
207 
208         return code;
209 }
210 
211 /* Print an LBP-8 page. */
212 static int
lbp8_print_page(gx_device_printer * pdev,gp_file * prn_stream)213 lbp8_print_page(gx_device_printer *pdev, gp_file *prn_stream)
214 {
215     return can_print_page(pdev, prn_stream, lbp8_init, sizeof(lbp8_init),
216                               NULL, 0);
217 }
218 
219 #ifdef NOCONTRIB
220 /* Print a LIPS III page. */
221 static int
lips3_print_page(gx_device_printer * pdev,gp_file * prn_stream)222 lips3_print_page(gx_device_printer *pdev, gp_file *prn_stream)
223 {	return can_print_page(pdev, prn_stream, lips3_init, sizeof(lips3_init),
224                               lips3_end, sizeof(lips3_end));
225 }
226 #endif
227