mirror of
https://github.com/golang/go
synced 2024-11-24 23:07:56 -07:00
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
This commit is contained in:
parent
c64e8e327e
commit
beed0a7844
@ -7,6 +7,7 @@ include ../../../Make.inc
|
||||
TARG=image/tiff
|
||||
GOFILES=\
|
||||
buffer.go\
|
||||
compress.go\
|
||||
consts.go\
|
||||
reader.go\
|
||||
|
||||
|
60
src/pkg/image/tiff/compress.go
Normal file
60
src/pkg/image/tiff/compress.go
Normal file
@ -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")
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
@ -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.
|
||||
|
BIN
src/pkg/image/tiff/testdata/bw-deflate.tiff
vendored
Normal file
BIN
src/pkg/image/tiff/testdata/bw-deflate.tiff
vendored
Normal file
Binary file not shown.
BIN
src/pkg/image/tiff/testdata/bw-packbits.tiff
vendored
Normal file
BIN
src/pkg/image/tiff/testdata/bw-packbits.tiff
vendored
Normal file
Binary file not shown.
BIN
src/pkg/image/tiff/testdata/bw-uncompressed.tiff
vendored
Normal file
BIN
src/pkg/image/tiff/testdata/bw-uncompressed.tiff
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user