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