OK. It turns out that the incorrect pixel wasn't black, it was
transparent.

The bug occurs when an alpha-map file specifying an entirely opaque
image is used. If -force is not specified, pnmtopng converts from an
alpha mask to a transparency index, using a pixel generated from
uninitialised data on the stack (which would be why pre-linking the
libraries gave a different result - probably still wrong, but less
visible).

The attached patch does three things:

1. alpha_trans() no longer modifies *alpha_transcolorP unless it's
   valid (i.e. *alpha_can_be_transparency_indexP is being set to TRUE)

2. We no longer say that we can be made transparent if the alphamap is
   completely opaque.

3. We now don't produce any alpha information if the alpha map is
   completely opaque unless -force is specified.

diff -u3 -r netpbm-free-10.0/pnm/pnmtopng.c 
netpbm-free-10.0.patched/pnm/pnmtopng.c
--- netpbm-free-10.0/pnm/pnmtopng.c     2005-08-26 03:25:17.000000000 +0000
+++ netpbm-free-10.0.patched/pnm/pnmtopng.c     2005-08-26 04:30:33.000000000 
+0000
@@ -566,7 +566,8 @@
             xelval  const maxval, int const format, 
             gray ** const alpha_mask, gray alpha_maxval,
             bool *  const alpha_can_be_transparency_indexP, 
-            pixel*  const alpha_transcolorP) {
+            pixel*  const alpha_transcolorP,
+            bool *  const alpha_is_completely_opaqueP) {
 /*----------------------------------------------------------------------------
   Check if the alpha mask can be represented by a single transparency
   value (i.e. all colors fully opaque except one fully transparent;
@@ -583,6 +584,7 @@
         /* We found a pixel in the image where the alpha mask says it is
            transparent.
         */
+    bool completely_opaque;
     pixel transcolor;
         /* Color of the transparent pixel mentioned above. */
     int const pnm_type = PNM_FORMAT_TYPE(format);
@@ -594,7 +596,9 @@
         /* Find a candidate transparent color -- the color of any pixel in the
            image that the alpha mask says should be transparent.
         */
+        completely_opaque = TRUE;
         found_transparent_pixel = FALSE;  /* initial assumption */
+        retval = FALSE;  /* if we don't find any transparent pixels */
         pm_seek(ifp, imagepos);
         for (row = 0 ; row < rows && !found_transparent_pixel ; ++row) {
             int col;
@@ -602,7 +606,10 @@
             for (col = 0 ; col < cols && !found_transparent_pixel; ++col) {
                 if (alpha_mask[row][col] == 0) {
                     found_transparent_pixel = TRUE;
+                    completely_opaque = FALSE;
                     transcolor = xeltopixel(xelrow[col]);
+                } else if (alpha_mask[row][col] != alpha_maxval) {
+                    completely_opaque = FALSE;
                 }
             }
         }
@@ -651,7 +658,10 @@
     pnm_freerow(xelrow);
 
     *alpha_can_be_transparency_indexP = retval;
-    *alpha_transcolorP = transcolor;
+    *alpha_is_completely_opaqueP = completely_opaque;
+    if (retval) {
+      *alpha_transcolorP = transcolor;
+    }
 }
 
 
@@ -1104,6 +1114,7 @@
   int alpha_rows;
   int alpha_cols;
   int alpha_can_be_transparency_index;
+  int alpha_is_completely_opaque;
 
   int colors;
   int fulldepth;
@@ -1201,7 +1212,8 @@
     }
     alpha_trans(ifp, imagepos, cols, rows, maxval, format, 
                 alpha_mask, alpha_maxval,
-                &alpha_can_be_transparency_index, &alpha_transcolor);
+                &alpha_can_be_transparency_index,
+                &alpha_transcolor, &alpha_is_completely_opaque);
 
     if (alpha_can_be_transparency_index && !force) {
       if (verbose)
@@ -1210,7 +1222,14 @@
       transparent = 2;
       transcolor = alpha_transcolor;
     } else {
-      transparent = -1;
+      if (alpha_is_completely_opaque && !force) {
+        if (verbose)
+          pm_message ("converting opaque alpha mask to non-transparent image");
+        alpha = FALSE;
+        transparent = -1;
+      } else {
+        transparent = -1;
+      }
     }
   } else
       /* Though there's no alpha_mask, we still need an alpha_maxval for

Reply via email to