github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/tiff/reader_test.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package tiff
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"encoding/hex"
    11  	"errors"
    12  	"image"
    13  	"io/ioutil"
    14  	"os"
    15  	"strings"
    16  	"testing"
    17  
    18  	_ "image/png"
    19  )
    20  
    21  const testdataDir = "../testdata/"
    22  
    23  // Read makes *buffer implements io.Reader, so that we can pass one to Decode.
    24  func (*buffer) Read([]byte) (int, error) {
    25  	panic("unimplemented")
    26  }
    27  
    28  func load(name string) (image.Image, error) {
    29  	f, err := os.Open(testdataDir + name)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	defer f.Close()
    34  	img, _, err := image.Decode(f)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return img, nil
    39  }
    40  
    41  // TestNoRPS tests decoding an image that has no RowsPerStrip tag. The tag is
    42  // mandatory according to the spec but some software omits it in the case of a
    43  // single strip.
    44  func TestNoRPS(t *testing.T) {
    45  	_, err := load("no_rps.tiff")
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  }
    50  
    51  // TestNoCompression tests decoding an image that has no Compression tag. This
    52  // tag is mandatory, but most tools interpret a missing value as no
    53  // compression.
    54  func TestNoCompression(t *testing.T) {
    55  	_, err := load("no_compress.tiff")
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  }
    60  
    61  // TestUnpackBits tests the decoding of PackBits-encoded data.
    62  func TestUnpackBits(t *testing.T) {
    63  	var unpackBitsTests = []struct {
    64  		compressed   string
    65  		uncompressed string
    66  	}{{
    67  		// Example data from Wikipedia.
    68  		"\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa",
    69  		"\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
    70  	}}
    71  	for _, u := range unpackBitsTests {
    72  		buf, err := unpackBits(strings.NewReader(u.compressed))
    73  		if err != nil {
    74  			t.Fatal(err)
    75  		}
    76  		if string(buf) != u.uncompressed {
    77  			t.Fatalf("unpackBits: want %x, got %x", u.uncompressed, buf)
    78  		}
    79  	}
    80  }
    81  
    82  func TestShortBlockData(t *testing.T) {
    83  	b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	// The bw-uncompressed.tiff image is a 153x55 bi-level image. This is 1 bit
    88  	// per pixel, or 20 bytes per row, times 55 rows, or 1100 bytes of pixel
    89  	// data. 1100 in hex is 0x44c, or "\x4c\x04" in little-endian. We replace
    90  	// that byte count (StripByteCounts-tagged data) by something less than
    91  	// that, so that there is not enough pixel data.
    92  	old := []byte{0x4c, 0x04}
    93  	new := []byte{0x01, 0x01}
    94  	i := bytes.Index(b, old)
    95  	if i < 0 {
    96  		t.Fatal(`could not find "\x4c\x04" byte count`)
    97  	}
    98  	if bytes.Contains(b[i+len(old):], old) {
    99  		t.Fatal(`too many occurrences of "\x4c\x04"`)
   100  	}
   101  	b[i+0] = new[0]
   102  	b[i+1] = new[1]
   103  	if _, err = Decode(bytes.NewReader(b)); err == nil {
   104  		t.Fatal("got nil error, want non-nil")
   105  	}
   106  }
   107  
   108  func TestDecodeInvalidDataType(t *testing.T) {
   109  	b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	// off is the offset of the ImageWidth tag. It is the offset of the overall
   115  	// IFD block (0x00000454), plus 2 for the uint16 number of IFD entries, plus 12
   116  	// to skip the first entry.
   117  	const off = 0x00000454 + 2 + 12*1
   118  
   119  	if v := binary.LittleEndian.Uint16(b[off : off+2]); v != tImageWidth {
   120  		t.Fatal(`could not find ImageWidth tag`)
   121  	}
   122  	binary.LittleEndian.PutUint16(b[off+2:], uint16(len(lengths))) // invalid datatype
   123  
   124  	if _, err = Decode(bytes.NewReader(b)); err == nil {
   125  		t.Fatal("got nil error, want non-nil")
   126  	}
   127  }
   128  
   129  func compare(t *testing.T, img0, img1 image.Image) {
   130  	b0 := img0.Bounds()
   131  	b1 := img1.Bounds()
   132  	if b0.Dx() != b1.Dx() || b0.Dy() != b1.Dy() {
   133  		t.Fatalf("wrong image size: want %s, got %s", b0, b1)
   134  	}
   135  	x1 := b1.Min.X - b0.Min.X
   136  	y1 := b1.Min.Y - b0.Min.Y
   137  	for y := b0.Min.Y; y < b0.Max.Y; y++ {
   138  		for x := b0.Min.X; x < b0.Max.X; x++ {
   139  			c0 := img0.At(x, y)
   140  			c1 := img1.At(x+x1, y+y1)
   141  			r0, g0, b0, a0 := c0.RGBA()
   142  			r1, g1, b1, a1 := c1.RGBA()
   143  			if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
   144  				t.Fatalf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
   145  			}
   146  		}
   147  	}
   148  }
   149  
   150  // TestDecode tests that decoding a PNG image and a TIFF image result in the
   151  // same pixel data.
   152  func TestDecode(t *testing.T) {
   153  	img0, err := load("video-001.png")
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	img1, err := load("video-001.tiff")
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	img2, err := load("video-001-strip-64.tiff")
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	img3, err := load("video-001-tile-64x64.tiff")
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	img4, err := load("video-001-16bit.tiff")
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  
   174  	compare(t, img0, img1)
   175  	compare(t, img0, img2)
   176  	compare(t, img0, img3)
   177  	compare(t, img0, img4)
   178  }
   179  
   180  // TestDecodeLZW tests that decoding a PNG image and a LZW-compressed TIFF
   181  // image result in the same pixel data.
   182  func TestDecodeLZW(t *testing.T) {
   183  	img0, err := load("blue-purple-pink.png")
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	img1, err := load("blue-purple-pink.lzwcompressed.tiff")
   188  	if err != nil {
   189  		t.Fatal(err)
   190  	}
   191  
   192  	compare(t, img0, img1)
   193  }
   194  
   195  // TestDecompress tests that decoding some TIFF images that use different
   196  // compression formats result in the same pixel data.
   197  func TestDecompress(t *testing.T) {
   198  	var decompressTests = []string{
   199  		"bw-uncompressed.tiff",
   200  		"bw-deflate.tiff",
   201  		"bw-packbits.tiff",
   202  	}
   203  	var img0 image.Image
   204  	for _, name := range decompressTests {
   205  		img1, err := load(name)
   206  		if err != nil {
   207  			t.Fatalf("decoding %s: %v", name, err)
   208  		}
   209  		if img0 == nil {
   210  			img0 = img1
   211  			continue
   212  		}
   213  		compare(t, img0, img1)
   214  	}
   215  }
   216  
   217  func replace(src []byte, find, repl string) ([]byte, error) {
   218  	removeSpaces := func(r rune) rune {
   219  		if r != ' ' {
   220  			return r
   221  		}
   222  		return -1
   223  	}
   224  
   225  	f, err := hex.DecodeString(strings.Map(removeSpaces, find))
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	r, err := hex.DecodeString(strings.Map(removeSpaces, repl))
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  	dst := bytes.Replace(src, f, r, 1)
   234  	if bytes.Equal(dst, src) {
   235  		return nil, errors.New("replacement failed")
   236  	}
   237  	return dst, nil
   238  }
   239  
   240  // TestZeroBitsPerSample tests that an IFD with a bitsPerSample of 0 does not
   241  // cause a crash.
   242  // Issue 10711.
   243  func TestZeroBitsPerSample(t *testing.T) {
   244  	b0, err := ioutil.ReadFile(testdataDir + "bw-deflate.tiff")
   245  	if err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	// Mutate the loaded image to have the problem.
   250  	// 02 01: tag number (tBitsPerSample)
   251  	// 03 00: data type (short, or uint16)
   252  	// 01 00 00 00: count
   253  	// ?? 00 00 00: value (1 -> 0)
   254  	b1, err := replace(b0,
   255  		"02 01 03 00 01 00 00 00 01 00 00 00",
   256  		"02 01 03 00 01 00 00 00 00 00 00 00",
   257  	)
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	_, err = Decode(bytes.NewReader(b1))
   263  	if err == nil {
   264  		t.Fatal("Decode with 0 bits per sample: got nil error, want non-nil")
   265  	}
   266  }
   267  
   268  // TestTileTooBig tests that we do not panic when a tile is too big compared to
   269  // the data available.
   270  // Issue 10712
   271  func TestTileTooBig(t *testing.T) {
   272  	b0, err := ioutil.ReadFile(testdataDir + "video-001-tile-64x64.tiff")
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  
   277  	// Mutate the loaded image to have the problem.
   278  	//
   279  	// 42 01: tag number (tTileWidth)
   280  	// 03 00: data type (short, or uint16)
   281  	// 01 00 00 00: count
   282  	// xx 00 00 00: value (0x40 -> 0x44: a wider tile consumes more data
   283  	// than is available)
   284  	b1, err := replace(b0,
   285  		"42 01 03 00 01 00 00 00 40 00 00 00",
   286  		"42 01 03 00 01 00 00 00 44 00 00 00",
   287  	)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  
   292  	// Turn off the predictor, which makes it possible to hit the
   293  	// place with the defect. Without this patch to the image, we run
   294  	// out of data too early, and do not hit the part of the code where
   295  	// the original panic was.
   296  	//
   297  	// 3d 01: tag number (tPredictor)
   298  	// 03 00: data type (short, or uint16)
   299  	// 01 00 00 00: count
   300  	// xx 00 00 00: value (2 -> 1: 2 = horizontal, 1 = none)
   301  	b2, err := replace(b1,
   302  		"3d 01 03 00 01 00 00 00 02 00 00 00",
   303  		"3d 01 03 00 01 00 00 00 01 00 00 00",
   304  	)
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  
   309  	_, err = Decode(bytes.NewReader(b2))
   310  	if err == nil {
   311  		t.Fatal("did not expect nil error")
   312  	}
   313  }
   314  
   315  // TestZeroSizedImages tests that decoding does not panic when image dimensions
   316  // are zero, and returns a zero-sized image instead.
   317  // Issue 10393.
   318  func TestZeroSizedImages(t *testing.T) {
   319  	testsizes := []struct {
   320  		w, h int
   321  	}{
   322  		{0, 0},
   323  		{1, 0},
   324  		{0, 1},
   325  		{1, 1},
   326  	}
   327  	for _, r := range testsizes {
   328  		img := image.NewRGBA(image.Rect(0, 0, r.w, r.h))
   329  		var buf bytes.Buffer
   330  		if err := Encode(&buf, img, nil); err != nil {
   331  			t.Errorf("encode w=%d h=%d: %v", r.w, r.h, err)
   332  			continue
   333  		}
   334  		if _, err := Decode(&buf); err != nil {
   335  			t.Errorf("decode w=%d h=%d: %v", r.w, r.h, err)
   336  		}
   337  	}
   338  }
   339  
   340  // TestLargeIFDEntry tests that a large IFD entry does not cause Decode to
   341  // panic.
   342  // Issue 10596.
   343  func TestLargeIFDEntry(t *testing.T) {
   344  	testdata := "II*\x00\x08\x00\x00\x00\f\x000000000000" +
   345  		"00000000000000000000" +
   346  		"00000000000000000000" +
   347  		"00000000000000000000" +
   348  		"00000000000000\x17\x01\x04\x00\x01\x00" +
   349  		"\x00\xc0000000000000000000" +
   350  		"00000000000000000000" +
   351  		"00000000000000000000" +
   352  		"000000"
   353  	_, err := Decode(strings.NewReader(testdata))
   354  	if err == nil {
   355  		t.Fatal("Decode with large IFD entry: got nil error, want non-nil")
   356  	}
   357  }
   358  
   359  // benchmarkDecode benchmarks the decoding of an image.
   360  func benchmarkDecode(b *testing.B, filename string) {
   361  	b.StopTimer()
   362  	contents, err := ioutil.ReadFile(testdataDir + filename)
   363  	if err != nil {
   364  		b.Fatal(err)
   365  	}
   366  	r := &buffer{buf: contents}
   367  	b.StartTimer()
   368  	for i := 0; i < b.N; i++ {
   369  		_, err := Decode(r)
   370  		if err != nil {
   371  			b.Fatal("Decode:", err)
   372  		}
   373  	}
   374  }
   375  
   376  func BenchmarkDecodeCompressed(b *testing.B)   { benchmarkDecode(b, "video-001.tiff") }
   377  func BenchmarkDecodeUncompressed(b *testing.B) { benchmarkDecode(b, "video-001-uncompressed.tiff") }