From: Nigel Tao Date: Sun, 12 Jul 2015 11:02:13 +0000 (+1000) Subject: image/png: don't read filter bytes for empty interlace passes. X-Git-Tag: go1.5beta2~89 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ca6ba492690135647443817ba0d3ccb0c2f0de14;p=gostls13.git image/png: don't read filter bytes for empty interlace passes. Fixes #11604 The gray-gradient.png image was created by a Go program: ---- package main import ( "image" "image/color" "image/png" "log" "os" ) func main() { f, err := os.Create("a.png") if err != nil { log.Fatal(err) } defer f.Close() m := image.NewGray(image.Rect(0, 0, 1, 16)) for i := 0; i < 16; i++ { m.SetGray(0, i, color.Gray{uint8(i * 0x11)}) } err = png.Encode(f, m) if err != nil { log.Fatal(err) } } ---- The equivalent gray-gradient.interlaced.png image was created via ImageMagick: $ convert -interlace PNG gray-gradient.png gray-gradient.interlaced.png As a sanity check: $ file gray-gradient.* gray-gradient.interlaced.png: PNG image data, 1 x 16, 4-bit grayscale, interlaced gray-gradient.png: PNG image data, 1 x 16, 8-bit grayscale, non-interlaced Change-Id: I7700284f74d1ea30073aede3bce4d7651787bdbc Reviewed-on: https://go-review.googlesource.com/12064 Reviewed-by: Rob Pike Reviewed-by: Brad Fitzpatrick --- diff --git a/src/image/png/reader.go b/src/image/png/reader.go index 33218e1516..bbd6f753fa 100644 --- a/src/image/png/reader.go +++ b/src/image/png/reader.go @@ -340,7 +340,9 @@ func (d *decoder) decode() (image.Image, error) { if err != nil { return nil, err } - d.mergePassInto(img, imagePass, pass) + if imagePass != nil { + d.mergePassInto(img, imagePass, pass) + } } } @@ -382,6 +384,12 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image // Add the multiplication factor and subtract one, effectively rounding up. width = (width - p.xOffset + p.xFactor - 1) / p.xFactor height = (height - p.yOffset + p.yFactor - 1) / p.yFactor + // A PNG image can't have zero width or height, but for an interlaced + // image, an individual pass might have zero width or height. If so, we + // shouldn't even read a per-row filter type byte, so return early. + if width == 0 || height == 0 { + return nil, nil + } } switch d.cb { case cbG1, cbG2, cbG4, cbG8: @@ -457,6 +465,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image cdat[i] += p } case ftAverage: + // The first column has no column to the left of it, so it is a + // special case. We know that the first column exists because we + // check above that width != 0, and so len(cdat) != 0. for i := 0; i < bytesPerPixel; i++ { cdat[i] += pdat[i] / 2 } diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go index 1f92f8c221..f89e7efe7f 100644 --- a/src/image/png/reader_test.go +++ b/src/image/png/reader_test.go @@ -13,6 +13,7 @@ import ( "io" "io/ioutil" "os" + "reflect" "strings" "testing" ) @@ -320,6 +321,20 @@ func TestPalettedDecodeConfig(t *testing.T) { } } +func TestInterlaced(t *testing.T) { + a, err := readPNG("testdata/gray-gradient.png") + if err != nil { + t.Fatal(err) + } + b, err := readPNG("testdata/gray-gradient.interlaced.png") + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(a, b) { + t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b) + } +} + func TestIncompleteIDATOnRowBoundary(t *testing.T) { // The following is an invalid 1x2 grayscale PNG image. The header is OK, // but the zlib-compressed IDAT payload contains two bytes "\x02\x00", diff --git a/src/image/png/testdata/gray-gradient.interlaced.png b/src/image/png/testdata/gray-gradient.interlaced.png new file mode 100644 index 0000000000..01f657ae86 Binary files /dev/null and b/src/image/png/testdata/gray-gradient.interlaced.png differ diff --git a/src/image/png/testdata/gray-gradient.png b/src/image/png/testdata/gray-gradient.png new file mode 100644 index 0000000000..6de1cd36f4 Binary files /dev/null and b/src/image/png/testdata/gray-gradient.png differ