aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/image
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2013-07-16 06:54:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-07-16 06:54:42 +0000
commitbe47d6eceffd2c5dbbc1566d5eea490527fb2bd4 (patch)
tree0e8fda573576bb4181dba29d0e88380a8c38fafd /libgo/go/image
parentefb30cdeb003fd7c585ee0d7657340086abcbd9e (diff)
downloadgcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.zip
gcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.tar.gz
gcc-be47d6eceffd2c5dbbc1566d5eea490527fb2bd4.tar.bz2
libgo: Update to Go 1.1.1.
From-SVN: r200974
Diffstat (limited to 'libgo/go/image')
-rw-r--r--libgo/go/image/gif/reader.go103
-rw-r--r--libgo/go/image/gif/reader_test.go138
-rw-r--r--libgo/go/image/jpeg/reader.go32
-rw-r--r--libgo/go/image/jpeg/reader_test.go63
-rw-r--r--libgo/go/image/jpeg/scan.go8
-rw-r--r--libgo/go/image/jpeg/writer_test.go39
-rw-r--r--libgo/go/image/png/reader.go5
-rw-r--r--libgo/go/image/png/reader_test.go59
-rw-r--r--libgo/go/image/png/writer.go2
9 files changed, 374 insertions, 75 deletions
diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go
index 8b36948..8e8531f 100644
--- a/libgo/go/image/gif/reader.go
+++ b/libgo/go/image/gif/reader.go
@@ -17,6 +17,11 @@ import (
"io"
)
+var (
+ errNotEnough = errors.New("gif: not enough image data")
+ errTooMuch = errors.New("gif: too much image data")
+)
+
// If the io.Reader does not also have ReadByte, then decode will introduce its own buffering.
type reader interface {
io.Reader
@@ -89,29 +94,35 @@ type decoder struct {
// comprises (n, (n bytes)) blocks, with 1 <= n <= 255. It is the
// reader given to the LZW decoder, which is thus immune to the
// blocking. After the LZW decoder completes, there will be a 0-byte
-// block remaining (0, ()), but under normal execution blockReader
-// doesn't consume it, so it is handled in decode.
+// block remaining (0, ()), which is consumed when checking that the
+// blockReader is exhausted.
type blockReader struct {
r reader
slice []byte
+ err error
tmp [256]byte
}
func (b *blockReader) Read(p []byte) (int, error) {
+ if b.err != nil {
+ return 0, b.err
+ }
if len(p) == 0 {
return 0, nil
}
if len(b.slice) == 0 {
- blockLen, err := b.r.ReadByte()
- if err != nil {
- return 0, err
+ var blockLen uint8
+ blockLen, b.err = b.r.ReadByte()
+ if b.err != nil {
+ return 0, b.err
}
if blockLen == 0 {
- return 0, io.EOF
+ b.err = io.EOF
+ return 0, b.err
}
b.slice = b.tmp[0:blockLen]
- if _, err = io.ReadFull(b.r, b.slice); err != nil {
- return 0, err
+ if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
+ return 0, b.err
}
}
n := copy(p, b.slice)
@@ -142,35 +153,33 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
}
-Loop:
- for err == nil {
- var c byte
- c, err = d.r.ReadByte()
- if err == io.EOF {
- break
+ for {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ return err
}
switch c {
case sExtension:
- err = d.readExtension()
+ if err = d.readExtension(); err != nil {
+ return err
+ }
case sImageDescriptor:
- var m *image.Paletted
- m, err = d.newImageFromDescriptor()
+ m, err := d.newImageFromDescriptor()
if err != nil {
- break
+ return err
}
if d.imageFields&fColorMapFollows != 0 {
m.Palette, err = d.readColorMap()
if err != nil {
- break
+ return err
}
// TODO: do we set transparency in this map too? That would be
// d.setTransparency(m.Palette)
} else {
m.Palette = d.globalColorMap
}
- var litWidth uint8
- litWidth, err = d.r.ReadByte()
+ litWidth, err := d.r.ReadByte()
if err != nil {
return err
}
@@ -178,18 +187,27 @@ Loop:
return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
}
// A wonderfully Go-like piece of magic.
- lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
+ br := &blockReader{r: d.r}
+ lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth))
if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
- break
+ if err != io.ErrUnexpectedEOF {
+ return err
+ }
+ return errNotEnough
}
-
- // There should be a "0" block remaining; drain that.
- c, err = d.r.ReadByte()
- if err != nil {
- return err
+ // Both lzwr and br should be exhausted. Reading from them
+ // should yield (0, io.EOF).
+ if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+ if err != nil {
+ return err
+ }
+ return errTooMuch
}
- if c != 0 {
- return errors.New("gif: extra data after image")
+ if n, err := br.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+ if err != nil {
+ return err
+ }
+ return errTooMuch
}
// Undo the interlacing if necessary.
@@ -202,19 +220,15 @@ Loop:
d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
case sTrailer:
- break Loop
+ if len(d.image) == 0 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
default:
- err = fmt.Errorf("gif: unknown block type: 0x%.2x", c)
+ return fmt.Errorf("gif: unknown block type: 0x%.2x", c)
}
}
- if err != nil {
- return err
- }
- if len(d.image) == 0 {
- return io.ErrUnexpectedEOF
- }
- return nil
}
func (d *decoder) readHeaderAndScreenDescriptor() error {
@@ -304,7 +318,6 @@ func (d *decoder) readExtension() error {
return err
}
}
- panic("unreachable")
}
func (d *decoder) readGraphicControl() error {
@@ -335,7 +348,15 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
width := int(d.tmp[4]) + int(d.tmp[5])<<8
height := int(d.tmp[6]) + int(d.tmp[7])<<8
d.imageFields = d.tmp[8]
- return image.NewPaletted(image.Rect(left, top, left+width, top+height), nil), nil
+
+ // The GIF89a spec, Section 20 (Image Descriptor) says:
+ // "Each image must fit within the boundaries of the Logical
+ // Screen, as defined in the Logical Screen Descriptor."
+ bounds := image.Rect(left, top, left+width, top+height)
+ if bounds != bounds.Intersect(image.Rect(0, 0, d.width, d.height)) {
+ return nil, errors.New("gif: frame bounds larger than image bounds")
+ }
+ return image.NewPaletted(bounds, nil), nil
}
func (d *decoder) readBlock() (int, error) {
diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go
new file mode 100644
index 0000000..dcc6c6d
--- /dev/null
+++ b/libgo/go/image/gif/reader_test.go
@@ -0,0 +1,138 @@
+package gif
+
+import (
+ "bytes"
+ "compress/lzw"
+ "image"
+ "image/color"
+ "reflect"
+ "testing"
+)
+
+func TestDecode(t *testing.T) {
+ // header and trailer are parts of a valid 2x1 GIF image.
+ const (
+ header = "GIF89a" +
+ "\x02\x00\x01\x00" + // width=2, height=1
+ "\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
+ "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
+ trailer = "\x3b"
+ )
+
+ // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
+ lzwEncode := func(n int) []byte {
+ b := &bytes.Buffer{}
+ w := lzw.NewWriter(b, lzw.LSB, 2)
+ w.Write(make([]byte, n))
+ w.Close()
+ return b.Bytes()
+ }
+
+ testCases := []struct {
+ nPix int // The number of pixels in the image data.
+ extra bool // Whether to write an extra block after the LZW-encoded data.
+ wantErr error
+ }{
+ {0, false, errNotEnough},
+ {1, false, errNotEnough},
+ {2, false, nil},
+ {2, true, errTooMuch},
+ {3, false, errTooMuch},
+ }
+ for _, tc := range testCases {
+ b := &bytes.Buffer{}
+ b.WriteString(header)
+ // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
+ // then this should result in an invalid GIF image. First, write a
+ // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
+ // byte, and 2-bit LZW literals.
+ b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+ if tc.nPix > 0 {
+ enc := lzwEncode(tc.nPix)
+ if len(enc) > 0xff {
+ t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
+ continue
+ }
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ }
+ if tc.extra {
+ b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
+ }
+ b.WriteByte(0x00) // An empty block signifies the end of the image data.
+ b.WriteString(trailer)
+
+ got, err := Decode(b)
+ if err != tc.wantErr {
+ t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
+ }
+
+ if tc.wantErr != nil {
+ continue
+ }
+ want := &image.Paletted{
+ Pix: []uint8{0, 0},
+ Stride: 2,
+ Rect: image.Rect(0, 0, 2, 1),
+ Palette: color.Palette{
+ color.RGBA{0x10, 0x20, 0x30, 0xff},
+ color.RGBA{0x40, 0x50, 0x60, 0xff},
+ },
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, got, want)
+ }
+ }
+}
+
+// testGIF is a simple GIF that we can modify to test different scenarios.
+var testGIF = []byte{
+ 'G', 'I', 'F', '8', '9', 'a',
+ 1, 0, 1, 0, // w=1, h=1 (6)
+ 128, 0, 0, // headerFields, bg, aspect (10)
+ 0, 0, 0, 1, 1, 1, // color map and graphics control (13)
+ 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
+ // frame 1 (0,0 - 1,1)
+ 0x2c,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, // (32)
+ 0x00,
+ 0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
+ // trailer
+ 0x3b,
+}
+
+func try(t *testing.T, b []byte, want string) {
+ _, err := DecodeAll(bytes.NewReader(b))
+ var got string
+ if err != nil {
+ got = err.Error()
+ }
+ if got != want {
+ t.Fatalf("got %v, want %v", got, want)
+ }
+}
+
+func TestBounds(t *testing.T) {
+ // make a local copy of testGIF
+ gif := make([]byte, len(testGIF))
+ copy(gif, testGIF)
+ // Make the bounds too big, just by one.
+ gif[32] = 2
+ want := "gif: frame bounds larger than image bounds"
+ try(t, gif, want)
+
+ // Make the bounds too small; does not trigger bounds
+ // check, but now there's too much data.
+ gif[32] = 0
+ want = "gif: too much image data"
+ try(t, gif, want)
+ gif[32] = 1
+
+ // Make the bounds really big, expect an error.
+ want = "gif: frame bounds larger than image bounds"
+ for i := 0; i < 4; i++ {
+ gif[32+i] = 0xff
+ }
+ try(t, gif, want)
+}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index 1ee6bbc..862d8dc 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -245,10 +245,38 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
if err != nil {
return nil, err
}
- if d.tmp[0] != 0xff {
- return nil, FormatError("missing 0xff marker start")
+ for d.tmp[0] != 0xff {
+ // Strictly speaking, this is a format error. However, libjpeg is
+ // liberal in what it accepts. As of version 9, next_marker in
+ // jdmarker.c treats this as a warning (JWRN_EXTRANEOUS_DATA) and
+ // continues to decode the stream. Even before next_marker sees
+ // extraneous data, jpeg_fill_bit_buffer in jdhuff.c reads as many
+ // bytes as it can, possibly past the end of a scan's data. It
+ // effectively puts back any markers that it overscanned (e.g. an
+ // "\xff\xd9" EOI marker), but it does not put back non-marker data,
+ // and thus it can silently ignore a small number of extraneous
+ // non-marker bytes before next_marker has a chance to see them (and
+ // print a warning).
+ //
+ // We are therefore also liberal in what we accept. Extraneous data
+ // is silently ignored.
+ //
+ // This is similar to, but not exactly the same as, the restart
+ // mechanism within a scan (the RST[0-7] markers).
+ //
+ // Note that extraneous 0xff bytes in e.g. SOS data are escaped as
+ // "\xff\x00", and so are detected a little further down below.
+ d.tmp[0] = d.tmp[1]
+ d.tmp[1], err = d.r.ReadByte()
+ if err != nil {
+ return nil, err
+ }
}
marker := d.tmp[1]
+ if marker == 0 {
+ // Treat "\xff\x00" as extraneous data.
+ continue
+ }
for marker == 0xff {
// Section B.1.1.2 says, "Any marker may optionally be preceded by any
// number of fill bytes, which are bytes assigned code X'FF'".
diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go
index b520a8a..e951e03 100644
--- a/libgo/go/image/jpeg/reader_test.go
+++ b/libgo/go/image/jpeg/reader_test.go
@@ -8,8 +8,11 @@ import (
"bytes"
"fmt"
"image"
+ "image/color"
"io/ioutil"
+ "math/rand"
"os"
+ "strings"
"testing"
)
@@ -131,6 +134,66 @@ func pixString(pix []byte, stride, x, y int) string {
return s.String()
}
+func TestExtraneousData(t *testing.T) {
+ // Encode a 1x1 red image.
+ src := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ src.Set(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
+ buf := new(bytes.Buffer)
+ if err := Encode(buf, src, nil); err != nil {
+ t.Fatalf("encode: %v", err)
+ }
+ enc := buf.String()
+ // Sanity check that the encoded JPEG is long enough, that it ends in a
+ // "\xff\xd9" EOI marker, and that it contains a "\xff\xda" SOS marker
+ // somewhere in the final 64 bytes.
+ if len(enc) < 64 {
+ t.Fatalf("encoded JPEG is too short: %d bytes", len(enc))
+ }
+ if got, want := enc[len(enc)-2:], "\xff\xd9"; got != want {
+ t.Fatalf("encoded JPEG ends with %q, want %q", got, want)
+ }
+ if s := enc[len(enc)-64:]; !strings.Contains(s, "\xff\xda") {
+ t.Fatalf("encoded JPEG does not contain a SOS marker (ff da) near the end: % x", s)
+ }
+ // Test that adding some random junk between the SOS marker and the
+ // EOI marker does not affect the decoding.
+ rnd := rand.New(rand.NewSource(1))
+ for i, nerr := 0, 0; i < 1000 && nerr < 10; i++ {
+ buf.Reset()
+ // Write all but the trailing "\xff\xd9" EOI marker.
+ buf.WriteString(enc[:len(enc)-2])
+ // Write some random extraneous data.
+ for n := rnd.Intn(10); n > 0; n-- {
+ if x := byte(rnd.Intn(256)); x != 0xff {
+ buf.WriteByte(x)
+ } else {
+ // The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
+ buf.WriteString("\xff\x00")
+ }
+ }
+ // Write the "\xff\xd9" EOI marker.
+ buf.WriteString("\xff\xd9")
+
+ // Check that we can still decode the resultant image.
+ got, err := Decode(buf)
+ if err != nil {
+ t.Errorf("could not decode image #%d: %v", i, err)
+ nerr++
+ continue
+ }
+ if got.Bounds() != src.Bounds() {
+ t.Errorf("image #%d, bounds differ: %v and %v", i, got.Bounds(), src.Bounds())
+ nerr++
+ continue
+ }
+ if averageDelta(got, src) > 2<<8 {
+ t.Errorf("image #%d changed too much after a round trip", i)
+ nerr++
+ continue
+ }
+ }
+}
+
func benchmarkDecode(b *testing.B, filename string) {
b.StopTimer()
data, err := ioutil.ReadFile(filename)
diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go
index e3ae8ae..a69ed17 100644
--- a/libgo/go/image/jpeg/scan.go
+++ b/libgo/go/image/jpeg/scan.go
@@ -109,9 +109,11 @@ func (d *decoder) processSOS(n int) error {
myy := (d.height + 8*v0 - 1) / (8 * v0)
if d.img1 == nil && d.img3 == nil {
d.makeImg(h0, v0, mxx, myy)
- if d.progressive {
- for i := 0; i < nComp; i++ {
- compIndex := scan[i].compIndex
+ }
+ if d.progressive {
+ for i := 0; i < nComp; i++ {
+ compIndex := scan[i].compIndex
+ if d.progCoeffs[compIndex] == nil {
d.progCoeffs[compIndex] = make([]block, mxx*myy*d.comp[compIndex].h*d.comp[compIndex].v)
}
}
diff --git a/libgo/go/image/jpeg/writer_test.go b/libgo/go/image/jpeg/writer_test.go
index 0b2143f..514b455 100644
--- a/libgo/go/image/jpeg/writer_test.go
+++ b/libgo/go/image/jpeg/writer_test.go
@@ -148,29 +148,38 @@ func TestWriter(t *testing.T) {
t.Error(tc.filename, err)
continue
}
- // Compute the average delta in RGB space.
- b := m0.Bounds()
- var sum, n int64
- for y := b.Min.Y; y < b.Max.Y; y++ {
- for x := b.Min.X; x < b.Max.X; x++ {
- c0 := m0.At(x, y)
- c1 := m1.At(x, y)
- r0, g0, b0, _ := c0.RGBA()
- r1, g1, b1, _ := c1.RGBA()
- sum += delta(r0, r1)
- sum += delta(g0, g1)
- sum += delta(b0, b1)
- n += 3
- }
+ if m0.Bounds() != m1.Bounds() {
+ t.Errorf("%s, bounds differ: %v and %v", tc.filename, m0.Bounds(), m1.Bounds())
+ continue
}
// Compare the average delta to the tolerance level.
- if sum/n > tc.tolerance {
+ if averageDelta(m0, m1) > tc.tolerance {
t.Errorf("%s, quality=%d: average delta is too high", tc.filename, tc.quality)
continue
}
}
}
+// averageDelta returns the average delta in RGB space. The two images must
+// have the same bounds.
+func averageDelta(m0, m1 image.Image) int64 {
+ b := m0.Bounds()
+ var sum, n int64
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c0 := m0.At(x, y)
+ c1 := m1.At(x, y)
+ r0, g0, b0, _ := c0.RGBA()
+ r1, g1, b1, _ := c1.RGBA()
+ sum += delta(r0, r1)
+ sum += delta(g0, g1)
+ sum += delta(b0, b1)
+ n += 3
+ }
+ }
+ return sum / n
+}
+
func BenchmarkEncode(b *testing.B) {
b.StopTimer()
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index ff83733..a6bf86e 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -652,10 +652,11 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
}
return image.Config{}, err
}
- if d.stage == dsSeenIHDR && d.cb != cbP8 {
+ paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
+ if d.stage == dsSeenIHDR && !paletted {
break
}
- if d.stage == dsSeenPLTE && d.cb == cbP8 {
+ if d.stage == dsSeenPLTE && paletted {
break
}
}
diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go
index 8223f52..ac0d949 100644
--- a/libgo/go/image/png/reader_test.go
+++ b/libgo/go/image/png/reader_test.go
@@ -38,6 +38,14 @@ var filenames = []string{
"basn6a16",
}
+var filenamesPaletted = []string{
+ "basn3p01",
+ "basn3p02",
+ "basn3p04",
+ "basn3p08",
+ "basn3p08-trns",
+}
+
var filenamesShort = []string{
"basn0g01",
"basn0g04-31",
@@ -208,7 +216,7 @@ func TestReader(t *testing.T) {
}
piper, pipew := io.Pipe()
- pb := bufio.NewReader(piper)
+ pb := bufio.NewScanner(piper)
go sng(pipew, fn, img)
defer piper.Close()
@@ -219,7 +227,7 @@ func TestReader(t *testing.T) {
continue
}
defer sf.Close()
- sb := bufio.NewReader(sf)
+ sb := bufio.NewScanner(sf)
if err != nil {
t.Error(fn, err)
continue
@@ -227,24 +235,28 @@ func TestReader(t *testing.T) {
// Compare the two, in SNG format, line by line.
for {
- ps, perr := pb.ReadString('\n')
- ss, serr := sb.ReadString('\n')
- if perr == io.EOF && serr == io.EOF {
- break
- }
- if perr != nil {
- t.Error(fn, perr)
+ pdone := pb.Scan()
+ sdone := sb.Scan()
+ if pdone && sdone {
break
}
- if serr != nil {
- t.Error(fn, serr)
+ if pdone || sdone {
+ t.Errorf("%s: Different sizes", fn)
break
}
+ ps := pb.Text()
+ ss := sb.Text()
if ps != ss {
t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
break
}
}
+ if pb.Err() != nil {
+ t.Error(fn, pb.Err())
+ }
+ if sb.Err() != nil {
+ t.Error(fn, sb.Err())
+ }
}
}
@@ -274,6 +286,31 @@ func TestReaderError(t *testing.T) {
}
}
+func TestPalettedDecodeConfig(t *testing.T) {
+ for _, fn := range filenamesPaletted {
+ f, err := os.Open("testdata/pngsuite/" + fn + ".png")
+ if err != nil {
+ t.Errorf("%s: open failed: %v", fn, err)
+ continue
+ }
+ defer f.Close()
+ cfg, err := DecodeConfig(f)
+ if err != nil {
+ t.Errorf("%s: %v", fn, err)
+ continue
+ }
+ pal, ok := cfg.ColorModel.(color.Palette)
+ if !ok {
+ t.Errorf("%s: expected paletted color model", fn)
+ continue
+ }
+ if pal == nil {
+ t.Errorf("%s: palette not initialized", fn)
+ continue
+ }
+ }
+}
+
func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
b.StopTimer()
data, err := ioutil.ReadFile(filename)
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
index 093d471..629452c 100644
--- a/libgo/go/image/png/writer.go
+++ b/libgo/go/image/png/writer.go
@@ -436,7 +436,7 @@ func Encode(w io.Writer, m image.Image) error {
// also rejected.
mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
- return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mw, 10))
+ return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10))
}
var e encoder