/* ** ppmtopict.c - read a portable pixmap and produce a Macintosh PICT2 file. ** ** Copyright (C) 1990 by Ken Yap . ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "ppm.h" #define HEADER_SIZE 512 #define RUN_THRESH 3 #define MAX_RUN 128 /* 0xff = 2, 0xfe = 3, etc */ #define MAX_COUNT 128 /* 0x00 = 1, 0x01 = 2, etc */ /* Opcodes */ #define PICT_NOP 0x00 #define PICT_clipRgn 0x01 #define PICT_bkPat 0x02 #define PICT_txFont 0x03 #define PICT_txFace 0x04 #define PICT_txMode 0x05 #define PICT_spExtra 0x06 #define PICT_pnSize 0x07 #define PICT_pnMode 0x08 #define PICT_pnPat 0x09 #define PICT_thePat 0x0A #define PICT_ovSize 0x0B #define PICT_origin 0x0C #define PICT_txSize 0x0D #define PICT_fgColor 0x0E #define PICT_bkColor 0x0F #define PICT_txRatio 0x10 #define PICT_picVersion 0x11 #define PICT_blPixPat 0x12 #define PICT_pnPixPat 0x13 #define PICT_fillPixPat 0x14 #define PICT_pnLocHFrac 0x15 #define PICT_chExtra 0x16 #define PICT_rgbFgCol 0x1A #define PICT_rgbBkCol 0x1B #define PICT_hiliteMode 0x1C #define PICT_hiliteColor 0x1D #define PICT_defHilite 0x1E #define PICT_opColor 0x1F #define PICT_line 0x20 #define PICT_line_from 0x21 #define PICT_short_line 0x22 #define PICT_short_line_from 0x23 #define PICT_long_text 0x28 #define PICT_DH_text 0x29 #define PICT_DV_text 0x2A #define PICT_DHDV_text 0x2B #define PICT_frameRect 0x30 #define PICT_paintRect 0x31 #define PICT_eraseRect 0x32 #define PICT_invertRect 0x33 #define PICT_fillRect 0x34 #define PICT_frameSameRect 0x38 #define PICT_paintSameRect 0x39 #define PICT_eraseSameRect 0x3A #define PICT_invertSameRect 0x3B #define PICT_fillSameRect 0x3C #define PICT_frameRRect 0x40 #define PICT_paintRRect 0x41 #define PICT_eraseRRect 0x42 #define PICT_invertRRect 0x43 #define PICT_fillRRect 0x44 #define PICT_frameSameRRect 0x48 #define PICT_paintSameRRect 0x49 #define PICT_eraseSameRRect 0x4A #define PICT_invertSameRRect 0x4B #define PICT_fillSameRRect 0x4C #define PICT_frameOval 0x50 #define PICT_paintOval 0x51 #define PICT_eraseOval 0x52 #define PICT_invertOval 0x53 #define PICT_fillOval 0x54 #define PICT_frameSameOval 0x58 #define PICT_paintSameOval 0x59 #define PICT_eraseSameOval 0x5A #define PICT_invertSameOval 0x5B #define PICT_fillSameOval 0x5C #define PICT_frameArc 0x60 #define PICT_paintArc 0x61 #define PICT_eraseArc 0x62 #define PICT_invertArc 0x63 #define PICT_fillArc 0x64 #define PICT_frameSameArc 0x68 #define PICT_paintSameArc 0x69 #define PICT_eraseSameArc 0x6A #define PICT_invertSameArc 0x6B #define PICT_fillSameArc 0x6C #define PICT_framePoly 0x70 #define PICT_paintPoly 0x71 #define PICT_erasePoly 0x72 #define PICT_invertPoly 0x73 #define PICT_fillPoly 0x74 #define PICT_frameSamePoly 0x78 #define PICT_paintSamePoly 0x79 #define PICT_eraseSamePoly 0x7A #define PICT_invertSamePoly 0x7B #define PICT_fillSamePoly 0x7C #define PICT_frameRgn 0x80 #define PICT_paintRgn 0x81 #define PICT_eraseRgn 0x82 #define PICT_invertRgn 0x83 #define PICT_fillRgn 0x84 #define PICT_frameSameRgn 0x88 #define PICT_paintSameRgn 0x89 #define PICT_eraseSameRgn 0x8A #define PICT_invertSameRgn 0x8B #define PICT_fillSameRgn 0x8C #define PICT_BitsRect 0x90 #define PICT_BitsRgn 0x91 #define PICT_PackBitsRect 0x98 #define PICT_PackBitsRgn 0x99 #define PICT_shortComment 0xA0 #define PICT_longComment 0xA1 #define PICT_EndOfPicture 0xFF #define PICT_headerOp 0x0C00 static void putFill ARGS(( FILE *fd, int n )); static void putShort ARGS(( FILE *fd, int i )); static void putLong ARGS(( FILE *fd, long i )); static void putFixed ARGS(( FILE *fd, int in, int frac )); static void putRect ARGS(( FILE *fd, int x1, int x2, int y1, int y2 )); static int putRow ARGS(( FILE *fd, int row, int cols, pixel *rowpixels, char *packed )); #define MAXCOLORS 256 static colorhash_table cht; int main(argc, argv) int argc; char *argv[]; { FILE *ifp; int argn, rows, cols, colors, i, row, oc; register pixel **pixels; char *packed; pixval maxval; long lmaxval, rval, gval, bval; colorhist_vector chv; ppm_init( &argc, argv ); argn = 1; if (argn < argc) { ifp = pm_openr(argv[1]); argn++; } else ifp = stdin; if (argn != argc) pm_usage("[ppmfile]"); pixels = ppm_readppm(ifp, &cols, &rows, &maxval); if (cols < 8) pm_error("ppm input too narrow, must be >= 8 pixels wide" ); lmaxval = (long)maxval; pm_close(ifp); /* Figure out the colormap. */ pm_message("computing colormap..." ); chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors); if (chv == (colorhist_vector) 0) pm_error("too many colors - try doing a 'pnmquant %d'", MAXCOLORS); pm_message("%d colors found", colors ); /* Make a hash table for fast color lookup. */ cht = ppm_colorhisttocolorhash(chv, colors); /* write the header */ putFill(stdout, HEADER_SIZE); /* write picSize and picFrame */ putShort(stdout, 0); putRect(stdout, 0, 0, rows, cols); /* write version op and version */ putShort(stdout, PICT_picVersion); putShort(stdout, 0x02FF); putShort(stdout, PICT_headerOp); putLong(stdout, -1L); putFixed(stdout, 0, 0); putFixed(stdout, 0, 0); putFixed(stdout, cols, 0); putFixed(stdout, rows, 0); putFill(stdout, 4); /* seems to be needed by many PICT2 programs */ putShort(stdout, PICT_clipRgn); putShort(stdout, 10); putRect(stdout, 0, 0, rows, cols); /* write picture */ putShort(stdout, PICT_PackBitsRect); putShort(stdout, cols | 0x8000); putRect(stdout, 0, 0, rows, cols); putShort(stdout, 0); /* pmVersion */ putShort(stdout, 0); /* packType */ putLong(stdout, 0L); /* packSize */ putFixed(stdout, 72, 0); /* hRes */ putFixed(stdout, 72, 0); /* vRes */ putShort(stdout, 0); /* pixelType */ putShort(stdout, 8); /* pixelSize */ putShort(stdout, 1); /* cmpCount */ putShort(stdout, 8); /* cmpSize */ putLong(stdout, 0L); /* planeBytes */ putLong(stdout, 0L); /* pmTable */ putLong(stdout, 0L); /* pmReserved */ putLong(stdout, 0L); /* ctSeed */ putShort(stdout, 0); /* ctFlags */ putShort(stdout, colors-1); /* ctSize */ /* Write out the colormap. */ for (i = 0; i < colors; i++) { putShort(stdout, i); rval = PPM_GETR(chv[i].color); gval = PPM_GETG(chv[i].color); bval = PPM_GETB(chv[i].color); if (lmaxval != 65535L) { rval = rval * 65535L / lmaxval; gval = gval * 65535L / lmaxval; bval = bval * 65535L / lmaxval; } putShort(stdout, (short)rval); putShort(stdout, (short)gval); putShort(stdout, (short)bval); } putRect(stdout, 0, 0, rows, cols); /* srcRect */ putRect(stdout, 0, 0, rows, cols); /* dstRect */ putShort(stdout, 0); /* mode */ /* Finally, write out the data. */ packed = (char*) malloc((unsigned)(cols+cols/MAX_COUNT+1)); oc = 0; for (row = 0; row < rows; row++) oc += putRow(stdout, row, cols, pixels[row], packed); /* if we wrote an odd number of pixdata bytes, pad */ if (oc & 1) (void) putc(0, stdout); putShort(stdout, PICT_EndOfPicture); lmaxval = ftell(stdout) - HEADER_SIZE; if (fseek(stdout, (long)HEADER_SIZE, 0) >= 0) putShort(stdout, (short)(lmaxval & 0xffff)); exit(0); } static void putFill(fd, n) FILE *fd; int n; { register int i; for (i = 0; i < n; i++) (void) putc(0, fd); } static void putShort(fd, i) FILE *fd; int i; { (void) putc((i >> 8) & 0xff, fd); (void) putc(i & 0xff, fd); } static void putLong( FILE *fd, long i ) { (void) putc((int)((i >> 24) & 0xff), fd); (void) putc(((int)(i >> 16) & 0xff), fd); (void) putc(((int)(i >> 8) & 0xff), fd); (void) putc((int)(i & 0xff), fd); } static void putFixed(fd, in, frac) FILE *fd; int in, frac; { putShort(fd, in); putShort(fd, frac); } static void putRect(fd, x1, x2, y1, y2) FILE *fd; int x1, x2, y1, y2; { putShort(fd, x1); putShort(fd, x2); putShort(fd, y1); putShort(fd, y2); } #define RUNLENGTH #ifdef RUNLENGTH #define runtochar(c) (257-(c)) #define counttochar(c) ((c)-1) static int putRow(fd, row, cols, rowpixels, packed) FILE *fd; int row, cols; pixel *rowpixels; char *packed; { register int i; int packcols, count, run, rep, oc; register pixel *pP; pixel lastp; register char *p; run = count = 0; for (cols--, i = cols, pP = rowpixels + cols, p = packed, lastp = *pP; i >= 0; i--, lastp = *pP, pP--) { if (PPM_EQUAL(lastp, *pP)) run++; else if (run < RUN_THRESH) { while (run > 0) { *p++ = ppm_lookupcolor(cht, &lastp); run--; count++; if (count == MAX_COUNT) { *p++ = counttochar(MAX_COUNT); count -= MAX_COUNT; } } run = 1; } else { if (count > 0) *p++ = counttochar(count); count = 0; while (run > 0) { rep = run > MAX_RUN ? MAX_RUN : run; *p++ = ppm_lookupcolor(cht, &lastp); *p++ = runtochar(rep); run -= rep; } run = 1; } } if (run < RUN_THRESH) { while (run > 0) { *p++ = ppm_lookupcolor(cht, &lastp); run--; count++; if (count == MAX_COUNT) { *p++ = counttochar(MAX_COUNT); count -= MAX_COUNT; } } } else { if (count > 0) *p++ = counttochar(count); count = 0; while (run > 0) { rep = run > MAX_RUN ? MAX_RUN : run; *p++ = ppm_lookupcolor(cht, &lastp); *p++ = runtochar(rep); run -= rep; } run = 1; } if (count > 0) *p++ = counttochar(count); packcols = p - packed; /* how many did we write? */ if (cols > 200) { putShort(fd, packcols); oc = packcols + 2; } else { (void) putc(packcols, fd); oc = packcols + 1; } /* now write out the packed row */ while(p != packed) { --p; (void) putc(*p, fd); } return (oc); } #else /* RUNLENGTH */ /* real dumb putRow with no compression */ static int putRow(fd, row, cols, rowpixels, packed) FILE *fd; int row, cols; pixel *rowpixels; char *packed; { register int i, j, bc, oc; register pixel *pP; #if notdef bzero(aux, cols); /* aux?? */ #endif /*notdef*/ bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT; if (bc > 200) { putShort(fd, bc); oc = bc + 2; } else { (void) putc(bc, fd); oc = bc + 1; } for (i = 0, pP = rowpixels; i < cols;) { if (cols - i > MAX_COUNT) { (void) putc(MAX_COUNT - 1, fd); for (j = 0; j < MAX_COUNT; j++) { (void) putc(ppm_lookupcolor(cht, pP), fd); pP++; } i += MAX_COUNT; } else { (void) putc(cols - i - 1, fd); for (j = 0; j < cols - i; j++) { (void) putc(ppm_lookupcolor(cht, pP), fd); pP++; } i = cols; } } return (oc); } #endif /* RUNLENGTH */