diff options
Diffstat (limited to 'converter/ppm/ppmtoilbm.c')
-rw-r--r-- | converter/ppm/ppmtoilbm.c | 2362 |
1 files changed, 2362 insertions, 0 deletions
diff --git a/converter/ppm/ppmtoilbm.c b/converter/ppm/ppmtoilbm.c new file mode 100644 index 00000000..6c04c9be --- /dev/null +++ b/converter/ppm/ppmtoilbm.c @@ -0,0 +1,2362 @@ +/* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file +** +** Copyright (C) 1989 by Jef Poskanzer. +** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de) +** 20/Jun/93: +** - 24-bit capability (new options -24if, -24force) +** - HAM8 capability (well, anything from HAM3 to HAM(MAXPLANES)) +** - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes) +** - colormap file (new option -map) +** - write colormap only (new option -cmaponly) +** - only writes CAMG chunk if it is a HAM-picture +** 29/Aug/93: +** - operates row-by-row whenever possible +** - faster colorscaling with lookup-table (~20% faster on HAM pictures) +** - options -ham8 and -ham6 now imply -hamforce +** 27/Nov/93: +** - byterun1 compression (this is now default) with new options: +** -compress, -nocompress, -cmethod, -savemem +** - floyd-steinberg error diffusion (for std+mapfile and HAM) +** - new options: -lace and -hires --> write CAMG chunk +** - LUT for luminance calculation (used by ppm_to_ham) +** 23/Oct/94: +** - rework of mapfile handling +** - added RGB8 & RGBN image types +** - added maskplane and transparent color capability +** - 24-bit & direct color modified to n-bit deep ILBM +** - removed "-savemem" option +** 22/Feb/95: +** - minor bugfixes +** - fixed "-camg 0" behaviour: now writes a CAMG chunk with value 0 +** - "-24if" is now default +** - "-mmethod" and "-cmethod" options accept numeric args and keywords +** - direct color (DCOL) reimplemented +** - mapfile useable for HAM +** - added HAM colormap "fixed" +** 29/Mar/95: +** - added HAM colormap "rgb4" and "rgb5" (compute with 4/5-bit table) +** - added IFF text chunks +** +** TODO: +** - multipalette capability (PCHG chunk) for std and HAM +** +** +** std HAM deep cmap RGB8 RGBN +** -------+-----+-----+-----+-----+-----+----- +** BMHD yes yes yes yes yes yes +** CMAP yes (1) no yes no no +** BODY yes yes yes no yes yes +** CAMG (2) yes (2) no yes yes +** nPlanes 1-16 3-16 3-48 0 25 13 +** +** (1): grayscale colormap +** (2): only if "-lace", "-hires" or "-camg" option used +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#include <string.h> + +#include "pm_c_util.h" +#include "mallocvar.h" +#include "ppm.h" +#include "ppmfloyd.h" +#include "pbm.h" +#include "ilbm.h" +#include "lum.h" + +/*#define DEBUG*/ + +#define MODE_RGB8 6 /* RGB8: 8-bit RGB */ +#define MODE_RGBN 5 /* RGBN: 4-bit RGB */ +#define MODE_CMAP 4 /* ILBM: colormap only */ +#define MODE_DCOL 3 /* ILBM: direct color */ +#define MODE_DEEP 2 /* ILBM: deep (24-bit) */ +#define MODE_HAM 1 /* ILBM: hold-and-modify (HAM) */ +#define MODE_NONE 0 /* ILBM: colormapped */ + +#define HAMMODE_GRAY 0 /* HAM colormap: grayscale */ +#define HAMMODE_FIXED 1 /* HAM colormap: 7 "rays" in RGB cube */ +#define HAMMODE_MAPFILE 2 /* HAM colormap: loaded from mapfile */ +#define HAMMODE_RGB4 3 /* HAM colormap: compute, 4bit RGB */ +#define HAMMODE_RGB5 4 /* HAM colormap: compute, 5bit RGB */ + +#define ECS_MAXPLANES 5 +#define ECS_HAMPLANES 6 +#define AGA_MAXPLANES 8 +#define AGA_HAMPLANES 8 + +#define HAMMAXPLANES 10 /* maximum planes for HAM */ + +#define DEF_MAXPLANES ECS_MAXPLANES +#define DEF_HAMPLANES ECS_HAMPLANES +#define DEF_COMPRESSION cmpByteRun1 +#define DEF_DEEPPLANES 8 +#define DEF_DCOLPLANES 5 +#define DEF_IFMODE MODE_DEEP + +static void put_big_short ARGS((short s)); +static void put_big_long ARGS((long l)); +#define put_byte(b) (void)(putc((unsigned char)(b), stdout)) +static void write_bytes ARGS((unsigned char *buffer, int bytes)); +static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int hamplanes)); +static void ppm_to_deep ARGS((FILE *fp, int cols, int rows, int maxval, int bitspercolor)); +static void ppm_to_dcol ARGS((FILE *fp, int cols, int rows, int maxval, DirectColor *dcol)); +static void ppm_to_rgb8 ARGS((FILE *fp, int cols, int rows, int maxval)); +static void ppm_to_rgbn ARGS((FILE *fp, int cols, int rows, int maxval)); +static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, pixel *colormap, int colors, int cmapmaxval, int maxcolors, int nPlanes)); +static void ppm_to_cmap ARGS((pixel *colormap, int colors, int maxval)); +static void write_bmhd ARGS((int cols, int rows, int nPlanes)); +static void write_cmap ARGS((pixel *colormap, int colors, int maxval)); +static long encode_row ARGS((FILE *outfile, rawtype *rawrow, int cols, int nPlanes)); +static long encode_maskrow ARGS((FILE *outfile, rawtype *rawrow, int cols)); +static int compress_row ARGS((int bytes)); +static void store_bodyrow ARGS((unsigned char *row, int len)); +static int runbyte1 ARGS((int bytes)); +static pixel * next_pixrow ARGS((FILE *fp, int row)); +static int * make_val_table ARGS((int oldmaxval, int newmaxval)); +static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int *formatP, int readall)); +static void write_body_rows ARGS((void)); +static void write_camg ARGS((void)); +static int length_of_text_chunks ARGS((void)); +static void write_text_chunks ARGS((void)); +#define PAD(n) (ODD(n) ? 1 : 0) /* pad to a word */ + + +/* global data */ +static unsigned char *coded_rowbuf; /* buffer for uncompressed scanline */ +static unsigned char *compr_rowbuf; /* buffer for compressed scanline */ +static pixel **pixels; /* PPM image (NULL for row-by-row operation) */ +static pixel *pixrow; + /* current row in PPM image (pointer into pixels array, or buffer + for row-by-row operation) + */ + +static long viewportmodes = 0; +static int slicesize = 1; + /* rows per slice for multipalette images - NOT USED */ + +static unsigned char compmethod = DEF_COMPRESSION; /* default compression */ +static unsigned char maskmethod = mskNone; + +static pixel *transpColor = NULL; /* transparent color */ +static short transpIndex = -1; /* index of transparent color */ + +static short hammapmode = HAMMODE_GRAY; +static short sortcmap = 0; /* sort colormap */ + +static FILE *maskfile = NULL; +static bit *maskrow = NULL; +static int maskcols, maskformat; +#define TOTALPLANES(nplanes) ((nplanes) + ((maskmethod == mskHasMask) ? 1 : 0)) + + +#define ROWS_PER_BLOCK 1024 +typedef struct bodyblock { + int used; + unsigned char *row[ROWS_PER_BLOCK]; + int len[ROWS_PER_BLOCK]; + struct bodyblock *next; +} bodyblock; +static bodyblock firstblock = { 0 }; +static bodyblock *cur_block = &firstblock; + +static char *anno_chunk, *auth_chunk, *name_chunk, *text_chunk, *copyr_chunk; + +/* flags */ +static short compr_force = 0; + /* force compressed output, even if the image got larger - NOT USED */ +static short floyd = 0; /* apply floyd-steinberg error diffusion */ +static short gen_camg = 0; /* write CAMG chunk */ + +#define WORSTCOMPR(bytes) ((bytes) + (bytes)/128 + 1) +#define DO_COMPRESS (compmethod != cmpNone) + + +/***** parse options and figure out what kind of ILBM to write *****/ + +static int get_int_val ARGS((char *string, char *option, int bot, int top)); +static int get_compr_method ARGS((char *string)); +static int get_mask_type ARGS((char *string)); +static int get_hammap_mode ARGS((char *string)); + + + +#define NEWDEPTH(pix, table) PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)]) + + +static void +report_too_many_colors(int const ifmode, + int const maxplanes, + int const hamplanes, + DirectColor const dcol, + int const deepbits) { + + int const maxcolors = 1 << maxplanes; + + switch( ifmode ) { + case MODE_HAM: + pm_message("too many colors for %d planes - " + "proceeding to write a HAM%d file", + maxplanes, hamplanes); + pm_message("if you want a non-HAM file, try doing a 'pnmquant %d'", + maxcolors); + break; + case MODE_DCOL: + pm_message("too many colors for %d planes - " + "proceeding to write a %d:%d:%d direct color ILBM", + maxplanes, dcol.r, dcol.g, dcol.b); + pm_message("if you want a non-direct color file, " + "try doing a 'pnmquant %d'", maxcolors); + break; + case MODE_DEEP: + pm_message("too many colors for %d planes - " + "proceeding to write a %d-bit \'deep\' ILBM", + maxplanes, deepbits*3); + pm_message("if you want a non-deep file, " + "try doing a 'pnmquant %d'", + maxcolors); + break; + default: + pm_error("too many colors for %d planes - " + "try doing a 'pnmquant %d'", + maxplanes, maxcolors); + break; + } +} + + +static int +get_int_val(string, option, bot, top) + char *string, *option; + int bot, top; +{ + int val; + + if( sscanf(string, "%d", &val) != 1 ) + pm_error("option \"%s\" needs integer argument", option); + + if( val < bot || val > top ) + pm_error("option \"%s\" argument value out of range (%d..%d)", + option, bot, top); + + return val; +} + + +static int +get_compr_method(string) + char *string; +{ + int retval; + if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) + retval = cmpNone; + else if( pm_keymatch(string, "byterun1", 1) || + pm_keymatch(string, "1", 1) ) + retval = cmpByteRun1; + else + pm_error("unknown compression method: %s", string); + return retval; +} + + +static int +get_mask_type(string) + char *string; +{ + int retval; + + if( pm_keymatch(string, "none", 1) || pm_keymatch(string, "0", 1) ) + retval = mskNone; + else + if( pm_keymatch(string, "plane", 1) || + pm_keymatch(string, "maskplane", 1) || + pm_keymatch(string, "1", 1) ) + retval = mskHasMask; + else + if( pm_keymatch(string, "transparentcolor", 1) || + pm_keymatch(string, "2", 1) ) + retval = mskHasTransparentColor; + else + if( pm_keymatch(string, "lasso", 1) || pm_keymatch(string, "3", 1) ) + retval = mskLasso; + else + pm_error("unknown masking method: %s", string); + return retval; +} + + +static int +get_hammap_mode(string) + char *string; +{ + int retval; + + if( pm_keymatch(string, "grey", 1) || pm_keymatch(string, "gray", 1) ) + retval = HAMMODE_GRAY; + else + if( pm_keymatch(string, "fixed", 1) ) + retval = HAMMODE_FIXED; + else + if( pm_keymatch(string, "rgb4", 4) ) + retval = HAMMODE_RGB4; + else + if( pm_keymatch(string, "rgb5", 4) ) + retval = HAMMODE_RGB5; + else + pm_error("unknown HAM colormap selection mode: %s", string); + return retval; +} + + +/************ colormap file ************/ + +static void +ppm_to_cmap(colorrow, colors, maxval) + pixel *colorrow; + int colors; + int maxval; +{ + int formsize, cmapsize; + + cmapsize = colors * 3; + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ + length_of_text_chunks(); + + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_ILBM); + + write_bmhd(0, 0, 0); + write_text_chunks(); + write_cmap(colorrow, colors, maxval); +} + +/************ HAM ************/ + +static long +do_ham_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, + pixval hammaxval, int nPlanes, pixel *cmap, int colors)); + + +static int hcmp (const void *va, const void *vb); +static pixel *compute_ham_cmap ARGS((int cols, int rows, int maxval, + int maxcolors, int *colorsP, int hbits)); + + +typedef struct { + long count; + pixval r, g, b; +} hentry; + + +static int +hcmp(const void *va, const void *vb) +{ + return(((hentry *)vb)->count - ((hentry *)va)->count); + /* reverse sort, highest count first */ +} + + +static pixel * +compute_ham_cmap(cols, rows, maxval, maxcolors, colorsP, hbits) + int cols, rows, maxval, maxcolors; + int *colorsP; + int hbits; +{ + int colors; + hentry *hmap; + pixel *cmap; + pixval hmaxval; + int i, r, g, b, col, row, *htable; + unsigned long dist, maxdist; + + pm_message("initializing HAM colormap..."); + + colors = 1<<(3*hbits); + MALLOCARRAY(hmap, colors); + if (hmap == NULL) + pm_error("Unable to allocate memory for HAM colormap."); + hmaxval = pm_bitstomaxval(hbits); + + i = 0; + for( r = 0; r <= hmaxval; r++ ) { + for( g = 0; g <= hmaxval; g++ ) { + for( b = 0; b <= hmaxval; b++ ) { + hmap[i].r = r; hmap[i].g = g; hmap[i].b = b; + hmap[i].count = 0; + i++; + } + } + } + + htable = make_val_table(maxval, hmaxval); + for( row = 0; row < rows; row++ ) { + unsigned int col; + for( col = 0; col < cols; ++col) { + pixel const p = pixels[row][col]; + pixval const r = PPM_GETR(p); + pixval const g = PPM_GETG(p); + pixval const b = PPM_GETB(p); + i = (htable[r]<<(2*hbits)) + (htable[g]<<hbits) + htable[b]; + hmap[i].count++; + } + } + free(htable); + + qsort((void *)hmap, colors, sizeof(hentry), hcmp); + for( i = colors-1; i >= 0; i-- ) { + if( hmap[i].count ) + break; + } + colors = i+1; + + if( colors > maxcolors ) { + pm_message("selecting HAM colormap from %d colors...", colors); + for( maxdist = 1; ; maxdist++ ) { + for( col = colors-1; col > 0; col-- ) { + r = hmap[col].r; g = hmap[col].g; b = hmap[col].b; + for( i = 0; i < col; i++ ) { + register int tmp; + + tmp = hmap[i].r - r; dist = tmp * tmp; + tmp = hmap[i].g - g; dist += tmp * tmp; + tmp = hmap[i].b - b; dist += tmp * tmp; + + if( dist <= maxdist ) { + int sum = hmap[i].count + hmap[col].count; + + hmap[i].r = (hmap[i].r * hmap[i].count + + r * hmap[col].count + sum/2)/sum; + hmap[i].g = (hmap[i].g * hmap[i].count + + g * hmap[col].count + sum/2)/sum; + hmap[i].b = (hmap[i].b * hmap[i].count + + b * hmap[col].count + sum/2)/sum; + hmap[i].count = sum; + + hmap[col] = hmap[i]; /* temp store */ + for( tmp = i-1; + tmp >= 0 && hmap[tmp].count < hmap[col].count; + tmp-- ) + hmap[tmp+1] = hmap[tmp]; + hmap[tmp+1] = hmap[col]; + + for( tmp = col; tmp < colors-1; tmp++ ) + hmap[tmp] = hmap[tmp+1]; + if( --colors <= maxcolors ) + goto out; + break; + } + } + } +#ifdef DEBUG + pm_message("\tmaxdist=%ld: %d colors left", maxdist, colors); +#endif + } + } +out: + pm_message("%d colors in HAM colormap", colors); + + cmap = ppm_allocrow(colors); + *colorsP = colors; + + for( i = 0; i < colors; i++ ) { + r = hmap[i].r; g = hmap[i].g; b = hmap[i].b; + PPM_ASSIGN(cmap[i], r, g, b); + } + + ppm_freerow(hmap); + return cmap; +} + + +static void +ppm_to_ham(fp, cols, rows, maxval, colormap, colors, cmapmaxval, hamplanes) + FILE *fp; + int cols, rows, maxval; + pixel *colormap; + int colors, cmapmaxval, hamplanes; +{ + int hamcolors, nPlanes, i, hammaxval; + long oldsize, bodysize, formsize, cmapsize; + int *table = NULL; + + if( maskmethod == mskHasTransparentColor ) { + pm_message("masking method '%s' not usable with HAM - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } + + hamcolors = 1 << (hamplanes-2); + hammaxval = pm_bitstomaxval(hamplanes-2); + + if( colors == 0 ) { + /* no colormap, make our own */ + switch( hammapmode ) { + case HAMMODE_GRAY: + colors = hamcolors; + MALLOCARRAY_NOFAIL(colormap, colors); +#ifdef DEBUG + pm_message("generating grayscale colormap"); +#endif + table = make_val_table(hammaxval, MAXCOLVAL); + for( i = 0; i < colors; i++ ) + PPM_ASSIGN(colormap[i], table[i], table[i], table[i]); + free(table); + cmapmaxval = MAXCOLVAL; + break; + case HAMMODE_FIXED: { + int entries, val; + double step; + +#ifdef DEBUG + pm_message("generating rgb colormap"); +#endif + /* generate a colormap of 7 "rays" in an RGB color cube: + r, g, b, r+g, r+b, g+b, r+g+b + we need one colormap entry for black, so the number of + entries per ray is (maxcolors-1)/7 */ + + entries = (hamcolors-1)/7; + colors = 7*entries+1; + MALLOCARRAY_NOFAIL(colormap, colors); + step = (double)MAXCOLVAL / (double)entries; + + PPM_ASSIGN(colormap[0], 0, 0, 0); + for( i = 1; i <= entries; i++ ) { + val = (int)((double)i * step); + PPM_ASSIGN(colormap[ i], val, 0, 0); /* r */ + PPM_ASSIGN(colormap[ entries+i], 0, val, 0); /* g */ + PPM_ASSIGN(colormap[2*entries+i], 0, 0, val); /* b */ + PPM_ASSIGN(colormap[3*entries+i], val, val, 0); /* r+g */ + PPM_ASSIGN(colormap[4*entries+i], val, 0, val); /* r+b */ + PPM_ASSIGN(colormap[5*entries+i], 0, val, val); /* g+b */ + PPM_ASSIGN(colormap[6*entries+i], val, val, val); /*r+g+b*/ + } + cmapmaxval = MAXCOLVAL; + } + break; + case HAMMODE_RGB4: + colormap = compute_ham_cmap(cols, rows, maxval, hamcolors, + &colors, 4); + cmapmaxval = 15; + break; + case HAMMODE_RGB5: + colormap = compute_ham_cmap(cols, rows, maxval, + hamcolors, &colors, 5); + cmapmaxval = 31; + break; + default: + pm_error("ppm_to_ham(): unknown hammapmode - can't happen"); + } + } + else { + hammapmode = HAMMODE_MAPFILE; + if( colors > hamcolors ) { + pm_message("colormap too large - using first %d colors", + hamcolors); + colors = hamcolors; + } + } + + if( cmapmaxval != maxval ) { + int i, *table; + pixel *newcmap; + + newcmap = ppm_allocrow(colors); + table = make_val_table(cmapmaxval, maxval); + for( i = 0; i < colors; i++ ) + PPM_ASSIGN(newcmap[i], + table[PPM_GETR(colormap[i])], + table[PPM_GETG(colormap[i])], + table[PPM_GETB(colormap[i])]); + free(table); + ppm_freerow(colormap); + colormap = newcmap; + } + if( sortcmap ) + ppm_sortcolorrow(colormap, colors, PPM_STDSORT); + + nPlanes = hamplanes; + cmapsize = colors * 3; + + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = do_ham_body(fp, NULL, cols, rows, maxval, + hammaxval, nPlanes, colormap, colors); + /*bodysize = do_ham_body(fp, NULL, cols, + rows, maxval, hammaxval, nPlanes, colbits, nocolor);*/ + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size " + "by %ld%%", + cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); + else + pm_message("BODY compression (%s): %ld%%", + cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); + } + + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmodes */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_ILBM); + + write_bmhd(cols, rows, nPlanes); + write_text_chunks(); + write_camg(); /* HAM requires CAMG chunk */ + write_cmap(colormap, colors, maxval); + + /* write body */ + put_big_long(ID_BODY); + put_big_long(bodysize); + if( DO_COMPRESS ) + write_body_rows(); + else + do_ham_body(fp, NULL, cols, rows, maxval, hammaxval, + nPlanes, colormap, colors); +} + + +static long +#ifdef __STDC__ +do_ham_body(FILE *ifP, FILE *ofp, int cols, int rows, + pixval maxval, pixval hammaxval, int nPlanes, + pixel *colormap, int colors) +#else +do_ham_body(ifP, ofp, cols, rows, maxval, hammaxval, nPlanes, colormap, colors) + FILE *ifP, *ofp; + int cols, rows; + pixval maxval; /* maxval of image color components */ + pixval hammaxval; /* maxval of HAM color changes */ + int nPlanes; + pixel *colormap; + int colors; +#endif +{ + register int col, row, i; + rawtype *raw_rowbuf; + ppm_fs_info *fi = NULL; + colorhash_table cht, cht2; + long bodysize = 0; + int *itoh; /* table image -> ham */ + int usehash = 1; + int colbits; + int hamcode_red, hamcode_green, hamcode_blue; + + MALLOCARRAY_NOFAIL(raw_rowbuf, cols); + + cht = ppm_colorrowtocolorhash(colormap, colors); + cht2 = ppm_alloccolorhash(); + colbits = pm_maxvaltobits(hammaxval); + + hamcode_red = HAMCODE_RED << colbits; + hamcode_green = HAMCODE_GREEN << colbits; + hamcode_blue = HAMCODE_BLUE << colbits; + + itoh = make_val_table(maxval, hammaxval); + + if( floyd ) + fi = ppm_fs_init(cols, maxval, 0); + + for( row = 0; row < rows; row++ ) { + int noprev; + int spr, spg, spb; /* scaled values of previous pixel */ + int upr, upg, upb; /* unscaled values of previous pixel, for floyd */ + pixel *prow; + + noprev = 1; + prow = next_pixrow(ifP, row); + for( col = ppm_fs_startrow(fi, prow); + col < cols; + col = ppm_fs_next(fi, col) ) { + + pixel const p = prow[col]; + + /* unscaled values of current pixel */ + pixval const ur = PPM_GETR(p); + pixval const ug = PPM_GETG(p); + pixval const ub = PPM_GETB(p); + + /* scaled values of current pixel */ + int const sr = itoh[ur]; + int const sg = itoh[ug]; + int const sb = itoh[ub]; + + i = ppm_lookupcolor(cht, &p); + if( i == -1 ) { /* no matching color in cmap, find closest match */ + int ucr, ucg, ucb; /* unscaled values of colormap entry */ + + if( hammapmode == HAMMODE_GRAY ) { + if( maxval <= 255 ) + /* Use fast approximation to + 0.299 r + 0.587 g + 0.114 b. */ + i = (int)ppm_fastlumin(p); + else + /* Can't use fast approximation, + so fall back on floats. + */ + i = (int)(PPM_LUMIN(p) + 0.5); + /* -IUW added '+ 0.5' */ + i = itoh[i]; + } + else { + i = ppm_lookupcolor(cht2, &p); + if( i == -1 ) { + i = ppm_findclosestcolor(colormap, colors, &p); + if( usehash ) { + if( ppm_addtocolorhash(cht2, &p, i) < 0 ) { + pm_message("out of memory " + "adding to hash table, " + "proceeding without it"); + usehash = 0; + } + } + } + } + ucr = PPM_GETR(colormap[i]); + ucg = PPM_GETG(colormap[i]); + ucb = PPM_GETB(colormap[i]); + + if( noprev ) { /* no previous pixel, must use colormap */ + raw_rowbuf[col] = i; /* + (HAMCODE_CMAP << colbits) */ + upr = ucr; upg = ucg; upb = ucb; + spr = itoh[upr]; spg = itoh[upg]; spb = itoh[upb]; + noprev = 0; + } else { + register long di, dr, dg, db; + int scr, scg, scb; /* scaled values of colormap entry */ + + scr = itoh[ucr]; scg = itoh[ucg]; scb = itoh[ucb]; + + /* compute distances for the four options */ +#if 1 + dr = abs(sg - spg) + abs(sb - spb); + dg = abs(sr - spr) + abs(sb - spb); + db = abs(sr - spr) + abs(sg - spg); + di = abs(sr - scr) + abs(sg - scg) + abs(sb - scb); +#else + dr = (sg - spg)*(sg - spg) + (sb - spb)*(sb - spb); + dg = (sr - spr)*(sr - spr) + (sb - spb)*(sb - spb); + db = (sr - spr)*(sr - spr) + (sg - spg)*(sg - spg); + di = (sr - scr)*(sr - scr) + (sg - scg)*(sg - scg) + + (sb - scb)*(sb - scb); +#endif + + if( di <= dr && di <= dg && di <= db ) { + /* prefer colormap lookup */ + raw_rowbuf[col] = i; + upr = ucr; upg = ucg; upb = ucb; + spr = scr; spg = scg; spb = scb; + } + else + if( db <= dr && db <= dg ) { + raw_rowbuf[col] = sb + hamcode_blue; + spb = sb; + upb = ub; + } + else + if( dr <= dg ) { + raw_rowbuf[col] = sr + hamcode_red; + spr = sr; + upr = ur; + } + else { + raw_rowbuf[col] = sg + hamcode_green; + spg = sg; + upg = ug; + } + } + } + else { /* prefect match in cmap */ + raw_rowbuf[col] = i; /* + (HAMCODE_CMAP << colbits) */ + upr = PPM_GETR(colormap[i]); + upg = PPM_GETG(colormap[i]); + upb = PPM_GETB(colormap[i]); + spr = itoh[upr]; + spg = itoh[upg]; + spb = itoh[upb]; + } + ppm_fs_update3(fi, col, upr, upg, upb); + } + bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes); + if( maskmethod == mskHasMask ) + bodysize += encode_maskrow(ofp, raw_rowbuf, cols); + ppm_fs_endrow(fi); + } + if( ofp && ODD(bodysize) ) + put_byte(0); + + free(itoh); + + /* clean up */ + free(raw_rowbuf); + ppm_fs_free(fi); + + return bodysize; +} + + +/************ deep (24-bit) ************/ + +static long do_deep_body ARGS((FILE *ifP, FILE *ofp, + int cols, int rows, + pixval maxval, int bitspercolor)); + +static void +ppm_to_deep(fp, cols, rows, maxval, bitspercolor) + FILE *fp; + int cols, rows, maxval, bitspercolor; +{ + int nPlanes; + long bodysize, oldsize, formsize; + + if( maskmethod == mskHasTransparentColor ) { + pm_message("masking method '%s' not usable with deep ILBM - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } + + nPlanes = 3*bitspercolor; + + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = do_deep_body(fp, NULL, cols, rows, maxval, bitspercolor); + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size by %ld%%", + cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); + else + pm_message("BODY compression (%s): %ld%%", + cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); + } + + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + if( gen_camg ) + formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ + + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_ILBM); + + write_bmhd(cols, rows, nPlanes); + write_text_chunks(); + if( gen_camg ) + write_camg(); + + /* write body */ + put_big_long(ID_BODY); + put_big_long(bodysize); + if( DO_COMPRESS ) + write_body_rows(); + else + do_deep_body(fp, stdout, cols, rows, maxval, bitspercolor); +} + + +static long +#if __STDC__ +do_deep_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, + int bitspercolor) +#else +do_deep_body(ifP, ofp, cols, rows, maxval, bitspercolor) + FILE *ifP, *ofp; + int cols, rows; + pixval maxval; + int bitspercolor; +#endif +{ + register int row, col; + pixel *pP; + int *table = NULL; + long bodysize = 0; + rawtype *redbuf, *greenbuf, *bluebuf; + int newmaxval; + + MALLOCARRAY_NOFAIL(redbuf, cols); + MALLOCARRAY_NOFAIL(greenbuf, cols); + MALLOCARRAY_NOFAIL(bluebuf, cols); + + newmaxval = pm_bitstomaxval(bitspercolor); + if( maxval != newmaxval ) { + pm_message("maxval is not %d - automatically rescaling colors", + newmaxval); + table = make_val_table(maxval, newmaxval); + } + + for( row = 0; row < rows; row++ ) { + pP = next_pixrow(ifP, row); + if( table ) { + for( col = 0; col < cols; col++, pP++ ) { + redbuf[col] = table[PPM_GETR(*pP)]; + greenbuf[col] = table[PPM_GETG(*pP)]; + bluebuf[col] = table[PPM_GETB(*pP)]; + } + } + else { + for( col = 0; col < cols; col++, pP++ ) { + redbuf[col] = PPM_GETR(*pP); + greenbuf[col] = PPM_GETG(*pP); + bluebuf[col] = PPM_GETB(*pP); + } + } + bodysize += encode_row(ofp, redbuf, cols, bitspercolor); + bodysize += encode_row(ofp, greenbuf, cols, bitspercolor); + bodysize += encode_row(ofp, bluebuf, cols, bitspercolor); + if( maskmethod == mskHasMask ) + bodysize += encode_maskrow(ofp, redbuf, cols); + } + if( ofp && ODD(bodysize) ) + put_byte(0); + + /* clean up */ + if( table ) + free(table); + free(redbuf); + free(greenbuf); + free(bluebuf); + + return bodysize; +} + + +/************ direct color ************/ + +static long do_dcol_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, + pixval maxval, DirectColor *dcol)); + +static void +ppm_to_dcol(fp, cols, rows, maxval, dcol) + FILE *fp; + int cols, rows, maxval; + DirectColor *dcol; +{ + int nPlanes; + long bodysize, oldsize, formsize; + + if( maskmethod == mskHasTransparentColor ) { + pm_message("masking method '%s' not usable with deep ILBM - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } + + nPlanes = dcol->r + dcol->g + dcol->b; + + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = do_dcol_body(fp, NULL, cols, rows, maxval, dcol); + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size by %ld%%", + cmpNAME[compmethod], + 100*(bodysize-oldsize)/oldsize); + else + pm_message("BODY compression (%s): %ld%%", cmpNAME[compmethod], + 100*(oldsize-bodysize)/oldsize); + } + + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + DirectColorSize + /* DCOL size dcol */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + if( gen_camg ) + formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ + + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_ILBM); + + write_bmhd(cols, rows, nPlanes); + write_text_chunks(); + + put_big_long(ID_DCOL); + put_big_long(DirectColorSize); + put_byte(dcol->r); + put_byte(dcol->g); + put_byte(dcol->b); + put_byte(0); /* pad */ + + if( gen_camg ) + write_camg(); + + /* write body */ + put_big_long(ID_BODY); + put_big_long(bodysize); + if( DO_COMPRESS ) + write_body_rows(); + else + do_dcol_body(fp, stdout, cols, rows, maxval, dcol); +} + + +static long +#if __STDC__ +do_dcol_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, + DirectColor *dcol) +#else +do_dcol_body(ifP, ofp, cols, rows, maxval, dcol) + FILE *ifP, *ofp; + int cols, rows; + pixval maxval; + DirectColor *dcol; +#endif +{ + register int row, col; + pixel *pP; + long bodysize = 0; + rawtype *redbuf, *greenbuf, *bluebuf; + int *redtable, *greentable, *bluetable; + + MALLOCARRAY_NOFAIL(redbuf, cols); + MALLOCARRAY_NOFAIL(greenbuf, cols); + MALLOCARRAY_NOFAIL(bluebuf, cols); + + redtable = make_val_table(maxval, pm_bitstomaxval(dcol->r)); + greentable = make_val_table(maxval, pm_bitstomaxval(dcol->g)); + bluetable = make_val_table(maxval, pm_bitstomaxval(dcol->b)); + + for( row = 0; row < rows; row++ ) { + pP = next_pixrow(ifP, row); + for( col = 0; col < cols; col++, pP++ ) { + redbuf[col] = redtable[PPM_GETR(*pP)]; + greenbuf[col] = greentable[PPM_GETG(*pP)]; + bluebuf[col] = bluetable[PPM_GETB(*pP)]; + } + bodysize += encode_row(ofp, redbuf, cols, dcol->r); + bodysize += encode_row(ofp, greenbuf, cols, dcol->g); + bodysize += encode_row(ofp, bluebuf, cols, dcol->b); + if( maskmethod == mskHasMask ) + bodysize += encode_maskrow(ofp, redbuf, cols); + } + if( ofp && ODD(bodysize) ) + put_byte(0); + + /* clean up */ + free(redtable); + free(greentable); + free(bluetable); + free(redbuf); + free(greenbuf); + free(bluebuf); + + return bodysize; +} + + +/************ normal colormapped ************/ + +static long do_std_body ARGS((FILE *ifP, FILE *ofp, int cols, int rows, + pixval maxval, pixel *colormap, + int colors, int nPlanes)); + +static void +ppm_to_std(fp, cols, rows, maxval, colormap, colors, cmapmaxval, + maxcolors, nPlanes) + FILE *fp; + int cols, rows, maxval; + pixel *colormap; + int cmapmaxval, colors, maxcolors, nPlanes; +{ + long formsize, cmapsize, bodysize, oldsize; + + if( maskmethod == mskHasTransparentColor ) { + if( transpColor ) { + transpIndex = + ppm_addtocolorrow(colormap, &colors, maxcolors, transpColor); + } + else + if( colors < maxcolors ) + transpIndex = colors; + + if( transpIndex < 0 ) { + pm_message("too many colors for masking method '%s' - " + "using '%s' instead", + mskNAME[mskHasTransparentColor], mskNAME[mskHasMask]); + maskmethod = mskHasMask; + } + } + + if( cmapmaxval != maxval ) { + int i, *table; + pixel *newcmap; + + newcmap = ppm_allocrow(colors); + table = make_val_table(cmapmaxval, maxval); + for (i = 0; i < colors; ++i) + PPM_ASSIGN(newcmap[i], + table[PPM_GETR(colormap[i])], + table[PPM_GETG(colormap[i])], + table[PPM_GETB(colormap[i])]); + free(table); + colormap = newcmap; + } + if( sortcmap ) + ppm_sortcolorrow(colormap, colors, PPM_STDSORT); + + bodysize = oldsize = rows * TOTALPLANES(nPlanes) * RowBytes(cols); + if( DO_COMPRESS ) { + bodysize = do_std_body(fp, NULL, cols, rows, maxval, colormap, + colors, nPlanes); + if( bodysize > oldsize ) + pm_message("warning - %s compression increases BODY size by %ld%%", + cmpNAME[compmethod], 100*(bodysize-oldsize)/oldsize); + else + pm_message("BODY compression (%s): %ld%%", + cmpNAME[compmethod], 100*(oldsize-bodysize)/oldsize); + } + + cmapsize = colors * 3; + + formsize = + 4 + /* ILBM */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + cmapsize + PAD(cmapsize) + /* CMAP size colormap */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + if( gen_camg ) + formsize += 4 + 4 + CAMGChunkSize; /* CAMG size viewportmodes */ + + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_ILBM); + + write_bmhd(cols, rows, nPlanes); + write_text_chunks(); + if( gen_camg ) + write_camg(); + write_cmap(colormap, colors, maxval); + + /* write body */ + put_big_long(ID_BODY); + put_big_long(bodysize); + if( DO_COMPRESS ) + write_body_rows(); + else + do_std_body(fp, stdout, cols, rows, maxval, colormap, colors, nPlanes); +} + + +static long +#if __STDC__ +do_std_body(FILE *ifP, FILE *ofp, int cols, int rows, pixval maxval, + pixel *colormap, int colors, int nPlanes) +#else +do_std_body(ifP, ofp, cols, rows, maxval, colormap, colors, nPlanes) + FILE *ifP, *ofp; + int cols, rows; + pixval maxval; + pixel *colormap; + int colors; + int nPlanes; +#endif +{ + register int row, col, i; + pixel *pP; + rawtype *raw_rowbuf; + ppm_fs_info *fi = NULL; + long bodysize = 0; + int usehash = 1; + colorhash_table cht; + + MALLOCARRAY_NOFAIL(raw_rowbuf, cols); + cht = ppm_colorrowtocolorhash(colormap, colors); + if( floyd ) + fi = ppm_fs_init(cols, maxval, FS_ALTERNATE); + + for( row = 0; row < rows; row++ ) { + pixel *prow; + prow = next_pixrow(ifP, row); + + for( col = ppm_fs_startrow(fi, prow); + col < cols; + col = ppm_fs_next(fi, col) ) { + pP = &prow[col]; + + if( maskmethod == mskHasTransparentColor && + maskrow[col] == PBM_WHITE ) + i = transpIndex; + else { + /* Check hash table to see if we have already matched + this color. + */ + i = ppm_lookupcolor(cht, pP); + if( i == -1 ) { + i = ppm_findclosestcolor(colormap, colors, pP); + /* No; search colormap for closest match. */ + if( usehash ) { + if( ppm_addtocolorhash(cht, pP, i) < 0 ) { + pm_message("out of memory adding to hash table, " + "proceeding without it"); + usehash = 0; + } + } + } + } + raw_rowbuf[col] = i; + ppm_fs_update(fi, col, &colormap[i]); + } + bodysize += encode_row(ofp, raw_rowbuf, cols, nPlanes); + if( maskmethod == mskHasMask ) + bodysize += encode_maskrow(ofp, raw_rowbuf, cols); + ppm_fs_endrow(fi); + } + if( ofp && ODD(bodysize) ) + put_byte(0); + + /* clean up */ + ppm_freecolorhash(cht); + free(raw_rowbuf); + ppm_fs_free(fi); + + return bodysize; +} + +/************ RGB8 ************/ + +static void +ppm_to_rgb8(ifP, cols, rows, maxval) + FILE *ifP; + int cols, rows; + int maxval; +{ + long bodysize, oldsize, formsize; + pixel *pP; + int *table = NULL; + int row, col1, col2, compr_len, len; + unsigned char *compr_row; + + maskmethod = 0; /* no masking - RGB8 uses genlock bits */ + compmethod = 4; /* RGB8 files are always compressed */ + MALLOCARRAY_NOFAIL(compr_row, cols * 4); + + if( maxval != 255 ) { + pm_message("maxval is not 255 - automatically rescaling colors"); + table = make_val_table(maxval, 255); + } + + oldsize = cols * rows * 4; + bodysize = 0; + for( row = 0; row < rows; row++ ) { + pP = next_pixrow(ifP, row); + compr_len = 0; + for( col1 = 0; col1 < cols; col1 = col2 ) { + col2 = col1 + 1; + if( maskrow ) { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && + maskrow[col1] == maskrow[col2] ) + col2++; + } + else { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) + col2++; + } + len = col2 - col1; + while( len ) { + int count; + count = (len > 127 ? 127 : len); + len -= count; + if( table ) { + compr_row[compr_len++] = table[PPM_GETR(pP[col1])]; + compr_row[compr_len++] = table[PPM_GETG(pP[col1])]; + compr_row[compr_len++] = table[PPM_GETB(pP[col1])]; + } + else { + compr_row[compr_len++] = PPM_GETR(pP[col1]); + compr_row[compr_len++] = PPM_GETG(pP[col1]); + compr_row[compr_len++] = PPM_GETB(pP[col1]); + } + compr_row[compr_len] = count; + if( maskrow && maskrow[col1] == PBM_WHITE ) + compr_row[compr_len] |= 1<<7; /* genlock bit */ + ++compr_len; + } + } + store_bodyrow(compr_row, compr_len); + bodysize += compr_len; + } + + pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); + + formsize = + 4 + /* RGB8 */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + + /* write header */ + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_RGB8); + + write_bmhd(cols, rows, 25); + write_text_chunks(); + write_camg(); /* RGB8 requires CAMG chunk */ + + put_big_long(ID_BODY); + put_big_long(bodysize); + write_body_rows(); +} + + +/************ RGBN ************/ + +static void +ppm_to_rgbn(ifP, cols, rows, maxval) + FILE *ifP; + int cols, rows; + int maxval; +{ + long bodysize, oldsize, formsize; + pixel *pP; + int *table = NULL; + int row, col1, col2, compr_len, len; + unsigned char *compr_row; + + maskmethod = 0; /* no masking - RGBN uses genlock bits */ + compmethod = 4; /* RGBN files are always compressed */ + MALLOCARRAY_NOFAIL(compr_row, cols * 2); + + if( maxval != 15 ) { + pm_message("maxval is not 15 - automatically rescaling colors"); + table = make_val_table(maxval, 15); + } + + oldsize = cols * rows * 2; + bodysize = 0; + for( row = 0; row < rows; row++ ) { + pP = next_pixrow(ifP, row); + compr_len = 0; + for( col1 = 0; col1 < cols; col1 = col2 ) { + col2 = col1 + 1; + if( maskrow ) { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) && + maskrow[col1] == maskrow[col2] ) + col2++; + } + else { + while( col2 < cols && PPM_EQUAL(pP[col1], pP[col2]) ) + col2++; + } + len = col2 - col1; + while( len ) { + int count; + count = (len > 65535 ? 65535 : len); + len -= count; + if( table ) { + compr_row[compr_len] = table[PPM_GETR(pP[col1])] << 4; + compr_row[compr_len] |= table[PPM_GETG(pP[col1])]; + ++compr_len; + compr_row[compr_len] = table[PPM_GETB(pP[col1])] << 4; + } + else { + compr_row[compr_len] = PPM_GETR(pP[col1]) << 4; + compr_row[compr_len] |= PPM_GETG(pP[col1]); + ++compr_len; + compr_row[compr_len] = PPM_GETB(pP[col1]) << 4; + } + if( maskrow && maskrow[col1] == PBM_WHITE ) + compr_row[compr_len] |= 1<<3; /* genlock bit */ + if( count <= 7 ) + compr_row[compr_len++] |= count; /* 3 bit repeat count */ + else { + ++compr_len; /* 3 bit repeat count = 0 */ + if( count <= 255 ) + compr_row[compr_len++] = (unsigned char)count; + /* byte repeat count */ + else { + compr_row[compr_len++] = (unsigned char)0; + /* byte repeat count = 0 */ + compr_row[compr_len++] = (count >> 8) & 0xff; + /* word repeat count MSB */ + compr_row[compr_len++] = count & 0xff; + /* word repeat count LSB */ + } + } + } + } + store_bodyrow(compr_row, compr_len); + bodysize += compr_len; + } + + pm_message("BODY compression: %ld%%", 100*(oldsize-bodysize)/oldsize); + + formsize = + 4 + /* RGBN */ + 4 + 4 + BitMapHeaderSize + /* BMHD size header */ + 4 + 4 + CAMGChunkSize + /* CAMG size viewportmode */ + 4 + 4 + bodysize + PAD(bodysize) + /* BODY size data */ + length_of_text_chunks(); + + /* write header */ + put_big_long(ID_FORM); + put_big_long(formsize); + put_big_long(ID_RGBN); + + write_bmhd(cols, rows, 13); + write_text_chunks(); + write_camg(); /* RGBN requires CAMG chunk */ + + put_big_long(ID_BODY); + put_big_long(bodysize); + write_body_rows(); +} + + +/************ multipalette ************/ + +#ifdef ILBM_PCHG +static pixel *ppmslice[2]; /* need 2 for laced ILBMs, else 1 */ + +void ppm_to_pchg() +{ +/* + read first slice + build a colormap from this slice + select upto <maxcolors> colors + build colormap from selected colors + map slice to colormap + write slice + while( !finished ) { + read next slice + compute distances for each pixel and select upto + <maxchangesperslice> unused colors in this slice + modify selected colors to the ones with maximum(?) distance + map slice to colormap + write slice + } + + + for HAM use a different mapping: + compute distance to closest color in colormap + if( there is no matching color in colormap ) { + compute distances for the three "modify" cases + use the shortest distance from the four cases + } +*/ +} +#endif + + +/************ ILBM functions ************/ + +static int +length_of_text_chunks ARGS((void)) +{ + int len, n; + + len = 0; + if( anno_chunk ) { + n = strlen(anno_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( auth_chunk ) { + n = strlen(auth_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( name_chunk ) { + n = strlen(name_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( copyr_chunk ) { + n = strlen(copyr_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + if( text_chunk ) { + n = strlen(text_chunk); + len += 4 + 4 + n + PAD(n); /* ID chunksize text */ + } + return len; +} + + +static void +write_text_chunks ARGS((void)) +{ + int n; + + if( anno_chunk ) { + n = strlen(anno_chunk); + put_big_long(ID_ANNO); + put_big_long(n); + write_bytes((unsigned char *)anno_chunk, n); + if( ODD(n) ) + put_byte(0); + } + if( auth_chunk ) { + n = strlen(auth_chunk); + put_big_long(ID_AUTH); + put_big_long(n); + write_bytes((unsigned char *)auth_chunk, n); + if( ODD(n) ) + put_byte(0); + } + if( copyr_chunk ) { + n = strlen(copyr_chunk); + put_big_long(ID_copy); + put_big_long(n); + write_bytes((unsigned char *)copyr_chunk, n); + if( ODD(n) ) + put_byte(0); + } + if( name_chunk ) { + n = strlen(name_chunk); + put_big_long(ID_NAME); + put_big_long(n); + write_bytes((unsigned char *)name_chunk, n); + if( ODD(n) ) + put_byte(0); + } + if( text_chunk ) { + n = strlen(text_chunk); + put_big_long(ID_TEXT); + put_big_long(n); + write_bytes((unsigned char *)text_chunk, n); + if( ODD(n) ) + put_byte(0); + } +} + + +static void +write_cmap(colormap, colors, maxval) + pixel *colormap; + int colors, maxval; +{ + int cmapsize, i; + + cmapsize = 3 * colors; + + /* write colormap */ + put_big_long(ID_CMAP); + put_big_long(cmapsize); + if( maxval != MAXCOLVAL ) { + int *table; + pm_message("maxval is not %d - automatically rescaling colors", + MAXCOLVAL); + table = make_val_table(maxval, MAXCOLVAL); + for( i = 0; i < colors; i++ ) { + put_byte(table[PPM_GETR(colormap[i])]); + put_byte(table[PPM_GETG(colormap[i])]); + put_byte(table[PPM_GETB(colormap[i])]); + } + free(table); + } + else { + for( i = 0; i < colors; i++ ) { + put_byte(PPM_GETR(colormap[i])); + put_byte(PPM_GETG(colormap[i])); + put_byte(PPM_GETB(colormap[i])); + } + } + if( ODD(cmapsize) ) + put_byte(0); +} + + +static void +write_bmhd(cols, rows, nPlanes) + int cols, rows, nPlanes; +{ + unsigned char xasp = 10, yasp = 10; + + if( viewportmodes & vmLACE ) + xasp *= 2; + if( viewportmodes & vmHIRES ) + yasp *= 2; + + put_big_long(ID_BMHD); + put_big_long(BitMapHeaderSize); + + put_big_short(cols); + put_big_short(rows); + put_big_short(0); /* x-offset */ + put_big_short(0); /* y-offset */ + put_byte(nPlanes); /* no of planes */ + put_byte(maskmethod); /* masking */ + put_byte(compmethod); /* compression */ + put_byte(BMHD_FLAGS_CMAPOK); /* flags */ + if( maskmethod == mskHasTransparentColor ) + put_big_short(transpIndex); + else + put_big_short(0); + put_byte(xasp); /* x-aspect */ + put_byte(yasp); /* y-aspect */ + put_big_short(cols); /* pageWidth */ + put_big_short(rows); /* pageHeight */ +} + + +/* encode algorithm by Johan Widen (jw@jwdata.se) */ +static const unsigned char bitmask[] = {1, 2, 4, 8, 16, 32, 64, 128}; + +static long +encode_row(outfile, rawrow, cols, nPlanes) + FILE *outfile; /* if non-NULL, write uncompressed row to this file */ + rawtype *rawrow; + int cols, nPlanes; +{ + int plane, bytes; + long retbytes = 0; + + bytes = RowBytes(cols); + + /* Encode and write raw bytes in plane-interleaved form. */ + for( plane = 0; plane < nPlanes; plane++ ) { + register int col, cbit; + register rawtype *rp; + register unsigned char *cp; + int mask; + + mask = 1 << plane; + cbit = -1; + cp = coded_rowbuf-1; + rp = rawrow; + for( col = 0; col < cols; col++, cbit--, rp++ ) { + if( cbit < 0 ) { + cbit = 7; + *++cp = 0; + } + if( *rp & mask ) + *cp |= bitmask[cbit]; + } + if( outfile ) { + write_bytes(coded_rowbuf, bytes); + retbytes += bytes; + } + else + retbytes += compress_row(bytes); + } + return retbytes; +} + + +static long +encode_maskrow(ofp, rawrow, cols) + FILE *ofp; + rawtype *rawrow; + int cols; +{ + int col; + + for( col = 0; col < cols; col++ ) { + if( maskrow[col] == PBM_BLACK ) + rawrow[col] = 1; + else + rawrow[col] = 0; + } + return encode_row(ofp, rawrow, cols, 1); +} + + +static int +compress_row(bytes) + int bytes; +{ + int newbytes; + + switch( compmethod ) { + case cmpByteRun1: + newbytes = runbyte1(bytes); + break; + default: + pm_error("compress_row(): unknown compression method %d", + compmethod); + } + store_bodyrow(compr_rowbuf, newbytes); + + return newbytes; +} + + +static void +store_bodyrow(row, len) + unsigned char *row; + int len; +{ + int idx = cur_block->used; + if( idx >= ROWS_PER_BLOCK ) { + MALLOCVAR_NOFAIL(cur_block->next); + cur_block = cur_block->next; + cur_block->used = idx = 0; + cur_block->next = NULL; + } + MALLOCARRAY_NOFAIL(cur_block->row[idx], len); + cur_block->len[idx] = len; + memcpy(cur_block->row[idx], row, len); + cur_block->used++; +} + + +static void +write_body_rows ARGS((void)) +{ + bodyblock *b; + int i; + long total = 0; + + for( b = &firstblock; b != NULL; b = b->next ) { + for( i = 0; i < b->used; i++ ) { + write_bytes(b->row[i], b->len[i]); + total += b->len[i]; + } + } + if( ODD(total) ) + put_byte(0); +} + + +static void +write_camg ARGS((void)) +{ + put_big_long(ID_CAMG); + put_big_long(CAMGChunkSize); + put_big_long(viewportmodes); +} + + +/************ compression ************/ + + +/* runbyte1 algorithm by Robert A. Knop (rknop@mop.caltech.edu) */ +static int +runbyte1(size) + int size; +{ + int in,out,count,hold; + register unsigned char *inbuf = coded_rowbuf; + register unsigned char *outbuf = compr_rowbuf; + + + in=out=0; + while( in<size ) { + if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) { + /*Begin replicate run*/ + for( count=0, hold=in; + in < size && inbuf[in] == inbuf[hold] && count < 128; + in++, count++) + ; + outbuf[out++]=(unsigned char)(char)(-count+1); + outbuf[out++]=inbuf[hold]; + } + else { /*Do a literal run*/ + hold=out; out++; count=0; + while( ((in>=size-2)&&(in<size)) || + ((in<size-2) && ((inbuf[in]!=inbuf[in+1]) + ||(inbuf[in]!=inbuf[in+2]))) ) { + outbuf[out++]=inbuf[in++]; + if( ++count>=128 ) + break; + } + outbuf[hold]=count-1; + } + } + return(out); +} + + + +/************ other utility functions ************/ + +static void +#if __STDC__ +put_big_short(short s) +#else +put_big_short(s) + short s; +#endif +{ + if ( pm_writebigshort( stdout, s ) == -1 ) + pm_error( "write error" ); +} + + +static void +put_big_long(l) + long l; +{ + if ( pm_writebiglong( stdout, l ) == -1 ) + pm_error( "write error" ); +} + + +static void +write_bytes(buffer, bytes) + unsigned char *buffer; + int bytes; +{ + if( fwrite(buffer, 1, bytes, stdout) != bytes ) + pm_error("write error"); +} + + +static int * +make_val_table(oldmaxval, newmaxval) + int oldmaxval, newmaxval; +{ + int i; + int *table; + + MALLOCARRAY_NOFAIL(table, oldmaxval + 1); + for(i = 0; i <= oldmaxval; i++ ) + table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval; + + return table; +} + + + +static int gFormat; +static int gCols; +static int gMaxval; + +static void +init_read(fp, colsP, rowsP, maxvalP, formatP, readall) + FILE *fp; + int *colsP, *rowsP; + pixval *maxvalP; + int *formatP; + int readall; +{ + ppm_readppminit(fp, colsP, rowsP, maxvalP, formatP); + if( readall ) { + int row; + + pixels = ppm_allocarray(*colsP, *rowsP); + for( row = 0; row < *rowsP; row++ ) + ppm_readppmrow(fp, pixels[row], *colsP, *maxvalP, *formatP); + /* pixels = ppm_readppm(fp, colsP, rowsP, maxvalP); */ + } + else { + pixrow = ppm_allocrow(*colsP); + } + gCols = *colsP; + gMaxval = *maxvalP; + gFormat = *formatP; +} + + +static pixel * +next_pixrow(fp, row) + FILE *fp; + int row; +{ + if( pixels ) + pixrow = pixels[row]; + else { + ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat); + } + if( maskrow ) { + int col; + + if( maskfile ) + pbm_readpbmrow(maskfile, maskrow, maskcols, maskformat); + else { + for( col = 0; col < gCols; col++ ) + maskrow[col] = PBM_BLACK; + } + if( transpColor ) { + for( col = 0; col < gCols; col++ ) + if( PPM_EQUAL(pixrow[col], *transpColor) ) + maskrow[col] = PBM_WHITE; + } + } + return pixrow; +} + + + +int +main(int argc, char ** argv) { + + FILE * ifP; + int argn, rows, cols, format, nPlanes; + int ifmode, forcemode, maxplanes, fixplanes, mode; + int hamplanes; + int deepbits; /* bits per color component in deep ILBM */ + DirectColor dcol; +#define MAXCOLORS (1<<maxplanes) + pixval maxval; + pixel * colormap; + int colors = 0; + pixval cmapmaxval; /* maxval of colors in cmap */ + const char * mapfile; + const char * transpname; + + ppm_init(&argc, argv); + + colormap = NULL; /* initial value */ + ifmode = DEF_IFMODE; forcemode = MODE_NONE; + maxplanes = DEF_MAXPLANES; fixplanes = 0; + hamplanes = DEF_HAMPLANES; + deepbits = DEF_DEEPPLANES; + dcol.r = dcol.g = dcol.b = DEF_DCOLPLANES; + mapfile = transpname = NULL; + + argn = 1; + while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { + if( pm_keymatch(argv[argn], "-ilbm", 5) ) { + if( forcemode == MODE_RGB8 || forcemode == MODE_RGBN ) + forcemode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-rgb8", 5) ) + forcemode = MODE_RGB8; + else + if( pm_keymatch(argv[argn], "-rgbn", 5) ) + forcemode = MODE_RGBN; + else + if( pm_keymatch(argv[argn], "-maxplanes", 4) || + pm_keymatch(argv[argn], "-mp", 3) ) { + if( ++argn >= argc ) + pm_error("-maxplanes requires a value"); + maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + fixplanes = 0; + } + else + if( pm_keymatch(argv[argn], "-fixplanes", 4) || + pm_keymatch(argv[argn], "-fp", 3) ) { + if( ++argn >= argc ) + pm_error("-fixplanes requires a value"); + fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + maxplanes = fixplanes; + } + else + if( pm_keymatch(argv[argn], "-mapfile", 4) ) { + if( ++argn >= argc ) + pm_error("-mapfile requires a value"); + mapfile = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-mmethod", 3) ) { + if( ++argn >= argc ) + pm_error("-mmethod requires a value"); + maskmethod = get_mask_type(argv[argn]); + switch( maskmethod ) { + case mskNone: + case mskHasMask: + case mskHasTransparentColor: + break; + default: + pm_error("This program does not know how to handle " + "masking method '%s'", + mskNAME[maskmethod]); + } + } + else + if( pm_keymatch(argv[argn], "-maskfile", 4) ) { + if( ++argn >= argc ) + pm_error("-maskfile requires a value"); + maskfile = pm_openr(argv[argn]); + if( maskmethod == mskNone ) + maskmethod = mskHasMask; + } + else + if( pm_keymatch(argv[argn], "-transparent", 3) ) { + if( ++argn >= argc ) + pm_error("-transparent requires a value"); + transpname = argv[argn]; + if( maskmethod == mskNone ) + maskmethod = mskHasTransparentColor; + } + else + if( pm_keymatch(argv[argn], "-sortcmap", 5) ) + sortcmap = 1; + else + if( pm_keymatch(argv[argn], "-cmaponly", 3) ) { + forcemode = MODE_CMAP; + } + else + if( pm_keymatch(argv[argn], "-lace", 2) ) { + slicesize = 2; + viewportmodes |= vmLACE; + gen_camg = 1; + } + else + if( pm_keymatch(argv[argn], "-nolace", 4) ) { + slicesize = 1; + viewportmodes &= ~vmLACE; + } + else + if( pm_keymatch(argv[argn], "-hires", 3) ) { + viewportmodes |= vmHIRES; + gen_camg = 1; + } + else + if( pm_keymatch(argv[argn], "-nohires", 5) ) + viewportmodes &= ~vmHIRES; + else + if( pm_keymatch(argv[argn], "-camg", 5) ) { + char *tail; + long value = 0L; + + if( ++argn >= argc ) + pm_error("-camg requires a value"); + value = strtol(argv[argn], &tail, 16); + /* TODO: should do some error checking here */ + viewportmodes |= value; + gen_camg = 1; + } + else + if( pm_keymatch(argv[argn], "-ecs", 2) ) { + maxplanes = ECS_MAXPLANES; + hamplanes = ECS_HAMPLANES; + } + else + if( pm_keymatch(argv[argn], "-aga", 3) ) { + maxplanes = AGA_MAXPLANES; + hamplanes = AGA_HAMPLANES; + } + else + if( pm_keymatch(argv[argn], "-hamplanes", 5) ) { + if( ++argn >= argc ) + pm_error("-hamplanes requires a value"); + hamplanes = get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES); + } + else + if( pm_keymatch(argv[argn], "-hambits", 5) ) { + if( ++argn >= argc ) + pm_usage("-hambits requires a value"); + hamplanes = + get_int_val(argv[argn], argv[argn-1], 3, HAMMAXPLANES-2) +2; + } + else + if( pm_keymatch(argv[argn], "-ham6", 5) ) { + hamplanes = ECS_HAMPLANES; + forcemode = MODE_HAM; + } + else + if( pm_keymatch(argv[argn], "-ham8", 5) ) { + hamplanes = AGA_HAMPLANES; + forcemode = MODE_HAM; + } + else + if( pm_keymatch(argv[argn], "-hammap", 5) ) { + if( ++argn >= argc ) + pm_error("-hammap requires a value"); + hammapmode = get_hammap_mode(argv[argn]); + } + else + if( pm_keymatch(argv[argn], "-hamif", 5) ) + ifmode = MODE_HAM; + else + if( pm_keymatch(argv[argn], "-nohamif", 7) ) { + if( ifmode == MODE_HAM ) + ifmode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-hamforce", 4) ) + forcemode = MODE_HAM; + else + if( pm_keymatch(argv[argn], "-nohamforce", 6) ) { + if( forcemode == MODE_HAM ) + forcemode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-24if", 4) ) { + ifmode = MODE_DEEP; + deepbits = 8; + } + else + if( pm_keymatch(argv[argn], "-no24if", 6) ) { + if( ifmode == MODE_DEEP ) + ifmode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-24force", 3) ) { + forcemode = MODE_DEEP; + deepbits = 8; + } + else + if( pm_keymatch(argv[argn], "-no24force", 5) ) { + if( forcemode == MODE_DEEP ) + forcemode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-deepplanes", 6) ) { + if( ++argn >= argc ) + pm_error("-deepplanes requires a value"); + deepbits = get_int_val(argv[argn], argv[argn-1], 3, 3*MAXPLANES); + if( deepbits % 3 != 0 ) + pm_error("option \"%s\" argument value must be divisible by 3", + argv[argn-1]); + deepbits /= 3; + } + else + if( pm_keymatch(argv[argn], "-deepbits", 6) ) { + if( ++argn >= argc ) + pm_error("-deepbits requires a value"); + deepbits = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES); + } + else + if( pm_keymatch(argv[argn], "-deepif", 6) ) + ifmode = MODE_DEEP; + else + if( pm_keymatch(argv[argn], "-nodeepif", 8) ) { + if( ifmode == MODE_DEEP ) + ifmode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-deepforce", 5) ) + forcemode = MODE_DEEP; + else + if( pm_keymatch(argv[argn], "-nodeepforce", 7) ) { + if( forcemode == MODE_DEEP ) + forcemode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-dcif", 4) ) + ifmode = MODE_DCOL; + else + if( pm_keymatch(argv[argn], "-nodcif", 6) ) { + if( ifmode == MODE_DCOL ) + ifmode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-dcforce", 4) ) + forcemode = MODE_DCOL; + else + if( pm_keymatch(argv[argn], "-nodcforce", 6) ) { + if( forcemode == MODE_DCOL ) + forcemode = MODE_NONE; + } + else + if( pm_keymatch(argv[argn], "-dcbits", 4) || + pm_keymatch(argv[argn], "-dcplanes", 4) ) { + if( argc - argn < 4 ) + pm_error("-dcbits requires 4 arguments"); + dcol.r = get_int_val(argv[argn+1], argv[argn], 1, MAXPLANES); + dcol.g = get_int_val(argv[argn+2], argv[argn], 1, MAXPLANES); + dcol.b = get_int_val(argv[argn+3], argv[argn], 1, MAXPLANES); + argn += 3; + } + else + if( pm_keymatch(argv[argn], "-normal", 4) ) { + ifmode = forcemode = MODE_NONE; + compmethod = DEF_COMPRESSION; + } + else + if( pm_keymatch(argv[argn], "-compress", 4) ) { + compr_force = 1; + if( compmethod == cmpNone ) +#if DEF_COMPRESSION == cmpNone + compmethod = cmpByteRun1; +#else + compmethod = DEF_COMPRESSION; +#endif + } + else + if( pm_keymatch(argv[argn], "-nocompress", 4) ) { + compr_force = 0; + compmethod = cmpNone; + } + else + if( pm_keymatch(argv[argn], "-cmethod", 4) ) { + if( ++argn >= argc ) + pm_error("-cmethod requires a value"); + compmethod = get_compr_method(argv[argn]); + } + else + if( pm_keymatch(argv[argn], "-floyd", 3) || + pm_keymatch(argv[argn], "-fs", 3) ) + floyd = 1; + else + if( pm_keymatch(argv[argn], "-nofloyd", 5) || + pm_keymatch(argv[argn], "-nofs", 5) ) + floyd = 0; + else + if( pm_keymatch(argv[argn], "-annotation", 3) ) { + if( ++argn >= argc ) + pm_error("-annotation requires a value"); + anno_chunk = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-author", 3) ) { + if( ++argn >= argc ) + pm_error("-author requires a value"); + auth_chunk = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-copyright", 4) ) { + if( ++argn >= argc ) + pm_error("-copyright requires a value"); + copyr_chunk = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-name", 3) ) { + if( ++argn >= argc ) + pm_error("-name requires a value"); + name_chunk = argv[argn]; + } + else + if( pm_keymatch(argv[argn], "-text", 3) ) { + if( ++argn >= argc ) + pm_error("-text requires a value"); + text_chunk = argv[argn]; + } + else + pm_error("invalid option: %s", argv[argn]); + ++argn; + } + + if( argn < argc ) { + ifP = pm_openr(argv[argn]); + ++argn; + } + else + ifP = stdin; + + if( argn != argc ) + pm_error("Program takes no arguments."); + + mode = forcemode; + switch(forcemode) { + case MODE_HAM: + if (hammapmode == HAMMODE_RGB4 || hammapmode == HAMMODE_RGB5) + init_read(ifP, &cols, &rows, &maxval, &format, 1); + else + init_read(ifP, &cols, &rows, &maxval, &format, 0); + break; + case MODE_DCOL: + case MODE_DEEP: + mapfile = NULL; + init_read(ifP, &cols, &rows, &maxval, &format, 0); + break; + case MODE_RGB8: + mapfile = NULL; + init_read(ifP, &cols, &rows, &maxval, &format, 0); + break; + case MODE_RGBN: + mapfile = NULL; + init_read(ifP, &cols, &rows, &maxval, &format, 0); + break; + case MODE_CMAP: + /* Figure out the colormap. */ + pm_message("computing colormap..."); + colormap = ppm_mapfiletocolorrow(ifP, MAXCOLORS, &colors, + &cmapmaxval); + if (colormap == NULL) + pm_error("too many colors - try doing a 'pnmquant %d'", + MAXCOLORS); + pm_message("%d colors found", colors); + break; + default: + if (mapfile) + init_read(ifP, &cols, &rows, &maxval, &format, 0); + else { + init_read(ifP, &cols, &rows, &maxval, &format, 1); + /* read file into memory */ + pm_message("computing colormap..."); + colormap = + ppm_computecolorrow(pixels, cols, rows, MAXCOLORS, + &colors); + if (colormap) { + cmapmaxval = maxval; + pm_message("%d colors found", colors); + nPlanes = pm_maxvaltobits(colors-1); + if (fixplanes > nPlanes) + nPlanes = fixplanes; + } else { /* too many colors */ + mode = ifmode; + report_too_many_colors(ifmode, maxplanes, hamplanes, + dcol, deepbits ); + } + } + } + + if (mapfile) { + FILE * mapfp; + + pm_message("reading colormap file..."); + mapfp = pm_openr(mapfile); + colormap = ppm_mapfiletocolorrow(mapfp, MAXCOLORS, &colors, + &cmapmaxval); + pm_close(mapfp); + if (colormap == NULL) + pm_error("too many colors in mapfile for %d planes", maxplanes); + if (colors == 0) + pm_error("empty colormap??"); + pm_message("%d colors found in colormap", colors); + } + + if (maskmethod != mskNone) { + if (transpname) { + MALLOCVAR_NOFAIL(transpColor); + *transpColor = ppm_parsecolor(transpname, maxval); + } + if (maskfile) { + int maskrows; + pbm_readpbminit(maskfile, &maskcols, &maskrows, &maskformat); + if (maskcols < cols || maskrows < rows) + pm_error("maskfile too small - try scaling it"); + if (maskcols > cols || maskrows > rows) + pm_message("warning - maskfile larger than image"); + } else + maskcols = rows; + maskrow = pbm_allocrow(maskcols); + } + + if (mode != MODE_CMAP) { + unsigned int i; + MALLOCARRAY_NOFAIL(coded_rowbuf, RowBytes(cols)); + for (i = 0; i < RowBytes(cols); ++i) + coded_rowbuf[i] = 0; + if (DO_COMPRESS) + MALLOCARRAY_NOFAIL(compr_rowbuf, WORSTCOMPR(RowBytes(cols))); + } + + switch (mode) { + case MODE_HAM: + viewportmodes |= vmHAM; + ppm_to_ham(ifP, cols, rows, maxval, + colormap, colors, cmapmaxval, hamplanes); + break; + case MODE_DEEP: + ppm_to_deep(ifP, cols, rows, maxval, deepbits); + break; + case MODE_DCOL: + ppm_to_dcol(ifP, cols, rows, maxval, &dcol); + break; + case MODE_RGB8: + ppm_to_rgb8(ifP, cols, rows, maxval); + break; + case MODE_RGBN: + ppm_to_rgbn(ifP, cols, rows, maxval); + break; + case MODE_CMAP: + ppm_to_cmap(colormap, colors, cmapmaxval); + break; + default: + if (mapfile == NULL) + floyd = 0; /* would only slow down conversion */ + ppm_to_std(ifP, cols, rows, maxval, colormap, colors, + cmapmaxval, MAXCOLORS, nPlanes); + break; + } + pm_close(ifP); + return 0; +} |