git.lucas.co / go_mono
git clone https://git.lucas.co/go_mono.git

tiff/reader_test.go (14.8K)

  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 	"compress/zlib"
 10 	"encoding/binary"
 11 	"encoding/hex"
 12 	"errors"
 13 	"fmt"
 14 	"image"
 15 	"io"
 16 	"io/ioutil"
 17 	"os"
 18 	"sort"
 19 	"strings"
 20 	"testing"
 21 
 22 	_ "image/png"
 23 )
 24 
 25 const testdataDir = "../testdata/"
 26 
 27 // Read makes *buffer implements io.Reader, so that we can pass one to Decode.
 28 func (*buffer) Read([]byte) (int, error) {
 29 	panic("unimplemented")
 30 }
 31 
 32 func load(name string) (image.Image, error) {
 33 	f, err := os.Open(testdataDir + name)
 34 	if err != nil {
 35 		return nil, err
 36 	}
 37 	defer f.Close()
 38 	img, _, err := image.Decode(f)
 39 	if err != nil {
 40 		return nil, err
 41 	}
 42 	return img, nil
 43 }
 44 
 45 // TestNoRPS tests decoding an image that has no RowsPerStrip tag. The tag is
 46 // mandatory according to the spec but some software omits it in the case of a
 47 // single strip.
 48 func TestNoRPS(t *testing.T) {
 49 	_, err := load("no_rps.tiff")
 50 	if err != nil {
 51 		t.Fatal(err)
 52 	}
 53 }
 54 
 55 // TestNoCompression tests decoding an image that has no Compression tag. This
 56 // tag is mandatory, but most tools interpret a missing value as no
 57 // compression.
 58 func TestNoCompression(t *testing.T) {
 59 	_, err := load("no_compress.tiff")
 60 	if err != nil {
 61 		t.Fatal(err)
 62 	}
 63 }
 64 
 65 // TestUnpackBits tests the decoding of PackBits-encoded data.
 66 func TestUnpackBits(t *testing.T) {
 67 	var unpackBitsTests = []struct {
 68 		compressed   string
 69 		uncompressed string
 70 	}{{
 71 		// Example data from Wikipedia.
 72 		"\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa",
 73 		"\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
 74 	}}
 75 	for _, u := range unpackBitsTests {
 76 		buf, err := unpackBits(strings.NewReader(u.compressed))
 77 		if err != nil {
 78 			t.Fatal(err)
 79 		}
 80 		if string(buf) != u.uncompressed {
 81 			t.Fatalf("unpackBits: want %x, got %x", u.uncompressed, buf)
 82 		}
 83 	}
 84 }
 85 
 86 func TestShortBlockData(t *testing.T) {
 87 	b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
 88 	if err != nil {
 89 		t.Fatal(err)
 90 	}
 91 	// The bw-uncompressed.tiff image is a 153x55 bi-level image. This is 1 bit
 92 	// per pixel, or 20 bytes per row, times 55 rows, or 1100 bytes of pixel
 93 	// data. 1100 in hex is 0x44c, or "\x4c\x04" in little-endian. We replace
 94 	// that byte count (StripByteCounts-tagged data) by something less than
 95 	// that, so that there is not enough pixel data.
 96 	old := []byte{0x4c, 0x04}
 97 	new := []byte{0x01, 0x01}
 98 	i := bytes.Index(b, old)
 99 	if i < 0 {
100 		t.Fatal(`could not find "\x4c\x04" byte count`)
101 	}
102 	if bytes.Contains(b[i+len(old):], old) {
103 		t.Fatal(`too many occurrences of "\x4c\x04"`)
104 	}
105 	b[i+0] = new[0]
106 	b[i+1] = new[1]
107 	if _, err = Decode(bytes.NewReader(b)); err == nil {
108 		t.Fatal("got nil error, want non-nil")
109 	}
110 }
111 
112 func TestDecodeInvalidDataType(t *testing.T) {
113 	b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
114 	if err != nil {
115 		t.Fatal(err)
116 	}
117 
118 	// off is the offset of the ImageWidth tag. It is the offset of the overall
119 	// IFD block (0x00000454), plus 2 for the uint16 number of IFD entries, plus 12
120 	// to skip the first entry.
121 	const off = 0x00000454 + 2 + 12*1
122 
123 	if v := binary.LittleEndian.Uint16(b[off : off+2]); v != tImageWidth {
124 		t.Fatal(`could not find ImageWidth tag`)
125 	}
126 	binary.LittleEndian.PutUint16(b[off+2:], uint16(len(lengths))) // invalid datatype
127 
128 	if _, err = Decode(bytes.NewReader(b)); err == nil {
129 		t.Fatal("got nil error, want non-nil")
130 	}
131 }
132 
133 func compare(t *testing.T, img0, img1 image.Image) {
134 	t.Helper()
135 	b0 := img0.Bounds()
136 	b1 := img1.Bounds()
137 	if b0.Dx() != b1.Dx() || b0.Dy() != b1.Dy() {
138 		t.Fatalf("wrong image size: want %s, got %s", b0, b1)
139 	}
140 	x1 := b1.Min.X - b0.Min.X
141 	y1 := b1.Min.Y - b0.Min.Y
142 	for y := b0.Min.Y; y < b0.Max.Y; y++ {
143 		for x := b0.Min.X; x < b0.Max.X; x++ {
144 			c0 := img0.At(x, y)
145 			c1 := img1.At(x+x1, y+y1)
146 			r0, g0, b0, a0 := c0.RGBA()
147 			r1, g1, b1, a1 := c1.RGBA()
148 			if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
149 				t.Fatalf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
150 			}
151 		}
152 	}
153 }
154 
155 // TestDecode tests that decoding a PNG image and a TIFF image result in the
156 // same pixel data.
157 func TestDecode(t *testing.T) {
158 	img0, err := load("video-001.png")
159 	if err != nil {
160 		t.Fatal(err)
161 	}
162 	img1, err := load("video-001.tiff")
163 	if err != nil {
164 		t.Fatal(err)
165 	}
166 	img2, err := load("video-001-strip-64.tiff")
167 	if err != nil {
168 		t.Fatal(err)
169 	}
170 	img3, err := load("video-001-tile-64x64.tiff")
171 	if err != nil {
172 		t.Fatal(err)
173 	}
174 	img4, err := load("video-001-16bit.tiff")
175 	if err != nil {
176 		t.Fatal(err)
177 	}
178 
179 	compare(t, img0, img1)
180 	compare(t, img0, img2)
181 	compare(t, img0, img3)
182 	compare(t, img0, img4)
183 }
184 
185 // TestDecodeLZW tests that decoding a PNG image and a LZW-compressed TIFF
186 // image result in the same pixel data.
187 func TestDecodeLZW(t *testing.T) {
188 	img0, err := load("blue-purple-pink.png")
189 	if err != nil {
190 		t.Fatal(err)
191 	}
192 	img1, err := load("blue-purple-pink.lzwcompressed.tiff")
193 	if err != nil {
194 		t.Fatal(err)
195 	}
196 
197 	compare(t, img0, img1)
198 }
199 
200 // TestEOF tests that decoding a TIFF image returns io.ErrUnexpectedEOF
201 // when there are no headers or data is empty
202 func TestEOF(t *testing.T) {
203 	_, err := Decode(bytes.NewReader(nil))
204 	if err != io.ErrUnexpectedEOF {
205 		t.Errorf("Error should be io.ErrUnexpectedEOF on nil but got %v", err)
206 	}
207 }
208 
209 // TestDecodeCCITT tests that decoding a PNG image and a CCITT compressed TIFF
210 // image result in the same pixel data.
211 func TestDecodeCCITT(t *testing.T) {
212 	// TODO Add more tests.
213 	for _, fn := range []string{
214 		"bw-gopher",
215 	} {
216 		img0, err := load(fn + ".png")
217 		if err != nil {
218 			t.Fatal(err)
219 		}
220 
221 		img1, err := load(fn + "_ccittGroup3.tiff")
222 		if err != nil {
223 			t.Fatal(err)
224 		}
225 		compare(t, img0, img1)
226 
227 		img2, err := load(fn + "_ccittGroup4.tiff")
228 		if err != nil {
229 			t.Fatal(err)
230 		}
231 		compare(t, img0, img2)
232 	}
233 }
234 
235 // TestDecodeTagOrder tests that a malformed image with unsorted IFD entries is
236 // correctly rejected.
237 func TestDecodeTagOrder(t *testing.T) {
238 	data, err := ioutil.ReadFile("../testdata/video-001.tiff")
239 	if err != nil {
240 		t.Fatal(err)
241 	}
242 
243 	// Swap the first two IFD entries.
244 	ifdOffset := int64(binary.LittleEndian.Uint32(data[4:8]))
245 	for i := ifdOffset + 2; i < ifdOffset+14; i++ {
246 		data[i], data[i+12] = data[i+12], data[i]
247 	}
248 	if _, _, err := image.Decode(bytes.NewReader(data)); err == nil {
249 		t.Fatal("got nil error, want non-nil")
250 	}
251 }
252 
253 // TestDecompress tests that decoding some TIFF images that use different
254 // compression formats result in the same pixel data.
255 func TestDecompress(t *testing.T) {
256 	var decompressTests = []string{
257 		"bw-uncompressed.tiff",
258 		"bw-deflate.tiff",
259 		"bw-packbits.tiff",
260 	}
261 	var img0 image.Image
262 	for _, name := range decompressTests {
263 		img1, err := load(name)
264 		if err != nil {
265 			t.Fatalf("decoding %s: %v", name, err)
266 		}
267 		if img0 == nil {
268 			img0 = img1
269 			continue
270 		}
271 		compare(t, img0, img1)
272 	}
273 }
274 
275 func replace(src []byte, find, repl string) ([]byte, error) {
276 	removeSpaces := func(r rune) rune {
277 		if r != ' ' {
278 			return r
279 		}
280 		return -1
281 	}
282 
283 	f, err := hex.DecodeString(strings.Map(removeSpaces, find))
284 	if err != nil {
285 		return nil, err
286 	}
287 	r, err := hex.DecodeString(strings.Map(removeSpaces, repl))
288 	if err != nil {
289 		return nil, err
290 	}
291 	dst := bytes.Replace(src, f, r, 1)
292 	if bytes.Equal(dst, src) {
293 		return nil, errors.New("replacement failed")
294 	}
295 	return dst, nil
296 }
297 
298 // TestZeroBitsPerSample tests that an IFD with a bitsPerSample of 0 does not
299 // cause a crash.
300 // Issue 10711.
301 func TestZeroBitsPerSample(t *testing.T) {
302 	b0, err := ioutil.ReadFile(testdataDir + "bw-deflate.tiff")
303 	if err != nil {
304 		t.Fatal(err)
305 	}
306 
307 	// Mutate the loaded image to have the problem.
308 	// 02 01: tag number (tBitsPerSample)
309 	// 03 00: data type (short, or uint16)
310 	// 01 00 00 00: count
311 	// ?? 00 00 00: value (1 -> 0)
312 	b1, err := replace(b0,
313 		"02 01 03 00 01 00 00 00 01 00 00 00",
314 		"02 01 03 00 01 00 00 00 00 00 00 00",
315 	)
316 	if err != nil {
317 		t.Fatal(err)
318 	}
319 
320 	_, err = Decode(bytes.NewReader(b1))
321 	if err == nil {
322 		t.Fatal("Decode with 0 bits per sample: got nil error, want non-nil")
323 	}
324 }
325 
326 // TestTileTooBig tests that we do not panic when a tile is too big compared to
327 // the data available.
328 // Issue 10712
329 func TestTileTooBig(t *testing.T) {
330 	b0, err := ioutil.ReadFile(testdataDir + "video-001-tile-64x64.tiff")
331 	if err != nil {
332 		t.Fatal(err)
333 	}
334 
335 	// Mutate the loaded image to have the problem.
336 	//
337 	// 42 01: tag number (tTileWidth)
338 	// 03 00: data type (short, or uint16)
339 	// 01 00 00 00: count
340 	// xx 00 00 00: value (0x40 -> 0x44: a wider tile consumes more data
341 	// than is available)
342 	b1, err := replace(b0,
343 		"42 01 03 00 01 00 00 00 40 00 00 00",
344 		"42 01 03 00 01 00 00 00 44 00 00 00",
345 	)
346 	if err != nil {
347 		t.Fatal(err)
348 	}
349 
350 	// Turn off the predictor, which makes it possible to hit the
351 	// place with the defect. Without this patch to the image, we run
352 	// out of data too early, and do not hit the part of the code where
353 	// the original panic was.
354 	//
355 	// 3d 01: tag number (tPredictor)
356 	// 03 00: data type (short, or uint16)
357 	// 01 00 00 00: count
358 	// xx 00 00 00: value (2 -> 1: 2 = horizontal, 1 = none)
359 	b2, err := replace(b1,
360 		"3d 01 03 00 01 00 00 00 02 00 00 00",
361 		"3d 01 03 00 01 00 00 00 01 00 00 00",
362 	)
363 	if err != nil {
364 		t.Fatal(err)
365 	}
366 
367 	_, err = Decode(bytes.NewReader(b2))
368 	if err == nil {
369 		t.Fatal("did not expect nil error")
370 	}
371 }
372 
373 // TestZeroSizedImages tests that decoding does not panic when image dimensions
374 // are zero, and returns a zero-sized image instead.
375 // Issue 10393.
376 func TestZeroSizedImages(t *testing.T) {
377 	testsizes := []struct {
378 		w, h int
379 	}{
380 		{0, 0},
381 		{1, 0},
382 		{0, 1},
383 		{1, 1},
384 	}
385 	for _, r := range testsizes {
386 		img := image.NewRGBA(image.Rect(0, 0, r.w, r.h))
387 		var buf bytes.Buffer
388 		if err := Encode(&buf, img, nil); err != nil {
389 			t.Errorf("encode w=%d h=%d: %v", r.w, r.h, err)
390 			continue
391 		}
392 		if _, err := Decode(&buf); err != nil {
393 			t.Errorf("decode w=%d h=%d: %v", r.w, r.h, err)
394 		}
395 	}
396 }
397 
398 // TestLargeIFDEntry tests that a large IFD entry does not cause Decode to
399 // panic.
400 // Issue 10596.
401 func TestLargeIFDEntry(t *testing.T) {
402 	testdata := "II*\x00\x08\x00\x00\x00\f\x000000000000" +
403 		"00000000000000000000" +
404 		"00000000000000000000" +
405 		"00000000000000000000" +
406 		"00000000000000\x17\x01\x04\x00\x01\x00" +
407 		"\x00\xc0000000000000000000" +
408 		"00000000000000000000" +
409 		"00000000000000000000" +
410 		"000000"
411 	_, err := Decode(strings.NewReader(testdata))
412 	if err == nil {
413 		t.Fatal("Decode with large IFD entry: got nil error, want non-nil")
414 	}
415 }
416 
417 func TestInvalidPaletteRef(t *testing.T) {
418 	contents, err := ioutil.ReadFile(testdataDir + "invalid-palette-ref.tiff")
419 	if err != nil {
420 		t.Fatal(err)
421 	}
422 	if _, err := Decode(bytes.NewReader(contents)); err == nil {
423 		t.Fatal("Decode with invalid palette index: got nil error, want non-nil")
424 	}
425 }
426 
427 // benchmarkDecode benchmarks the decoding of an image.
428 func benchmarkDecode(b *testing.B, filename string) {
429 	b.Helper()
430 	contents, err := ioutil.ReadFile(testdataDir + filename)
431 	if err != nil {
432 		b.Fatal(err)
433 	}
434 	benchmarkDecodeData(b, contents)
435 }
436 
437 func benchmarkDecodeData(b *testing.B, data []byte) {
438 	b.Helper()
439 	r := &buffer{buf: data}
440 	b.ResetTimer()
441 	for i := 0; i < b.N; i++ {
442 		_, err := Decode(r)
443 		if err != nil {
444 			b.Fatal("Decode:", err)
445 		}
446 	}
447 }
448 
449 func BenchmarkDecodeCompressed(b *testing.B)   { benchmarkDecode(b, "video-001.tiff") }
450 func BenchmarkDecodeUncompressed(b *testing.B) { benchmarkDecode(b, "video-001-uncompressed.tiff") }
451 
452 func BenchmarkZeroHeightTile(b *testing.B) {
453 	enc := binary.BigEndian
454 	data := newTIFF(enc)
455 	data = appendIFD(data, enc, map[uint16]interface{}{
456 		tImageWidth:  uint32(4294967295),
457 		tImageLength: uint32(0),
458 		tTileWidth:   uint32(1),
459 		tTileLength:  uint32(0),
460 	})
461 	benchmarkDecodeData(b, data)
462 }
463 
464 func BenchmarkRepeatedOversizedTileData(b *testing.B) {
465 	const (
466 		imageWidth  = 256
467 		imageHeight = 256
468 		tileWidth   = 8
469 		tileLength  = 8
470 		numTiles    = (imageWidth * imageHeight) / (tileWidth * tileLength)
471 	)
472 
473 	// Create a chunk of tile data that decompresses to a large size.
474 	zdata := func() []byte {
475 		var zbuf bytes.Buffer
476 		zw := zlib.NewWriter(&zbuf)
477 		zeros := make([]byte, 1024)
478 		for i := 0; i < 1<<16; i++ {
479 			zw.Write(zeros)
480 		}
481 		zw.Close()
482 		return zbuf.Bytes()
483 	}()
484 
485 	enc := binary.BigEndian
486 	data := newTIFF(enc)
487 
488 	zoff := len(data)
489 	data = append(data, zdata...)
490 
491 	// Each tile refers to the same compressed data chunk.
492 	var tileoffs []uint32
493 	var tilesizes []uint32
494 	for i := 0; i < numTiles; i++ {
495 		tileoffs = append(tileoffs, uint32(zoff))
496 		tilesizes = append(tilesizes, uint32(len(zdata)))
497 	}
498 
499 	data = appendIFD(data, enc, map[uint16]interface{}{
500 		tImageWidth:                uint32(imageWidth),
501 		tImageLength:               uint32(imageHeight),
502 		tTileWidth:                 uint32(tileWidth),
503 		tTileLength:                uint32(tileLength),
504 		tTileOffsets:               tileoffs,
505 		tTileByteCounts:            tilesizes,
506 		tCompression:               uint16(cDeflate),
507 		tBitsPerSample:             []uint16{16, 16, 16},
508 		tPhotometricInterpretation: uint16(pRGB),
509 	})
510 	benchmarkDecodeData(b, data)
511 }
512 
513 type byteOrder interface {
514 	binary.ByteOrder
515 	binary.AppendByteOrder
516 }
517 
518 // newTIFF returns the TIFF header.
519 func newTIFF(enc byteOrder) []byte {
520 	b := []byte{0, 0, 0, 42, 0, 0, 0, 0}
521 	switch enc.Uint16([]byte{1, 0}) {
522 	case 0x1:
523 		b[0], b[1] = 'I', 'I'
524 	case 0x100:
525 		b[0], b[1] = 'M', 'M'
526 	default:
527 		panic("odd byte order")
528 	}
529 	return b
530 }
531 
532 // appendIFD appends an IFD to the TIFF in b,
533 // updating the IFD location in the header.
534 func appendIFD(b []byte, enc byteOrder, entries map[uint16]interface{}) []byte {
535 	var tags []uint16
536 	for tag := range entries {
537 		tags = append(tags, tag)
538 	}
539 	sort.Slice(tags, func(i, j int) bool {
540 		return tags[i] < tags[j]
541 	})
542 
543 	var ifd []byte
544 	for _, tag := range tags {
545 		ifd = enc.AppendUint16(ifd, tag)
546 		switch v := entries[tag].(type) {
547 		case uint16:
548 			ifd = enc.AppendUint16(ifd, dtShort)
549 			ifd = enc.AppendUint32(ifd, 1)
550 			ifd = enc.AppendUint16(ifd, v)
551 			ifd = enc.AppendUint16(ifd, v)
552 		case uint32:
553 			ifd = enc.AppendUint16(ifd, dtLong)
554 			ifd = enc.AppendUint32(ifd, 1)
555 			ifd = enc.AppendUint32(ifd, v)
556 		case []uint16:
557 			ifd = enc.AppendUint16(ifd, dtShort)
558 			ifd = enc.AppendUint32(ifd, uint32(len(v)))
559 			switch len(v) {
560 			case 0:
561 				ifd = enc.AppendUint32(ifd, 0)
562 			case 1:
563 				ifd = enc.AppendUint16(ifd, v[0])
564 				ifd = enc.AppendUint16(ifd, v[1])
565 			default:
566 				ifd = enc.AppendUint32(ifd, uint32(len(b)))
567 				for _, e := range v {
568 					b = enc.AppendUint16(b, e)
569 				}
570 			}
571 		case []uint32:
572 			ifd = enc.AppendUint16(ifd, dtLong)
573 			ifd = enc.AppendUint32(ifd, uint32(len(v)))
574 			switch len(v) {
575 			case 0:
576 				ifd = enc.AppendUint32(ifd, 0)
577 			case 1:
578 				ifd = enc.AppendUint32(ifd, v[0])
579 			default:
580 				ifd = enc.AppendUint32(ifd, uint32(len(b)))
581 				for _, e := range v {
582 					b = enc.AppendUint32(b, e)
583 				}
584 			}
585 		default:
586 			panic(fmt.Errorf("unhandled type %T", v))
587 		}
588 	}
589 
590 	enc.PutUint32(b[4:8], uint32(len(b)))
591 	b = enc.AppendUint16(b, uint16(len(entries)))
592 	b = append(b, ifd...)
593 	b = enc.AppendUint32(b, 0)
594 	return b
595 }