tiff: Add support for CCITT group 3/4 compression

The algorithm is described at https://www.itu.int/rec/T-REC-T.6/en

Fixes golang/go#19443

Change-Id: Ib8a078ab43c78d1f58d2ac849ed455b05dc209e9
Reviewed-on: https://go-review.googlesource.com/c/image/+/174139
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
Run-TryBot: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/testdata/bw-gopher.png b/testdata/bw-gopher.png
new file mode 100644
index 0000000..6e8e957
--- /dev/null
+++ b/testdata/bw-gopher.png
Binary files differ
diff --git a/testdata/bw-gopher_ccittGroup3.tiff b/testdata/bw-gopher_ccittGroup3.tiff
new file mode 100644
index 0000000..1b969b4
--- /dev/null
+++ b/testdata/bw-gopher_ccittGroup3.tiff
Binary files differ
diff --git a/testdata/bw-gopher_ccittGroup4.tiff b/testdata/bw-gopher_ccittGroup4.tiff
new file mode 100644
index 0000000..aeeef8a
--- /dev/null
+++ b/testdata/bw-gopher_ccittGroup4.tiff
Binary files differ
diff --git a/tiff/consts.go b/tiff/consts.go
index 3c51a70..3e5f7f1 100644
--- a/tiff/consts.go
+++ b/tiff/consts.go
@@ -42,11 +42,16 @@
 	tCompression               = 259
 	tPhotometricInterpretation = 262
 
+	tFillOrder = 266
+
 	tStripOffsets    = 273
 	tSamplesPerPixel = 277
 	tRowsPerStrip    = 278
 	tStripByteCounts = 279
 
+	tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits.
+	tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits.
+
 	tTileWidth      = 322
 	tTileLength     = 323
 	tTileOffsets    = 324
@@ -112,22 +117,33 @@
 	mRGB
 	mRGBA
 	mNRGBA
+	mCMYK
 )
 
 // CompressionType describes the type of compression used in Options.
 type CompressionType int
 
+// Constants for supported compression types.
 const (
 	Uncompressed CompressionType = iota
 	Deflate
+	LZW
+	CCITTGroup3
+	CCITTGroup4
 )
 
 // specValue returns the compression type constant from the TIFF spec that
 // is equivalent to c.
 func (c CompressionType) specValue() uint32 {
 	switch c {
+	case LZW:
+		return cLZW
 	case Deflate:
 		return cDeflate
+	case CCITTGroup3:
+		return cG3
+	case CCITTGroup4:
+		return cG4
 	}
 	return cNone
 }
diff --git a/tiff/reader.go b/tiff/reader.go
index ce2ef71..c26ec36 100644
--- a/tiff/reader.go
+++ b/tiff/reader.go
@@ -17,6 +17,7 @@
 	"io/ioutil"
 	"math"
 
+	"golang.org/x/image/ccitt"
 	"golang.org/x/image/tiff/lzw"
 )
 
@@ -129,7 +130,10 @@
 		tTileOffsets,
 		tTileByteCounts,
 		tImageLength,
-		tImageWidth:
+		tImageWidth,
+		tFillOrder,
+		tT4Options,
+		tT6Options:
 		val, err := d.ifdUint(p)
 		if err != nil {
 			return 0, err
@@ -441,7 +445,8 @@
 	d.config.Height = int(d.firstVal(tImageLength))
 
 	if _, ok := d.features[tBitsPerSample]; !ok {
-		return nil, FormatError("BitsPerSample tag missing")
+		// Default is 1 per specification.
+		d.features[tBitsPerSample] = []uint{1}
 	}
 	d.bpp = d.firstVal(tBitsPerSample)
 	switch d.bpp {
@@ -539,6 +544,13 @@
 	return d.config, nil
 }
 
+func ccittFillOrder(tiffFillOrder uint) ccitt.Order {
+	if tiffFillOrder == 2 {
+		return ccitt.LSB
+	}
+	return ccitt.MSB
+}
+
 // Decode reads a TIFF image from r and returns it as an image.Image.
 // The type of Image returned depends on the contents of the TIFF.
 func Decode(r io.Reader) (img image.Image, err error) {
@@ -644,6 +656,16 @@
 					d.buf = make([]byte, n)
 					_, err = d.r.ReadAt(d.buf, offset)
 				}
+			case cG3:
+				inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
+				order := ccittFillOrder(d.firstVal(tFillOrder))
+				r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
+				d.buf, err = ioutil.ReadAll(r)
+			case cG4:
+				inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
+				order := ccittFillOrder(d.firstVal(tFillOrder))
+				r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
+				d.buf, err = ioutil.ReadAll(r)
 			case cLZW:
 				r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
 				d.buf, err = ioutil.ReadAll(r)
diff --git a/tiff/reader_test.go b/tiff/reader_test.go
index 53d2b3c..82134c4 100644
--- a/tiff/reader_test.go
+++ b/tiff/reader_test.go
@@ -193,6 +193,32 @@
 	compare(t, img0, img1)
 }
 
+// TestDecodeCCITT tests that decoding a PNG image and a CCITT compressed TIFF
+// image result in the same pixel data.
+func TestDecodeCCITT(t *testing.T) {
+	// TODO Add more tests.
+	for _, fn := range []string{
+		"bw-gopher",
+	} {
+		img0, err := load(fn + ".png")
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		img1, err := load(fn + "_ccittGroup3.tiff")
+		if err != nil {
+			t.Fatal(err)
+		}
+		compare(t, img0, img1)
+
+		img2, err := load(fn + "_ccittGroup4.tiff")
+		if err != nil {
+			t.Fatal(err)
+		}
+		compare(t, img0, img2)
+	}
+}
+
 // TestDecodeTagOrder tests that a malformed image with unsorted IFD entries is
 // correctly rejected.
 func TestDecodeTagOrder(t *testing.T) {
diff --git a/tiff/writer_test.go b/tiff/writer_test.go
index 05e27d2..0650df3 100644
--- a/tiff/writer_test.go
+++ b/tiff/writer_test.go
@@ -42,6 +42,7 @@
 		if err != nil {
 			t.Fatal(err)
 		}
+
 		out := new(bytes.Buffer)
 		err = Encode(out, img, rt.opts)
 		if err != nil {