diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/other/pamtodjvurle.c | |
download | netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip |
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/pamtodjvurle.c')
-rw-r--r-- | converter/other/pamtodjvurle.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/converter/other/pamtodjvurle.c b/converter/other/pamtodjvurle.c new file mode 100644 index 00000000..ae35e81d --- /dev/null +++ b/converter/other/pamtodjvurle.c @@ -0,0 +1,293 @@ +/***************************************************************************** + pamtodjvurle +****************************************************************************** + This program converts a PAM image to DjVu Color RLE format. + + By Bryan Henderson, San Jose, CA April 2004. + + Contributed to the public domain by its author. + + This work is inspired by Ppmtodjvurle, written by Scott Pakin + <scott+pbm@pakin.org> in March 2004. Bryan took the requirements of + the DjVu Color RLE format and the technique for generating the format + (but not code) from that program. + +*****************************************************************************/ +#include <stdio.h> +#include <assert.h> + +#include "pam.h" +#include "pammap.h" +#include "shhopt.h" + + +struct cmdlineInfo { + const char * inputFilespec; + const char * transparent; + unsigned int showcolormap; +}; + + + +static void +parseCommandLine(int argc, + char ** argv, + struct cmdlineInfo * const cmdlineP) { +/* -------------------------------------------------------------------------- + Parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +--------------------------------------------------------------------------*/ + optEntry *option_def = malloc( 100*sizeof( optEntry ) ); + /* Instructions to optParseOptions3 on how to parse our options. */ + optStruct3 opt; + + unsigned int option_def_index; + unsigned int transparentSpec; + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "transparent", OPT_STRING, &cmdlineP->transparent, + &transparentSpec, 0); + OPTENT3(0, "showcolormap", OPT_FLAG, NULL, + &cmdlineP->showcolormap, 0); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + optParseOptions3( &argc, argv, opt, sizeof(opt), 0 ); + /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + + if (!transparentSpec) + cmdlineP->transparent = "white"; + + /* Get the program parameters */ + + if (argc-1 >= 1) + cmdlineP->inputFilespec = argv[1]; + else + cmdlineP->inputFilespec = "-"; + + if (argc-1 > 1) + pm_error("Program takes at most one argument: the file name. " + "You specified %d", argc-1); +} + + + +static void +computeColorMap(struct pam * const pamP, + tuple ** const tupleArray, + unsigned int * const numColorsP, + tupletable * const colormapP, + tuplehash * const colorhashP, + bool const show) { + + unsigned int numColors; + tupletable colormap; + + colormap = pnm_computetuplefreqtable(pamP, tupleArray, 0, &numColors); + if (numColors > 0xFF0) + pm_error("too many colors; " + "use pnmquant to reduce to no more than %u colors", 0xFF0); + + if (show) { + unsigned int colorIndex; + fprintf(stderr, "Color map:\n"); + fprintf(stderr, " Index Color\n"); + for (colorIndex = 0; colorIndex < numColors; ++colorIndex) { + unsigned int plane; + fprintf(stderr, " %5u ", colorIndex); + for (plane = 0; plane < pamP->depth; ++plane) + fprintf(stderr, "%3lu ", colormap[colorIndex]->tuple[plane]); + fprintf(stderr, "\n"); + } + } + + *colorhashP = pnm_computetupletablehash(pamP, colormap, numColors); + + *numColorsP = numColors; + *colormapP = colormap; +} + + + +static void +makeDjvurleHeader(FILE * const ofP, + struct pam * const pamP, + unsigned int const numColors, + tupletable const colormap) { + + unsigned int colorIndex; + + fprintf(ofP, "R6\n"); + fprintf(ofP, "%d %d %d\n", pamP->width, pamP->height, numColors); + + for (colorIndex = 0; colorIndex < numColors; ++colorIndex) { + sample red, grn, blu; + + if (pamP->depth >= 3) { + red = colormap[colorIndex]->tuple[PAM_RED_PLANE]; + grn = colormap[colorIndex]->tuple[PAM_GRN_PLANE]; + blu = colormap[colorIndex]->tuple[PAM_BLU_PLANE]; + } else + red = grn = blu = colormap[colorIndex]->tuple[0]; + + fputc(pnm_scalesample(red, pamP->maxval, 255), ofP); + fputc(pnm_scalesample(grn, pamP->maxval, 255), ofP); + fputc(pnm_scalesample(blu, pamP->maxval, 255), ofP); + } +} + + + +static bool +colorEqual(tuple comparand, + unsigned int comparandDepth, + tuple comparator) { + + /* comparator has depth 3 */ + + if (comparandDepth >= 3) + return (comparand[0] == comparator[0] && + comparand[1] == comparator[1] && + comparand[2] == comparator[2]); + else + return (comparand[0] == comparator[0] && + comparand[0] == comparator[1] && + comparand[0] == comparator[2]); +} + + + +static void +writeRleRun(FILE * const ofP, + struct pam * const pamP, + tuple const color, + int const count, + tuplehash const colorhash, + tuple const transcolor) { +/*---------------------------------------------------------------------------- + Write one DjVu Color RLE run to the file 'ofP'. The run is + 'count' pixels of color 'color', using the color index given by + 'colorhash' and assuming 'transcolor' is the transparent color. + + 'transcolor' is a 3-deep tuple with the same maxval as the image. +-----------------------------------------------------------------------------*/ + uint32n rlevalue; /* RLE-encoded color/valuex */ + int index; + + if (count > 0) { + if (colorEqual(color, pamP->depth, transcolor)) + index = 0xFFF; + else { + int found; + pnm_lookuptuple(pamP, colorhash, color, &found, &index); + assert(found); + } + rlevalue = (index << 20) | count; + + pm_writebiglong(ofP, rlevalue); + } +} + + + +static void +writeDjvurleRow(FILE * const ofP, + struct pam * const pamP, + tuple * const tupleRow, + tuplehash const colorhash, + tuple const transcolor) { + + unsigned int col; + unsigned int runlength; + tuple prevpixel; /* Previous pixel seen */ + + prevpixel = tupleRow[0]; + runlength = 0; + + for (col = 0; col < pamP->width; ++col) { + tuple const newpixel = tupleRow[col]; /* Current pixel color */ + + if (pnm_tupleequal(pamP, newpixel, prevpixel)) + /* This is a continuation of the current run */ + ++runlength; + else { + /* The run is over. Write it out and start a run of the next + color. + */ + writeRleRun(ofP, pamP, prevpixel, runlength, + colorhash, transcolor); + runlength = 1; + prevpixel = newpixel; + } + if (runlength >= (1<<20)-1) { + /* Can't make the run any longer. Write it out and start a + new run. + */ + writeRleRun(ofP, pamP, prevpixel, runlength, + colorhash, transcolor); + runlength = 1; + } + } + /* Write the last run we started */ + writeRleRun(ofP, pamP, prevpixel, runlength, colorhash, transcolor); +} + + + +int +main(int argc, char *argv[]) { + + FILE * const rlefile = stdout; + + struct cmdlineInfo cmdline; + FILE *ifP; /* Input (Netpbm) file */ + struct pam pam; /* Description of the image */ + tuple ** tupleArray; /* The image raster */ + tupletable colormap; /* List of all of the colors used */ + unsigned int numColors; /* Number of unique colors in the color map */ + tuplehash colorhash; + /* Mapping from color to index into colormap[] */ + tuple transcolor; + /* Color that should be considered transparent */ + + pnm_init (&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFilespec); + + tupleArray = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + transcolor = pnm_parsecolor(cmdline.transparent, pam.maxval); + + computeColorMap(&pam, tupleArray, &numColors, &colormap, &colorhash, + cmdline.showcolormap); + + makeDjvurleHeader(rlefile, &pam, numColors, colormap); + + /* Write the raster */ + + { + unsigned int row; + for (row = 0; row < pam.height; ++row) + writeDjvurleRow(rlefile, &pam, tupleArray[row], colorhash, + transcolor); + } + /* Clean up */ + + pnm_freepamarray(tupleArray, &pam); + pnm_freetupletable(&pam, colormap); + pnm_destroytuplehash(colorhash); + pnm_freepamtuple(transcolor); + pm_close(ifP); + + return 0; +} |