tuplehash pnm_computetupletablehash(struct pam * const pamP, tupletable const tupletable, unsigned int const tupletableSize) { /*---------------------------------------------------------------------------- Create a tuple hash containing indices into the tuple table 'tupletable'. The hash index for the hash is the value of a tuple; the hash value is the tuple table index for the element in the tuple table that contains that tuple value. Assume there are no duplicate tuple values in the tuple table. We allocate space for the main hash table and all the elements of the hash chains. -----------------------------------------------------------------------------*/ tuplehash tupletablehash; unsigned int i; bool fits; tupletablehash = pnm_createtuplehash(); fits = TRUE; /* initial assumption */ for (i = 0; i < tupletableSize && fits; ++i) { pnm_addtotuplehash(pamP, tupletablehash, tupletable[i]->tuple, i, &fits); } if (!fits) { pnm_destroytuplehash(tupletablehash); pm_error("Out of memory computing tuple hash from tuple table"); } return tupletablehash; }
static void computehashrecoverable(struct pam * const pamP, tuple ** const tupleArray, unsigned int const maxsize, sample const newMaxval, unsigned int * const sizeP, tuplehash * const tuplefreqhashP, tuple ** const rowbufferP, tuple * const colorP) { /*---------------------------------------------------------------------------- This is computetuplefreqhash(), only it leaves a trail so that if it happens to longjmp out because of a failed memory allocation, the setjmp'er can cleanup whatever it had done so far. -----------------------------------------------------------------------------*/ unsigned int row; struct pam freqPam; bool full; freqPam = *pamP; freqPam.maxval = newMaxval; *tuplefreqhashP = pnm_createtuplehash(); *sizeP = 0; /* initial value */ *rowbufferP = pnm_allocpamrow(pamP); *colorP = pnm_allocpamtuple(&freqPam); full = FALSE; /* initial value */ /* Go through the entire raster, building a hash table of tuple values. */ for (row = 0; row < pamP->height && !full; ++row) { int col; const tuple * tuplerow; /* The row of tuples we are processing */ if (tupleArray) tuplerow = tupleArray[row]; else { pnm_readpamrow(pamP, *rowbufferP); tuplerow = *rowbufferP; } for (col = 0; col < pamP->width && !full; ++col) { pnm_scaletuple(pamP, *colorP, tuplerow[col], freqPam.maxval); addColorOccurrenceToHash( *colorP, *tuplefreqhashP, &freqPam, maxsize, sizeP, &full); } } pnm_freepamtuple(*colorP); *colorP = NULL; pnm_freepamrow(*rowbufferP); *rowbufferP = NULL; if (full) { pnm_destroytuplehash(*tuplefreqhashP); *tuplefreqhashP = NULL; } }
static void makeReverseLookupHash(struct pam * const lookuppamP, tuple ** const lookup, tuplehash * const hashP) { /*---------------------------------------------------------------------------- Create a tuple hash that maps each tuple values in the first row of 'lookup' to the number of the column in which it appears. Abort the program with an error if the same tuple value occurs in two columns of the first row. -----------------------------------------------------------------------------*/ tuplehash hash; unsigned int col; hash = pnm_createtuplehash(); for (col = 0; col < lookuppamP->width; ++col) { tuple const thisValue = lookup[0][col]; int found; int priorValue; pnm_lookuptuple(lookuppamP, hash, thisValue, &found, &priorValue); if (found) pm_error("Same tuple value occurs in both Column %u and " "Column %u of the lookup image", priorValue, col); else { int fits; pnm_addtotuplehash(lookuppamP, hash, lookup[0][col], col, &fits); if (!fits) pm_error("Out of memory constructing hash of lookup table"); } } *hashP = hash; }
static void copyRaster(struct pam * const inpamP, struct pam * const outpamP, tupletable const colormap, unsigned int const colormapSize, bool const floyd, bool const randomize, tuple const defaultColor, unsigned int * const missingCountP) { tuplehash const colorhash = pnm_createtuplehash(); tuple * inrow; tuple * outrow; struct pam workpam; /* This is for work space we use for building up the output pixels. To save time and memory, we modify them in place in a buffer, which ultimately holds the output pixels. This pam structure is thus the same as the *outpamP, but with a tuple allocation depth large enough to handle intermediate results. */ depthAdjustment depthAdjustment; struct colormapFinder * colorFinderP; bool usehash; struct fserr fserr; int row; workpam = *outpamP; workpam.allocation_depth = MAX(workpam.depth, inpamP->depth); workpam.size = sizeof(workpam); workpam.len = PAM_STRUCT_SIZE(allocation_depth); inrow = pnm_allocpamrow(inpamP); outrow = pnm_allocpamrow(&workpam); if (outpamP->maxval != inpamP->maxval && defaultColor) pm_error("The maxval of the colormap (%u) is not equal to the " "maxval of the input image (%u). This is allowable only " "if you are doing an approximate mapping (i.e. you don't " "specify -firstisdefault or -missingcolor)", (unsigned int)outpamP->maxval, (unsigned int)inpamP->maxval); selectDepthAdjustment(inpamP, outpamP->depth, &depthAdjustment); usehash = TRUE; createColormapFinder(outpamP, colormap, colormapSize, &colorFinderP); if (floyd) initFserr(inpamP, &fserr, randomize); *missingCountP = 0; /* initial value */ for (row = 0; row < inpamP->height; ++row) { unsigned int missingCount; pnm_readpamrow(inpamP, inrow); convertRow(inpamP, &workpam, inrow, depthAdjustment, colormap, colorFinderP, colorhash, &usehash, floyd, defaultColor, &fserr, outrow, &missingCount); *missingCountP += missingCount; pnm_writepamrow(outpamP, outrow); } destroyColormapFinder(colorFinderP); pnm_freepamrow(inrow); pnm_freepamrow(outrow); pnm_destroytuplehash(colorhash); }
static void computeHistogram(FILE * const ifP, int * const formatP, struct pam * const freqPamP, tupletable2 * const colorfreqtableP) { /*---------------------------------------------------------------------------- Make a histogram of the colors in the image stream in the file '*ifP'. Return as *freqPamP a description of the tuple values in the histogram. Only the fields of *freqPamP that describe individual tuples are meaningful (depth, maxval, tuple type); As a fringe benefit, also return the format of the input file as *formatP. ----------------------------------------------------------------------------*/ unsigned int imageSeq; struct pam firstPam; tuplehash tuplehash; unsigned int colorCount; int eof; pm_message("making histogram..."); tuplehash = pnm_createtuplehash(); colorCount = 0; eof = FALSE; for (imageSeq = 0; !eof; ++imageSeq) { struct pam inpam; pm_message("Scanning image %u", imageSeq); pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); if (imageSeq == 0) firstPam = inpam; else validateCompatibleImage(&inpam, &firstPam, imageSeq); addImageColorsToHash(&inpam, tuplehash, &colorCount); pm_message("%u colors so far", colorCount); pnm_nextimage(ifP, &eof); } colorfreqtableP->table = pnm_tuplehashtotable(&firstPam, tuplehash, colorCount); colorfreqtableP->size = colorCount; pnm_destroytuplehash(tuplehash); pm_message("%u colors found", colorfreqtableP->size); freqPamP->size = sizeof(*freqPamP); freqPamP->len = PAM_STRUCT_SIZE(tuple_type); freqPamP->maxval = firstPam.maxval; freqPamP->bytes_per_sample = pnm_bytespersample(freqPamP->maxval); freqPamP->depth = firstPam.depth; STRSCPY(freqPamP->tuple_type, firstPam.tuple_type); *formatP = firstPam.format; }