diff options
Diffstat (limited to 'converter/other/sgitopnm.c')
-rw-r--r-- | converter/other/sgitopnm.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c index ea2daef3..008d5376 100644 --- a/converter/other/sgitopnm.c +++ b/converter/other/sgitopnm.c @@ -5,6 +5,11 @@ ** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp) ** Available via ftp from sgi.com:graphics/SGIIMAGESPEC ** +** The definitive document describing the SGI image file format, +** SGI Image File Format Version 1.00 is available from +** ftp://ftp.sgi.com/graphics/grafica/sgiimage.html +** +** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that @@ -12,12 +17,9 @@ ** documentation. This software is provided "as is" without express or ** implied warranty. ** -** 29Jan94: first version -** 08Feb94: minor bugfix -** 29Jul00: added -channel option (smar@reptiles.org) -** 19Oct10: added checks for artihmetic overflows -** fixed problem with -channel on verbatim sgi images (afu) */ + + #include <unistd.h> #include <limits.h> #include "pm_c_util.h" @@ -28,12 +30,12 @@ -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; /* '-' if stdin */ - unsigned int verbose; + const char * inputFileName; /* '-' if stdin */ + unsigned int verbose; unsigned int channelSpec; unsigned int channel; }; @@ -42,10 +44,10 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- parse program command line described in Unix standard form by argc - and argv. Return the information in the options as *cmdlineP. + and argv. Return the information in the options as *cmdlineP. If command line is internally inconsistent (invalid options, etc.), issue error message to stderr and abort program. @@ -53,7 +55,7 @@ parseCommandLine(int argc, const char ** argv, Note that the strings we return are stored in the storage that was passed to us as the argv array. We also trash *argv. -----------------------------------------------------------------------------*/ - optEntry *option_def; + optEntry * option_def; /* Instructions to pm_optParseOptions3 on how to parse our options. */ optStruct3 opt; @@ -68,7 +70,7 @@ parseCommandLine(int argc, const char ** argv, &cmdlineP->channelSpec, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); - OPTENT3(0, "noverbose", OPT_FLAG, NULL, + OPTENT3(0, "noverbose", OPT_FLAG, NULL, NULL, 0); /* backward compatibility */ opt.opt_table = option_def; @@ -78,6 +80,8 @@ parseCommandLine(int argc, const char ** argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); /* Uses and sets argc, argv, and some of *cmdlineP and others. */ + free(option_def); + if (argc-1 < 1) cmdlineP->inputFileName = "-"; else if (argc-1 == 1) @@ -165,9 +169,9 @@ getByteAsShort(FILE * const ifP) { static const char * -compressionName(char const compr) { +compressionName(unsigned char const storageCode) { - switch (compr) { + switch (storageCode) { case STORAGE_VERBATIM: return "none"; case STORAGE_RLE: @@ -214,7 +218,7 @@ readHeader(FILE * const ifP, headP->pixmin = getBigLong(ifP); headP->pixmax = getBigLong(ifP); if (headP->pixmin >= headP->pixmax) - pm_error("Invalid sgi image header: pixmin larger than pixmax"); + pm_error("Invalid sgi image header: pixmin larger than pixmax"); readBytes(ifP, 4, headP->dummy1); readBytes(ifP, 80, headP->name); headP->colormap = getBigLong(ifP); @@ -243,26 +247,32 @@ readHeader(FILE * const ifP, headP->dimension = 2; break; case 2: - pm_error("don't know how to interpret 2-channel image"); + if (!outChannelSpec) + pm_message("2-channel image, using only first channel. " + "Extract alpha channel with -channel=1"); break; case 3: break; default: if (!outChannelSpec) - pm_message("%d-channel image, using only first 3 channels", - headP->zsize); + pm_message("%u-channel image, using only first 3 channels " + "Extract %s with -channel=%c", + headP->zsize, + headP->zsize==4 ? + "alpha channel" : "additional channels", + headP->zsize==4 ? '3' : 'N'); break; } break; default: - pm_error("illegal dimension value %d (only 1-3 allowed)", + pm_error("illegal dimension value %u (only 1-3 allowed)", headP->dimension); } if (verbose) { - pm_message("raster size %dx%d, %d channels", + pm_message("raster size %ux%u, %u channels", headP->xsize, headP->ysize, headP->zsize); - pm_message("compression: %d = %s", + pm_message("compression: 0x%02x = %s", headP->storage, compressionName(headP->storage)); headP->name[79] = '\0'; /* just to be safe */ pm_message("Image name: '%s'", headP->name); @@ -345,7 +355,7 @@ rleDecompress(ScanElem * const srcStart, static ScanLine * readChannels(FILE * const ifP, Header * const head, - TabEntry * const table, + TabEntry * const table, bool const outChannelSpec, unsigned int const outChannel) { @@ -357,11 +367,14 @@ readChannels(FILE * const ifP, if (outChannelSpec) { maxchannel = outChannel + 1; MALLOCARRAY_NOFAIL(image, head->ysize); + } else if (head->zsize <= 2) { + maxchannel = 1; + MALLOCARRAY_NOFAIL(image, head->ysize); } else { - maxchannel = MIN(3, head->zsize); + maxchannel = 3; MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel); } - if (table) + if (table) MALLOCARRAY_NOFAIL(temp, WORSTCOMPR(head->xsize)); for (channel = 0; channel < maxchannel; ++channel) { @@ -377,16 +390,17 @@ readChannels(FILE * const ifP, if (table) { if (!outChannelSpec || channel >= outChannel) { - long const offset = table[sgiIndex].start; + pm_filepos const offset = (pm_filepos) + table[sgiIndex].start; long const length = head->bpc == 2 ? table[sgiIndex].length / 2 : table[sgiIndex].length; unsigned int i; - /* doc says length is in bytes, we are reading words */ - if (fseek(ifP, offset, SEEK_SET) != 0) - pm_error("seek error for offset %ld", offset); + /* Note: (offset < currentPosition) can happen */ + + pm_seek2(ifP, &offset, sizeof(offset)); for (i = 0; i < length; ++i) if (head->bpc == 1) @@ -404,7 +418,7 @@ readChannels(FILE * const ifP, else p = getBigShort(ifP); - if (channel == outChannel || !outChannelSpec) + if (!outChannelSpec || outChannel == channel) image[iindex][i] = p; } } @@ -430,7 +444,7 @@ imageToPnm(Header * const head, int row; int format; - if (head->zsize == 1 || outChannelSpec) { + if (head->zsize <= 2 || outChannelSpec) { pm_message("writing PGM image"); format = PGM_TYPE; } else { @@ -459,10 +473,10 @@ imageToPnm(Header * const head, -int +int main(int argc, const char * argv[]) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; TabEntry * table; ScanLine * image; @@ -472,8 +486,8 @@ main(int argc, const char * argv[]) { pm_proginit(&argc, argv); parseCommandLine(argc, argv, &cmdline); - - ifP = pm_openr(cmdline.inputFileName); + + ifP = pm_openr_seekable(cmdline.inputFileName); headP = readHeader(ifP, cmdline.channelSpec, cmdline.verbose); @@ -491,14 +505,14 @@ main(int argc, const char * argv[]) { table = readTable(ifP, headP->ysize * headP->zsize); else table = NULL; - + image = readChannels(ifP, headP, table, cmdline.channelSpec, cmdline.channel); imageToPnm(headP, image, maxval, cmdline.channelSpec, cmdline.channel); pm_close(ifP); - + return 0; } |