1 /* Copyright (C) 1989, 1992, 1995 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gdevepsc.c,v 1.11 2004/08/04 19:36:12 stefan Exp $*/
18 /* Epson color dot-matrix printer driver by dave@exlog.com */
19 #include "gdevprn.h"
20
21 /*
22 * For 9-pin printers, you may select
23 * X_DPI = 60, 120, or 240
24 * Y_DPI = 60 or 72
25 * For 24-pin printers, you may select
26 * X_DPI = 60, 120, 180, 240, or 360
27 * Y_DPI = 60, 72, 180, or 216
28 * Note that a given printer implements *either* Y_DPI = 60 | 180 *or*
29 * Y_DPI = 72 | 216; no attempt is made to check this here.
30 * Note that X_DPI = 180 or 360 requires Y_DPI > 100;
31 * this isn't checked either. Finally, note that X_DPI=240 and
32 * X_DPI=360 are double-density modes requiring two passes to print.
33 *
34 * The values of X_DPI and Y_DPI may be set at compile time:
35 * see gdevs.mak.
36 *
37 * At some time in the future, we could simulate 24-bit output on
38 * 9-pin printers by using fractional vertical positioning;
39 * we could even implement an X_DPI=360 mode by using the
40 * ESC++ command that spaces vertically in units of 1/360"
41 * (not supported on many printers.)
42 */
43
44 #ifndef X_DPI
45 # define X_DPI 180 /* pixels per inch */
46 #endif
47 #ifndef Y_DPI
48 # define Y_DPI 180 /* pixels per inch */
49 #endif
50
51 /*
52 ** Colors for EPSON LQ-2550.
53 **
54 ** We map VIOLET to BLUE since this is the best we can do.
55 */
56 #define BLACK 0
57 #define MAGENTA 1
58 #define CYAN 2
59 #define VIOLET 3
60 #define YELLOW 4
61 #define RED 5
62 #define GREEN 6
63 #define WHITE 7
64
65 /*
66 ** The offset in this array correspond to
67 ** the ESC-r n value
68 */
69 static char rgb_color[2][2][2] = {
70 {{BLACK, VIOLET}, {GREEN, CYAN}},
71 {{RED, MAGENTA}, {YELLOW, WHITE}}
72 };
73
74 /* Map an RGB color to a printer color. */
75 #define cv_shift (sizeof(gx_color_value) * 8 - 1)
76 private gx_color_index
epson_map_rgb_color(gx_device * dev,const gx_color_value cv[])77 epson_map_rgb_color(gx_device *dev, const gx_color_value cv[])
78 {
79
80 gx_color_value r = cv[0];
81 gx_color_value g = cv[1];
82 gx_color_value b = cv[2];
83
84 if (gx_device_has_color(dev))
85 /* use ^7 so WHITE is 0 for internal calculations */
86 return (gx_color_index)rgb_color[r >> cv_shift][g >> cv_shift][b >> cv_shift] ^ 7;
87 else
88 return gx_default_map_rgb_color(dev, cv);
89 }
90
91 /* Map the printer color back to RGB. */
92 private int
epson_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])93 epson_map_color_rgb(gx_device *dev, gx_color_index color,
94 gx_color_value prgb[3])
95 {
96 #define c1 gx_max_color_value
97 if (gx_device_has_color(dev))
98 switch ((ushort)color ^ 7)
99 {
100 case BLACK:
101 prgb[0] = 0; prgb[1] = 0; prgb[2] = 0; break;
102 case VIOLET:
103 prgb[0] = 0; prgb[1] = 0; prgb[2] = c1; break;
104 case GREEN:
105 prgb[0] = 0; prgb[1] = c1; prgb[2] = 0; break;
106 case CYAN:
107 prgb[0] = 0; prgb[1] = c1; prgb[2] = c1; break;
108 case RED:
109 prgb[0] = c1; prgb[1] = 0; prgb[2] = 0; break;
110 case MAGENTA:
111 prgb[0] = c1; prgb[1] = 0; prgb[2] = c1; break;
112 case YELLOW:
113 prgb[0] = c1; prgb[1] = c1; prgb[2] = 0; break;
114 case WHITE:
115 prgb[0] = c1; prgb[1] = c1; prgb[2] = c1; break;
116 }
117 else
118 return gx_default_map_color_rgb(dev, color, prgb);
119 return 0;
120 }
121
122 /* The device descriptor */
123 private dev_proc_print_page(epsc_print_page);
124
125 private gx_device_procs epson_procs =
126 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
127 epson_map_rgb_color, epson_map_color_rgb);
128
129 const gx_device_printer far_data gs_epsonc_device =
130 prn_device(epson_procs, "epsonc",
131 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
132 X_DPI, Y_DPI,
133 0, 0, 0.25, 0, /* margins */
134 3, epsc_print_page);
135
136 /* ------ Internal routines ------ */
137
138 /* Forward references */
139 private void epsc_output_run(byte *, int, int, char, FILE *, int);
140
141 /* Send the page to the printer. */
142 #define DD 0x80 /* double density flag */
143 private int
epsc_print_page(gx_device_printer * pdev,FILE * prn_stream)144 epsc_print_page(gx_device_printer *pdev, FILE *prn_stream)
145 { static int graphics_modes_9[5] =
146 { -1, 0 /*60*/, 1 /*120*/, -1, DD+3 /*240*/
147 };
148 static int graphics_modes_24[7] =
149 { -1, 32 /*60*/, 33 /*120*/, 39 /*180*/,
150 -1, -1, DD+40 /*360*/
151 };
152 int y_24pin = pdev->y_pixels_per_inch > 72;
153 int y_mult = (y_24pin ? 3 : 1);
154 int line_size = (pdev->width + 7) >> 3; /* always mono */
155 int in_size = line_size * (8 * y_mult);
156 byte *in = (byte *)gs_malloc(pdev->memory, in_size+1, 1, "epsc_print_page(in)");
157 int out_size = ((pdev->width + 7) & -8) * y_mult;
158 byte *out = (byte *)gs_malloc(pdev->memory, out_size+1, 1, "epsc_print_page(out)");
159 int x_dpi = (int)pdev->x_pixels_per_inch;
160 char start_graphics = (char)
161 ((y_24pin ? graphics_modes_24 : graphics_modes_9)[x_dpi / 60]);
162 int first_pass = (start_graphics & DD ? 1 : 0);
163 int last_pass = first_pass * 2;
164 int dots_per_space = x_dpi / 10; /* pica space = 1/10" */
165 int bytes_per_space = dots_per_space * y_mult;
166 int skip = 0, lnum = 0, pass;
167 /* declare color buffer and related vars */
168 byte *color_in;
169 int color_line_size, color_in_size;
170 int spare_bits = (pdev->width % 8); /* left over bits to go to margin */
171 int whole_bits = pdev->width - spare_bits;
172
173 /* Check allocations */
174 if ( in == 0 || out == 0 )
175 { if ( in ) gs_free(pdev->memory, (char *)in, in_size+1, 1, "epsc_print_page(in)");
176 if ( out ) gs_free(pdev->memory, (char *)out, out_size+1, 1, "epsc_print_page(out)");
177 return -1;
178 }
179
180 /* Initialize the printer and reset the margins. */
181 fwrite("\033@\033P\033l\000\033Q\377\033U\001\r", 1, 14, prn_stream);
182
183 /* Create color buffer */
184 if (gx_device_has_color(pdev))
185 {
186 color_line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
187 color_in_size = color_line_size * (8 * y_mult);
188 if((color_in = (byte *)gs_malloc(pdev->memory, color_in_size+1, 1,
189 "epsc_print_page(color)")) == 0)
190 {
191 gs_free(pdev->memory, (char *)in, in_size+1, 1, "epsc_print_page(in)");
192 gs_free(pdev->memory, (char *)out, out_size+1, 1, "epsc_print_page(out)");
193 return(-1);
194 }
195 }
196 else
197 {
198 color_in = in;
199 color_in_size = in_size;
200 color_line_size = line_size;
201 }
202
203 /* Print lines of graphics */
204 while ( lnum < pdev->height )
205 {
206 int lcnt;
207 byte *nextcolor = NULL; /* position where next color appears */
208 byte *nextmono = NULL; /* position to map next color */
209
210 /* Copy 1 scan line and test for all zero. */
211 gdev_prn_copy_scan_lines(pdev, lnum, color_in, color_line_size);
212
213 if ( color_in[0] == 0 &&
214 !memcmp((char *)color_in, (char *)color_in + 1, color_line_size - 1)
215 )
216 { lnum++;
217 skip += 3 / y_mult;
218 continue;
219 }
220
221 /* Vertical tab to the appropriate position. */
222 while ( skip > 255 )
223 { fputs("\033J\377", prn_stream);
224 skip -= 255;
225 }
226 if ( skip )
227 fprintf(prn_stream, "\033J%c", skip);
228
229 /* Copy the rest of the scan lines. */
230 lcnt = 1 + gdev_prn_copy_scan_lines(pdev, lnum + 1,
231 color_in + color_line_size, color_in_size - color_line_size);
232
233 if ( lcnt < 8 * y_mult )
234 {
235 memset((char *)(color_in + lcnt * color_line_size), 0,
236 color_in_size - lcnt * color_line_size);
237 if (gx_device_has_color(pdev)) /* clear the work buffer */
238 memset((char *)(in + lcnt * line_size), 0,
239 in_size - lcnt * line_size);
240 }
241
242 /*
243 ** We need to create a normal epson scan line from our color scan line
244 ** We do this by setting a bit in the "in" buffer if the pixel byte is set
245 ** to any color. We then search for any more pixels of that color, setting
246 ** "in" accordingly. If any other color is found, we save it for the next
247 ** pass. There may be up to 7 passes.
248 ** In the future, we should make the passes so as to maximize the
249 ** life of the color ribbon (i.e. go lightest to darkest).
250 */
251 do
252 {
253 byte *inp = in;
254 byte *in_end = in + line_size;
255 byte *out_end = out;
256 byte *out_blk;
257 register byte *outp;
258
259 if (gx_device_has_color(pdev))
260 {
261 register int i,j;
262 register byte *outbuf, *realbuf;
263 byte current_color;
264 int end_next_bits = whole_bits;
265 int lastbits;
266
267 /* Move to the point in the scanline that has a new color */
268 if (nextcolor)
269 {
270 realbuf = nextcolor;
271 outbuf = nextmono;
272 memset((char *)in, 0, (nextmono - in));
273 i = nextcolor - color_in;
274 nextcolor = NULL;
275 end_next_bits = (i / color_line_size) * color_line_size
276 + whole_bits;
277 }
278 else
279 {
280 i = 0;
281 realbuf = color_in;
282 outbuf = in;
283 nextcolor = NULL;
284 }
285 /* move thru the color buffer, turning on the appropriate
286 ** bit in the "mono" buffer", setting pointers to the next
287 ** color and changing the color output of the epson
288 */
289 for (current_color = 0; i <= color_in_size && outbuf < in + in_size; outbuf++)
290 {
291 /* Remember, line_size is rounded up to next whole byte
292 ** whereas color_line_size is the proper length
293 ** We only want to set the proper bits in the last line_size byte.
294 */
295 if (spare_bits && i == end_next_bits)
296 {
297 end_next_bits = whole_bits + i + spare_bits;
298 lastbits = 8 - spare_bits;
299 }
300 else
301 lastbits = 0;
302
303 for (*outbuf = 0, j = 8; --j >= lastbits && i <= color_in_size;
304 realbuf++,i++)
305 {
306 if (*realbuf)
307 {
308 if (current_color > 0)
309 {
310 if (*realbuf == current_color)
311 {
312 *outbuf |= 1 << j;
313 *realbuf = 0; /* throw this byte away */
314 }
315 /* save this location for next pass */
316 else if (nextcolor == NULL)
317 {
318 nextcolor = realbuf - (7 - j);
319 nextmono = outbuf;
320 }
321 }
322 else
323 {
324 *outbuf |= 1 << j;
325 current_color = *realbuf; /* set color */
326 *realbuf = 0;
327 }
328 }
329 }
330 }
331 *outbuf = 0; /* zero the end, for safe keeping */
332 /* Change color on the EPSON, current_color must be set
333 ** but lets check anyway
334 */
335 if (current_color)
336 fprintf(prn_stream,"\033r%d",current_color ^ 7);
337 }
338
339 /* We have to 'transpose' blocks of 8 pixels x 8 lines, */
340 /* because that's how the printer wants the data. */
341 /* If we are in a 24-pin mode, we have to transpose */
342 /* groups of 3 lines at a time. */
343
344 if ( y_24pin )
345 { for ( ; inp < in_end; inp++, out_end += 24 )
346 { gdev_prn_transpose_8x8(inp, line_size, out_end, 3);
347 gdev_prn_transpose_8x8(inp + line_size * 8, line_size, out_end + 1, 3);
348 gdev_prn_transpose_8x8(inp + line_size * 16, line_size, out_end + 2, 3);
349 }
350 /* Remove trailing 0s. */
351 while ( out_end > out && out_end[-1] == 0 &&
352 out_end[-2] == 0 && out_end[-3] == 0
353 )
354 out_end -= 3;
355 }
356 else
357 { for ( ; inp < in_end; inp++, out_end += 8 )
358 { gdev_prn_transpose_8x8(inp, line_size, out_end, 1);
359 }
360 /* Remove trailing 0s. */
361 while ( out_end > out && out_end[-1] == 0 )
362 out_end--;
363 }
364
365 for ( pass = first_pass; pass <= last_pass; pass++ )
366 {
367 for ( out_blk = outp = out; outp < out_end; )
368 { /* Skip a run of leading 0s. */
369 /* At least 10 are needed to make tabbing worth it. */
370 /* We do everything by 3's to avoid having to make */
371 /* different cases for 9- and 24-pin. */
372
373 if ( *outp == 0 && outp + 12 <= out_end &&
374 outp[1] == 0 && outp[2] == 0 &&
375 (outp[3] | outp[4] | outp[5]) == 0 &&
376 (outp[6] | outp[7] | outp[8]) == 0 &&
377 (outp[9] | outp[10] | outp[11]) == 0
378 )
379 { byte *zp = outp;
380 int tpos;
381 byte *newp;
382 outp += 12;
383 while ( outp + 3 <= out_end && *outp == 0 &&
384 outp[1] == 0 && outp[2] == 0
385 )
386 outp += 3;
387 tpos = (outp - out) / bytes_per_space;
388 newp = out + tpos * bytes_per_space;
389 if ( newp > zp + 10 )
390 { /* Output preceding bit data. */
391 if ( zp > out_blk ) /* only false at */
392 /* beginning of line */
393 epsc_output_run(out_blk, (int)(zp - out_blk),
394 y_mult, start_graphics,
395 prn_stream, pass);
396 /* Tab over to the appropriate position. */
397 fprintf(prn_stream, "\033D%c%c\t", tpos, 0);
398 out_blk = outp = newp;
399 }
400 }
401 else
402 outp += y_mult;
403 }
404 if ( outp > out_blk )
405 epsc_output_run(out_blk, (int)(outp - out_blk),
406 y_mult, start_graphics,
407 prn_stream, pass);
408
409 fputc('\r', prn_stream);
410 }
411 } while (nextcolor);
412 skip = 24;
413 lnum += 8 * y_mult;
414 }
415
416 /* Eject the page and reinitialize the printer */
417 fputs("\f\033@", prn_stream);
418
419
420 gs_free(pdev->memory, (char *)out, out_size+1, 1, "epsc_print_page(out)");
421 gs_free(pdev->memory, (char *)in, in_size+1, 1, "epsc_print_page(in)");
422 if (gx_device_has_color(pdev))
423 gs_free(pdev->memory, (char *)color_in, color_in_size+1, 1, "epsc_print_page(rin)");
424 return 0;
425 }
426
427 /* Output a single graphics command. */
428 /* pass=0 for all columns, 1 for even columns, 2 for odd columns. */
429 private void
epsc_output_run(byte * data,int count,int y_mult,char start_graphics,FILE * prn_stream,int pass)430 epsc_output_run(byte *data, int count, int y_mult,
431 char start_graphics, FILE *prn_stream, int pass)
432 { int xcount = count / y_mult;
433 fputc(033, prn_stream);
434 if ( !(start_graphics & ~3) )
435 { fputc("KLYZ"[(int)start_graphics], prn_stream);
436 }
437 else
438 { fputc('*', prn_stream);
439 fputc(start_graphics & ~DD, prn_stream);
440 }
441 fputc(xcount & 0xff, prn_stream);
442 fputc(xcount >> 8, prn_stream);
443 if ( !pass )
444 fwrite((char *)data, 1, count, prn_stream);
445 else
446 { /* Only write every other column of y_mult bytes. */
447 int which = pass;
448 byte *dp = data;
449 register int i, j;
450 for ( i = 0; i < xcount; i++, which++ )
451 for ( j = 0; j < y_mult; j++, dp++ )
452 { putc(((which & 1) ? *dp : 0), prn_stream);
453 }
454 }
455 }
456