diff options
Diffstat (limited to 'converter')
38 files changed, 4069 insertions, 1204 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile index 746db87c..35f420f2 100644 --- a/converter/other/Makefile +++ b/converter/other/Makefile @@ -118,12 +118,13 @@ PORTBINARIES = avstopam bmptopnm fitstopnm \ pamtoavs pamtodjvurle pamtofits pamtogif \ pamtohdiff pamtohtmltbl pamtompfont pamtooctaveimg \ pamtopam pamtopfm pamtopnm pamtouil \ - pamtoxvmini \ + pamtowinicon pamtoxvmini \ pbmtopgm pfmtopam \ pgmtopbm pgmtoppm ppmtopgm pnmtoddif \ pnmtopclxl \ pnmtosgi pnmtosir pamtotga pnmtoxwd \ - rlatopam sgitopnm sirtopnm sunicontopnm xwdtopnm zeisstopnm + rlatopam sgitopnm sirtopnm sunicontopnm \ + winicontopam xwdtopnm zeisstopnm BINARIES = \ $(PORTBINARIES) \ diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c index ea5eec39..254b6710 100644 --- a/converter/other/cameratopam/camera.c +++ b/converter/other/cameratopam/camera.c @@ -761,7 +761,7 @@ kodak_radc_load_raw() void kodak_jpeg_load_raw() {} #else -static boolean +static bool fill_input_buffer (j_decompress_ptr cinfo) { static char jpeg_buffer[4096]; diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c index 54b68a23..71c9c7af 100644 --- a/converter/other/cameratopam/cameratopam.c +++ b/converter/other/cameratopam/cameratopam.c @@ -69,7 +69,7 @@ int fuji_secondary; float cam_mul[4], pre_mul[4], coeff[3][4]; int histogram[3][0x2000]; jmp_buf failure; -bool use_secondary; +int use_secondary; bool verbose; #ifdef USE_LCMS diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c index 0198940c..78e40baf 100644 --- a/converter/other/cameratopam/foveon.c +++ b/converter/other/cameratopam/foveon.c @@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) { void -foveon_coeff(bool * const useCoeffP, - float coeff[3][4]) { +foveon_coeff(int * const useCoeffP, + float coeff[3][4]) { static const float foveon[3][3] = { { 1.4032, -0.2231, -0.1016 }, diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h index 57be2244..f3177e50 100644 --- a/converter/other/cameratopam/foveon.h +++ b/converter/other/cameratopam/foveon.h @@ -10,5 +10,5 @@ void foveon_load_raw(void); void -foveon_coeff(bool * const useCoeffP, - float coeff[3][4]); +foveon_coeff(int * const useCoeffP, + float coeff[3][4]); diff --git a/converter/other/ipdb.c b/converter/other/ipdb.c index 5c1fc314..eec4495a 100644 --- a/converter/other/ipdb.c +++ b/converter/other/ipdb.c @@ -19,6 +19,7 @@ * Authors: Eric A. Howe (mu@trends.net) * Bryan Henderson, 2010 */ +#define _BSD_SOURCE /* Ensure strdup() is in <string.h> */ #include <assert.h> #include <time.h> #include <string.h> diff --git a/converter/other/pamtogif.c b/converter/other/pamtogif.c index 4dac8923..5b9c219c 100644 --- a/converter/other/pamtogif.c +++ b/converter/other/pamtogif.c @@ -220,7 +220,7 @@ closestColor(tuple const color, unsigned int i; unsigned int imin, dmin; - bool fits; + int fits; dmin = UINT_MAX; imin = 0; @@ -1544,7 +1544,7 @@ computeTransparent(char const colorarg[], const char * colorspec; bool exact; tuple transcolor; - bool found; + int found; int colorindex; if (colorarg[0] == '=') { diff --git a/converter/other/pamtooctaveimg.c b/converter/other/pamtooctaveimg.c index b090281d..28bc4cd4 100644 --- a/converter/other/pamtooctaveimg.c +++ b/converter/other/pamtooctaveimg.c @@ -75,13 +75,13 @@ findOrAddColor(tuple const color, colormap *cmapP. If the color isn't in the map, give it a new colormap index, put it in the colormap, and return that. -----------------------------------------------------------------------------*/ - bool found; + int found; int colorIndex; pnm_lookuptuple(&cmapP->pam, cmapP->hash, color, &found, &colorIndex); if (!found) { - bool fits; + int fits; unsigned int plane; colorIndex = cmapP->nColors++; diff --git a/converter/other/pamtopam.c b/converter/other/pamtopam.c index cae54060..9cb82f7a 100644 --- a/converter/other/pamtopam.c +++ b/converter/other/pamtopam.c @@ -17,7 +17,7 @@ int main(int argc, const char * argv[]) { - bool eof; /* no more images in input stream */ + int eof; /* no more images in input stream */ struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PAM image */ diff --git a/converter/other/pamtopnm.c b/converter/other/pamtopnm.c index ba655b1e..9bb662b7 100644 --- a/converter/other/pamtopnm.c +++ b/converter/other/pamtopnm.c @@ -109,7 +109,7 @@ main(int argc, char *argv[]) { struct cmdlineInfo cmdline; FILE* ifP; - bool eof; /* no more images in input stream */ + int eof; /* no more images in input stream */ struct pam inpam; /* Input PAM image */ struct pam outpam; /* Output PNM image */ diff --git a/converter/other/pamtosrf.c b/converter/other/pamtosrf.c index 19328073..3800d77c 100644 --- a/converter/other/pamtosrf.c +++ b/converter/other/pamtosrf.c @@ -112,7 +112,7 @@ srfAlphaFromTuple(tuple const t, const struct pam * const pamP) { uint8_t retval; - bool haveOpacity; + int haveOpacity; unsigned int opacityPlane; pnm_getopacity(pamP, &haveOpacity, &opacityPlane); @@ -181,7 +181,7 @@ main(int argc, const char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; struct srf srf; - bool eof; /* No more images in input */ + int eof; /* No more images in input */ unsigned int imageSeq; /* Sequence of current image in input file. First = 0 */ diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c index 72aa4151..adf76801 100644 --- a/converter/other/pamtosvg/pamtosvg.c +++ b/converter/other/pamtosvg/pamtosvg.c @@ -134,7 +134,7 @@ parseCommandLine(int argc, 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; + optEntry * option_def; /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c index 551909a0..0206678d 100644 --- a/converter/other/pamtotiff.c +++ b/converter/other/pamtotiff.c @@ -1055,7 +1055,7 @@ main(int argc, char *argv[]) { const char * inputFileDescription; FILE* ifP; TIFF* tifP; - bool eof; + int eof; unsigned int imageSeq; pnm_init(&argc, argv); diff --git a/converter/other/pamtowinicon.c b/converter/other/pamtowinicon.c new file mode 100644 index 00000000..c67267e4 --- /dev/null +++ b/converter/other/pamtowinicon.c @@ -0,0 +1,1177 @@ +#define _POSIX_SOURCE /* Make sure fdopen() is in <stdio.h> */ +#include <assert.h> +#include <string.h> +#include <stdio.h> + +#include "netpbm/pm_config.h" +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" +#include "netpbm/shhopt.h" +#include "netpbm/pm_system.h" +#include "netpbm/pam.h" +#include "winicon.h" + + + +struct CmdlineInfo { + const char * inputFileName; + unsigned int verbose; + int pngthreshold; + unsigned int truetransparent; +}; + + + +static void +parseCommandLine(int argc, const char **argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + unsigned int option_def_index; + optStruct3 opt3; + unsigned int pngthresholdSpec; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; + + OPTENT3 (0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3 (0, "pngthreshold", OPT_UINT, &cmdlineP->pngthreshold, + &pngthresholdSpec, 0); + OPTENT3 (0, "truetransparent", OPT_FLAG, NULL, + &cmdlineP->truetransparent, 0); + + opt3.opt_table = option_def; + opt3.short_allowed = false; + opt3.allowNegNum = false; + + pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0); + + if (pngthresholdSpec) { + if (UINT_MAX / cmdlineP->pngthreshold < cmdlineP->pngthreshold) + pm_error("-pngthreshold is too large: %u", cmdlineP->pngthreshold); + } else + cmdlineP->pngthreshold = 128; + + if (argc-1 > 0) { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments: %u. The only non-option " + "argument is the optional input file name", argc-1); + } else + cmdlineP->inputFileName = "-"; + + free(option_def); +} + + + +static bool verbose; + +static unsigned char const pngHeader[] = PNG_HEADER; + + + +struct Palette { + sample color[256][3]; + unsigned int colorCt; + /* Number of colors in color[][] */ + bool tooManyColors; + /* There are too many colors for a BMP palette (more than 256); only + the first 256 are in color[][] + */ +}; + + + +static struct IconDir * +newIconDir() { + + struct IconDir * dirP; + + MALLOCVAR_NOFAIL(dirP); + + dirP->zero = 0; + dirP->type = ICONDIR_TYPE_ICO; + dirP->count = 0; + + dirP->entriesAllocCt = 0; + dirP->entries = NULL; + + return dirP; +} + + + +static void +freeIconDir(struct IconDir * const dirP) { + if (dirP->entries) + free(dirP->entries); + + free(dirP); +} + + + +static void +addToDirectory(struct IconDirEntry * const dirEntryP, + struct IconDir * const dirP) { +/*---------------------------------------------------------------------------- + Add an icon to the icon directory. +-----------------------------------------------------------------------------*/ + if (dirP->count + 1 > dirP->entriesAllocCt) { + /* Out of space in dirP->entries[]. Expand. */ + + dirP->entriesAllocCt += 8; + + REALLOCARRAY(dirP->entries, dirP->entriesAllocCt); + + if (!dirP->entries) + pm_error("Unable to get memory for %u entries " + "in the Icon directory.", dirP->entriesAllocCt); + } + + dirP->entries[dirP->count++] = *dirEntryP; +} + + + +typedef void (GetPixelFn) (tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel); + + + +static GetPixelFn get_grayscalePixel; + +static void +get_grayscalePixel(tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel) { +/*---------------------------------------------------------------------------- + Get a pixel from a grayscale PAM +-----------------------------------------------------------------------------*/ + pixel[0] = tuples[row][col][0]; + pixel[1] = tuples[row][col][0]; + pixel[2] = tuples[row][col][0]; +} + + + +static GetPixelFn get_rgbPixel; + +static void +get_rgbPixel(tuple ** const tuples, + unsigned int const col, + unsigned int const row, + sample * const pixel) { +/*---------------------------------------------------------------------------- + Get a pixel from an RGB PAM +-----------------------------------------------------------------------------*/ + pixel [0] = tuples [row][col][0]; + pixel [1] = tuples [row][col][1]; + pixel [2] = tuples [row][col][2]; +} + + +static bool +andMakesOpaque(const struct pam * const pamP, + tuple ** const tuples, + unsigned int const row, + unsigned int const col, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane) { +/*---------------------------------------------------------------------------- + The AND mask makes a pixel opaque +-----------------------------------------------------------------------------*/ + if (haveAnd) + return (pamP->maxval <= tuples[row][col][andPlane]); + else if (haveAlpha) + return (pamP->maxval <= tuples[row][col][alphaPlane]); + else + /* neither alpha channel nor AND mask: full opacity */ + return true; +} + + + +static void +getPalette(struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + struct Palette * const paletteP) { +/*---------------------------------------------------------------------------- + Create the palette for all the colors in 'tuples'. +-----------------------------------------------------------------------------*/ + unsigned int row; + + paletteP->colorCt = 0; /* initial value */ + paletteP->tooManyColors = false; /* initial value */ + + for (row = 0; pamP->height > row && !paletteP->tooManyColors; ++row) { + unsigned int col; + for (col = 0; pamP->width > col && !paletteP->tooManyColors; ++col) { + sample pixel[3]; + unsigned int i; + + getPixel(tuples, col, row, pixel); + + for (i = 0; i < paletteP->colorCt; ++i) { + if ((paletteP->color[i][0] == pixel[0]) + && (paletteP->color[i][1] == pixel[1]) + && (paletteP->color[i][2] == pixel[2])) + break; + } + if (i == paletteP->colorCt) { + /* We didn't find the color. */ + if (paletteP->colorCt >= 256) { + /* Image exceeds the palette capacity */ + paletteP->tooManyColors = true; + } else { + /* Add the color to the palette */ + paletteP->color[paletteP->colorCt][0] = pixel[0]; + paletteP->color[paletteP->colorCt][1] = pixel[1]; + paletteP->color[paletteP->colorCt][2] = pixel[2]; + + ++paletteP->colorCt; + } + } + } + } +} + + + +static bool +realAlphaNeeded(const struct pam * const pamP, + tuple ** const tuples, + unsigned int const alphaPlane) { +/*---------------------------------------------------------------------------- + A real alpha channel (in contrast to an AND mask) is needed to represent the + image in 'tuples', given that 'alphaPlane' is the alpha plane. + + A real alpha channel is needed if any pixel is translucent (neither opaque + nor transparent). +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + sample const opacity = tuples[row][col][alphaPlane]; + + if (opacity != 0 && opacity != pamP->maxval) + return true; + } + } + return false; +} + + + +static void +writeBmpImageHeader(unsigned int const width, + unsigned int const height, + unsigned int const bpp, + unsigned int const rasterSize, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + + Write BMP image header + + Note: bm_height is sum of rows in XOR mask and AND mask, while + image_size is the size of the AND mask only. + + image_size does not include the sizes of the (optional) palette + and the (mandatory) AND mask. +-----------------------------------------------------------------------------*/ + pm_writelittlelongu (ofP, 40); /* header_size */ + pm_writelittlelongu (ofP, width); /* bm_width */ + pm_writelittlelongu (ofP, height *2); /* bm_height */ + pm_writelittleshortu (ofP, 1); /* color_planes */ + pm_writelittleshortu (ofP, bpp); /* bits_per_pixel */ + pm_writelittlelongu (ofP, BI_RGB); /* compression_method */ + pm_writelittlelongu (ofP, rasterSize); /* image_size */ + pm_writelittlelongu (ofP, 0); /* horizontal_resolution*/ + pm_writelittlelongu (ofP, 0); /* vertical_resolution */ + pm_writelittlelongu (ofP, 0); /* colors_in_palette */ + pm_writelittlelongu (ofP, 0); /* important_colors */ +} + + + +static void +write32BitBmp(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + bool const haveAlpha, + unsigned int const alphaPlane, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write a 32-bit BMP encoded image to file *ofP. +-----------------------------------------------------------------------------*/ + int row; + + writeBmpImageHeader(pamP->width, pamP->height, 32, + pamP->width * 4 * pamP->height, ofP); + + /* write "XOR mask" */ + for (row = pamP->height - 1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + sample pixel[3]; + uint32_t val; + + getPixel(tuples, col, row, pixel); + + val = ((uint32_t) pixel[PAM_RED_PLANE] << 16) + + ((uint32_t) pixel[PAM_GRN_PLANE] << 8) + + ((uint32_t) pixel[PAM_BLU_PLANE] << 0) + ; + + if (haveAlpha) + val += (uint32_t) tuples[row][col][alphaPlane] << 24; + + pm_writelittlelongu(ofP, val); + } + } + *sizeP = 40 + pamP->height * pamP->width * 4; +} + + + +static void +writeBmpPalette(const struct Palette * const paletteP, + unsigned int const maxColors, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write the palette of a BMP image. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; i < paletteP->colorCt; ++i) + pm_writelittlelongu(ofP, 0 + +(paletteP->color[i][PAM_RED_PLANE] << 16) + +(paletteP->color[i][PAM_GRN_PLANE] << 8) + +(paletteP->color[i][PAM_BLU_PLANE] << 0)); + + for (; i < maxColors; ++i) + pm_writelittlelongu(ofP, 0); +} + + + +static void +writeXorMask(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + const struct Palette * const paletteP, + unsigned int const bpp, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write the "XOR mask" part of a BMP image. + + This is what one normally thinks of as the foreground image raster. +-----------------------------------------------------------------------------*/ + unsigned int const maxCol = ((pamP->width * bpp + 31) & ~31) / bpp; + + int row; + + for (row = pamP->height - 1; row >= 0; --row) { + uint8_t val; + uint16_t mask; + unsigned int col; + + mask = 0x1; + val = 0x0; + + for (col = 0; col < pamP->width; ++col) { + sample pixel[3]; + unsigned int i; + + mask <<= bpp; + val <<= bpp; + + getPixel(tuples, col, row, pixel); + + for (i = 0; i < paletteP->colorCt; ++i) + if (true + && (pixel[0] == paletteP->color[i][0]) + && (pixel[1] == paletteP->color[i][1]) + && (pixel[2] == paletteP->color[i][2])) + break; + + assert(i < paletteP->colorCt); + + val |= i; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + mask = 0x1; + val = 0x0; + } + } + for (; col < maxCol; ++col) { + mask <<= bpp; + val <<= bpp; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + mask = 0x1; + } + } + } +} + + + +static void +writePaletteBmp(unsigned int const bpp, + const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + const struct Palette * const paletteP, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write a `BMP with palette' encoded image to file *ofP. + + Unless it would be smaller as a 32-bit direct image, in which case + write that instead. +-----------------------------------------------------------------------------*/ + unsigned int const maxColors = 1 << bpp; + + unsigned int const rasterSize = + pamP->height *((pamP->width * bpp + 31) & ~31) / 8; + + if (pamP->height * pamP->width * 4 <= maxColors * 4 + rasterSize) + write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0, + ofP, sizeP); + else { + unsigned int const headerSize = 40; + unsigned int const paletteSize = maxColors * 4; + + writeBmpImageHeader(pamP->width, pamP->height, bpp, rasterSize, ofP); + + writeBmpPalette(paletteP, maxColors, ofP); + + writeXorMask(pamP, tuples, getPixel, paletteP, bpp, ofP); + + *sizeP = headerSize + paletteSize + rasterSize; + } +} + + + +static void +writeAndMask(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + FILE * const ofP, + uint32_t * const sizeP) { +/*---------------------------------------------------------------------------- + Write the AND mask to file *ofP. +-----------------------------------------------------------------------------*/ + unsigned int const maxCol =((pamP->width * 1 + 31) & ~31) / 1; + + int row; + unsigned int sizeSoFar; + + sizeSoFar = 0; + + for (row = pamP->height - 1; row >= 0; --row) { + uint8_t val; + uint16_t mask; + unsigned int col; + + mask = 0x1; + val = 0x0; + + for (col = 0; col < pamP->width; ++col) { + mask <<= 1; + val <<= 1; + + if (!andMakesOpaque(pamP, tuples, row, col, + haveAlpha, alphaPlane, haveAnd, andPlane)) + val |= 0x1; + + if (mask > 0xFF) { + pm_writecharu(ofP, val); + sizeSoFar += 1; + mask = 0x1; + val = 0x0; + } + } + for (; col < maxCol; ++col) { + mask <<= 1; + val <<= 1; + + if (mask > 0xFF){ + pm_writecharu(ofP, val); + sizeSoFar += 1; + mask = 0x1; + } + } + } + *sizeP = sizeSoFar; +} + + + +static void +makeAlphaFile(const struct pam * const imagePamP, + tuple ** const imageTuples, + unsigned int const alphaPlane, + const char ** const alphaFileNameP) { + + FILE * alphaFileP; + struct pam alphaPam; + tuple ** alphaTuples; + unsigned int row; + + pm_make_tmpfile(&alphaFileP, alphaFileNameP); + + alphaPam.size = sizeof(alphaPam); + alphaPam.len = PAM_STRUCT_SIZE(tuple_type); + alphaPam.file = alphaFileP; + alphaPam.format = PAM_FORMAT; + alphaPam.width = imagePamP->width; + alphaPam.height = imagePamP->height; + alphaPam.depth = 1; + alphaPam.maxval = imagePamP->maxval; + strcpy(alphaPam.tuple_type, PAM_PGM_TUPLETYPE); + + alphaTuples = pnm_allocpamarray(&alphaPam); + + assert(alphaPlane < imagePamP->depth); + + for (row = 0; row < alphaPam.height; ++row) { + unsigned int col; + for (col = 0; col < alphaPam.width; ++col) + alphaTuples[row][col][0] = imageTuples[row][col][alphaPlane]; + } + + pnm_writepam(&alphaPam, alphaTuples); + + pnm_freepamarray(alphaTuples, &alphaPam); + + pm_close(alphaFileP); +} + + + +struct AcceptToFileParm { + FILE * ofP; + size_t * writeCtP; +}; + +static void +acceptToFile(int const pipeToSuckFd, + void * const accepterParm) { + + struct AcceptToFileParm * const parmP = accepterParm; + + FILE * const inFileP = fdopen(pipeToSuckFd, "r"); + + bool eof; + size_t copyCt; + + for (eof = false, copyCt = 0; !eof; ) { + size_t readCt; + unsigned char buffer[1024]; + + readCt = fread(buffer, 1, sizeof(buffer), inFileP); + + if (readCt == 0) + eof = true; + else { + size_t writeCt; + + writeCt = fwrite(buffer, 1, readCt, parmP->ofP); + + if (writeCt != readCt) + pm_error("Write to images file failed. errno=%d (%s)", + errno, strerror(errno)); + + copyCt += writeCt; + } + } + *parmP->writeCtP = copyCt; +} + + + +static void +writePng(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + uint32_t * const sizeP, + FILE * const ofP) { + + struct pamtuples pamTuples; + size_t pngSize; + struct AcceptToFileParm acceptParm; + struct pam pam; + + pam = *pamP; + pam.depth = pamP->depth - (haveAlpha ? 1 : 0) - (haveAnd ? 1 : 0); + + pamTuples.pamP = &pam; + pamTuples.tuplesP = (tuple ***)&tuples; + + /* We're going to fork a process to add stuff to *ofP, so we flush + out this process' previous writes to that file first: + */ + fflush(ofP); + + acceptParm.ofP = ofP; + acceptParm.writeCtP = &pngSize; + + if (haveAlpha || haveAnd) { + const char * alphaFileName; + const char * command; + + if (haveAlpha) + makeAlphaFile(pamP, tuples, alphaPlane, &alphaFileName); + else + makeAlphaFile(pamP, tuples, andPlane, &alphaFileName); + + strcpy (pam.tuple_type, + pam.depth == 3 ? PAM_PPM_TUPLETYPE: PAM_PGM_TUPLETYPE); + + pm_asprintf(&command, "pnmtopng -alpha=\"%s\"", alphaFileName); + + pm_system(pm_feed_from_pamtuples, &pamTuples, + acceptToFile, &acceptParm, + command); + + pm_strfree(command); + + unlink(alphaFileName); + } else { + pm_system(pm_feed_from_pamtuples, &pamTuples, + acceptToFile, &acceptParm, + "pnmtopng"); + } + + *sizeP = pngSize; +} + + + +static void +blackenXor(const struct pam * const pamP, + tuple ** const tuples, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane) { +/*---------------------------------------------------------------------------- + Set all pixels marked as transparent in AND mask to black. +-----------------------------------------------------------------------------*/ + unsigned int row; + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + if (!andMakesOpaque(pamP, tuples, row, col, + haveAlpha, alphaPlane, haveAnd, andPlane)) { + tuples[row][col][0] = PAM_BLACK; + + if (pamP->depth >= 3) { + tuples[row][col][1] = PAM_BLACK; + tuples[row][col][2] = PAM_BLACK; + } + } + } + } +} + + + + +static void +readAndScalePam(struct pam * const pamP, + bool const doingPng, + tuple ** const tuples) { + + if (doingPng) { + /* Read the image with its native maxval */ + unsigned int row; + for (row = 0; row < pamP->height; ++row) + pnm_readpamrow(pamP, tuples[row]); + } else { + /* Read the image and scale to maxval 255 */ + tuple * tuplerow; + unsigned int row; + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < pamP->height; ++row) { + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuples[row], tuplerow, 255); + } + pnm_freepamrow(tuplerow); + pamP->maxval = 255; + } +} + + + +static void +determineImageType(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn ** const getPixelP, + bool * const haveAlphaP, + unsigned int * const alphaPlaneP, + bool * const haveAndP, + unsigned int * const andPlaneP) { + + /* PAM input channels: + * + * 1-channel PAM: Grayscale + * 2-channel PAM: Grayscale +Alpha + * 3-channel PAM: RGB + * 4-channel PAM: RGB +Alpha + * 5-channel PAM: RGB +Alpha +AND mask + */ + switch (pamP->depth) { + case 1: + *getPixelP = get_grayscalePixel; + *haveAlphaP = false; + *haveAndP = false; + break; + + case 2: + *getPixelP = get_grayscalePixel; + if (realAlphaNeeded(pamP, tuples, 1)) { + *haveAlphaP = true; + *alphaPlaneP = 1; + *haveAndP = false; + } else { + *haveAlphaP = false; + *haveAndP = true; + *andPlaneP = 1; + } + break; + + case 3: + *getPixelP = get_rgbPixel; + *haveAlphaP = false; + *haveAndP = false; + break; + + case 4: + *getPixelP = get_rgbPixel; + if (realAlphaNeeded(pamP, tuples, 3)) { + *haveAlphaP = true; + *alphaPlaneP = 3; + *haveAndP = false; + } else { + *haveAlphaP = false; + *haveAndP = true; + *andPlaneP = 3; + } + break; + + case 5: + *getPixelP = get_rgbPixel; + *haveAlphaP = true; + *alphaPlaneP = 3; + *haveAndP = true; + *andPlaneP = 4; + break; + + default: + pm_error("unexpected PAM depth %u. " + "We understand depths 1-5", pamP->depth); + break; + } +} + + + +static void +reportImageInfo(unsigned int const imageNum, + const struct pam * const pamP, + const struct Palette * const paletteP, + bool const haveAlpha, + bool const haveAnd) { + + const char * colorCt; + + if (paletteP->tooManyColors) + pm_asprintf(&colorCt, "> 256"); + else + pm_asprintf(&colorCt, "%u", paletteP->colorCt); + + pm_message("Image %2u:" + " %3u x %3u x %u, %s colors%s%s", + imageNum, + pamP->width, pamP->height, pamP->depth, + colorCt, + haveAlpha ? ", alpha channel": "", + haveAnd ? ", AND mask": ""); + + pm_strfree(colorCt); +} + + + +static void +writeIconAndCreateDirEntry(const struct pam * const pamP, + tuple ** const tuples, + GetPixelFn * const getPixel, + bool const doingPng, + bool const haveAlpha, + unsigned int const alphaPlane, + bool const haveAnd, + unsigned int const andPlane, + bool const mustBlackenXor, + const struct Palette * const paletteP, + FILE * const ofP, + struct IconDirEntry * const dirEntryP) { +/*---------------------------------------------------------------------------- + Write to *ofP the icon image for the image represented by *pamP and + 'tuples'. + + Generate the information for an icon directory entry for this image + and return it as *dirEntryP. ==>BUT: the 'offset' member of this + structure will not be meaningful. <== + + Make a PNG image if 'doingPng' is true; BMP otherwise. + + 'haveAlpha' means that there is an alpha plane in 'tuples' and it is + Plane 'alphaPlane'. + + 'haveAnd' means that there is an AND plane in 'tuples' and it is Plane + 'andPlane'. + + *paletteP is the color palette for the icon; it contains an entry for each + color in 'tuples'. Except: it may simply indicate that there are too many + colors in 'tuples' to have a palette. + + The 'bits_per_pixel' member of the directory entry is supposed to tell the + color resolution of the image so the user can decide which of many versions + of the icon in the file to use. But we just call it 32 bits in every case + except paletted BMP, where it actually relates to how many colors are in + the image. +-----------------------------------------------------------------------------*/ + dirEntryP->width = pamP->width; + dirEntryP->height = pamP->height; + dirEntryP->color_planes = 1; + dirEntryP->zero = 0; + + if (doingPng) { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + writePng(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane, + &dirEntryP->size, ofP); + } else { + uint32_t bmpSize; + uint32_t andMaskSize; + + if (mustBlackenXor) + blackenXor(pamP, tuples, + haveAlpha, alphaPlane, haveAnd, andPlane); + + if (haveAlpha) { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + write32BitBmp(pamP, tuples, getPixel, haveAlpha, alphaPlane, + ofP, &bmpSize); + } else if (paletteP->tooManyColors) { + /* Do a truecolor image */ + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 32; + + write32BitBmp(pamP, tuples, getPixel, false /*haveAlpha*/, 0, + ofP, &bmpSize); + } else { + /* Do a paletted image */ + + if (paletteP->colorCt <= 2) { + dirEntryP->color_count = paletteP->colorCt; + dirEntryP->bits_per_pixel = 1; + + writePaletteBmp(1, pamP, tuples, getPixel, paletteP, + ofP, &bmpSize); + } else if (paletteP->colorCt <= 16) { + dirEntryP->color_count = paletteP->colorCt; + dirEntryP->bits_per_pixel = 4; + + writePaletteBmp(4, pamP, tuples, getPixel,paletteP, + ofP, &bmpSize); + } else { + dirEntryP->color_count = 0; + dirEntryP->bits_per_pixel = 8; + + writePaletteBmp(8, pamP, tuples, getPixel, paletteP, + ofP, &bmpSize); + } + } + writeAndMask(pamP, tuples, haveAlpha, alphaPlane, haveAnd, andPlane, + ofP, &andMaskSize); + + dirEntryP->size = bmpSize + andMaskSize; + } +} + + + +static void +convertOneImage(unsigned int const imageNum, + FILE * const ifP, + unsigned int const pngThreshold, + bool const mustBlackenXor, + FILE * const ofP, + struct IconDir * const dirP) { + + struct IconDirEntry dirEntry; + struct pam pam; + tuple ** tuples; + bool haveAlpha; + unsigned int alphaPlane; + bool haveAnd; + unsigned int andPlane; + GetPixelFn * getPixel; + struct Palette palette; + bool doingPng; + + /* Output: + * + * threshold^2 pixels or more: + * no alpha channel: PNG (RGB) + * alpha channel: PNG (RGBA) + * alpha channel +AND mask: PNG (RGBA), AND mask dropped + * alpha values other than 0 and maxval: 32bit +alpha BMP + * no more than 2 colors: 1bit or 32bit BMP + * no more than 16 colors: 4bit or 32bit BMP + * no more than 256 colors: 8bit or 32bit BMP + * more than 256 colors: 32bit BMP + */ + pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(tuple_type)); + + if (pam.width > 256 || pam.height > 256) + pm_error("Image %u: too large as a windows icon (%u x %u). " + "Maximum allowed dimension is 256", + imageNum, pam.width, pam.height); + + tuples = pnm_allocpamarray(&pam); + + doingPng = pam.width * pam.height >= pngThreshold; + + readAndScalePam(&pam, doingPng, tuples); + + determineImageType(&pam, tuples, &getPixel, + &haveAlpha, &alphaPlane, &haveAnd, &andPlane); + + getPalette(&pam, tuples, getPixel, &palette); + + if (verbose) + reportImageInfo(imageNum, &pam, &palette, haveAlpha, haveAnd); + + writeIconAndCreateDirEntry(&pam, tuples, getPixel, doingPng, + haveAlpha, alphaPlane, + haveAnd, andPlane, + mustBlackenXor, + &palette, + ofP, &dirEntry); + + if (verbose) + pm_message("Image %2u: %u bytes", imageNum, dirEntry.size); + + pnm_freepamarray(tuples, &pam); + + addToDirectory(&dirEntry, dirP); +} + + + +static void +convert(FILE * const ifP, + unsigned int const pngThreshold, + bool const mustBlackenXor, + struct IconDir * const dirP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Read a (multi-image) PAM file from *ifP and convert the individual images + to the proper format for a Windows icon file and write those to *ofP. + + Where the number of pixels in an image is at least 'pngThreshold', use + a PNG image. Otherwise, use a BMP. +-----------------------------------------------------------------------------*/ + unsigned int imageNum; + int eof; + + for (imageNum = 0, eof = false; !eof; ++imageNum) { + convertOneImage(imageNum, ifP, pngThreshold, mustBlackenXor, + ofP, dirP); + + pnm_nextimage(ifP, &eof); + } +} + + + +static void +writeIconDirEntry(const struct IconDirEntry * const dirEntryP, + FILE * const ofP) { + + pm_writecharu (ofP, dirEntryP->width); + pm_writecharu (ofP, dirEntryP->height); + pm_writecharu (ofP, dirEntryP->color_count); + pm_writecharu (ofP, dirEntryP->zero); + pm_writelittleshortu (ofP, dirEntryP->color_planes); + pm_writelittleshortu (ofP, dirEntryP->bits_per_pixel); + pm_writelittlelongu (ofP, dirEntryP->size); + pm_writelittlelongu (ofP, dirEntryP->offset); +} + + + +static void +writeIconDirectory(const struct IconDir * const dirP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write to file *ofP the icon directory described by *dirP. + + *dirP's image offset members are meaningless as input. We fill them in. +-----------------------------------------------------------------------------*/ + uint32_t const hsize = 6 + dirP->count * 16; + + unsigned int imageNum; + unsigned int imageOffset; + + pm_writelittleshortu(ofP, dirP->zero); + pm_writelittleshortu(ofP, dirP->type); + pm_writelittleshortu(ofP, dirP->count); + + for (imageNum = 0, imageOffset = hsize; + imageNum < dirP->count; + ++imageNum) { + + struct IconDirEntry * const dirEntryP = &dirP->entries[imageNum]; + + pm_message("image %2u: %3u x %3u x %2u", + imageNum, + dirEntryP->width, + dirEntryP->height, + dirEntryP->bits_per_pixel); + + dirEntryP->offset = imageOffset; + + writeIconDirEntry(dirEntryP, ofP); + + imageOffset += dirEntryP->size; + } +} + + + +static void +copyFile(FILE * const ifP, + FILE * const ofP) { + + bool eof; + + for (eof = false; !eof; ) { + unsigned char buffer[1024]; + size_t bytesRead; + + bytesRead = fread(buffer, 1, sizeof(buffer), ifP); + + if (bytesRead == 0) + eof = true; + else { + size_t bytesWritten; + + bytesWritten = fwrite(buffer, 1, bytesRead, ofP); + + if (bytesWritten < bytesRead) + pm_error("Error writing to output file."); + } + } +} + + + +static void +writeIconFile(const struct IconDir * const dirP, + FILE * const imagesFileP, + FILE * const ofP) { +/*---------------------------------------------------------------------------- + Write a windows icon file. + + *dirP is the icon directory to put in it. + + *imagesFileP contains all the text of the icon images. The contents of + this file go verbatim into the output. +-----------------------------------------------------------------------------*/ + writeIconDirectory(dirP, ofP); + + copyFile(imagesFileP, ofP); +} + + + +int +main(int argc, const char *argv []) { + + struct CmdlineInfo cmdline; + FILE * ifP; + FILE * imagesFileP; + /* This is the file in which we collect the individual icon + images to be copied later to the output. + */ + struct IconDir * dirP; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + /* The output icon file has directory information at the top that we + can't know until we have looked at the input images. So as we pass + through the input, we collect the directory information and generate + the individual icon images and store them in *imageFileP. When we've + been through all of the input, we write out the directory and then + copy the images from *imageFileP to the output. + */ + + dirP = newIconDir(); + + imagesFileP = pm_tmpfile(); + + ifP = pm_openr(cmdline.inputFileName); + + convert(ifP, SQR(cmdline.pngthreshold), cmdline.truetransparent, + dirP, imagesFileP); + + rewind(imagesFileP); + + writeIconFile(dirP, imagesFileP, stdout); + + freeIconDir(dirP); + + return 0; +} + + + diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c index e1aa9b52..b57bcc74 100644 --- a/converter/other/pamtoxvmini.c +++ b/converter/other/pamtoxvmini.c @@ -152,14 +152,14 @@ getPaletteIndexThroughCache(struct pam * const pamP, If the tuple-index association is in *paletteIndexP, use it. If not, find it the hard way and add it to *palettedIndexP for the next guy. -----------------------------------------------------------------------------*/ - bool found; + int found; int paletteIndex; pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex); if (found) *paletteIndexP = paletteIndex; else { - bool fits; + int fits; findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP); pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits); diff --git a/converter/other/pnmtopclxl.c b/converter/other/pnmtopclxl.c index 83fdf7bf..4cd7c4d0 100644 --- a/converter/other/pnmtopclxl.c +++ b/converter/other/pnmtopclxl.c @@ -1177,7 +1177,7 @@ printPages(int const outFd, while (sourceP) { FILE * ifP; struct pam pam; - bool eof; + int eof; unsigned int pageNum; ifP = pm_openr(sourceP->name); diff --git a/converter/other/pnmtopng.c b/converter/other/pnmtopng.c index edbe57f5..bcb94612 100644 --- a/converter/other/pnmtopng.c +++ b/converter/other/pnmtopng.c @@ -128,7 +128,6 @@ struct cmdlineInfo { int filterSet; unsigned int force; unsigned int libversion; - unsigned int compressionSpec; struct zlibCompression zlibCompression; }; @@ -480,6 +479,27 @@ parseCommandLine(int argc, const char ** argv, +static void +reportInputType(int const format, + xelval const maxval) { + + switch (PNM_FORMAT_TYPE(format)) { + case PBM_TYPE: + pm_message ("reading a PBM file"); + break; + case PGM_TYPE: + pm_message ("reading a PGM file (maxval=%d)", maxval); + break; + case PPM_TYPE: + pm_message ("reading a PPM file (maxval=%d)", maxval); + break; + default: + assert(false); + } +} + + + static png_color_16 xelToPngColor_16(xel const input, xelval const maxval, @@ -857,7 +877,7 @@ tryTransparentColor(FILE * const ifp, pixel const transcolor, bool * const singleColorIsTransP) { - int const pnm_type = PNM_FORMAT_TYPE(format); + int const pnmType = PNM_FORMAT_TYPE(format); xel * xelrow; bool singleColorIsTrans; @@ -878,7 +898,7 @@ tryTransparentColor(FILE * const ifp, /* If we have a second transparent color, we're disqualified */ - if (pnm_type == PPM_TYPE) { + if (pnmType == PPM_TYPE) { if (!PPM_EQUAL(xelrow[col], transcolor)) singleColorIsTrans = FALSE; } else { @@ -895,7 +915,7 @@ tryTransparentColor(FILE * const ifp, the same color as our candidate transparent color, that disqualifies us. */ - if (pnm_type == PPM_TYPE) { + if (pnmType == PPM_TYPE) { if (PPM_EQUAL(xelrow[col], transcolor)) singleColorIsTrans = FALSE; } else { @@ -1118,6 +1138,51 @@ determineBackground(struct cmdlineInfo const cmdline, +static bool +hasColor(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + xelval const maxval, + int const format, + pm_filepos const rasterPos) { +/*---------------------------------------------------------------------------- + The image contains colors other than black, white, and gray. +-----------------------------------------------------------------------------*/ + bool retval; + + if (PNM_FORMAT_TYPE(format) == PPM_TYPE) { + unsigned int row; + xel * xelrow; /* malloc'ed */ + /* The row of the input image currently being analyzed */ + bool isGray; + + xelrow = pnm_allocrow(cols); + + pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); + + for (row = 0, isGray = true; row < rows && isGray; ++row) { + unsigned int col; + + pnm_readpnmrow(ifP, xelrow, cols, maxval, format); + + for (col = 0; col < cols && isGray; ++col) { + xel const p = xelrow[col]; + if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p)) + isGray = FALSE; + } + } + + pnm_freerow(xelrow); + + retval = !isGray; + } else + retval = false; + + return retval; +} + + + static void findRedundantBits(FILE * const ifp, int const rasterPos, @@ -1819,19 +1884,19 @@ tryAlphaPalette(FILE * const ifP, static void -computePixelWidth(int const pnm_type, - unsigned int const pnm_meaningful_bits, +computePixelWidth(bool const colorPng, + unsigned int const pnmMeaningfulBitCt, bool const alpha, unsigned int * const bitsPerSampleP, unsigned int * const bitsPerPixelP) { unsigned int bitsPerSample, bitsPerPixel; - if (pnm_type == PPM_TYPE || alpha) { + if (colorPng || alpha) { /* PNG allows only depths of 8 and 16 for a truecolor image and for a grayscale image with an alpha channel. */ - if (pnm_meaningful_bits > 8) + if (pnmMeaningfulBitCt > 8) bitsPerSample = 16; else bitsPerSample = 8; @@ -1839,24 +1904,24 @@ computePixelWidth(int const pnm_type, /* A grayscale, non-colormapped, no-alpha PNG may have any bit depth from 1 to 16 */ - if (pnm_meaningful_bits > 8) + if (pnmMeaningfulBitCt > 8) bitsPerSample = 16; - else if (pnm_meaningful_bits > 4) + else if (pnmMeaningfulBitCt > 4) bitsPerSample = 8; - else if (pnm_meaningful_bits > 2) + else if (pnmMeaningfulBitCt > 2) bitsPerSample = 4; - else if (pnm_meaningful_bits > 1) + else if (pnmMeaningfulBitCt > 1) bitsPerSample = 2; else bitsPerSample = 1; } if (alpha) { - if (pnm_type == PPM_TYPE) + if (colorPng) bitsPerPixel = 4 * bitsPerSample; else bitsPerPixel = 2 * bitsPerSample; } else { - if (pnm_type == PPM_TYPE) + if (colorPng) bitsPerPixel = 3 * bitsPerSample; else bitsPerPixel = bitsPerSample; @@ -1904,7 +1969,7 @@ computeColorMap(FILE * const ifP, int const cols, int const rows, xelval const maxval, - int const pnmType, + bool const colorPng, int const format, bool const force, FILE * const pfP, @@ -1947,6 +2012,8 @@ computeColorMap(FILE * const ifP, If the image is to have a background color, we return the palette index of that color as *backgroundIndexP. + + 'colorPng' means the PNG will be of the RGB variety. -------------------------------------------------------------------------- */ if (force) pm_asprintf(noColormapReasonP, "You requested no color map"); @@ -1956,7 +2023,7 @@ computeColorMap(FILE * const ifP, maxval, PALETTEMAXVAL); else { unsigned int bitsPerPixel; - computePixelWidth(pnmType, pnm_meaningful_bits, alpha, + computePixelWidth(colorPng, pnm_meaningful_bits, alpha, NULL, &bitsPerPixel); if (!pfP && bitsPerPixel == 1) @@ -2069,9 +2136,9 @@ static void computeColorMapLookupTable( static void computeRasterWidth(bool const colorMapped, - unsigned int const palette_size, - int const pnm_type, - unsigned int const pnm_meaningful_bits, + unsigned int const paletteSize, + bool const colorPng, + unsigned int const pnmMeaningfulBitCt, bool const alpha, unsigned int * const bitsPerSampleP, unsigned int * const bitsPerPixelP) { @@ -2082,24 +2149,24 @@ computeRasterWidth(bool const colorMapped, -----------------------------------------------------------------------------*/ if (colorMapped) { /* The raster element is a palette index */ - if (palette_size <= 2) + if (paletteSize <= 2) *bitsPerSampleP = 1; - else if (palette_size <= 4) + else if (paletteSize <= 4) *bitsPerSampleP = 2; - else if (palette_size <= 16) + else if (paletteSize <= 16) *bitsPerSampleP = 4; else *bitsPerSampleP = 8; *bitsPerPixelP = *bitsPerSampleP; if (verbose) - pm_message("Writing %d-bit color indexes", *bitsPerSampleP); + pm_message("Writing %u-bit color indexes", *bitsPerSampleP); } else { /* The raster element is an explicit pixel -- color and transparency */ - computePixelWidth(pnm_type, pnm_meaningful_bits, alpha, + computePixelWidth(colorPng, pnmMeaningfulBitCt, alpha, bitsPerSampleP, bitsPerPixelP); if (verbose) - pm_message("Writing %d bits per component per pixel", + pm_message("Writing %u bits per component per pixel", *bitsPerSampleP); } } @@ -2339,14 +2406,14 @@ doIhdrChunk(struct pngx * const pngxP, unsigned int const height, unsigned int const depth, bool const colorMapped, - int const pnmType, + bool const colorPng, bool const alpha) { int colorType; if (colorMapped) colorType = PNG_COLOR_TYPE_PALETTE; - else if (pnmType == PPM_TYPE) + else if (colorPng) colorType = PNG_COLOR_TYPE_RGB; else colorType = PNG_COLOR_TYPE_GRAY; @@ -2552,252 +2619,235 @@ convertpnm(struct cmdlineInfo const cmdline, lazy -- it takes a great deal of work to carry all that information as separate arguments -- and it's only a very small violation. -----------------------------------------------------------------------------*/ - xel p; - int rows, cols, format; - xelval maxval; - /* The maxval of the input image */ - xelval png_maxval; - /* The maxval of the samples in the PNG output - (must be 1, 3, 7, 15, 255, or 65535) - */ - pixel transcolor; - /* The color that is to be transparent, with maxval equal to that - of the input image. - */ - int transexact; - /* boolean: the user wants only the exact color he specified to be - transparent; not just something close to it. - */ - int transparent; - bool alpha; - /* There will be an alpha mask */ - unsigned int pnm_meaningful_bits; - pixel backcolor; - /* The background color, with maxval equal to that of the input - image. - */ - jmp_buf jmpbuf; - struct pngx * pngxP; - - bool colorMapped; - pixel palettePnm[MAXCOLORS]; - png_color palette[MAXCOLORS]; - /* The color part of the color/alpha palette passed to the PNG - compressor - */ - unsigned int paletteSize; - - gray transPnm[MAXCOLORS]; - png_byte trans[MAXCOLORS]; - /* The alpha part of the color/alpha palette passed to the PNG - compressor - */ - unsigned int transSize; - - colorhash_table cht; - coloralphahash_table caht; - - unsigned int background_index; - /* Index into palette[] of the background color. */ - - gray alphaMaxval; - const char * noColormapReason; - /* The reason that we shouldn't make a colormapped PNG, or NULL if - we should. malloc'ed null-terminated string. - */ - unsigned int depth; - /* The number of bits per sample in the (uncompressed) png - raster -- if the raster contains palette indices, this is the - number of bits in the index. - */ - unsigned int fulldepth; - /* The total number of bits per pixel in the (uncompressed) png - raster, including all channels. - */ - pm_filepos rasterPos; - /* file position in input image file of start of image (i.e. after - the header) - */ - xel *xelrow; /* malloc'ed */ - /* The row of the input image currently being processed */ - - int pnmType; - gray ** alpha_mask; - - /* We initialize these guys to quiet compiler warnings: */ - depth = 0; - - errorlevel = 0; - - if (setjmp(jmpbuf)) - pm_error ("setjmp returns error condition"); - - pngx_create(&pngxP, PNGX_WRITE, &jmpbuf); - - pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); - pm_tell2(ifP, &rasterPos, sizeof(rasterPos)); - pnmType = PNM_FORMAT_TYPE(format); - - xelrow = pnm_allocrow(cols); - - if (verbose) { - if (pnmType == PBM_TYPE) - pm_message ("reading a PBM file"); - else if (pnmType == PGM_TYPE) - pm_message ("reading a PGM file (maxval=%d)", maxval); - else if (pnmType == PPM_TYPE) - pm_message ("reading a PPM file (maxval=%d)", maxval); - } - - determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format, - afP, - &alpha, &transparent, &transcolor, &transexact, - &alpha_mask, &alphaMaxval); - - determineBackground(cmdline, maxval, &backcolor); - - /* first of all, check if we have a grayscale image written as PPM */ - - if (pnmType == PPM_TYPE && !cmdline.force) { - unsigned int row; - bool isgray; - - isgray = TRUE; /* initial assumption */ - pm_seek2(ifP, &rasterPos, sizeof(rasterPos)); - for (row = 0; row < rows && isgray; ++row) { - unsigned int col; - pnm_readpnmrow(ifP, xelrow, cols, maxval, format); - for (col = 0; col < cols && isgray; ++col) { - p = xelrow[col]; - if (PPM_GETR(p) != PPM_GETG(p) || PPM_GETG(p) != PPM_GETB(p)) - isgray = FALSE; - } - } - if (isgray) - pnmType = PGM_TYPE; - } - - /* handle `odd' maxvalues */ - - if (maxval > 65535 && !cmdline.downscale) { - pm_error("can only handle files up to 16-bit " - "(use -downscale to override"); - } - - findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha, - cmdline.force, &pnm_meaningful_bits); + int rows, cols, format; + xelval maxval; + /* The maxval of the input image */ + xelval pngMaxval; + /* The maxval of the samples in the PNG output + (must be 1, 3, 7, 15, 255, or 65535) + */ + pixel transcolor; + /* The color that is to be transparent, with maxval equal to that + of the input image. + */ + bool transExact; + /* boolean: the user wants only the exact color he specified to be + transparent; not just something close to it. + */ + int transparent; + bool alpha; + /* There will be an alpha mask */ + unsigned int pnmMeaningfulBitCt; + pixel backColor; + /* The background color, with maxval equal to that of the input + image. + */ + jmp_buf jmpbuf; + struct pngx * pngxP; + + bool colorMapped; + pixel palettePnm[MAXCOLORS]; + png_color palette[MAXCOLORS]; + /* The color part of the color/alpha palette passed to the PNG + compressor + */ + unsigned int paletteSize; + + gray transPnm[MAXCOLORS]; + png_byte trans[MAXCOLORS]; + /* The alpha part of the color/alpha palette passed to the PNG + compressor + */ + unsigned int transSize; + + colorhash_table cht; + coloralphahash_table caht; + + unsigned int backgroundIndex; + /* Index into palette[] of the background color. */ + + gray alphaMaxval; + const char * noColormapReason; + /* The reason that we shouldn't make a colormapped PNG, or NULL if + we should. malloc'ed null-terminated string. + */ + unsigned int depth; + /* The number of bits per sample in the (uncompressed) png + raster -- if the raster contains palette indices, this is the + number of bits in the index. + */ + unsigned int fulldepth; + /* The total number of bits per pixel in the (uncompressed) png + raster, including all channels. + */ + pm_filepos rasterPos; + /* file position in input image file of start of image (i.e. after + the header) + */ + xel * xelrow; /* malloc'ed */ + /* The row of the input image currently being processed */ + + gray ** alpha_mask; + + bool colorPng; + /* The PNG shall be of the color (RGB) variety */ + + /* We initialize these guys to quiet compiler warnings: */ + depth = 0; + + errorlevel = 0; + + if (setjmp(jmpbuf)) + pm_error ("setjmp returns error condition"); + + pngx_create(&pngxP, PNGX_WRITE, &jmpbuf); + + pnm_readpnminit(ifP, &cols, &rows, &maxval, &format); + pm_tell2(ifP, &rasterPos, sizeof(rasterPos)); + + xelrow = pnm_allocrow(cols); + + if (verbose) + reportInputType(format, maxval); + + determineTransparency(cmdline, ifP, rasterPos, cols, rows, maxval, format, + afP, + &alpha, &transparent, &transcolor, &transExact, + &alpha_mask, &alphaMaxval); + + determineBackground(cmdline, maxval, &backColor); + + if (cmdline.force) + colorPng = (PNM_FORMAT_TYPE(format) == PPM_TYPE); + else { + if (PNM_FORMAT_TYPE(format) == PPM_TYPE) { + colorPng = hasColor(ifP, cols, rows, maxval, format, rasterPos); + } else + colorPng = false; + } + + + /* handle `odd' maxvalues */ + + if (maxval > 65535 && !cmdline.downscale) { + pm_error("can only handle files up to 16-bit " + "(use -downscale to override"); + } + + findRedundantBits(ifP, rasterPos, cols, rows, maxval, format, alpha, + cmdline.force, &pnmMeaningfulBitCt); - computeColorMap(ifP, rasterPos, cols, rows, maxval, pnmType, format, - cmdline.force, pfP, - alpha, transparent >= 0, transcolor, transexact, - !!cmdline.background, backcolor, - alpha_mask, alphaMaxval, pnm_meaningful_bits, - palettePnm, &paletteSize, transPnm, &transSize, - &background_index, &noColormapReason); - - if (noColormapReason) { - if (pfP) - pm_error("You specified a particular palette, but this image " - "cannot be represented by any palette. %s", - noColormapReason); - if (verbose) - pm_message("Not using color map. %s", noColormapReason); - pm_strfree(noColormapReason); - colorMapped = FALSE; - } else - colorMapped = TRUE; + computeColorMap(ifP, rasterPos, cols, rows, maxval, colorPng, format, + cmdline.force, pfP, + alpha, transparent >= 0, transcolor, transExact, + !!cmdline.background, backColor, + alpha_mask, alphaMaxval, pnmMeaningfulBitCt, + palettePnm, &paletteSize, transPnm, &transSize, + &backgroundIndex, &noColormapReason); + + if (noColormapReason) { + if (pfP) + pm_error("You specified a particular palette, but this image " + "cannot be represented by any palette. %s", + noColormapReason); + if (verbose) + pm_message("Not using color map. %s", noColormapReason); + pm_strfree(noColormapReason); + colorMapped = FALSE; + } else + colorMapped = TRUE; - computeColorMapLookupTable(colorMapped, palettePnm, paletteSize, - transPnm, transSize, alpha, alphaMaxval, - &cht, &caht); + computeColorMapLookupTable(colorMapped, palettePnm, paletteSize, + transPnm, transSize, alpha, alphaMaxval, + &cht, &caht); - computeRasterWidth(colorMapped, paletteSize, pnmType, - pnm_meaningful_bits, alpha, - &depth, &fulldepth); - if (verbose) - pm_message ("writing a%s %d-bit %s%s file%s", - fulldepth == 8 ? "n" : "", fulldepth, - colorMapped ? "palette": - (pnmType == PPM_TYPE ? "RGB" : "gray"), - alpha ? (colorMapped ? "+transparency" : "+alpha") : "", - cmdline.interlace ? " (interlaced)" : ""); + computeRasterWidth(colorMapped, paletteSize, colorPng, + pnmMeaningfulBitCt, alpha, + &depth, &fulldepth); + if (verbose) + pm_message ("writing a%s %d-bit %s%s file%s", + fulldepth == 8 ? "n" : "", fulldepth, + colorMapped ? "palette": + colorPng ? "RGB" : "gray", + alpha ? (colorMapped ? "+transparency" : "+alpha") : "", + cmdline.interlace ? " (interlaced)" : ""); - /* now write the file */ + /* now write the file */ - png_maxval = pm_bitstomaxval(depth); + pngMaxval = pm_bitstomaxval(depth); - if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) { - pm_error ("setjmp returns error condition (2)"); - } + if (setjmp (pnmtopng_jmpbuf_struct.jmpbuf)) { + pm_error ("setjmp returns error condition (2)"); + } - doIhdrChunk(pngxP, cols, rows, depth, colorMapped, pnmType, alpha); + doIhdrChunk(pngxP, cols, rows, depth, colorMapped, colorPng, alpha); - if (cmdline.interlace) - pngx_setInterlaceHandling(pngxP); + if (cmdline.interlace) + pngx_setInterlaceHandling(pngxP); - doGamaChunk(cmdline, pngxP); + doGamaChunk(cmdline, pngxP); - doChrmChunk(cmdline, pngxP); + doChrmChunk(cmdline, pngxP); - doPhysChunk(cmdline, pngxP); + doPhysChunk(cmdline, pngxP); - if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { + if (pngx_colorType(pngxP) == PNG_COLOR_TYPE_PALETTE) { - /* creating PNG palette (Not counting the transparency palette) */ + /* creating PNG palette (Not counting the transparency palette) */ - createPngPalette(palettePnm, paletteSize, maxval, - transPnm, transSize, alphaMaxval, - palette, trans); - pngx_setPlte(pngxP, palette, paletteSize); + createPngPalette(palettePnm, paletteSize, maxval, + transPnm, transSize, alphaMaxval, + palette, trans); + pngx_setPlte(pngxP, palette, paletteSize); - doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos, - cols, rows, maxval, format, cmdline.verbose); - } + doHistChunk(pngxP, cmdline.hist, palettePnm, ifP, rasterPos, + cols, rows, maxval, format, cmdline.verbose); + } - doTrnsChunk(pngxP, trans, transSize, - transparent, transcolor, maxval, png_maxval); + doTrnsChunk(pngxP, trans, transSize, + transparent, transcolor, maxval, pngMaxval); - doBkgdChunk(pngxP, !!cmdline.background, - background_index, backcolor, - maxval, png_maxval, cmdline.verbose); + doBkgdChunk(pngxP, !!cmdline.background, + backgroundIndex, backColor, + maxval, pngMaxval, cmdline.verbose); - doSbitChunk(pngxP, png_maxval, maxval, alpha, alphaMaxval); + doSbitChunk(pngxP, pngMaxval, maxval, alpha, alphaMaxval); - /* tEXT and zTXT chunks */ - if (cmdline.text || cmdline.ztxt) - pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose); + /* tEXT and zTXT chunks */ + if (cmdline.text || cmdline.ztxt) + pngtxt_read(pngxP, tfP, !!cmdline.ztxt, cmdline.verbose); - doTimeChunk(cmdline, pngxP); + doTimeChunk(cmdline, pngxP); - if (cmdline.filterSet != 0) - pngx_setFilter(pngxP, cmdline.filterSet); + if (cmdline.filterSet != 0) + pngx_setFilter(pngxP, cmdline.filterSet); - setZlibCompression(pngxP, cmdline.zlibCompression); + setZlibCompression(pngxP, cmdline.zlibCompression); - png_init_io(pngxP->png_ptr, ofP); + png_init_io(pngxP->png_ptr, ofP); - /* write the png-info struct */ - pngx_writeInfo(pngxP); + /* write the png-info struct */ + pngx_writeInfo(pngxP); - /* let libpng take care of, e.g., bit-depth conversions */ - pngx_setPacking(pngxP); + /* let libpng take care of, e.g., bit-depth conversions */ + pngx_setPacking(pngxP); - writeRaster(pngxP, ifP, rasterPos, - cols, rows, maxval, format, - png_maxval, depth, alpha, alpha_mask, cht, caht); + writeRaster(pngxP, ifP, rasterPos, + cols, rows, maxval, format, + pngMaxval, depth, alpha, alpha_mask, cht, caht); - pngx_writeEnd(pngxP); + pngx_writeEnd(pngxP); - pngx_destroy(pngxP); + pngx_destroy(pngxP); - pnm_freerow(xelrow); + pnm_freerow(xelrow); - if (cht) - ppm_freecolorhash(cht); - if (caht) - freecoloralphahash(caht); + if (cht) + ppm_freecolorhash(cht); + if (caht) + freecoloralphahash(caht); - *errorLevelP = errorlevel; + *errorLevelP = errorlevel; } diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index dc55a7e3..1cf23be7 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -335,6 +335,22 @@ basebasename(const char * const filespec) { +static void +writeFile(const unsigned char * const buffer, + size_t const writeCt, + const char * const name, + FILE * const ofP) { + + size_t writtenCt; + + writtenCt = fwrite(buffer, 1, writeCt, ofP); + + if (writtenCt != writeCt) + pm_error("Error writing to %s output file", name); +} + + + #define MAX_FILTER_CT 10 /* The maximum number of filters this code is capable of applying */ @@ -494,18 +510,12 @@ flateFilter(FILE * const ifP, */ do { unsigned int have; - size_t bytesWritten; strm.avail_out = chunkSz; strm.next_out = out; deflate(&strm, flush); have = chunkSz - strm.avail_out; - bytesWritten = fwrite(out, 1, have, ofP); - if (ferror(ofP) || bytesWritten != have) { - deflateEnd(&strm); - pm_error("Error writing to internal pipe during " - "flate compression."); - } + writeFile(out, have, "flate filter", ofP); } while (strm.avail_out == 0); assert(strm.avail_in == 0); /* all input is used */ @@ -548,10 +558,8 @@ rlePutBuffer (unsigned int const repeat, if (repeat) { fputc(257 - count, fP); fputc(repeatitem, fP); - } else { - fputc(count - 1, fP); - fwrite(itembuf, 1, count, fP); - } + } else + writeFile(itembuf, count, "rlePutBuffer", fP); } @@ -673,23 +681,24 @@ asciiHexFilter(FILE * const ifP, unsigned char inbuff[40], outbuff[81]; for (eof = false; !eof; ) { - size_t bytesRead; + size_t readCt; - bytesRead = fread(inbuff, 1, 40, ifP); + readCt = fread(inbuff, 1, 40, ifP); - if (bytesRead == 0) + if (readCt == 0) eof = true; else { unsigned int i; - for (i = 0; i < bytesRead; ++i) { + for (i = 0; i < readCt; ++i) { int const item = inbuff[i]; outbuff[i*2] = hexits[item >> 4]; outbuff[i*2+1] = hexits[item & 15]; } } - outbuff[bytesRead * 2] = '\n'; - fwrite(outbuff, 1, bytesRead*2 + 1, ofP); + outbuff[readCt * 2] = '\n'; + + writeFile(outbuff, readCt * 2 + 1, "asciiHex filter", ofP); } fclose(ifP); @@ -737,7 +746,9 @@ ascii85Filter(FILE * const ifP, outbuff[1] = value % 85 + 33; outbuff[0] = value / 85 + 33; - fwrite(outbuff, 1, count + 1, ofP); + writeFile((const unsigned char *)outbuff, count + 1, + "ASCII 85 filter", ofP); + count = value = 0; outcount += 5; } @@ -759,7 +770,8 @@ ascii85Filter(FILE * const ifP, outbuff[0] = value / 85 + 33; outbuff[count + 1] = '\n'; - fwrite(outbuff, 1, count + 2, ofP); + writeFile((const unsigned char *)outbuff, count + 2, + "ASCII 85 filter", ofP); } fclose(ifP); @@ -869,13 +881,22 @@ addFilter(const char * const description, OutputEncoder * const oeP, FILE ** const feedFilePP, pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Add a filter to the front of the chain. - pid_t pid; + Spawn a process to do the filtering, by running function 'filter'. + *feedFilePP is the present head of the chain. We make the new filter + process write its output to that and get its input from a new pipe. + We update *feedFilePP to the sending end of the new pipe. + + Add to the list pidList[] the PID of the process we spawn. +-----------------------------------------------------------------------------*/ FILE * const oldFeedFileP = *feedFilePP; FILE * newFeedFileP; - + pid_t pid; + spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid); if (verbose) @@ -883,7 +904,7 @@ addFilter(const char * const description, description, (unsigned)pid); fclose(oldFeedFileP); /* Child keeps this open now */ - + addToPidList(pidList, pid); *feedFilePP = newFeedFileP; @@ -1720,7 +1741,7 @@ convertRowPbm(struct pam * const pamP, bitrow[colChars-1] <<= padRight; /* right edge */ } - fwrite(bitrow, 1, colChars, fP); + writeFile(bitrow, colChars, "PBM reader", fP); } @@ -1863,6 +1884,21 @@ convertRaster(struct pam * const inpamP, +/* FILE MANAGEMENT: File management is pretty hairy here. A filter, which + runs in its own process, needs to be able to cause its output file to + close because it might be an internal pipe and the next stage needs to + know output is done. So the forking process must close its copy of the + file descriptor. BUT: if the output of the filter is not an internal + pipe but this program's output, then we don't want it closed when the + filter terminates because we'll need it to be open for the next image + the program converts (with a whole new chain of filters). + + To prevent the progam output file from getting closed, we pass a + duplicate of it to spawnFilters() and keep the original open. +*/ + + + static void convertPage(FILE * const ifP, int const turnflag, diff --git a/converter/other/pstopnm.c b/converter/other/pstopnm.c index 1dd27140..3704841b 100644 --- a/converter/other/pstopnm.c +++ b/converter/other/pstopnm.c @@ -18,6 +18,7 @@ #define _XOPEN_SOURCE 500 /* Make sure fdopen() is in stdio.h and strdup() is in string.h */ +#include <assert.h> #include <string.h> #include <unistd.h> #include <stdlib.h> @@ -32,8 +33,8 @@ #include "shhopt.h" #include "nstring.h" -enum orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED}; -struct box { +enum Orientation {PORTRAIT, LANDSCAPE, UNSPECIFIED}; +struct Box { /* Description of a rectangle within an image; all coordinates measured in points (1/72") with lower left corner of page being the origin. @@ -45,15 +46,15 @@ struct box { int ury; /* upper right Y coord */ }; -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ const char * inputFileName; /* Names of input files */ unsigned int forceplain; - struct box extract_box; + struct Box extractBox; unsigned int nocrop; - unsigned int format_type; + unsigned int formatType; unsigned int verbose; float xborder; unsigned int xmax; @@ -62,15 +63,15 @@ struct cmdlineInfo { unsigned int ymax; unsigned int ysize; /* zero means unspecified */ unsigned int dpi; /* zero means unspecified */ - enum orientation orientation; - unsigned int goto_stdout; + enum Orientation orientation; + unsigned int stdout; unsigned int textalphabits; }; static void parseCommandLine(int argc, char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that the file spec array we return is stored in the storage that was passed to us as the argv array. @@ -82,8 +83,8 @@ parseCommandLine(int argc, char ** argv, unsigned int option_def_index; - unsigned int pbm_opt, pgm_opt, ppm_opt; - unsigned int portrait_opt, landscape_opt; + unsigned int pbmOpt, pgmOpt, ppmOpt; + unsigned int portraitOpt, landscapeOpt; float llx, lly, urx, ury; unsigned int llxSpec, llySpec, urxSpec, urySpec; unsigned int xmaxSpec, ymaxSpec, xsizeSpec, ysizeSpec, dpiSpec; @@ -98,9 +99,9 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "urx", OPT_FLOAT, &urx, &urxSpec, 0); OPTENT3(0, "ury", OPT_FLOAT, &ury, &urySpec, 0); OPTENT3(0, "nocrop", OPT_FLAG, NULL, &cmdlineP->nocrop, 0); - OPTENT3(0, "pbm", OPT_FLAG, NULL, &pbm_opt, 0); - OPTENT3(0, "pgm", OPT_FLAG, NULL, &pgm_opt, 0); - OPTENT3(0, "ppm", OPT_FLAG, NULL, &ppm_opt, 0); + OPTENT3(0, "pbm", OPT_FLAG, NULL, &pbmOpt , 0); + OPTENT3(0, "pgm", OPT_FLAG, NULL, &pgmOpt, 0); + OPTENT3(0, "ppm", OPT_FLAG, NULL, &ppmOpt, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "xborder", OPT_FLOAT, &cmdlineP->xborder, NULL, 0); OPTENT3(0, "xmax", OPT_UINT, &cmdlineP->xmax, &xmaxSpec, 0); @@ -109,9 +110,9 @@ parseCommandLine(int argc, char ** argv, OPTENT3(0, "ymax", OPT_UINT, &cmdlineP->ymax, &ymaxSpec, 0); OPTENT3(0, "ysize", OPT_UINT, &cmdlineP->ysize, &ysizeSpec, 0); OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi, &dpiSpec, 0); - OPTENT3(0, "portrait", OPT_FLAG, NULL, &portrait_opt, 0); - OPTENT3(0, "landscape", OPT_FLAG, NULL, &landscape_opt, 0); - OPTENT3(0, "stdout", OPT_FLAG, NULL, &cmdlineP->goto_stdout, 0); + OPTENT3(0, "portrait", OPT_FLAG, NULL, &portraitOpt, 0); + OPTENT3(0, "landscape", OPT_FLAG, NULL, &landscapeOpt, 0); + OPTENT3(0, "stdout", OPT_FLAG, NULL, &cmdlineP->stdout, 0); OPTENT3(0, "textalphabits", OPT_UINT, &cmdlineP->textalphabits, &textalphabitsSpec, 0); @@ -149,38 +150,38 @@ parseCommandLine(int argc, char ** argv, } else cmdlineP->ysize = 0; - if (portrait_opt && !landscape_opt) + if (portraitOpt && !landscapeOpt) cmdlineP->orientation = PORTRAIT; - else if (!portrait_opt && landscape_opt) + else if (!portraitOpt && landscapeOpt) cmdlineP->orientation = LANDSCAPE; - else if (!portrait_opt && !landscape_opt) + else if (!portraitOpt && !landscapeOpt) cmdlineP->orientation = UNSPECIFIED; else pm_error("Cannot specify both -portrait and -landscape options"); - if (pbm_opt) - cmdlineP->format_type = PBM_TYPE; - else if (pgm_opt) - cmdlineP->format_type = PGM_TYPE; - else if (ppm_opt) - cmdlineP->format_type = PPM_TYPE; + if (pbmOpt) + cmdlineP->formatType = PBM_TYPE; + else if (pgmOpt) + cmdlineP->formatType = PGM_TYPE; + else if (ppmOpt) + cmdlineP->formatType = PPM_TYPE; else - cmdlineP->format_type = PPM_TYPE; + cmdlineP->formatType = PPM_TYPE; /* If any one of the 4 bounding box coordinates is given on the command line, we default any of the 4 that aren't. */ if (llxSpec || llySpec || urxSpec || urySpec) { - if (!llxSpec) cmdlineP->extract_box.llx = 72; - else cmdlineP->extract_box.llx = llx * 72; - if (!llySpec) cmdlineP->extract_box.lly = 72; - else cmdlineP->extract_box.lly = lly * 72; - if (!urxSpec) cmdlineP->extract_box.urx = 540; - else cmdlineP->extract_box.urx = urx * 72; - if (!urySpec) cmdlineP->extract_box.ury = 720; - else cmdlineP->extract_box.ury = ury * 72; + if (!llxSpec) cmdlineP->extractBox.llx = 72; + else cmdlineP->extractBox.llx = llx * 72; + if (!llySpec) cmdlineP->extractBox.lly = 72; + else cmdlineP->extractBox.lly = lly * 72; + if (!urxSpec) cmdlineP->extractBox.urx = 540; + else cmdlineP->extractBox.urx = urx * 72; + if (!urySpec) cmdlineP->extractBox.ury = 720; + else cmdlineP->extractBox.ury = ury * 72; } else { - cmdlineP->extract_box.llx = -1; + cmdlineP->extractBox.llx = -1; } if (dpiSpec) { @@ -230,19 +231,19 @@ addPsToFileName(char const origFileName[], *newFileNameP. -----------------------------------------------------------------------------*/ struct stat statbuf; - int stat_rc; + int statRc; - stat_rc = lstat(origFileName, &statbuf); + statRc = lstat(origFileName, &statbuf); - if (stat_rc == 0) + if (statRc == 0) *newFileNameP = strdup(origFileName); else { const char * fileNamePlusPs; pm_asprintf(&fileNamePlusPs, "%s.ps", origFileName); - stat_rc = lstat(fileNamePlusPs, &statbuf); - if (stat_rc == 0) + statRc = lstat(fileNamePlusPs, &statbuf); + if (statRc == 0) *newFileNameP = strdup(fileNamePlusPs); else *newFileNameP = strdup(origFileName); @@ -311,9 +312,9 @@ computeSizeResBlind(unsigned int const xmax, static void -computeSizeRes(struct cmdlineInfo const cmdline, - enum orientation const orientation, - struct box const bordered_box, +computeSizeRes(struct CmdlineInfo const cmdline, + enum Orientation const orientation, + struct Box const borderedBox, unsigned int * const xsizeP, unsigned int * const ysizeP, unsigned int * const xresP, @@ -344,11 +345,11 @@ computeSizeRes(struct cmdlineInfo const cmdline, */ if (orientation == LANDSCAPE) { - sx = bordered_box.ury - bordered_box.lly; - sy = bordered_box.urx - bordered_box.llx; + sx = borderedBox.ury - borderedBox.lly; + sy = borderedBox.urx - borderedBox.llx; } else { - sx = bordered_box.urx - bordered_box.llx; - sy = bordered_box.ury - bordered_box.lly; + sx = borderedBox.urx - borderedBox.llx; + sy = borderedBox.ury - borderedBox.lly; } if (cmdline.dpi) { @@ -373,9 +374,9 @@ computeSizeRes(struct cmdlineInfo const cmdline, -enum postscript_language {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT}; +enum PostscriptLanguage {COMMON_POSTSCRIPT, ENCAPSULATED_POSTSCRIPT}; -static enum postscript_language +static enum PostscriptLanguage languageDeclaration(char const inputFileName[], bool const verbose) { /*---------------------------------------------------------------------------- @@ -383,7 +384,7 @@ languageDeclaration(char const inputFileName[], (Except that if the file is on Standard Input or doesn't validly declare a languages, just say it is Common Postscript). -----------------------------------------------------------------------------*/ - enum postscript_language language; + enum PostscriptLanguage language; if (streq(inputFileName, "-")) /* Can't read stdin, because we need it to remain positioned for the @@ -399,9 +400,9 @@ languageDeclaration(char const inputFileName[], if (fgets(line, sizeof(line), infile) == NULL) language = COMMON_POSTSCRIPT; else { - const char eps_header[] = " EPSF-"; + const char epsHeader[] = " EPSF-"; - if (strstr(line, eps_header)) + if (strstr(line, epsHeader)) language = ENCAPSULATED_POSTSCRIPT; else language = COMMON_POSTSCRIPT; @@ -418,61 +419,64 @@ languageDeclaration(char const inputFileName[], -static struct box -computeBoxToExtract(struct box const cmdline_extract_box, +static struct Box +computeBoxToExtract(struct Box const cmdlineExtractBox, char const inputFileName[], bool const verbose) { - struct box retval; + struct Box retval; - if (cmdline_extract_box.llx != -1) + if (cmdlineExtractBox.llx != -1) /* User told us what box to extract, so that's what we'll do */ - retval = cmdline_extract_box; + retval = cmdlineExtractBox; else { /* Try to get the bounding box from the DSC %%BoundingBox statement (A Postscript comment) in the input. */ - struct box ps_bb; /* Box described by %%BoundingBox stmt in input */ + struct Box psBb; /* Box described by %%BoundingBox stmt in input */ if (streq(inputFileName, "-")) /* Can't read stdin, because we need it to remain positioned for the Ghostscript interpreter to read it. */ - ps_bb.llx = -1; + psBb.llx = -1; else { - FILE *infile; - int found_BB, eof; /* logical */ - infile = pm_openr(inputFileName); + FILE * ifP; + bool foundBb; + bool eof; + + ifP = pm_openr(inputFileName); - found_BB = FALSE; - eof = FALSE; - while (!eof && !found_BB) { + for (foundBb = FALSE, eof = FALSE; !foundBb && !eof; ) { char line[200]; - - if (fgets(line, sizeof(line), infile) == NULL) + char * fgetsRc; + + fgetsRc = fgets(line, sizeof(line), ifP); + + if (fgetsRc == NULL) eof = TRUE; else { int rc; rc = sscanf(line, "%%%%BoundingBox: %d %d %d %d", - &ps_bb.llx, &ps_bb.lly, - &ps_bb.urx, &ps_bb.ury); + &psBb.llx, &psBb.lly, + &psBb.urx, &psBb.ury); if (rc == 4) - found_BB = TRUE; + foundBb = TRUE; } } - fclose(infile); + fclose(ifP); - if (!found_BB) { - ps_bb.llx = -1; + if (!foundBb) { + psBb.llx = -1; pm_message("Warning: no %%%%BoundingBox statement " - "in the input or command line.\n" + "in the input or command line. " "Will use defaults"); } } - if (ps_bb.llx != -1) { + if (psBb.llx != -1) { if (verbose) pm_message("Using %%%%BoundingBox statement from input."); - retval = ps_bb; + retval = psBb; } else { /* Use the center of an 8.5" x 11" page with 1" border all around*/ retval.llx = 72; @@ -489,13 +493,14 @@ computeBoxToExtract(struct box const cmdline_extract_box, -static enum orientation -computeOrientation(struct cmdlineInfo const cmdline, - struct box const extract_box) { +static enum Orientation +computeOrientation(struct CmdlineInfo const cmdline, + struct Box const extractBox) { - enum orientation retval; - unsigned int const input_width = extract_box.urx - extract_box.llx; - unsigned int const input_height = extract_box.ury - extract_box.lly; + unsigned int const inputWidth = extractBox.urx - extractBox.llx; + unsigned int const inputHeight = extractBox.ury - extractBox.lly; + + enum Orientation retval; if (cmdline.orientation != UNSPECIFIED) retval = cmdline.orientation; @@ -506,24 +511,24 @@ computeOrientation(struct cmdlineInfo const cmdline, so we can't use output dimensions to make the decision. So just use the input dimensions. */ - if (input_height > input_width) retval = PORTRAIT; + if (inputHeight > inputWidth) retval = PORTRAIT; else retval = LANDSCAPE; } else { - int output_width, output_height; + unsigned int outputWidth, outputHeight; if (cmdline.xsize) { /* He gave xsize and ysize, so that's the output size */ - output_width = cmdline.xsize; - output_height = cmdline.ysize; + outputWidth = cmdline.xsize; + outputHeight = cmdline.ysize; } else { /* Well then we'll just use his (or default) xmax, ymax */ - output_width = cmdline.xmax; - output_height = cmdline.ymax; + outputWidth = cmdline.xmax; + outputHeight = cmdline.ymax; } - if (input_height > input_width && output_height > output_width) + if (inputHeight > inputWidth && outputHeight > outputWidth) retval = PORTRAIT; - else if (input_height < input_width && - output_height < output_width) + else if (inputHeight < inputWidth && + outputHeight < outputWidth) retval = PORTRAIT; else retval = LANDSCAPE; @@ -534,32 +539,39 @@ computeOrientation(struct cmdlineInfo const cmdline, -static struct box -addBorders(struct box const input_box, - float const xborder_scale, - float const yborder_scale, +static struct Box +addBorders(struct Box const inputBox, + float const xborderScale, + float const yborderScale, bool const verbose) { /*---------------------------------------------------------------------------- - Return a box which is 'input_box' plus some borders. + Return a box which is 'inputBox' plus some borders. - Add left and right borders that are the fraction 'xborder_scale' of the + Add left and right borders that are the fraction 'xborderScale' of the width of the input box; likewise for top and bottom borders with - 'yborder_scale'. + 'yborderScale'. -----------------------------------------------------------------------------*/ - struct box retval; + unsigned int const leftRightBorderSize = + ROUNDU((inputBox.urx - inputBox.llx) * xborderScale); + unsigned int const topBottomBorderSize = + ROUNDU((inputBox.ury - inputBox.lly) * yborderScale); + + struct Box retval; + - const int left_right_border_size = - (int) ((input_box.urx - input_box.llx) * xborder_scale + 0.5); - const int top_bottom_border_size = - (int) ((input_box.ury - input_box.lly) * yborder_scale + 0.5); + assert(inputBox.urx >= inputBox.llx); + assert(inputBox.ury >= inputBox.lly); - retval.llx = input_box.llx - left_right_border_size; - retval.lly = input_box.lly - top_bottom_border_size; - retval.urx = input_box.urx + left_right_border_size; - retval.ury = input_box.ury + top_bottom_border_size; + assert(inputBox.llx >= leftRightBorderSize); + assert(inputBox.lly >= topBottomBorderSize); + + retval.llx = inputBox.llx - leftRightBorderSize; + retval.lly = inputBox.lly - topBottomBorderSize; + retval.urx = inputBox.urx + leftRightBorderSize; + retval.ury = inputBox.ury + topBottomBorderSize; if (verbose) - pm_message("With borders, extracted box is ((%d,%d),(%d,%d))", + pm_message("With borders, extracted box is ((%u,%u),(%u,%u))", retval.llx, retval.lly, retval.urx, retval.ury); return retval; @@ -568,8 +580,8 @@ addBorders(struct box const input_box, static const char * -computePstrans(struct box const box, - enum orientation const orientation, +computePstrans(struct Box const box, + enum Orientation const orientation, int const xsize, int const ysize, int const xres, @@ -598,11 +610,20 @@ computePstrans(struct box const box, static const char * -computeOutfileArg(struct cmdlineInfo const cmdline) { - +computeOutfileArg(struct CmdlineInfo const cmdline) { +/*---------------------------------------------------------------------------- + Determine the value for the "OutputFile" variable to pass to Ghostscript, + which is what tells Ghostscript where to put its output. This is either + a pattern such as "foo%03d.ppm" or "-" to indicate Standard Output. + + We go with "-" if, according to 'cmdline', the user asked for + Standard Output or is giving his input on Standard Input. Otherwise, + we go with the pattern, based on the name of the input file and output + format type the user requested. +-----------------------------------------------------------------------------*/ const char * retval; /* malloc'ed */ - if (cmdline.goto_stdout) + if (cmdline.stdout) retval = strdup("-"); else if (streq(cmdline.inputFileName, "-")) retval = strdup("-"); @@ -616,12 +637,12 @@ computeOutfileArg(struct cmdlineInfo const cmdline) { /* The input file name ends in ".ps". Chop it off. */ basename[strlen(basename)-3] = '\0'; - switch (cmdline.format_type) { + switch (cmdline.formatType) { case PBM_TYPE: suffix = "pbm"; break; case PGM_TYPE: suffix = "pgm"; break; case PPM_TYPE: suffix = "ppm"; break; - default: pm_error("Internal error: invalid value for format_type: %d", - cmdline.format_type); + default: pm_error("Internal error: invalid value for formatType: %d", + cmdline.formatType); } pm_asprintf(&retval, "%s%%03d.%s", basename, suffix); @@ -633,17 +654,17 @@ computeOutfileArg(struct cmdlineInfo const cmdline) { static const char * -computeGsDevice(int const format_type, +computeGsDevice(int const formatType, bool const forceplain) { const char * basetype; const char * retval; - switch (format_type) { + switch (formatType) { case PBM_TYPE: basetype = "pbm"; break; case PGM_TYPE: basetype = "pgm"; break; case PPM_TYPE: basetype = "ppm"; break; - default: pm_error("Internal error: invalid value format_type"); + default: pm_error("Internal error: invalid value formatType"); } if (forceplain) retval = strdup(basetype); @@ -703,14 +724,13 @@ findGhostscriptProg(const char ** const retvalP) { static void execGhostscript(int const inputPipeFd, - char const ghostscript_device[], - char const outfile_arg[], + char const ghostscriptDevice[], + char const outfileArg[], int const xsize, int const ysize, int const xres, int const yres, unsigned int const textalphabits, - char const inputFileName[], bool const verbose) { const char * arg0; @@ -729,8 +749,8 @@ execGhostscript(int const inputPipeFd, close(inputPipeFd); pm_asprintf(&arg0, "gs"); - pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscript_device); - pm_asprintf(&outfileopt, "-sOutputFile=%s", outfile_arg); + pm_asprintf(&deviceopt, "-sDEVICE=%s", ghostscriptDevice); + pm_asprintf(&outfileopt, "-sOutputFile=%s", outfileArg); pm_asprintf(&gopt, "-g%dx%d", xsize, ysize); pm_asprintf(&ropt, "-r%dx%d", xres, yres); pm_asprintf(&textalphabitsopt, "-dTextAlphaBits=%u", textalphabits); @@ -760,26 +780,26 @@ execGhostscript(int const inputPipeFd, static void -executeGhostscript(char const pstrans[], - char const ghostscript_device[], - char const outfile_arg[], - int const xsize, - int const ysize, - int const xres, - int const yres, - unsigned int const textalphabits, - char const inputFileName[], - enum postscript_language const language, - bool const verbose) { - - int gs_exit; /* wait4 exit code from Ghostscript */ - FILE *gs; /* Pipe to Ghostscript's standard input */ - FILE *infile; +executeGhostscript(char const pstrans[], + char const ghostscriptDevice[], + char const outfileArg[], + int const xsize, + int const ysize, + int const xres, + int const yres, + unsigned int const textalphabits, + char const inputFileName[], + enum PostscriptLanguage const language, + bool const verbose) { + + int gsTermStatus; /* termination status of Ghostscript process */ + FILE * pipeToGsP; /* Pipe to Ghostscript's standard input */ + FILE * ifP; int rc; int eof; /* End of file on input */ int pipefd[2]; - if (strlen(outfile_arg) > 80) + if (strlen(outfileArg) > 80) pm_error("output file spec too long."); rc = pm_pipe(pipefd); @@ -794,20 +814,20 @@ executeGhostscript(char const pstrans[], else if (rc == 0) { /* Child process */ close(pipefd[1]); - execGhostscript(pipefd[0], ghostscript_device, outfile_arg, + execGhostscript(pipefd[0], ghostscriptDevice, outfileArg, xsize, ysize, xres, yres, textalphabits, - inputFileName, verbose); + verbose); } else { pid_t const ghostscriptPid = rc; int const pipeToGhostscriptFd = pipefd[1]; /* parent process */ close(pipefd[0]); - gs = fdopen(pipeToGhostscriptFd, "w"); - if (gs == NULL) + pipeToGsP = fdopen(pipeToGhostscriptFd, "w"); + if (pipeToGsP == NULL) pm_error("Unable to open stream on pipe to Ghostscript process."); - infile = pm_openr(inputFileName); + ifP = pm_openr(inputFileName); /* In encapsulated Postscript, we the encapsulator are supposed to handle showing the page (which we do by passing a showpage @@ -822,12 +842,12 @@ executeGhostscript(char const pstrans[], here, I think, so I boiled it down a bit. JM */ if (language == ENCAPSULATED_POSTSCRIPT) - fprintf(gs, "\n/b4_Inc_state save def /showpage { } def\n"); + fprintf(pipeToGsP, "\n/b4_Inc_state save def /showpage { } def\n"); if (verbose) pm_message("Postscript prefix command: '%s'", pstrans); - fprintf(gs, "%s\n", pstrans); + fprintf(pipeToGsP, "%s\n", pstrans); /* If our child dies, it closes the pipe and when we next write to it, we get a SIGPIPE. We must survive that signal in order to report @@ -840,34 +860,34 @@ executeGhostscript(char const pstrans[], char buffer[4096]; int bytes_read; - bytes_read = fread(buffer, 1, sizeof(buffer), infile); + bytes_read = fread(buffer, 1, sizeof(buffer), ifP); if (bytes_read == 0) eof = TRUE; else - fwrite(buffer, 1, bytes_read, gs); + fwrite(buffer, 1, bytes_read, pipeToGsP); } - pm_close(infile); + pm_close(ifP); if (language == ENCAPSULATED_POSTSCRIPT) - fprintf(gs, "\nb4_Inc_state restore showpage\n"); + fprintf(pipeToGsP, "\nb4_Inc_state restore showpage\n"); - fclose(gs); + fclose(pipeToGsP); - waitpid(ghostscriptPid, &gs_exit, 0); + waitpid(ghostscriptPid, &gsTermStatus, 0); if (rc < 0) pm_error("Wait for Ghostscript process to terminated failed. " "errno = %d (%s)", errno, strerror(errno)); - if (gs_exit != 0) { - if (WIFEXITED(gs_exit)) + if (gsTermStatus != 0) { + if (WIFEXITED(gsTermStatus)) pm_error("Ghostscript failed. Exit code=%d\n", - WEXITSTATUS(gs_exit)); - else if (WIFSIGNALED(gs_exit)) + WEXITSTATUS(gsTermStatus)); + else if (WIFSIGNALED(gsTermStatus)) pm_error("Ghostscript process died due to a signal %d.", - WTERMSIG(gs_exit)); + WTERMSIG(gsTermStatus)); else pm_error("Ghostscript process died with exit code %d", - gs_exit); + gsTermStatus); } } } @@ -877,22 +897,22 @@ executeGhostscript(char const pstrans[], int main(int argc, char ** argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; const char * inputFileName; /* malloc'ed */ /* The file specification of our Postscript input file */ unsigned int xres, yres; /* Resolution in pixels per inch */ unsigned int xsize, ysize; /* output image size in pixels */ - struct box extract_box; + struct Box extractBox; /* coordinates of the box within the input we are to extract; i.e. that will become the output. */ - struct box bordered_box; + struct Box borderedBox; /* Same as above, but expanded to include borders */ - enum postscript_language language; - enum orientation orientation; - const char * ghostscript_device; - const char * outfile_arg; + enum PostscriptLanguage language; + enum Orientation orientation; + const char * ghostscriptDevice; + const char * outfileArg; const char * pstrans; pnm_init(&argc, argv); @@ -901,36 +921,36 @@ main(int argc, char ** argv) { addPsToFileName(cmdline.inputFileName, &inputFileName, cmdline.verbose); - extract_box = computeBoxToExtract(cmdline.extract_box, inputFileName, + extractBox = computeBoxToExtract(cmdline.extractBox, inputFileName, cmdline.verbose); language = languageDeclaration(inputFileName, cmdline.verbose); - orientation = computeOrientation(cmdline, extract_box); + orientation = computeOrientation(cmdline, extractBox); - bordered_box = addBorders(extract_box, cmdline.xborder, cmdline.yborder, - cmdline.verbose); + borderedBox = addBorders(extractBox, cmdline.xborder, cmdline.yborder, + cmdline.verbose); - computeSizeRes(cmdline, orientation, bordered_box, + computeSizeRes(cmdline, orientation, borderedBox, &xsize, &ysize, &xres, &yres); - pstrans = computePstrans(bordered_box, orientation, + pstrans = computePstrans(borderedBox, orientation, xsize, ysize, xres, yres); - outfile_arg = computeOutfileArg(cmdline); + outfileArg = computeOutfileArg(cmdline); - ghostscript_device = - computeGsDevice(cmdline.format_type, cmdline.forceplain); + ghostscriptDevice = + computeGsDevice(cmdline.formatType, cmdline.forceplain); - pm_message("Writing %s file", ghostscript_device); + pm_message("Writing %s format", ghostscriptDevice); - executeGhostscript(pstrans, ghostscript_device, outfile_arg, + executeGhostscript(pstrans, ghostscriptDevice, outfileArg, xsize, ysize, xres, yres, cmdline.textalphabits, inputFileName, language, cmdline.verbose); - pm_strfree(ghostscript_device); - pm_strfree(outfile_arg); + pm_strfree(ghostscriptDevice); + pm_strfree(outfileArg); pm_strfree(pstrans); return 0; diff --git a/converter/other/winicon.h b/converter/other/winicon.h new file mode 100644 index 00000000..9ede01f5 --- /dev/null +++ b/converter/other/winicon.h @@ -0,0 +1,82 @@ +#include "pm_c_util.h" + +#define ICONDIR_TYPE_ICO (1) + +/* windows icon structures */ +struct IconDirEntry { + uint16_t width; /* image width in pixels 0 == 256 */ + uint16_t height; /* image height in pixels 0 == 256 */ + uint8_t color_count; /* 0 if bits_per_pixel >= 8 */ + uint8_t zero; /* 0 */ + uint16_t color_planes; /* 1 */ + uint16_t bits_per_pixel; /* allowed values: 1, 4, 8, 16 or 32 (1) */ + uint32_t size; /* size of image */ + uint32_t offset; /* file offset of image */ + + uint16_t index; /* extra field (not in file) */ +}; + +/* (1) This is from + * http://blogs.msdn.com/b/oldnewthing/archive/2010/10/19/10077610.aspx. + * + * However, the bpp value in the icon directory is used as a hint for + * image selection only. It seems to be legal to set this value to + * zero, and e.g. in SHELL32.DLL of Win98SE, there are many 8bpp + * images described as 24 bit images in the icon directory. + * + * The bpp value of image 1 in icon 150 in SHELL32.DLL of WinXP is 24 + * (in header and BMP). This may be a bug, as the 32 x 32 x 8 image + * is missing, but it shows the Windows icon rendering engine is able + * to cope with 24 bit images). + * + * 16bpp icons are at least rare in the wild. + */ +struct IconDir { + uint16_t zero; /* 0 */ + uint16_t type; /* 1 */ + uint16_t count; /* number of images in icon */ + + unsigned int entriesAllocCt; /* # of allocated slots in 'entries'*/ + struct IconDirEntry * entries; /* one entry for each image */ +}; + +/* BMP image structures */ + +struct BitmapInfoHeader { + uint32_t header_size; /* >= 40 */ + int32_t bm_width; + int32_t bm_height; + uint16_t color_planes; + uint16_t bits_per_pixel; + uint32_t compression_method; + uint32_t image_size; + int32_t horizontal_resolution; /* pixels per meter (!) */ + int32_t vertical_resolution; /* pixels per meter (!) */ + uint32_t colors_in_palette; + uint32_t important_colors; + + bool top_down; /* extra field (not in file) */ + +}; + +typedef enum { + BI_RGB = 0, + BI_BITFIELDS = 3 + +} BiCompression; + +/* PNG image structures */ +#define PNG_HEADER { 0x89, 'P', 'N', 'G', '\r', '\n', 0x1A /* ^Z */, '\n' } + +struct PngIhdr { + uint32_t length; /* 13 */ + uint32_t signature; /* "IHDR" */ + uint32_t width; /* image width in pixels */ + uint32_t height; /* image height in pixels */ + uint8_t bit_depth; /* depth per channel */ + uint8_t color_type; /* recognized values: 0, 2, 3, 4 and 6 */ + uint8_t compression; + uint8_t filter; + uint8_t interlace; + uint32_t crc; +}; diff --git a/converter/other/winicontopam.c b/converter/other/winicontopam.c new file mode 100644 index 00000000..9bee8b3c --- /dev/null +++ b/converter/other/winicontopam.c @@ -0,0 +1,1282 @@ +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include "netpbm/pm_config.h" +#include "netpbm/pm_c_util.h" +#include "netpbm/mallocvar.h" +#include "netpbm/nstring.h" +#include "netpbm/shhopt.h" +#include "netpbm/pam.h" +#include "netpbm/pm_system.h" + +#include "winicon.h" + +#define RED 0 +#define GRN 1 +#define BLU 2 +#define ALPHA 3 +#define CHANNEL_CHARS "RGBA" + + + +static bool verbose; + + + +struct CmdlineInfo { + + const char * inputFileName; + unsigned int allimages; + unsigned int imageSpec; + unsigned int image; + unsigned int andmasks; + unsigned int headerdump; + unsigned int verbose; +}; + + + +static void +parseCommandLine(int argc, const char **argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + unsigned int option_def_index; + optStruct3 opt3; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; + + OPTENT3 (0, "allimages", OPT_FLAG, NULL, + &cmdlineP->allimages, 0); + OPTENT3 (0, "image", OPT_UINT, &cmdlineP->image, + &cmdlineP->imageSpec, 0); + OPTENT3 (0, "andmasks", OPT_FLAG, NULL, + &cmdlineP->andmasks, 0); + OPTENT3 (0, "headerdump", OPT_FLAG, NULL, + &cmdlineP->headerdump, 0); + OPTENT3 (0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + + opt3.opt_table = option_def; + opt3.short_allowed = false; + opt3.allowNegNum = false; + + pm_optParseOptions3(&argc, (char **)argv, opt3, sizeof(opt3), 0); + + if (cmdlineP->allimages && cmdlineP->imageSpec) + pm_error("You cannot specify both -allimages and -image"); + + if (argc-1 < 1) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[1]; + + if (argc-1 > 1) + pm_error("Too many arguments. The only possible " + "non-option argument is the input file name"); + } + + free(option_def); +} + + + +static unsigned char const pngHeader[] = PNG_HEADER; + + + +struct File { + + FILE * fileP; + const char * name; + pm_filepos pos; + +}; + + + +static uint32_t +u8_le(const unsigned char * const buf, + size_t const offset) { + + return buf[offset + 0]; +} + + + +static uint32_t +u16_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8); +} + + + +static uint32_t +u32_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8) + + ((uint32_t)buf[offset + 2] << 16) + + ((uint32_t)buf[offset + 3] << 24); +} + + + +static uint32_t +s32_le(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 0) + + ((uint32_t)buf[offset + 1] << 8) + + ((uint32_t)buf[offset + 2] << 16) + + ((uint32_t)buf[offset + 3] << 24); +} + + + +static uint32_t +u8_be(const unsigned char * const buf, + size_t const offset) { + + return buf[offset + 0]; +} + + + +static uint32_t +u32_be(const unsigned char * const buf, + size_t const offset) { + + return + ((uint32_t)buf[offset + 0] << 24) + + ((uint32_t)buf[offset + 1] << 16) + + ((uint32_t)buf[offset + 2] << 8) + + ((uint32_t)buf[offset + 3] << 0); +} + + + +static uint32_t +u32_xx(const unsigned char * const buf, + size_t const offset) { + + uint32_t u32; + + ((uint8_t*) &u32)[0] = buf[offset + 0]; + ((uint8_t*) &u32)[1] = buf[offset + 1]; + ((uint8_t*) &u32)[2] = buf[offset + 2]; + ((uint8_t*) &u32)[3] = buf[offset + 3]; + + return (u32); +} + + + +static int +cmpfn(const void * const aP, + const void * const bP) { + + const struct IconDirEntry * const dirEntryAP = aP; + const struct IconDirEntry * const dirEntryBP = bP; + + if (dirEntryAP->offset < dirEntryBP->offset) + return -1; + else if (dirEntryAP->offset > dirEntryBP->offset) + return +1; + else + return 0; +} + + + +static void +dumpIconDir(const struct IconDir * const dirP) { + + unsigned int i; + + pm_message("Type: %u", dirP->type); + pm_message("Icon directory has %u images:", dirP->count); + + for (i = 0; i < dirP->count; ++i) { + const struct IconDirEntry * const dirEntryP = &dirP->entries[i]; + + pm_message("width: %u", dirEntryP->width); + pm_message("height: %u", dirEntryP->height); + pm_message("color count: %u", dirEntryP->color_count); + pm_message("# color planes: %u", dirEntryP->color_planes); + pm_message("bits per pixel: %u", dirEntryP->bits_per_pixel); + pm_message("offset in file of image: %u", dirEntryP->offset); + pm_message("size of image: %u", dirEntryP->size); + pm_message("zero field: %u", dirEntryP->zero); + } +} + + + +static struct IconDir * +readIconDir(struct File * const fP, + bool const needHeaderDump) { + + struct IconDir head; + struct IconDir * dirP; + uint32_t imageIndex; /* more bits than dir.count */ + + pm_readlittleshortu(fP->fileP, &head.zero); + pm_readlittleshortu(fP->fileP, &head.type); + pm_readlittleshortu(fP->fileP, &head.count); + fP->pos += 6; + + if (head.zero != 0 || head.type != ICONDIR_TYPE_ICO) + pm_error("Not a valid windows icon file"); + + MALLOCVAR(dirP); + + if (dirP == NULL) + pm_error("Could't allocate memory for Icon directory"); + + MALLOCARRAY(dirP->entries, head.count); + + if (dirP->entries == NULL) + pm_error("Could not allocate memory for %u entries in icon directory", + head.count); + + dirP->zero = head.zero; + dirP->type = head.type; + dirP->count = head.count; + dirP->entriesAllocCt = head.count; + + for (imageIndex = 0; imageIndex < head.count; ++imageIndex) { + struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex]; + + unsigned char widthField, heightField; + + unsigned long ul; + + pm_readcharu(fP->fileP, &widthField); + dirEntryP->width = (widthField == 0 ? 256 : widthField); + + pm_readcharu(fP->fileP, &heightField); + dirEntryP->height = (heightField == 0 ? 256 : heightField); + + pm_readcharu(fP->fileP, &dirEntryP->color_count); + + pm_readcharu(fP->fileP, &dirEntryP->zero); + + pm_readlittleshortu(fP->fileP, &dirEntryP->color_planes); + + pm_readlittleshortu(fP->fileP, &dirEntryP->bits_per_pixel); + + pm_readlittlelongu(fP->fileP, &ul); dirEntryP->size = ul; + + pm_readlittlelongu(fP->fileP, &ul); dirEntryP->offset = ul; + + fP->pos += 16; + + dirEntryP->index = imageIndex; + } + + /* The following is paranoia code only: + + I've never seen a windows icon file in the wild with having the entries + in the directory stored in a different order than the images + themselves. However, the file format allows for it ... + */ + qsort(dirP->entries, dirP->count, sizeof(struct IconDirEntry), cmpfn); + + if (verbose) { + pm_message("%s icon directory (%u image%s):", + fP->name, + dirP->count, dirP->count == 1 ? "" : "s"); + + for (imageIndex = 0; imageIndex < dirP->count; ++imageIndex) { + const struct IconDirEntry * const dirEntryP = + &dirP->entries[imageIndex]; + + uint32_t colorCt; + + if (dirEntryP->bits_per_pixel == 0) + colorCt = 0; + else if (dirEntryP->bits_per_pixel >= 32) + colorCt = 1u << 24; + else + colorCt = 1u << dirEntryP->bits_per_pixel; + + if (dirEntryP->color_count != 0 && + colorCt > dirEntryP->color_count) { + colorCt = dirEntryP->color_count; + } + pm_message ("%5u: %3u x %3u, %8u colors, %5u bytes", + dirEntryP->index, + dirEntryP->width, + dirEntryP->height, + colorCt, + dirEntryP->size); + } + } + + if (needHeaderDump) + dumpIconDir(dirP); + + return dirP; +} + + + +static void +freeIconDir(struct IconDir * const dirP) { + + free(dirP->entries); + free(dirP); +} + + + +static const unsigned char * +readImage(struct File * const fP, + struct IconDirEntry * const dirEntryP) { + + size_t rc; + unsigned char * image; + uint32_t skippedCt; + + /* Don't try to read an image that is smaller than the + BITMAPINFOHEADER of BMP images (40 bytes). + + PNG compressed images can't be smaller than that either, as the + PNG header plus the mandantory IHDR and IEND chunks already take + 8 + 25 + 12 = 35 bytes, and there is to be a IDAT chunk too. + */ + if (dirEntryP->size < 40) { + pm_error("image %2u: format violation: too small as an image.", + dirEntryP->index); + } + if ((pm_filepos) dirEntryP->offset < fP->pos) + pm_error("image %2u: format violation: invalid offset.", + dirEntryP->index); + + /* The following is paranoia code only: + + I've never seen a windows icon file in the wild with gaps between + the images, but the file format allows for it, and Microsoft + expects the user to fseek() to the start of each image. + */ + skippedCt = 0; + + while ((pm_filepos) dirEntryP->offset > fP->pos) { + if (getc(fP->fileP) == EOF) { + pm_error("seeking to image %u: unexpected EOF", dirEntryP->index); + } + ++fP->pos; + ++skippedCt; + } + + /* The additional four bytes are for purify and friends, as the + routines reading BMP XOR and AND masks might read (but not + evaluate) some bytes beyond the image data. + */ + image = malloc(dirEntryP->size + sizeof(uint32_t)); + if (image == NULL) + pm_error("out of memory."); + + rc = fread (image, 1, dirEntryP->size, fP->fileP); + if (rc != dirEntryP->size) { + pm_error("reading image %2u: unexpected EOF", dirEntryP->index); + } + fP->pos += dirEntryP->size; + + return image; +} + + + +static uint8_t +getIdx1(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + return u8_le(bitmap, offset + (col >> 3)) >> (7 - (col & 0x07)) & 0x1; +} + + + +static uint8_t +getIdx4(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + if ((col & 1) == 0x0000) + return u8_le(bitmap, offset + (col >> 1)) >> 4 & 0x0F; + else + return u8_le(bitmap, offset + (col >> 1)) >> 0 & 0x0F; +} + + + +static uint8_t +getIdx8(const unsigned char * const bitmap, + uint32_t const offset, + int16_t const col) { + + return u8_le(bitmap, offset + col); +} + + + +typedef unsigned char PaletteEntry[4]; + + + +static void +dumpPalette(const PaletteEntry * const palette, + unsigned int const colorCt) { + + unsigned int i; + + for (i = 0; i < colorCt; ++i) { + pm_message("Color %u: (%u, %u, %u)", + i, palette[i][2], palette[i][1], palette[i][0]); + } +} + + + +static void +readXorPalette(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + bool const needHeaderDump, + uint32_t * const bytesConsumedP) { + + uint32_t paletteSize; + + int16_t row; + const PaletteEntry * palette; + uint32_t truncatedXorSize; + uint32_t bytesConsumed; + uint32_t bytesPerRow; + const unsigned char * bitmapCursor; + uint32_t sizeRemaining; + + uint8_t (*getIdx) (const unsigned char * bitmap, + uint32_t rowOffset, + int16_t col); + + if (hdrP->compression_method != BI_RGB) + pm_error("image %2u: invalid compression method %u.", + index, hdrP->compression_method); + + assert(hdrP->bits_per_pixel < 16); + + switch (hdrP->bits_per_pixel) { + case 1: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 2; + getIdx = getIdx1; + break; + + case 4: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 16; + getIdx = getIdx4; + break; + + case 8: + if (hdrP->colors_in_palette == 0) + hdrP->colors_in_palette = 256; + getIdx = getIdx8; + break; + + default: + pm_error("image %2u: " + "bits per pixel is a value we don't understand: %u", + index, hdrP->bits_per_pixel); + getIdx = NULL; + } + + bitmapCursor = &bitmap[0]; /* initial value */ + sizeRemaining = maxSize; /* initial value */ + bytesConsumed = 0; /* initial value */ + + paletteSize = hdrP->colors_in_palette * 4; + + if (sizeRemaining < paletteSize) + pm_error("image %2u: " + "reading palette: image truncated.", index); + + palette = (const PaletteEntry *) bitmapCursor; + + if (needHeaderDump) + dumpPalette(palette, hdrP->colors_in_palette); + + bitmapCursor += paletteSize; + sizeRemaining -= paletteSize; + bytesConsumed += paletteSize; + + { + uint32_t const xorSize = (uint32_t) + (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) + * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < xorSize) { + pm_message("image %2u: " + "reading XOR mask: image truncated.", index); + truncatedXorSize = sizeRemaining; + } else + truncatedXorSize = xorSize; + } + + bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4; + + for (row = 0; hdrP->bm_height / 2 > row; ++row) { + uint32_t rowOffset; + + if (hdrP->top_down) + rowOffset = row * bytesPerRow; + else + rowOffset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (rowOffset + bytesPerRow <= truncatedXorSize) { + int16_t col; + for (col = 0; hdrP->bm_width > col; ++col) { + uint8_t const idx = getIdx(bitmapCursor, rowOffset, col); + + if (idx > hdrP->colors_in_palette) + pm_error("invalid palette index in row %u, column %u.", + row, col); + + /* The palette is an array of little-endian 32-bit values, + where the RGB value is encoded as follows: + + red: bits 2^16..2^23 + green: bits 2^8 ..2^15 + blue: bits 2^0 ..2^7 + */ + tuples[row][col][PAM_RED_PLANE] = palette[idx][2]; + tuples[row][col][PAM_GRN_PLANE] = palette[idx][1]; + tuples[row][col][PAM_BLU_PLANE] = palette[idx][0]; + } + } + } + + bitmapCursor += truncatedXorSize; + sizeRemaining -= truncatedXorSize; + bytesConsumed += truncatedXorSize; + + *bytesConsumedP = bytesConsumed; +} + + + +static void +readXorBitfields(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + bool * const haveAlphaP, + uint32_t * const bytesConsumedP) { + + uint32_t bitfields[4]; + uint8_t shift [4]; + sample maxval [4]; + + int16_t row; + uint32_t bytesConsumed; + uint32_t bytesPerSample; + uint32_t bytesPerRow; + const unsigned char * bitmapCursor; + uint32_t sizeRemaining; + uint32_t truncatedXorSize; + + static uint8_t alphas [256]; + bool allOpaque; + bool allTransparent; + + bytesConsumed = 0; + + if (hdrP->compression_method != BI_RGB + && hdrP->compression_method != BI_BITFIELDS) + pm_error("image %2u: invalid compression method %u.", + index, hdrP->compression_method); + + assert(hdrP->bits_per_pixel >= 16); + + switch (hdrP->bits_per_pixel) { + case 16: + bytesPerSample = 2; + bitfields[RED] = 0x7C00; + bitfields[GRN] = 0x03E0; + bitfields[BLU] = 0x001F; + bitfields[ALPHA] = 0x0000; + break; + + case 24: + bytesPerSample = 3; + bitfields[RED] = 0xFF0000; + bitfields[GRN] = 0x00FF00; + bitfields[BLU] = 0x0000FF; + bitfields[ALPHA] = 0x000000; + break; + + case 32: + bytesPerSample = 4; + bitfields[RED] = 0x00FF0000; + bitfields[GRN] = 0x0000FF00; + bitfields[BLU] = 0x000000FF; + bitfields[ALPHA] = 0xFF000000; + break; + + default: + pm_error("image %2u: bits per pixel is one we don't understand: %u.", + index, hdrP->bits_per_pixel); + bytesPerSample = 0; + } + + bitmapCursor = &bitmap[0]; /* initial value */ + sizeRemaining = maxSize; /* initial value */ + + /* read bit fields from image data */ + if (hdrP->compression_method == BI_BITFIELDS) { + if (sizeRemaining < 12) + pm_error("image %2u: " + "reading bit fields: image truncated.", index); + + bitfields[RED] = u32_le(bitmapCursor, 0); + bitfields[GRN] = u32_le(bitmapCursor, 4); + bitfields[BLU] = u32_le(bitmapCursor, 8); + bitfields[ALPHA] = 0; + + bitmapCursor += 12; + sizeRemaining -= 12; + bytesConsumed += 12; + } + + /* determine shift and maxval from bit field for each channel */ + { + unsigned int i; + + for (i = 0; 4 > i; ++i) { + if (bitfields[i] == 0) { + maxval[i] = 1; + shift [i] = 0; + } else { + unsigned int j; + + maxval[i] = bitfields[i]; + + for (j = 0; 32 > j; ++j) { + if ((maxval[i] & 0x1) != 0) + break; + maxval[i] >>= 1; + } + shift[i] = j; + } + + } + } + + /* read the XOR mask */ + { + uint32_t const xorSize = (uint32_t) + (((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) + * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < xorSize) { + pm_message("image %2u: " + "reading XOR mask: image truncated.", index); + truncatedXorSize = sizeRemaining; + } else + truncatedXorSize = xorSize; + } + + bytesPerRow = ((hdrP->bits_per_pixel * hdrP->bm_width + 31) / 32) * 4; + MEMSZERO(alphas); + + for (row = 0, allOpaque = true, allTransparent = true; + hdrP->bm_height / 2 > row; + ++row) { + + uint32_t offset; + + if (hdrP->top_down) + offset = row * bytesPerRow; + else + offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (offset + bytesPerRow <= truncatedXorSize) { + unsigned int col; + for (col = 0; col < hdrP->bm_width; ++col) { + uint32_t const pixel = u32_le(bitmapCursor, offset); + offset += bytesPerSample; + + tuples[row][col][PAM_RED_PLANE] = + pnm_scalesample((pixel & bitfields[RED]) >> shift[RED], + maxval[RED], 255); + tuples[row][col][PAM_GRN_PLANE] = + pnm_scalesample((pixel & bitfields[GRN]) >> shift[GRN], + maxval[GRN], 255); + tuples [row][col][PAM_BLU_PLANE] + = pnm_scalesample((pixel & bitfields[BLU]) >> shift[BLU], + maxval[BLU], 255); + + if (bitfields [ALPHA] != 0) { + tuples[row][col][PAM_TRN_PLANE] + = pnm_scalesample( + (pixel & bitfields[ALPHA]) >> shift[ALPHA], + maxval[ALPHA], 255); + + if (tuples[row][col][PAM_TRN_PLANE] != 0) + allTransparent = false; + + if (tuples [row][col][PAM_TRN_PLANE] != 255) + allOpaque = false; + + alphas[tuples[row][col][PAM_TRN_PLANE]] = !0; + } + } + } + } + + bitmapCursor += truncatedXorSize; + sizeRemaining -= truncatedXorSize; + bytesConsumed += truncatedXorSize; + + /* A fully transparent alpha channel (all zero) in XOR mask is + defined to be void by Microsoft, and a fully opaque alpha + channel (all maxval) is trivial and will be dropped. + */ + *haveAlphaP = !allTransparent && !allOpaque; + + if (!allTransparent && verbose) { + unsigned int i; + unsigned int c; + + for (i = 0, c = 0; 256 > i; ++i) { + if (alphas[i] != 0) + ++c; + } + pm_message("image %2u: %u distinct transparency value%s", + index, c, (c == 1) ? "": "s"); + } + *bytesConsumedP = bytesConsumed; +} + + + +static void +readAnd(struct BitmapInfoHeader * const hdrP, + const unsigned char * const bitmap, + uint32_t const maxSize, + tuple ** const tuples, + uint16_t const index, + unsigned int const plane, + sample const maxval) { + + int16_t row; + uint32_t bytesConsumed; + uint32_t bytesPerRow; + uint32_t sizeRemaining; + uint32_t truncatedAndSize; + + sizeRemaining = maxSize; /* initial value */ + bytesConsumed = 0; /* initial value */ + + { + uint32_t const andSize = (uint32_t) + (((1 * hdrP->bm_width + 31) / 32) * 4 * hdrP->bm_height / 2); + + if (sizeRemaining < andSize) { + pm_message ("image %2u: " + "Input image ends %u bytes into the %u-byte " + "AND mask. Implying remainder of mask", + index, sizeRemaining, andSize); + truncatedAndSize = sizeRemaining; + } else + truncatedAndSize = andSize; + } + + bytesPerRow = ((1 * hdrP->bm_width + 31) / 32) * 4; + + for (row = 0; row < hdrP->bm_height / 2; ++row) { + uint32_t offset; + + if (hdrP->top_down) + offset = row * bytesPerRow; + else + offset = (hdrP->bm_height / 2 - row - 1) * bytesPerRow; + + if (offset + bytesPerRow <= sizeRemaining) { + unsigned int col; + + for (col = 0; col < hdrP->bm_width; ++col) { + tuples[row][col][plane] = + ((u8_le(bitmap, offset + col/8) + & (1 << (7 - (col & 0x7)))) == 0x00) ? + maxval : 0 + ; + } + } + } + sizeRemaining -= truncatedAndSize; + bytesConsumed += truncatedAndSize; +} + + + +static void +dumpBmpHeader(struct BitmapInfoHeader const hdr, + unsigned int const imageIndex) { + + pm_message("BMP header for Image %u:", imageIndex); + + pm_message("header size: %u", hdr.header_size); + pm_message("bitmap width: %u", hdr.bm_width); + pm_message("bitmap height * 2: %u", hdr.bm_height); + pm_message("row order: %s", hdr.top_down ? "top down" : "bottom up"); + pm_message("# color planes: %u", hdr.color_planes); + pm_message("bits per pixel: %u", hdr.bits_per_pixel); + pm_message("image size: %u", hdr.image_size); + pm_message("horizontal resolution: %u", hdr.horizontal_resolution); + pm_message("vertical resolution: %u", hdr.vertical_resolution); + pm_message("# colors in palette: %u", hdr.colors_in_palette); + pm_message("# important colors: %u", hdr.important_colors); +} + + + +static void +readBmpHeader(const unsigned char * const image, + uint32_t const size, + unsigned int const imageIndex, + bool const needHeaderDump, + struct BitmapInfoHeader * const hdrP) { + + /* BITMAPINFOHEADER structure */ + + if (size < 40) + pm_error("image %2u: reading BITMAPINFOHEADER: not enough data.", + imageIndex); + + hdrP->header_size = u32_le(image, 0); + hdrP->bm_width = s32_le(image, 4); + hdrP->bm_height = s32_le(image, 8); + hdrP->color_planes = u16_le(image, 12); + hdrP->bits_per_pixel = u16_le(image, 14); + hdrP->compression_method = u32_le(image, 16); + hdrP->image_size = u32_le(image, 20); + hdrP->horizontal_resolution = s32_le(image, 24); + hdrP->vertical_resolution = s32_le(image, 28); + hdrP->colors_in_palette = u32_le(image, 32); + hdrP->important_colors = u32_le(image, 36); + + if (hdrP->bm_height > 0) { + hdrP->top_down = false; + } else { + hdrP->top_down = true; + hdrP->bm_height *= -1; + } + + if (hdrP->header_size < 36 + || hdrP->bm_width == 0 || hdrP->bm_height == 0 + || (hdrP->bm_height & 1) != 0x0000) { + pm_error("image %2u: format violation: invalid BMP header.", + imageIndex); + } + + if (needHeaderDump) + dumpBmpHeader(*hdrP, imageIndex); +} + + + +static void +readXorMask(struct BitmapInfoHeader * const hdrP, + const unsigned char * const imageCursor, + uint32_t const imageSize, + tuple ** const tuples, + uint16_t const index, + bool const needHeaderDump, + bool * const haveAlphaP, + uint32_t * const bytesConsumedP) { +/*---------------------------------------------------------------------------- + Read the so-called XOR mask (for non-monochrome images, this is the + color pixmap) +-----------------------------------------------------------------------------*/ + /* preset the PAM with fully opaque black (just in case the image + is truncated and not all pixels are filled in below). + */ + { + unsigned int row; + + for (row = 0; row < hdrP->bm_height / 2; ++row) { + unsigned int col; + for (col = 0; col < hdrP->bm_width; ++col) { + tuples[row][col][PAM_RED_PLANE] = 0; + tuples[row][col][PAM_GRN_PLANE] = 0; + tuples[row][col][PAM_BLU_PLANE] = 0; + tuples[row][col][PAM_TRN_PLANE] = 255; + } + } + } + + if (hdrP->bits_per_pixel < 16) { + readXorPalette(hdrP, imageCursor, imageSize, tuples, index, + needHeaderDump, + bytesConsumedP); + *haveAlphaP = false; + } else + readXorBitfields(hdrP, imageCursor, imageSize, tuples, index, + haveAlphaP, bytesConsumedP); +} + + + +static void +reportImage(unsigned int const imageIndex, + struct BitmapInfoHeader const hdr, + bool const haveAlpha) { + + const char * const style = + haveAlpha ? "RGB +alpha" : + hdr.bits_per_pixel < 16 ? "RGB/palette" : + "RGB" + ; + + pm_message("image %2u: " + "BMP %3u x %3u x %2u (%s)", + imageIndex, + hdr.bm_width, hdr.bm_height / 2, hdr.bits_per_pixel, + style); +} + + + +static void +convertBmp(const unsigned char * const image, + FILE * const ofP, + struct IconDirEntry * const dirEntryP, + bool const needHeaderDump, + bool const wantAndMaskPlane) { + + struct BitmapInfoHeader hdr; + uint32_t offset; + bool haveAlpha; + uint32_t xorByteCt; + + struct pam outpam; + tuple ** tuples; + + readBmpHeader(image, dirEntryP->size, dirEntryP->index, needHeaderDump, + &hdr); + + offset = hdr.header_size; /* Start after header */ + + if ((dirEntryP->width != hdr.bm_width) + || (dirEntryP->height != hdr.bm_height / 2)) { + pm_message("image %2u: " + "mismatch in header and image dimensions " + "(%u x %u vs. %u x %u)", + dirEntryP->index, + dirEntryP->width, + dirEntryP->height, + hdr.bm_width, + hdr.bm_height / 2); + } + + if ((dirEntryP->bits_per_pixel != 0) + && (dirEntryP->bits_per_pixel != hdr.bits_per_pixel)) { + pm_message("image %2u " + "mismatch in header and image bpp value" + "(%u vs. %u)", + dirEntryP->index, + dirEntryP->bits_per_pixel, + hdr.bits_per_pixel); + } + + outpam.size = sizeof(struct pam); + outpam.len = PAM_STRUCT_SIZE(allocation_depth); + outpam.file = ofP; + outpam.format = PAM_FORMAT; + outpam.width = hdr.bm_width; + outpam.height = hdr.bm_height / 2; + outpam.maxval = 255; + outpam.allocation_depth = 5; + outpam.depth = 0; + /* Just for tuple array allocation; we set the value for the actual + output image below. + */ + + tuples = pnm_allocpamarray(&outpam); + + readXorMask(&hdr, &image[offset], + dirEntryP->size - offset, + tuples, dirEntryP->index, needHeaderDump, + &haveAlpha, &xorByteCt); + + offset += xorByteCt; + + { + /* If there is no alpha channel in XOR mask, store the AND mask to + the transparency plane. Else, here are two transparency + maps. If requested, store the AND mask to a fifth PAM plane + */ + bool haveAnd; + unsigned int andPlane; + + if (!haveAlpha) { + haveAnd = true; + andPlane = PAM_TRN_PLANE; + strcpy (outpam.tuple_type, "RGB_ALPHA"); + outpam.depth = 4; + } else if (wantAndMaskPlane) { + haveAnd = true; + andPlane = PAM_TRN_PLANE + 1; + outpam.depth = 5; + strcpy(outpam.tuple_type, "RGB_ALPHA_ANDMASK"); + } else { + haveAnd = false; + strcpy (outpam.tuple_type, "RGB_ALPHA"); + outpam.depth = 4; + } + if (haveAnd) { + readAnd(&hdr, &image[offset], dirEntryP->size - offset, + tuples, dirEntryP->index, andPlane, outpam.maxval); + } + } + pnm_writepam(&outpam, tuples); + pnm_freepamarray(tuples, &outpam); + + reportImage(dirEntryP->index, hdr, haveAlpha); +} + + + +static void +reportPngInfo(const unsigned char * const image, + struct IconDirEntry * const dirEntryP) { + + struct PngIhdr ihdr; + + ihdr.length = u32_be (image, sizeof(pngHeader) +0); + ihdr.signature = u32_xx (image, sizeof(pngHeader) +4); + ihdr.width = u32_be (image, sizeof(pngHeader) +8); + ihdr.height = u32_be (image, sizeof(pngHeader) +12); + ihdr.bit_depth = u8_be (image, sizeof(pngHeader) +16); + ihdr.color_type = u8_be (image, sizeof(pngHeader) +17); + ihdr.compression = u8_be (image, sizeof(pngHeader) +18); + ihdr.filter = u8_be (image, sizeof(pngHeader) +19); + ihdr.interlace = u8_be (image, sizeof(pngHeader) +20); + + if ((ihdr.length != 13) + || ihdr.signature != *(uint32_t*)"IHDR") { + pm_message("image %2u: PNG (uncommonly formatted)", + dirEntryP->index); + } else { + uint32_t depth; + const char * colorType; + + switch (ihdr.color_type) { + case 0: + colorType = "grayscale"; + depth = ihdr.bit_depth; + break; + + case 2: + colorType = "RGB"; + depth = ihdr.bit_depth * 3; + break; + + case 3: + colorType = "RGB/palette"; + depth = 8; + break; + + case 4: + colorType = "grayscale + alpha"; + depth = ihdr.bit_depth * 2; + break; + + case 6: + colorType = "RGB + alpha"; + depth = ihdr.bit_depth * 4; + break; + + default: + colorType = "unknown color system"; + depth = 0; + break; + } + pm_message("image %2u: PNG %3u x %3u x %2u (%s)", + dirEntryP->index, + ihdr.width, ihdr.height, depth, colorType); + + if ((dirEntryP->width != ihdr.width) + || (dirEntryP->height != ihdr.height)) { + pm_message("image %2u:" + " mismatch in header and image dimensions" + " (%u x %u vs %u x %u)", + dirEntryP->index, dirEntryP->width, dirEntryP->height, + ihdr.width, ihdr.height); + } + /* Mismatch between dirEntryP->bits_per_pixel and 'depth' is + normal, because the creator of the winicon file doesn't necessarily + know the true color resolution. + */ + } +} + + + +static void +convertPng(const unsigned char * const image, + FILE * const ofP, + struct IconDirEntry * const dirEntryP) { + + struct bufferDesc imageBuffer; + + reportPngInfo(image, dirEntryP); + + imageBuffer.size = dirEntryP->size; + imageBuffer.buffer = (unsigned char *)image; + + fflush (stdout); + pm_system(pm_feed_from_memory, &imageBuffer, + NULL /* stdout accepter */, NULL, + "pngtopam -alphapam"); +} + + + +static uint32_t +bestImage(struct IconDir * const dirP) { + + uint32_t imageIndex; + uint32_t bestPixelCt; + uint32_t bestColorCt; + uint16_t best; + + bestPixelCt = 0; /* initial value */ + bestColorCt = 0; /* initial value */ + best = 0; /* initial value */ + + for (imageIndex = 0; dirP->count > imageIndex; ++imageIndex) { + struct IconDirEntry * const dirEntryP = &dirP->entries[imageIndex]; + + uint32_t const pixelCt = dirEntryP->width * dirEntryP->height; + + uint32_t colorCt; + + /* 32-bit icons have 24 bit color information only. + + Since NT 5.1 (aka WinXP), it is allowed to place 8-bit + transparency information in the remaining bits (to check, + you have to read all these bits in the image!), so I prefer + 32-bit images over 24-bit images (which violate the + spec. anyway). + */ + if (dirEntryP->bits_per_pixel > 24) + colorCt = 1u << 25; + else + colorCt = 1u << dirEntryP->bits_per_pixel; + + if (dirEntryP->color_count != 0 && colorCt > dirEntryP->color_count) + colorCt = dirEntryP->color_count; + + if ((pixelCt > bestPixelCt) + || ((pixelCt == bestPixelCt) && (colorCt > bestColorCt))) { + /* This is a new best */ + bestPixelCt = pixelCt; + bestColorCt = colorCt; + best = imageIndex; + } + } + return best; +} + + + +static void +convertImage(struct File * const icoP, + struct IconDirEntry * const dirEntryP, + FILE * const ofP, + bool const needHeaderDump, + bool const wantAndMaskPlane) { + + const unsigned char * image; /* malloced */ + + image = readImage(icoP, dirEntryP); + + if (MEMEQ(image, pngHeader, sizeof (pngHeader))) + convertPng(image, ofP, dirEntryP); + else + convertBmp(image, ofP, dirEntryP, needHeaderDump, wantAndMaskPlane); + + free((void *)image); +} + + + +int +main (int argc, const char *argv []) { + + struct File ico; + struct IconDir * dirP; + struct CmdlineInfo cmdline; + + pm_proginit (&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + verbose = cmdline.verbose; + + ico.name = + streq(cmdline.inputFileName, "-") ? "<stdin>" : cmdline.inputFileName; + ico.pos = 0; + ico.fileP = pm_openr(cmdline.inputFileName); + + dirP = readIconDir(&ico, cmdline.headerdump); + + if (cmdline.allimages) { + unsigned int i; + for (i = 0; i < dirP->count; ++i) + convertImage(&ico, &dirP->entries[i], stdout, + cmdline.headerdump, cmdline.andmasks); + } else if (cmdline.imageSpec) { + unsigned int i; + bool found; + for (i = 0, found = false; i < dirP->count; ++i) { + if (dirP->entries[i].index == cmdline.image) { + found = true; + convertImage(&ico, &dirP->entries[i], stdout, + cmdline.headerdump, cmdline.andmasks); + } + } + if (!found) + pm_error("no image index %u in.input", cmdline.image); + } else { + convertImage(&ico, &dirP->entries[bestImage(dirP)], stdout, + cmdline.headerdump, cmdline.andmasks); + } + + freeIconDir(dirP); + + if (ico.fileP != stdin) + pm_close(ico.fileP); + + return 0; +} + + + diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c index 89dcb76c..0cceb4fe 100644 --- a/converter/pbm/pbmtolj.c +++ b/converter/pbm/pbmtolj.c @@ -545,7 +545,7 @@ main(int argc, char * argv[]) { struct cmdlineInfo cmdline; FILE * ifP; - bool eof; + int eof; pbm_init(&argc, argv); diff --git a/converter/pbm/pbmtopsg3.c b/converter/pbm/pbmtopsg3.c index 2878686b..8163b70a 100644 --- a/converter/pbm/pbmtopsg3.c +++ b/converter/pbm/pbmtopsg3.c @@ -323,7 +323,7 @@ doPages(FILE * const ifP, unsigned int * const pagesP, double const dpi) { - bool eof; + int eof; unsigned int pagesDone; eof = FALSE; diff --git a/converter/ppm/411toppm.c b/converter/ppm/411toppm.c index b5e3c03b..eb2372a5 100644 --- a/converter/ppm/411toppm.c +++ b/converter/ppm/411toppm.c @@ -192,6 +192,7 @@ YUVtoPPM(FILE * const ifP, int main(int argc, const char **argv) { + pixval const maxval = 255; struct CmdlineInfo cmdline; FILE * ifP; pixel * pixrow; @@ -208,13 +209,16 @@ main(int argc, const char **argv) { ifP = pm_openr(cmdline.inputFileName); - ppm_writeppminit(stdout, cmdline.width, cmdline.height, 255, 0); + ppm_writeppminit(stdout, cmdline.width, cmdline.height, maxval, 0); - for (row = 0; row < cmdline.height; row++) { + for (row = 0; row < cmdline.height; ++row) { YUVtoPPM(ifP, cmdline.width, cmdline.height, pixrow); - ppm_writeppmrow(stdout, pixrow, cmdline.width, 255, 0); + ppm_writeppmrow(stdout, pixrow, cmdline.width, maxval, 0); } + if (fgetc(ifP) != EOF) + pm_message("Extraneous data at end of image."); + pm_close(ifP); ppm_freerow(pixrow); diff --git a/converter/ppm/ppmtompeg/bframe.c b/converter/ppm/ppmtompeg/bframe.c index 1dbc1846..f5009d6c 100644 --- a/converter/ppm/ppmtompeg/bframe.c +++ b/converter/ppm/ppmtompeg/bframe.c @@ -523,7 +523,7 @@ makeNonSkipBlock(int const y, MpegFrame * const curr, MpegFrame * const prev, MpegFrame * const next, - boolean const specificsOn, + bool const specificsOn, int const mbAddress, int const QScale, const LumBlock * const currentBlockP, diff --git a/converter/ppm/ppmtompeg/frame.c b/converter/ppm/ppmtompeg/frame.c index 09f46f66..75b209f8 100644 --- a/converter/ppm/ppmtompeg/frame.c +++ b/converter/ppm/ppmtompeg/frame.c @@ -753,7 +753,7 @@ Frame_AllocHalf(MpegFrame * const frameP) { *===========================================================================*/ void Frame_AllocDecoded(MpegFrame * const frameP, - boolean const makeReference) { + bool const makeReference) { if (frameP->decoded_y != NULL) { /* already allocated */ diff --git a/converter/ppm/ppmtompeg/headers/frames.h b/converter/ppm/ppmtompeg/headers/frames.h index f2bcf6ae..966d9214 100644 --- a/converter/ppm/ppmtompeg/headers/frames.h +++ b/converter/ppm/ppmtompeg/headers/frames.h @@ -255,7 +255,6 @@ extern int gopSize; extern int slicesPerFrame; extern int blocksPerSlice; extern int referenceFrame; -extern boolean specificsOn; extern int quietTime; /* shut up for at least quietTime seconds; * negative means shut up forever */ diff --git a/converter/ppm/ppmtompeg/headers/param.h b/converter/ppm/ppmtompeg/headers/param.h index c7f57b44..0c6d8e5c 100644 --- a/converter/ppm/ppmtompeg/headers/param.h +++ b/converter/ppm/ppmtompeg/headers/param.h @@ -51,7 +51,7 @@ extern char machineName[MAX_MACHINES][256]; extern char userName[MAX_MACHINES][256]; extern char executable[MAX_MACHINES][1024]; extern char remoteParamFile[MAX_MACHINES][1024]; -extern boolean remote[MAX_MACHINES]; +extern bool remote[MAX_MACHINES]; extern char currentPath[MAXPATHLEN]; extern char currentFramePath[MAXPATHLEN]; extern char currentGOPPath[MAXPATHLEN]; @@ -62,12 +62,21 @@ extern int realWidth, realHeight; extern char ioConversion[1024]; extern char slaveConversion[1024]; extern FILE * bitRateFile; -extern boolean showBitRatePerFrame; -extern boolean computeMVHist; extern const double VidRateNum[9]; -extern boolean keepTempFiles; +extern bool keepTempFiles; +extern int outputWidth, outputHeight; +extern bool specificsOn; +extern char specificsFile[256]; +extern char specificsDefines[1024]; +extern bool GammaCorrection; +extern float GammaValue; +extern char userDataFileName[256]; +/* Defined in ppmtompeg.c; computed from command line */ +extern bool showBitRatePerFrame; +extern bool computeMVHist; + /* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. diff --git a/converter/ppm/ppmtompeg/parallel.c b/converter/ppm/ppmtompeg/parallel.c index 50381271..2835c67c 100644 --- a/converter/ppm/ppmtompeg/parallel.c +++ b/converter/ppm/ppmtompeg/parallel.c @@ -968,7 +968,7 @@ IoServer(struct inputSource * const inputSourceP, -----------------------------------------------------------------------------*/ int ioPortNum; int serverSocket; - boolean done; + bool done; unsigned char *bigBuffer; /* A work buffer that we keep around permanently. We increase its size as needed, but never shrink it. diff --git a/converter/ppm/ppmtompeg/param.c b/converter/ppm/ppmtompeg/param.c index 15f13473..45605981 100644 --- a/converter/ppm/ppmtompeg/param.c +++ b/converter/ppm/ppmtompeg/param.c @@ -73,14 +73,14 @@ #define LAST_OPTION 15 /* put any non-required options after LAST_OPTION */ -#define OPTION_RESIZE 16 +#define OPTION_RESIZE 16 #define OPTION_IO_CONVERT 17 #define OPTION_SLAVE_CONVERT 18 -#define OPTION_IQTABLE 19 -#define OPTION_NIQTABLE 20 +#define OPTION_IQTABLE 19 +#define OPTION_NIQTABLE 20 #define OPTION_FRAME_RATE 21 #define OPTION_ASPECT_RATIO 22 -#define OPTION_YUV_SIZE 23 +#define OPTION_YUV_SIZE 23 #define OPTION_SPECIFICS 24 #define OPTION_DEFS_SPECIFICS 25 #define OPTION_BUFFER_SIZE 26 @@ -98,48 +98,49 @@ * GLOBAL VARIABLES * *==================*/ -extern char currentPath[MAXPATHLEN]; -char outputFileName[256]; -int outputWidth, outputHeight; +char outputFileName[256]; +int outputWidth, outputHeight; char inputConversion[1024]; char ioConversion[1024]; char slaveConversion[1024]; char yuvConversion[256]; char specificsFile[256],specificsDefines[1024]=""; -boolean GammaCorrection=FALSE; -float GammaValue; +bool GammaCorrection=FALSE; +float GammaValue; char userDataFileName[256]={0}; -boolean specificsOn = FALSE; +bool specificsOn = FALSE; char currentGOPPath[MAXPATHLEN]; char currentFramePath[MAXPATHLEN]; -boolean keepTempFiles; +bool keepTempFiles; +int numMachines; +char machineName[MAX_MACHINES][256]; +char userName[MAX_MACHINES][256]; +char executable[MAX_MACHINES][1024]; +char remoteParamFile[MAX_MACHINES][1024]; +bool remote[MAX_MACHINES]; +int mult_seq_headers = 0; /* 0 for none, N for header/N GOPs */ + + +extern char currentPath[MAXPATHLEN]; static const char * const optionText[LAST_OPTION+1] = { "GOP_SIZE", "PATTERN", "PIXEL", "PQSCALE", "OUTPUT", "RANGE", "PSEARCH_ALG", "IQSCALE", "INPUT_DIR", "INPUT_CONVERT", "INPUT", "BQSCALE", "BASE_FILE_FORMAT", "SLICES_PER_FRAME", "BSEARCH_ALG", "REFERENCE_FRAME"}; -static boolean optionSeen[NUM_OPTIONS+1]; +static bool optionSeen[NUM_OPTIONS+1]; /* optionSeen[x] means we have seen option x in the parameter file we've been reading. */ -int numMachines; -char machineName[MAX_MACHINES][256]; -char userName[MAX_MACHINES][256]; -char executable[MAX_MACHINES][1024]; -char remoteParamFile[MAX_MACHINES][1024]; -boolean remote[MAX_MACHINES]; -int mult_seq_headers = 0; /* 0 for none, N for header/N GOPs */ - /*===========================================================================* * * SkipSpacesTabs * - * skip all spaces and tabs + * skip all spaces and tabs * - * RETURNS: point to next character not a space or tab + * RETURNS: point to next character not a space or tab * * SIDE EFFECTS: none * @@ -172,13 +173,13 @@ static int GetAspectRatio(const char * const p) { float ratio; - int ttRatio; + int ttRatio; int retval; sscanf(p, "%f", &ratio); ttRatio = (int)(0.5+ratio*10000.0); - if ( ttRatio == 10000 ) retval = 1; + if ( ttRatio == 10000 ) retval = 1; else if ( ttRatio == 6735 ) retval = 2; else if ( ttRatio == 7031 ) retval = 3; else if ( ttRatio == 7615 ) retval = 4; @@ -205,9 +206,9 @@ GetAspectRatio(const char * const p) * * ReadMachineNames * - * read a list of machine names for parallel execution + * read a list of machine names for parallel execution * - * RETURNS: nothing + * RETURNS: nothing * * SIDE EFFECTS: machine info updated * @@ -219,7 +220,7 @@ ReadMachineNames(FILE * const fpointer) const char *charPtr; while ( (fgets(input, 256, fpointer) != NULL) && - (strncmp(input, "END_PARALLEL", 12) != 0) ) { + (strncmp(input, "END_PARALLEL", 12) != 0) ) { if ( input[0] == '#' || input[0] == '\n') { continue; } @@ -229,13 +230,13 @@ ReadMachineNames(FILE * const fpointer) remote[numMachines] = TRUE; sscanf(charPtr, "%s %s %s %s", machineName[numMachines], - userName[numMachines], executable[numMachines], - remoteParamFile[numMachines]); + userName[numMachines], executable[numMachines], + remoteParamFile[numMachines]); } else { remote[numMachines] = FALSE; sscanf(input, "%s %s %s", machineName[numMachines], - userName[numMachines], executable[numMachines]); + userName[numMachines], executable[numMachines]); } numMachines++; @@ -259,13 +260,13 @@ static int GetFrameRate(const char * const p) { float rate; - int thouRate; + int thouRate; int retval; sscanf(p, "%f", &rate); thouRate = (int)(0.5+1000.0*rate); - if ( thouRate == 23976 ) retval = 1; + if ( thouRate == 23976 ) retval = 1; else if ( thouRate == 24000 ) retval = 2; else if ( thouRate == 25000 ) retval = 3; else if ( thouRate == 29970 ) retval = 4; diff --git a/converter/ppm/ppmtompeg/ppmtompeg.c b/converter/ppm/ppmtompeg/ppmtompeg.c index 6e7e9833..b8ef37f1 100644 --- a/converter/ppm/ppmtompeg/ppmtompeg.c +++ b/converter/ppm/ppmtompeg/ppmtompeg.c @@ -65,7 +65,8 @@ int main _ANSI_ARGS_((int argc, char **argv)); * GLOBAL VARIABLES * *==================*/ -boolean showBitRatePerFrame; +bool showBitRatePerFrame; +bool computeMVHist = FALSE; boolean frameSummary; extern time_t IOtime; @@ -79,9 +80,7 @@ boolean noFrameSummaryOption = FALSE; boolean debugSockets = FALSE; boolean debugMachines = FALSE; boolean bitRateInfoOption = FALSE; -boolean computeMVHist = FALSE; int baseFormat; -extern boolean specificsOn; extern FrameSpecList *fsl; boolean pureDCT=FALSE; char encoder_name[1024]; diff --git a/converter/ppm/ppmtompeg/readframe.c b/converter/ppm/ppmtompeg/readframe.c index 112ebdf0..cac6bdad 100644 --- a/converter/ppm/ppmtompeg/readframe.c +++ b/converter/ppm/ppmtompeg/readframe.c @@ -67,9 +67,6 @@ struct YuvLine { * Global VARIABLES * *==================*/ -extern boolean GammaCorrection; -extern float GammaValue; -extern int outputWidth,outputHeight; boolean resizeFrame; const char *CurrFile; @@ -828,7 +825,7 @@ MpegFrame *mf; int w,h; { static int GammaVal[256]; - static boolean init_done=FALSE; + static bool init_done=FALSE; int i,j; if (!init_done) { @@ -882,7 +879,7 @@ DoKillDim(mf, w, h) MpegFrame *mf; int w,h; { - static boolean init_done=FALSE; + static bool init_done=FALSE; static unsigned char mapper[256]; register int i,j; double slope, intercept; diff --git a/converter/ppm/ppmtompeg/specifics.c b/converter/ppm/ppmtompeg/specifics.c index d2093e7f..ffbce80a 100644 --- a/converter/ppm/ppmtompeg/specifics.c +++ b/converter/ppm/ppmtompeg/specifics.c @@ -46,14 +46,12 @@ #include <stdio.h> #include <string.h> #include "prototypes.h" +#include "param.h" /*==================* * GLOBAL VARIABLES * *==================*/ -extern boolean specificsOn; -extern char specificsFile[]; -extern char specificsDefines[]; FrameSpecList *fsl; /*=====================* diff --git a/converter/ppm/ppmtopjxl.c b/converter/ppm/ppmtopjxl.c index 91cd1a45..ddf49638 100644 --- a/converter/ppm/ppmtopjxl.c +++ b/converter/ppm/ppmtopjxl.c @@ -12,6 +12,7 @@ * */ +#include <assert.h> #include <stdio.h> #include <math.h> #include <string.h> @@ -33,7 +34,7 @@ const char * const usage="[-nopack] [-gamma <n>] [-presentation] [-dark]\n\ #define PCL_MAXHEIGHT 32767 #define PCL_MAXVAL 255 -static int nopack = 0; +static bool nopack = false; static int dark = 0; static int diffuse = 0; static int dither = 0; @@ -73,16 +74,28 @@ static const struct options { {"-nopack", BOOL, &nopack }, }; -#define putword(w) (putchar(((w)>>8) & 255), putchar((w) & 255)) -static int -bitsperpixel(int v) { - int bpp = 0; - while (v > 0) { /* calculate # bits for value */ - ++bpp; - v>>=1; - } - return (bpp); + +static void +putword(unsigned short const w) { + putchar((w >> 8) & 0xff); + putchar((w >> 0) & 0xff); +} + + + +static unsigned int +bitsperpixel(unsigned int v) { + + unsigned int bpp; + + /* calculate # bits for value */ + + for (bpp = 0; v > 0; ) { + ++bpp; + v >>= 1; + } + return bpp; } @@ -94,101 +107,117 @@ static char *outrow = NULL; static signed char *runcnt = NULL; static void -putbits(b, n) { - /* put #n bits in b out, packing into bytes; n=0 flushes bits */ - /* n should never be > 8 */ - - static int out = 0; - static int cnt = 0; - static int num = 0; - static int pack = 0; - if (n) { - int xo = 0; - int xc = 0; - if (cnt+n > 8) { /* overflowing current byte? */ - xc = cnt + n - 8; - xo = (b & ~(-1 << xc)) << (8-xc); - n -= xc; - b >>= xc; - } - cnt += n; - out |= (b & ~(-1 << n)) << (8-cnt); - if (cnt >= 8) { - inrow[num++] = out; - out = xo; - cnt = xc; - } - } else { /* flush row */ - int i; - if (cnt) { - inrow[num++] = out; - out = cnt = 0; - } - for (; num > 0 && inrow[num-1] == 0; num--); /* remove trailing zeros */ - printf("\033*b"); - if (num && !nopack) { /* TIFF 4.0 packbits encoding */ - int start = 0; - int next; - runcnt[start] = 0; - for (i = 1; i < num; i++) { - if (inrow[i] == inrow[i-1]) { - if (runcnt[start] <= 0 && runcnt[start] > -127) - runcnt[start]--; - else - runcnt[start = i] = 0; - } else { - if (runcnt[start] >= 0 && runcnt[start] < 127) - runcnt[start]++; - else - runcnt[start = i] = 0; +putbits(int const bArg, + int const nArg) { +/*---------------------------------------------------------------------------- + Put 'n' bits in 'b' out, packing into bytes; n=0 flushes bits. + + n should never be > 8 +-----------------------------------------------------------------------------*/ + static int out = 0; + static int cnt = 0; + static int num = 0; + static bool pack = false; + + int b; + int n; + + b = bArg; + n = nArg; + + if (n) { + int xo = 0; + int xc = 0; + + assert(n <= 8); + + if (cnt + n > 8) { /* overflowing current byte? */ + xc = cnt + n - 8; + xo = (b & ~(-1 << xc)) << (8-xc); + n -= xc; + b >>= xc; } - } - start = 0; - for (i = 0; i < num; i = next) { - int count = runcnt[i]; - int from = i; - if (count >= 0) { /* merge two-byte runs */ - for (;;) { - next = i+1+runcnt[i]; - if(next >= num || runcnt[next] < 0 || - count+runcnt[next]+1 > 127) - break; - count += runcnt[next]+1; - i = next; - } + cnt += n; + out |= (b & ~(-1 << n)) << (8-cnt); + if (cnt >= 8) { + inrow[num++] = out; + out = xo; + cnt = xc; } - next = i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]); - if (next < num && count > 0 && - runcnt[next] < 0 && runcnt[next] > -127) { - count--; - next--; - runcnt[next] = runcnt[next+1]-1; + } else { /* flush row */ + if (cnt) { + inrow[num++] = out; + out = cnt = 0; } - outrow[start++] = count; - if (count >= 0) { - while (count-- >= 0) - outrow[start++] = inrow[from++]; - } else - outrow[start++] = inrow[from]; - } - if (start < num) { - num = start; - if (!pack) { - printf("2m"); - pack = 1; + for (; num > 0 && inrow[num-1] == 0; --num); + /* remove trailing zeros */ + printf("\033*b"); + if (num && !nopack) { /* TIFF 4.0 packbits encoding */ + unsigned int i; + int start = 0; + int next; + runcnt[start] = 0; + for (i = 1; i < num; ++i) { + if (inrow[i] == inrow[i-1]) { + if (runcnt[start] <= 0 && runcnt[start] > -127) + runcnt[start]--; + else + runcnt[start = i] = 0; + } else { + if (runcnt[start] >= 0 && runcnt[start] < 127) + runcnt[start]++; + else + runcnt[start = i] = 0; + } + } + for (i = 0, start = 0; i < num; i = next) { + int count = runcnt[i]; + int from = i; + if (count >= 0) { /* merge two-byte runs */ + for (;;) { + next = i+1+runcnt[i]; + if(next >= num || runcnt[next] < 0 || + count+runcnt[next]+1 > 127) + break; + count += runcnt[next]+1; + i = next; + } + } + next = i + 1 + ((runcnt[i] < 0) ? -runcnt[i] : runcnt[i]); + if (next < num && count > 0 && + runcnt[next] < 0 && runcnt[next] > -127) { + --count; + --next; + runcnt[next] = runcnt[next+1]-1; + } + outrow[start++] = count; + if (count >= 0) { + while (count-- >= 0) + outrow[start++] = inrow[from++]; + } else + outrow[start++] = inrow[from]; + } + if (start < num) { + num = start; + if (!pack) { + printf("2m"); + pack = true; + } + } else { + if (pack) { + printf("0m"); + pack = false; + } + } } - } else { - if (pack) { - printf("0m"); - pack = 0; + printf("%dW", num); + { + unsigned int i; + for (i = 0; i < num; ++i) + putchar(pack ? outrow[i] : inrow[i]); } - } - } - printf("%dW", num); - for (i = 0; i < num; i++) - putchar(pack ? outrow[i] : inrow[i]); - num = 0; /* new row */ - } + num = 0; /* new row */ + } } diff --git a/converter/ppm/ppmtoyuv.c b/converter/ppm/ppmtoyuv.c index 7d843cc0..75f79c1e 100644 --- a/converter/ppm/ppmtoyuv.c +++ b/converter/ppm/ppmtoyuv.c @@ -19,79 +19,102 @@ #include "ppm.h" -int -main(argc, argv) -char **argv; -{ - FILE *ifp; - pixel *pixelrow; - register pixel *pP; - int rows, cols, format, row; - register int col; - pixval maxval; - unsigned long y1, y2=0, u=0, v=0, u0=0, u1, u2, v0=0, v1, v2; - unsigned char *yuvbuf; - - - ppm_init(&argc, argv); - if (argc > 2) pm_usage("[ppmfile]"); - if (argc == 2) ifp = pm_openr(argv[1]); - else ifp = stdin; - - ppm_readppminit(ifp, &cols, &rows, &maxval, &format); +static void +convertRow(const pixel * const pixelrow, + unsigned int const cols, + unsigned char * const yuvBuf, + unsigned long * const uP, + unsigned long * const vP, + unsigned long * const u0P, + unsigned long * const v0P, + unsigned long * const y2CarryP) { + + unsigned int col; + unsigned char * yuvptr; + + for (col = 0, yuvptr = &yuvBuf[0]; col < cols; col += 2) { + unsigned long y1, y2, u1, u2, v1, v2; + + { + /* first pixel gives Y and 0.5 of chroma */ + pixval const r = PPM_GETR(pixelrow[col]); + pixval const g = PPM_GETG(pixelrow[col]); + pixval const b = PPM_GETB(pixelrow[col]); + + y1 = 16829 * r + 33039 * g + 6416 * b + (*y2CarryP & 0xffff); + u1 = -4853 * r - 9530 * g + 14383 * b; + v1 = 14386 * r - 12046 * g - 2340 * b; + } + { + /* second pixel gives Y and 0.25 of chroma */ + pixval const r = PPM_GETR(pixelrow[col + 1]); + pixval const g = PPM_GETG(pixelrow[col + 1]); + pixval const b = PPM_GETB(pixelrow[col + 1]); + + y2 = 16829 * r + 33039 * g + 6416 * b + (y1 & 0xffff); + u2 = -2426 * r - 4765 * g + 7191 * b; + v2 = 7193 * r - 6023 * g - 1170 * b; + } + /* filter the chroma */ + *uP = *u0P + u1 + u2 + (*uP & 0xffff); + *vP = *v0P + v1 + v2 + (*vP & 0xffff); + + *u0P = u2; + *v0P = v2; + + *yuvptr++ = (*uP >> 16) + 128; + *yuvptr++ = (y1 >> 16) + 16; + *yuvptr++ = (*vP >> 16) + 128; + *yuvptr++ = (y2 >> 16) + 16; + + *y2CarryP = y2; + } +} - if (cols % 2 != 0) - pm_error("Image must have even number of columns.\n" - "This image is %d columns wide. Try Pnmcut.", cols); - pixelrow = ((pixel*) pm_allocrow( cols, sizeof(pixel) )); - yuvbuf = (unsigned char *) pm_allocrow( cols, 2 ); - for (row = 0; row < rows; ++row) { - unsigned char *yuvptr; +int +main(int argc, const char **argv) { - ppm_readppmrow(ifp, pixelrow, cols, maxval, format); + FILE * ifP; + pixel * pixelrow; + int rows, cols, format; + pixval maxval; + unsigned int row; + unsigned char * yuvBuf; + unsigned long u, v, u0, v0, y2Carry; - for (col = 0, pP = pixelrow, yuvptr=yuvbuf; col < cols; col += 2, ++pP) { - pixval r, g, b; + pm_proginit(&argc, argv); - /* first pixel gives Y and 0.5 of chroma */ - r = PPM_GETR(*pP); - g = PPM_GETG(*pP); - b = PPM_GETB(*pP); + if (argc-1 > 1) + pm_error("Too many arguments: %u. The only possible argument " + "is the name of the input file", argc-1); - y1 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y2); - u1 = -4853 * r - 9530 * g + 14383 * b; - v1 = 14386 * r - 12046 * g - 2340 * b; + if (argc-1 == 1) + ifP = pm_openr(argv[1]); + else + ifP = stdin; - pP++; - /* second pixel just yields a Y and 0.25 U, 0.25 V */ - r = PPM_GETR(*pP); - g = PPM_GETG(*pP); - b = PPM_GETB(*pP); + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); - y2 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y1); - u2 = -2426 * r - 4765 * g + 7191 * b; - v2 = 7193 * r - 6023 * g - 1170 * b; + if (cols % 2 != 0) + pm_error("Image must have even number of columns.\n" + "This image is %u columns wide. Try Pamcut.", cols); - /* filter the chroma */ - u = u0 + u1 + u2 + (0xffff & u); - v = v0 + v1 + v2 + (0xffff & v); + pixelrow = ppm_allocrow(cols); + yuvBuf = (unsigned char *) pm_allocrow(cols, 2); - u0 = u2; - v0 = v2; + for (row = 0, u = v = u0 = v0 = y2Carry = 0; row < rows; ++row) { + ppm_readppmrow(ifP, pixelrow, cols, maxval, format); - *yuvptr++ = (u >> 16) + 128; - *yuvptr++ = (y1 >> 16) + 16; - *yuvptr++ = (v >> 16) + 128; - *yuvptr++ = (y2 >> 16) + 16; - } - fwrite(yuvbuf, cols*2, 1, stdout); - } + convertRow(pixelrow, cols, yuvBuf, &u, &v, &u0, &v0, &y2Carry); + + fwrite(yuvBuf, cols*2, 1, stdout); + } - pm_close(ifp); + pm_close(ifP); - exit(0); + return 0; } diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c index ad16a649..6ba4cb40 100644 --- a/converter/ppm/sldtoppm.c +++ b/converter/ppm/sldtoppm.c @@ -26,23 +26,20 @@ #include <string.h> #include <math.h> +#include "pm_c_util.h" #include "ppm.h" #include "ppmdraw.h" #include "nstring.h" -#ifdef DEBUG #include <assert.h> -#else -#define assert(x) -#endif + +#include "autocad.h" /* AutoCAD standard color assignments */ + /* Define a variable type accepting numbers -127 <= n <= 127. But note that we still expect it to act UNSIGNED. */ #define smallint unsigned char /* Small integers */ -#define TRUE 1 -#define FALSE 0 - #define EOS '\0' /* Screen point */ @@ -70,18 +67,17 @@ typedef void (slvecfn)(struct svector * vec, int color); typedef void (slfloodfn)(struct spolygon * poly, int color); +static unsigned long const pixmaxval = 255; /* Largest pixel value */ + static int ixdots, iydots; /* Screen size in dots */ -static FILE *slfile; /* Slide file descriptor */ -static int blither = FALSE; /* Dump slide file information ? */ -static int info = FALSE; /* Print header information */ +static FILE * slfile; /* Slide file descriptor */ +static bool blither; /* Dump slide file information ? */ +static bool info; /* Print header information */ static pixel **pixels; /* Pixel map */ -static int pixcols, pixrows; /* Pixel map size */ -#define pixmaxval 255 /* Largest pixel value */ +static int pixcols, pixrows; /* Pixel map size */ static double uscale = -1; /* Uniform scale factor */ static int sxsize = -1, sysize = -1; /* Scale to X, Y size ? */ -#include "autocad.h" /* AutoCAD standard color assignments */ - /* Local variables */ struct slhead { @@ -94,11 +90,11 @@ struct slhead { char spad; /* Pad to even byte length */ }; -static int adjust = FALSE; /* Adjust to correct aspect ratio ? */ -static struct slhead slfrof; /* Slide file header */ -static long xfac, yfac; /* Aspect ratio scale factors */ +static bool adjust; /* Adjust to correct aspect ratio ? */ +static struct slhead slfrof; /* Slide file header */ +static long xfac, yfac; /* Aspect ratio scale factors */ -static int sdrawkcab; +static bool sdrawkcab; /* Slide drawing kinematic conversion of ass-backwards data flag */ @@ -108,7 +104,7 @@ static int sdrawkcab; */ static int -extend(smallint ch) { +extend(unsigned char const ch) { return ((int) ((ch & 0x80) ? (ch | ~0xFF) : ch)); } @@ -136,9 +132,9 @@ sli(void) { static int slib(void) { - smallint ch = 0; + unsigned char ch; - if (fread(&ch, sizeof ch, 1, slfile) != 1) { + if (fread(&ch, sizeof(ch), 1, slfile) != 1) { pm_error("error reading slide file"); } return extend(ch); @@ -171,22 +167,28 @@ slidefind(const char * const sname, char uname[32]; unsigned char libent[36]; long pos; + bool found; + bool eof; if (dironly) pm_message("Slides in library:"); else { - int i; + unsigned int i; const char * ip; ip = sname; /* initial value */ - for (i = 0; i < 31; i++) { - char ch = *ip++; + for (i = 0; i < 31; ++i) { + char const ch = *ip++; if (ch == EOS) break; - if (ucasen && ISLOWER(ch)) - ch = TOUPPER(ch); - uname[i] = ch; + + { + char const upperCh = + ucasen && islower(ch) ? toupper(ch) : ch; + + uname[i] = upperCh; + } } uname[i] = EOS; } @@ -199,31 +201,38 @@ slidefind(const char * const sname, } pos = 32; - /* Search for a slide with the requested name. */ + /* Search for a slide with the requested name or list the directory */ - while (TRUE) { - if ((fread(libent, 36, 1, slfile) != 1) || - (strlen((char *)libent) == 0)) { - if (dironly) { - return; - } - pm_error("slide %s not in library.", sname); - } + for (found = false, eof = false; !found && !eof; ) { + size_t readCt; + readCt = fread(libent, 36, 1, slfile); + if (readCt != 1) + eof = true; + else if (strlen((char *)libent) == 0) + eof = true; + } + if (!eof) { pos += 36; if (dironly) { pm_message(" %s", libent); } else if (streq((char *)libent, uname)) { - long dpos = (((((libent[35] << 8) | libent[34]) << 8) | - libent[33]) << 8) | libent[32]; + long dpos; + + dpos = (((((libent[35] << 8) | libent[34]) << 8) | + libent[33]) << 8) | libent[32]; + if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) { dpos -= pos; while (dpos-- > 0) getc(slfile); } - break; + found = true; } } + + if (!found && !dironly) + pm_error("slide '%s' not in library.", sname); } @@ -329,7 +338,7 @@ slider(slvecfn slvec, /* Process the header of the slide file. */ - sdrawkcab = FALSE; /* Initially guess byte order is OK */ + sdrawkcab = false; /* Initially guess byte order is OK */ fread(slfrof.slh, 17, 1, slfile); fread(&slfrof.sntype, sizeof(char), 1, slfile); fread(&slfrof.slevel, sizeof(char), 1, slfile); @@ -364,12 +373,12 @@ slider(slvecfn slvec, */ if (btest != rtest) { - sdrawkcab = TRUE; -#define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8) + sdrawkcab = true; + #define rshort(x) x = ((x >> 8) & 0xFF) | (x << 8) rshort(slfrof.sxdots); rshort(slfrof.sydots); rshort(slfrof.shwfill); -#undef rshort + #undef rshort } /* Dump the header if we're blithering. */ @@ -413,7 +422,7 @@ slider(slvecfn slvec, ixdots = slfrof.sxdots; iydots = slfrof.sydots; dsar = slfrof.sdsar; - adjust = FALSE; /* Mark no adjustment needed */ + adjust = false; /* Mark no adjustment needed */ } /* If there's a uniform scale factor specified, apply it. */ @@ -571,32 +580,42 @@ slider(slvecfn slvec, /* Main program. */ int -main(int argc, - char * argv[]) { +main(int argc, + const char * argv[]) { int argn; const char * const usage = "[-verbose] [-info] [-adjust] [-scale <s>]\n\ [-dir] [-lib|-Lib <name>]\n\ [-xsize|-width <x>] [-ysize|-height <y>] [sldfile]"; - int scalespec = FALSE, widspec = FALSE, hgtspec = FALSE, dironly = FALSE, - ucasen; + bool dironly; + bool hgtspec; + bool widspec; + bool scalespec; + bool ucasen; const char * slobber; /* Slide library item */ + pm_proginit(&argc, argv); + argn = 1; slobber = NULL; - - ppm_init(&argc, argv); - argn = 1; + dironly = false; + hgtspec = false; + widspec = false; + scalespec = false; + ucasen = false; + blither = false; + info = false; + adjust = false; while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') { if (pm_keymatch(argv[argn], "-verbose", 2)) { - blither = TRUE; + blither = true; } else if (pm_keymatch(argv[argn], "-adjust", 2)) { - adjust = TRUE; + adjust = true; } else if (pm_keymatch(argv[argn], "-dir", 2)) { - dironly = TRUE; + dironly = true; } else if (pm_keymatch(argv[argn], "-info", 2)) { - info = TRUE; + info = true; } else if (pm_keymatch(argv[argn], "-lib", 2)) { if (slobber) pm_error("already specified a library item"); @@ -616,7 +635,7 @@ main(int argc, if (uscale <= 0.0) { pm_error("scale factor must be greater than 0"); } - scalespec = TRUE; + scalespec = true; } else if (pm_keymatch(argv[argn], "-xsize", 2) || pm_keymatch(argv[argn], "-width", 2)) { if (widspec) { @@ -625,7 +644,7 @@ main(int argc, argn++; if ((argn == argc) || (sscanf(argv[argn], "%d", &sxsize) != 1)) pm_usage(usage); - widspec = TRUE; + widspec = true; } else if (pm_keymatch(argv[argn], "-ysize", 2) || pm_keymatch(argv[argn], "-height", 2)) { if (hgtspec) { @@ -634,7 +653,7 @@ main(int argc, argn++; if ((argn == argc) || (sscanf(argv[argn], "%d", &sysize) != 1)) pm_usage(usage); - hgtspec = TRUE; + hgtspec = true; } else { pm_usage(usage); } @@ -665,7 +684,7 @@ main(int argc, if (!dironly) { slider(draw, flood); - ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, FALSE); + ppm_writeppm(stdout, pixels, pixcols, pixrows, pixmaxval, 0); } pm_close(slfile); pm_close(stdout); diff --git a/converter/ppm/winicontoppm.c b/converter/ppm/winicontoppm.c index 014eab40..6b1376b2 100644 --- a/converter/ppm/winicontoppm.c +++ b/converter/ppm/winicontoppm.c @@ -31,10 +31,9 @@ #define MAJVERSION 0 #define MINVERSION 4 -static int file_offset = 0; /* not actually used, but useful for debug */ +static int fileOffset = 0; /* not actually used, but useful for debug */ static const char er_read[] = "%s: read error"; static const char * infname; -static FILE * ifp; struct cmdlineInfo { /* All the information the user supplied in the command line, @@ -53,8 +52,8 @@ struct cmdlineInfo { static void -parseCommandLine ( int argc, char ** argv, - struct cmdlineInfo *cmdlineP ) { +parseCommandLine (int argc, const char ** argv, + struct cmdlineInfo *cmdlineP ) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc and argv. Return the information in the options as *cmdlineP. @@ -65,13 +64,15 @@ parseCommandLine ( int argc, 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 = malloc(100*sizeof(optEntry)); + optEntry * option_def; /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; unsigned int option_def_index; + MALLOCARRAY(option_def, 100); + option_def_index = 0; /* incremented by OPTENT3 */ OPTENT3(0, "allicons", OPT_FLAG, NULL, &cmdlineP->allicons, 0 ); @@ -88,10 +89,9 @@ parseCommandLine ( int argc, char ** argv, 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, argv, opt, sizeof(opt), 0); + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ - if (argc-1 < 1) cmdlineP->inputFilespec = "-"; else @@ -116,37 +116,37 @@ parseCommandLine ( int argc, char ** argv, static int -GetByte(void) { +GetByte(FILE * const ifP) { + int v; - if ((v = getc(ifp)) == EOF) - { + v = getc(ifP); + if (v == EOF) pm_error(er_read, infname); - } return v; } + + static short -GetShort(void) { +GetShort(FILE * const ifP) { + short v; - if (pm_readlittleshort(ifp, &v) == -1) - { - pm_error(er_read, infname); - } - + pm_readlittleshort(ifP, &v); + return v; } + + static long -GetLong(void) { +GetLong(FILE * const ifP) { + long v; - if (pm_readlittlelong(ifp, &v) == -1) - { - pm_error(er_read, infname); - } + pm_readlittlelong(ifP, &v); return v; } @@ -158,14 +158,18 @@ GetLong(void) { * functions. */ static u1 -readU1 (void) { - file_offset++; - return GetByte(); +readU1(FILE * const ifP) { + + ++fileOffset; + + return GetByte(ifP); } + + static u1 * -readU1String (int length) -{ +readU1String (FILE * const ifP, + unsigned int const length) { u1 * string; @@ -173,150 +177,173 @@ readU1String (int length) if (string == NULL) pm_error("out of memory"); - fread(string,sizeof(u1),length,ifp); + fread(string, sizeof(u1), length, ifP); string[length] = 0; - file_offset += length * sizeof(u1); + fileOffset += length * sizeof(u1); + return string; } + + static u2 -readU2 (void) { - file_offset +=2; - return GetShort(); +readU2 (FILE * const ifP) { + + fileOffset +=2; + + return GetShort(ifP); } + + static u4 -readU4 (void) { - file_offset += 4; - return GetLong(); +readU4 (FILE * const ifP) { + + fileOffset += 4; + + return GetLong(ifP); } + + static IC_Entry -readICEntry (void) -{ - IC_Entry entry; +readICEntry(FILE * const ifP) { + + IC_Entry entryP; - MALLOCVAR(entry); + MALLOCVAR(entryP); - if (entry == NULL) + if (entryP == NULL) pm_error("Unable to allcoate memory for IC entry"); - entry->width = readU1(); - entry->height = readU1(); - entry->color_count = readU1(); - entry->reserved = readU1(); - entry->planes = readU2(); - entry->bitcount = readU2(); - entry->size_in_bytes = readU4(); - entry->file_offset = readU4(); - entry->colors = NULL; - entry->ih = NULL; - entry->xorBitmap = NULL; - entry->andBitmap = NULL; + entryP->width = readU1(ifP); + entryP->height = readU1(ifP); + entryP->color_count = readU1(ifP); + entryP->reserved = readU1(ifP); + entryP->planes = readU2(ifP); + entryP->bitcount = readU2(ifP); + entryP->size_in_bytes = readU4(ifP); + entryP->file_offset = readU4(ifP); + entryP->colors = NULL; + entryP->ih = NULL; + entryP->xorBitmap = NULL; + entryP->andBitmap = NULL; - return entry; + return entryP; } static IC_InfoHeader -readInfoHeader (IC_Entry entry) -{ - IC_InfoHeader ih; +readInfoHeader (FILE * const ifP, + IC_Entry const entryP) { + + IC_InfoHeader ihP; - MALLOCVAR(ih); + MALLOCVAR(ihP); - if (ih == NULL) + if (ihP == NULL) pm_error("Unable to allocate memory for info header"); - ih->size = readU4(); - ih->width = readU4(); - ih->height = readU4(); - ih->planes = readU2(); - ih->bitcount = readU2(); - ih->compression = readU4(); - ih->imagesize = readU4(); - ih->x_pixels_per_m = readU4(); - ih->y_pixels_per_m = readU4(); - ih->colors_used = readU4(); - ih->colors_important = readU4(); + ihP->size = readU4(ifP); + ihP->width = readU4(ifP); + ihP->height = readU4(ifP); + ihP->planes = readU2(ifP); + ihP->bitcount = readU2(ifP); + ihP->compression = readU4(ifP); + ihP->imagesize = readU4(ifP); + ihP->x_pixels_per_m = readU4(ifP); + ihP->y_pixels_per_m = readU4(ifP); + ihP->colors_used = readU4(ifP); + ihP->colors_important = readU4(ifP); - if (!entry->bitcount) entry->bitcount = ih->bitcount; - if (entry->color_count == 0 && - entry->bitcount <= 8) entry->color_count = 256; - if (ih->compression) { + if (!entryP->bitcount) + entryP->bitcount = ihP->bitcount; + + if (entryP->color_count == 0 && entryP->bitcount <= 8) + entryP->color_count = 256; + + if (ihP->compression) { pm_error("Can't handle compressed icons"); } - return ih; + return ihP; } -/* - * I don't know why this isn't the same as the spec, it just <b>isn't</b> - * The colors honestly seem to be stored BGR. Bizarre. - * - * I've checked this in the BMP code for bmptoppm and the gimp. Guess the - * spec I have is just plain wrong. - */ + + static IC_Color -readICColor (void) -{ - IC_Color col; +readICColor(FILE * const ifP) { + + IC_Color colorP; - MALLOCVAR(col); + MALLOCVAR(colorP); - if (col == NULL) + if (colorP == NULL) pm_error("Unable to allocate memory for color"); - col->blue = readU1(); - col->green = readU1(); - col->red = readU1(); - col->reserved = readU1(); - return col; + /* I don't know why this isn't the same as the spec, it just isn't. + The colors honestly seem to be stored BGR. Bizarre. + + I've checked this in the BMP code for bmptoppm and the gimp. Guess the + spec I have is just plain wrong. + */ + + colorP->blue = readU1(ifP); + colorP->green = readU1(ifP); + colorP->red = readU1(ifP); + colorP->reserved = readU1(ifP); + + return colorP; } -/* - * Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the - * encoding mechanism is different. - * - * 8bpp => 1 byte/palette index. - * 4bpp => High Nibble, Low Nibble - * 1bpp => 1 palette value per bit, high bit 1st. - */ static u1 * -read1Bitmap (int width, int height) -{ - int tmp; - int xBytes; +read1Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + unsigned int xByteCt; u1 * bitmap; - int wt = width; + unsigned int wt; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); - wt >>= 3; - if (wt & 3) { - wt = (wt & ~3) + 4; + /* Depending on if the image is stored as 1bpp, 4bpp or 8bpp, the + encoding mechanism is different. + + 8bpp => 1 byte/palette index. + 4bpp => High Nibble, Low Nibble + 1bpp => 1 palette value per bit, high bit 1st. + */ + + wt = width >> 3; + + if ((wt & 0x3) != 0) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp<height; tmp++ ) { - int x; - int rowByte = 0; - int xOrVal = 128; - u1 * row = readU1String(xBytes); - for (x = 0; x< width; x++) { - *(bitmap+((height-tmp-1)*width) + (x)) = - (row[rowByte] & xOrVal) / xOrVal; - if (xOrVal == 1) { - xOrVal = 128; - rowByte++; - } else { + xByteCt = wt; + + for (row = 0; row < height; ++row) { + u1 * const imgRow = readU1String(ifP, xByteCt); + + unsigned int col; + unsigned int rowByte; + unsigned int xOrVal; + + for (col = 0, rowByte = 0, xOrVal = 0x80; col < width; ++col) { + *(bitmap+((height - row - 1) * width) + col) = + (imgRow[rowByte] & xOrVal) / xOrVal; + if (xOrVal == 0x01) { + xOrVal = 0x80; + ++rowByte; + } else xOrVal >>= 1; - } } - free(row); + free(imgRow); } return bitmap; } @@ -324,43 +351,46 @@ read1Bitmap (int width, int height) static u1 * -read4Bitmap (int width, int height) -{ - int tmp; +read4Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; u1 * bitmap; - int wt = width; - int xBytes; + unsigned int wt; + unsigned int xByteCt; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); + wt = width >> 1; - wt >>= 1; - if (wt & 3) { - wt = (wt & ~3) + 4; + if (wt & 0x3) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp<height ; tmp++ ) { - int rowByte = 0; - int bottom = 1; - int x; - u1 * row = readU1String(xBytes); - for (x = 0; x< width; x++) { - /* - * 2 nibbles, 2 values. - */ + xByteCt = wt; + + for (row = 0; row < height; ++row) { + u1 * const imgRow = readU1String(ifP, xByteCt); + + unsigned int rowByte; + bool bottom; + unsigned int col; + for (col = 0, rowByte = 0, bottom = true; col < width; ++col) { + /* 2 nibbles, 2 values */ if (bottom) { - *(bitmap+((height-tmp-1)*width) + (x)) = - (row[rowByte] & 0xF0) >> 4; + *(bitmap + ((height - row - 1) * width) + col) = + (imgRow[rowByte] & 0xF0) >> 4; } else { - *(bitmap+((height-tmp-1)*width) + (x)) = (row[rowByte] & 0xF); - rowByte++; + *(bitmap + ((height - row -1) * width) + col) = + (imgRow[rowByte] & 0xF); + ++rowByte; } bottom = !bottom; } - free(row); + free(imgRow); } return bitmap; } @@ -368,52 +398,57 @@ read4Bitmap (int width, int height) static u1 * -read8Bitmap (int width, int height) -{ - int tmp; - unsigned int xBytes; - unsigned int wt = width; +read8Bitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height) { + + unsigned int row; + unsigned int xByteCt; + unsigned int wt; u1 * bitmap; MALLOCARRAY(bitmap, width * height); if (bitmap == NULL) pm_error("out of memory"); - if (wt & 3) { - wt = (wt & ~3) + 4; + wt = width; + if (wt & 0x3) { + wt = (wt & ~0x3) + 4; } - xBytes = wt; - for (tmp = 0; tmp<height ; tmp++ ) { - int rowByte = 0; - int x; - u1 * row = readU1String(xBytes); - for ( x = 0; x< width; x++) { - *(bitmap+((height-tmp-1)*width) + (x)) = row[rowByte]; - rowByte++; - } - free(row); + xByteCt = wt; + + for (row = 0; row < height; ++row) { + u1 * imgRow = readU1String(ifP, xByteCt); + + unsigned int rowByte; + unsigned int col; + for (col = 0, rowByte = 0; col < width; ++col) + *(bitmap + ((height - row - 1) * width) + col) = imgRow[rowByte++]; + + free(imgRow); } return bitmap; } -/* - * Read a true color bitmap. (24/32 bits) - * - * The output routine deplanarizes it for us, we keep it flat here. - */ static u1 * -readXBitmap (int const width, - int const height, - int const bpp) { - int const bytes = bpp >> 3; - unsigned int const xBytes = width * bytes; +readXBitmap (FILE * const ifP, + unsigned int const width, + unsigned int const height, + unsigned int const bpp) { +/*---------------------------------------------------------------------------- + Read a true color bitmap. (24/32 bits) + + The output routine deplanarizes it for us, we keep it flat here. +-----------------------------------------------------------------------------*/ + unsigned int const byteCt = bpp >> 3; + unsigned int const xByteCt = width * byteCt; u1 * bitmap; /* remember - bmp (dib) stored upside down, so reverse */ - MALLOCARRAY(bitmap, bytes * width * height); + MALLOCARRAY(bitmap, byteCt * width * height); if (bitmap == NULL) pm_error("out of memory allocating bitmap array"); @@ -421,12 +456,12 @@ readXBitmap (int const width, unsigned int i; u1 * bitcurptr; - for (i = 0, bitcurptr = &bitmap[bytes * width * (height-1)]; + for (i = 0, bitcurptr = &bitmap[byteCt * width * (height-1)]; i < height; - ++i, bitcurptr -= xBytes) { + ++i, bitcurptr -= xByteCt) { - u1 * const row = readU1String(xBytes); - memcpy(bitcurptr, row, xBytes); + u1 * const row = readU1String(ifP, xByteCt); + memcpy(bitcurptr, row, xByteCt); free(row); } } @@ -436,80 +471,70 @@ readXBitmap (int const width, static MS_Ico -readIconFile (bool const verbose) { - int iter,iter2; +readIconFile(FILE * const ifP, + bool const verbose) { + + unsigned int i; MS_Ico MSIconData; MALLOCVAR(MSIconData); - /* - * reserved - should equal 0. - */ - MSIconData->reserved = readU2(); - /* - * Type - should equal 1 - */ - MSIconData->type = readU2(); - /* - * count - no of icons in file.. - */ - MSIconData->count = readU2(); - /* - * Allocate "count" array of entries. - */ + MSIconData->reserved = readU2(ifP); /* should be 0 */ + MSIconData->type = readU2(ifP); /* should be 1 */ + MSIconData->count = readU2(ifP); /* # icons in file */ + if (verbose) pm_message("Icon file contains %d icons.", MSIconData->count); MALLOCARRAY(MSIconData->entries, MSIconData->count); if (MSIconData->entries == NULL) pm_error("out of memory"); - /* - * Read in each of the entries - */ - for (iter = 0;iter < MSIconData->count ; iter++ ) { - MSIconData->entries[iter] = readICEntry(); - } - /* After that, we have to read in the infoheader, color map (if - * any) and the actual bit/pix maps for the icons. - */ + + /* Read in each of the entries */ + for (i = 0; i < MSIconData->count; ++i) + MSIconData->entries[i] = readICEntry(ifP); + + /* Read in the infoheader, color map (if any) and the actual bit/pix maps + for the icons. + */ if (verbose) - fprintf (stderr,"#\tColors\tBPP\tWidth\tHeight\n"); - for (iter = 0;iter < MSIconData->count ; iter++ ) { - int bpp; - MSIconData->entries[iter]->ih = - readInfoHeader (MSIconData->entries[iter]); + pm_message("#\tColors\tBPP\tWidth\tHeight\n"); + + for (i = 0; i < MSIconData->count; ++i) { + unsigned int bpp; /* bits per pixel */ + + MSIconData->entries[i]->ih = + readInfoHeader(ifP, MSIconData->entries[i]); - /* What's the bits per pixel? */ - bpp = MSIconData->entries[iter]->bitcount; + bpp = MSIconData->entries[i]->bitcount; + /* Read the palette, if appropriate */ switch (bpp) { case 24: case 32: /* 24/32 bpp icon has no palette */ break; - default: - MALLOCARRAY(MSIconData->entries[iter]->colors, - MSIconData->entries[iter]->color_count); - if (MSIconData->entries[iter]->colors == NULL) + default: { + unsigned int j; + + MALLOCARRAY(MSIconData->entries[i]->colors, + MSIconData->entries[i]->color_count); + if (MSIconData->entries[i]->colors == NULL) pm_error("out of memory"); - for (iter2 = 0; - iter2 < MSIconData->entries[iter]->color_count ; - iter2++ ) { - MSIconData->entries[iter]->colors[iter2] = readICColor(); - } - break; + for (j = 0; j < MSIconData->entries[i]->color_count; ++j) + MSIconData->entries[i]->colors[j] = readICColor(ifP); + } } if (verbose) { - char cols_text[10]; - sprintf (cols_text, "%d", MSIconData->entries[iter]->color_count); - fprintf (stderr, - "%d\t%s\t%d\t%d\t%d\n", iter, - MSIconData->entries[iter]->color_count ? - cols_text : "TRUE", - bpp, MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + char colsText[10]; + sprintf (colsText, "%d", MSIconData->entries[i]->color_count); + pm_message("%d\t%s\t%d\t%d\t%d\n", i, + MSIconData->entries[i]->color_count ? + colsText : "TRUE", + bpp, MSIconData->entries[i]->width, + MSIconData->entries[i]->height); } /* Pixels are stored bottom-up, left-to-right. Pixel lines are * padded with zeros to end on a 32bit (4byte) boundary. Every @@ -528,35 +553,40 @@ readIconFile (bool const verbose) { */ switch (bpp) { case 1: - MSIconData->entries[iter]->xorBitmap = - read1Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read1Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 4: - MSIconData->entries[iter]->xorBitmap = - read4Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read4Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 8: - MSIconData->entries[iter]->xorBitmap = - read8Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->xorBitmap = + read8Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); break; case 24: case 32: - MSIconData->entries[iter]->xorBitmap = - readXBitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height,bpp); + MSIconData->entries[i]->xorBitmap = + readXBitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height,bpp); break; default: - pm_error("Uncatered bit depth %d",bpp); + pm_error("Uncatered bit depth %u", bpp); } /* * Read AND Bitmap */ - MSIconData->entries[iter]->andBitmap = - read1Bitmap(MSIconData->entries[iter]->width, - MSIconData->entries[iter]->height); + MSIconData->entries[i]->andBitmap = + read1Bitmap(ifP, + MSIconData->entries[i]->width, + MSIconData->entries[i]->height); } } @@ -566,15 +596,14 @@ readIconFile (bool const verbose) { static char * -trimOutputName(const char inputName[]) -{ +trimmedOutputName(const char inputName[]) { /* * Just trim off the final ".ppm", if there is one, else return as is. * oh, for =~ ... :) */ - char * outFile = strdup(inputName); - if (streq(outFile + (strlen (outFile) - 4), ".ppm")) { - *(outFile + (strlen (outFile) - 4)) = 0; + char * const outFile = strdup(inputName); + if (streq(outFile + (strlen(outFile) - 4), ".ppm")) { + *(outFile + (strlen(outFile) - 4)) = 0; } return outFile; @@ -585,29 +614,34 @@ trimOutputName(const char inputName[]) static int getBestQualityIcon(MS_Ico MSIconData) { - int x,best,best_size,best_bpp,bpp,size; - IC_Entry entry; - - best_size = best_bpp = 0; - for (x = 0; x < MSIconData->count; x++) { - entry = MSIconData->entries[x]; - size = entry->width * entry->height; - bpp = entry->bitcount ? entry->bitcount : entry->ih->bitcount; - if (size > best_size) { - best = x; - best_size = size; - } else if (size == best_size && bpp > best_bpp) { - best = x; - best_bpp = bpp; + unsigned int i; + unsigned int best; + unsigned int bestSize; + unsigned int bestBpp; + + for (i = 0, bestSize = 0, bestBpp = 0; i < MSIconData->count; ++i) { + IC_Entry const entryP = MSIconData->entries[i]; + unsigned int const size = entryP->width * entryP->height; + unsigned int const bpp = + entryP->bitcount ? entryP->bitcount : entryP->ih->bitcount; + + if (size > bestSize) { + best = i; + bestSize = size; + } else if (size == bestSize && bpp > bestBpp) { + best = i; + bestBpp = bpp; } } return best; } + + static void writeXors(FILE * const multiOutF, - char outputFileBase[], - IC_Entry const entry, + char * const outputFileBase, + IC_Entry const entryP, int const entryNum, bool const multiple, bool const xor) { @@ -625,85 +659,79 @@ writeXors(FILE * const multiOutF, we are to open a file using outputFileBase[] and 'entryNum' and 'xor' to derive its name, and close it afterward. -----------------------------------------------------------------------------*/ - FILE * outF; - pixel ** ppm_array; - int row; - int pel_size; - const char *outputFile; - int maxval; - int forcetext; + FILE * ofP; + pixel ** pixArray; + unsigned int row; + const char * outputFileName; if (multiOutF) { - outF = multiOutF; - outputFile = strdup(""); + ofP = multiOutF; + outputFileName = strdup(""); } else { if (outputFileBase) { if (multiple) { - pm_asprintf(&outputFile, "%s%s_%d.ppm", + pm_asprintf(&outputFileName, "%s%s_%d.ppm", outputFileBase,(xor ? "_xor" : ""), entryNum); } else { - pm_asprintf(&outputFile, "%s%s.ppm", + pm_asprintf(&outputFileName, "%s%s.ppm", outputFileBase,(xor ? "_xor" : "")); } } else - outputFile = strdup("-"); + outputFileName = strdup("-"); - outF = pm_openw(outputFile); + ofP = pm_openw(outputFileName); } /* - * allocate an array to save the bmp data into. - * note that entry->height will be 1/2 entry->ih->height, - * as the latter adds "and" and "xor" height. - */ - ppm_array = ppm_allocarray(entry->width, entry->height); - for (row=0; row < entry->height; row++) { - u1 * xorRow; - int col; - switch (entry->bitcount) { + Allocate an array to save the bmp data into. + note that entry->height will be 1/2 entry->ih->height, + as the latter adds "and" and "xor" height. + */ + pixArray = ppm_allocarray(entryP->width, entryP->height); + for (row = 0; row < entryP->height; ++row) { + switch (entryP->bitcount) { case 24: - case 32: - pel_size = entry->bitcount >> 3; - xorRow = entry->xorBitmap + row * entry->width * pel_size; - for (col=0; col < entry->width*pel_size;col+=pel_size) { - PPM_ASSIGN(ppm_array[row][col/pel_size], - xorRow[col+2],xorRow[col+1],xorRow[col]); - } - break; - default: - xorRow = entry->xorBitmap + row * entry->width; - for (col=0; col < entry->width; col++) { - int colorIndex; - IC_Color color; - colorIndex = xorRow[col]; - color = entry->colors[colorIndex]; - PPM_ASSIGN(ppm_array[row][col], - color->red,color->green,color->blue); + case 32: { + unsigned int const pixelSize = entryP->bitcount >> 3; + u1 * const xorRow = + entryP->xorBitmap + row * entryP->width * pixelSize; + unsigned int col; + for (col = 0; col < entryP->width * pixelSize; col += pixelSize) + PPM_ASSIGN(pixArray[row][col/pixelSize], + xorRow[col+2], xorRow[col+1], xorRow[col]); + } break; + default: { + u1 * const xorRow = entryP->xorBitmap + row * entryP->width; + unsigned int col; + for (col = 0; col < entryP->width; ++col) { + unsigned int const colorIndex = xorRow[col]; + IC_Color const colorP = entryP->colors[colorIndex]; + PPM_ASSIGN(pixArray[row][col], + colorP->red, colorP->green, colorP->blue); } - break; + } break; } } - maxval = 255; - forcetext = 0; - - ppm_writeppm(outF,ppm_array,entry->width, entry->height, - (pixval) maxval, forcetext); - ppm_freearray(ppm_array,entry->height); + ppm_writeppm(ofP, pixArray, entryP->width, entryP->height, + 255 /* maxval */, false /* text */); + ppm_freearray(pixArray, entryP->height); - pm_strfree(outputFile); + pm_strfree(outputFileName); if (!multiOutF) - pm_close(outF); + pm_close(ofP); } static void -writeAnds(FILE * const multiOutF, - char outputFileBase[], IC_Entry const entry, int const entryNum, - bool multiple) { +writeAnds(FILE * const multiOutF, + char const outputFileBase[], + IC_Entry const entryP, + unsigned int const entryNum, + bool const multiple) { /*---------------------------------------------------------------------------- - Write the "and" image (i.e. the alpha mask) of the image 'IC_Entry' out. + Write the "and" image (i.e. the alpha mask) of the image *entryP out. 'multiple' means this is one of multiple images that are being written. 'entryNum' is the sequence number within the winicon file of the image @@ -714,115 +742,122 @@ writeAnds(FILE * const multiOutF, we are to open a file using outputFileBase[] and 'entryNum' and 'xor' to derive its name, and close it afterward. -----------------------------------------------------------------------------*/ - FILE * outF; - bit ** pbm_array; - u1 * andRow; - int row; + FILE * ofP; + bit ** bitArray; + unsigned int row; if (multiOutF) - outF = multiOutF; + ofP = multiOutF; else { - const char *outputFile; + const char * outputFileName; assert(outputFileBase); if (multiple) - pm_asprintf(&outputFile, "%s_and_%d.pbm", + pm_asprintf(&outputFileName, "%s_and_%u.pbm", outputFileBase, entryNum); else - pm_asprintf(&outputFile, "%s_and.pbm", outputFileBase); - outF = pm_openw(outputFile); - pm_strfree(outputFile); + pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase); + ofP = pm_openw(outputFileName); + pm_strfree(outputFileName); } - pbm_array = pbm_allocarray(entry->width, entry->height); - for (row=0; row < entry->height; row++) { - int col; - andRow = entry->andBitmap + row * entry->width; - for (col=0; col < entry->width; col++) { + bitArray = pbm_allocarray(entryP->width, entryP->height); + for (row = 0; row < entryP->height; ++row) { + u1 * const andRow = entryP->andBitmap + row * entryP->width; + unsigned int col; + for (col = 0; col < entryP->width; ++col) { /* Note: black is transparent in a Netpbm alpha mask */ - pbm_array[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE; + bitArray[row][col] = andRow[col] ? PBM_BLACK: PBM_WHITE; } } - pbm_writepbm(outF, pbm_array, entry->width, entry->height, 0); + pbm_writepbm(ofP, bitArray, entryP->width, entryP->height, 0); - pbm_freearray(pbm_array, entry->height); + pbm_freearray(bitArray, entryP->height); if (!multiOutF) - pm_close (outF); + pm_close(ofP); } static void -openMultiXor(char outputFileBase[], +openMultiXor(char const outputFileBase[], bool const writeands, FILE ** const multiOutFP) { - const char *outputFile; + const char * outputFileName; if (outputFileBase) { - pm_asprintf(&outputFile, "%s%s.ppm", + pm_asprintf(&outputFileName, "%s%s.ppm", outputFileBase, (writeands ? "_xor" : "")); } else - outputFile = strdup("-"); + outputFileName = strdup("-"); - /* - * Open the output file now, it'll stay open the whole time. - */ - *multiOutFP = pm_openw(outputFile); + *multiOutFP = pm_openw(outputFileName); - pm_strfree(outputFile); + pm_strfree(outputFileName); } static void -openMultiAnd(char outputFileBase[], FILE ** const multiAndOutFP) { +openMultiAnd(char const outputFileBase[], + FILE ** const multiAndOutFP) { - const char *outputFile; + const char * outputFileName; assert(outputFileBase); - pm_asprintf(&outputFile, "%s_and.pbm", outputFileBase); + pm_asprintf(&outputFileName, "%s_and.pbm", outputFileBase); - *multiAndOutFP = pm_openw(outputFile); + *multiAndOutFP = pm_openw(outputFileName); - pm_strfree(outputFile); + pm_strfree(outputFileName); } -static void free_iconentry(IC_Entry entry) { - int x; - if (entry->colors && entry->color_count) { - for (x=0;x<entry->color_count;x++) free(entry->colors[x]); - free(entry->colors); + + +static void +freeIconentry(IC_Entry const entryP) { + + if (entryP->colors && entryP->color_count) { + unsigned int i; + for (i = 0; i <entryP->color_count; ++i) + free(entryP->colors[i]); + free(entryP->colors); } - if (entry->andBitmap) free(entry->andBitmap); - if (entry->xorBitmap) free(entry->xorBitmap); - if (entry->ih) free(entry->ih); - free(entry); + if (entryP->andBitmap) free(entryP->andBitmap); + if (entryP->xorBitmap) free(entryP->xorBitmap); + if (entryP->ih) free(entryP->ih); + free(entryP); } -static void free_icondata(MS_Ico MSIconData) -{ - int x; - for (x=0;x<MSIconData->count;x++) { - free_iconentry(MSIconData->entries[x]); - } - free(MSIconData); + + +static void +freeIcondata(MS_Ico const MSIconDataP) { + + unsigned int i; + for (i = 0; i < MSIconDataP->count; ++i) + freeIconentry(MSIconDataP->entries[i]); + + free(MSIconDataP); } + int -main(int argc, char *argv[]) { +main(int argc, const char *argv[]) { struct cmdlineInfo cmdline; - int startEntry, endEntry; - MS_Ico MSIconData; + FILE * ifP; + unsigned int startEntry, endEntry; + MS_Ico MSIconDataP; char * outputFileBase; FILE * multiOutF; FILE * multiAndOutF; - ppm_init (&argc, argv); + pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); @@ -833,13 +868,13 @@ main(int argc, char *argv[]) { if (streq(cmdline.outputFilespec, "-")) outputFileBase = NULL; else - outputFileBase = trimOutputName(cmdline.outputFilespec); + outputFileBase = trimmedOutputName(cmdline.outputFilespec); - ifp = pm_openr(cmdline.inputFilespec); + ifP = pm_openr(cmdline.inputFilespec); infname = cmdline.inputFilespec; - MSIconData = readIconFile(cmdline.verbose); + MSIconDataP = readIconFile(ifP, cmdline.verbose); /* * Now we've read the icon file in (Hopefully! :) * Go through each of the entries, and write out files of the @@ -853,18 +888,15 @@ main(int argc, char *argv[]) { /* * If allicons is set, we want everything, if not, just go through once. */ - startEntry = 0; - if (cmdline.allicons) { - endEntry = MSIconData->count; - } else { - endEntry = 1; - } - /* - * If bestqual is set, find the icon with highest size & bpp. - */ if (cmdline.bestqual) { - startEntry = getBestQualityIcon(MSIconData); + startEntry = getBestQualityIcon(MSIconDataP); endEntry = startEntry+1; + } else { + startEntry = 0; + if (cmdline.allicons) + endEntry = MSIconDataP->count; + else + endEntry = 1; } if (cmdline.multippm) @@ -878,24 +910,25 @@ main(int argc, char *argv[]) { multiAndOutF = NULL; { - int entryNum; + unsigned int entryNum; - for (entryNum = startEntry ; entryNum < endEntry ; entryNum++ ) { - IC_Entry const entry = MSIconData->entries[entryNum]; + for (entryNum = startEntry; entryNum < endEntry; ++entryNum) { + IC_Entry const entryP = MSIconDataP->entries[entryNum]; - writeXors(multiOutF, outputFileBase, entry, entryNum, + writeXors(multiOutF, outputFileBase, entryP, entryNum, cmdline.allicons, cmdline.writeands); if (cmdline.writeands) writeAnds(multiAndOutF, outputFileBase, - entry, entryNum, cmdline.allicons); + entryP, entryNum, cmdline.allicons); } } if (multiOutF) - pm_close (multiOutF); + pm_close(multiOutF); if (multiAndOutF) pm_close(multiAndOutF); /* free up the image data here. */ - free_icondata(MSIconData); + freeIcondata(MSIconDataP); + return 0; } diff --git a/converter/ppm/yuvtoppm.c b/converter/ppm/yuvtoppm.c index 2b44c65f..151ff9f9 100644 --- a/converter/ppm/yuvtoppm.c +++ b/converter/ppm/yuvtoppm.c @@ -20,96 +20,201 @@ ** implied warranty. */ -#include "ppm.h" +#include "pm_c_util.h" #include "mallocvar.h" +#include "shhopt.h" +#include "ppm.h" -/* x must be signed for the following to work correctly */ -#define limit(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16) -int -main(argc, argv) - char **argv; -{ - FILE *ifp; - pixel *pixrow; - int argn, rows, cols, row; - const char * const usage = "<width> <height> [yuvfile]"; - struct yuv { - /* This is an element of a YUV file. It describes two - side-by-side pixels. - */ - unsigned char u; - unsigned char y1; - unsigned char v; - unsigned char y2; - } *yuvbuf; - - ppm_init(&argc, argv); - - argn = 1; - - if (argn + 2 > argc) - pm_usage(usage); - - cols = atoi(argv[argn++]); - rows = atoi(argv[argn++]); - if (cols <= 0 || rows <= 0) - pm_usage(usage); - - if (argn < argc) { - ifp = pm_openr(argv[argn]); - ++argn; - } else - ifp = stdin; - - if (argn != argc) - pm_usage(usage); - - if (cols % 2 != 0) { - pm_error("Number of columns (%d) is odd. A YUV image must have an " - "even number of columns.", cols); + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + unsigned int cols; + unsigned int rows; + const char * inputFileName; /* Name of input file */ +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { + + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options */ + optStruct3 opt; + + MALLOCARRAY_NOFAIL(option_def, 100); + + OPTENTINIT; + + 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 */ + + pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); + /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + + if (argc-1 < 2) + pm_error("You need at least two arguments: width and height in " + "pixels. You specified %u", argc-1); + else { + int const widthArg = atoi(argv[1]); + int const heightArg = atoi(argv[2]); + + if (widthArg < 0) + pm_error("Negative number for width: %d", widthArg); + if (heightArg < 0) + pm_error("Negative number for height: %d", heightArg); + + cmdlineP->cols = widthArg; + cmdlineP->rows = heightArg; + + if (cmdlineP->cols % 2 != 0) + pm_error("Number of columns (%u) is odd. " + "A YUV image must have an " + "even number of columns.", cmdlineP->cols); + + if (argc-1 < 3) + cmdlineP->inputFileName = "-"; + else { + cmdlineP->inputFileName = argv[3]; + + if (argc-1 > 3) + pm_error("Too many arguments: %u. " + "The only possible arguments are " + "width, height, and input file name", argc-1); + } } +} - ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0); - pixrow = ppm_allocrow(cols); - MALLOCARRAY(yuvbuf, (cols+1)/2); - if (yuvbuf == NULL) - pm_error("Unable to allocate YUV buffer for %d columns.", cols); - for (row = 0; row < rows; ++row) { - int col; - fread(yuvbuf, cols * 2, 1, ifp); +static int +limit(int const x) { - for (col = 0; col < cols; col += 2) { - /* Produce two pixels in pixrow[] */ - int y1, u, v, y2, r, g, b; + if (x > 0xffffff) + return 0xff; + else if (x <= 0xffff) + return 0; + else + return ((x >> 16) & 0xff); +} + + + +static int +nonneg(int const x) { +/*---------------------------------------------------------------------------- + Raise 'x' to 0 if negative +-----------------------------------------------------------------------------*/ + return x < 0 ? 0 : x; +} + + + +struct Yuv { +/*---------------------------------------------------------------------------- + This is an element of a YUV file. It describes two side-by-side pixels. + + This is the actual layout of the data in the file (4 bytes). +-----------------------------------------------------------------------------*/ + unsigned char u; + unsigned char y1; + unsigned char v; + unsigned char y2; +}; - u = yuvbuf[col/2].u-128; - y1 = yuvbuf[col/2].y1 - 16; - if (y1 < 0) y1 = 0; - v = yuvbuf[col/2].v - 128; +static void +readYuv(FILE * const ifP, + struct Yuv * const yuvP) { - y2 = yuvbuf[col/2].y2 - 16; - if (y2 < 0) y2 = 0; + size_t readCt; - r = 104635 * v; - g = -25690 * u + -53294 * v; - b = 132278 * u; + readCt = fread(yuvP, sizeof(*yuvP), 1, ifP); - y1*=76310; y2*=76310; + if (readCt != 1) { + if (feof(ifP)) + pm_error("Premature end of input."); + else + pm_error("Error reading input."); + } +} + + + +static void +yuvtoppm(FILE * const ifP, + unsigned int const cols, + unsigned int const rows, + FILE * const ofP) { + + pixval const maxval = 255; + + pixel * pixrow; + unsigned int row; + + ppm_writeppminit(ofP, cols, rows, maxval, 0); + + pixrow = ppm_allocrow(cols); + + for (row = 0; row < rows; ++row) { + unsigned int col; + for (col = 0; col < cols; col += 2) { + /* Produce two pixels in pixrow[] */ + struct Yuv yuv; + int y1, u, v, y2, r, g, b; + + readYuv(ifP, &yuv); + + u = yuv.u - 128; + y1 = nonneg (yuv.y1 - 16); + v = yuv.v - 128; + y2 = nonneg (yuv.y2 - 16); + + r = 104635 * v; + g = -25690 * u + -53294 * v; + b = 132278 * u; + + y1 *= 76310; + y2 *= 76310; + + PPM_ASSIGN(pixrow[col], + limit(r + y1), limit(g + y1), limit(b + y1)); + PPM_ASSIGN(pixrow[col + 1], + limit(r + y2), limit(g + y2), limit(b + y2)); + } + ppm_writeppmrow(ofP, pixrow, cols, maxval, 0); + } - PPM_ASSIGN(pixrow[col], limit(r+y1), limit(g+y1), limit(b+y1)); - PPM_ASSIGN(pixrow[col+1], limit(r+y2), limit(g+y2), limit(b+y2)); - } - ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0); - } - free(yuvbuf); ppm_freerow(pixrow); - pm_close(ifp); - pm_close(stdout); - exit(0); + if (fgetc(ifP) != EOF) + pm_message("Extraneous data at end of image."); +} + + + +int +main (int argc, const char ** argv) { + + FILE * ifP; + struct CmdlineInfo cmdline; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + yuvtoppm(ifP, cmdline.cols, cmdline.rows, stdout); + + pm_close(ifP); + pm_close(stdout); + + return 0; } |