about summary refs log tree commit diff
path: root/converter/ppm/ppmtopict.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/ppm/ppmtopict.c')
-rw-r--r--converter/ppm/ppmtopict.c220
1 files changed, 133 insertions, 87 deletions
diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c
index 36464b6c..c7f1d61d 100644
--- a/converter/ppm/ppmtopict.c
+++ b/converter/ppm/ppmtopict.c
@@ -12,8 +12,10 @@
 */
 
 #include <assert.h>
+
 #include "pm_c_util.h"
 #include "pm.h"
+#include "mallocvar.h"
 #include "ppm.h"
 
 #define HEADER_SIZE     512
@@ -130,14 +132,15 @@
 #define PICT_headerOp       0x0C00
 
 #define MAXCOLORS 256
-static colorhash_table cht;
 
 
 
 static void
 putFill(FILE *       const ifP,
         unsigned int const n) {
-
+/*----------------------------------------------------------------------------
+   Write 'n' bytes of zeroes to *ifP.
+-----------------------------------------------------------------------------*/
     unsigned int i;
 
     for (i = 0; i < n; ++i)
@@ -194,19 +197,21 @@ putRect(FILE * const ifP,
 #define     counttochar(c)  ((c)-1)
 
 static void
-putRow(FILE *         const ofP,
-       unsigned int   const row,
-       unsigned int   const cols,
-       pixel *        const rowpixels,
-       char *         const outBuf,
-       unsigned int * const outCountP) {
+putRow(FILE *          const ofP,
+       unsigned int    const row,
+       unsigned int    const cols,
+       pixel *         const rowpixels,
+       colorhash_table const cht,
+       unsigned char * const outBuf,
+       unsigned int *  const outCountP) {
 /*----------------------------------------------------------------------------
    Write the row rowpixels[], which is 'cols' pixels wide and is row 'row' of
    the image, to file *ofP in PICT format.
 
    Return as *outCountP the number of bytes we write to *ofP.
 
-   Use buffer 'outBuf'.
+   Use buffer 'outBuf', which is at least 1.5*cols + 1 bytes -- the worst
+   case compacted size of the row.
 -----------------------------------------------------------------------------*/
     unsigned int i;
     unsigned int count;
@@ -214,13 +219,13 @@ putRow(FILE *         const ofP,
     unsigned int rep;
     unsigned int outCount;
     pixel lastpix;
-    char * p;
+    unsigned int outCursor;
 
-    run = 0;
-    count = 0;
-    lastpix = rowpixels[cols-1];
+    run = 0;  /* initial value */
+    count = 0;  /* initial value */
+    lastpix = rowpixels[cols-1];  /* initial value */
 
-    for (i = 0, p = &outBuf[0]; i < cols; ++i) {
+    for (i = 0, outCursor = 0; i < cols; ++i) {
 
         pixel const pix = rowpixels[cols - 1 - i];
 
@@ -228,23 +233,23 @@ putRow(FILE *         const ofP,
             ++run;
         else if (run < RUN_THRESH) {
             while (run > 0) {
-                *p++ = ppm_lookupcolor(cht, &lastpix);
+                outBuf[outCursor++] = ppm_lookupcolor(cht, &lastpix);
                 --run;
                 ++count;
                 if (count == MAX_COUNT) {
-                    *p++ = counttochar(MAX_COUNT);
+                    outBuf[outCursor++] = counttochar(MAX_COUNT);
                     count -= MAX_COUNT;
                 }
             }
             run = 1;
         } else {
             if (count > 0)
-                *p++ = counttochar(count);
+                outBuf[outCursor++] = counttochar(count);
             count = 0;
             while (run > 0) {
                 rep = MIN(run, MAX_RUN);
-                *p++ = ppm_lookupcolor(cht, &lastpix);
-                *p++ = runtochar(rep);
+                outBuf[outCursor++] = ppm_lookupcolor(cht, &lastpix);
+                outBuf[outCursor++] = runtochar(rep);
                 assert(run >= rep);
                 run -= rep;
             }
@@ -254,46 +259,43 @@ putRow(FILE *         const ofP,
     }
     if (run < RUN_THRESH) {
         while (run > 0) {
-            *p++ = ppm_lookupcolor(cht, &lastpix);
+            outBuf[outCursor++] = ppm_lookupcolor(cht, &lastpix);
             --run;
             ++count;
             if (count == MAX_COUNT) {
-                *p++ = counttochar(MAX_COUNT);
+                outBuf[outCursor++] = counttochar(MAX_COUNT);
                 count -= MAX_COUNT;
             }
         }
     } else {
         if (count > 0)
-            *p++ = counttochar(count);
+            outBuf[outCursor++] = counttochar(count);
         count = 0;
         while (run > 0) {
             rep = MIN(run, MAX_RUN);
-            *p++ = ppm_lookupcolor(cht, &lastpix);
-            *p++ = runtochar(rep);
+            outBuf[outCursor++] = ppm_lookupcolor(cht, &lastpix);
+            outBuf[outCursor++] = runtochar(rep);
             assert(run >= rep);
             run -= rep;
         }
         run = 1;
     }
     if (count > 0)
-        *p++ = counttochar(count);
+        outBuf[outCursor++] = counttochar(count);
 
-    {
-        unsigned int const packcols = p - outBuf;
-            /* How many we wrote */
-        if (cols-1 > 200) {
-            putShort(ofP, packcols);
-            outCount = packcols + 2;
-        } else {
-            putc(packcols, ofP);
-            outCount = packcols + 1;
-        }
-    }
-    /* now write out the packed row */
-    while (p != outBuf) {
-        --p;
-        putc(*p, ofP);
+    /* Write out the packed row */
+
+    if (cols-1 > 200) {
+        putShort(ofP, outCursor);
+        outCount = outCursor + 2;
+    } else {
+        putc(outCursor, ofP);
+        outCount = outCursor + 1;
     }
+
+    for (i = 0; i < outCursor; ++i)
+        putc(outBuf[outCursor-i-1], ofP);
+
     *outCountP = outCount;
 }
 
@@ -303,12 +305,13 @@ putRow(FILE *         const ofP,
 
 /* real dumb putRow with no compression */
 static void
-putRow(FILE *         const ifP,
-       unsigned int   const row,
-       unsigned int   const cols,
-       pixel *        const rowpixels,
-       char *         const outBuf,
-       unsigned int * const outCountP) {
+putRow(FILE *          const ifP,
+       unsigned int    const row,
+       unsigned int    const cols,
+       pixel *         const rowpixels,
+       char *          const outBuf,
+       colorhash_table const cht,
+       unsigned int *  const outCountP) {
 
     unsigned int const bc = cols + (cols + MAX_COUNT - 1) / MAX_COUNT;
 
@@ -345,20 +348,82 @@ putRow(FILE *         const ifP,
 
 
 
+static void
+writeColorMap(FILE *           const ofP,
+              colorhist_vector const chv,
+              unsigned int     const colorCt,
+              long             const lmaxval) {
+
+    unsigned int i;
+
+    for (i = 0; i < colorCt; ++i) {
+        long rval, gval, bval;
+
+        putShort(ofP, i);
+        rval = PPM_GETR(chv[i].color);
+        gval = PPM_GETG(chv[i].color);
+        bval = PPM_GETB(chv[i].color);
+        if (lmaxval != 65535L) {
+            rval = rval * 65535L / lmaxval;
+            gval = gval * 65535L / lmaxval;
+            bval = bval * 65535L / lmaxval;
+        }
+        putShort(ofP, (short)rval);
+        putShort(ofP, (short)gval);
+        putShort(ofP, (short)bval);
+    }
+}
+
+
+
+static void
+writeRaster(FILE *          const ofP,
+            pixel **        const pixels,
+            unsigned int    const rows,
+            unsigned int    const cols,
+            colorhash_table const cht) {
+
+    unsigned char * outBuf;  /* malloc'ed */
+    unsigned int oc;
+    unsigned int row;
+
+    if (cols > UINT_MAX - cols/MAX_COUNT - 1) {
+        /* We can't compute the size of buffer 'putRow' needs for worst-case
+           compaction.
+        */
+        pm_error("Image is too wide (%u columns) for computation", cols);
+    }
+
+    MALLOCARRAY(outBuf, cols + cols/MAX_COUNT + 1);
+    if (!outBuf)
+        pm_error("Unable to allocate %u-byte row buffer",
+                 cols + cols/MAX_COUNT + 1);
+
+    for (row = 0, oc = 0; row < rows; ++row) {
+        unsigned int rowSize;
+        putRow(ofP, row, cols, pixels[row], cht, outBuf, &rowSize);
+        oc += rowSize;
+    }
+    /* Pad to an even number of pixdata bytes */
+    if (oc & 0x1)
+        putc(0, ofP);
+
+    free(outBuf);
+}
+
+
+
 int
 main(int argc, const char ** argv) {
 
     FILE * ifP;
-    int nColors;
-    unsigned int oc;
-    unsigned int i;
+    int colorCt;
     int rows, cols;
-    unsigned int row;
     pixel ** pixels;
-    char * outBuf;
     pixval maxval;
-    long lmaxval, rval, gval, bval;
     colorhist_vector chv;
+    colorhash_table cht;
+    long lmaxval;
 
     pm_proginit(&argc, argv);
 
@@ -367,8 +432,8 @@ main(int argc, const char ** argv) {
     else
         ifP = stdin;
     if (argc-1 > 1)
-        pm_error("Too many arguments.  The only argument is the "
-                 "input file name");
+        pm_error("Too many arguments (%u).  The only argument is the "
+                 "input file name", argc-1);
 
     pixels = ppm_readppm(ifP, &cols, &rows, &maxval);
     if (cols < 8)
@@ -378,19 +443,19 @@ main(int argc, const char ** argv) {
 
     /* Figure out the colormap. */
     pm_message("computing colormap..." );
-    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &nColors);
+    chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colorCt);
     if (chv == NULL)
         pm_error("too many colors - try doing a 'pnmquant %u'", MAXCOLORS);
-    pm_message("%u colors found", nColors);
+    pm_message("%u colors found", colorCt);
 
     /* Make a hash table for fast color lookup. */
-    cht = ppm_colorhisttocolorhash(chv, nColors);
+    cht = ppm_colorhisttocolorhash(chv, colorCt);
 
     /* write the header */
     putFill(stdout, HEADER_SIZE);
 
     /* write picSize and picFrame */
-    putShort(stdout, 0);
+    putShort(stdout, 0);  /* We overwrite this later when we know the size */
     putRect(stdout, 0, 0, rows, cols);
 
     /* write version op and version */
@@ -427,43 +492,24 @@ main(int argc, const char ** argv) {
     putLong(stdout, 0L);    /* pmReserved */
     putLong(stdout, 0L);    /* ctSeed */
     putShort(stdout, 0);    /* ctFlags */
-    putShort(stdout, nColors-1); /* ctSize */
+    putShort(stdout, colorCt-1); /* ctSize */
 
-    /* Write out the colormap. */
-    for (i = 0; i < nColors; ++i) {
-        putShort(stdout, i);
-        rval = PPM_GETR(chv[i].color);
-        gval = PPM_GETG(chv[i].color);
-        bval = PPM_GETB(chv[i].color);
-        if (lmaxval != 65535L) {
-            rval = rval * 65535L / lmaxval;
-            gval = gval * 65535L / lmaxval;
-            bval = bval * 65535L / lmaxval;
-        }
-        putShort(stdout, (short)rval);
-        putShort(stdout, (short)gval);
-        putShort(stdout, (short)bval);
-    }
+    writeColorMap(stdout, chv, colorCt, lmaxval);
 
     putRect(stdout, 0, 0, rows, cols);  /* srcRect */
     putRect(stdout, 0, 0, rows, cols);  /* dstRect */
     putShort(stdout, 0);            /* mode */
 
-    /* Finally, write out the data. */
-    outBuf = malloc((unsigned)(cols+cols/MAX_COUNT+1));
-    for (row = 0, oc = 0; row < rows; ++row) {
-        unsigned int rowSize;
-        putRow(stdout, row, cols, pixels[row], outBuf, &rowSize);
-        oc += rowSize;
-    }
-    /* if we wrote an odd number of pixdata bytes, pad */
-    if (oc & 0x1)
-        putc(0, stdout);
+    writeRaster(stdout, pixels, rows, cols, cht);
+
     putShort(stdout, PICT_EndOfPicture);
 
-    lmaxval = ftell(stdout) - HEADER_SIZE;
-    if (fseek(stdout, (long)HEADER_SIZE, 0) >= 0)
-        putShort(stdout, (short)(lmaxval & 0xffff));
+    {
+        /* patch size of pict in */
+        long const picSz = ftell(stdout) - HEADER_SIZE;
+        if (fseek(stdout, (long)HEADER_SIZE, 0) >= 0)
+            putShort(stdout, (short)(picSz & 0xffff));
+    }
 
     return 0;
 }