Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
}