1 /* Copyright (C) 1989, 1995 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 /*$Id: gdevadmp.c,v 1.3 2001/08/01 00:48:23 stefan911 Exp $*/ 20 /* 21 * Apple DMP / Imagewriter driver 22 * 23 * This is a modification of Mark Wedel's Apple DMP and 24 * Jonathan Luckey's Imagewriter II driver to 25 * support the Imagewriter LQ's higher resolution (320x216): 26 * appledmp: 120dpi x 72dpi is still supported (yuck) 27 * iwlo: 160dpi x 72dpi 28 * iwhi: 160dpi x 144dpi 29 * iwlq: 320dpi x 216dpi 30 * 31 * This is also my first attempt to work with gs. I have not included the LQ's 32 * ability to print in colour. Perhaps at a later date I will tackle that. 33 * 34 * BTW, to get your Imagewriter LQ serial printer to work with a PC, attach it 35 * with a nullmodem serial cable. 36 * 37 * Scott Barker (barkers@cuug.ab.ca) 38 */ 39 40 /* 41 * This is a modification of Mark Wedel's Apple DMP driver to 42 * support 2 higher resolutions: 43 * appledmp: 120dpi x 72dpi is still supported (yuck) 44 * iwlo: 160dpi x 72dpi 45 * iwhi: 160dpi x 144dpi 46 * 47 * The Imagewriter II is a bit odd. In pinfeed mode, it thinks its 48 * First line is 1 inch from the top of the page. If you set the top 49 * form so that it starts printing at the top of the page, and print 50 * to near the bottom, it thinks it has run onto the next page and 51 * the formfeed will skip a whole page. As a work around, I reverse 52 * the paper about a 1.5 inches at the end of the page before the 53 * formfeed to make it think its on the 'right' page. bah. hack! 54 * 55 * This is my first attempt to work with gs, so your milage may vary 56 * 57 * Jonathan Luckey (luckey@rtfm.mlb.fl.us) 58 */ 59 60 /* This is a bare bones driver I developed for my apple Dot Matrix Printer. 61 * This code originally was from the epson driver, but I removed a lot 62 * of stuff that was not needed. 63 * 64 * The Dot Matrix Printer was a predecessor to the apple Imagewriter. Its 65 * main difference being that it was parallel. 66 * 67 * This code should work fine on Imagewriters, as they have a superset 68 * of commands compared to the DMP printer. 69 * 70 * This driver does not produce the smalles output files possible. To 71 * do that, it should look through the output strings and find repeat 72 * occurances of characters, and use the escape sequence that allows 73 * printing repeat sequences. However, as I see it, this the limiting 74 * factor in printing is not transmission speed to the printer itself, 75 * but rather, how fast the print head can move. This is assuming the 76 * printer is set up with a reasonable speed (9600 bps) 77 * 78 * WHAT THE CODE DOES AND DOES NOT DO: 79 * 80 * To print out images, it sets the printer for unidirection printing 81 * and 15 cpi (120 dpi). IT sets line feed to 1/9 of an inch (72 dpi). 82 * When finished, it sets things back to bidirection print, 1/8" line 83 * feeds, and 12 cpi. There does not appear to be a way to reset 84 * things to initial values. 85 * 86 * This code does not set for 8 bit characters (which is required). It 87 * also assumes that carriage return/newline is needed, and not just 88 * carriage return. These are all switch settings on the DMP, and 89 * I have configured them for 8 bit data and cr only. 90 * 91 * You can search for the strings Init and Reset to find the strings 92 * that set up the printer and clear things when finished, and change 93 * them to meet your needs. 94 * 95 * Also, you need to make sure that the printer daemon (assuming unix) 96 * doesn't change the data as it is being printed. I have set my 97 * printcap file (sunos 4.1.1) with the string: 98 * ms=pass8,-opost 99 * and it works fine. 100 * 101 * Feel free to improve this code if you want. However, please make 102 * sure that the old DMP will still be supported by any changes. This 103 * may mean making an imagewriter device, and just copying this file 104 * to something like gdevimage.c. 105 * 106 * The limiting factor of the DMP is the vertical resolution. However, I 107 * see no way to do anything about this. Horizontal resolution could 108 * be increased by using 17 cpi (136 dpi). I believe the Imagewriter 109 * supports 24 cpi (192 dpi). However, the higher dpi, the slower 110 * the printing. 111 * 112 * Dot Matrix Code by Mark Wedel (master@cats.ucsc.edu) 113 */ 114 115 116 #include "gdevprn.h" 117 118 /* The device descriptors */ 119 private dev_proc_print_page(dmp_print_page); 120 121 /* Standard DMP device */ 122 const gx_device_printer far_data gs_appledmp_device = 123 prn_device(prn_std_procs, "appledmp", 124 85, /* width_10ths, 8.5" */ 125 110, /* height_10ths, 11" */ 126 120, 72, /* X_DPI, Y_DPI */ 127 0, 0.5, 0.5, 0, /* margins */ 128 1, dmp_print_page); 129 130 131 /* lowrez Imagewriter device */ 132 const gx_device_printer far_data gs_iwlo_device = 133 prn_device(prn_std_procs, "iwlo", 134 85, /* width_10ths, 8.5" */ 135 110, /* height_10ths, 11" */ 136 160, 72, /* X_DPI, Y_DPI */ 137 0, 0.5, 0.5, 0, /* margins */ 138 1, dmp_print_page); 139 140 141 /* hirez Imagewriter device */ 142 const gx_device_printer far_data gs_iwhi_device = 143 prn_device(prn_std_procs, "iwhi", 144 85, /* width_10ths, 8.5" */ 145 110, /* height_10ths, 11" */ 146 160, 144, /* X_DPI, Y_DPI */ 147 0, 0.5, 0.5, 0, /* margins */ 148 1, dmp_print_page); 149 150 151 /* LQ hirez Imagewriter device */ 152 const gx_device_printer far_data gs_iwlq_device = 153 prn_device(prn_std_procs, "iwlq", 154 85, /* width_10ths, 8.5" */ 155 110, /* height_10ths, 11" */ 156 320, 216, 157 0, 0, 0.5, 0, /* margins */ 158 1, dmp_print_page); 159 160 161 /* ------ Internal routines ------ */ 162 163 #define DMP 1 164 #define IWLO 2 165 #define IWHI 3 166 #define IWLQ 4 167 168 /* Send the page to the printer. */ 169 private int 170 dmp_print_page(gx_device_printer *pdev, FILE *prn_stream) 171 { 172 int dev_type; 173 174 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev); 175 /* Note that in_size is a multiple of 8. */ 176 int in_size = line_size * 8; 177 178 byte *buf1 = (byte *)gs_malloc(in_size, 1, "dmp_print_page(buf1)"); 179 byte *buf2 = (byte *)gs_malloc(in_size, 1, "dmp_print_page(buf2)"); 180 byte *prn = (byte *)gs_malloc(3*in_size, 1, "dmp_print_page(prn)"); 181 182 byte *in = buf1; 183 byte *out = buf2; 184 int lnum = 0; 185 186 /* Check allocations */ 187 if ( buf1 == 0 || buf2 == 0 || prn == 0 ) 188 { 189 if ( buf1 ) 190 gs_free((char *)buf1, in_size, 1, 191 "dmp_print_page(buf1)"); 192 if ( buf2 ) 193 gs_free((char *)buf2, in_size, 1, 194 "dmp_print_page(buf2)"); 195 if ( prn ) 196 gs_free((char *)prn, in_size, 1, 197 "dmp_print_page(prn)"); 198 return_error(gs_error_VMerror); 199 } 200 201 if ( pdev->y_pixels_per_inch == 216 ) 202 dev_type = IWLQ; 203 else if ( pdev->y_pixels_per_inch == 144 ) 204 dev_type = IWHI; 205 else if ( pdev->x_pixels_per_inch == 160 ) 206 dev_type = IWLO; 207 else 208 dev_type = DMP; 209 210 /* Initialize the printer and reset the margins. */ 211 212 fputs("\r\n\033>\033T16", prn_stream); 213 214 switch(dev_type) 215 { 216 case IWLQ: 217 fputs("\033P\033a3", prn_stream); 218 break; 219 case IWHI: 220 case IWLO: 221 fputs("\033P", prn_stream); 222 break; 223 case DMP: 224 default: 225 fputs("\033q", prn_stream); 226 break; 227 } 228 229 /* Print lines of graphics */ 230 while ( lnum < pdev->height ) 231 { 232 byte *inp; 233 byte *in_end; 234 byte *out_end; 235 int lcnt,ltmp; 236 int count, passes; 237 byte *prn_blk, *prn_end, *prn_tmp; 238 239 /* The apple DMP printer seems to be odd in that the bit order on 240 * each line is reverse what might be expected. Meaning, an 241 * underscore would be done as a series of 0x80, while on overscore 242 * would be done as a series of 0x01. So we get each 243 * scan line in reverse order. 244 */ 245 246 switch (dev_type) 247 { 248 case IWLQ: passes = 3; break; 249 case IWHI: passes = 2; break; 250 case IWLO: 251 case DMP: 252 default: passes = 1; break; 253 } 254 255 for (count = 0; count < passes; count++) 256 { 257 for (lcnt=0; lcnt<8; lcnt++) 258 { 259 switch(dev_type) 260 { 261 case IWLQ: ltmp = lcnt + 8*count; break; 262 case IWHI: ltmp = 2*lcnt + count; break; 263 case IWLO: 264 case DMP: 265 default: ltmp = lcnt; break; 266 } 267 268 if ((lnum+ltmp)>pdev->height) 269 memset(in+lcnt*line_size,0,line_size); 270 else 271 gdev_prn_copy_scan_lines(pdev, 272 lnum+ltmp, in + line_size*(7 - lcnt), 273 line_size); 274 } 275 276 out_end = out; 277 inp = in; 278 in_end = inp + line_size; 279 for ( ; inp < in_end; inp++, out_end += 8 ) 280 { 281 gdev_prn_transpose_8x8(inp, line_size, 282 out_end, 1); 283 } 284 285 out_end = out; 286 287 switch (dev_type) 288 { 289 case IWLQ: prn_end = prn + count; break; 290 case IWHI: prn_end = prn + in_size*count; break; 291 case IWLO: 292 case DMP: 293 default: prn_end = prn; break; 294 } 295 296 while ( (int)(out_end-out) < in_size) 297 { 298 *prn_end = *(out_end++); 299 if ((dev_type) == IWLQ) prn_end += 3; 300 else prn_end++; 301 } 302 } 303 304 switch (dev_type) 305 { 306 case IWLQ: 307 prn_blk = prn; 308 prn_end = prn_blk + in_size * 3; 309 while (prn_end > prn && prn_end[-1] == 0 && 310 prn_end[-2] == 0 && prn_end[-3] == 0) 311 { 312 prn_end -= 3; 313 } 314 while (prn_blk < prn_end && prn_blk[0] == 0 && 315 prn_blk[1] == 0 && prn_blk[2] == 0) 316 { 317 prn_blk += 3; 318 } 319 if (prn_end != prn_blk) 320 { 321 if ((prn_blk - prn) > 7) 322 fprintf(prn_stream,"\033U%04d%c%c%c", 323 (int)((prn_blk - prn)/3), 324 0, 0, 0); 325 else 326 prn_blk = prn; 327 fprintf(prn_stream,"\033C%04d", 328 (int)((prn_end - prn_blk)/3)); 329 fwrite(prn_blk, 1, (int)(prn_end - prn_blk), 330 prn_stream); 331 } 332 break; 333 case IWHI: 334 for (count = 0; count < 2; count++) 335 { 336 prn_blk = prn_tmp = prn + in_size*count; 337 prn_end = prn_blk + in_size; 338 while (prn_end > prn_blk && prn_end[-1] == 0) 339 prn_end--; 340 while (prn_blk < prn_end && prn_blk[0] == 0) 341 prn_blk++; 342 if (prn_end != prn_blk) 343 { 344 if ((prn_blk - prn_tmp) > 7) 345 fprintf(prn_stream, 346 "\033V%04d%c", 347 (int)(prn_blk-prn_tmp), 348 0); 349 else 350 prn_blk = prn_tmp; 351 fprintf(prn_stream,"\033G%04d", 352 (int)(prn_end - prn_blk)); 353 fwrite(prn_blk, 1, 354 (int)(prn_end - prn_blk), 355 prn_stream); 356 } 357 if (!count) fputs("\033T01\r\n",prn_stream); 358 } 359 fputs("\033T15",prn_stream); 360 break; 361 case IWLO: 362 case DMP: 363 default: 364 prn_blk = prn; 365 prn_end = prn_blk + in_size; 366 while (prn_end > prn_blk && prn_end[-1] == 0) 367 prn_end--; 368 while (prn_blk < prn_end && prn_blk[0] == 0) 369 prn_blk++; 370 if (prn_end != prn_blk) 371 { 372 if ((prn_blk - prn) > 7) 373 fprintf(prn_stream,"\033V%04d%c", 374 (int)(prn_blk - prn), 0); 375 else 376 prn_blk = prn; 377 fprintf(prn_stream,"\033G%04d", 378 (int)(prn_end - prn_blk)); 379 fwrite(prn_blk, 1, (int)(prn_end - prn_blk), 380 prn_stream); 381 } 382 break; 383 } 384 385 fputs("\r\n",prn_stream); 386 387 switch (dev_type) 388 { 389 case IWLQ: lnum += 24 ; break; 390 case IWHI: lnum += 16 ; break; 391 case IWLO: 392 case DMP: 393 default: lnum += 8 ; break; 394 } 395 } 396 397 /* ImageWriter will skip a whole page if too close to end */ 398 /* so skip back more than an inch */ 399 if ( !(dev_type == DMP) ) 400 fputs("\033T99\n\n\033r\n\n\n\n\033f", prn_stream); 401 402 /* Formfeed and Reset printer */ 403 fputs("\033T16\f\033<\033B\033E", prn_stream); 404 fflush(prn_stream); 405 406 gs_free((char *)prn, in_size, 1, "dmp_print_page(prn)"); 407 gs_free((char *)buf2, in_size, 1, "dmp_print_page(buf2)"); 408 gs_free((char *)buf1, in_size, 1, "dmp_print_page(buf1)"); 409 return 0; 410 } 411