2014.12.27 23:06 "[Tiff] [PATCH] tiff2ps: fix grayscale with unassociated alpha (and other extrasamples != 0)", by Yuriy M. Kaminskiy

2014.12.27 23:06 "[Tiff] [PATCH] tiff2ps: fix grayscale with unassociated alpha (and other extrasamples != 0)", by Yuriy M. Kaminskiy

Attempt to convert grayscale (min-is-black/white) with unassociated alpha tiff produces broken postscript output. See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=611141 and https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=552382 Patch attached.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
NotDashEscaped: You need GnuPG to verify this message

From: Yuriy M. Kaminskiy <yumkam@gmail.com>

Subject: [PATCH][v3] tiff2ps: fix grayscale with unassociated alpha (and other extrasamples != 0)

See: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=611141 Note: this patch only fixes postscript level 1 output from grayscale source.

While fixing this bug, I've found a lot of other broken cases:

  1. postscript 2+ from any PLANARCONFIG_SEPARATE source (/MultipleDataSources does not work this way, and I doubt in can be used in tiff2ps at all)
  2. postscript 2+ from compressed source with alpha
  3. postscript 1 from compressed color source with PLANARCONFIG_SEPARATE
  4. postscript 1 from jbig compressed tiff

Index: tiff-4.0.x-20141215/tools/tiff2ps.c

=================================================================== --- tiff-4.0.x-20141215.orig/tools/tiff2ps.c 2014-12-28 01:35:28.548097063 +0300 +++ tiff-4.0.x-20141215/tools/tiff2ps.c 2014-12-28 01:39:03.720095721 +0300 @@ -41,6 +41,7 @@

 #endif

 #include "tiffio.h"
+#include "tiffiop.h" /* TIFFSafeMultiply */

 /*
  * Revision history
@@ -2595,6 +2596,11 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w,
        unsigned char* cp;
        tsize_t stripsize = TIFFStripSize(tif);
        tstrip_t s;

+       int sp = samplesperpixel;
+       int nc = samplesperpixel - extrasamples;
+       tstrip_t ns = TIFFNumberOfStrips(tif);
+       tsize_t buf_size = stripsize;
+       tstrip_t strip_offset = 0;

 #if defined( EXP_ASCII85ENCODER )

        tsize_t ascii85_l;              /* Length, in bytes, of ascii85_p[] data */

@@ -2602,7 +2608,19 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w,
 #endif

        (void) w; (void) h;

-       tf_buf = (unsigned char *) _TIFFmalloc(stripsize);
+
+       if (planarconfiguration == PLANARCONFIG_SEPARATE) {
+           if (sp > 1) {
+               ns = TIFFComputeStrip(tif, 0, 1); /* ns / sp */
+               strip_offset = nc == 1 ? ns : TIFFComputeStrip(tif, 0, nc); /* nc * ns */
+               sp = 1;
+           }
+           nc = stripsize;
+           if (alpha) /* space for alpha strip */
+               buf_size = TIFFSafeMultiply(tsize_t, stripsize, 2);
+       }
+
+       tf_buf = (unsigned char *) _TIFFmalloc(buf_size);
        if (tf_buf == NULL) {
                TIFFError(filename, "No space for scanline buffer");
                return;
@@ -2636,12 +2654,20 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, 
        if (ascii85)
                Ascii85Init();

-       for (s = 0; s < TIFFNumberOfStrips(tif); s++) {
+       for (s = 0; s < ns; s++) {
                tmsize_t cc = TIFFReadEncodedStrip(tif, s, tf_buf, stripsize);
                if (cc < 0) {
                        TIFFError(filename, "Can't read strip");
                        break;
                }
+               if (alpha && strip_offset) {
+                       if (TIFFReadEncodedStrip(tif, s + strip_offset,
+                                                tf_buf + stripsize,
+                                                stripsize) != cc) {
+                               TIFFError(filename, "Can't read alpha strip");
+                               break;
+                       }
+               }
                cp = tf_buf;
                if (photometric == PHOTOMETRIC_MINISWHITE) {
                        for (cp += cc; --cp >= tf_buf;)
@@ -2657,13 +2683,19 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, 
                }
                if (ascii85) {
 #if defined( EXP_ASCII85ENCODER )
-                       if (alpha) {
-                               int adjust, i;
-                               for (i = 0; i < cc; i+=2) {
-                                       adjust = 255 - cp[i + 1];
-                                   cp[i / 2] = cp[i] + adjust;
+                       if (alpha && sp != nc) {
+                               int adjust, i, j = 0;
+                               for (i = 0; i < cc; i += sp) {
+                                       adjust = 255 - cp[i + nc];
+                                   cp[j++] = cp[i] + adjust;
                                }
-                               cc /= 2;
+                               cc = j;
+                       } else if (sp != 1) {
+                               int i, j = 0;
+                               for (i = 0; i < cc; i += sp) {
+                                   cp[j++] = cp[i];
+                               }
+                               cc = j;
                        }

                        ascii85_l = Ascii85EncodeBlock( ascii85_p, 1, cp, cc );
@@ -2671,15 +2703,15 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, 
                        if ( ascii85_l > 0 )
                            fwrite( ascii85_p, ascii85_l, 1, fd );
 #else
-                       while (cc-- > 0)
-                               Ascii85Put(*cp++, fd);
+                       for (; cc > 0; cc -= sp, cp += sp)
+                               Ascii85Put(*cp, fd);
 #endif /* EXP_ASCII85_ENCODER */

                } else {
                        unsigned char c;

                        if (alpha) {
                                int adjust;
- while (cc-- > 0) {
+ for ( ; cc >= sp; cc -= sp, cp += sp) {
                                        DOBREAK(breaklen, 1, fd);
                                        /*

                                         * For images with alpha, matte against
@@ -2687,13 +2719,12 @@ PSDataBW(FILE* fd, TIFF* tif, uint32 w, 
                                         *    Cback * (1 - Aimage)
                                         * where Cback = 1.
                                         */

+                                       adjust = 255 - cp[nc];
+                                       c = *cp + adjust; PUTHEX(c,fd);
                                }
                        } else {
-                               while (cc-- > 0) {
-                                       c = *cp++;
+                               for (; cc >= sp; cc -= sp, cp += sp) {
+                                       c = *cp;

                                        DOBREAK(breaklen, 1, fd);
                                        PUTHEX(c, fd);
                                }
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iF4EAREIAAYFAlSfOKUACgkQKZn9iF16KMOB9gD/f1w4d6udFWyaDIJ+ZL2vSARg qnCW6pWIleyQ9ir9mqQBAImK7U1sEQHsYobdCuB0b0qcRPpur9H0opP7ti9vMR6u

=GmJZ
-----END PGP SIGNATURE-----