1 /*
2 Copyright (C)1998 Ivan Schreter
3
4 This file is part of GNU Ghostscript.
5
6 GNU Ghostscript is distributed in the hope that it will be useful, but
7 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to
8 anyone for the consequences of using it or for whether it serves any
9 particular purpose or works at all, unless he says so in writing. Refer
10 to the GNU General Public License for full details.
11
12 This source is partially based on deskjet device driver for Ghostscript.
13 */
14
15 /* gdevop4w.c */
16 /* OkiPage 4w/4w+ LED printer driver for Ghostscript */
17
18 #include "gdevprn.h"
19 #include "gdevpcl.h" /* for mode 2 compression */
20
21 /*
22 * Thanks for various improvements to:
23 * (none so far)
24 */
25
26 /*
27 * TODO: You may select a default resolution of 150, 300 or 600 DPI
28 * TODO: in the makefile, or an actual resolution on the gs command line.
29 *
30 * If the preprocessor symbol A4 is defined, the default paper size is
31 * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
32 *
33 * You may find the following test page useful in determining the exact
34 * margin settings on your printer. It prints four big arrows which
35 * point exactly to the for corners of an A4 sized paper. Of course the
36 * arrows cannot appear in full on the paper, and they are truncated by
37 * the margins. The margins measured on the testpage must match those
38 * in gdevdjet.c. So the testpage indicates two facts: 1) the page is
39 * not printed in the right position 2) the page is truncated too much
40 * because the margins are wrong. Setting wrong margins in gdevop4w.c
41 * will also move the page, so both facts should be matched with the
42 * real world.
43
44 %!
45 newpath
46 0 0 moveto 144 72 lineto 72 144 lineto
47 closepath fill stroke 0 0 moveto 144 144 lineto stroke
48
49 595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto
50 closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke
51
52 0 841.88 moveto 144 769.88 lineto 72 697.88 lineto
53 closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke
54
55 595.27 0 moveto 451.27 72 lineto 523.27 144 lineto
56 closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke
57
58 /Helvetica findfont
59 14 scalefont setfont
60 100 600 moveto
61 (This is an A4 testpage. The arrows should point exactly to the) show
62 100 580 moveto
63 (corners and the margins should match those given in gdev*.c) show
64 showpage
65
66 */
67
68 /* Define the default, maximum resolutions. */
69 #ifndef X_DPI
70 # define X_DPI 300
71 #endif
72 #ifndef Y_DPI
73 # define Y_DPI 300
74 #endif
75
76 /* Margins are left, bottom, right, top. */
77 /* from Frans van Hoesel hoesel@rugr86.rug.nl. */
78 /* A4 has a left margin of 1/8 inch and at a printing width of
79 * 8 inch this give a right margin of 0.143. The 0.09 top margin is
80 * not the actual margin - which is 0.07 - but compensates for the
81 * inexact paperlength which is set to 117 10ths.
82 * Somebody should check for letter sized paper. I left it at 0.07".
83 */
84 #define OKI4W_MARGINS_LETTER 0.125f, 0.25f, 0.125f, 0.07f
85 #define OKI4W_MARGINS_A4 0.125f, 0.25f, 0.125f, 0.07f
86
87 /* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
88 #define word ulong
89 #define W sizeof(word)
90 #define byte unsigned char
91
92 /* The device descriptors */
93 static dev_proc_open_device(oki4w_open);
94 static dev_proc_close_device(oki4w_close);
95 static dev_proc_print_page(oki4w_print_page);
96
97 static gx_device_procs prn_hp_procs =
98 prn_params_procs(oki4w_open, gdev_prn_output_page, oki4w_close,
99 gdev_prn_get_params, gdev_prn_put_params);
100
101 gx_device_printer far_data gs_oki4w_device =
102 prn_device(prn_hp_procs, "oki4w",
103 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
104 X_DPI, Y_DPI,
105 0, 0, 0, 0, /* margins filled in by oki4w_open */
106 1, oki4w_print_page);
107
108 #define ppdev ((gx_device_printer *)pdev)
109
110 /* Find out paper size code */
111 static int
oki_paper_size(gx_device * dev)112 oki_paper_size(gx_device *dev)
113 {
114 float height_inches = dev->height / dev->y_pixels_per_inch;
115 return
116 height_inches >= 15.9 ? 0x1b/*PAPER_SIZE_A3*/ :
117 height_inches >= 11.8 ? 0x03/*PAPER_SIZE_LEGAL*/ :
118 height_inches >= 11.1 ? 0x1a /*PAPER_SIZE_A4*/ :
119 height_inches >= 8.3 ? 0x02 /*PAPER_SIZE_LETTER*/ :
120 0x19 /*PAPER_SIZE_A5*/;
121 }
122
123 /* Open the printer, adjusting the margins if necessary. */
124 static int
oki4w_open(gx_device * pdev)125 oki4w_open(gx_device *pdev)
126 { /* Change the margins if necessary. */
127 const float *m = 0;
128 static const float m_a4[4] = { OKI4W_MARGINS_A4 };
129 static const float m_letter[4] = { OKI4W_MARGINS_LETTER };
130 m = (oki_paper_size(pdev) == 0x1a /*PAPER_SIZE_A4*/ ? m_a4 : m_letter);
131 if ( m != 0 )
132 gx_device_set_margins(pdev, m, true);
133 return gdev_prn_open(pdev);
134 }
135
136 /* oki4w_close is only here to eject odd numbered pages in duplex mode. */
137 static int
oki4w_close(gx_device * pdev)138 oki4w_close(gx_device *pdev)
139 {
140 /* RJW: We must call the close entry point for the class. */
141 return gdev_prn_close(pdev);
142 /*
143 if ( pdev->Duplex_set >= 0 && pdev->Duplex )
144 { gdev_prn_open_printer(pdev, 1);
145 gp_fputs("\033$B\033\177", ppdev->file);
146 gp_fputc(0, ppdev->file);
147 return gdev_prn_close_printer(pdev);
148 }
149 */
150 return 0;
151 }
152
153 #undef ppdev
154
155 /* ------ Internal routines ------ */
156
157 /* Send the page to the printer. For speed, compress each scan line, */
158 /* since computer-to-printer communication time is often a bottleneck. */
159 static int
oki4w_print_page(gx_device_printer * pdev,gp_file * prn_stream)160 oki4w_print_page(gx_device_printer *pdev, gp_file *prn_stream)
161 {
162 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
163 int line_size_words = (line_size + W - 1) / W;
164 uint storage_size_words = line_size_words * 8; /* data, out_row, out_row_alt, prev_row */
165 word *storage = (ulong *)gs_malloc(pdev->memory->non_gc_memory, storage_size_words, W,
166 "oki4w_print_page");
167 word
168 *data_words,
169 *out_row_words;
170 #define data ((byte *)data_words)
171 #define out_row ((byte *)out_row_words)
172 byte *out_data;
173 int x_dpi = (int)pdev->x_pixels_per_inch;
174 int y_dpi = (int)pdev->y_pixels_per_inch;
175 int y_dots_per_pixel = x_dpi / y_dpi;
176 int dpi_code, compress_code;
177 int num_rows = dev_print_scan_lines(pdev);
178
179 int out_count;
180 int paper_size = oki_paper_size((gx_device *)pdev);
181 int code = 0;
182 /* bool dup = pdev->Duplex;
183 bool dupset = pdev->Duplex_set >= 0; */
184
185 if ( storage == 0 ) /* can't allocate working area */
186 return_error(gs_error_VMerror);
187 data_words = storage;
188 out_row_words = data_words + (line_size_words * 2);
189 /* Clear temp storage */
190 memset(data, 0, storage_size_words * W);
191
192 out_data = out_row;
193
194 if (y_dpi == 150) {
195 dpi_code = 3;
196 } else if (y_dpi == 300) {
197 dpi_code = 5;
198 } else {
199 dpi_code = 7;
200 }
201 compress_code = 2;
202
203 /* Initialize printer. */
204 /* if ( pdev->PageCount == 0 ) { */
205 /* Put out init string before page. */
206 gp_fprintf(prn_stream, "\x1B%%-98765X\x1C\x14\x03\x41i\x10\x1C"
207 "\x14\x05\x41\x65%cf%c\x1C\x14\x09\x42\x61%cb\x02\x63"
208 "\x01\x65%c\x1C\x7F\x39\x1B&B\x1B&A\x07%c\x01%c"
209 "\x01%c%c%c%c\x1B$A",
210 dpi_code, dpi_code, 0, 0, 0, paper_size,
211 0, dpi_code, dpi_code, 0);
212 /* } */
213
214 /* Send each scan line in turn */
215 { int lnum;
216 int num_blank_lines = 0;
217 word rmask = ~(word)0 << (-pdev->width & (W * 8 - 1));
218
219 /* Transfer raster graphics. */
220 for ( lnum = 0; lnum < num_rows; lnum++ )
221 { register word *end_data =
222 data_words + line_size_words;
223 int i;
224 code = gdev_prn_copy_scan_lines(pdev, lnum,
225 (byte *)data, line_size);
226 if ( code < 0 )
227 break;
228 /* Mask off 1-bits beyond the line width. */
229 end_data[-1] &= rmask;
230 /* Remove trailing 0s. */
231 while ( end_data > data_words && end_data[-1] == 0 )
232 end_data--;
233 if ( end_data == data_words )
234 { /* Blank line */
235 num_blank_lines++;
236 continue;
237 }
238
239 /* We've reached a non-blank line. */
240 /* Put out a spacing command if necessary. */
241 if ( num_blank_lines == lnum )
242 { /* We're at the top of a page. */
243 /* TODO: skip top_margin lines... */
244 /* num_blank_lines += xxx */
245 /* Skip blank lines if any */
246 if (num_blank_lines > 0) {
247 gp_fprintf(prn_stream, "\x1b*B%c%c",
248 num_blank_lines & 0xff,
249 num_blank_lines >> 8);
250 }
251 }
252 else if ( num_blank_lines != 0 )
253 {
254 /* Skip blank lines if any */
255 gp_fprintf(prn_stream, "\x1b*B%c%c",
256 num_blank_lines & 0xff,
257 num_blank_lines >> 8);
258 }
259 num_blank_lines = 0;
260
261 /* Compress the data */
262 out_count = gdev_pcl_mode2compress(data_words,
263 end_data, out_data);
264
265 /* Transfer the data */
266 for (i = 0; i < y_dots_per_pixel; ++i) {
267 gp_fprintf(prn_stream, "\033*A%c%c%c",
268 compress_code,
269 out_count & 0xff, out_count >> 8);
270 gp_fwrite(out_data, sizeof(byte), out_count,
271 prn_stream);
272 }
273 }
274 }
275
276 /* end raster graphics and eject page */
277 gp_fprintf(prn_stream, "\x1b$B\x1b\x7f%c", 0);
278
279 /* free temporary storage */
280 gs_free(pdev->memory->non_gc_memory, (char *)storage, storage_size_words, W, "oki4w_print_page");
281
282 return code;
283 }
284