diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2010-10-23 02:43:05 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2010-10-23 02:43:05 +0000 |
commit | b58715c62b6e24e61fdee85417fbf5528af46605 (patch) | |
tree | 900dae0c9c227a48f285589a6e2f1b23768faf22 /converter/other | |
parent | 063ae4faa08449fdfd860a1550c7a7b7c4742cf7 (diff) | |
download | netpbm-mirror-b58715c62b6e24e61fdee85417fbf5528af46605.tar.gz netpbm-mirror-b58715c62b6e24e61fdee85417fbf5528af46605.tar.xz netpbm-mirror-b58715c62b6e24e61fdee85417fbf5528af46605.zip |
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1340 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other')
-rw-r--r-- | converter/other/sgitopnm.c | 697 |
1 files changed, 379 insertions, 318 deletions
diff --git a/converter/other/sgitopnm.c b/converter/other/sgitopnm.c index 86744638..2adb76a8 100644 --- a/converter/other/sgitopnm.c +++ b/converter/other/sgitopnm.c @@ -20,296 +20,429 @@ */ #include <unistd.h> #include <limits.h> +#include "pm_c_util.h" #include "mallocvar.h" +#include "shhopt.h" #include "pnm.h" #include "sgi.h" -/* entry in RLE offset table */ -typedef struct { - long start; /* offset in file */ - long length; /* length of compressed scanline */ -} TabEntry; -typedef short ScanElem; -typedef ScanElem * ScanLine; -/* prototypes */ -static unsigned char get_byte ARGS(( FILE* f )); -static long get_big_long ARGS((FILE *f)); -static short get_big_short ARGS((FILE *f)); -static short get_byte_as_short ARGS((FILE *f)); -static void readerr ARGS((FILE *f)); -static const char * -compression_name(char compr); -static void read_bytes ARGS((FILE *ifp, int n, char *buf)); -static Header * read_header ARGS((FILE *ifp, int outChannel, int verbose)); -static TabEntry * read_table ARGS((FILE *ifp, int tablen)); -static ScanLine * read_channels ARGS((FILE *ifp, Header *head, TabEntry *table, int outChannel )); -static void image_to_pnm ARGS((Header *head, ScanLine *image, xelval maxval, int outChannel)); -static void rle_decompress ARGS((ScanElem *src, int srclen, ScanElem *dest, int destlen)); +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; + unsigned int channelSpec; + unsigned int channel; +}; -#define WORSTCOMPR(x) (2*(x) + 2) + + +static void +parseCommandLine(int argc, const char ** argv, + 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. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + 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; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "channel", OPT_UINT, + &cmdlineP->channel, + &cmdlineP->channelSpec, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0); + OPTENT3(0, "noverbose", OPT_FLAG, NULL, + NULL, 0); /* backward compatibility */ + + 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 < 1) + cmdlineP->inputFileName = "-"; + else if (argc-1 == 1) + cmdlineP->inputFileName = argv[1]; + else + pm_error("Program takes at most one argument: input file name"); +} -int -main(int argc, char *argv[]) -{ - FILE *ifp; - int argn; - const char * const usage = "[-verbose] [-channel n] [sgifile]"; - TabEntry *table = NULL; - ScanLine *image; - Header *head; - pixval maxval; - long int outChannel = -1; - int verbose = 0; - - pnm_init(&argc, argv); - - argn = 1; - while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { - if( pm_keymatch(argv[argn], "-verbose", 2) ) - verbose++; - else - if( pm_keymatch(argv[argn], "-noverbose", 4) ) - verbose = 0; - else - if( pm_keymatch(argv[argn], "-channel", 2) ) { - char *s; - - ++argn; - if( argn >= argc ) - pm_usage(usage); - - s = argv[argn]; - outChannel = strtol(argv[argn], &s, 10); - if( s == argv[argn] || outChannel < 0) - pm_usage(usage); - } - else - pm_usage(usage); - ++argn; - } +/* basic I/O functions, taken from ilbmtoppm.c */ - if( argn < argc ) { - ifp = pm_openr( argv[argn] ); - argn++; - } +static void +readerr(FILE * const f) { + + if (ferror(f)) + pm_error("read error"); else - ifp = stdin; + pm_error("premature EOF"); +} - if( argn != argc ) - pm_usage(usage); - head = read_header(ifp, outChannel, verbose); - maxval = head->pixmax - head->pixmin; - if( maxval > PNM_OVERALLMAXVAL ) - pm_error("Maximum sample value in input image (%d) is too large. " - "This program's limit is %d.", - maxval, PNM_OVERALLMAXVAL); - if (outChannel >= head->zsize) - pm_error("channel out of range - only %d channels in image", - head->zsize); - if( head->storage != STORAGE_VERBATIM ) - table = read_table(ifp, head->ysize * head->zsize); - - image = read_channels(ifp, head, table, outChannel); - pm_close(ifp); - - image_to_pnm(head, image, (xelval)maxval, outChannel); - exit(0); +static short +getBigShort(FILE * const ifP) { + + short s; + + if (pm_readbigshort(ifP, &s) == -1) + readerr(ifP); + + return s; +} + + + +static long +getBigLong(FILE * const ifP) { + + long l; + + if (pm_readbiglong(ifP, &l) == -1) + readerr(ifP); + + return l; +} + + + +static unsigned char +getByte(FILE * const ifP) { + + int i; + + i = getc(ifP); + if (i == EOF) + readerr(ifP); + + return (unsigned char) i; +} + + + +static void +readBytes(FILE * const ifP, + int const n, + char * const buf) { + + int r; + + r = fread((void *)buf, 1, n, ifP); + + if (r != n) + readerr(ifP); +} + + + +static short +getByteAsShort(FILE * const ifP) { + + return (short)getByte(ifP); } + +static const char * +compressionName(char const compr) { + + switch (compr) { + case STORAGE_VERBATIM: + return "none"; + case STORAGE_RLE: + return "RLE"; + default: + return "unknown"; + } +} + + + +/* entry in RLE offset table */ +typedef struct { + long start; /* offset in file */ + long length; /* length of compressed scanline */ +} TabEntry; + +typedef short ScanElem; +typedef ScanElem * ScanLine; + +#define WORSTCOMPR(x) (2*(x) + 2) + + + static Header * -read_header(FILE * const ifp, int const outChannel, int const verbose) -{ - Header *head; - - MALLOCVAR_NOFAIL(head); - - head->magic = get_big_short(ifp); - head->storage = get_byte(ifp); - head->bpc = get_byte(ifp); - head->dimension = get_big_short(ifp); - head->xsize = get_big_short(ifp); - head->ysize = get_big_short(ifp); - head->zsize = get_big_short(ifp); - if(head->zsize > 256) - pm_error("Too many channels in input image: %u", - (unsigned int) head->zsize ); - head->pixmin = get_big_long(ifp); - head->pixmax = get_big_long(ifp); - if(head->pixmin >= head->pixmax) - pm_error("Invalid sgi image header: pixmin larger than pixmax"); - read_bytes(ifp, 4, head->dummy1); - read_bytes(ifp, 80, head->name); - head->colormap = get_big_long(ifp); - read_bytes(ifp, 404, head->dummy2); - - if( head->magic != SGI_MAGIC ) +readHeader(FILE * const ifP, + bool const outChannelSpec, + bool const verbose) { + + Header * headP; + + MALLOCVAR_NOFAIL(headP); + + headP->magic = getBigShort(ifP); + headP->storage = getByte(ifP); + headP->bpc = getByte(ifP); + headP->dimension = getBigShort(ifP); + headP->xsize = getBigShort(ifP); + headP->ysize = getBigShort(ifP); + headP->zsize = getBigShort(ifP); + if (headP->zsize > 256) + pm_error("Too many channels in input image: %u", + (unsigned int) headP->zsize ); + headP->pixmin = getBigLong(ifP); + headP->pixmax = getBigLong(ifP); + if (headP->pixmin >= headP->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); + readBytes(ifP, 404, headP->dummy2); + + if (headP->magic != SGI_MAGIC) pm_error("bad magic number - not an SGI image"); - if( head->storage != STORAGE_VERBATIM && head->storage != STORAGE_RLE ) + if (headP->storage != STORAGE_VERBATIM && headP->storage != STORAGE_RLE) pm_error("unknown compression type"); - if( head->bpc < 1 || head->bpc > 2 ) - pm_error("illegal precision value %d (only 1-2 allowed)", head->bpc ); - if( head->colormap != CMAP_NORMAL ) + if (headP->bpc < 1 || headP->bpc > 2) + pm_error("illegal precision value %d (only 1-2 allowed)", headP->bpc); + if (headP->colormap != CMAP_NORMAL) pm_error("non-normal pixel data of a form we don't recognize"); /* adjust ysize/zsize to dimension, just to be sure */ - switch( head->dimension ) { + switch (headP->dimension) { + case 1: + headP->ysize = 1; + break; + case 2: + headP->zsize = 1; + break; + case 3: + switch (headP->zsize) { case 1: - head->ysize = 1; + headP->dimension = 2; break; case 2: - head->zsize = 1; + pm_error("don't know how to interpret 2-channel image"); break; case 3: - switch( head->zsize ) { - case 1: - head->dimension = 2; - break; - case 2: - pm_error("don\'t know how to interpret 2-channel image"); - break; - case 3: - break; - default: - if (outChannel < 0) - pm_message("%d-channel image, using only first 3 channels", head->zsize); - break; - } break; default: - pm_error("illegal dimension value %d (only 1-3 allowed)", head->dimension); + if (!outChannelSpec) + pm_message("%d-channel image, using only first 3 channels", + headP->zsize); + break; + } + break; + default: + pm_error("illegal dimension value %d (only 1-3 allowed)", + headP->dimension); } - if( verbose ) { - pm_message("raster size %dx%d, %d channels", head->xsize, head->ysize, head->zsize); - pm_message("compression: %d = %s", head->storage, compression_name(head->storage)); - head->name[79] = '\0'; /* just to be safe */ - pm_message("Image name: \"%s\"", head->name); + if (verbose) { + pm_message("raster size %dx%d, %d channels", + headP->xsize, headP->ysize, headP->zsize); + pm_message("compression: %d = %s", + headP->storage, compressionName(headP->storage)); + headP->name[79] = '\0'; /* just to be safe */ + pm_message("Image name: '%s'", headP->name); } - return head; + return headP; } + static TabEntry * -read_table(FILE * const ifp, int const tablen) -{ - TabEntry *table; - int i; +readTable(FILE * const ifP, + int const tablen) { + + TabEntry * table; + unsigned int i; MALLOCARRAY_NOFAIL(table, tablen); - for( i = 0; i < tablen; i++ ) - table[i].start = get_big_long(ifp); - for( i = 0; i < tablen; i++ ) - table[i].length = get_big_long(ifp); + for (i = 0; i < tablen; ++i) + table[i].start = getBigLong(ifP); + for (i = 0; i < tablen; ++i) + table[i].length = getBigLong(ifP); return table; } +static void +rleDecompress(ScanElem * const srcStart, + int const srcleftStart, + ScanElem * const destStart, + int const destleftStart) { + + ScanElem * src; + int srcleft; + ScanElem * dest; + int destleft; + + for (src = srcStart, + srcleft = srcleftStart, + dest = destStart, + destleft = destleftStart; srcleft; ) { + + unsigned char const el = (unsigned char)(*src++ & 0xff); + unsigned int const count = (unsigned int)(el & 0x7f); + + --srcleft; + + if (count == 0) + return; + if (destleft < count) + pm_error("RLE error: too much input data " + "(space left %d, need %d)", destleft, count); + destleft -= count; + if (el & 0x80) { + unsigned int i; + if (srcleft < count) + pm_error("RLE error: not enough data for literal run " + "(data left %d, need %d)", srcleft, count); + srcleft -= count; + for (i = 0; i < count; ++i) + *dest++ = *src++; + } else { + unsigned int i; + if (srcleft == 0) + pm_error("RLE error: not enough data for replicate run"); + for (i = 0; i < count; ++i) + *dest++ = *src; + ++src; + --srcleft; + } + } + pm_error("RLE error: no terminating 0-byte"); +} + + + static ScanLine * -read_channels(FILE * const ifp, - Header * const head, - TabEntry * const table, - int const outChannel) -{ - ScanLine *image; - ScanElem *temp; - int channel, maxchannel, sgi_index, i; - long offset, length; - - if (outChannel < 0) { - maxchannel = (head->zsize < 3) ? head->zsize : 3; - MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel); - } else { +readChannels(FILE * const ifP, + Header * const head, + TabEntry * const table, + bool const outChannelSpec, + unsigned int const outChannel) { + + ScanLine * image; + ScanElem * temp; + unsigned int channel; + unsigned int maxchannel; + + if (outChannelSpec) { maxchannel = outChannel + 1; MALLOCARRAY_NOFAIL(image, head->ysize); + } else { + maxchannel = MIN(3, head->zsize); + MALLOCARRAY_NOFAIL(image, head->ysize * maxchannel); } - if ( table ) + if (table) MALLOCARRAY_NOFAIL(temp, WORSTCOMPR(head->xsize)); - for( channel = 0; channel < maxchannel; channel++ ) { + for (channel = 0; channel < maxchannel; ++channel) { unsigned int row; - for( row = 0; row < head->ysize; row++ ) { + for (row = 0; row < head->ysize; ++row) { + int const sgiIndex = channel * head->ysize + row; + unsigned long int iindex; - sgi_index = channel * head->ysize + row; - iindex = (outChannel < 0) ? sgi_index : row; - if (outChannel < 0 || outChannel == channel) + iindex = outChannelSpec ? row : sgiIndex; + if (!outChannelSpec || outChannel == channel) MALLOCARRAY_NOFAIL(image[iindex], head->xsize); - if( table ) { - if (channel < outChannel) - continue; + if (table) { + if (outChannelSpec && channel >= outChannel) { + long const offset = table[sgiIndex].start; + long const length = head->bpc == 2 ? + table[sgiIndex].length / 2 : + table[sgiIndex].length; + + unsigned int i; - offset = table[sgi_index].start; - length = table[sgi_index].length; - if( head->bpc == 2 ) - length /= 2; /* 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); - - for( i = 0; i < length; i++ ) - if( head->bpc == 1 ) - temp[i] = get_byte_as_short(ifp); - else - temp[i] = get_big_short(ifp); - rle_decompress(temp, length, image[iindex], head->xsize); - } - else { - for( i = 0; i < head->xsize; i++ ) - { - ScanElem p; - if( head->bpc == 1 ) - p = get_byte_as_short(ifp); - else - p = get_big_short(ifp); - - if (channel == -1 || channel ==outChannel) - image[iindex][i] = p; - } + if (fseek(ifP, offset, SEEK_SET) != 0) + pm_error("seek error for offset %ld", offset); + + for (i = 0; i < length; ++i) + if (head->bpc == 1) + temp[i] = getByteAsShort(ifP); + else + temp[i] = getBigShort(ifP); + rleDecompress(temp, length, image[iindex], head->xsize); + } + } else { + unsigned int i; + for (i = 0; i < head->xsize; ++i) { + ScanElem p; + if (head->bpc == 1) + p = getByteAsShort(ifP); + else + p = getBigShort(ifP); + + if (channel == outChannel || !outChannelSpec) + image[iindex][i] = p; + } } } } - - if( table ) free(temp); + if (table) + free(temp); return image; } static void -image_to_pnm(Header * const head, - ScanLine * const image, - xelval const maxval, - int const channel) -{ - int col, row, format; - xel *pnmrow = pnm_allocrow(head->xsize); - int sub = head->pixmin; - - if( head->zsize == 1 || channel >= 0) { +imageToPnm(Header * const head, + ScanLine * const image, + xelval const maxval, + bool const outChannelSpec, + unsigned int const outChannel) { + + int const sub = head->pixmin; + xel * const pnmrow = pnm_allocrow(head->xsize); + + int row; + int format; + + if (head->zsize == 1 || outChannelSpec) { pm_message("writing PGM image"); format = PGM_TYPE; - } - else { + } else { pm_message("writing PPM image"); format = PPM_TYPE; } - pnm_writepnminit(stdout, head->xsize, head->ysize, (xelval)maxval, format, 0); - for( row = head->ysize-1; row >= 0; row-- ) { - for( col = 0; col < head->xsize; col++ ) { - if( format == PGM_TYPE ) + pnm_writepnminit(stdout, head->xsize, head->ysize, maxval, format, 0); + for (row = head->ysize-1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < head->xsize; ++col) { + if (format == PGM_TYPE) PNM_ASSIGN1(pnmrow[col], image[row][col] - sub); else { pixval r, g, b; @@ -319,126 +452,54 @@ image_to_pnm(Header * const head, PPM_ASSIGN(pnmrow[col], r, g, b); } } - pnm_writepnmrow(stdout, pnmrow, head->xsize, (xelval)maxval, format, 0); + pnm_writepnmrow(stdout, pnmrow, head->xsize, maxval, format, 0); } pnm_freerow(pnmrow); } -static void -rle_decompress(ScanElem * src, - int srcleft, - ScanElem * dest, - int destleft) -{ - int count; - unsigned char el; - - while( srcleft ) { - el = (unsigned char)(*src++ & 0xff); - --srcleft; - count = (int)(el & 0x7f); - - if( count == 0 ) - return; - if( destleft < count ) - pm_error("RLE error: too much input data (space left %d, need %d)", destleft, count); - destleft -= count; - if( el & 0x80 ) { - if( srcleft < count ) - pm_error("RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count); - srcleft -= count; - while( count-- ) - *dest++ = *src++; - } - else { - if( srcleft == 0 ) - pm_error("RLE error: not enough data for replicate run"); - while( count-- ) - *dest++ = *src; - ++src; - --srcleft; - } - } - pm_error("RLE error: no terminating 0-byte"); -} - - -/* basic I/O functions, taken from ilbmtoppm.c */ - -static short -get_big_short(FILE * const ifp) -{ - short s; - - if( pm_readbigshort(ifp, &s) == -1 ) - readerr(ifp); - - return s; -} - -static long -get_big_long(FILE * const ifp) -{ - long l; +int +main(int argc, const char * argv[]) { - if( pm_readbiglong(ifp, &l) == -1 ) - readerr(ifp); + struct cmdlineInfo cmdline; + FILE * ifP; + TabEntry * table; + ScanLine * image; + Header * headP; + xelval maxval; - return l; -} + pm_proginit(&argc, argv); -static unsigned char -get_byte(FILE * const ifp) -{ - int i; + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); - i = getc(ifp); - if( i == EOF ) - readerr(ifp); + headP = readHeader(ifP, cmdline.channelSpec, cmdline.verbose); - return (unsigned char) i; -} + maxval = headP->pixmax - headP->pixmin; + if (maxval > PNM_OVERALLMAXVAL) + pm_error("Maximum sample value in input image (%d) is too large. " + "This program's limit is %d.", + maxval, PNM_OVERALLMAXVAL); + if (cmdline.channelSpec && cmdline.channel >= headP->zsize) + pm_error("channel out of range - only %d channels in image", + headP->zsize); -static void -readerr(FILE * const f) -{ - if( ferror(f) ) - pm_error("read error"); + if (headP->storage != STORAGE_VERBATIM) + table = readTable(ifP, headP->ysize * headP->zsize); else - pm_error("premature EOF"); -} - - -static void -read_bytes(FILE * const ifp, int const n, char * const buf) -{ - int r; - - r = fread((void *)buf, 1, n, ifp); - if( r != n ) - readerr(ifp); -} + table = NULL; + + image = readChannels(ifP, headP, table, + cmdline.channelSpec, cmdline.channel); + imageToPnm(headP, image, maxval, cmdline.channelSpec, cmdline.channel); -static short -get_byte_as_short(FILE * const ifp) -{ - return (short)get_byte(ifp); + pm_close(ifP); + + return 0; } -static const char * -compression_name(char const compr) -{ - switch( compr ) { - case STORAGE_VERBATIM: - return "none"; - case STORAGE_RLE: - return "RLE"; - default: - return "unknown"; - } -} |