go.image/tiff: fix (TIFF-specific) LZW decompression.
The blue-purple-pink.lzwcompressed.tiff image was created by "bmp2tiff -c lzw". LGTM=djd R=djd CC=bsiegert, golang-codereviews https://golang.org/cl/105750045
This commit is contained in:
parent
2bda575717
commit
a1da419f1a
BIN
testdata/blue-purple-pink.lzwcompressed.tiff
vendored
Normal file
BIN
testdata/blue-purple-pink.lzwcompressed.tiff
vendored
Normal file
Binary file not shown.
BIN
testdata/blue-purple-pink.png
vendored
Normal file
BIN
testdata/blue-purple-pink.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -6,13 +6,32 @@
|
||||||
// described in T. A. Welch, ``A Technique for High-Performance Data
|
// described in T. A. Welch, ``A Technique for High-Performance Data
|
||||||
// Compression'', Computer, 17(6) (June 1984), pp 8-19.
|
// Compression'', Computer, 17(6) (June 1984), pp 8-19.
|
||||||
//
|
//
|
||||||
// In particular, it implements LZW as used by the GIF, TIFF and PDF file
|
// In particular, it implements LZW as used by the TIFF file format, including
|
||||||
// formats, which means variable-width codes up to 12 bits and the first
|
// an "off by one" algorithmic difference when compared to standard LZW.
|
||||||
// two non-literal codes are a clear code and an EOF code.
|
|
||||||
package lzw
|
package lzw
|
||||||
|
|
||||||
// TODO(nigeltao): check that TIFF and PDF use LZW in the same way as GIF,
|
/*
|
||||||
// modulo LSB/MSB packing order.
|
This file was branched from src/pkg/compress/lzw/reader.go in the
|
||||||
|
standard library. Differences from the original are marked with "NOTE".
|
||||||
|
|
||||||
|
The tif_lzw.c file in the libtiff C library has this comment:
|
||||||
|
|
||||||
|
----
|
||||||
|
The 5.0 spec describes a different algorithm than Aldus
|
||||||
|
implements. Specifically, Aldus does code length transitions
|
||||||
|
one code earlier than should be done (for real LZW).
|
||||||
|
Earlier versions of this library implemented the correct
|
||||||
|
LZW algorithm, but emitted codes in a bit order opposite
|
||||||
|
to the TIFF spec. Thus, to maintain compatibility w/ Aldus
|
||||||
|
we interpret MSB-LSB ordered codes to be images written w/
|
||||||
|
old versions of this library, but otherwise adhere to the
|
||||||
|
Aldus "off by one" algorithm.
|
||||||
|
----
|
||||||
|
|
||||||
|
The Go code doesn't read (invalid) TIFF files written by old versions of
|
||||||
|
libtiff, but the LZW algorithm in this package still differs from the one in
|
||||||
|
Go's standard package library to accomodate this "off by one" in valid TIFFs.
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -53,7 +72,7 @@ type decoder struct {
|
||||||
// The next two codes mean clear and EOF.
|
// The next two codes mean clear and EOF.
|
||||||
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
|
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
|
||||||
// with the upper bound incrementing on each code seen.
|
// with the upper bound incrementing on each code seen.
|
||||||
// overflow is the code at which hi overflows the code width.
|
// overflow is the code at which hi overflows the code width. NOTE: TIFF's LZW is "off by one".
|
||||||
// last is the most recently seen code, or decoderInvalidCode.
|
// last is the most recently seen code, or decoderInvalidCode.
|
||||||
clear, eof, hi, overflow, last uint16
|
clear, eof, hi, overflow, last uint16
|
||||||
|
|
||||||
|
@ -189,7 +208,7 @@ func (d *decoder) decode() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.last, d.hi = code, d.hi+1
|
d.last, d.hi = code, d.hi+1
|
||||||
if d.hi >= d.overflow {
|
if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm.
|
||||||
if d.width == maxWidth {
|
if d.width == maxWidth {
|
||||||
d.last = decoderInvalidCode
|
d.last = decoderInvalidCode
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
package tiff
|
package tiff
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/lzw"
|
|
||||||
"compress/zlib"
|
"compress/zlib"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -16,6 +15,8 @@ import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"code.google.com/p/go.image/tiff/lzw"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A FormatError reports that the input is not a valid TIFF image.
|
// A FormatError reports that the input is not a valid TIFF image.
|
||||||
|
|
|
@ -125,6 +125,21 @@ func TestDecode(t *testing.T) {
|
||||||
compare(t, img0, img4)
|
compare(t, img0, img4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDecodeLZW tests that decoding a PNG image and a LZW-compressed TIFF image
|
||||||
|
// result in the same pixel data.
|
||||||
|
func TestDecodeLZW(t *testing.T) {
|
||||||
|
img0, err := load("blue-purple-pink.png")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
img1, err := load("blue-purple-pink.lzwcompressed.tiff")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
compare(t, img0, img1)
|
||||||
|
}
|
||||||
|
|
||||||
// TestDecompress tests that decoding some TIFF images that use different
|
// TestDecompress tests that decoding some TIFF images that use different
|
||||||
// compression formats result in the same pixel data.
|
// compression formats result in the same pixel data.
|
||||||
func TestDecompress(t *testing.T) {
|
func TestDecompress(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user