about summary refs log tree commit diff
path: root/converter/other/pamtotiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/pamtotiff.c')
-rw-r--r--converter/other/pamtotiff.c210
1 files changed, 130 insertions, 80 deletions
diff --git a/converter/other/pamtotiff.c b/converter/other/pamtotiff.c
index 7b645b23..115b8b4a 100644
--- a/converter/other/pamtotiff.c
+++ b/converter/other/pamtotiff.c
@@ -22,7 +22,6 @@
 */
 
 #define _XOPEN_SOURCE    /* Make sure stdio.h contains fileno() */
-#define _BSD_SOURCE      /* Make sure string.h contains strcasecmp() */
 
 #include <unistd.h>
 #include <stdio.h>
@@ -135,6 +134,44 @@ validateTagList(struct optNameValue const taglist[]) {
 
 
 static void
+parseIndexbits(bool          const indexbitsSpec,
+               char **       const indexbits,
+               CmdlineInfo * const cmdlineP) {
+
+    if (indexbitsSpec) {
+        unsigned int i;
+
+        /* Set initial values */
+        cmdlineP->indexsizeAllowed.b1 = false;
+        cmdlineP->indexsizeAllowed.b2 = false;
+        cmdlineP->indexsizeAllowed.b4 = false;
+        cmdlineP->indexsizeAllowed.b8 = false;
+
+        for (i = 0; indexbits[i]; ++i) {
+            const char * const thisItem = indexbits[i];
+            if (streq(thisItem, "1"))
+                cmdlineP->indexsizeAllowed.b1 = true;
+            else if (streq(thisItem, "2"))
+                cmdlineP->indexsizeAllowed.b2 = true;
+            else if (streq(thisItem, "4"))
+                cmdlineP->indexsizeAllowed.b4 = true;
+            else if (streq(thisItem, "8"))
+                cmdlineP->indexsizeAllowed.b8 = true;
+            else
+                pm_error("Invalid item in -indexbits list: '%s'.  "
+                         "We recognize only 1, 2, 4, and 8", thisItem);
+        }
+    } else {
+        cmdlineP->indexsizeAllowed.b1 = false;
+        cmdlineP->indexsizeAllowed.b2 = false;
+        cmdlineP->indexsizeAllowed.b4 = false;
+        cmdlineP->indexsizeAllowed.b8 = true;
+    }
+}
+
+
+
+static void
 parseCommandLine(int                 argc,
                  const char ** const argv,
                  CmdlineInfo * const cmdlineP) {
@@ -148,7 +185,7 @@ parseCommandLine(int                 argc,
 
     unsigned int none, packbits, lzw, g3, g4, msb2lsb, lsb2msb, opt_2d, fill;
     unsigned int flate, adobeflate;
-    char * indexbits;
+    char ** indexbits;
     char * resolutionunit;
 
     unsigned int appendSpec, outputSpec, predictorSpec, rowsperstripSpec,
@@ -191,13 +228,13 @@ parseCommandLine(int                 argc,
             &yresolutionSpec,  0);
     OPTENT3(0, "resolutionunit", OPT_STRING, &resolutionunit,
             &resolutionunitSpec,    0);
-    OPTENT3(0, "indexbits",    OPT_STRING,   &indexbits,
+    OPTENT3(0, "indexbits",    OPT_STRINGLIST, &indexbits,
             &indexbitsSpec,    0);
     OPTENT3(0, "tag",          OPT_NAMELIST, &cmdlineP->taglist, &tagSpec, 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 */
+    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. */
@@ -301,35 +338,16 @@ parseCommandLine(int                 argc,
     } else
         cmdlineP->resolutionunit = RESUNIT_INCH;
 
-    if (indexbitsSpec) {
-        if (strstr(indexbits, "1"))
-            cmdlineP->indexsizeAllowed.b1 = TRUE;
-        else
-            cmdlineP->indexsizeAllowed.b1 = FALSE;
-        if (strstr(indexbits, "2"))
-            cmdlineP->indexsizeAllowed.b2 = TRUE;
-        else
-            cmdlineP->indexsizeAllowed.b2 = FALSE;
-        if (strstr(indexbits, "4"))
-            cmdlineP->indexsizeAllowed.b4 = TRUE;
-        else
-            cmdlineP->indexsizeAllowed.b4 = FALSE;
-        if (strstr(indexbits, "8"))
-            cmdlineP->indexsizeAllowed.b8 = TRUE;
-        else
-            cmdlineP->indexsizeAllowed.b8 = FALSE;
-    } else {
-        cmdlineP->indexsizeAllowed.b1 = FALSE;
-        cmdlineP->indexsizeAllowed.b2 = FALSE;
-        cmdlineP->indexsizeAllowed.b4 = FALSE;
-        cmdlineP->indexsizeAllowed.b8 = TRUE;
-    }
+    parseIndexbits(indexbitsSpec, indexbits, cmdlineP);
+
+    if (indexbitsSpec)
+        free(indexbits);
 
     if (tagSpec)
         validateTagList(cmdlineP->taglist);
     else {
         MALLOCARRAY_NOFAIL(cmdlineP->taglist, 1);
-        cmdlineP->taglist[0].name = NULL;
+        cmdlineP->taglist[0].name  = NULL;
         cmdlineP->taglist[0].value = NULL;
     }
 
@@ -345,6 +363,14 @@ parseCommandLine(int                 argc,
 
 
 static void
+freeCmdline(CmdlineInfo const cmdline) {
+
+    pm_optDestroyNameValueList(cmdline.taglist);
+}
+
+
+
+static void
 fillRowOfSubBytePixels(struct pam *    const pamP,
                        const tuple *   const tuplerow,
                        unsigned char * const buf,
@@ -517,7 +543,7 @@ writeScanLines(struct pam *   const pamP,
 
        The samples form pixel values according to the pixel format indicated
        by the TIFF photometric.  E.g. if it is MINISWHITE, then a pixel is
-       one sample and a value of 0 for that sample means white.
+       grayscale, composed of one sample where a value of 0 means white.
     */
     MALLOCARRAY(buf, bytesperrow);
 
@@ -577,14 +603,14 @@ analyzeColorsInRgbInput(struct pam *   const pamP,
                         CmdlineInfo    const cmdline,
                         int            const maxcolors,
                         tupletable *   const chvP,
-                        unsigned int * const colorsP,
+                        unsigned int * const colorCtP,
                         bool *         const grayscaleP) {
 /*----------------------------------------------------------------------------
    Same as analyzeColors(), except assuming input image has R/G/B tuples.
 -----------------------------------------------------------------------------*/
     if (cmdline.color && cmdline.truecolor) {
         *chvP = NULL;
-        *grayscaleP = FALSE;
+        *grayscaleP = false;
     } else {
         tupletable chv;
         bool grayscale;
@@ -592,17 +618,17 @@ analyzeColorsInRgbInput(struct pam *   const pamP,
         pm_message("computing colormap...");
         chv = pnm_computetuplefreqtable2(pamP, NULL, maxcolors,
                                          pamP->maxval,
-                                         colorsP);
+                                         colorCtP);
         if (chv == NULL) {
-            grayscale = FALSE;
+            grayscale = false;
         } else {
             unsigned int i;
             pm_message("%u color%s found",
-                       *colorsP, *colorsP == 1 ? "" : "s");
-            grayscale = TRUE;  /* initial assumption */
-            for (i = 0; i < *colorsP && grayscale; ++i) {
+                       *colorCtP, *colorCtP == 1 ? "" : "s");
+            grayscale = true;  /* initial assumption */
+            for (i = 0; i < *colorCtP && grayscale; ++i) {
                 if (!pnm_rgbtupleisgray(chv[i]->tuple))
-                    grayscale = FALSE;
+                    grayscale = false;
             }
         }
         *grayscaleP = grayscale;
@@ -634,21 +660,22 @@ analyzeColors(struct pam *   const pamP,
               CmdlineInfo    const cmdline,
               int            const maxcolors,
               tupletable *   const chvP,
-              unsigned int * const colorsP,
+              unsigned int * const colorCtP,
               bool *         const grayscaleP) {
 /*----------------------------------------------------------------------------
    Analyze the colors in the input image described by 'pamP', whose file
    is positioned to the raster.
 
-   If the colors, combined with command line options 'cmdline', indicate
-   a colormapped TIFF should be generated, return as *chvP the address
-   of a color map (in newly malloc'ed space).  If a colormapped TIFF is
-   not indicated, return *chvP == NULL.
-
    Return *grayscaleP == true iff the image should be stored as a grayscale
    image (which means the image is monochromatic and the user doesn't
    insist on color format).
 
+   If *grayscaleP is false and the colors, combined with command line options
+   'cmdline', indicate a colormapped TIFF should be generated, return as *chvP
+   the address of a color map (in newly malloc'ed space) and the number of
+   colors in it as *colorCtP.  If a colormapped color TIFF is not indicated,
+   return *chvP == NULL and nothing as *colorCtP.
+
    Leave the file position undefined.
 -----------------------------------------------------------------------------*/
     if (pamP->depth >= 3)
@@ -656,10 +683,28 @@ analyzeColors(struct pam *   const pamP,
            (tuple type RGB or RGB_ALPHA)
         */
         analyzeColorsInRgbInput(pamP, cmdline, maxcolors,
-                                chvP, colorsP, grayscaleP);
+                                chvP, colorCtP, grayscaleP);
     else {
         *chvP = NULL;
-        *grayscaleP = TRUE;
+        *grayscaleP = true;
+    }
+}
+
+
+
+static void
+reportTiffType(bool const grayscale,
+               bool const colormapped,
+               unsigned int const colorCt,
+               bool const verbose) {
+
+    if (verbose) {
+        pm_message("Generating %s TIFF", grayscale ? "grayscale" : "color");
+
+        if (colormapped)
+            pm_message("TIFF will have palette of %u colors", colorCt);
+        else
+            pm_message("TIFF will be truecolor (24 bit RGB)");
     }
 }
 
@@ -668,7 +713,7 @@ analyzeColors(struct pam *   const pamP,
 static void
 computeRasterParm(struct pam *     const pamP,
                   tupletable       const chv,
-                  int              const colors,
+                  int              const colorCt,
                   bool             const grayscale,
                   int              const compression,
                   bool             const minisblack,
@@ -682,7 +727,7 @@ computeRasterParm(struct pam *     const pamP,
    Compute the parameters of the raster portion of the TIFF image.
 
    'minisblack' and 'miniswhite' mean the user requests the corresponding
-   photometric.  Both FALSE means user has no explicit requirement.
+   photometric.  Both false means user has no explicit requirement.
 -----------------------------------------------------------------------------*/
     unsigned short defaultPhotometric;
     /* The photometric we use if the user specified no preference */
@@ -709,14 +754,14 @@ computeRasterParm(struct pam *     const pamP,
         if (chv) {
             *samplesperpixelP = 1;  /* Pixel is just the one index value */
             *bitspersampleP =
-                colors <=   2 && indexsizeAllowed.b1 ? 1 :
-                colors <=   4 && indexsizeAllowed.b2 ? 2 :
-                colors <=  16 && indexsizeAllowed.b4 ? 4 :
-                colors <= 256 && indexsizeAllowed.b8 ? 8 :
+                colorCt <=   2 && indexsizeAllowed.b1 ? 1 :
+                colorCt <=   4 && indexsizeAllowed.b2 ? 2 :
+                colorCt <=  16 && indexsizeAllowed.b4 ? 4 :
+                colorCt <= 256 && indexsizeAllowed.b8 ? 8 :
                 0;
             if (*bitspersampleP == 0)
                 pm_error("Your -indexbits option is insufficient for the "
-                         "%d colors in this image.", colors);
+                         "%d colors in this image.", colorCt);
 
             defaultPhotometric = PHOTOMETRIC_PALETTE;
         } else {
@@ -736,11 +781,15 @@ computeRasterParm(struct pam *     const pamP,
         }
     }
 
-    if (miniswhite)
+    if (miniswhite) {
+        if (!grayscale)
+            pm_error("Image is color, so -miniswhite is invalid");
         *photometricP = PHOTOMETRIC_MINISWHITE;
-    else if (minisblack)
+    } else if (minisblack) {
+        if (!grayscale)
+            pm_error("Image is color, so -minisblack is invalid");
         *photometricP = PHOTOMETRIC_MINISBLACK;
-    else
+    } else
         *photometricP = defaultPhotometric;
 
     {
@@ -764,9 +813,9 @@ computeRasterParm(struct pam *     const pamP,
 /*----------------------------------------------------------------------------
   WRITE MODES
   -----------
-  
+
   The Tiff library does all output.  There are several issues:
-  
+
     1) The manner of output is opaque to the library client.  I.e.  we cannot
        see or control it.
 
@@ -777,22 +826,22 @@ computeRasterParm(struct pam *     const pamP,
 
     4) The Tiff library produces unhelpful error messages when the above
        conditions are not met.
-  
+
   We provide two modes for output:
-  
+
   1. Tmpfile mode (default)
-  
+
      We have the Tiff library direct output to an unnamed temporary file we
      create which is seekable and readable.  When output is complete, we copy
      the file's contents to Standard Output.
-  
+
   2. Direct mode (specified with -output)
-  
+
      We have the Tiff library write output to the specified file.  As the Tiff
      library requires taht it be be seekable and readable, we fail the program
      rather than ask the Tiff library to use the file if it does not meet
      these requirements.
-  
+
      Direct mode is further divided into append and create.  They are the same
      except that in append mode, we insist that the file already exist,
      whereas with create mode, we create it if necessary.  In either case, if
@@ -972,9 +1021,9 @@ copyBufferToStdout(int const tmpfileFd) {
 
 
 static void
-destroyTiffGenerator(WriteMethod const writeMethod,
-                     TIFF *      const tifP,
-                     int         const ofd) {
+closeTiffGenerator(WriteMethod const writeMethod,
+                   TIFF *      const tifP,
+                   int         const ofd) {
 
     TIFFFlushData(tifP);
 
@@ -994,7 +1043,7 @@ static void
 createTiffColorMap(struct pam *       const pamP,
                    unsigned int       const bitspersample,
                    tupletable         const chv,
-                   unsigned int       const colors,
+                   unsigned int       const colorCt,
                    unsigned short *** const tiffColorMapP) {
 
     unsigned int const colorMapSize = 1 << bitspersample;
@@ -1009,7 +1058,7 @@ createTiffColorMap(struct pam *       const pamP,
     for (i = 0; i < colorMapSize; ++i) {
         unsigned int plane;
         for (plane = 0; plane < pamP->depth; ++plane) {
-            if (i < colors)
+            if (i < colorCt)
                 tiffColorMap[plane][i] =
                     chv[i]->tuple[plane] * 65535L / pamP->maxval;
             else
@@ -1136,7 +1185,7 @@ convertImage(FILE *       const ifP,
     tuplehash cht;
     unsigned short ** tiffColorMap;  /* malloc'ed */
     struct pam pam;
-    unsigned int colors;
+    unsigned int colorCt;
     bool grayscale;
     unsigned short photometric;
     unsigned short samplesperpixel;
@@ -1152,14 +1201,16 @@ convertImage(FILE *       const ifP,
 
     pm_tell2(ifP, &rasterPos, sizeof(rasterPos));
 
-    analyzeColors(&pam, cmdline, MAXCOLORS, &chv, &colors, &grayscale);
+    analyzeColors(&pam, cmdline, MAXCOLORS, &chv, &colorCt, &grayscale);
+
+    reportTiffType(grayscale, chv != NULL, colorCt, cmdline.verbose);
 
     /* Go back to beginning of raster */
     pm_seek2(ifP, &rasterPos, sizeof(rasterPos));
 
     /* Figure out TIFF parameters. */
 
-    computeRasterParm(&pam, chv, colors, grayscale,
+    computeRasterParm(&pam, chv, colorCt, grayscale,
                       cmdline.compression,
                       cmdline.minisblack, cmdline.miniswhite,
                       cmdline.indexsizeAllowed,
@@ -1172,10 +1223,10 @@ convertImage(FILE *       const ifP,
         cht = NULL;
         tiffColorMap = NULL;
     } else {
-        createTiffColorMap(&pam, bitspersample, chv, colors, &tiffColorMap);
+        createTiffColorMap(&pam, bitspersample, chv, colorCt, &tiffColorMap);
 
         /* Convert color vector to color hash table, for fast lookup. */
-        cht = pnm_computetupletablehash(&pam, chv, colors);
+        cht = pnm_computetupletablehash(&pam, chv, colorCt);
         pnm_freetupletable(&pam, chv);
     }
 
@@ -1193,9 +1244,6 @@ convertImage(FILE *       const ifP,
 
 
 
-
-
-
 int
 main(int argc, const char *argv[]) {
     CmdlineInfo cmdline;
@@ -1205,7 +1253,7 @@ main(int argc, const char *argv[]) {
     int ofd;
     int eof;
     unsigned int imageSeq;
-    
+
     pm_proginit(&argc, argv);
 
     parseCommandLine(argc, argv, &cmdline);
@@ -1229,7 +1277,7 @@ main(int argc, const char *argv[]) {
         break;
     }
 
-    eof = FALSE;  /* initial assumption */
+    eof = false;  /* initial assumption */
     imageSeq = 0;
 
     while (!eof) {
@@ -1254,9 +1302,11 @@ main(int argc, const char *argv[]) {
         }
     }
 
-    destroyTiffGenerator(cmdline.writeMethod, tifP, ofd);
+    closeTiffGenerator(cmdline.writeMethod, tifP, ofd);
     pm_close(ifP);
 
+    freeCmdline(cmdline);
+
     return 0;
 }