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