diff options
Diffstat (limited to 'other/pnmcolormap.c')
-rw-r--r-- | other/pnmcolormap.c | 457 |
1 files changed, 294 insertions, 163 deletions
diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c index 7da3122b..f59a1a0d 100644 --- a/other/pnmcolormap.c +++ b/other/pnmcolormap.c @@ -1,7 +1,6 @@ -/****************************************************************************** - pnmcolormap.c -******************************************************************************* - +/*============================================================================= + pnmcolormap +=============================================================================== Create a colormap file (a PPM image containing one pixel of each of a set of colors). Base the set of colors on an input image. @@ -20,9 +19,8 @@ copyright notice and this permission notice appear in supporting documentation. This software is provided "as is" without express or implied warranty. - -******************************************************************************/ - +=============================================================================*/ +#include <stdbool.h> #include <assert.h> #include <math.h> @@ -41,19 +39,41 @@ enum MethodForRep {REP_CENTER_BOX, REP_AVERAGE_COLORS, REP_AVERAGE_PIXELS}; enum MethodForSplit {SPLIT_MAX_PIXELS, SPLIT_MAX_COLORS, SPLIT_MAX_SPREAD}; struct Box { - unsigned int index; +/*---------------------------------------------------------------------------- + A box contains an extent of a color frequency table, i.e. the colors + with some consecutive index values in the color frequency table. +-----------------------------------------------------------------------------*/ + unsigned int serialNum; + /* Unique identifier of this box; sequence number of creation. */ + unsigned int startIndex; + /* First index in the extent */ unsigned int colorCt; + /* Size of the extent (Number of colors in it -- at least 1) */ unsigned int sum; + /* Number of pixels of all colors in the extent */ unsigned int maxdim; - /* which dimension has the largest spread. RGB plane number. */ + /* Which dimension has the largest spread. RGB plane number. */ + /* Meaningless if box contains only 1 color */ sample spread; /* spread in dimension 'maxdim' */ + /* Meaningless if box contains only 1 color */ }; struct BoxVector { + tupletable2 colorFreqTable; + /* The colors and their frequencies (number of pixels in the image of + that color), ordered into consecutive boxes, as defined by 'box'. + */ + unsigned int colorDepth; + /* Number of planes in the tuples of 'colorFreqTable' */ struct Box * box; /* malloc'ed array */ + /* An array of boxes that contain consecutive extents of + 'colorFreqTable'. The list covers the entire table. + */ unsigned int boxCt; + /* Number of boxes in the above list */ unsigned int capacity; + /* Number of boxes the array is capable of containing */ }; struct CmdlineInfo { @@ -62,7 +82,7 @@ struct CmdlineInfo { */ const char * inputFileNm; /* Name of input file */ unsigned int allcolors; /* boolean: select all colors from the input */ - unsigned int newcolors; + unsigned int newColorCt; /* Number of colors argument; meaningless if allcolors true */ enum MethodForLargest methodForLargest; /* -spreadintensity/-spreadluminosity options */ @@ -73,13 +93,14 @@ struct CmdlineInfo { unsigned int sort; unsigned int square; unsigned int verbose; + unsigned int debug; }; static void parseCommandLine (int argc, const char ** argv, - struct CmdlineInfo *cmdlineP) { + 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. @@ -90,9 +111,7 @@ parseCommandLine (int argc, const char ** argv, 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; - /* Instructions to pm_optParseOptions3 on how to parse our options. - */ + optEntry * option_def; optStruct3 opt; unsigned int option_def_index; @@ -120,18 +139,20 @@ parseCommandLine (int argc, const char ** argv, NULL, &splitcolorct, 0); OPTENT3(0, "splitspread", OPT_FLAG, NULL, &splitspread, 0); - OPTENT3(0, "sort", OPT_FLAG, NULL, - &cmdlineP->sort, 0 ); - OPTENT3(0, "square", OPT_FLAG, NULL, - &cmdlineP->square, 0 ); - OPTENT3(0, "verbose", OPT_FLAG, NULL, - &cmdlineP->verbose, 0 ); + OPTENT3(0, "sort", OPT_FLAG, NULL, + &cmdlineP->sort, 0); + OPTENT3(0, "square", OPT_FLAG, NULL, + &cmdlineP->square, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "debug", OPT_FLAG, NULL, + &cmdlineP->debug, 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 */ + opt.short_allowed = false; /* We have no short (old-fashioned) options */ + opt.allowNegNum = false; /* We have no parms that are negative numbers */ - pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 ); + pm_optParseOptions4( &argc, argv, opt, sizeof(opt), 0 ); /* Uses and sets argc, argv, and some of *cmdline_p and others. */ @@ -177,21 +198,18 @@ parseCommandLine (int argc, const char ** argv, "output as an argument."); else { if (strcmp(argv[1], "all") == 0) - cmdlineP->allcolors = TRUE; + cmdlineP->allcolors = true; else { - char * tail; - long int const newcolors = strtol(argv[1], &tail, 10); - if (*tail != '\0') + const char * error; + cmdlineP->allcolors = false; + pm_string_to_uint(argv[1], &cmdlineP->newColorCt, &error); + + if (error) { pm_error("The number of colors argument '%s' is not " - "a number or 'all'", argv[1]); - else if (newcolors < 1) + "an unsigned number or 'all'. %s", + argv[1], error); + } else if (cmdlineP->newColorCt == 0) pm_error("The number of colors must be positive"); - else if (newcolors == 1) - pm_error("The number of colors must be greater than 1."); - else { - cmdlineP->newcolors = newcolors; - cmdlineP->allcolors = FALSE; - } } } } @@ -200,28 +218,63 @@ parseCommandLine (int argc, const char ** argv, #ifndef LITERAL_FN_DEF_MATCH -static qsort_comparison_fn compareplane; +static qsort_comparison_fn compareColor; #endif -static unsigned int compareplanePlane; - /* This is a parameter to compareplane(). We use this global variable - so that compareplane() can be called by qsort(), to compare two - tuples. qsort() doesn't pass any arguments except the two tuples. - */ +static struct { +/*---------------------------------------------------------------------------- + This is a parameter to compareColor(). We use this global variable + so that compareColor() can be called by qsort(), to compare two + tuples. qsort() doesn't pass any arguments except the two tuples. +-----------------------------------------------------------------------------*/ + unsigned int comparePlane; + /* The number of the plane to compare between the tuples */ + unsigned int colorDepth; + /* Depth (number of planes) of the tuples */ +} compareColorParm; + static int -compareplane(const void * const arg1, +compareColor(const void * const arg1, const void * const arg2) { const struct tupleint * const * const comparandPP = arg1; const struct tupleint * const * const comparatorPP = arg2; - sample const comparandSample = (*comparandPP) ->tuple[compareplanePlane]; - sample const comparatorSample = (*comparatorPP)->tuple[compareplanePlane]; + sample const comparandSample = + (*comparandPP) ->tuple[compareColorParm.comparePlane]; + sample const comparatorSample = + (*comparatorPP)->tuple[compareColorParm.comparePlane]; - return - comparandSample < comparatorSample ? -1 : - comparandSample > comparatorSample ? 1 : - 0; + int retval; + + if (comparandSample < comparatorSample) + retval = -1; + else if (comparandSample > comparatorSample) + retval = +1; + else { + /* In the plane that matters, samples are equal, but we're going to + try to differentiate the colors anyway so as to make qsort put the + colors in a deterministic order so the boxes are deterministic. + */ + unsigned int plane; + int bestDiffSoFar; /* -1, 0, or 1, like our return value */ + for (plane = 0, bestDiffSoFar = 0; + plane < compareColorParm.colorDepth && bestDiffSoFar == 0; + ++plane) { + + sample const comparandSample = + (*comparandPP) ->tuple[compareColorParm.comparePlane]; + sample const comparatorSample = + (*comparatorPP)->tuple[compareColorParm.comparePlane]; + + if (comparandSample < comparatorSample) + bestDiffSoFar = -1; + else if (comparandSample > comparatorSample) + bestDiffSoFar = +1; + } + retval = bestDiffSoFar; + } + return retval; } @@ -239,7 +292,9 @@ sumcompare(const void * const arg1, return comparatorP->sum < comparandP->sum ? -1 : - comparatorP->sum > comparandP->sum ? 1 : + comparatorP->sum > comparandP->sum ? +1 : + comparatorP->serialNum < comparandP->serialNum ? -1 : + comparatorP->serialNum > comparandP->serialNum ? +1 : 0; } @@ -259,6 +314,8 @@ colcompare(const void * const arg1, return comparatorP->colorCt < comparandP->colorCt ? -1 : comparatorP->colorCt > comparandP->colorCt ? 1 : + comparatorP->serialNum < comparandP->serialNum ? -1 : + comparatorP->serialNum > comparandP->serialNum ? +1 : 0; } @@ -278,6 +335,8 @@ spreadcompare(const void * const arg1, return comparatorP->spread < comparandP->spread ? -1 : comparatorP->spread > comparandP->spread ? 1 : + comparatorP->serialNum < comparandP->serialNum ? -1 : + comparatorP->serialNum > comparandP->serialNum ? +1 : 0; } @@ -308,7 +367,7 @@ sortBoxes(struct BoxVector * const boxVectorP, */ static void -findBoxBoundaries(tupletable2 const colorfreqtable, +findBoxBoundaries(tupletable2 const colorFreqTable, unsigned int const depth, unsigned int const boxStart, unsigned int const boxSize, @@ -322,14 +381,14 @@ findBoxBoundaries(tupletable2 const colorfreqtable, unsigned int i; for (plane = 0; plane < depth; ++plane) { - minval[plane] = colorfreqtable.table[boxStart]->tuple[plane]; + minval[plane] = colorFreqTable.table[boxStart]->tuple[plane]; maxval[plane] = minval[plane]; } for (i = 1; i < boxSize; ++i) { unsigned int plane; for (plane = 0; plane < depth; ++plane) { - sample const v = colorfreqtable.table[boxStart + i]->tuple[plane]; + sample const v = colorFreqTable.table[boxStart + i]->tuple[plane]; if (v < minval[plane]) minval[plane] = v; if (v > maxval[plane]) maxval[plane] = v; } @@ -402,7 +461,7 @@ findPlaneWithLargestSpreadByLuminosity(sample const minval[], static void computeBoxSpread(const struct Box * const boxP, - tupletable2 const colorfreqtable, + tupletable2 const colorFreqTable, unsigned int const depth, enum MethodForLargest const methodForLargest, unsigned int * const planeWithLargestP, @@ -420,7 +479,7 @@ computeBoxSpread(const struct Box * const boxP, MALLOCARRAY_NOFAIL(minval, depth); MALLOCARRAY_NOFAIL(maxval, depth); - findBoxBoundaries(colorfreqtable, depth, boxP->index, boxP->colorCt, + findBoxBoundaries(colorFreqTable, depth, boxP->startIndex, boxP->colorCt, minval, maxval); switch (methodForLargest) { @@ -439,13 +498,13 @@ computeBoxSpread(const struct Box * const boxP, static unsigned int -freqTotal(tupletable2 const freqtable) { +freqTotal(tupletable2 const freqTable) { unsigned int i; unsigned int sum; - for (i = 0, sum = 0; i < freqtable.size; ++i) - sum += freqtable.table[i]->value; + for (i = 0, sum = 0; i < freqTable.size; ++i) + sum += freqTable.table[i]->value; return sum; } @@ -453,27 +512,30 @@ freqTotal(tupletable2 const freqtable) { static struct BoxVector -newBoxVector(tupletable2 const colorfreqtable, +newBoxVector(tupletable2 const colorFreqTable, unsigned int const capacity, unsigned int const depth, enum MethodForLargest const methodForLargest) { - unsigned int const colorCt = colorfreqtable.size; - unsigned int const sum = freqTotal(colorfreqtable); + unsigned int const colorCt = colorFreqTable.size; + unsigned int const sum = freqTotal(colorFreqTable); struct BoxVector boxVector; + boxVector.colorFreqTable = colorFreqTable; + boxVector.colorDepth = depth; + MALLOCARRAY(boxVector.box, capacity); if (!boxVector.box) pm_error("out of memory allocating box vector table"); /* Set up the initial box. */ - boxVector.box[0].index = 0; - boxVector.box[0].colorCt = colorCt; - boxVector.box[0].sum = sum; + boxVector.box[0].startIndex = 0; + boxVector.box[0].colorCt = colorCt; + boxVector.box[0].sum = sum; - computeBoxSpread(&boxVector.box[0], colorfreqtable, depth, + computeBoxSpread(&boxVector.box[0], colorFreqTable, depth, methodForLargest, &boxVector.box[0].maxdim, &boxVector.box[0].spread); @@ -497,7 +559,7 @@ destroyBoxVector(struct BoxVector const boxVector) { static void centerBox(int const boxStart, int const boxSize, - tupletable2 const colorfreqtable, + tupletable2 const colorFreqTable, unsigned int const depth, tuple const newTuple) { @@ -507,10 +569,10 @@ centerBox(int const boxStart, int minval, maxval; unsigned int i; - minval = maxval = colorfreqtable.table[boxStart]->tuple[plane]; + minval = maxval = colorFreqTable.table[boxStart]->tuple[plane]; for (i = 1; i < boxSize; ++i) { - int const v = colorfreqtable.table[boxStart + i]->tuple[plane]; + int const v = colorFreqTable.table[boxStart + i]->tuple[plane]; minval = MIN( minval, v); maxval = MAX( maxval, v); } @@ -547,7 +609,7 @@ newColorMap(unsigned int const colorCt, static void averageColors(int const boxStart, int const boxSize, - tupletable2 const colorfreqtable, + tupletable2 const colorFreqTable, unsigned int const depth, tuple const newTuple) { @@ -560,7 +622,7 @@ averageColors(int const boxStart, sum = 0; for (i = 0; i < boxSize; ++i) - sum += colorfreqtable.table[boxStart+i]->tuple[plane]; + sum += colorFreqTable.table[boxStart+i]->tuple[plane]; newTuple[plane] = ROUNDDIV(sum, boxSize); } @@ -571,7 +633,7 @@ averageColors(int const boxStart, static void averagePixels(int const boxStart, int const boxSize, - tupletable2 const colorfreqtable, + tupletable2 const colorFreqTable, unsigned int const depth, tuple const newTuple) { @@ -583,7 +645,7 @@ averagePixels(int const boxStart, /* Count the tuples in question */ n = 0; /* initial value */ for (i = 0; i < boxSize; ++i) - n += colorfreqtable.table[boxStart + i]->value; + n += colorFreqTable.table[boxStart + i]->value; for (plane = 0; plane < depth; ++plane) { @@ -593,8 +655,8 @@ averagePixels(int const boxStart, sum = 0; for (i = 0; i < boxSize; ++i) - sum += colorfreqtable.table[boxStart+i]->tuple[plane] - * colorfreqtable.table[boxStart+i]->value; + sum += colorFreqTable.table[boxStart+i]->tuple[plane] + * colorFreqTable.table[boxStart+i]->value; newTuple[plane] = ROUNDDIV(sum, n); } @@ -605,8 +667,6 @@ averagePixels(int const boxStart, static tupletable2 colormapFromBv(unsigned int const colorCt, struct BoxVector const boxVector, - tupletable2 const colorfreqtable, - unsigned int const depth, enum MethodForRep const methodForRep) { /* ** Ok, we've got enough boxes. Now choose a representative color for @@ -619,26 +679,26 @@ colormapFromBv(unsigned int const colorCt, tupletable2 colormap; unsigned int boxIdx; - colormap = newColorMap(colorCt, depth); + colormap = newColorMap(colorCt, boxVector.colorDepth); for (boxIdx = 0; boxIdx < boxVector.boxCt; ++boxIdx) { switch (methodForRep) { case REP_CENTER_BOX: - centerBox(boxVector.box[boxIdx].index, + centerBox(boxVector.box[boxIdx].startIndex, boxVector.box[boxIdx].colorCt, - colorfreqtable, depth, + boxVector.colorFreqTable, boxVector.colorDepth, colormap.table[boxIdx]->tuple); break; case REP_AVERAGE_COLORS: - averageColors(boxVector.box[boxIdx].index, + averageColors(boxVector.box[boxIdx].startIndex, boxVector.box[boxIdx].colorCt, - colorfreqtable, depth, + boxVector.colorFreqTable, boxVector.colorDepth, colormap.table[boxIdx]->tuple); break; case REP_AVERAGE_PIXELS: - averagePixels(boxVector.box[boxIdx].index, + averagePixels(boxVector.box[boxIdx].startIndex, boxVector.box[boxIdx].colorCt, - colorfreqtable, depth, + boxVector.colorFreqTable, boxVector.colorDepth, colormap.table[boxIdx]->tuple); break; default: @@ -652,42 +712,72 @@ colormapFromBv(unsigned int const colorCt, static void +setBox(struct Box * const boxP, + unsigned int const startIndex, + unsigned int const colorCt, + unsigned int const sum, + struct BoxVector * const boxVectorP, + enum MethodForLargest const methodForLargest + ) { + + boxP->startIndex = startIndex; + boxP->colorCt = colorCt; + boxP->sum = sum; + + computeBoxSpread(boxP, boxVectorP->colorFreqTable, + boxVectorP->colorDepth, methodForLargest, + &boxP->maxdim, &boxP->spread); +} + + + +static void +makeNewBox(struct BoxVector * const boxVectorP, + unsigned int const startIndex, + unsigned int const colorCt, + unsigned int const sum, + enum MethodForLargest const methodForLargest) { + + struct Box * const boxP = &boxVectorP->box[boxVectorP->boxCt++]; + + assert(boxVectorP->boxCt <= boxVectorP->capacity); + + boxP->serialNum = boxVectorP->boxCt; + + setBox(boxP, startIndex, colorCt, sum, boxVectorP, methodForLargest); +} + + + +static void splitBox(struct BoxVector * const boxVectorP, unsigned int const boxIdx, - tupletable2 const colorfreqtable, - unsigned int const depth, enum MethodForLargest const methodForLargest, enum MethodForSplit const methodForSplit) { /*---------------------------------------------------------------------------- - Split Box 'boxIdx' in the box vector 'boxVector' (so that bv contains one - more box than it did as input). Split it so that each new box represents - about half of the pixels in the distribution given by 'colorfreqtable' for - the colors in the original box, but with distinct colors in each of the two - new boxes. + Split Box 'boxIdx' in the box vector 'boxVector' (so that 'boxVector' + contains one more box than it did as input). Split it so that each new box + represents about half of the pixels in the image for the colors in the + original box, but with distinct colors in each of the two new boxes. Assume the box contains at least two colors. -----------------------------------------------------------------------------*/ - unsigned int const boxStart = boxVectorP->box[boxIdx].index; + unsigned int const boxStart = boxVectorP->box[boxIdx].startIndex; unsigned int const boxSize = boxVectorP->box[boxIdx].colorCt; unsigned int const sum = boxVectorP->box[boxIdx].sum; unsigned int medianIndex; - int lowersum; + unsigned int lowerSum; /* Number of pixels whose value is "less than" the median */ - - /* Perhaps this sort should go after creating a box, not before splitting. - Because you need the sort to use the REP_CENTER_BOX method of choosing - a color to represent the final boxes - */ - - /* Set the gross global variable 'compareplanePlane' as a - parameter to compareplane(), which is called by qsort(). + /* Set the gross global variable 'compareColorParm' as a + parameter to compareColor(), which is called by qsort(). */ - compareplanePlane = boxVectorP->box[boxIdx].maxdim; - qsort((char*) &colorfreqtable.table[boxStart], boxSize, - sizeof(colorfreqtable.table[boxStart]), - compareplane); + compareColorParm.comparePlane = boxVectorP->box[boxIdx].maxdim; + compareColorParm.colorDepth = boxVectorP->colorDepth; + qsort((char*) &boxVectorP->colorFreqTable.table[boxStart], boxSize, + sizeof(boxVectorP->colorFreqTable.table[boxStart]), + compareColor); { /* Find the median based on the counts, so that about half the pixels @@ -695,31 +785,25 @@ splitBox(struct BoxVector * const boxVectorP, */ unsigned int i; - lowersum = colorfreqtable.table[boxStart]->value; /* initial value */ - for (i = 1; i < boxSize - 1 && lowersum < sum/2; ++i) { - lowersum += colorfreqtable.table[boxStart + i]->value; + lowerSum = boxVectorP->colorFreqTable.table[boxStart]->value; + /* initial value */ + for (i = 1; i < boxSize - 1 && lowerSum < sum/2; ++i) { + lowerSum += boxVectorP->colorFreqTable.table[boxStart + i]->value; } medianIndex = i; } - /* Split the box, and sort to bring the biggest boxes to the top. */ - { - struct Box * const oldBoxP = &boxVectorP->box[boxIdx]; + /* Split the box, and sort to bring the biggest boxes to the top. The old + box becomes the lower half; we make a new box for the upper half. + */ + setBox(&boxVectorP->box[boxIdx], + boxStart, medianIndex, + lowerSum, + boxVectorP, methodForLargest); - oldBoxP->colorCt = medianIndex; - oldBoxP->sum = lowersum; - computeBoxSpread(oldBoxP, colorfreqtable, depth, methodForLargest, - &oldBoxP->maxdim, &oldBoxP->spread); - } - { - struct Box * const newBoxP = &boxVectorP->box[boxVectorP->boxCt]; - - newBoxP->index = boxStart + medianIndex; - newBoxP->colorCt = boxSize - medianIndex; - newBoxP->sum = sum - lowersum; - computeBoxSpread(newBoxP, colorfreqtable, depth, methodForLargest, - &newBoxP->maxdim, &newBoxP->spread); - ++boxVectorP->boxCt; - } + makeNewBox(boxVectorP, + boxStart + medianIndex, boxSize - medianIndex, + sum - lowerSum, + methodForLargest); sortBoxes(boxVectorP, methodForSplit); } @@ -727,21 +811,58 @@ splitBox(struct BoxVector * const boxVectorP, static void -mediancut(tupletable2 const colorfreqtable, +reportBoxVector(struct BoxVector const boxVector) { + + unsigned int i; + + pm_message("All colors of image, sorted into %u boxes:", boxVector.boxCt); + + for (i = 0; i < boxVector.boxCt; ++i) { + const struct Box * const boxP = &boxVector.box[i]; + + unsigned int j; + + pm_message("Box %u, %u colors starting with index %u (%u pixels):", + i, boxP->colorCt, boxP->startIndex, boxP->sum); + if (boxP->colorCt > 1) + pm_message("Largest spread is %lu, in plane %u", + boxP->spread, boxP->maxdim); + + for (j = 0; j < boxP->colorCt; ++j) { + unsigned int colorIdx = boxP->startIndex + j; + + assert(colorIdx < boxVector.colorFreqTable.size); + + tuple const color = + boxVector.colorFreqTable.table[colorIdx]->tuple; + + pm_message("(%lu, %lu, %lu)", + color[PAM_RED_PLANE], + color[PAM_GRN_PLANE], + color[PAM_BLU_PLANE]); + } + } +} + + + +static void +mediancut(tupletable2 const colorFreqTable, unsigned int const depth, - int const newcolorCt, + unsigned int const newColorCt, enum MethodForLargest const methodForLargest, enum MethodForRep const methodForRep, enum MethodForSplit const methodForSplit, + bool const wantBvReport, tupletable2 * const colormapP) { /*---------------------------------------------------------------------------- - Compute a set of only 'newcolorCt' colors that best represent an + Compute a set of only 'newColorCt' colors that best represent an image whose pixels are summarized by the histogram - 'colorfreqtable'. Each tuple in that table has depth 'depth'. - colorfreqtable.table[i] tells the number of pixels in the subject image - have a particular color. + 'colorFreqTable'. Each tuple in that table has depth 'depth'. + colorFreqTable.table[i] tells the number of pixels in the subject image + that have a particular color. - As a side effect, sort 'colorfreqtable'. + As a side effect, sort 'colorFreqTable'. -----------------------------------------------------------------------------*/ struct BoxVector boxVector; bool multicolorBoxesExist; @@ -749,13 +870,13 @@ mediancut(tupletable2 const colorfreqtable, there is more splitting we can do. */ - boxVector = newBoxVector(colorfreqtable, newcolorCt, depth, + boxVector = newBoxVector(colorFreqTable, newColorCt, depth, methodForLargest); - multicolorBoxesExist = (colorfreqtable.size > 1); + multicolorBoxesExist = (colorFreqTable.size > 1); /* Split boxes until we have enough. */ - while (boxVector.boxCt < newcolorCt && multicolorBoxesExist) { + while (boxVector.boxCt < newColorCt && multicolorBoxesExist) { unsigned int boxIdx; for (boxIdx = 0; @@ -764,13 +885,18 @@ mediancut(tupletable2 const colorfreqtable, /* Find the first splittable box. */ if (boxIdx >= boxVector.boxCt) - multicolorBoxesExist = FALSE; + multicolorBoxesExist = false; else - splitBox(&boxVector, boxIdx, colorfreqtable, depth, - methodForLargest, methodForSplit); + splitBox(&boxVector, boxIdx, methodForLargest, methodForSplit); + /* Side effect: sorts the extent of 'colorfreqTable' that is + in the box + */ } - *colormapP = colormapFromBv(newcolorCt, boxVector, colorfreqtable, - depth, methodForRep); + + if (wantBvReport) + reportBoxVector(boxVector); + + *colormapP = colormapFromBv(newColorCt, boxVector, methodForRep); destroyBoxVector(boxVector); } @@ -834,7 +960,7 @@ static void computeHistogram(FILE * const ifP, int * const formatP, struct pam * const freqPamP, - tupletable2 * const colorfreqtableP) { + tupletable2 * const colorFreqTableP) { /*---------------------------------------------------------------------------- Make a histogram of the colors in the image stream in the file '*ifP'. @@ -856,7 +982,7 @@ computeHistogram(FILE * const ifP, tuplehash = pnm_createtuplehash(); colorCount = 0; - eof = FALSE; + eof = false; for (imageSeq = 0; !eof; ++imageSeq) { struct pam inpam; @@ -876,13 +1002,13 @@ computeHistogram(FILE * const ifP, pnm_nextimage(ifP, &eof); } - colorfreqtableP->table = + colorFreqTableP->table = pnm_tuplehashtotable(&firstPam, tuplehash, colorCount); - colorfreqtableP->size = colorCount; + colorFreqTableP->size = colorCount; pnm_destroytuplehash(tuplehash); - pm_message("%u colors found", colorfreqtableP->size); + pm_message("%u colors found", colorFreqTableP->size); freqPamP->size = sizeof(*freqPamP); freqPamP->len = PAM_STRUCT_SIZE(tuple_type); @@ -899,10 +1025,11 @@ computeHistogram(FILE * const ifP, static void computeColorMapFromInput(FILE * const ifP, bool const allColors, - int const reqColors, + unsigned int const reqColorCt, enum MethodForLargest const methodForLargest, enum MethodForRep const methodForRep, enum MethodForSplit const methodForSplit, + bool const wantBvReport, int * const formatP, struct pam * const freqPamP, tupletable2 * const colormapP) { @@ -911,7 +1038,7 @@ computeColorMapFromInput(FILE * const ifP, image stream in file 'ifP'. Figure it out using the median cut technique. - The colormap will have 'reqcolors' or fewer colors in it, unless + The colormap will have 'reqcolorCt' or fewer colors in it, unless 'allcolors' is true, in which case it will have all the colors that are in the input. @@ -925,23 +1052,26 @@ computeColorMapFromInput(FILE * const ifP, *formatP and *freqPamP. (This information is not really relevant to our colormap mission; just a fringe benefit). -----------------------------------------------------------------------------*/ - tupletable2 colorfreqtable; + tupletable2 colorFreqTable; + /* Table of all colors in the image, with the number of pixels of + each color. + */ - computeHistogram(ifP, formatP, freqPamP, &colorfreqtable); + computeHistogram(ifP, formatP, freqPamP, &colorFreqTable); if (allColors) { - *colormapP = colorfreqtable; + *colormapP = colorFreqTable; } else { - if (colorfreqtable.size <= reqColors) { - pm_message("Image already has few enough colors (<=%d). " - "Keeping same colors.", reqColors); - *colormapP = colorfreqtable; + if (colorFreqTable.size <= reqColorCt) { + pm_message("Image already has few enough colors (<=%u). " + "Keeping same colors.", reqColorCt); + *colormapP = colorFreqTable; } else { - pm_message("choosing %d colors...", reqColors); - mediancut(colorfreqtable, freqPamP->depth, - reqColors, methodForLargest, methodForRep, - methodForSplit, colormapP); - pnm_freetupletable2(freqPamP, colorfreqtable); + pm_message("choosing %u colors...", reqColorCt); + mediancut(colorFreqTable, freqPamP->depth, + reqColorCt, methodForLargest, methodForRep, + methodForSplit, wantBvReport, colormapP); + pnm_freetupletable2(freqPamP, colorFreqTable); } } } @@ -967,16 +1097,16 @@ sortColormap(tupletable2 const colormap, unsigned int plane; bool iIsGreater, iIsLess; - iIsGreater = FALSE; iIsLess = FALSE; + iIsGreater = false; iIsLess = false; for (plane = 0; plane < depth && !iIsGreater && !iIsLess; ++plane) { if (colormap.table[i]->tuple[plane] > colormap.table[j]->tuple[plane]) - iIsGreater = TRUE; + iIsGreater = true; else if (colormap.table[i]->tuple[plane] < colormap.table[j]->tuple[plane]) - iIsLess = TRUE; + iIsLess = true; } if (iIsGreater) { for (plane = 0; plane < depth; ++plane) { @@ -1077,7 +1207,7 @@ colormapToImage(int const format, outpamP->size = sizeof(*outpamP); outpamP->len = PAM_STRUCT_SIZE(tuple_type); outpamP->format = format, - outpamP->plainformat = FALSE; + outpamP->plainformat = false; outpamP->depth = colormapPamP->depth; outpamP->maxval = colormapPamP->maxval; outpamP->bytes_per_sample = pnm_bytespersample(outpamP->maxval); @@ -1112,10 +1242,11 @@ main(int argc, const char * argv[] ) { ifP = pm_openr(cmdline.inputFileNm); computeColorMapFromInput(ifP, - cmdline.allcolors, cmdline.newcolors, + cmdline.allcolors, cmdline.newColorCt, cmdline.methodForLargest, cmdline.methodForRep, cmdline.methodForSplit, + !!cmdline.debug, &format, &colormapPam, &colormap); pm_close(ifP); |