Skip to content

Commit

Permalink
image/png: don't read filter bytes for empty interlace passes.
Browse files Browse the repository at this point in the history
Fixes golang#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 <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
  • Loading branch information
nigeltao committed Jul 13, 2015
1 parent 616cb3c commit ca6ba49
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/image/png/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
}
Expand Down
15 changes: 15 additions & 0 deletions src/image/png/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"io"
"io/ioutil"
"os"
"reflect"
"strings"
"testing"
)
Expand Down Expand Up @@ -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",
Expand Down
Binary file added src/image/png/testdata/gray-gradient.interlaced.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/image/png/testdata/gray-gradient.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ca6ba49

Please sign in to comment.