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 lookupThroughHash(struct pam * const pamP, tuple const tuple, bool const needExactMatch, struct colormapFinder * const colorFinderP, tuplehash const colorhash, int * const colormapIndexP, bool * const usehashP) { /*---------------------------------------------------------------------------- Look up the color of tuple 'tuple' in the color map indicated by 'colorFinderP' and, if it's in there, return its index as *colormapIndexP. If not, return *colormapIndexP == -1. Both the tuple 'tuple' and the colors in color map 'colormap' are described by *pamP. If 'needExactMatch' isn't true, we find the closest color in the color map, and never return *colormapIndex == -1. lookaside at the hash table 'colorhash' to possibly avoid the cost of a full lookup. If we do a full lookup, we add the result to 'colorhash' unless *usehashP is false, and if that makes 'colorhash' full, we set *usehashP false. -----------------------------------------------------------------------------*/ int found; /* Check hash table to see if we have already matched this color. */ pnm_lookuptuple(pamP, colorhash, tuple, &found, colormapIndexP); if (!found) { /* No, have to do a full lookup */ if (needExactMatch) { bool found; searchColormapExact(pamP, colorFinderP, tuple, colormapIndexP, &found); if (!found) *colormapIndexP = -1; } else searchColormapClose(pamP, tuple, colorFinderP, colormapIndexP); if (*usehashP) { int fits; pnm_addtotuplehash(pamP, colorhash, tuple, *colormapIndexP, &fits); if (!fits) { pm_message("out of memory adding to hash table; " "proceeding without it"); *usehashP = FALSE; } } } }
static void doUnlookup(struct pam * const inpamP, tuplehash const lookupHash, sample const maxIndex, FILE * const ofP) { struct pam outpam; unsigned int row; tuple * inrow; tuple * outrow; inrow = pnm_allocpamrow(inpamP); outpam.size = sizeof(outpam); outpam.len = PAM_STRUCT_SIZE(tuple_type); outpam.file = ofP; outpam.format = PAM_FORMAT; outpam.height = inpamP->height; outpam.width = inpamP->width; outpam.depth = 1; outpam.maxval = maxIndex + 1; /* +1 for missing color */ strcpy(outpam.tuple_type, "INDEX"); pnm_writepaminit(&outpam); outrow = pnm_allocpamrow(&outpam); for (row = 0; row < inpamP->height; ++row) { unsigned int col; pnm_readpamrow(inpamP, inrow); for (col = 0; col < inpamP->width; ++col) { int found; int index; pnm_lookuptuple(inpamP, lookupHash, inrow[col], &found, &index); if (found) { assert(index <= outpam.maxval); outrow[col][0] = index; } else outrow[col][0] = maxIndex + 1; } pnm_writepamrow(&outpam, outrow); } pnm_freepamrow(outrow); pnm_freepamrow(inrow); }
static void putPixel(struct pam * const pamP, tuple const tuple, enum TGAbaseImageType const imgType, bool const withAlpha, tuplehash const cht) { /*---------------------------------------------------------------------------- Write a single pixel of the TGA raster to Standard Output. The pixel is to have color 'tuple'. The raster has format 'imgType'. The color palette from which the specified color is to be drawn, if 'imgType' indicates use of a color palette, is 'cht'. -----------------------------------------------------------------------------*/ if (imgType == TGA_MAP_TYPE) { int retval; int found; pnm_lookuptuple(pamP, cht, tuple, &found, &retval); if (!found) pm_error("Internal error: color not found in map that was " "generated from all the colors in the image"); putchar(retval); } else { if (imgType == TGA_RGB_TYPE && pamP->depth < 3) { /* Make RGB pixel out of a single input plane */ unsigned int plane; for (plane = 0; plane < 3; ++plane) putchar(pnm_scalesample(tuple[0], pamP->maxval, TGA_MAXVAL)); } else if (imgType == TGA_MONO_TYPE) putchar(pnm_scalesample(tuple[0], pamP->maxval, TGA_MAXVAL)); else { putchar(pnm_scalesample(tuple[PAM_BLU_PLANE], pamP->maxval, TGA_MAXVAL)); putchar(pnm_scalesample(tuple[PAM_GRN_PLANE], pamP->maxval, TGA_MAXVAL)); putchar(pnm_scalesample(tuple[PAM_RED_PLANE], pamP->maxval, TGA_MAXVAL)); if (withAlpha) putchar(pnm_scalesample(tuple[PAM_TRN_PLANE], pamP->maxval, TGA_MAXVAL)); } } }
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 writeScanLines(struct pam * const pamP, TIFF * const tif, tuplehash const cht, unsigned short const tiffMaxval, unsigned short const bitspersample, unsigned short const photometric, int const bytesperrow, int const fillorder) { /*---------------------------------------------------------------------------- Write out the raster for the input image described by 'pamP', whose file is positioned to the raster of the image. -----------------------------------------------------------------------------*/ tuple * tuplerow; /* malloc'ed */ unsigned char * buf; /* malloc'ed */ int row; /* The man page for TIFFWriteScanLine doesn't tell the format of it's 'buf' parameter, but here it is: Its format depends on the bits per pixel of the TIFF image. If it's 16, 'buf' is an array of short (16 bit) integers, one per raster column. If it's 8, 'buf' is an array of characters (8 bit integers), one per image column. If it's less than 8, it's an array of characters, each of which represents 1-8 raster columns, packed into it in the order specified by the TIFF image's fill order, with don't-care bits on the right such that each byte contains only whole pixels. In all cases, the array elements are in order left to right going from low array indices to high array indices. */ MALLOCARRAY(buf, bytesperrow); if (buf == NULL) pm_error("can't allocate memory for row buffer"); tuplerow = pnm_allocpamrow(pamP); for (row = 0; row < pamP->height; ++row) { int col; pnm_readpamrow(pamP, tuplerow); if (cht == NULL) { /* It's a direct, non-colormapped raster */ if (bitspersample == 8 || bitspersample == 16) fillRowOfWholeBytePixels(pamP, tuplerow, buf, photometric, tiffMaxval, bitspersample); else fillRowOfSubBytePixels(pamP, tuplerow, buf, tiffMaxval, photometric, fillorder, bitspersample, NULL); } else { /* It's a colormapped raster */ if (bitspersample == 8) { for (col = 0; col < pamP->width; ++col) { int si; int found; pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si); if (!found) pm_error("INTERNAL ERROR. We made a color map, and a " "color map we need is not in it! " "col=%d r=%lu g=%lu b=%lu", col, tuplerow[col][0], tuplerow[col][1], tuplerow[col][2]); buf[col] = (unsigned char) si; } } else { fillRowOfSubBytePixels(pamP, tuplerow, buf, 0, 0, fillorder, bitspersample, cht); } } if (TIFFWriteScanline(tif, buf, row, 0) < 0) pm_error("failed a scanline write on row %d", row); } pnm_freepamrow(tuplerow); free(buf); }
static void fillRowOfSubBytePixels(struct pam * const pamP, const tuple * const tuplerow, unsigned char * const buf, unsigned short const tiff_maxval, unsigned short const photometric, int const fillorder, int const bitspersample, tuplehash const cht) { /*---------------------------------------------------------------------------- This subroutine deals with cases where multiple pixels are packed into a single byte of the Tiff output image, i.e. bits per pixel < 8. -----------------------------------------------------------------------------*/ int col; int bitshift; /* The number of bits we have to shift a pixel value left to line it up with where the current pixel goes in the current byte of the output buffer. */ int const firstbitshift = (fillorder == FILLORDER_MSB2LSB) ? 8 - bitspersample : 0; /* The value of 'bitshift' for the first pixel into a byte of the output buffer. (MSB2LSB is normal). */ sample s; /* The value of the current sample */ unsigned char* tP; /* The address of the byte in the output buffer in which the current pixel goes. */ unsigned char byte; /* The under-construction value of the byte pointed to by tP, above. */ bitshift = firstbitshift; byte = 0; for (col = 0, tP = buf; col < pamP->width; ++col) { if (cht == NULL) { /* It's grayscale */ s = tuplerow[col][0]; if (pamP->maxval != tiff_maxval ) s = (long) s * tiff_maxval / pamP->maxval; if (photometric == PHOTOMETRIC_MINISWHITE) s = tiff_maxval - s; } else { /* It's a colormapped raster */ int si; int found; pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si); if (!found) pm_error("INTERNAL ERROR. We made a color map, and a " "color map we need is not in it!. " "col=%d r=%lu g=%lu b=%lu", col, tuplerow[col][0], tuplerow[col][1], tuplerow[col][2]); s = (unsigned char) si; } byte |= s << bitshift; if (fillorder == FILLORDER_MSB2LSB) bitshift -= bitspersample; /* normal case */ else bitshift += bitspersample; if (bitshift < 0 || bitshift > 7) { *tP++ = byte; bitshift = firstbitshift; byte = 0; } } if (bitshift != firstbitshift) *tP++ = byte; }