📄 palmtopnm.c
字号:
static voidcreateHistogram(unsigned int const ncolors, unsigned int ** const seenP) { unsigned int * seen; MALLOCARRAY(seen, ncolors); if (!seen) pm_error("Can't allocate array for keeping track of " "how many pixels of each of %u colors are in the image.", ncolors); { /* Initialize the counter for each color to zero */ unsigned int i; for (i = 0; i < ncolors; ++i) seen[i] = 0; } *seenP = seen;}static voidreadRleRow(FILE * const ifP, unsigned char * const palmrow, unsigned int const bytesPerRow) { unsigned int j; for (j = 0; j < bytesPerRow; ) { unsigned int const incount = fgetc(ifP); unsigned int const inval = fgetc(ifP); memset(palmrow + j, inval, incount); j += incount; }} static voidreadScanlineRow(FILE * const ifP, unsigned char * const palmrow, unsigned char * const lastrow, unsigned int const bytesPerRow, bool const firstRow) { unsigned int j; unsigned int incount, inval; unsigned char inbit; for (j = 0; j < bytesPerRow; j += 8) { incount = fgetc(ifP); inval = MIN(bytesPerRow - j, 8); for (inbit = 0; inbit < inval; inbit += 1) { /* the first row cannot be compressed */ if (firstRow || ((incount & (1 << (7 - inbit))) != 0)) palmrow[j + inbit] = fgetc(ifP); else palmrow[j + inbit] = lastrow[j + inbit]; } } memcpy(lastrow, palmrow, bytesPerRow);}static voidreadUncompressedRow(FILE * const ifP, unsigned char * const palmrow, unsigned int const bytesPerRow) { int bytesRead; bytesRead = fread(palmrow, 1, bytesPerRow, ifP); if (bytesRead != bytesPerRow) pm_error("Error reading Palm file. Short read.");}static voidreadDecompressedRow(FILE * const ifP, unsigned char * const palmrow, unsigned char * const lastrow, enum palmCompressionType const compressionType, unsigned int const bytesPerRow, bool const firstRow, bool const verbose) { switch (compressionType) { case COMPRESSION_RLE: readRleRow(ifP, palmrow, bytesPerRow); break; case COMPRESSION_SCANLINE: readScanlineRow(ifP, palmrow, lastrow, bytesPerRow, firstRow); break; case COMPRESSION_PACKBITS: pm_error("INTERNAL ERROR: impossible value of compressionType"); break; case COMPRESSION_NONE: readUncompressedRow(ifP, palmrow, bytesPerRow); break; }}static voidconvertRowToPnmDirect(const unsigned char * const palmrow, xel * const xelrow, unsigned int const cols, xelval const maxval, unsigned int * const seen) { /* There's a problem with this. Take the Palm 16-bit direct color. That's 5 bits for the red, 6 for the green, and 5 for the blue. So what should the MAXVAL be? I decided to use 255 (8 bits) for everything, since that's the theoretical max of the number of bits in any one color, according to Palm. So the Palm color 0xFFFF (white) would be red=0x1F, green=0x3F, and blue=0x1F. How do we promote those colors? Simple shift would give us R=248,G=252,B=248; which is slightly green. Hardly seems right. So I've perverted the math a bit. Each color value is multiplied by 255, then divided by either 31 (red or blue) or 63 (green). That's the right way to do it anyway. */ const unsigned char *inbyte; unsigned int j; for (inbyte = palmrow, j = 0; j < cols; ++j) { unsigned int inval; inval = *inbyte++ << 8; inval |= *inbyte++; if (seen) ++seen[inval]; PPM_ASSIGN(xelrow[j], (((inval >> 11) & 0x1F) * maxval) / 0x1F, (((inval >> 5) & 0x3F) * maxval) / 0x3F, (((inval >> 0) & 0x1F) * maxval) / 0x1F ); }}static voidconvertRowToPnmNotDirect(const unsigned char * const palmrow, xel * const xelrow, unsigned int const cols, Colormap const colormap, xelval * const graymap, unsigned int * const seen, unsigned int const pixelSize) { unsigned int const mask = (1 << pixelSize) - 1; const unsigned char *inbyte; unsigned int inbit; unsigned int j; inbit = 8 - pixelSize; inbyte = palmrow; for (j = 0; j < cols; ++j) { short const color = ((*inbyte) & (mask << inbit)) >> inbit; if (seen) ++seen[color]; if (colormap) { Color_s const color2 = color << 24; Color const actualColor = (bsearch (&color2, colormap->color_entries, colormap->ncolors, sizeof(color2), palmcolor_compare_indices)); PPM_ASSIGN(xelrow[j], (*actualColor >> 16) & 0xFF, (*actualColor >> 8) & 0xFF, (*actualColor >> 0) & 0xFF); } else PNM_ASSIGN1(xelrow[j], graymap[color]); if (!inbit) { ++inbyte; inbit = 8 - pixelSize; } else inbit -= pixelSize; }}static voidwritePnm(struct palmHeader const palmHeader, FILE * const ifP, Colormap const colormap, xelval * const graymap, unsigned int const nColors, int const format, xelval const maxval, unsigned int ** const seenP, bool const verbose) { int const cols = palmHeader.cols; int const rows = palmHeader.rows; unsigned char * palmrow; unsigned char * lastrow; xel * xelrow; unsigned int * seen; unsigned int row; pnm_writepnminit(stdout, cols, rows, maxval, format, 0); xelrow = pnm_allocrow(cols); /* Read the picture data, one row at a time */ MALLOCARRAY_NOFAIL(palmrow, palmHeader.bytesPerRow); MALLOCARRAY_NOFAIL(lastrow, palmHeader.bytesPerRow); if (seenP) { createHistogram(nColors, &seen); *seenP = seen; } else seen = NULL; if (palmHeader.compressionType != COMPRESSION_NONE) { if (palmHeader.version < 3) { short compressedDataSize16; pm_readbigshort(ifP, &compressedDataSize16); } else { long compressedDataSize32; pm_readbiglong(ifP, &compressedDataSize32); } } for (row = 0; row < rows; ++row) { readDecompressedRow(ifP, palmrow, lastrow, palmHeader.compressionType, palmHeader.bytesPerRow, row == 0, verbose); if (palmHeader.flags & PALM_DIRECT_COLOR) { assert(palmHeader.pixelSize == 16); convertRowToPnmDirect(palmrow, xelrow, cols, maxval, seen); } else convertRowToPnmNotDirect(palmrow, xelrow, cols, colormap, graymap, seen, palmHeader.pixelSize); pnm_writepnmrow(stdout, xelrow, cols, maxval, format, 0); } free(lastrow); free(palmrow); pnm_freerow(xelrow);}static voidshowHistogram(unsigned int * const seen, Colormap const colormap, const xelval * const graymap, unsigned int const ncolors) { unsigned int colorIndex; for (colorIndex = 0; colorIndex < ncolors; ++colorIndex) { if (!colormap) pm_message("%.3d -> %.3d: %d", colorIndex, graymap[colorIndex], seen[colorIndex]); else { Color_s const color = colorIndex << 24; Color const actualColor = (bsearch(&color, colormap->color_entries, colormap->ncolors, sizeof(color), palmcolor_compare_indices)); if (actualColor) pm_message("%.3d -> %ld,%ld,%ld: %d", colorIndex, (*actualColor >> 16) & 0xFF, (*actualColor >> 8) & 0xFF, (*actualColor & 0xFF), seen[colorIndex]); } }}intmain(int argc, char **argv) { struct cmdlineInfo cmdline; FILE* ifP; struct palmHeader palmHeader; Colormap colormap; struct directColorInfo directColorInfo; int format; xelval maxval; unsigned int nColors; /* Parse default params */ pnm_init(&argc, argv); parseCommandLine(argc, argv, &cmdline); ifP = pm_openr(cmdline.inputFilespec); readHeader(ifP, cmdline.rendition, &palmHeader); if (cmdline.verbose) reportPalmHeader(palmHeader); if (palmHeader.compressionType == COMPRESSION_PACKBITS) pm_error("The image is compression with the packbits method. " "This program does not know how to read that."); if ((palmHeader.flags & PALM_DIRECT_COLOR) && palmHeader.pixelSize != 16) pm_error("The image is of the direct color type, but has %u " "bits per pixel. The only kind of direct color images " "this program understands are 16 bit ones.", palmHeader.pixelSize); determineOutputFormat(palmHeader, &format, &maxval); getColorInfo(palmHeader, ifP, &colormap, &nColors, &directColorInfo); if (cmdline.transparent) doTransparent(palmHeader.flags, palmHeader.transparentIndex, palmHeader.pixelSize, colormap, directColorInfo); else { unsigned int * seen; xelval * graymap; graymap = createGraymap(nColors, 0, maxval); writePnm(palmHeader, ifP, colormap, graymap, nColors, format, maxval, cmdline.showhist ? &seen : NULL, cmdline.verbose); if (cmdline.showhist) showHistogram(seen, colormap, graymap, nColors); free(graymap); } pm_close(ifP); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -