1 /* Copyright (C) 1992, 1996, 1997 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 #include "gdevprn.h" 18 19 20 /* $Id: gdevdm24.c,v 1.8 2004/08/04 23:33:29 stefan Exp $*/ 21 /* High-res 24Dot-matrix printer driver */ 22 23 /* Supported printers 24 * NEC P6 and similar, implemented by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) 25 * Epson LQ850, implemented by Christian Felsch (felsch@tu-harburg.d400.de) 26 */ 27 28 /* Driver for NEC P6 */ 29 private dev_proc_print_page (necp6_print_page); 30 const gx_device_printer far_data gs_necp6_device = 31 prn_device (prn_std_procs, "necp6", 32 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 33 360, 360, 34 0, 0, 0.5, 0, /* margins */ 35 1, necp6_print_page); 36 37 38 /* Driver for Epson LQ850 */ 39 /* I've tested this driver on a BJ300 with LQ850 emulation and there it produce correct 360x360dpi output. */ 40 private dev_proc_print_page (lq850_print_page); 41 const gx_device_printer gs_lq850_device = 42 prn_device (prn_std_procs, "lq850", 43 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 44 360, 360, 45 0, 0, 0.5, 0, /* margins */ 46 1, lq850_print_page); 47 48 /* ------ Internal routines ------ */ 49 50 /* Forward references */ 51 private void dot24_output_run (byte *, int, int, FILE *); 52 private void dot24_improve_bitmap (byte *, int); 53 54 /* Send the page to the printer. */ 55 private int 56 dot24_print_page (gx_device_printer *pdev, FILE *prn_stream, char *init_string, int init_len) 57 { 58 int xres = (int)pdev->x_pixels_per_inch; 59 int yres = (int)pdev->y_pixels_per_inch; 60 int x_high = (xres == 360); 61 int y_high = (yres == 360); 62 int bits_per_column = (y_high ? 48 : 24); 63 uint line_size = gdev_prn_raster (pdev); 64 uint in_size = line_size * bits_per_column; 65 byte *in = (byte *) gs_malloc (pdev->memory, in_size, 1, "dot24_print_page (in)"); 66 uint out_size = ((pdev->width + 7) & -8) * 3; 67 byte *out = (byte *) gs_malloc (pdev->memory, out_size, 1, "dot24_print_page (out)"); 68 int y_passes = (y_high ? 2 : 1); 69 int dots_per_space = xres / 10; /* pica space = 1/10" */ 70 int bytes_per_space = dots_per_space * 3; 71 int skip = 0, lnum = 0, ypass; 72 73 /* Check allocations */ 74 if (in == 0 || out == 0) 75 { 76 if (out) 77 gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)"); 78 if (in) 79 gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)"); 80 return_error (gs_error_VMerror); 81 } 82 83 /* Initialize the printer and reset the margins. */ 84 fwrite (init_string, init_len - 1, sizeof (char), prn_stream); 85 fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2, 86 prn_stream); 87 88 /* Print lines of graphics */ 89 while (lnum < pdev->height) 90 { 91 byte *inp; 92 byte *in_end; 93 byte *out_end; 94 byte *out_blk; 95 register byte *outp; 96 int lcnt; 97 98 /* Copy 1 scan line and test for all zero. */ 99 gdev_prn_copy_scan_lines (pdev, lnum, in, line_size); 100 if (in[0] == 0 101 && !memcmp ((char *) in, (char *) in + 1, line_size - 1)) 102 { 103 lnum++; 104 skip += 2 - y_high; 105 continue; 106 } 107 108 /* Vertical tab to the appropriate position. */ 109 while ((skip >> 1) > 255) 110 { 111 fputs ("\033J\377", prn_stream); 112 skip -= 255 * 2; 113 } 114 115 if (skip) 116 { 117 if (skip >> 1) 118 fprintf (prn_stream, "\033J%c", skip >> 1); 119 if (skip & 1) 120 fputc ('\n', prn_stream); 121 } 122 123 /* Copy the rest of the scan lines. */ 124 if (y_high) 125 { 126 inp = in + line_size; 127 for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size) 128 if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp, 129 line_size)) 130 { 131 memset (inp, 0, (24 - lcnt) * line_size); 132 break; 133 } 134 inp = in + line_size * 24; 135 for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size) 136 if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp, 137 line_size)) 138 { 139 memset (inp, 0, (24 - lcnt) * line_size); 140 break; 141 } 142 } 143 else 144 { 145 lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size, 146 in_size - line_size); 147 if (lcnt < 24) 148 /* Pad with lines of zeros. */ 149 memset (in + lcnt * line_size, 0, in_size - lcnt * line_size); 150 } 151 152 for (ypass = 0; ypass < y_passes; ypass++) 153 { 154 out_end = out; 155 inp = in; 156 if (ypass) 157 inp += line_size * 24; 158 in_end = inp + line_size; 159 160 for (; inp < in_end; inp++, out_end += 24) 161 { 162 memflip8x8 (inp, line_size, out_end, 3); 163 memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3); 164 memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3); 165 } 166 /* Remove trailing 0s. */ 167 while (out_end - 3 >= out && out_end[-1] == 0 168 && out_end[-2] == 0 && out_end[-3] == 0) 169 out_end -= 3; 170 171 for (out_blk = outp = out; outp < out_end;) 172 { 173 /* Skip a run of leading 0s. */ 174 /* At least 10 are needed to make tabbing worth it. */ 175 176 if (outp[0] == 0 && outp + 12 <= out_end 177 && outp[1] == 0 && outp[2] == 0 178 && outp[3] == 0 && outp[4] == 0 && outp[5] == 0 179 && outp[6] == 0 && outp[7] == 0 && outp[8] == 0 180 && outp[9] == 0 && outp[10] == 0 && outp[11] == 0) 181 { 182 byte *zp = outp; 183 int tpos; 184 byte *newp; 185 outp += 12; 186 while (outp + 3 <= out_end 187 && outp[0] == 0 && outp[1] == 0 && outp[2] == 0) 188 outp += 3; 189 tpos = (outp - out) / bytes_per_space; 190 newp = out + tpos * bytes_per_space; 191 if (newp > zp + 10) 192 { 193 /* Output preceding bit data. */ 194 /* only false at beginning of line */ 195 if (zp > out_blk) 196 { 197 if (x_high) 198 dot24_improve_bitmap (out_blk, (int) (zp - out_blk)); 199 dot24_output_run (out_blk, (int) (zp - out_blk), 200 x_high, prn_stream); 201 } 202 /* Tab over to the appropriate position. */ 203 fprintf (prn_stream, "\033D%c%c\t", tpos, 0); 204 out_blk = outp = newp; 205 } 206 } 207 else 208 outp += 3; 209 } 210 if (outp > out_blk) 211 { 212 if (x_high) 213 dot24_improve_bitmap (out_blk, (int) (outp - out_blk)); 214 dot24_output_run (out_blk, (int) (outp - out_blk), x_high, 215 prn_stream); 216 } 217 218 fputc ('\r', prn_stream); 219 if (ypass < y_passes - 1) 220 fputc ('\n', prn_stream); 221 } 222 skip = 48 - y_high; 223 lnum += bits_per_column; 224 } 225 226 /* Eject the page and reinitialize the printer */ 227 fputs ("\f\033@", prn_stream); 228 fflush (prn_stream); 229 230 gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)"); 231 gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)"); 232 233 return 0; 234 } 235 236 /* Output a single graphics command. */ 237 private void 238 dot24_output_run (byte *data, int count, int x_high, FILE *prn_stream) 239 { 240 int xcount = count / 3; 241 fputc (033, prn_stream); 242 fputc ('*', prn_stream); 243 fputc ((x_high ? 40 : 39), prn_stream); 244 fputc (xcount & 0xff, prn_stream); 245 fputc (xcount >> 8, prn_stream); 246 fwrite (data, 1, count, prn_stream); 247 } 248 249 /* If xdpi == 360, the P6 / LQ850 cannot print adjacent pixels. Clear the 250 second last pixel of every run of set pixels, so that the last pixel 251 is always printed. */ 252 private void 253 dot24_improve_bitmap (byte *data, int count) 254 { 255 int i; 256 register byte *p = data + 6; 257 258 for (i = 6; i < count; i += 3, p += 3) 259 { 260 p[-6] &= ~(~p[0] & p[-3]); 261 p[-5] &= ~(~p[1] & p[-2]); 262 p[-4] &= ~(~p[2] & p[-1]); 263 } 264 p[-6] &= ~p[-3]; 265 p[-5] &= ~p[-2]; 266 p[-4] &= ~p[-1]; 267 268 } 269 270 271 private int 272 necp6_print_page(gx_device_printer *pdev, FILE *prn_stream) 273 { 274 char necp6_init_string [] = "\033@\033P\033l\000\r\034\063\001\033Q"; 275 276 return dot24_print_page(pdev, prn_stream, necp6_init_string, sizeof(necp6_init_string)); 277 } 278 279 280 private int 281 lq850_print_page(gx_device_printer *pdev, FILE *prn_stream) 282 { 283 char lq850_init_string [] = "\033@\033P\033l\000\r\033\053\001\033Q"; 284 285 return dot24_print_page(pdev, prn_stream, lq850_init_string, sizeof(lq850_init_string)); 286 } 287 288