about summary refs log tree commit diff
path: root/converter/other/pnmtorle.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/pnmtorle.c')
-rw-r--r--converter/other/pnmtorle.c293
1 files changed, 209 insertions, 84 deletions
diff --git a/converter/other/pnmtorle.c b/converter/other/pnmtorle.c
index 1882fe5d..e8a37d9b 100644
--- a/converter/other/pnmtorle.c
+++ b/converter/other/pnmtorle.c
@@ -33,71 +33,155 @@
  * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler
  *            warnings.
  *
+ * 2022.03.06 revision by Akira F Urushibata
+ *            use shhopt instead of scanargs
+ *            proper handling of multiple image files with -h
+ *
  */
 /*-----------------------------------------------------
  * System includes.
  */
 #include <string.h>
 #include <stdio.h>
+#include <assert.h>
 #include "pnm.h"
 #include "mallocvar.h"
 #include "rle.h"
+#include "shhopt.h"
+#include "pm_c_util.h"
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * inFileName;
+    const char * outfile;
+    unsigned int verbose;
+    unsigned int header;
+    unsigned int alpha;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 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.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;   /* Used by OPTENT3 */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int outfileSpec;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "alpha",    OPT_FLAG,   NULL,  &cmdlineP->alpha,     0);
+    OPTENT3(0, "header",   OPT_FLAG,   NULL,  &cmdlineP->header,    0);
+    OPTENT3(0, "verbose",  OPT_FLAG,   NULL,  &cmdlineP->verbose,   0);
+    OPTENT3(0, "outfile",  OPT_STRING, &cmdlineP->outfile,
+                                              &outfileSpec,         0);
+
+    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_optParseOptions4(&argc, argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    free(option_def);
+
+    if (argc-1 == 0)
+        cmdlineP->inFileName = "-";
+    else if (argc-1 != 1) {
+        pm_error("Program takes zero or one argument (filename).  You "
+                 "specified %d", argc-1);
+    }
+    else
+        cmdlineP->inFileName = argv[1];
+
+    if (!outfileSpec)
+        cmdlineP->outfile = "-";
+}
+
 
-#define VPRINTF if (verbose || header) fprintf
 
-typedef unsigned char U_CHAR;
-/*
- * Global variables.
- */
-static FILE    *fp;
-static rle_hdr hdr;
-static int  format;
-static int width, height;
-static int verbose = 0, header = 0, do_alpha = 0;
-static gray    maxval;
-/*-----------------------------------------------------------------------------
- *                                        Read the pnm image file header.
- */
 static void
-read_pnm_header(void) {
+readPnmHeader(bool      const verbose,
+              bool      const wantAlpha,
+              FILE    * const ifP,
+              int     * const widthP,
+              int     * const heightP,
+              gray    * const maxvalP,
+              int     * const formatP) {
+/*-----------------------------------------------------------------------------
+  Read the pnm image file header.
+---------------------------------------------------------------------------- */
+    int   width;
+    int   height;
+    gray  maxval;
+    int   format;
+    const char * type;
+
+    pnm_readpnminit(ifP, &width, &height, &maxval, &format);
 
-    pnm_readpnminit(fp, &width, &height, &maxval, &format);
     switch (format) {
     case PBM_FORMAT:
-        VPRINTF(stderr, "Image type: plain pbm format\n");
+        type="plain pbm";
         break;
     case RPBM_FORMAT:
-        VPRINTF(stderr, "Image type: raw pbm format\n");
+        type="raw pbm";
         break;
     case PGM_FORMAT:
-        VPRINTF(stderr, "Image type: plain pgm format\n");
+        type="plain pgm";
         break;
     case RPGM_FORMAT:
-        VPRINTF(stderr, "Image type: raw pgm format\n");
+        type="raw pgm";
         break;
     case PPM_FORMAT:
-        VPRINTF(stderr, "Image type: plain ppm format\n");
+        type="plain ppm";
         break;
     case RPPM_FORMAT:
-        VPRINTF(stderr, "Image type: raw ppm format\n");
+        type="raw ppm";
         break;
     }
-    VPRINTF(stderr, "Full image: %dx%d\n", width, height);
-    VPRINTF(stderr, "Maxval:     %d\n", maxval);
-    if (do_alpha)
-        VPRINTF(stderr, "Computing alpha channel...\n");
+    if (verbose) {
+        pm_message("Image type: %s format", type);
+        pm_message("Full image: %dx%d", width, height);
+        pm_message("Maxval:     %d", maxval);
+
+        if (wantAlpha)
+            pm_message("Computing alpha channel...");
+    }
+    *widthP  = width;
+    *heightP = height;
+    *maxvalP = maxval;
+    *formatP = format;
 }
 
 
 
 static void
-write_rle_header(void) {
+writeRleHeader(bool         const wantAlpha,
+               int          const format,
+               unsigned int const width,
+               unsigned int const height,
+               rle_hdr *    const hdrP) {
+
+    rle_hdr hdr;
+
+    hdr = *hdrP;  /* initial value */
 
     hdr.xmin    = 0;
     hdr.xmax    = width-1;
     hdr.ymin    = 0;
     hdr.ymax    = height-1;
     hdr.background = 0;
+
     switch (format) {
     case PBM_FORMAT:
     case RPBM_FORMAT:
@@ -114,31 +198,42 @@ write_rle_header(void) {
         RLE_SET_BIT(hdr, RLE_BLUE);
         break;
     }
-    if (do_alpha) {
+    if (wantAlpha) {
         hdr.alpha = 1;
         RLE_SET_BIT(hdr, RLE_ALPHA);
     }
     rle_put_setup(&hdr);
+
+    *hdrP = hdr;
 }
 
 
 
 static void
-write_rle_data(void) {
+writeRleData(bool         const verbose,
+             bool         const wantAlpha,
+             FILE      *  const ifP,
+             rle_hdr   *  const hdrP,
+             unsigned int const width,
+             unsigned int const height,
+             gray         const maxval,
+             int          const format) {
 
     unsigned int scan;
     xel * xelrow;
     rle_pixel *** scanlines;
 
     MALLOCARRAY(xelrow, width);
-    MALLOCARRAY(scanlines, height);
+    if (xelrow == NULL)
+        pm_error("Failed to allocate memory for row of %u pixels", width);
 
-    if (!scanlines)
+    MALLOCARRAY(scanlines, height);
+    if (scanlines == NULL)
         pm_error("Failed to allocate memory for %u scanline pointers", height);
 
     for (scan = 0; scan < height; ++scan) {
         int rc;
-        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        rc = rle_row_alloc(hdrP, &scanlines[scan]);
         if (rc < 0)
             pm_error("Failed to allocate memory for a scanline");
     }
@@ -151,10 +246,10 @@ write_rle_data(void) {
         for (scan = 0; scan < height; ++scan) {
             rle_pixel ** const scanline = scanlines[height - scan - 1];
             unsigned int col;
-            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
             for (col = 0; col < width; ++col) {
                 scanline[RLE_RED][col] = PNM_GET1(xelrow[col]) ? 255 : 0;
-                if (do_alpha)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] = scanline[RLE_RED][col];
             }
         }
@@ -165,10 +260,10 @@ write_rle_data(void) {
         for (scan = 0; scan < height; ++scan) {
             rle_pixel ** const scanline = scanlines[height - scan - 1];
             unsigned int col;
-            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
             for (col = 0; col < width; ++col) {
                 scanline[RLE_RED][col] = PNM_GET1(xelrow[col]);
-                if (do_alpha)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] =
                         scanline[RLE_RED][col] ? 255 : 0;
             }
@@ -179,13 +274,16 @@ write_rle_data(void) {
         unsigned int scan;
         for (scan = 0; scan < height; scan++) {
             rle_pixel ** const scanline = scanlines[height - scan - 1];
+
             unsigned int col;
-            pnm_readpnmrow(fp, xelrow, width, maxval, format);
+
+            pnm_readpnmrow(ifP, xelrow, width, maxval, format);
+
             for (col = 0; col < width; ++col) {
                 scanline[RLE_RED][col]   = PPM_GETR(xelrow[col]);
                 scanline[RLE_GREEN][col] = PPM_GETG(xelrow[col]);
                 scanline[RLE_BLUE][col]  = PPM_GETB(xelrow[col]);
-                if (do_alpha)
+                if (wantAlpha)
                     scanline[RLE_ALPHA][col] =
                         (scanline[RLE_RED][col] ||
                          scanline[RLE_GREEN][col] ||
@@ -196,71 +294,98 @@ write_rle_data(void) {
     }
     /* Write out data in URT order (bottom to top). */
     for (scan = 0; scan < height; ++scan)
-        rle_putrow(scanlines[scan], width, &hdr);
+        rle_putrow(scanlines[scan], width, hdrP);
 
     for (scan = 0; scan < height; ++scan)
-        rle_row_free(&hdr, scanlines[scan]);
+        rle_row_free(hdrP, scanlines[scan]);
     free(scanlines);
     free(xelrow);
 
-    VPRINTF(stderr, "Done -- write eof to RLE data.\n");
-    rle_puteof(&hdr);
+    if (verbose)
+        pm_message("Done -- write eof to RLE data.");
+
+    rle_puteof(hdrP);
+}
+
+
+
+static void
+skipData(FILE      *  const ifP,
+         unsigned int const width,
+         unsigned int const height,
+         gray         const maxval,
+         int          const format) {
+
+    xel * xelrow;
+    unsigned int scan;
+
+    MALLOCARRAY(xelrow, width);
+    if (xelrow == NULL)
+        pm_error("Failed to allocate memory for row of %u pixels", width);
+
+    for (scan=0; scan < height; ++scan)
+        pnm_readpnmrow(ifP, xelrow, width, maxval, format);
+
+    free(xelrow);
 }
 
 
 
 int
-main(int argc, char **  argv) {
-
-    const char * pnmname;
-    const char * outname;
-    int oflag;
-
-    pnm_init(&argc, argv);
-
-    pnmname = NULL;  /* initial value */
-    outname = NULL;  /* initial value */
-
-    /* Get those options. */
-    if (!scanargs(argc,argv,
-                  "% v%- h%- a%- o%-outfile!s pnmfile%s\n(\
-\tConvert a PNM file to URT RLE format.\n\
-\t-a\tFake an alpha channel.  Alpha=0 when input=0, 255 otherwise.\n\
-\t-h\tPrint header of PNM file and exit.\n\
-\t-v\tVerbose mode.)",
-                  &verbose,
-                  &header,
-                  &do_alpha,
-                  &oflag, &outname,
-                  &pnmname))
-        exit(-1);
+main(int argc, const char ** argv) {
+
+    struct CmdlineInfo cmdline;
+
+    FILE   * ifP;
+    rle_hdr hdr;
+    int  format;
+    int  width, height;
+    gray maxval;
+    bool verbose;
+    const char ** argvWork;
+    unsigned int i;
+    int eof;
+
+    MALLOCARRAY_NOFAIL(argvWork, argc + 1);
+
+    for (i = 0; i < argc; ++i)  /* Make a copy of argv */
+        argvWork[i] = argv[i];
+
+    pm_proginit(&argc, argvWork);
+
+    parseCommandLine(argc, argvWork, &cmdline);
+
+    verbose = cmdline.verbose || cmdline.header;
 
     hdr = *rle_hdr_init(NULL);
-    rle_names(&hdr, cmd_name(argv), outname, 0);
+
+    rle_names(&hdr, "pnmtorle", cmdline.outfile, 0);
 
     /* Open the file. */
-    if (pnmname == NULL) {
-        fp = pm_openr("-");
-    } else {
-        fp = pm_openr(pnmname);
-    }
+    assert(cmdline.inFileName != NULL);
+    ifP = pm_openr(cmdline.inFileName);
 
-    hdr.rle_file = rle_open_f( hdr.cmd, outname, "wb" );
+    hdr.rle_file = rle_open_f(hdr.cmd, cmdline.outfile, "wb");
 
-    if (header)
-        read_pnm_header();
-    else {
-        int eof;
-        for (eof = 0; !eof; ) {
-            read_pnm_header();
-            rle_addhist(argv, NULL, &hdr);
-            write_rle_header();
-            write_rle_data();
+    for (eof = 0; !eof; ) {
+        readPnmHeader(verbose, cmdline.alpha, ifP,
+                      &width, &height, &maxval, &format);
 
-            pnm_nextimage(fp, &eof);
+        if (cmdline.header) {
+            skipData(ifP, width, height, maxval, format);
+        } else {
+            rle_addhist(argv, NULL, &hdr);
+            writeRleHeader(cmdline.alpha, format, width, height, &hdr);
+            writeRleData(verbose, cmdline.alpha, ifP, &hdr,
+                         width, height, maxval, format);
         }
+        pnm_nextimage(ifP, &eof);
     }
-    pm_close(fp);
+
+    pm_close(ifP);
 
     return 0;
 }
+
+
+