about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2010-10-23 02:43:05 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2010-10-23 02:43:05 +0000
commitb58715c62b6e24e61fdee85417fbf5528af46605 (patch)
tree900dae0c9c227a48f285589a6e2f1b23768faf22 /converter
parent063ae4faa08449fdfd860a1550c7a7b7c4742cf7 (diff)
downloadnetpbm-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')
-rw-r--r--converter/other/sgitopnm.c697
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";
-    }
-}