diff options
Diffstat (limited to 'converter/ppm')
-rw-r--r-- | converter/ppm/ilbmtoppm.c | 446 | ||||
-rw-r--r-- | converter/ppm/mitsu.h | 1 | ||||
-rw-r--r-- | converter/ppm/picttoppm.c | 632 | ||||
-rw-r--r-- | converter/ppm/ppmtomitsu.c | 143 | ||||
-rw-r--r-- | converter/ppm/ppmtomitsu.test | 4 | ||||
-rw-r--r-- | converter/ppm/ppmtopict.c | 4 |
6 files changed, 762 insertions, 468 deletions
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c index d140d088..0c365834 100644 --- a/converter/ppm/ilbmtoppm.c +++ b/converter/ppm/ilbmtoppm.c @@ -1,4 +1,4 @@ -/* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap +/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM ** ** Copyright (C) 1989 by Jef Poskanzer. ** @@ -43,11 +43,10 @@ #include <string.h> #include "pm_c_util.h" -#include "ppm.h" -#include "ilbm.h" #include "mallocvar.h" - -/*#define DEBUG*/ +#include "intcode.h" +#include "ilbm.h" +#include "ppm.h" typedef struct { int reg; /* color register to change */ @@ -765,10 +764,15 @@ multi_free(cmap) ****************************************************************************/ static void -check_cmap(bmhd, cmap) - BitMapHeader *bmhd; - ColorMap *cmap; -{ +prepareCmap(const BitMapHeader * const bmhd, + ColorMap * const cmap) { +/*---------------------------------------------------------------------------- + This is a really ugly subroutine that 1) analyzes a colormap and its + context (returning the analysis in global variables); and 2) modifies that + color map, because it's really one type of data structure as input and + another as output. + +-----------------------------------------------------------------------------*/ pixval colmaxval = 0; int shifted = 1; int i, r, g, b; @@ -987,6 +991,8 @@ std_to_ppm(FILE * const ifp, ColorMap * const cmap, long const viewportmodes); + + static void ham_to_ppm(FILE * const ifp, long const chunksize, @@ -1342,16 +1348,10 @@ dcol_to_ppm(FILE * const ifP, static void -cmap_to_ppm(cmap) - ColorMap *cmap; -{ - ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL); -#if 0 - int i; - ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1); - for( i = 0; i < cmap->ncolors; i++ ) - ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1); -#endif +cmapToPpm(FILE * const ofP, + ColorMap * const cmapP) { + + ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL); } @@ -1656,39 +1656,41 @@ PCHG_DecompHuff(src, dest, tree, origsize) } + static void -PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data) - PCHGHeader *PCHG; - PCHGCompHeader *CompHdr; - unsigned char *compdata; - unsigned long compsize; - unsigned char *comptree; - unsigned char *data; -{ - short *hufftree; - unsigned long huffsize, i; - unsigned long treesize = CompHdr->CompInfoSize; +PCHG_Decompress(PCHGHeader * const PCHG, + PCHGCompHeader * const CompHdr, + unsigned char * const compdata, + unsigned long const compsize, + unsigned char * const comptree, + unsigned char * const data) { - switch( PCHG->Compression ) { - case PCHG_COMP_HUFFMAN: + switch(PCHG->Compression) { + case PCHG_COMP_HUFFMAN: { + unsigned long const treesize = CompHdr->CompInfoSize; + unsigned long const huffsize = treesize / 2; + const bigend16 * const bigendComptree = (const void *)comptree; -#ifdef DEBUG - pm_message("PCHG Huffman compression"); -#endif - /* turn big-endian 2-byte shorts into native format */ - huffsize = treesize/2; - MALLOCARRAY_NOFAIL(hufftree, huffsize); - for( i = 0; i < huffsize; i++ ) { - hufftree[i] = (short)BIG_WORD(comptree); - comptree += 2; - } + short * hufftree; + unsigned long i; - /* decompress the change structure data */ - PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], - CompHdr->OriginalDataSize); + /* Convert big-endian 2-byte shorts to C shorts */ - free(hufftree); - break; + MALLOCARRAY(hufftree, huffsize); + + if (!hufftree) + pm_error("Couldn't get memory for %lu-byte Huffman tree", + huffsize); + + for (i = 0; i < huffsize; ++i) + hufftree[i] = pm_uintFromBigend16(bigendComptree[i]); + + /* decompress the change structure data */ + PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], + CompHdr->OriginalDataSize); + + free(hufftree); + } break; default: pm_error("unknown PCHG compression type %d", PCHG->Compression); } @@ -1797,94 +1799,119 @@ fail2: } + static void -PCHG_ConvertBig(PCHG, cmap, mask, datasize) - PCHGHeader *PCHG; - ColorMap *cmap; - unsigned char *mask; - unsigned long datasize; -{ - unsigned char *data; +PCHG_ConvertBig(PCHGHeader * const PCHG, + ColorMap * const cmap, + unsigned char * const maskStart, + unsigned long const datasize) { + + unsigned char * data; unsigned char thismask; - int bits, row, i, changes, masklen, reg; - unsigned long totalchanges = 0; - int changedlines = PCHG->ChangedLines; + int bits; + unsigned int row; + int changes; + int masklen; + int reg; + unsigned long totalchanges; + int changedlines; + unsigned long dataRemaining; + unsigned char * mask; + + mask = maskStart; /* initial value */ + dataRemaining = datasize; /* initial value */ + changedlines = PCHG->ChangedLines; /* initial value */ + totalchanges = 0; /* initial value */ masklen = 4 * MaskLongWords(PCHG->LineCount); - data = mask + masklen; datasize -= masklen; + data = mask + masklen; dataRemaining -= masklen; - bits = 0; - for( row = PCHG->StartLine; changedlines && row < 0; row++ ) { - if( bits == 0 ) { - if( masklen == 0 ) goto fail2; + for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) { + if (bits == 0) { + if (masklen == 0) + pm_error("insufficient data in line mask"); thismask = *mask++; --masklen; bits = 8; } - if( thismask & (1<<7) ) { - if( datasize < 2 ) goto fail; - changes = BIG_WORD(data); data += 2; datasize -= 2; + if (thismask & (1<<7)) { + unsigned int i; + + if (dataRemaining < 2) + pm_error("insufficient data in BigLineChanges structures"); + + changes = BIG_WORD(data); data += 2; dataRemaining -= 2; + + for (i = 0; i < changes; ++i) { + if (totalchanges >= PCHG->TotalChanges) + pm_error("insufficient data in BigLineChanges structures"); + + if (dataRemaining < 6) + pm_error("insufficient data in BigLineChanges structures"); - for( i = 0; i < changes; i++ ) { - if( totalchanges >= PCHG->TotalChanges ) goto fail; - if( datasize < 6 ) goto fail; reg = BIG_WORD(data); data += 2; cmap->mp_init[reg - PCHG->MinReg].reg = reg; ++data; /* skip alpha */ cmap->mp_init[reg - PCHG->MinReg].r = *data++; cmap->mp_init[reg - PCHG->MinReg].b = *data++; /* yes, RBG */ cmap->mp_init[reg - PCHG->MinReg].g = *data++; - datasize -= 6; + dataRemaining -= 6; ++totalchanges; } --changedlines; } thismask <<= 1; - bits--; + --bits; } - for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) { - if( bits == 0 ) { - if( masklen == 0 ) goto fail2; + for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) { + if (bits == 0) { + if (masklen == 0) + pm_error("insufficient data in line mask"); + thismask = *mask++; --masklen; bits = 8; } - if( thismask & (1<<7) ) { - if( datasize < 2 ) goto fail; - changes = BIG_WORD(data); data += 2; datasize -= 2; + if (thismask & (1<<7)) { + unsigned int i; + + if (dataRemaining < 2) + pm_error("insufficient data in BigLineChanges structures"); + + changes = BIG_WORD(data); data += 2; dataRemaining -= 2; MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1); - for( i = 0; i < changes; i++ ) { - if( totalchanges >= PCHG->TotalChanges ) goto fail; - if( datasize < 6 ) goto fail; + for (i = 0; i < changes; ++i) { + if (totalchanges >= PCHG->TotalChanges) + pm_error("insufficient data in BigLineChanges structures"); + + if (dataRemaining < 6) + pm_error("insufficient data in BigLineChanges structures"); + reg = BIG_WORD(data); data += 2; cmap->mp_change[row][i].reg = reg; ++data; /* skip alpha */ cmap->mp_change[row][i].r = *data++; cmap->mp_change[row][i].b = *data++; /* yes, RBG */ cmap->mp_change[row][i].g = *data++; - datasize -= 6; + dataRemaining -= 6; ++totalchanges; } cmap->mp_change[row][changes].reg = MP_REG_END; --changedlines; } thismask <<= 1; - bits--; + --bits; } - if( totalchanges != PCHG->TotalChanges ) + if (totalchanges != PCHG->TotalChanges) pm_message("warning - got %ld change structures, " "chunk header reports %ld", totalchanges, PCHG->TotalChanges); - return; -fail: - pm_error("insufficient data in BigLineChanges structures"); -fail2: - pm_error("insufficient data in line mask"); } + static void read_pchg(FILE * const ifp, IFF_ID const iffid, @@ -1938,7 +1965,7 @@ read_pchg(FILE * const ifp, read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize); compsize = remainingChunksize; - MALLOCARRAY_NOFAIL(compdata, remainingChunksize); + MALLOCARRAY_NOFAIL(compdata, compsize); read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize); datasize = CompHdr.OriginalDataSize; @@ -2032,7 +2059,7 @@ process_body( FILE * const ifp, pm_error("%s chunk without %s chunk", ID2string(ID_BODY), ID2string(ID_BMHD)); - check_cmap(bmhdP, cmap); + prepareCmap(bmhdP, cmap); pixelrow = ppm_allocrow(bmhdP->w); if( maskfile ) { @@ -2080,21 +2107,21 @@ process_body( FILE * const ifp, static void -process_chunk(FILE * const ifp, - long const formsize, - IFF_ID const ignorelist[], - unsigned int const ignorecount, - int const fakeviewport, - int const viewportmask, - int const isdeepopt, - bool const cmaponly, - bool * const bodyChunkProcessedP, - bool * const endchunkP, - BitMapHeader ** const bmhdP, - ColorMap * const cmap, - DirectColor ** const dcolP, - int * const viewportmodesP, - long * const bytesReadP +processChunk(FILE * const ifP, + long const formsize, + IFF_ID const ignorelist[], + unsigned int const ignorecount, + int const fakeviewport, + int const viewportmask, + int const isdeepopt, + bool const cmaponly, + bool * const bodyChunkProcessedP, + bool * const endchunkP, + BitMapHeader ** const bmhdP, + ColorMap * const cmap, + DirectColor ** const dcolP, + int * const viewportmodesP, + long * const bytesReadP ) { IFF_ID iffid; @@ -2103,129 +2130,168 @@ process_chunk(FILE * const ifp, bytesread = 0; - iffid = get_big_long(ifp, ID_FORM, NULL); - chunksize = get_big_long(ifp, iffid, NULL); + iffid = get_big_long(ifP, ID_FORM, NULL); + chunksize = get_big_long(ifP, iffid, NULL); bytesread += 8; if (debug) - pm_message("reading %s chunk: %ld bytes", - ID2string(iffid), chunksize); + pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize); - if( ignored_iffid(iffid, ignorelist, ignorecount) ) { + if (ignored_iffid(iffid, ignorelist, ignorecount)) { pm_message("ignoring %s chunk", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); - } else if( iffid == ID_END ) { + skip_chunk(ifP, iffid, chunksize); + } else if (iffid == ID_END) { /* END chunks are not officially valid in IFF, but suggested as a future expansion for stream-writing, see Amiga RKM Devices, 3rd Ed, page 376 */ - if( chunksize != 0 ) { + if (chunksize != 0 ) { pm_message("warning - non-0 %s chunk", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } - if( formsize != 0xffffffff ) + if (formsize != 0xffffffff) pm_message("warning - %s chunk with FORM size 0x%08lx " "(should be 0x%08x)", ID2string(iffid), formsize, 0xffffffff); *endchunkP = 1; - } else if( *bodyChunkProcessedP ) { + } else if (*bodyChunkProcessedP) { pm_message("%s chunk found after %s chunk - skipping", ID2string(iffid), ID2string(ID_BODY)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else - switch( iffid ) { + switch (iffid) { case ID_BMHD: - *bmhdP = read_bmhd(ifp, iffid, chunksize); + *bmhdP = read_bmhd(ifP, iffid, chunksize); break; case ID_CMAP: - read_cmap(ifp, iffid, chunksize, cmap); + read_cmap(ifP, iffid, chunksize, cmap); break; case ID_CMYK: - read_cmyk(ifp, iffid, chunksize, cmap); + read_cmyk(ifP, iffid, chunksize, cmap); break; case ID_CLUT: - read_clut(ifp, iffid, chunksize, cmap); + read_clut(ifP, iffid, chunksize, cmap); break; case ID_CAMG: - if( chunksize != CAMGChunkSize ) + if (chunksize != CAMGChunkSize) pm_error("%s chunk size mismatch", ID2string(iffid)); - *viewportmodesP = get_big_long(ifp, ID_CAMG, NULL); + *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL); *viewportmodesP &= viewportmask; /* -isnotham/-isnotehb */ break; case ID_PCHG: - read_pchg(ifp, iffid, chunksize, cmap); + read_pchg(ifP, iffid, chunksize, cmap); break; case ID_CTBL: case ID_SHAM: - read_4bit_mp(ifp, iffid, chunksize, cmap); + read_4bit_mp(ifP, iffid, chunksize, cmap); break; case ID_DCOL: - if( chunksize != DirectColorSize ) + if (chunksize != DirectColorSize) pm_error("%s chunk size mismatch", ID2string(iffid)); MALLOCVAR_NOFAIL(*dcolP); - (*dcolP)->r = get_byte(ifp, iffid, NULL); - (*dcolP)->g = get_byte(ifp, iffid, NULL); - (*dcolP)->b = get_byte(ifp, iffid, NULL); - (void)get_byte(ifp, iffid, NULL); /* skip pad byte */ + (*dcolP)->r = get_byte(ifP, iffid, NULL); + (*dcolP)->g = get_byte(ifP, iffid, NULL); + (*dcolP)->b = get_byte(ifP, iffid, NULL); + get_byte(ifP, iffid, NULL); /* skip pad byte */ break; case ID_BODY: - if( cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0 )) { - skip_chunk(ifp, ID_BODY, chunksize); - return; - } - - process_body(ifp, chunksize, *bmhdP, cmap, - maskfile, fakeviewport, isdeepopt, *dcolP, - viewportmodesP); - - *bodyChunkProcessedP = TRUE; + if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0)) + skip_chunk(ifP, ID_BODY, chunksize); + else { + process_body(ifP, chunksize, *bmhdP, cmap, + maskfile, fakeviewport, isdeepopt, *dcolP, + viewportmodesP); - break; + *bodyChunkProcessedP = TRUE; + } break; case ID_GRAB: case ID_DEST: case ID_SPRT: case ID_CRNG: case ID_CCRT: case ID_DYCP: case ID_DPPV: case ID_DRNG: case ID_EPSF: case ID_JUNK: case ID_CNAM: case ID_PRVW: case ID_TINY: case ID_DPPS: - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; case ID_copy: case ID_AUTH: case ID_NAME: case ID_ANNO: case ID_TEXT: case ID_FVER: - if( verbose ) - display_chunk(ifp, iffid, chunksize); + if (verbose) + display_chunk(ifP, iffid, chunksize); else - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; - case ID_DPI: - { + case ID_DPI: { int x, y; - x = get_big_short(ifp, ID_DPI, NULL); - y = get_big_short(ifp, ID_DPI, NULL); - if( verbose ) + x = get_big_short(ifP, ID_DPI, NULL); + y = get_big_short(ifP, ID_DPI, NULL); + if (verbose) pm_message("%s chunk: dpi_x = %d dpi_y = %d", ID2string(ID_DPI), x, y); - } - break; + } break; default: pm_message("unknown chunk type %s - skipping", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); break; } bytesread += chunksize; - if( ODD(chunksize) ) { - (void) get_byte(ifp, iffid, NULL); + if (ODD(chunksize)) { + get_byte(ifP, iffid, NULL); bytesread += 1; } *bytesReadP = bytesread; } + +static void +maybeWriteColorMap(FILE * const ofP, + const BitMapHeader * const bmhdP, + ColorMap * const cmapP, + bool const bodyChunkProcessed, + bool const cmaponly) { +/*---------------------------------------------------------------------------- + Write to file *ofP the color map *cmapP as a PPM, if appropriate. + + The logic (not just here -- in the program as a whole) for deciding whether + to write the image or the colormap is quite twisted. If I thought anyone + was actually using this program, I would take the time to straighten it + out. + + What's really sick about this subroutine is that in choosing to write + a color map, it has to know that Caller hasn't already written + the image. Huge modularity violation. +-----------------------------------------------------------------------------*/ + if (cmaponly) { + if (HAS_COLORMAP(cmapP)) { + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("You specified -cmaponly, but the ILBM " + "has no colormap"); + } else if (bmhdP && bmhdP->nPlanes == 0) { + if (HAS_COLORMAP(cmapP)) { + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("ILBM has neither a color map nor color planes"); + } else if (!bodyChunkProcessed) { + if (HAS_COLORMAP(cmapP)) { + pm_message("input is a colormap file"); + prepareCmap(bmhdP, cmapP); + cmapToPpm(ofP, cmapP); + } else + pm_error("ILBM has neither %s or %s chunk", + ID2string(ID_BODY), ID2string(ID_CMAP)); + } +} + + + int main(int argc, char *argv[]) { - FILE *ifp; + FILE * ifP; int argn; short cmaponly = 0, isdeepopt = 0; bool endchunk; @@ -2299,25 +2365,25 @@ main(int argc, char *argv[]) { } if( argn < argc ) { - ifp = pm_openr( argv[argn] ); + ifP = pm_openr( argv[argn] ); argn++; } else - ifp = stdin; + ifP = stdin; if( argn != argc ) pm_usage(usage); /* Read in the ILBM file. */ - firstIffid = get_big_long(ifp, ID_FORM, NULL); - if( firstIffid != ID_FORM ) + firstIffid = get_big_long(ifP, ID_FORM, NULL); + if (firstIffid != ID_FORM) pm_error("input is not a FORM type IFF file"); - formsize = get_big_long(ifp, ID_FORM, NULL); - typeid = get_big_long(ifp, ID_FORM, NULL); - if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && - typeid != ID_PBM ) - pm_error( "input is not an ILBM, RGBN, RGB8 or PBM " - "type FORM IFF file" ); + formsize = get_big_long(ifP, ID_FORM, NULL); + typeid = get_big_long(ifP, ID_FORM, NULL); + if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && + typeid != ID_PBM) + pm_error("input is not an ILBM, RGBN, RGB8 or PBM " + "type FORM IFF file"); bytesread = 4; /* FORM and formsize do not count */ cmap = alloc_cmap(); @@ -2325,55 +2391,41 @@ main(int argc, char *argv[]) { /* Main loop, parsing the IFF FORM. */ bodyChunkProcessed = FALSE; endchunk = FALSE; - while( !endchunk && formsize-bytesread >= 8 ) { - long bytes_read_for_chunk; + while (!endchunk && formsize-bytesread >= 8) { + long bytesReadForChunk; - process_chunk(ifp, formsize, ignorelist, ignorecount, - fakeviewport, viewportmask, - isdeepopt, cmaponly, - &bodyChunkProcessed, - &endchunk, &bmhdP, cmap, &dcol, - &viewportmodes, &bytes_read_for_chunk); + processChunk(ifP, formsize, ignorelist, ignorecount, + fakeviewport, viewportmask, + isdeepopt, cmaponly, + &bodyChunkProcessed, + &endchunk, &bmhdP, cmap, &dcol, + &viewportmodes, &bytesReadForChunk); - bytesread += bytes_read_for_chunk; + bytesread += bytesReadForChunk; } - if( maskfile ) { + if (maskfile) { pm_close(maskfile); - if( !wrotemask ) + if (!wrotemask) remove(maskname); pbm_freerow(maskrow); } - if( cmaponly || (bmhdP && bmhdP->nPlanes == 0 )) { - if( HAS_COLORMAP(cmap) ) { - check_cmap(bmhdP, cmap); - cmap_to_ppm(cmap); - } else - pm_error("no colormap"); - } else if( !bodyChunkProcessed ) { - if( HAS_COLORMAP(cmap) ) { - pm_message("input is a colormap file"); - check_cmap(bmhdP, cmap); - cmap_to_ppm(cmap); - } else - pm_error("no %s or %s chunk found", - ID2string(ID_BODY), ID2string(ID_CMAP)); - } + maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly); { unsigned int skipped; - for( skipped = 0; fgetc(ifp) != EOF; ++skipped ) - bytesread++; + for (skipped = 0; fgetc(ifP) != EOF; ++skipped) + ++bytesread; - if( skipped > 0 ) + if (skipped > 0) pm_message("skipped %u extraneous byte%s after last chunk", skipped, (skipped == 1 ? "" : "s")); } - pm_close(ifp); + pm_close(ifP); - if( !endchunk && bytesread != formsize ) { + if (!endchunk && bytesread != formsize) { pm_message("warning - file length/FORM size field mismatch " "(%ld != %ld+8)", bytesread+8 /* FORM+size */, formsize); diff --git a/converter/ppm/mitsu.h b/converter/ppm/mitsu.h index 8676a39d..bca4fbdf 100644 --- a/converter/ppm/mitsu.h +++ b/converter/ppm/mitsu.h @@ -1,7 +1,6 @@ #ifndef MITSU_H_INCLUDED #define MITSU_H_INCLUDED -/* static char SCCSid[] = "@(#)mitsu.h\t\t1.3\t(SPZ)\t3/11/92\n"; */ #define MAXLUTCOL 255 #define A4_MAXCOLS 1184 diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index b7da0c79..9a7d8e7c 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -142,15 +142,6 @@ static int ps_cent_x; static int ps_cent_y; static int ps_cent_set; -typedef void (drawFn)(struct canvas *, int); - -struct opdef { - const char* name; - int len; - drawFn * impl; - const char* description; -}; - struct raster { /*---------------------------------------------------------------------------- An image raster. May be either truecolor or paletted. @@ -265,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) @@ -610,6 +618,7 @@ static drawFn ShortComment; static void ShortComment(struct canvas * const canvasP, + blitList * const blitListP, int const version) { picComment(read_word(), 0); @@ -621,6 +630,7 @@ static drawFn LongComment; static void LongComment(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word type; @@ -635,6 +645,7 @@ static drawFn skip_poly_or_region; static void skip_poly_or_region(struct canvas * const canvasP, + blitList * const blitListP, int const version) { stage = "skipping polygon or region"; @@ -765,24 +776,33 @@ load_fontdir(const char * const dirfile) { static void +dumpRect(const char * const label, + struct Rect const rectangle) { + + pm_message("%s (%u,%u) (%u,%u)", + label, + rectangle.left, rectangle.top, + rectangle.right, rectangle.bottom); +} + + + +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); -static void -dumpRect(const char * const label, - struct Rect const rectangle) { - - pm_message("%s (%u,%u) (%u,%u)", - label, - rectangle.left, rectangle.top, - rectangle.right, rectangle.bottom); + 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"); } @@ -802,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 ; } @@ -835,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; + } } @@ -1327,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'. @@ -1501,19 +1544,30 @@ blitIdempotent(unsigned int const pixSize, static void -generalBlit(struct Rect const srcRect, - struct Rect const srcBounds, - struct raster const srcplane, - struct rgbPlanes const planes, - 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; @@ -1523,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 = planes.red + dstoff; - dst.grn = planes.grn + dstoff; - dst.blu = planes.blu + 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) @@ -1555,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) @@ -1575,12 +1629,21 @@ 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, @@ -1595,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; @@ -1605,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, canvasP->planes, pixSize, - dstRect, dstBounds, dstwid, color_map, mode, - clipsrc, clipdst); + doBlit(clipsrc, clipdst, + srcBounds, srcplane, dstBounds, canvasP->planes, + pixSize, dstwid, color_map, mode); retval = 1; } @@ -1680,9 +1735,31 @@ compact(word const input) { static void -do_blits(struct canvas * const canvasP) { +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); + } +} + - struct blit_info* bi; + +static void +doBlitList(struct canvas * const canvasP, + blitList * const blitListP) { +/*---------------------------------------------------------------------------- + Do the list of blits *blitListP, drawing on canvas *canvasP. + + 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; @@ -1690,9 +1767,11 @@ do_blits(struct canvas * const canvasP) { 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); @@ -1768,11 +1847,12 @@ do_blits(struct canvas * const canvasP) { } 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); } @@ -1783,12 +1863,10 @@ do_blits(struct canvas * const canvasP) { clip_rect = picFrame; - for (bi = blit_list; bi; bi = bi->next) { - blit(bi->srcRect, bi->srcBounds, bi->srcplane, canvasP, - bi->pixSize, - bi->dstRect, picFrame, rowlen, - bi->color_map, - bi->mode); + 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); } } @@ -1856,6 +1934,7 @@ static drawFn Clip; static void Clip(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word len; @@ -1878,6 +1957,7 @@ static drawFn OpColor; static void OpColor(struct canvas * const canvasP, + blitList * const blitListP, int const version) { op_color.red = read_word(); @@ -1967,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); @@ -2173,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, @@ -2375,7 +2491,7 @@ interpretCompressedLine(unsigned char * const linebuf, assert(lineCursor <= linelen); - if (verbose > 1) + if (verbose > 2) pm_message("At Byte %u of line, Column %u of row", lineCursor, rasterCursor); @@ -2394,6 +2510,32 @@ interpretCompressedLine(unsigned char * const linebuf, } +/* 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, @@ -2410,14 +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; /* Width in bytes of the field at the beginning of a line that tells - how long (in bytes) the line is. + how long (in bytes) the line is. See notes above about this + computation. */ - unsigned int rowOfRect; + unsigned int row; unsigned char * linebuf; unsigned int linebufSize; @@ -2426,9 +2567,9 @@ 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; if (llsize == 2) @@ -2436,8 +2577,7 @@ unpackCompressedBits(FILE * const ifP, else linelen = read_byte(); - if (verbose > 1) - pm_message("Row %u: %u-byte line", rowOfRect, linelen); + reportValidateCompressedLineLen(row, linelen, raster.rowSize); if (linelen > linebufSize) { linebufSize = linelen; @@ -2554,6 +2694,7 @@ static drawFn BkPixPat; static void BkPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2565,6 +2706,7 @@ static drawFn PnPixPat; static void PnPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2576,6 +2718,7 @@ static drawFn FillPixPat; static void FillPixPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_pattern(); @@ -2610,6 +2753,7 @@ static drawFn BkPat; static void BkPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&bkpat); @@ -2621,6 +2765,7 @@ static drawFn PnPat; static void PnPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&pen_pat); @@ -2632,6 +2777,7 @@ static drawFn FillPat; static void FillPat(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_8x8_pattern(&fillpat); @@ -2643,6 +2789,7 @@ static drawFn PnSize; static void PnSize(struct canvas * const canvasP, + blitList * const blitListP, int const version) { pen_height = read_word(); @@ -2657,6 +2804,7 @@ static drawFn PnSize; static void PnMode(struct canvas * const canvasP, + blitList * const blitListP, int const version) { pen_mode = read_word(); @@ -2685,6 +2833,7 @@ static drawFn RGBFgCol; static void RGBFgCol(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rgb(&foreground); @@ -2699,6 +2848,7 @@ static drawFn RGBBkCol; static void RGBBkCol(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rgb(&background); @@ -2857,6 +3007,7 @@ static drawFn Line; static void Line(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2874,6 +3025,7 @@ static drawFn LineFrom; static void LineFrom(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2881,7 +3033,7 @@ LineFrom(struct canvas * const canvasP, if (verbose) pm_message("(%d,%d) to (%d, %d)", current.x, current.y, p1.x, p1.y); - if (!fullres) + if (!blitListP) scan_line(canvasP, current.x, current.y, p1.x, p1.y); current.x = p1.x; @@ -2894,6 +3046,7 @@ static drawFn ShortLine; static void ShortLine(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2904,7 +3057,7 @@ ShortLine(struct canvas * const canvasP, current.x += p1.x; current.y += p1.y; - if (!fullres) + if (!blitListP) scan_line(canvasP, p1.x, p1.y, current.x, current.y); } @@ -2914,6 +3067,7 @@ static drawFn ShortLineFrom; static void ShortLineFrom(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p1; @@ -2923,7 +3077,7 @@ ShortLineFrom(struct canvas * const canvasP, current.x,current.y,p1.x,p1.y); p1.x += current.x; p1.y += current.y; - if (!fullres) + if (!blitListP) scan_line(canvasP, current.x, current.y, p1.x, p1.y); current.x = p1.x; current.y = p1.y; @@ -2937,9 +3091,6 @@ do_paintRect(struct canvas * const canvasP, struct Rect rect; - if (fullres) - return; - if (verbose) dumpRect("painting", prect); @@ -2954,10 +3105,12 @@ static drawFn paintRect; static void paintRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rect(&cur_rect); - do_paintRect(canvasP, cur_rect); + if (!blitListP) + do_paintRect(canvasP, cur_rect); } @@ -2966,9 +3119,11 @@ static drawFn paintSameRect; static void paintSameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - do_paintRect(canvasP, cur_rect); + if (!blitListP) + do_paintRect(canvasP, cur_rect); } @@ -2976,25 +3131,22 @@ paintSameRect(struct canvas * const canvasP, static void do_frameRect(struct canvas * const canvasP, struct Rect const rect) { - int x, y; - 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(canvasP, x, rect.top); - draw_pen(canvasP, 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(canvasP, rect.left, y); - draw_pen(canvasP, 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); + } } } @@ -3004,10 +3156,12 @@ static drawFn frameRect; static void frameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { read_rect(&cur_rect); - do_frameRect(canvasP, cur_rect); + if (!blitListP) + do_frameRect(canvasP, cur_rect); } @@ -3016,9 +3170,11 @@ static drawFn frameSameRect; static void frameSameRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - do_frameRect(canvasP, cur_rect); + if (!blitListP) + do_frameRect(canvasP, cur_rect); } @@ -3165,6 +3321,7 @@ static drawFn paintPoly; static void paintPoly(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Rect bb; @@ -3176,7 +3333,7 @@ paintPoly(struct canvas * const canvasP, read_point(&pts[i]); /* scan convert poly ... */ - if (!fullres) + if (!blitListP) scan_poly(canvasP, np, pts); } @@ -3186,6 +3343,7 @@ static drawFn PnLocHFrac; static void PnLocHFrac(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word frac = read_word(); @@ -3200,6 +3358,7 @@ static drawFn TxMode; static void TxMode(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_mode = read_word(); @@ -3220,6 +3379,7 @@ static drawFn TxFont; static void TxFont(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_font = read_word(); @@ -3233,6 +3393,7 @@ static drawFn TxFace; static void TxFace(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_face = read_byte(); @@ -3246,6 +3407,7 @@ static drawFn TxSize; static void TxSize(struct canvas * const canvasP, + blitList * const blitListP, int const version) { text_size = read_word(); @@ -3256,11 +3418,11 @@ TxSize(struct canvas * const canvasP, static void -skip_text(void) { +skip_text(blitList * const blitListP) { - pm_message("Warning: text is omitted from the output because " - "we don't know how to do text with -fullres."); skip(read_byte()); + + blitListP->unblittableText = true; } @@ -3279,6 +3441,7 @@ static struct font* get_font(int const font, int const size, int const style) { + int closeness, bestcloseness; struct fontinfo* fi, *best; @@ -3410,11 +3573,12 @@ do_ps_text(struct canvas * const canvasP, static void do_text(struct canvas * const canvasP, + blitList * const blitListP, word const startx, word const starty) { - if (fullres) - skip_text(); + if (blitListP) + skip_text(blitListP); else { if (!(tfont = get_font(text_font, text_size, text_face))) tfont = pbm_defaultfont("bdf"); @@ -3459,13 +3623,14 @@ static drawFn LongText; static void LongText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { struct Point p; read_point(&p); - do_text(canvasP, p.x, p.y); + do_text(canvasP, blitListP, p.x, p.y); } @@ -3474,10 +3639,12 @@ static drawFn DHText; static void DHText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { current.x += read_byte(); - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3486,10 +3653,12 @@ static drawFn DVText; static void DVText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { current.y += read_byte(); - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3498,6 +3667,7 @@ static drawFn DHDVText; static void DHDVText(struct canvas * const canvasP, + blitList * const blitListP, int const version) { byte dh, dv; @@ -3509,7 +3679,8 @@ DHDVText(struct canvas * const canvasP, current.x += dh; current.y += dv; - do_text(canvasP, current.x, current.y); + + do_text(canvasP, blitListP, current.x, current.y); } @@ -3520,6 +3691,7 @@ DHDVText(struct canvas * const canvasP, static void directBits(struct canvas * const canvasP, + blitList * const blitListP, unsigned int const pictVersion, bool const skipRegion) { @@ -3561,11 +3733,11 @@ directBits(struct canvas * const canvasP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (skipRegion) - skip_poly_or_region(canvasP, pictVersion); + skip_poly_or_region(canvasP, blitListP, pictVersion); unpackbits(ifp, &p.Bounds, 0, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, canvasP, p.pixelSize, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, p.pixelSize, dstRect, picFrame, rowlen, NULL, mode); freeRaster(raster); @@ -3580,9 +3752,10 @@ static drawFn DirectBitsRect; static void DirectBitsRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - directBits(canvasP, version, SKIP_REGION_FALSE); + directBits(canvasP, blitListP, version, SKIP_REGION_FALSE); } @@ -3591,15 +3764,17 @@ static drawFn DirectBitsRgn; static void DirectBitsRgn(struct canvas * const canvasP, + blitList * const blitListP, int const version) { - directBits(canvasP, version, SKIP_REGION_TRUE); + directBits(canvasP, blitListP, version, SKIP_REGION_TRUE); } static void do_pixmap(struct canvas * const canvasP, + blitList * const blitListP, int const version, word const rowBytes, int const is_region) { @@ -3638,13 +3813,13 @@ do_pixmap(struct canvas * const canvasP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(canvasP, version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; unpackbits(ifp, &p.Bounds, rowBytes, p.pixelSize, &raster); - blit(srcRect, p.Bounds, raster, canvasP, 8, + blit(srcRect, p.Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); free(color_table); @@ -3656,6 +3831,7 @@ do_pixmap(struct canvas * const canvasP, static void do_bitmap(FILE * const ifP, struct canvas * const canvasP, + blitList * const blitListP, int const version, int const rowBytes, int const is_region) { @@ -3683,13 +3859,13 @@ do_bitmap(FILE * const ifP, pm_message("transfer mode = %s", const_name(transfer_name, mode)); if (is_region) - skip_poly_or_region(canvasP, version); + skip_poly_or_region(canvasP, blitListP, version); stage = "unpacking rectangle"; unpackbits(ifP, &Bounds, rowBytes, 1, &raster); - blit(srcRect, Bounds, raster, canvasP, 8, + blit(srcRect, Bounds, raster, canvasP, blitListP, 8, dstRect, picFrame, rowlen, color_table, mode); freeRaster(raster); @@ -3701,6 +3877,7 @@ static drawFn BitsRect; static void BitsRect(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word rowBytesWord; @@ -3713,9 +3890,9 @@ BitsRect(struct canvas * const canvasP, interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(canvasP, version, rowBytes, 0); + do_pixmap(canvasP, blitListP, version, rowBytes, 0); else - do_bitmap(ifp, canvasP, version, rowBytes, 0); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 0); } @@ -3724,6 +3901,7 @@ static drawFn BitsRegion; static void BitsRegion(struct canvas * const canvasP, + blitList * const blitListP, int const version) { word rowBytesWord; @@ -3736,9 +3914,9 @@ BitsRegion(struct canvas * const canvasP, interpretRowBytesWord(rowBytesWord, &pixMap, &rowBytes); if (pixMap) - do_pixmap(canvasP, version, rowBytes, 1); + do_pixmap(canvasP, blitListP, version, rowBytes, 1); else - do_bitmap(ifp, canvasP, version, rowBytes, 1); + do_bitmap(ifp, canvasP, blitListP, version, rowBytes, 1); } @@ -3921,15 +4099,85 @@ static struct opdef const optable[] = { static 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 canvas canvas; + blitList blitList; + + initBlitList(&blitList); for (i = 0; i < 64; i++) pen_pat.pix[i] = bkpat.pix[i] = fillpat.pix[i] = 1; @@ -3943,16 +4191,16 @@ interpret_pict(FILE * const ofP) { 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) { @@ -3988,68 +4236,15 @@ interpret_pict(FILE * const ofP) { 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)(&canvas, 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(&canvas); - + 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); @@ -4123,6 +4318,7 @@ main(int argc, char * argv[]) { if (header) { stage = "Reading 512 byte header"; + /* Note that the "header" in PICT is entirely comment! */ skip(512); } diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c index 837d9e2b..e59f09b3 100644 --- a/converter/ppm/ppmtomitsu.c +++ b/converter/ppm/ppmtomitsu.c @@ -1,10 +1,10 @@ -/* ppmtomitsu.c - read a portable pixmap and produce output for the +/* ppmtomitsu.c - read a PPM image and produce output for the ** Mitsubishi S340-10 Thermo-Sublimation Printer ** (or the S3410-30 parallel interface) ** ** Copyright (C) 1992,93 by S.Petra Zeidler ** Minor modifications by Ingo Wilken: -x** - mymalloc() and check_and_rotate() functions for often used +** - mymalloc() and check_and_rotate() functions for often used ** code fragments. Reduces code size by a few KB. ** - use pm_error() instead of fprintf(stderr) ** - localized allocation of colorhastable @@ -271,12 +271,12 @@ frametransferinit(int const cols, static void -colorRow(colorhist_vector const table, - unsigned int const colanz, - hashinfo * const colorhashtable) { +doLookupTableColors(colorhist_vector const table, + unsigned int const nColor, + hashinfo * const colorhashtable) { unsigned int colval; - for (colval = 0; colval < colanz; ++colval) { + for (colval = 0; colval < nColor; ++colval) { struct hashinfo * const hashchain = &colorhashtable[myhash((table[colval]).color)]; @@ -308,12 +308,12 @@ colorRow(colorhist_vector const table, static void -grayRow(colorhist_vector const table, - unsigned int const colanz, - hashinfo * const colorhashtable) { +doLookupTableGrays(colorhist_vector const table, + unsigned int const nColor, + hashinfo * const colorhashtable) { unsigned int colval; - for (colval = 0; colval < colanz; ++colval) { + for (colval = 0; colval < nColor; ++colval) { struct hashinfo * const hashchain = &colorhashtable[myhash((table[colval]).color)]; struct hashinfo * hashrun; @@ -329,8 +329,7 @@ grayRow(colorhist_vector const table, if (hashrun->flag == -1) { hashrun->color = (table[colval]).color; hashrun->flag = colval; - } - else { + } else { while (hashrun->next != NULL) hashrun = hashrun->next; MALLOCVAR_NOFAIL(hashrun->next); @@ -345,20 +344,28 @@ grayRow(colorhist_vector const table, static void -useLookupTable(pixel ** const pixels, - colorhist_vector const table, - int const sharpness, - int const enlarge, - int const copy, - struct mediasize const medias, - unsigned int const cols, - unsigned int const rows, - int const format, - unsigned int const colanz) { - +generateLookupTable(colorhist_vector const table, + unsigned int const nColor, + unsigned int const cols, + unsigned int const rows, + int const format, + int const sharpness, + int const enlarge, + int const copy, + struct mediasize const medias, + hashinfo ** const colorhashtableP) { +/*---------------------------------------------------------------------------- + Write to the output file the palette (color lookup table) indicated by + 'table' and generate a hash table to use with it: *colorhashtableP. + + Also write the various properties 'sharpness', 'enlarge', 'copy', and + 'medias' to the output file. +-----------------------------------------------------------------------------*/ hashinfo * colorhashtable; - pm_message("found %u colors - using the lookuptable-method", colanz); + lookuptableinit(sharpness, enlarge, copy, medias); + + /* Initialize the hash table to empty */ MALLOCARRAY_NOFAIL(colorhashtable, HASHSIZE); { @@ -369,34 +376,75 @@ useLookupTable(pixel ** const pixels, } } - lookuptableinit(sharpness, enlarge, copy, medias); switch(PPM_FORMAT_TYPE(format)) { case PPM_TYPE: - colorRow(table, colanz, colorhashtable); + doLookupTableColors(table, nColor, colorhashtable); break; default: - grayRow(table, colanz, colorhashtable); + doLookupTableGrays(table, nColor, colorhashtable); } lookuptabledata(cols, rows, enlarge, medias); - { - unsigned int row; - for (row = 0; row < rows; ++row) { - unsigned int col; - for (col = 0; col < cols; ++col) { - pixel * const pixrow = pixels[row]; - struct hashinfo * const hashchain = - &colorhashtable[myhash(pixrow[col])]; - struct hashinfo * p; + + *colorhashtableP = colorhashtable; +} + + + +static void +writeColormapRaster(pixel ** const pixels, + unsigned int const cols, + unsigned int const rows, + hashinfo * const colorhashtable) { +/*---------------------------------------------------------------------------- + Write a colormapped raster: write the pixels pixels[][] (dimensions cols x + rows) as indices into the colormap (palette; lookup table) indicated by + 'colorhashtable'. +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < rows; ++row) { + unsigned int col; + + for (col = 0; col < cols; ++col) { + pixel * const pixrow = pixels[row]; + struct hashinfo * const hashchain = + &colorhashtable[myhash(pixrow[col])]; + struct hashinfo * p; - p = hashchain; - while (!PPM_EQUAL((p->color), pixrow[col])) { - assert(p->next); - p = p->next; - } - datum(p->flag); + p = hashchain; + while (!PPM_EQUAL((p->color), pixrow[col])) { + assert(p->next); + p = p->next; } + datum(p->flag); } } +} + + + +static void +useLookupTable(pixel ** const pixels, + colorhist_vector const table, + int const sharpness, + int const enlarge, + int const copy, + struct mediasize const medias, + unsigned int const cols, + unsigned int const rows, + int const format, + unsigned int const nColor) { + + hashinfo * colorhashtable; + + pm_message("found %u colors - using the lookuptable-method", nColor); + + generateLookupTable(table, nColor, cols, rows, format, + sharpness, enlarge, copy, medias, + &colorhashtable); + + writeColormapRaster(pixels, cols, rows, colorhashtable); + free(colorhashtable); } @@ -540,7 +588,7 @@ doTiny(FILE * const ifP, data(blurow, cols); data(blurow, cols); data(blurow, cols); - } + } } } } @@ -649,21 +697,21 @@ main(int argc, char * argv[]) { } else { pixel ** pixels; - int colanz; + int nColor; colorhist_vector table; unsigned int row; pixels = ppm_allocarray(cols, rows); - for (row = 0; row < rows; row++) + for (row = 0; row < rows; ++row) ppm_readppmrow(ifP, pixels[row], cols, maxval, format); /* first check wether we can use the lut transfer */ table = ppm_computecolorhist(pixels, cols, rows, MAXLUTCOL+1, - &colanz); + &nColor); if (table) useLookupTable(pixels, table, sharpness, enlarge, copy, medias, - cols, rows, format, colanz); + cols, rows, format, nColor); else useNoLookupTable(pixels, sharpness, enlarge, copy, medias, cols, rows, format); @@ -673,4 +721,3 @@ main(int argc, char * argv[]) { pm_close(ifP); return 0; } - diff --git a/converter/ppm/ppmtomitsu.test b/converter/ppm/ppmtomitsu.test index 1805838a..f574d927 100644 --- a/converter/ppm/ppmtomitsu.test +++ b/converter/ppm/ppmtomitsu.test @@ -2,9 +2,9 @@ echo Test 1. Should print 3110813682 101562 ./ppmtomitsu ../../testimg.ppm | cksum echo Test 2. Should print 239186803 34399 pnmquant 100 ../../testimg.ppm | ./ppmtomitsu | cksum -echo Test 3. Should print 816221676 310 +echo Test 3. Should print 3201293405 310 ./ppmtomitsu ../../testgrid.pbm | cksum -echo Test 4. Should print 629834989 752 +echo Test 4. Should print 3354679572 752 ./ppmtomitsu -tiny ../../testgrid.pbm | cksum echo Test 5. Should print 3999654426 101549 ./ppmtomitsu -tiny ../../testimg.ppm | cksum diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c index 22456857..1b9f2d5c 100644 --- a/converter/ppm/ppmtopict.c +++ b/converter/ppm/ppmtopict.c @@ -398,7 +398,7 @@ char *packed; *p++ = counttochar(count); packcols = p - packed; /* how many did we write? */ - if (cols > 250) + if (cols > 200) { putShort(fd, packcols); oc = packcols + 2; @@ -436,7 +436,7 @@ char *packed; bzero(aux, cols); /* aux?? */ #endif /*notdef*/ bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT; - if (bc > 250) + if (bc > 200) { putShort(fd, bc); oc = bc + 2; |