diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-03-27 01:38:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-03-27 01:38:28 +0000 |
commit | 367c9cb514c9da766488b9bdb218a18e31cb7624 (patch) | |
tree | f9e343be94161a4837f0f1c1d072a35538ae0f63 /converter/ppm/picttoppm.c | |
parent | 6e88e3326cb0c7f7975b56189278cab3f84ba1bd (diff) | |
download | netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.gz netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.tar.xz netpbm-mirror-367c9cb514c9da766488b9bdb218a18e31cb7624.zip |
Promote Stable (10.47) to Super Stable
git-svn-id: http://svn.code.sf.net/p/netpbm/code/super_stable@2691 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/ppm/picttoppm.c')
-rw-r--r-- | converter/ppm/picttoppm.c | 1436 |
1 files changed, 991 insertions, 445 deletions
diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index d52963fc..9a7d8e7c 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -94,16 +94,16 @@ struct rgbPlanes { word * blu; }; +struct canvas { + struct rgbPlanes planes; +}; + typedef void (*transfer_func) (struct RGBColor* src, struct RGBColor* dst); -static const char* stage; +static const char * stage; static struct Rect picFrame; -static word* red; -static word* green; -static word* blue; static word rowlen; static word collen; -static longword planelen; static int verbose; static int fullres; static int recognize_comment; @@ -142,13 +142,6 @@ static int ps_cent_x; static int ps_cent_y; static int ps_cent_set; -struct opdef { - const char* name; - int len; - void (*impl) (int); - const char* description; -}; - struct raster { /*---------------------------------------------------------------------------- An image raster. May be either truecolor or paletted. @@ -178,13 +171,28 @@ struct raster { }; + static void allocateRaster(struct raster * const rasterP, unsigned int const width, unsigned int const height, unsigned int const bitsPerPixel) { +/*---------------------------------------------------------------------------- + Allocate storage for a raster that can contain a 'width' x 'height' + pixel rectangle read from a PICT image with 'bitsPerPixel' bits + per pixel. + + Make the space large enough to round the number of pixels up to a + multiple of 16, because we've seen many images in which the PICT raster + does contain that much padding on the right. I don't know why; I could + understand a multiple of 8, since in 1 bpp image, the smallest unit + expressable in PICT is 8 pixels. But why 16? The images we saw came + from Adobe Illustrator 10 in March 2007, supplied by + Guillermo Gómez Valcárcel. +-----------------------------------------------------------------------------*/ + unsigned int const allocWidth = ROUNDUP(width, 16); - if (width > UINT_MAX/4) + if (width > UINT_MAX/4 - 16) pm_error("Width %u pixels too large for arithmetic", width); rasterP->rowCount = height; @@ -209,16 +217,16 @@ allocateRaster(struct raster * const rasterP, We have yet to see if we can properly interpret the data. */ - rasterP->rowSize = width * 4; + rasterP->rowSize = allocWidth * 4; break; case 16: - rasterP->rowSize = width * 2; + rasterP->rowSize = allocWidth * 2; break; case 8: case 4: case 2: case 1: - rasterP->rowSize = width * 1; + rasterP->rowSize = allocWidth * 1; break; default: pm_error("INTERNAL ERROR: impossible bitsPerPixel value in " @@ -248,13 +256,30 @@ struct blit_info { struct raster srcplane; int pixSize; struct Rect dstRect; - struct RGBColor * color_map; + struct RGBColor * colorMap; int mode; struct blit_info * next; }; -static struct blit_info* blit_list = 0; -static struct blit_info** last_bl = &blit_list; +typedef struct { + struct blit_info * firstP; + struct blit_info ** connectorP; + bool unblittableText; + /* The image contains text opcodes, and we don't know how to put that + in a blit list (I really don't even know what a blit _is_), so + the image information here is incomplete. + */ +} blitList; + + +typedef void (drawFn)(struct canvas *, blitList *, int); + +struct opdef { + const char* name; + int len; + drawFn * impl; + const char* description; +}; #define WORD_LEN (-1) @@ -589,15 +614,25 @@ picComment(word const type, +static drawFn ShortComment; + static void -ShortComment(int const version) { +ShortComment(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + picComment(read_word(), 0); } +static drawFn LongComment; + static void -LongComment(int const version) { +LongComment(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + word type; type = read_word(); @@ -606,8 +641,13 @@ LongComment(int const version) { +static drawFn skip_poly_or_region; + static void -skip_poly_or_region(int const version) { +skip_poly_or_region(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + stage = "skipping polygon or region"; skip(read_word() - 2); } @@ -639,56 +679,98 @@ static struct fontinfo** fontlist_ins = &fontlist; +static void +tokenize(char * const s, + const char ** const vec, + unsigned int const vecSize, + unsigned int * const nTokenP) { + + unsigned int nToken; + char * p; + + p = &s[0]; /* start at beginning of string */ + nToken = 0; /* no tokens yet */ + + while (*p && nToken < vecSize - 1) { + if (ISSPACE(*p)) + *p++ = '\0'; + else { + vec[nToken++] = p; + /* Skip to next non-space character or end */ + while (*p && !ISSPACE(*p)) + ++p; + } + } + vec[nToken] = NULL; + + *nTokenP = nToken; +} + + + +static void +parseFontLine(const char ** const token, + struct fontinfo ** const fontinfoPP) { + + struct fontinfo * fontinfoP; + + MALLOCVAR(fontinfoP); + if (fontinfoP == NULL) + pm_error("out of memory for font information"); + MALLOCARRAY(fontinfoP->filename, strlen(token[3] + 1)); + if (fontinfoP->filename == NULL) + pm_error("out of memory for font information file name"); + + fontinfoP->font = atoi(token[0]); + fontinfoP->size = atoi(token[1]); + fontinfoP->style = atoi(token[2]); + strcpy(fontinfoP->filename, token[3]); + fontinfoP->loaded = 0; + + *fontinfoPP = fontinfoP; +} + + + static int load_fontdir(const char * const dirfile) { /*---------------------------------------------------------------------------- Load the font directory from file named 'dirfile'. Add its contents to the global list of fonts 'fontlist'. -----------------------------------------------------------------------------*/ - FILE* fp; - int n, nfont; - char* arg[5], line[1024]; - struct fontinfo* fontinfo; + FILE * ifP; + unsigned int nFont; + char line[1024]; - if (!(fp = fopen(dirfile, "rb"))) - return -1; - - nfont = 0; - while (fgets(line, 1024, fp)) { - if ((n = mk_argvn(line, arg, 5)) == 0 || arg[0][0] == '#') - continue; - if (n != 4) - continue; - MALLOCVAR(fontinfo); - if (fontinfo == NULL) - pm_error("out of memory for font information"); - MALLOCARRAY(fontinfo->filename, strlen(arg[3] + 1)); - if (fontinfo->filename == NULL) - pm_error("out of memory for font information file name"); + ifP = pm_openr(dirfile); - fontinfo->font = atoi(arg[0]); - fontinfo->size = atoi(arg[1]); - fontinfo->style = atoi(arg[2]); - strcpy(fontinfo->filename, arg[3]); - fontinfo->loaded = 0; + nFont = 0; + while (fgets(line, 1024, ifP) && nFont < INT_MAX) { + const char * token[10]; + unsigned int nToken; - fontinfo->next = 0; - *fontlist_ins = fontinfo; - fontlist_ins = &fontinfo->next; - nfont++; - } + tokenize(line, token, ARRAY_SIZE(token), &nToken); - return nfont; -} + if (nToken == 0) { + /* blank line - ignore */ + } else if (token[0][0] == '#') { + /* comment - ignore */ + } else if (nToken != 4) { + /* Unrecognized format - ignore */ + } else { + struct fontinfo * fontinfoP; + parseFontLine(token, &fontinfoP); + fontinfoP->next = 0; + *fontlist_ins = fontinfoP; + fontlist_ins = &fontinfoP->next; + ++nFont; + } + } + pm_close(ifP); -static void -read_rect(struct Rect * const r) { - r->top = read_word(); - r->left = read_word(); - r->bottom = read_word(); - r->right = read_word(); + return nFont; } @@ -705,6 +787,26 @@ dumpRect(const char * const label, +static void +read_rect(struct Rect * const r) { + + r->top = read_word(); + r->left = read_word(); + r->bottom = read_word(); + r->right = read_word(); + + if (r->top > r->bottom || r->right < r->left) + dumpRect("Invalid rectangle", *r); + + if (r->top > r->bottom) + pm_error("Invalid PICT: a rectangle has a top below its bottom"); + if (r->right < r->left) + pm_error("Invalid PICT: a rectangle has a right edge " + "left of its left edge"); +} + + + static int rectwidth(const struct Rect * const r) { return r->right - r->left; @@ -720,10 +822,10 @@ rectheight(const struct Rect * const r) { static bool -rectsamesize(const struct Rect * const r1, - const struct Rect * const r2) { - return r1->right - r1->left == r2->right - r2->left && - r1->bottom - r1->top == r2->bottom - r2->top ; +rectsamesize(struct Rect const r1, + struct Rect const r2) { + return r1.right - r1.left == r2.right - r2.left && + r1.bottom - r1.top == r2.bottom - r2.top ; } @@ -753,20 +855,45 @@ rectscale(struct Rect * const r, -static struct blit_info* -add_blit_list(void) { +static void + initBlitList(blitList * const blitListP) { - struct blit_info * bi; + blitListP->firstP = NULL; + blitListP->connectorP = &blitListP->firstP; + blitListP->unblittableText = false; +} + + + +static void +addBlitList(blitList * const blitListP, + struct Rect const srcRect, + struct Rect const srcBounds, + struct raster const srcplane, + int const pixSize, + struct Rect const dstRect, + struct RGBColor * const colorMap, + int const mode) { + + struct blit_info * biP; - MALLOCVAR(bi); - if (bi == NULL) + MALLOCVAR(biP); + if (biP == NULL) pm_error("out of memory for blit list"); - - bi->next = 0; - *last_bl = bi; - last_bl = &bi->next; - - return bi; + else { + biP->srcRect = srcRect; + biP->srcBounds = srcBounds; + biP->srcplane = srcplane; + biP->pixSize = pixSize; + biP->dstRect = dstRect; + biP->colorMap = colorMap; + biP->mode = mode; + + biP->next = NULL; + + *blitListP->connectorP = biP; + blitListP->connectorP = &biP->next; + } } @@ -1026,7 +1153,7 @@ static pixval redepth(pixval const c, pixval const oldMaxval) { - return (c * PPM_MAXMAXVAL + oldMaxval / 2) / oldMaxval; + return ROUNDDIV(c * PPM_MAXMAXVAL, oldMaxval); } @@ -1245,8 +1372,6 @@ doSameSize(transfer_func trf, struct rgbPlanes const dst, unsigned int const dstwid) { /*---------------------------------------------------------------------------- - Generalized (but slow) blit. - Transfer pixels from 'src' to 'dst', applying the transfer function 'trf'. @@ -1419,18 +1544,30 @@ blitIdempotent(unsigned int const pixSize, static void -generalBlit(struct Rect const srcRect, - struct Rect const srcBounds, - struct raster const srcplane, - int const pixSize, - struct Rect const dstRect, - struct Rect const dstBounds, - int const dstwid, - struct RGBColor * const color_map, - int const mode, - struct Rect const clipsrc, - struct Rect const clipdst) { - +doBlit(struct Rect const srcRect, + struct Rect const dstRect, + struct Rect const srcBounds, + struct raster const srcplane, + struct Rect const dstBounds, + struct rgbPlanes const canvasPlanes, + int const pixSize, + int const dstwid, + struct RGBColor * const color_map, + int const mode) { +/*---------------------------------------------------------------------------- + Transfer some pixels from 'srcplane' to 'canvasPlanes', applying the + transfer function 'trf'. + + 'srcplane' contains the rectangle 'srcBounds' of the image. + 'canvasPlanes' contains the rectangle 'dstRect' of the image. + + Take the rectangle 'srcRect' of the source image and copy it to the + rectangle 'dstRec' of the destination image. + + Each plane of 'canvasPlanes' is one word per pixel and contains actual + colors, never a palette index. It is an array in row-major order + with 'dstwid' words per row. +-----------------------------------------------------------------------------*/ unsigned char * src; struct rgbPlanes dst; int dstoff; @@ -1440,31 +1577,31 @@ generalBlit(struct Rect const srcRect, transfer_func trf; if (verbose) { - dumpRect("copying from:", clipsrc); - dumpRect("to: ", clipdst); + dumpRect("copying from:", srcRect); + dumpRect("to: ", dstRect); pm_message("a %u x %u area to a %u x %u area", - rectwidth(&clipsrc), rectheight(&clipsrc), - rectwidth(&clipdst), rectheight(&clipdst)); + rectwidth(&srcRect), rectheight(&srcRect), + rectwidth(&dstRect), rectheight(&dstRect)); } { unsigned int const pkpixsize = pixSize == 16 ? 2 : 1; - unsigned int const srcRowNumber = clipsrc.top - srcBounds.top; + unsigned int const srcRowNumber = srcRect.top - srcBounds.top; unsigned int const srcRowOffset = - (clipsrc.left - srcBounds.left) * pkpixsize; + (srcRect.left - srcBounds.left) * pkpixsize; assert(srcRowNumber < srcplane.rowCount); assert(srcRowOffset < srcplane.rowSize); src = srcplane.bytes + srcRowNumber * srcplane.rowSize + srcRowOffset; - xsize = clipsrc.right - clipsrc.left; - ysize = clipsrc.bottom - clipsrc.top; + xsize = rectwidth(&srcRect); + ysize = rectheight(&srcRect); srcadd = srcplane.rowSize - xsize * pkpixsize; } - dstoff = (clipdst.top - dstBounds.top) * dstwid + - (clipdst.left - dstBounds.left); - dst.red = red + dstoff; - dst.grn = green + dstoff; - dst.blu = blue + dstoff; + dstoff = (dstRect.top - dstBounds.top) * dstwid + + (dstRect.left - dstBounds.left); + dst.red = canvasPlanes.red + dstoff; + dst.grn = canvasPlanes.grn + dstoff; + dst.blu = canvasPlanes.blu + dstoff; /* get rid of Text mask mode bit, if (erroneously) set */ if ((mode & ~64) == 0) @@ -1472,8 +1609,8 @@ generalBlit(struct Rect const srcRect, else trf = transfer(mode & ~64); - if (!rectsamesize(&clipsrc, &clipdst)) - doDiffSize(clipsrc, clipdst, pixSize, xsize, ysize, + if (!rectsamesize(srcRect, dstRect)) + doDiffSize(srcRect, dstRect, pixSize, xsize, ysize, trf, color_map, src, srcplane.rowSize, dst, dstwid); else { if (trf == NULL) @@ -1491,12 +1628,22 @@ static int blit(struct Rect const srcRect, struct Rect const srcBounds, struct raster const srcplane, + struct canvas * const canvasP, + blitList * const blitListP, int const pixSize, struct Rect const dstRect, struct Rect const dstBounds, int const dstwid, struct RGBColor * const color_map, int const mode) { +/*---------------------------------------------------------------------------- + 'srcplane' contains the rectangle 'srcBounds' of the image. + + We transfer rectangle 'srcRect' from that. + + if 'blitListP' is non-null, we don't draw anything on 'canvasP'; instead, + we add to the list *blitlistP a description of what needs to be drawn. +-----------------------------------------------------------------------------*/ /* I can't tell what the result value of this function is supposed to mean, but I found several return statements that did not set it to anything, @@ -1511,9 +1658,7 @@ blit(struct Rect const srcRect, retval = 1; else { /* Almost got it. Clip source rect with source bounds. - clip dest rect with dest bounds. If source and - destination are not the same size, use Pnmscale - to get a nicely sized rectangle. + clip dest rect with dest bounds. */ struct Rect clipsrc; struct Rect clipdst; @@ -1521,22 +1666,16 @@ blit(struct Rect const srcRect, rectinter(srcBounds, srcRect, &clipsrc); rectinter(dstBounds, dstRect, &clipdst); - if (fullres) { - struct blit_info * bi; - bi = add_blit_list(); - bi->srcRect = clipsrc; - bi->srcBounds = srcBounds; - bi->srcplane = srcplane; - bi->pixSize = pixSize; - bi->dstRect = clipdst; - bi->color_map = color_map; - bi->mode = mode; + if (blitListP) { + addBlitList(blitListP, + clipsrc, srcBounds, srcplane, pixSize, + clipdst, color_map, mode); retval = 0; } else { - generalBlit(srcRect, srcBounds, srcplane, pixSize, - dstRect, dstBounds, dstwid, color_map, mode, - clipsrc, clipdst); + doBlit(clipsrc, clipdst, + srcBounds, srcplane, dstBounds, canvasP->planes, + pixSize, dstwid, color_map, mode); retval = 1; } @@ -1553,17 +1692,15 @@ blit(struct Rect const srcRect, */ static void -allocPlanes(struct rgbPlanes * const planesP) { - - struct rgbPlanes planes; +allocPlanes(unsigned int const width, + unsigned int const height, + struct rgbPlanes * const planesP) { - rowlen = picFrame.right - picFrame.left; - collen = picFrame.bottom - picFrame.top; + unsigned int const planelen = width * height; - clip_rect = picFrame; + struct rgbPlanes planes; - planelen = rowlen * collen; - MALLOCARRAY(planes.red, planelen); + MALLOCARRAY(planes.red, planelen); MALLOCARRAY(planes.grn, planelen); MALLOCARRAY(planes.blu, planelen); if (planes.red == NULL || planes.grn == NULL || planes.blu == NULL) @@ -1575,14 +1712,6 @@ allocPlanes(struct rgbPlanes * const planesP) { memset(planes.blu, 255, planelen * sizeof(word)); *planesP = planes; - - /* Until we wean this program off of global variables, we have to - set these: - */ - - red = planes.red; - green = planes.grn; - blue = planes.blu; } @@ -1606,9 +1735,31 @@ compact(word const input) { static void -do_blits(struct rgbPlanes * const planesP) { +reportBlitList(blitList * const blitListP) { + + if (verbose) { + unsigned int count; + struct blit_info * biP; + + for (count = 0, biP = blitListP->firstP; biP; biP = biP->next) + ++count; + + pm_message("# blits: %u", count); + } +} + + + +static void +doBlitList(struct canvas * const canvasP, + blitList * const blitListP) { +/*---------------------------------------------------------------------------- + Do the list of blits *blitListP, drawing on canvas *canvasP. - struct blit_info* bi; + We allocate new plane data structures in *canvasP. We assume it doesn't + have them already. +-----------------------------------------------------------------------------*/ + struct blit_info * bi; int srcwidth, dstwidth, srcheight, dstheight; double scale, scalelow, scalehigh; double xscale = 1.0; @@ -1616,9 +1767,11 @@ do_blits(struct rgbPlanes * const planesP) { double lowxscale, highxscale, lowyscale, highyscale; int xscalecalc = 0, yscalecalc = 0; + reportBlitList(blitListP); + fullres = 0; - for (bi = blit_list; bi; bi = bi->next) { + for (bi = blitListP->firstP; bi; bi = bi->next) { srcwidth = rectwidth(&bi->srcRect); dstwidth = rectwidth(&bi->dstRect); srcheight = rectheight(&bi->srcRect); @@ -1694,29 +1847,34 @@ do_blits(struct rgbPlanes * const planesP) { } if (xscale != 1.0 || yscale != 1.0) { - for (bi = blit_list; bi; bi = bi->next) - rectscale(&bi->dstRect, xscale, yscale); + struct blit_info * biP; + + for (biP = blitListP->firstP; biP; biP = biP->next) + rectscale(&biP->dstRect, xscale, yscale); - pm_message("Scaling output by %f in X and %f in Y", - xscale, yscale); + pm_message("Scaling output by %f in X and %f in Y", xscale, yscale); rectscale(&picFrame, xscale, yscale); } - allocPlanes(planesP); + rowlen = picFrame.right - picFrame.left; + collen = picFrame.bottom - picFrame.top; + + allocPlanes(rowlen, collen, &canvasP->planes); - for (bi = blit_list; bi; bi = bi->next) { - blit(bi->srcRect, bi->srcBounds, bi->srcplane, - bi->pixSize, - bi->dstRect, picFrame, rowlen, - bi->color_map, - bi->mode); + clip_rect = picFrame; + + for (bi = blitListP->firstP; bi; bi = bi->next) { + doBlit(bi->srcRect, bi->dstRect, + bi->srcBounds, bi->srcplane, picFrame, canvasP->planes, + bi->pixSize, rowlen, bi->colorMap, bi->mode); } } static void -outputPpm(struct rgbPlanes const planes) { +outputPpm(FILE * const ofP, + struct rgbPlanes const planes) { unsigned int width; unsigned int height; @@ -1732,7 +1890,7 @@ outputPpm(struct rgbPlanes const planes) { width = picFrame.right - picFrame.left; height = picFrame.bottom - picFrame.top; - ppm_writeppminit(stdout, width, height, PPM_MAXMAXVAL, 0); + ppm_writeppminit(ofP, width, height, PPM_MAXMAXVAL, 0); pixelrow = ppm_allocrow(width); srcCursor = 0; for (row = 0; row < height; ++row) { @@ -1745,9 +1903,8 @@ outputPpm(struct rgbPlanes const planes) { ); ++srcCursor; } - ppm_writeppmrow(stdout, pixelrow, width, PPM_MAXMAXVAL, 0); + ppm_writeppmrow(ofP, pixelrow, width, PPM_MAXMAXVAL, 0); } - pm_close(stdout); } @@ -1773,8 +1930,13 @@ get_op(int const version) { +static drawFn Clip; + static void -Clip(int const version) { +Clip(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + word len; len = read_word(); @@ -1791,8 +1953,13 @@ Clip(int const version) { +static drawFn OpColor; + static void -OpColor(int const version) { +OpColor(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + op_color.red = read_word(); op_color.grn = read_word(); op_color.blu = read_word(); @@ -1806,17 +1973,17 @@ read_pixmap(struct pixMap * const p) { stage = "getting pixMap header"; read_rect(&p->Bounds); - p->version = read_word(); - p->packType = read_word(); - p->packSize = read_long(); - p->hRes = read_long(); - p->vRes = read_long(); - p->pixelType = read_word(); - p->pixelSize = read_word(); - p->cmpCount = read_word(); - p->cmpSize = read_word(); + p->version = read_word(); + p->packType = read_word(); + p->packSize = read_long(); + p->hRes = read_long(); + p->vRes = read_long(); + p->pixelType = read_word(); + p->pixelSize = read_word(); + p->cmpCount = read_word(); + p->cmpSize = read_word(); p->planeBytes = read_long(); - p->pmTable = read_long(); + p->pmTable = read_long(); p->pmReserved = read_long(); if (verbose) { @@ -1824,6 +1991,8 @@ read_pixmap(struct pixMap * const p) { pm_message("pixelSize: %d", p->pixelSize); pm_message("cmpCount: %d", p->cmpCount); pm_message("cmpSize: %d", p->cmpSize); + if (verbose) + dumpRect("Bounds:", p->Bounds); } if (p->pixelType != 0) @@ -1878,7 +2047,7 @@ read_color_table(void) { color_table[val].blu = read_word(); if (verbose > 1) - pm_message("%d: [%d,%d,%d]", val, + pm_message("Color %3u: [%u,%u,%u]", val, color_table[val].red, color_table[val].grn, color_table[val].blu); @@ -2084,6 +2253,42 @@ unpackUncompressedBits(FILE * const ifP, static void +reportValidateCompressedLineLen(unsigned int const row, + unsigned int const linelen, + unsigned int const rowSize) { +/*---------------------------------------------------------------------------- + 'row' is a row number in the raster. + + 'linelen' is the number of bytes of PICT that the PICT says hold the + compressed version of that row. + + 'rowSize' is the number of bytes we expect the uncompressed line to + be (includes pad pixels on the right). +-----------------------------------------------------------------------------*/ + if (verbose > 1) + pm_message("Row %u: %u-byte compressed line", row, linelen); + + /* When the line length value is garbage, it often causes the program to + try to read beyond EOF. To make that failure easier to diagnose, + we sanity check the line length now. + */ + + /* In the worst case, a pixel is represented by two bytes: a one byte + repeat count of one followed by a one byte pixel value (the byte could + be up to 8 pixels) or a one byte block length of one followed by the + pixel value. So expansion factor two. + */ + + if (linelen > rowSize * 2) + pm_error("Invalid PICT: compressed line of %u bytes for Row %u " + "is too big " + "to represent a %u-byte padded row, even with worse case " + "compression.", linelen, row, rowSize); +} + + + +static void expandRun(unsigned char * const block, unsigned int const blockLimit, unsigned int const bitsPerPixel, @@ -2099,6 +2304,9 @@ expandRun(unsigned char * const block, returned. -----------------------------------------------------------------------------*/ unsigned int const pkpixsize = bitsPerPixel == 16 ? 2 : 1; + /* The repetition unit size, in bytes. The run consists of this many + bytes of packed data repeated the specified number of times. + */ if (1 + pkpixsize > blockLimit) pm_error("PICT run block runs off the end of its line. " @@ -2114,14 +2322,28 @@ expandRun(unsigned char * const block, assert(block[0] & 0x80); /* It's a run */ if (verbose > 1) - pm_message("Block: run of %u pixels or plane samples", runLength); - + pm_message("Block: run of %u packed %u-byte units", + runLength, pkpixsize); + unpackBuf(&block[1], pkpixsize, bitsPerPixel, &bytePixels, &expandedByteCount); + + /* I assume in a legal PICT the run never has padding for the + case that the run is at the right edge of a row and the + remaining columns in the row don't fill whole bytes. + E.g. if there are 25 columns left in the row and 1 bit per + pixel, we won't see a run of 4 bytes and have to ignore the + last 7 pixels. Instead, we'll see a run of 3 bytes + followed by a non-run block for the remaining pixel. + + That is what I saw in a test image. + */ - if (expandedByteCount > expandedSize) + if (expandedByteCount * runLength > expandedSize) pm_error("Invalid PICT image. It contains a row with more pixels " - "than the width of the image"); + "than the width of the rectangle containing it, " + "even padded up to a " + "multiple of 16 pixels. Use -verbose to see details."); outputCursor = 0; for (i = 0; i < runLength; ++i) { @@ -2146,9 +2368,23 @@ copyPixelGroup(unsigned char * const block, unsigned int * const rasterBytesGeneratedP) { /*---------------------------------------------------------------------------- Copy a group of pixels (the data says, "take the following N pixels"). + + Copy them (unpacked) from block block[] to dest[]. + + block[] self-describes its length. Return that length as + *blockLengthP. + + block[] contains at most 'blockLimit' valid array elements, so if + the length information in block[] indicates the block is larger + than that, the block is corrupt. + + Return the number of pixels placed in dest[] as *rasterBytesGeneratedP. + + The output array dest[] has 'destSize' elements of space. Ignore + any pixels on the right that won't fit in that. -----------------------------------------------------------------------------*/ - unsigned int const pkpixsize = bitsPerPixel == 16 ? 2 : 1; - unsigned int const groupLen = block[0] + 1; + unsigned int const pkpixsize = bitsPerPixel == 16 ? 2 : 1; + unsigned int const groupLen = block[0] + 1; unsigned int const blockLength = 1 + groupLen * pkpixsize; if (blockLength > blockLimit) @@ -2159,22 +2395,35 @@ copyPixelGroup(unsigned char * const block, unsigned int i; unsigned char * bytePixels; /* Points to static storage */ unsigned int bytePixelLen; + unsigned int rasterBytesGenerated; assert(blockLimit >= 1); /* block[0] exists */ assert((block[0] & 0x80) == 0); /* It's not a run */ if (verbose > 1) - pm_message("Block: %u individual pixels or plane samples", - groupLen); + pm_message("Block: %u explicit packed %u-byte units", + groupLen, pkpixsize); unpackBuf(&block[1], groupLen * pkpixsize, bitsPerPixel, &bytePixels, &bytePixelLen); - - for (i = 0; i < MIN(bytePixelLen, destSize); ++i) + + /* It is normal for the above to return more pixels than there + are left in the row, because of padding. E.g. there is one + pixel left in the row, at one bit per pixel. But a block + contains full bytes, so it must contain at least 8 pixels. + 7 of them are padding, which we should ignore. + + BUT: I saw an image in which the block had _two_ data bytes + (16 pixels) when only 1 pixel remained in the row. I don't + understand why, but ignoring the 15 extra seemed to work. + */ + rasterBytesGenerated = MIN(bytePixelLen, destSize); + + for (i = 0; i < rasterBytesGenerated; ++i) dest[i] = bytePixels[i]; *blockLengthP = blockLength; - *rasterBytesGeneratedP = MIN(bytePixelLen, destSize); + *rasterBytesGeneratedP = rasterBytesGenerated; } } @@ -2218,12 +2467,83 @@ static unsigned int const maxPixelBytesPerBlock = 1024; static void +interpretCompressedLine(unsigned char * const linebuf, + unsigned int const linelen, + unsigned char * const rowRaster, + unsigned int const rowSize, + unsigned int const bitsPerPixel) { +/*---------------------------------------------------------------------------- + linebuf[] contains 'linelen' bytes from the PICT image that represents + one row of the image, in compressed format. Return the + uncompressed pixels of that row as rowRaster[]. + + rowRaster[] has 'rowSize' bytes of space. Caller ensures that + linebuf[] does not contain more pixels than that, unless the PICT + image from which it comes is corrupt. +-----------------------------------------------------------------------------*/ + unsigned int lineCursor; + /* Cursor into linebuf[] -- the compressed data */ + unsigned int rasterCursor; + /* Cursor into rowRaster[] -- the uncompressed data */ + + for (lineCursor = 0, rasterCursor = 0; lineCursor < linelen; ) { + unsigned int blockLength, rasterBytesGenerated; + + assert(lineCursor <= linelen); + + if (verbose > 2) + pm_message("At Byte %u of line, Column %u of row", + lineCursor, rasterCursor); + + interpretOneRasterBlock( + &linebuf[lineCursor], linelen - lineCursor, + bitsPerPixel, + &rowRaster[rasterCursor], rowSize - rasterCursor, + &blockLength, &rasterBytesGenerated); + + lineCursor += blockLength; + rasterCursor += rasterBytesGenerated; + assert(rasterCursor <= rowSize); + } + if (verbose > 1) + pm_message("Got %u pixels for row", rasterCursor); +} + + +/* There is some confusion about when, in PICT, a line length is one byte and + when it is two. An Apple document says it is two bytes when the number of + pixels in the row, padded, is > 250. Ppmtopict generated PICTs that way + until January 2009. Picttoppm assumed something similar until March 2004: + It assumed the line length is two bytes when the number of pixels > 250 _or_ + bits per pixel > 8. But in March 2004, Steve Summit did a bunch of + experiments on existing PICT files and found that they all worked with the + rule "pixels per row > 200 => 2 byte line length" and some did not work + with the original rule. + + So in March 2004, Picttoppm changed to pixels per row > 200. Ppmtopict + didn't catch up until January 2009. + + http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-460.html#HEADING460-0 + + Of course, neither 200 nor 250 make any logical sense. In the worst case, + you can represent 254 pixels of 8 bpp or less in a 255 byte line. + In the worst case, you can represent 127 16bpp pixels in a 255 byte line. + So with 200 being the cutoff, it's actually impossible to represent some + 16 bpp images with 200 pixels per row. + + We have not been able to find an offical spec for PICT. + + Some day, we may have to make a user option for this. +*/ + + +static void unpackCompressedBits(FILE * const ifP, struct raster const raster, unsigned int const rowBytes, unsigned int const bitsPerPixel) { /*---------------------------------------------------------------------------- - Read the raster of on file *ifP and place it in 'raster'. + Read the raster on file *ifP and place it in 'raster'. The data in the file is compressed with run length encoding and possibly packed multiple pixels per byte as well. @@ -2232,11 +2552,13 @@ unpackCompressedBits(FILE * const ifP, "packing" and I don't know what packing is called. But we don't use that confusing terminology in this program, except when talking to the user. - - *boundsP describes the rectangle. -----------------------------------------------------------------------------*/ unsigned int const llsize = rowBytes > 200 ? 2 : 1; - unsigned int rowOfRect; + /* Width in bytes of the field at the beginning of a line that tells + how long (in bytes) the line is. See notes above about this + computation. + */ + unsigned int row; unsigned char * linebuf; unsigned int linebufSize; @@ -2245,20 +2567,17 @@ unpackCompressedBits(FILE * const ifP, if (linebuf == NULL) pm_error("can't allocate memory for line buffer"); - for (rowOfRect = 0; rowOfRect < raster.rowCount; ++rowOfRect) { + for (row = 0; row < raster.rowCount; ++row) { unsigned char * const rowRaster = - &raster.bytes[rowOfRect * raster.rowSize]; + &raster.bytes[row * raster.rowSize]; unsigned int linelen; - unsigned int lineCursor; - unsigned int rasterCursor; if (llsize == 2) linelen = read_word(); else linelen = read_byte(); - if (verbose > 1) - pm_message("linelen: %u", linelen); + reportValidateCompressedLineLen(row, linelen, raster.rowSize); if (linelen > linebufSize) { linebufSize = linelen; @@ -2268,23 +2587,8 @@ unpackCompressedBits(FILE * const ifP, } readBytes(ifP, linelen, linebuf); - for (lineCursor = 0, rasterCursor = 0; lineCursor < linelen; ) { - unsigned int blockLength, rasterBytesGenerated; - - assert(lineCursor <= linelen); - - interpretOneRasterBlock( - &linebuf[lineCursor], linelen - lineCursor, - bitsPerPixel, - &rowRaster[rasterCursor], raster.rowSize - rasterCursor, - &blockLength, &rasterBytesGenerated); - - lineCursor += blockLength; - rasterCursor += rasterBytesGenerated; - assert(rasterCursor <= raster.rowSize); - } - if (verbose > 1) - pm_message("row %u: got %u", rowOfRect, rasterCursor); + interpretCompressedLine(linebuf, linelen, rowRaster, raster.rowSize, + bitsPerPixel); } free(linebuf); } @@ -2386,21 +2690,42 @@ read_pattern(void) { /* these 3 do nothing but skip over their data! */ +static drawFn BkPixPat; + static void -BkPixPat(int const version) { +BkPixPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_pattern(); } + + +static drawFn PnPixPat; + static void -PnPixPat(int const version) { +PnPixPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_pattern(); } + + +static drawFn FillPixPat; + static void -FillPixPat(int const version) { +FillPixPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_pattern(); } + + static void read_8x8_pattern(struct Pattern * const pat) { unsigned char buf[8]; @@ -2424,29 +2749,49 @@ read_8x8_pattern(struct Pattern * const pat) { +static drawFn BkPat; + static void -BkPat(int const version) { +BkPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_8x8_pattern(&bkpat); } +static drawFn PnPat; + static void -PnPat(int const version) { +PnPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_8x8_pattern(&pen_pat); } +static drawFn FillPat; + static void -FillPat(int const version) { +FillPat(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_8x8_pattern(&fillpat); } +static drawFn PnSize; + static void -PnSize(int const version) { +PnSize(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + pen_height = read_word(); pen_width = read_word(); if (verbose) @@ -2455,8 +2800,12 @@ PnSize(int const version) { +static drawFn PnSize; + static void -PnMode(int const version) { +PnMode(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { pen_mode = read_word(); @@ -2480,8 +2829,13 @@ read_rgb(struct RGBColor * const rgb) { +static drawFn RGBFgCol; + static void -RGBFgCol(int const v) { +RGBFgCol(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_rgb(&foreground); if (verbose) pm_message("foreground now [%d,%d,%d]", @@ -2490,8 +2844,13 @@ RGBFgCol(int const v) { +static drawFn RGBBkCol; + static void -RGBBkCol(int const v) { +RGBBkCol(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_rgb(&background); if (verbose) pm_message("background now [%d,%d,%d]", @@ -2503,34 +2862,37 @@ RGBBkCol(int const v) { #define PIXEL_INDEX(x,y) ((y) - picFrame.top) * rowlen + (x) - picFrame.left static void -draw_pixel(int const x, - int const y, +draw_pixel(struct canvas * const canvasP, + int const x, + int const y, struct RGBColor * const clr, - transfer_func trf) { - - int i; - struct RGBColor dst; + transfer_func trf) { if (x < clip_rect.left || x >= clip_rect.right || - y < clip_rect.top || y >= clip_rect.bottom) - { - return; - } + y < clip_rect.top || y >= clip_rect.bottom) { + } else { + unsigned int const i = PIXEL_INDEX(x, y); + + struct RGBColor dst; + + dst.red = canvasP->planes.red[i]; + dst.grn = canvasP->planes.grn[i]; + dst.blu = canvasP->planes.blu[i]; + + (*trf)(clr, &dst); - i = PIXEL_INDEX(x, y); - dst.red = red[i]; - dst.grn = green[i]; - dst.blu = blue[i]; - (*trf)(clr, &dst); - red[i] = dst.red; - green[i] = dst.grn; - blue[i] = dst.blu; + canvasP->planes.red[i] = dst.red; + canvasP->planes.grn[i] = dst.grn; + canvasP->planes.blu[i] = dst.blu; + } } static void -draw_pen_rect(struct Rect * const r) { +draw_pen_rect(struct canvas * const canvasP, + struct Rect * const r) { + int const rowadd = rowlen - (r->right - r->left); int i; @@ -2541,16 +2903,18 @@ draw_pen_rect(struct Rect * const r) { for (y = r->top; y < r->bottom; y++) { for (x = r->left; x < r->right; x++) { - dst.red = red[i]; - dst.grn = green[i]; - dst.blu = blue[i]; + dst.red = canvasP->planes.red[i]; + dst.grn = canvasP->planes.grn[i]; + dst.blu = canvasP->planes.blu[i]; + if (pen_pat.pix[(x & 7) + (y & 7) * 8]) (*pen_trf)(&black, &dst); else (*pen_trf)(&white, &dst); - red[i] = dst.red; - green[i] = dst.grn; - blue[i] = dst.blu; + + canvasP->planes.red[i] = dst.red; + canvasP->planes.grn[i] = dst.grn; + canvasP->planes.blu[i] = dst.blu; i++; } @@ -2561,8 +2925,10 @@ draw_pen_rect(struct Rect * const r) { static void -draw_pen(int const x, - int const y) { +draw_pen(struct canvas * const canvasP, + int const x, + int const y) { + struct Rect penrect; penrect.left = x; @@ -2572,7 +2938,7 @@ draw_pen(int const x, rectinter(penrect, clip_rect, &penrect); - draw_pen_rect(&penrect); + draw_pen_rect(canvasP, &penrect); } /* @@ -2589,10 +2955,12 @@ draw_pen(int const x, * Paul Heckbert 3 Sep 85 */ static void -scan_line(short const x1, - short const y1, - short const x2, - short const y2) { +scan_line(struct canvas * const canvasP, + short const x1, + short const y1, + short const x2, + short const y2) { + int d, x, y, ax, ay, sx, sy, dx, dy; if (!(pen_width == 0 && pen_height == 0)) { @@ -2605,7 +2973,7 @@ scan_line(short const x1, if (ax>ay) { /* x dominant */ d = ay-(ax>>1); for (;;) { - draw_pen(x, y); + draw_pen(canvasP, x, y); if (x==x2) return; if ((x > rowlen) && (sx > 0)) return; if (d>=0) { @@ -2619,7 +2987,7 @@ scan_line(short const x1, else { /* y dominant */ d = ax-(ay>>1); for (;;) { - draw_pen(x, y); + draw_pen(canvasP, x, y); if (y==y2) return; if ((y > collen) && (sy > 0)) return; if (d>=0) { @@ -2635,137 +3003,178 @@ scan_line(short const x1, +static drawFn Line; + static void -Line(int const v) { +Line(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + struct Point p1; read_point(&p1); read_point(¤t); if (verbose) pm_message("(%d,%d) to (%d, %d)", p1.x,p1.y,current.x,current.y); - scan_line(p1.x,p1.y,current.x,current.y); + scan_line(canvasP, p1.x,p1.y,current.x,current.y); } +static drawFn LineFrom; + static void -LineFrom(int const v) { - struct Point p1; - read_point(&p1); - if (verbose) - pm_message("(%d,%d) to (%d, %d)", - current.x,current.y,p1.x,p1.y); +LineFrom(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + + struct Point p1; + read_point(&p1); + if (verbose) + pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y); - if (!fullres) - scan_line(current.x,current.y,p1.x,p1.y); + if (!blitListP) + scan_line(canvasP, current.x, current.y, p1.x, p1.y); - current.x = p1.x; - current.y = p1.y; + current.x = p1.x; + current.y = p1.y; } +static drawFn ShortLine; + static void -ShortLine(int const v) { - struct Point p1; - read_point(&p1); - read_short_point(¤t); - if (verbose) - pm_message("(%d,%d) delta (%d, %d)", - p1.x,p1.y,current.x,current.y); - current.x += p1.x; - current.y += p1.y; +ShortLine(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { - if (!fullres) - scan_line(p1.x,p1.y,current.x,current.y); + struct Point p1; + read_point(&p1); + read_short_point(¤t); + if (verbose) + pm_message("(%d,%d) delta (%d, %d)", p1.x, p1.y, current.x, current.y); + current.x += p1.x; + current.y += p1.y; + + if (!blitListP) + scan_line(canvasP, p1.x, p1.y, current.x, current.y); } +static drawFn ShortLineFrom; + static void -ShortLineFrom(int const v) { - struct Point p1; - read_short_point(&p1); - if (verbose) - pm_message("(%d,%d) delta (%d, %d)", - current.x,current.y,p1.x,p1.y); - p1.x += current.x; - p1.y += current.y; - if (!fullres) - scan_line(current.x,current.y,p1.x,p1.y); - current.x = p1.x; - current.y = p1.y; +ShortLineFrom(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + + struct Point p1; + read_short_point(&p1); + if (verbose) + pm_message("(%d,%d) delta (%d, %d)", + current.x,current.y,p1.x,p1.y); + p1.x += current.x; + p1.y += current.y; + if (!blitListP) + scan_line(canvasP, current.x, current.y, p1.x, p1.y); + current.x = p1.x; + current.y = p1.y; } + + static void -do_paintRect(struct Rect const prect) { +do_paintRect(struct canvas * const canvasP, + struct Rect const prect) { + struct Rect rect; - if (fullres) - return; - if (verbose) dumpRect("painting", prect); rectinter(clip_rect, prect, &rect); - draw_pen_rect(&rect); + draw_pen_rect(canvasP, &rect); } +static drawFn paintRect; + static void -paintRect(int const v) { +paintRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_rect(&cur_rect); - do_paintRect(cur_rect); + if (!blitListP) + do_paintRect(canvasP, cur_rect); } +static drawFn paintSameRect; + static void -paintSameRect(int const v) { - do_paintRect(cur_rect); +paintSameRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + + if (!blitListP) + do_paintRect(canvasP, cur_rect); } static void -do_frameRect(struct Rect const rect) { - int x, y; +do_frameRect(struct canvas * const canvasP, + struct Rect const rect) { - if (fullres) - return; - if (verbose) dumpRect("framing", rect); - if (pen_width == 0 || pen_height == 0) - return; - - for (x = rect.left; x <= rect.right - pen_width; x += pen_width) { - draw_pen(x, rect.top); - draw_pen(x, rect.bottom - pen_height); - } + if (pen_width > 0 && pen_height > 0) { + unsigned int x, y; - for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) { - draw_pen(rect.left, y); - draw_pen(rect.right - pen_width, y); + for (x = rect.left; x <= rect.right - pen_width; x += pen_width) { + draw_pen(canvasP, x, rect.top); + draw_pen(canvasP, x, rect.bottom - pen_height); + } + + for (y = rect.top; y <= rect.bottom - pen_height ; y += pen_height) { + draw_pen(canvasP, rect.left, y); + draw_pen(canvasP, rect.right - pen_width, y); + } } } +static drawFn frameRect; + static void -frameRect(int const v) { +frameRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + read_rect(&cur_rect); - do_frameRect(cur_rect); + if (!blitListP) + do_frameRect(canvasP, cur_rect); } +static drawFn frameSameRect; + static void -frameSameRect(int const v) { - do_frameRect(cur_rect); +frameSameRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + + if (!blitListP) + do_frameRect(canvasP, cur_rect); } @@ -2806,8 +3215,10 @@ poly_sort(int const sort_index, struct Point points[]) { /* Watch out for the lack of error checking in the next two functions ... */ static void -scan_poly(int const np, - struct Point pts[]) { +scan_poly(struct canvas * const canvasP, + int const np, + struct Point pts[]) { + int dx,dy,dxabs,dyabs,i,scan_index,j,k,px,py; int sdx,sdy,x,y,toggle,old_sdy,sy0; @@ -2860,7 +3271,7 @@ scan_poly(int const np, scan_index++; } px += sdx; - draw_pen(px, py); + draw_pen(canvasP, px, py); } } else @@ -2876,7 +3287,7 @@ scan_poly(int const np, old_sdy = sdy; if (sdy != 0) scan_index--; } - draw_pen(px,py); + draw_pen(canvasP, px,py); coord[scan_index].x = px; coord[scan_index].y = py; scan_index++; @@ -2896,7 +3307,7 @@ scan_poly(int const np, if ((coord[i].y == coord[i+1].y) && (toggle == 0)) { for (j = coord[i].x; j <= coord[i+1].x; j++) - draw_pen(j, coord[i].y); + draw_pen(canvasP, j, coord[i].y); toggle = 1; } else @@ -2905,9 +3316,14 @@ scan_poly(int const np, } + +static drawFn paintPoly; static void -paintPoly(int const v) { +paintPoly(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + struct Rect bb; struct Point pts[100]; int i, np = (read_word() - 10) >> 2; @@ -2917,14 +3333,19 @@ paintPoly(int const v) { read_point(&pts[i]); /* scan convert poly ... */ - if (!fullres) - scan_poly(np, pts); + if (!blitListP) + scan_poly(canvasP, np, pts); } +static drawFn PnLocHFrac; + static void -PnLocHFrac(int const version) { +PnLocHFrac(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + word frac = read_word(); if (verbose) @@ -2933,8 +3354,13 @@ PnLocHFrac(int const version) { +static drawFn TxMode; + static void -TxMode(int const version) { +TxMode(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + text_mode = read_word(); if (text_mode >= 8 && text_mode < 15) @@ -2949,8 +3375,13 @@ TxMode(int const version) { +static drawFn TxFont; + static void -TxFont(int const version) { +TxFont(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + text_font = read_word(); if (verbose) pm_message("text font %s", const_name(font_name, text_font)); @@ -2958,8 +3389,13 @@ TxFont(int const version) { +static drawFn TxFace; + static void -TxFace(int const version) { +TxFace(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + text_face = read_byte(); if (verbose) pm_message("text face %d", text_face); @@ -2967,8 +3403,13 @@ TxFace(int const version) { +static drawFn TxSize; + static void -TxSize(int const version) { +TxSize(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + text_size = read_word(); if (verbose) pm_message("text size %d", text_size); @@ -2977,8 +3418,11 @@ TxSize(int const version) { static void -skip_text(void) { +skip_text(blitList * const blitListP) { + skip(read_byte()); + + blitListP->unblittableText = true; } @@ -2997,6 +3441,7 @@ static struct font* get_font(int const font, int const size, int const style) { + int closeness, bestcloseness; struct fontinfo* fi, *best; @@ -3058,8 +3503,10 @@ rotate(int * const x, static void -do_ps_text(word const tx, - word const ty) { +do_ps_text(struct canvas * const canvasP, + word const tx, + word const ty) { + int len, width, i, w, h, x, y, rx, ry, o; byte str[256], ch; struct glyph* glyph; @@ -3110,9 +3557,9 @@ do_ps_text(word const tx, { o = PIXEL_INDEX(rx, ry); if (glyph->bmap[h * glyph->width + w]) { - red[o] = foreground.red; - green[o] = foreground.grn; - blue[o] = foreground.blu; + canvasP->planes.red[o] = foreground.red; + canvasP->planes.grn[o] = foreground.grn; + canvasP->planes.blu[o] = foreground.blu; } } } @@ -3125,16 +3572,19 @@ do_ps_text(word const tx, static void -do_text(word const startx, - word const starty) { - if (fullres) - skip_text(); +do_text(struct canvas * const canvasP, + blitList * const blitListP, + word const startx, + word const starty) { + + if (blitListP) + skip_text(blitListP); else { if (!(tfont = get_font(text_font, text_size, text_face))) tfont = pbm_defaultfont("bdf"); if (ps_text) - do_ps_text(startx, starty); + do_ps_text(canvasP, startx, starty); else { int len; word x, y; @@ -3154,7 +3604,8 @@ do_text(word const startx, struct RGBColor * const colorP = glyph->bmap[h * glyph->width + w] ? &black : &white; - draw_pixel(x + w + glyph->x, dy, colorP, text_trf); + draw_pixel(canvasP, + x + w + glyph->x, dy, colorP, text_trf); } } x += glyph->xadd; @@ -3168,34 +3619,56 @@ do_text(word const startx, +static drawFn LongText; + static void -LongText(int const version) { +LongText(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + struct Point p; read_point(&p); - do_text(p.x, p.y); + + do_text(canvasP, blitListP, p.x, p.y); } +static drawFn DHText; + static void -DHText(int const version) { +DHText(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + current.x += read_byte(); - do_text(current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } +static drawFn DVText; + static void -DVText(int const version) { +DVText(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + current.y += read_byte(); - do_text(current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } +static drawFn DHDVText; + static void -DHDVText(int const version) { +DHDVText(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { byte dh, dv; dh = read_byte(); @@ -3206,7 +3679,8 @@ DHDVText(int const version) { current.x += dh; current.y += dv; - do_text(current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3216,8 +3690,10 @@ DHDVText(int const version) { */ static void -directBits(unsigned int const pictVersion, - bool const skipRegion) { +directBits(struct canvas * const canvasP, + blitList * const blitListP, + unsigned int const pictVersion, + bool const skipRegion) { struct pixMap p; struct Rect srcRect; @@ -3257,11 +3733,11 @@ directBits(unsigned int const pictVersion, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (skipRegion) - skip_poly_or_region(pictVersion); + skip_poly_or_region(canvasP, blitListP, pictVersion); unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, p.pixelSize, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize, dstRect, picFrame, rowlen, NULL, mode); freeRaster(raster); @@ -3272,26 +3748,36 @@ directBits(unsigned int const pictVersion, #define SKIP_REGION_TRUE TRUE #define SKIP_REGION_FALSE FALSE +static drawFn DirectBitsRect; + static void -DirectBitsRect(int const version) { +DirectBitsRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { - directBits(version, SKIP_REGION_FALSE); + directBits(canvasP, blitListP, version, SKIP_REGION_FALSE); } +static drawFn DirectBitsRgn; + static void -DirectBitsRgn(int const version) { +DirectBitsRgn(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { - directBits(version, SKIP_REGION_TRUE); + directBits(canvasP, blitListP, version, SKIP_REGION_TRUE); } static void -do_pixmap(int const version, - word const rowBytes, - int const is_region) { +do_pixmap(struct canvas * const canvasP, + blitList * const blitListP, + int const version, + word const rowBytes, + int const is_region) { /*---------------------------------------------------------------------------- Do a paletted image. -----------------------------------------------------------------------------*/ @@ -3327,13 +3813,13 @@ do_pixmap(int const version, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, 8, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); free(color_table); @@ -3343,17 +3829,25 @@ do_pixmap(int const version, static void -do_bitmap(int const version, - int const rowBytes, - int const is_region) { +do_bitmap(FILE * const ifP, + struct canvas * const canvasP, + blitList * const blitListP, + int const version, + int const rowBytes, + int const is_region) { /*---------------------------------------------------------------------------- Do a bitmap. That's one bit per pixel, 0 is white, 1 is black. + + Read the raster from file 'ifP'. -----------------------------------------------------------------------------*/ struct Rect Bounds; struct Rect srcRect; struct Rect dstRect; word mode; struct raster raster; + /* This raster contains padding on the right to make a multiple + of 16 pixels per row. + */ static struct RGBColor color_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} }; @@ -3365,13 +3859,13 @@ do_bitmap(int const version, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; - unpackbits(ifp, &Bounds, rowBytes, 1, &raster); + unpackbits(ifP, &Bounds, rowBytes, 1, &raster); - blit(srcRect, Bounds, raster, 8, + blit(srcRect, Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); freeRaster(raster); @@ -3379,8 +3873,12 @@ do_bitmap(int const version, +static drawFn BitsRect; + static void -BitsRect(int const version) { +BitsRect(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { word rowBytesWord; bool pixMap; @@ -3392,16 +3890,20 @@ BitsRect(int const version) { interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(version, rowBytes, 0); + do_pixmap(canvasP, blitListP, version, rowBytes, 0); else - do_bitmap(version, rowBytes, 0); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0); } -static void -BitsRegion(int const version) { +static drawFn BitsRegion; +static void +BitsRegion(struct canvas * const canvasP, + blitList * const blitListP, + int const version) { + word rowBytesWord; bool pixMap; unsigned int rowBytes; @@ -3412,9 +3914,9 @@ BitsRegion(int const version) { interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(version, rowBytes, 1); + do_pixmap(canvasP, blitListP, version, rowBytes, 1); else - do_bitmap(version, rowBytes, 1); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1); } @@ -3597,14 +4099,85 @@ static struct opdef const optable[] = { static void -interpret_pict(void) { +processOpcode(word const opcode, + struct canvas * const canvasP, + blitList * const blitListP, + unsigned int const version) { + + if (opcode < 0xa2) { + stage = optable[opcode].name; + if (verbose) { + if (streq(stage, "reserved")) + pm_message("reserved opcode=0x%x", opcode); + else + pm_message("Opcode: %s", optable[opcode].name); + } + + if (optable[opcode].impl != NULL) + (*optable[opcode].impl)(canvasP, blitListP, version); + else if (optable[opcode].len >= 0) + skip(optable[opcode].len); + else { + switch (optable[opcode].len) { + case WORD_LEN: { + word const len = read_word(); + skip(len); + } break; + default: + pm_error("can't do length %u", optable[opcode].len); + } + } + } else if (opcode == 0xc00) { + if (verbose) + pm_message("HeaderOp"); + stage = "HeaderOp"; + skip(24); + } else if (opcode >= 0xa2 && opcode <= 0xaf) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_word()); + } else if (opcode >= 0xb0 && opcode <= 0xcf) { + /* just a reserved opcode, no data */ + if (verbose) + pm_message("reserved 0x%x", opcode); + } else if (opcode >= 0xd0 && opcode <= 0xfe) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_long()); + } else if (opcode >= 0x100 && opcode <= 0x7fff) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip((opcode >> 7) & 255); + } else if (opcode >= 0x8000 && opcode <= 0x80ff) { + /* just a reserved opcode */ + if (verbose) + pm_message("reserved 0x%x", opcode); + } else if (opcode >= 0x8100) { + stage = "skipping reserved"; + if (verbose) + pm_message("%s 0x%x", stage, opcode); + skip(read_long()); + } else + pm_error("This program does not understand opcode 0x%04x", opcode); +} + + + +static void +interpret_pict(FILE * const ofP) { + byte ch; word picSize; word opcode; - word len; unsigned int version; int i; - struct rgbPlanes planes; + struct canvas canvas; + blitList blitList; + + initBlitList(&blitList); for (i = 0; i < 64; i++) pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1; @@ -3618,20 +4191,26 @@ interpret_pict(void) { picSize = read_word(); if (verbose) - pm_message("picture size = %d (0x%x)", picSize, picSize); + pm_message("picture size = %u (0x%x)", picSize, picSize); stage = "reading picture frame"; read_rect(&picFrame); if (verbose) { dumpRect("Picture frame:", picFrame); - pm_message("Picture size is %d x %d", - picFrame.right - picFrame.left, - picFrame.bottom - picFrame.top); + pm_message("Picture size is %u x %u", + picFrame.right - picFrame.left, + picFrame.bottom - picFrame.top); } - if (!fullres) - allocPlanes(&planes); + if (!fullres) { + rowlen = picFrame.right - picFrame.left; + collen = picFrame.bottom - picFrame.top; + + allocPlanes(rowlen, collen, &canvas.planes); + + clip_rect = picFrame; + } while ((ch = read_byte()) == 0) ; @@ -3657,71 +4236,35 @@ interpret_pict(void) { if (verbose) pm_message("PICT version %u", version); - while((opcode = get_op(version)) != 0xff) { - if (opcode < 0xa2) { - stage = optable[opcode].name; - if (verbose) { - if (STREQ(stage, "reserved")) - pm_message("reserved opcode=0x%x", opcode); - else - pm_message("Opcode: %s", optable[opcode].name); - } - - if (optable[opcode].impl != NULL) - (*optable[opcode].impl)(version); - else if (optable[opcode].len >= 0) - skip(optable[opcode].len); - else switch (optable[opcode].len) { - case WORD_LEN: - len = read_word(); - skip(len); - break; - default: - pm_error("can't do length %u", optable[opcode].len); - } - } else if (opcode == 0xc00) { - if (verbose) - pm_message("HeaderOp"); - stage = "HeaderOp"; - skip(24); - } else if (opcode >= 0xa2 && opcode <= 0xaf) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_word()); - } else if (opcode >= 0xb0 && opcode <= 0xcf) { - /* just a reserved opcode, no data */ - if (verbose) - pm_message("reserved 0x%x", opcode); - } else if (opcode >= 0xd0 && opcode <= 0xfe) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_long()); - } else if (opcode >= 0x100 && opcode <= 0x7fff) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip((opcode >> 7) & 255); - } else if (opcode >= 0x8000 && opcode <= 0x80ff) { - /* just a reserved opcode */ - if (verbose) - pm_message("reserved 0x%x", opcode); - } else if (opcode >= 0x8100) { - stage = "skipping reserved"; - if (verbose) - pm_message("%s 0x%x", stage, opcode); - skip(read_long()); - } else - pm_error("This program does not understand opcode 0x%04x", opcode); - } + while((opcode = get_op(version)) != 0xff) + processOpcode(opcode, &canvas, fullres ? &blitList : NULL, version); - if (fullres) - do_blits(&planes); + if (fullres) { + if (blitList.unblittableText) + pm_message("Warning: text is omitted from the output because " + "we don't know how to do text with -fullres."); + doBlitList(&canvas, &blitList); + } + outputPpm(ofP, canvas.planes); + + freePlanes(canvas.planes); +} + + - outputPpm(planes); +static void +loadDefaultFontDir(void) { +/*---------------------------------------------------------------------------- + Load the fonts from the font directory file "fontdir" (in the current + directory), if it exists. +-----------------------------------------------------------------------------*/ + struct stat statbuf; + int rc; - freePlanes(planes); + rc = stat("fontdir", &statbuf); + + if (rc == 0) + load_fontdir("fontdir"); } @@ -3762,8 +4305,6 @@ main(int argc, char * argv[]) { ++argn; } - load_fontdir("fontdir"); - if (argn < argc) { ifp = pm_openr(argv[argn]); ++argn; @@ -3773,12 +4314,17 @@ main(int argc, char * argv[]) { if (argn != argc) pm_usage(usage); + loadDefaultFontDir(); + if (header) { stage = "Reading 512 byte header"; + /* Note that the "header" in PICT is entirely comment! */ skip(512); } - interpret_pict(); + interpret_pict(stdout); + + pm_close(stdout); return 0; } |