From beed0a784415c2e20c2530e1898c0fa4c00d1ac8 Mon Sep 17 00:00:00 2001 From: Benny Siegert Date: Thu, 13 Oct 2011 13:31:26 +1100 Subject: [PATCH] image/tiff: Implement PackBits decoding. The decompression routine is in its own file because G3 encoding (which is more complicated) will be put there. R=nigeltao CC=golang-dev https://golang.org/cl/5177047 --- src/pkg/image/tiff/Makefile | 1 + src/pkg/image/tiff/compress.go | 60 +++++++++++++++ src/pkg/image/tiff/reader.go | 2 + src/pkg/image/tiff/reader_test.go | 69 ++++++++++++++++++ src/pkg/image/tiff/testdata/bw-deflate.tiff | Bin 0 -> 594 bytes src/pkg/image/tiff/testdata/bw-packbits.tiff | Bin 0 -> 890 bytes .../image/tiff/testdata/bw-uncompressed.tiff | Bin 0 -> 1396 bytes 7 files changed, 132 insertions(+) create mode 100644 src/pkg/image/tiff/compress.go create mode 100644 src/pkg/image/tiff/testdata/bw-deflate.tiff create mode 100644 src/pkg/image/tiff/testdata/bw-packbits.tiff create mode 100644 src/pkg/image/tiff/testdata/bw-uncompressed.tiff diff --git a/src/pkg/image/tiff/Makefile b/src/pkg/image/tiff/Makefile index 1a001afb9b..67ef5c9ec6 100644 --- a/src/pkg/image/tiff/Makefile +++ b/src/pkg/image/tiff/Makefile @@ -7,6 +7,7 @@ include ../../../Make.inc TARG=image/tiff GOFILES=\ buffer.go\ + compress.go\ consts.go\ reader.go\ diff --git a/src/pkg/image/tiff/compress.go b/src/pkg/image/tiff/compress.go new file mode 100644 index 0000000000..e89aa6d7ac --- /dev/null +++ b/src/pkg/image/tiff/compress.go @@ -0,0 +1,60 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tiff + +import ( + "bufio" + "io" + "os" +) + +type byteReader interface { + io.Reader + io.ByteReader +} + +// unpackBits decodes the PackBits-compressed data in src and returns the +// uncompressed data. +// +// The PackBits compression format is described in section 9 (p. 42) +// of the TIFF spec. +func unpackBits(r io.Reader) ([]byte, os.Error) { + buf := make([]byte, 128) + dst := make([]byte, 0, 1024) + br, ok := r.(byteReader) + if !ok { + br = bufio.NewReader(r) + } + + for { + b, err := br.ReadByte() + if err != nil { + if err == os.EOF { + return dst, nil + } + return nil, err + } + code := int(int8(b)) + switch { + case code >= 0: + n, err := io.ReadFull(br, buf[:code+1]) + if err != nil { + return nil, err + } + dst = append(dst, buf[:n]...) + case code == -128: + // No-op. + default: + if b, err = br.ReadByte(); err != nil { + return nil, err + } + for j := 0; j < 1-code; j++ { + buf[j] = b + } + dst = append(dst, buf[:1-code]...) + } + } + panic("unreachable") +} diff --git a/src/pkg/image/tiff/reader.go b/src/pkg/image/tiff/reader.go index 2db82bf210..c452f5d54c 100644 --- a/src/pkg/image/tiff/reader.go +++ b/src/pkg/image/tiff/reader.go @@ -412,6 +412,8 @@ func Decode(r io.Reader) (img image.Image, err os.Error) { } d.buf, err = ioutil.ReadAll(r) r.Close() + case cPackBits: + d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n)) default: err = UnsupportedError("compression") } diff --git a/src/pkg/image/tiff/reader_test.go b/src/pkg/image/tiff/reader_test.go index 1eb2bcd76e..86b7dc3761 100644 --- a/src/pkg/image/tiff/reader_test.go +++ b/src/pkg/image/tiff/reader_test.go @@ -5,8 +5,10 @@ package tiff import ( + "image" "io/ioutil" "os" + "strings" "testing" ) @@ -30,6 +32,73 @@ func TestNoRPS(t *testing.T) { } } +// TestUnpackBits tests the decoding of PackBits-encoded data. +func TestUnpackBits(t *testing.T) { + var unpackBitsTests = []struct { + compressed string + uncompressed string + }{{ + // Example data from Wikipedia. + "\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa", + "\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + }} + for _, u := range unpackBitsTests { + buf, err := unpackBits(strings.NewReader(u.compressed)) + if err != nil { + t.Fatal(err) + } + if string(buf) != u.uncompressed { + t.Fatalf("unpackBits: want %x, got %x", u.uncompressed, buf) + } + } +} + +// TestDecompress tests that decoding some TIFF images that use different +// compression formats result in the same pixel data. +func TestDecompress(t *testing.T) { + var decompressTests = []string{ + "bw-uncompressed.tiff", + "bw-deflate.tiff", + "bw-packbits.tiff", + } + var img0 image.Image + for _, name := range decompressTests { + f, err := os.Open("testdata/" + name) + if err != nil { + t.Fatal(err) + } + defer f.Close() + if img0 == nil { + img0, err = Decode(f) + if err != nil { + t.Fatalf("decoding %s: %v", name, err) + } + continue + } + + img1, err := Decode(f) + if err != nil { + t.Fatalf("decoding %s: %v", name, err) + } + b := img1.Bounds() + // Compare images. + if !b.Eq(img0.Bounds()) { + t.Fatalf("wrong image size: want %s, got %s", img0.Bounds(), b) + } + for y := b.Min.Y; y < b.Max.Y; y++ { + for x := b.Min.X; x < b.Max.X; x++ { + c0 := img0.At(x, y) + c1 := img1.At(x, y) + r0, g0, b0, a0 := c0.RGBA() + r1, g1, b1, a1 := c1.RGBA() + if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { + t.Fatalf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1) + } + } + } + } +} + const filename = "testdata/video-001-uncompressed.tiff" // BenchmarkDecode benchmarks the decoding of an image. diff --git a/src/pkg/image/tiff/testdata/bw-deflate.tiff b/src/pkg/image/tiff/testdata/bw-deflate.tiff new file mode 100644 index 0000000000000000000000000000000000000000..137a0c3ef1f669b7c51a5d437160e6784675e68c GIT binary patch literal 594 zcmebD)M7AVWMHV6(|g&_`>=xu`-lHenXWr!99h|Xqi61tvR4aKn&g)R*f&^MrdWtB zX_i08|41V0;QEOd4VyMUzuUTP`uC_8w?8R=|EI6dd10mdhDpm(rmeA?8Ea>2uzO;# z*Q3b2n>(gfEnZglM0=}ayvvnylf)f!YeI{5=Pl^0eSYRhgzn0dyAKMmZakXr?0aUv zR>~2hkByus*IsvFJUJEwf0W^A+gBJD?=CN^>PbCtR8D&br*AHk=SjZfZX5Zl&-<*4w08Mp?tVmV z3wOp=>W8TLww5 z29ymH1_S-j;?$yI{iNc|)b!M%5`CA{vecaXg47~?_k8{0qGbJo>~#Ii+{E-${gTYI lH2sp);*ylal0^Naa@~~Fw4B6}R6URc*f0+u3GyhI1^_H#vqAs> literal 0 HcmV?d00001 diff --git a/src/pkg/image/tiff/testdata/bw-packbits.tiff b/src/pkg/image/tiff/testdata/bw-packbits.tiff new file mode 100644 index 0000000000000000000000000000000000000000..d59fa4aeed32c855d74bec465904dd7474243fd0 GIT binary patch literal 890 zcmY+C&ubGw6vw|av&n8CHfcdETI?Q!V7GeFgOUgZtw+I&rzYt(#3~KDi+admTS0p8 z9}xUQJccUxZ{+B4HLX9|X2&;gr!^f|zMt=#H*em|?E3mmJeR;v;O!I>NTr9l(dxlh z*4w)g>qB)X$03y1b3ZYt1NQ@i`$N5Fn5ziMuvC2~7#jD73{K-ghE&sf=X;as2qn>Q z_f3#cZO$#CRbclpvnV#cjo@=s_~J8Gxxg41>P$XbxM2u>4pf-xM749OGIvt;euQ$51ZW9BRYvqiR}@ zrvE)HPpJ)>_P7n5QX7SvTm-s>BC>E1d|-tm1oRA)$l;i)D~3?aAIS;JcZsEClcy|~QlM;^!nhS z+RHP1#d3>suG;*k61XNx+`|j1bKP=8yfm}6VVTl-1kd6yii1wv4|`#h1Z&~z@a4`R zjDklyK^%31!FDg`ziRiwAn9*y1xXkuo9(0>bl%(=w7c7#eiE;k8B^^sedeI7{{Y9_ B=bQil literal 0 HcmV?d00001 diff --git a/src/pkg/image/tiff/testdata/bw-uncompressed.tiff b/src/pkg/image/tiff/testdata/bw-uncompressed.tiff new file mode 100644 index 0000000000000000000000000000000000000000..8390f11357f9c3b38464b17a08d4cdd111b7d5ce GIT binary patch literal 1396 zcmZvb&ubGw6vyA}v~CNrsRgyP#qKc(cB&UWSdv1a271(c(q;+|NDux4 zLjMqtp$h&RJ@%M_=T6^DXEw8Me6V@n`Me)Hc{AH?KZUmoKAL!VSdFkHToYD=Ymx4*6`(n3`f2J@`3Om$(EdJl4E1$Y*uk44Q==sI84nCGN#z zcv@&mfydU7aHW%5Wi6uEAn16kuFU=_OqmyhW_mWpEUGXU>v(w{BXc(W)?D0qtPNNK zu;b#+BWpSBd;+X++WB4JPL_U&9yvx9U|hzX;J*teOCN=wIYg~8T#BeDWhuB}t8jyF z(-*)P<3|6)1+)4k>d0!H$31<|YF&FDzwS-PsI5BKny>0 l2U6t2eqZD=%X{6tD~>-s>&gD8o68*?FwNfJul}RP-vZMgXo3I$ literal 0 HcmV?d00001 -- 2.51.0