Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!rutgers!rochester!pt.cs.cmu.edu!andrew.cmu.edu!jhm+ From: jhm+@andrew.cmu.edu (Jim Morris) Newsgroups: comp.lang.postscript Subject: Re: Bitmap decompression in PostScript? Message-ID: Date: 31 Jan 89 17:46:24 GMT References: <432@skep2.ATT.COM> <10529@well.UUCP>, <23360@watmath.waterloo.edu> Organization: Carnegie Mellon, Pittsburgh, PA Lines: 275 In-Reply-To: <23360@watmath.waterloo.edu> Here is a program that works for me. It seems to compress a business letter by a factor of 5 and sometimes the printing time as well. Your mileage may vary... ------------------------CUT HERE----------------------------- /* pssqw.c Compression of postscript image files just squeezes the white space */ /* Written Jim Morris (james.morris@andrew.cmu.edu) 7/19/88 derived from a version (pscomp.c) by Ganapathy Krishnan (krishnan@cs.buffalo.edu) (716-636-3197) Morris's work was supported by the NSF EXPRES project. */ #include #ifdef VMS #include #else #include #endif #define BSIZE 10000 /* PS internal buffer size */ #define PSLineSize 72 /* Limit on output lines */ #define LINEBUF 300 #define MinimunF 22 /*default shortest run of f's to encode */ /* This number seems to minimize processing time on a Laserwriter If your printer is different, hopefully faster, revising this number may improve performance. */ #define dig(c) ((c) >= '0' && (c) <= '9' ) #define hdig(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) #define hexdig(c) ( dig(c) || hdig (c)) #define white(c) (c == ' ' || c == '\n' || c=='\t') /* Usage pssqw < file.ps | lpr cc pssqw.c -o pssqw This program accepts a PostScript file and writes out a new one in which all the image commands have been altered to use compressed rasters. Each image command must appear on a line by itself and the image data can contain only hex digits and white space. It is possible for the program to malfunction either by missing an image command or mistaking some innocent text for one. If the next command after the image data starts with a hex digit, e.g. endpage, put a PS comment before it, e.g. %end of image Here is an example of the kind of input expected: %! To be embedded, delete the '!' % Bits are stored left-to-right, bottom-to-top; 1=white, 0=black /width 1016 def /height 1321 def % dimensions in pixels /xScale 0.60 def /yScale 0.60 def % scaling factors width xScale mul height yScale mul scale % set scaling /picstr width 7 add 8 idiv string def % define place to read lines % the "image" operator has five parameters: width height 1 % dimensions [width 0 0 height 0 0] % transform matrix {currentfile picstr readhexstring pop} % bits source image % PRINT IT fff fff fffff ffff fffff ffffffff aab034 f09b ....... showpage Here is the PS program that replaces image: pop % discard standard proc /bz 10000 def % co-ordinate with BSIZE above /bf bz string def %place to build lines /ff bz string def ff 0 255 put /hbz bz 1 add 2 idiv def /i 1 def %fill ff with 255 { % [0...i) contains 255, i < bz ff i % start putting at i ff 0 % start taking from 0 i hbz ge {bz i sub getinterval putinterval exit} {i getinterval putinterval /i i i add def } ifelse } loop { % new proc /len currentfile token pop def len 0 lt {ff 0 len neg getinterval} {currentfile bf 0 len getinterval readhexstring pop} ifelse } bind image A squeezed version appears immediately below. */ static char pscommand[] = { "pop/bz 10000 def/bf bz string def/ff bz string def ff 0 255 put /hbz\n\ bz 1 add 2 idiv def/i 1 def{ff i ff 0 i hbz ge{bz i sub getinterval\n\ putinterval exit}{i getinterval putinterval/i i i add def}ifelse}loop\n\ {/len currentfile token pop def len 0 lt{ff 0 len neg getinterval}\n\ {currentfile bf 0 len getinterval readhexstring pop}ifelse}bind image\n" }; static char line[LINEBUF]; static int nch; /* next character from file */ static int minF = MinimunF; main(argc, argv) int argc; char **argv; { int j; /* get the argument */ while (--argc > 0 && (*++argv)[0] == '-') { while (*++(*argv)) { switch (**argv) { case 'f': minF = atoi (*argv+1); if (minF<6) minF = 6; while (*++(*argv)); --(*argv); break; default: fprintf (stderr, "Usage: pssqw [-f] \n"); exit (1); } } } nch = getchar(); for(; ;) { if (nch == EOF) exit(0); readline(); /* look for line starting with "image" */ for (j=0; white(line[j]); j++) ; if (strncmp(&(line[j]), "image", 5) == 0 ) { printf("%s", pscommand); runlength_encode(); } else { printf("%s\n", line); nch = getchar(); } } } readline() { int i; i=0; /* nch contains the next item of input */ for (;;) { if (i>=LINEBUF) { fprintf(stderr, "Line buffer length exceeded\n"); exit(1); } if(nch =='\n' || nch == EOF) { line[i] = '\0'; return(i); } line[i++] = nch; nch = getchar(); } } runlength_encode() { char duffer[2*BSIZE]; /* double sized buffer */ int size = 2*BSIZE; int done = 0; int i, j, lout; for(;!done;) { /* read in a buffer's worth */ for (size=0;size!=2*BSIZE ;) { nch = getchar(); if white(nch) continue; if (hexdig(nch)) duffer[size++] = nch; else {done = 1; break; } } /* write out duffer[0...size) */ size = (size/2)*2; /* ignore odd character */ for(lout=0;lout!=size;) { /* duffer[0...lout) has been put out */ /* find a string of ff's */ for (i=lout; i!=size; i+=2) { /* duffer[lout..i) contains non F-string */ if(duffer[i] != 'f' && duffer[i] != 'F') continue; for (j=i+1; j!=size; j++) { if (duffer[j] != 'f' && duffer[j] != 'F') break; } /* duffer[i...j) are f's */ j = (j/2)*2; /* must be even */ if(j-i >= minF) break; } /* duffer[lout...i) is non-F stuff */ /* duffer[i...j) are f's if i!=size */ if(i>lout) { PNum((i-lout)/2); for (;lout!=i; lout++) PC(duffer[lout]); } if (lout!=size) { PNum(-(j-i)/2); lout = j; } } } printf("\n"); } #define PSLength 72 static int tlcount = 0; /* there are tlcount chars sent since the last cr */ PC(c) char c; { if (++tlcount >= PSLength) { putchar('\n'); tlcount = 1; } putchar(c); } PNum(n) int n; { int an = n; int length = 0; if (n<0) {an = -n; length = 1; } length += (an>9999) ? 6 : (an>999) ? 5 : (an>99) ? 4 : (an>9) ? 3 : 2; if( (tlcount += length) >= PSLength) { printf("\n"); tlcount = length; } printf("%d ", n); }