/* * compress HP PCL-format bit image data * usage: pcl_pack input output * copyright 1990 Digital Insight */ #include #include #include #include #define MAX_RUN 128 /* max compressed run length */ char inbuf[4096]; /* image input buffer */ char pbuf[4096]; /* packed output buffer */ char esbuf[100]; /* escape sequence buffer */ char rawbuf[8192]; /* raw input buffer */ char *rawptr = rawbuf; /* current position in buffer */ int rawbytes; /* bytes left in buffer */ FILE *in_fp; FILE *out_fp; /* * Abort program with error message */ void fail(char *msg) { puts(msg); exit(1); } /* * Buffered input from in_fp. Used in place of fread() to speed things up * (depending on the stream I/O library's own buffer size) */ int bfread(char *buf, int nbytes) { int bytes_read = 0; /* bytes read so far */ register int partial; /* partial transfer count */ while (nbytes > 0) { if (rawbytes == 0) { /* buffer empty, get some more */ rawbytes = fread(rawptr=rawbuf, 1, sizeof(rawbuf), in_fp); if (rawbytes == 0) break; } partial = nbytes; /* transfer data from buffer */ if (partial > rawbytes) partial = rawbytes; memcpy(buf, rawptr, partial); bytes_read += partial; rawptr += partial; buf += partial; nbytes -= partial; rawbytes -= partial; } return bytes_read; } /* * Buffered input from in_fp. Used in place of fgetc() to speed things up * (depending on the stream I/O library's own buffer size) */ int bfgetc(void) { if (rawbytes == 0) { /* buffer empty, get some more */ rawbytes = fread(rawptr=rawbuf, 1, sizeof(rawbuf), in_fp); if (rawbytes == 0) return EOF; } rawbytes--; return *rawptr++; } /* * Copy input to output up to next escape sequence; * save sequence in esbuf[]. Return sequence length. */ int read_seq(void) { int c; char *seq = esbuf; do { /* read up to escape char */ if ((c = bfgetc()) == EOF) exit(0); /* done! */ fputc(c, out_fp); } while (c != 0x1B); do { /* read seq thru uppercase char */ *seq++ = c = bfgetc(); if (c == EOF) fail("unexpected end of input"); } while (!isupper(c)); *seq = 0; /* terminate sequence */ return seq-esbuf; } /* * Read line of image data into inbuf; return length. * Any other data (text, escape sequences) are sent directly to output. */ int read_line(void) { register int n; char *pos; for (;;) { /* look for [esc]*b...W/M */ n = read_seq(); if (n < 3 || esbuf[0] != '*' || esbuf[1] != 'b') { /* some other seq, send out */ fwrite(esbuf, 1, n, out_fp); continue; } for (pos=esbuf+2; *pos; pos++) { /* get # */ n = (int)strtol(pos, &pos, 10); switch (*pos) { case 'W': /* found image data */ goto got_image; case 'm': /* compression mode */ case 'M': if (n != 0) fail("Input is already compressed"); break; default: /* some other sequence */ /* split off and output */ if (islower(*pos)) *pos = toupper(*pos); fprintf(out_fp, "*b%d%c\1xB", n, *pos++); } } } got_image: if (bfread(inbuf, n) != n) fail("Unexpected end of input"); while (n>1 && inbuf[n-1] == 0) /* remove trailing zero bytes */ n--; return n; } /* * Pack image data lines */ void pack(void) { static int first=1; /* first time? */ register char *rptr; /* repeat pointer */ register char *bptr; /* input buffer position */ char *bend; /* end of input */ char *pptr; /* pack buffer position */ int n, cnt; for (;;) { n = read_line(); /* (last output was [esc]) */ bend = inbuf+n; for (bptr=inbuf, pptr=pbuf; bptr 1) { n = (cnt < MAX_RUN) ? cnt : MAX_RUN; *pptr++ = 1 - n; *pptr++ = *bptr; cnt -= n; bptr += n; } /* finished with repeat run? */ if (rptr >= bend) break; /* find number of non-repeated bytes */ for (rptr=bptr+1; rptr= bend) cnt++; while (cnt > 0) { n = (cnt < MAX_RUN) ? cnt : MAX_RUN; *pptr++ = n - 1; memcpy(pptr, bptr, n); cnt -= n; bptr += n; pptr += n; } } n = pptr - pbuf; if (first) { /* set compaction mode */ first = 0; /* (note: ESC already output) */ fwrite("*b2M\x1B", 5, 1, out_fp); } /* output compressed image data */ fprintf(out_fp, "*b%dW", n); if (fwrite(pbuf, 1, n, out_fp) != n) fail("can't write output"); } } main(int argc, char **argv) { if (argc != 3) { puts("Compress HP PCL-format graphics file"); puts("(c) Copyright 1990 Digital Insight"); puts("Usage: pcl_pack "); exit(1); } if ((in_fp = fopen(argv[1], "rb")) == NULL) { perror(argv[1]); exit(1); } if ((out_fp = fopen(argv[2], "wb")) == NULL) { perror(argv[2]); exit(1); } pack(); }