2014.12.23 03:11 "[Tiff] TIFF JBIG writer and scanlines", by Bob Friesenhahn

2014.12.29 22:42 "[Tiff] [PATCH] tiffcp: use buffered by-strip conversion for jbig instead of by-scanline (was: TIFF JBIG writer and scanlines)", by Yuriy M. Kaminskiy

Today I encountered this:

% tiffcp -r -1 -c jbig golfer-150-bilevel.tiff golfer-150-bilevel-jbig.tiff golfer-150-bilevel-jbig.tiff: ISO JBIG scanline encoding is not implemented.

golfer-150-bilevel-jbig.tiff: Error, can't write scanline 0.

This was due to a GraphicsMagick user reporting that scanline reading sometimes fails due to libtiff's JBIG support reporting that reading via scanlines is not supported. I used the tiffcp incantation he provided and encountered the same error as when GraphicsMagick tries to write via its scanline writer.

This is using jbigkit-2.0. I tried on a machine with jbigkit-1.6 and it worked.

Ideas?

Apparently, it fails when source has more than one strip.
Working:
  Image Width: 1100 Image Length: 1600
  Rows/Strip: 1600
Failing:
  Image Width: 1100 Image Length: 1600
  Rows/Strip: 256
Conversion in two steps works:
tiffcp -r -1 in.tiff temp.tiff # convert to single strip
tiffcp -c jbig temp.tiff out.tiff # compress to jbig

Attached patch should solve this.

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

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

Subject: tiffcp: use buffered by-strip conversion for jbig instead of by-scanline

LibTiff JBIG encoder only supports by-strip encoding/decoding.

Index: tiff-3.9.4/tools/tiffcp.c
===================================================================

--- tiff-3.9.4.orig/tools/tiffcp.c      2014-12-23 18:42:25.680097625 +0300

+++ tiff-3.9.4/tools/tiffcp.c   2014-12-23 18:57:45.680096066 +0300
@@ -1542,6 +1542,50 @@ DECLAREcpFunc(cpContigStrips2SeparateTil
 }

 /*
+ * Contig strips -> contig strips (change chunk & jbig).
+ */
+DECLAREcpFunc(cpContigStrips2ContigStrips)
+{
+       return cpImage(in, out,
+           readContigStripsIntoBuffer,
+           writeBufferToContigStrips,
+           imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig strips -> separate strips (change chunk & jbig).
+ */
+DECLAREcpFunc(cpContigStrips2SeparateStrips)
+{
+       return cpImage(in, out,
+           readContigStripsIntoBuffer,
+           writeBufferToSeparateStrips,
+           imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> contig strips (change chunk & jbig).
+ */
+DECLAREcpFunc(cpSeparateStrips2ContigStrips)
+{
+       return cpImage(in, out,
+           readSeparateStripsIntoBuffer,
+           writeBufferToContigStrips,
+           imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> separate strips (change chunk & jbig).
+ */
+DECLAREcpFunc(cpSeparateStrips2SeparateStrips)
+{
+       return cpImage(in, out,
+           readSeparateStripsIntoBuffer,
+           writeBufferToSeparateStrips,
+           imagelength, imagewidth, spp);
+}
+
+/*
  * Separate strips -> contig tiles.
  */
 DECLAREcpFunc(cpSeparateStrips2ContigTiles)
@@ -1660,6 +1704,7 @@ pickCopyFunc(TIFF* in, TIFF* out, uint16
        uint16 shortv;
        uint32 w, l, tw, tl;
        int bychunk;
+       uint16 input_compression, output_compression;

        (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
        if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {
@@ -1694,6 +1739,8 @@ pickCopyFunc(TIFF* in, TIFF* out, uint16
                bychunk = (tw == w && tl == rowsperstrip);
             }
        }
+       TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
+       TIFFGetFieldDefaulted(out, TIFFTAG_COMPRESSION, &output_compression);
 #define        T 1
 #define        F 0
 #define pack(a,b,c,d,e)        ((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e)))
@@ -1739,17 +1786,32 @@ pickCopyFunc(TIFF* in, TIFF* out, uint16
                return cpSeparateTiles2SeparateStrips;
 /* Strips -> Strips */
        case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,F):
+               if (input_compression == COMPRESSION_JBIG ||
+                   output_compression == COMPRESSION_JBIG)
+                       return cpContigStrips2ContigStrips;
                return bias ? cpBiasedContig2Contig : cpContig2ContigByRow;
        case pack(PLANARCONFIG_CONTIG,   PLANARCONFIG_CONTIG,   F,F,T):
+               if (input_compression == COMPRESSION_JBIG ||
+                   output_compression == COMPRESSION_JBIG)
+                       return cpContigStrips2ContigStrips;
                return cpDecodedStrips;
        case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,F):
        case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE,   F,F,T):
+               if (input_compression == COMPRESSION_JBIG ||
+                   output_compression == COMPRESSION_JBIG)
+                       return cpContigStrips2SeparateStrips;
                return cpContig2SeparateByRow;
        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,F):
        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG,   F,F,T):
+               if (input_compression == COMPRESSION_JBIG ||
+                   output_compression == COMPRESSION_JBIG)
+                       return cpSeparateStrips2ContigStrips;
                return cpSeparate2ContigByRow;
        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F):
        case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T):
+               if (input_compression == COMPRESSION_JBIG ||
+                   output_compression == COMPRESSION_JBIG)
+                       return cpSeparateStrips2SeparateStrips;

                return cpSeparate2SeparateByRow;
        }
 #undef pack
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iF4EAREIAAYFAlSh1/EACgkQKZn9iF16KMNk4gD/SAhCyNaloRX6ChEDQQGfkGYz
3kP5RF0qNANiqOgqtxsA/2ahdZW2JBdW65j5Cw1nG2usUqCYUCYKTc/4pd6lE0B8
=+t36
-----END PGP SIGNATURE-----