1 /* Copyright (C) 1992, 1993, 1994, 1996 by 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: gdevimgn.c,v 1.4 2001/08/01 00:48:23 stefan911 Exp $*/ 20 /* 21 * Imagen ImPRESS printer driver - version 1.4 22 * 23 * This driver uses the Impress bitmap operation to print the page image. 24 */ 25 26 /* Written by Alan Millar (AMillar@bolis.sf-bay.org) August 4 1992. 27 Basic bitmap dump. */ 28 /* Updated by Alan Millar Sept 21 1992. Added resolution handling 29 for 75, 150, and 300 dpi. */ 30 /* Updated by Alan Millar June 05 1993. General cleanup for 31 beta test release. */ 32 /* Updated by Alan Millar June 21 1993. v1.3. Combined multipage 33 output into single imPress document. Quote fewer special 34 chars in byte stream mode. imPress document header options 35 can be set from environment variable IMPRESSHEADER */ 36 /* Updated by Alan Millar July 04 1993. v1.4. 37 New makefile option USE_BYTE_STREAM instead of changing source. 38 Swatch output redone to eliminate ALL blank swatches (swatchMap). 39 Buffer copying changed to multi-byte operations (BIGTYPE). 40 Page margins and A4 paper settings fixed, at least for Canon CX. 41 */ 42 43 /* -------------------------------------------------------- */ 44 /* Instructions: 45 46 - Add "imagen.dev" to DEVICE_DEVS in the makefile. For example: 47 DEVICE_DEVS2=laserjet.dev imagen.dev 48 49 - Include or exclude USE_BYTE_STREAM in makefile as appropriate 50 If you are compiling on Unix, re-run "tar_cat" to update the makefile 51 from devs.mak 52 53 - At run time, specify the resolution on the GS command line 54 by using -r300 or -r150 or -r75 55 - At run time, specify any imPress document options in 56 the IMPRESSHEADER environment variable. 57 */ 58 59 /* -------------------------------------------------------- */ 60 /* Hardware/software combinations tested: 61 - ImageStation IP3 8/300 with parallel byte-stream interface, 62 using GS 2.6.1 on Linux with GCC 2.3.3; 63 earlier using GS 2.5.1 on MS-Dos with Turbo C++ 1.0 64 - Sequenced-packet-protocol interface untested. 65 */ 66 /* -------------------------------------------------------- */ 67 /* Bugs/Enhancements: 68 - Driver does not use any Impress language features for 69 drawing lines/arcs 70 - Driver does not use resident or downloadable fonts. 71 - Buffer output instead of system call for each byte? 72 */ 73 74 /* -------------------------------------------------------- */ 75 #include "gdevprn.h" 76 /* #include <stdio.h> should not be used in drivers */ 77 #include <stdlib.h> 78 79 /* -------------------------------------------------------- */ 80 /* Working Constants */ 81 82 /* Byte stream quoting: convert special characters to hex. 83 Specify by including/excluding -DUSE_BYTE_STREAM in makefile. 84 This should match printer's hardware interface configuration. 85 If printer interface is serial with sequenced-packet-protocol 86 spooler software (ImageStation config# 11 = 01), then don't use it. 87 Imagen "ipr" spooler software should not use byte stream. 88 If printer interface is Centronics parallel byte stream, 89 (ImageStation config# 11 = 03), then use byte stream. */ 90 91 #ifdef USE_BYTE_STREAM 92 # define BYTE_STREAM 1 93 #else 94 # define BYTE_STREAM 0 95 #endif 96 97 /* Byte stream quote character (ImageStation config# 15). 98 Only needed when using byte stream */ 99 #define QUOTE_CHAR (char) 0x02 100 /* Byte stream end-of-file character (ImageStation config# 14). */ 101 #define EOF_CHAR (char) 0x04 102 /* Other special characters to quote. Put them here if spooler or 103 hardware uses flow control, etc. If not needed, set to 104 a redundant value such as EOF_CHAR */ 105 #define EXTRA_QUOTE1 (char) 0x11 /* ^Q */ 106 #define EXTRA_QUOTE2 (char) 0x13 /* ^S */ 107 #define EXTRA_QUOTE3 EOF_CHAR 108 #define EXTRA_QUOTE4 EOF_CHAR 109 110 /* -------------------------------------------------------- */ 111 /* imPress header default options. 112 Can be overridden at run-time with IMPRESSHEADER env variable */ 113 114 #define IMPRESSHEADER "jobheader onerror, prerasterization off" 115 116 /* -------------------------------------------------------- */ 117 118 #define CANON_CX 119 120 /* Printer engine max resolution. 300 for Canon CX models such as 121 ImageStation IP3. Others (240?) unverified */ 122 #ifdef CANON_CX 123 # define MAX_DPI 300 124 #endif 125 #ifndef MAX_DPI 126 # define MAX_DPI 300 127 #endif 128 129 /* Determine imPress scaling factor from GS resolution. 130 Magnify can be 0, 1, or 2. 131 0 = MAX_DPI, 1 = MAX_DPI / 2, 2 = MAX_DPI / 4 132 Assuming MAX_DPI is 300, you can specify -r75 or -r150 133 or -r300 on the GS command line */ 134 #define getMagnification ( \ 135 ( pdev->x_pixels_per_inch > (MAX_DPI >> 1) ) ? 0 : \ 136 ( pdev->x_pixels_per_inch > (MAX_DPI >> 2) ) ? 1 : \ 137 2 ) 138 139 /* Page dimensions from gdevprn.h - specify -DA4 in makefile for A4 paper */ 140 #define WIDTH_10THS DEFAULT_WIDTH_10THS 141 #define HEIGHT_10THS DEFAULT_HEIGHT_10THS 142 143 /* Width in inches of unprintable edge of paper. May need fine tuning. 144 Canon CX engine in ImageStation IP3 8/300 will only print 8 inches 145 wide on any paper size. May vary for other engines */ 146 147 #ifdef CANON_CX 148 # define MARG_L 0.15 149 # define MARG_R ( (float)WIDTH_10THS / 10.0 - 8.0 - MARG_L) 150 #endif 151 #ifndef MARG_L 152 # define MARG_L 0.2 153 #endif 154 #ifndef MARG_R 155 # define MARG_R 0.2 156 #endif 157 #define MARG_T 0.1 158 #define MARG_B 0.2 159 160 161 /* Flag for displaying debug messages at run-time. Higher 162 number = higher detail */ 163 #define IM_DEBUG 0 164 #define DebugMsg(Level,P1,P2) if (Level<=IM_DEBUG) {errprintf(P1,P2 );} 165 166 /*-------------------------------------------*/ 167 /* Impress bitmaps are made up of 32x32 bit swatches. 168 A swatch is four bytes (32 bits) wide by 32 bytes high, 169 totalling 128 bytes. */ 170 #define HorzBytesPerSw 4 171 #define HorzBitsPerSw (HorzBytesPerSw * 8) 172 #define VertBytesPerSw 32 173 #define TotalBytesPerSw (HorzBytesPerSw * VertBytesPerSw) 174 175 /*-------------------------------------------*/ 176 /* Attempt at optimization to something faster than byte-by-byte copying. 177 imPress swatches are 4 bytes wide, so type must align on a 4-byte 178 boundary. Swatch interleaving restricts the copy to 4 bytes in a row. 179 Type must be numeric where value is zero when all bytes in it are zero. */ 180 #if arch_sizeof_long == 4 181 # define BIGTYPE unsigned long int 182 #else 183 # if arch_sizeof_short == 4 184 # define BIGTYPE unsigned short int 185 # else 186 # if arch_sizeof_short == 2 187 # define BIGTYPE unsigned short 188 # endif 189 # endif 190 #endif 191 #ifndef BIGTYPE 192 #define BIGTYPE byte 193 #endif 194 195 #define BIGSIZE ( sizeof( BIGTYPE ) ) 196 197 /*-------------------------------------------*/ 198 /* IMAGEN imPress Command opcodes */ 199 /* from DVIIMP.C */ 200 #define iSP 128 /* advance one space */ 201 #define iSP1 129 /* advance one space + 1 pixel */ 202 #define iMPLUS 131 /* Move one pixel forward */ 203 #define iMMINUS 132 /* Move one pixel back */ 204 #define iMMOVE 133 /* Move in main advance direction */ 205 #define iSMOVE 134 /* Move in secondary advance direction */ 206 207 #define iABS_H 135 /* Move to H position */ 208 #define iREL_H 136 /* Move in H direction */ 209 #define iABS_V 137 /* Move to V position */ 210 #define iREL_V 138 /* Move in V direction */ 211 212 #define iCRLF 197 /* move to beginning of next line */ 213 214 #define iSET_HV_SYSTEM 205 /* Define new coordinate system */ 215 #define iSET_ADV_DIRS 206 /* Define advance directions */ 216 217 #define iPAGE 213 /* Set H and V to 0 */ 218 #define iENDPAGE 219 /* print the current page */ 219 220 #define iBITMAP 235 /* Print a full bitmap */ 221 #define iSET_MAGNIFICATION 236 222 /* magnify the page by 1, 2, 4 */ 223 #define iNOOP 254 /* no operation */ 224 #define iEOF 255 /* end of impress document */ 225 226 /*-------------------------------------------*/ 227 /*-------------------------------------------*/ 228 /* The device descriptor */ 229 230 private dev_proc_print_page(imagen_print_page); 231 private dev_proc_open_device(imagen_prn_open); 232 private dev_proc_close_device(imagen_prn_close); 233 234 gx_device_procs imagen_procs = 235 prn_procs(imagen_prn_open, gdev_prn_output_page, imagen_prn_close); 236 237 #define ppdev ((gx_device_printer *)pdev) 238 239 /*-------------------------------------------*/ 240 const gx_device_printer far_data gs_imagen_device = 241 prn_device(/*prn_std_procs*/ imagen_procs, 242 "imagen", 243 WIDTH_10THS, 244 HEIGHT_10THS, 245 MAX_DPI, /* x_dpi */ 246 MAX_DPI, /* y_dpi */ 247 MARG_L,MARG_R,MARG_T,MARG_B, /* margins */ 248 1, imagen_print_page); 249 250 /*-------------------------------------------*/ 251 252 /*-------------------------------------------*/ 253 private void 254 iWrite(FILE *Out, byte Val) 255 { /* iWrite */ 256 char *hexList = "0123456789ABCDEF"; 257 258 /* if we are doing byte-stream, quote characters that would otherwise 259 match EOF and QUOTE itself, or other special chars */ 260 /* Imagen quoting takes one character and writes out the QUOTE 261 character followed by the hex digits of the quoted character */ 262 if (BYTE_STREAM && 263 ( Val == QUOTE_CHAR || Val == EOF_CHAR 264 || Val == EXTRA_QUOTE1 || Val == EXTRA_QUOTE2 265 || Val == EXTRA_QUOTE3 || Val == EXTRA_QUOTE4 ) ) { 266 fputc (QUOTE_CHAR, Out); 267 fputc ((char) hexList[Val / 0x10], Out); 268 fputc ((char) hexList[Val % 0x10], Out); 269 } else { /* quoted char */ 270 /* Not doing quoting, just send it out */ 271 fputc(Val, Out); 272 } /* quoted char */ 273 } /* iWrite */ 274 275 /* Write out 16bit, high byte first */ 276 void 277 iWrite2(FILE *Out, int Val) 278 { /* iWrite2 */ 279 iWrite(Out,(byte) (Val >> 8) & 0x00FF ); 280 iWrite(Out,(byte) Val & 0x00FF ); 281 } /* iWrite2 */ 282 283 /* --------------------------------------------------------- */ 284 285 private int 286 imagen_prn_open(gx_device *pdev) 287 { /* imagen_prn_open */ 288 int code; 289 290 char *impHeader; 291 292 /* ----------------------------------------- */ 293 DebugMsg(1,"%s\n","Start of imagen_prn_open"); 294 DebugMsg(2,"BIGSIZE = %ld \n",BIGSIZE); 295 296 code = gdev_prn_open(pdev); 297 if ( code < 0 ) return code; 298 299 /* ----------------------------------------- */ 300 301 DebugMsg(2,"opening file: %s\n",ppdev->fname); 302 code = gdev_prn_open_printer(pdev, 1); 303 if ( code < 0 ) return code; 304 305 impHeader = getenv("IMPRESSHEADER"); 306 if (impHeader == NULL ) { 307 impHeader = IMPRESSHEADER ; 308 } /* if impHeader */ 309 310 fprintf(ppdev->file,"@document(language impress, %s)",impHeader); 311 312 code = gdev_prn_close_printer(pdev); 313 if ( code < 0 ) return code; 314 315 /* ----------------------------------------- */ 316 DebugMsg(1,"%s\n","End of imagen_prn_open"); 317 318 return code; 319 } /* imagen_prn_open */ 320 321 private int 322 imagen_prn_close(gx_device *pdev) 323 { /* imagen_prn_close */ 324 int code; 325 326 /* ----------------------------------------- */ 327 DebugMsg(1,"%s\n","Start of imagen_prn_close"); 328 329 code = gdev_prn_open_printer(pdev, 1); 330 if ( code < 0 ) return code; 331 332 /* Write imPress end of document marker */ 333 iWrite(ppdev->file,iEOF); 334 335 /* And byte stream end of file */ 336 if (BYTE_STREAM) { 337 /* DON'T use iWrite because actual EOF should not be quoted! */ 338 fputc(EOF_CHAR,ppdev->file); 339 } /* if byte stream */ 340 341 fflush(ppdev->file); 342 343 code = gdev_prn_close_printer(pdev); 344 if ( code < 0 ) return code; 345 346 code = gdev_prn_close(pdev); 347 348 DebugMsg(1,"%s\n","End of imagen_prn_close"); 349 350 return(code); 351 } /* imagen_prn_close */ 352 353 /*-------------------------------------------*/ 354 /* Send the page to the printer. */ 355 private int 356 imagen_print_page(gx_device_printer *pdev, FILE *prn_stream) 357 { 358 int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev); 359 /* input buffer: one line of bytes rasterized by gs */ 360 byte *in = (byte *)gs_malloc(BIGSIZE, line_size / BIGSIZE + 1, 361 "imagen_print_page(in)"); 362 /* output buffer: 32 lines, interleaved into imPress swatches */ 363 byte *out; 364 /* working pointer into output buffer */ 365 byte *swatch; 366 byte *temp; 367 /* map of which swatches in a row are completely blank, or are non-blank */ 368 byte *swatchMap; 369 /* starting line number on page of a row of swatches */ 370 int lnum ; 371 /* line number within a row of swatches */ 372 int swatchLine; 373 /* ending line number of row of swatches */ 374 int lastLine; 375 /* how many swatches can fit on a row */ 376 int swatchCount; 377 /* index into row of non-blank swatch */ 378 int startSwatch; 379 int endSwatch; 380 /* Scaling factor for resolution */ 381 int Magnify; 382 /* page totals */ 383 int totalBlankSwatches; 384 int totalGreySwatches; 385 386 /* ----------------------------------------- */ 387 /* Start of routine */ 388 /* ----------------------------------------- */ 389 390 DebugMsg(1,"%s\n","Start of imagen_print_page"); 391 392 /* ----------------------------------------- */ 393 Magnify = getMagnification ; 394 395 /* Impress bitmaps are made up of 32x32 bit swatches. 396 A swatch is four bytes wide by 32 bytes high. 397 See how many swatches will fit horizontally. */ 398 399 swatchCount = (line_size + HorzBytesPerSw - 1) / HorzBytesPerSw; 400 401 totalBlankSwatches = 0 ; 402 totalGreySwatches = 0 ; 403 DebugMsg(2,"Swatch count = %d\n",swatchCount); 404 DebugMsg(2,"Line size = %d\n",line_size ); 405 406 out = (byte *)gs_malloc(TotalBytesPerSw , swatchCount + 1, 407 "imagen_print_page(out)"); 408 409 swatchMap = (byte *)gs_malloc(BIGSIZE,swatchCount / BIGSIZE + 1, 410 "imagen_print_page(swatchMap)" ); 411 412 if ( in == 0 || out == 0 ) 413 return -1; 414 415 /* Initialize the page */ 416 iWrite(prn_stream,iPAGE); 417 418 /* Tell ImPress what resolution we will be using */ 419 iWrite(prn_stream,iSET_MAGNIFICATION); 420 iWrite(prn_stream,Magnify); 421 422 /*------------------------------------------------------*/ 423 /* main loop down page */ 424 lnum = 0; 425 while (lnum <= pdev->height) { 426 427 /* erase swatch map. */ 428 for (swatch = swatchMap; swatch < swatchMap + swatchCount ; 429 swatch += BIGSIZE ) { 430 * (BIGTYPE *)swatch = (BIGTYPE) 0; 431 } /* for */ 432 433 /* get scan lines to fill swatches */ 434 swatchLine = 0; 435 lastLine = VertBytesPerSw - 1; 436 437 /* Check if we don't have a full-height row of swatches at end of page */ 438 if (lnum + lastLine > pdev->height ) { 439 /* back up last row so it overlaps with previous. Not a problem 440 on a laser printer, because the overlapping part will be identical */ 441 lnum = pdev->height - lastLine ; 442 }; /* not full height */ 443 444 DebugMsg (3,"lnum = %d \n",lnum); 445 446 /* ------------------------------------------------------- */ 447 /* get 32 lines and interleave into a row of swatches */ 448 for (swatchLine = 0 ; swatchLine <= lastLine; swatchLine++) { 449 /* blank out end of buffer for BIGSIZE overlap */ 450 for (temp = in + line_size; temp < in + line_size + BIGSIZE;temp++){ 451 *temp = 0; 452 } /* for temp */ 453 454 /* get one line */ 455 gdev_prn_copy_scan_lines(pdev, lnum + swatchLine, in, line_size); 456 DebugMsg(5,"Got scan line %d ", lnum + swatchLine); 457 DebugMsg(5,"line %d \n", swatchLine); 458 459 /* interleave scan line into swatch buffer */ 460 /* a swatch is a 4 byte * 32 byte square. Swatches are placed 461 next to each other. The first scan line maps into the first 462 four bytes of the first swatch, then the first four of the second 463 swatch, etc. 464 To get this on the page: 465 A1 A1 A1 A1 B1 B1 B1 B1 C1 C1 C1 C1 466 A2 A2 A2 A2 B2 B2 B2 B2 C2 C2 C2 C2 467 ... 468 A32 A32 A32 A32 B32 B32 B32 B32 C32 C32 C32 C32 469 You have to send it as: 470 A1 A1 A1 A1 A2 ... A32 B1 B1 .. B32 C1 C1 ... C32 */ 471 472 /* set initial offset into swatch buffer based on which 473 line in the swatch we are processing */ 474 swatch = out + swatchLine * HorzBytesPerSw; 475 DebugMsg(5,"offset: swatch = %d \n",(int) (swatch - out) ); 476 temp = in; 477 while ( temp < in + line_size ) { 478 /* copy multi-byte to swatch buffer */ 479 * (BIGTYPE *)swatch = * (BIGTYPE *)temp; 480 if ( * (BIGTYPE *)temp ) { 481 /* mark map if not blank */ 482 swatchMap[(swatch - out)/TotalBytesPerSw] = (byte) 1 ; 483 } /* if not zero */ 484 485 temp += (BIGSIZE > HorzBytesPerSw) ? HorzBytesPerSw : BIGSIZE ; 486 swatch += (BIGSIZE > HorzBytesPerSw) ? HorzBytesPerSw : BIGSIZE ; 487 488 /* if we copied four bytes, skip to next swatch */ 489 if ( ((temp - in) % HorzBytesPerSw ) == 0 ) { 490 swatch += (TotalBytesPerSw - HorzBytesPerSw) ; 491 } /* if need to skip */ 492 } /* while < line_size */ 493 494 } /* for swatchLine */ 495 496 /* ------------------------------------------------- */ 497 /* we now have full swatches. */ 498 /* Send to printer */ 499 500 /* go through swatch map to find non-blank swatches. 501 Skip over completely blank swatches */ 502 startSwatch = 0; 503 while (startSwatch < swatchCount ) { 504 if (swatchMap[startSwatch] == 0 ) { 505 /* skip blank swatch */ 506 DebugMsg(6,"Skip blank %d \n",startSwatch); 507 totalBlankSwatches++; 508 startSwatch++; 509 } else { /* if swatch == 0 */ 510 /* we hit a non-blank swatch. */ 511 totalGreySwatches++; 512 513 /* See how many there are in a row */ 514 endSwatch = startSwatch; 515 while ( (endSwatch < swatchCount) && swatchMap[endSwatch] ) { 516 endSwatch++; 517 totalGreySwatches++; 518 } /* while */ 519 /* endSwatch is one past last non-blank swatch */ 520 DebugMsg(6,"Grey swatches %d ",startSwatch); 521 DebugMsg(6,"until %d \n",endSwatch); 522 523 /* vertical position: scan line, shifted for magnification */ 524 iWrite(prn_stream, iABS_V); 525 iWrite2(prn_stream, lnum << Magnify); 526 527 /* horizontal position = swatch number * 32 bits/swatch */ 528 iWrite(prn_stream,iABS_H); 529 iWrite2(prn_stream, startSwatch * HorzBitsPerSw << Magnify ); 530 iWrite(prn_stream,iBITMAP); /* start bitmap */ 531 iWrite(prn_stream,0x07); /* bit OR with page */ 532 iWrite(prn_stream,(endSwatch - startSwatch)); /* horizontal 533 number of swatches */ 534 iWrite(prn_stream, 1) ; /* vertical number of swatches */ 535 /* write out swatch buffer */ 536 for (swatch = out + startSwatch * TotalBytesPerSw; 537 swatch < out + endSwatch * TotalBytesPerSw; swatch++) { 538 iWrite(prn_stream,*swatch); 539 } /* for swatch */ 540 541 /* swatches have been printed, see if there are still 542 more in this row */ 543 startSwatch = endSwatch; 544 } /* if swatch == 0 */ 545 546 } /* while startSwatch */ 547 548 /* Whole row of swatches is done. Go on to next row of swatches */ 549 lnum += lastLine + 1; 550 551 } /* while lnum */ 552 553 /* Eject the page */ 554 iWrite(prn_stream,iENDPAGE); 555 556 fflush(prn_stream); 557 558 gs_free((char *)swatchMap, BIGSIZE, swatchCount / BIGSIZE + 1, 559 "imagen_print_page(swatchMap)" ); 560 gs_free((char *)out, TotalBytesPerSw, swatchCount+1, "imagen_print_page(out)"); 561 gs_free((char *)in, BIGSIZE, line_size / BIGSIZE + 1, "imagen_print_page(in)"); 562 /* ----------------------------------------- */ 563 564 DebugMsg(1,"Debug: Grey: %d \n",totalGreySwatches); 565 DebugMsg(1,"Debug: Blank: %d \n",totalBlankSwatches ); 566 DebugMsg(1,"%s\n","End of imagen_print_page"); 567 568 /* ----------------------------------------- */ 569 return 0; 570 571 } /* imagen_print_page */ 572