Commit dd294fbd authored by Nigel Tao's avatar Nigel Tao

image/png: speed up PNG decoding for common color models: Gray, NRGBA,

Paletted, RGBA.

benchmark                       old ns/op    new ns/op    delta
BenchmarkDecodeGray               3681144      2536049  -31.11%
BenchmarkDecodeNRGBAGradient     12108660     10020650  -17.24%
BenchmarkDecodeNRGBAOpaque       10699230      8677165  -18.90%
BenchmarkDecodePaletted           2562806      1458798  -43.08%
BenchmarkDecodeRGB                8468175      7180730  -15.20%

benchmark                        old MB/s     new MB/s  speedup
BenchmarkDecodeGray                 17.80        25.84    1.45x
BenchmarkDecodeNRGBAGradient        21.65        26.16    1.21x
BenchmarkDecodeNRGBAOpaque          24.50        30.21    1.23x
BenchmarkDecodePaletted             25.57        44.92    1.76x
BenchmarkDecodeRGB                  30.96        36.51    1.18x

$ file $GOROOT/src/pkg/image/png/testdata/bench*
benchGray.png:           PNG image, 256 x 256, 8-bit grayscale, non-interlaced
benchNRGBA-gradient.png: PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
benchNRGBA-opaque.png:   PNG image, 256 x 256, 8-bit/color RGBA, non-interlaced
benchPaletted.png:       PNG image, 256 x 256, 8-bit colormap, non-interlaced
benchRGB.png:            PNG image, 256 x 256, 8-bit/color RGB, non-interlaced

R=r
CC=golang-dev
https://golang.org/cl/6127051
parent 9ce770af
......@@ -301,6 +301,7 @@ func (d *decoder) decode() (image.Image, error) {
defer r.Close()
bitsPerPixel := 0
maxPalette := uint8(0)
pixOffset := 0
var (
gray *image.Gray
rgba *image.RGBA
......@@ -423,18 +424,24 @@ func (d *decoder) decode() (image.Image, error) {
}
}
case cbG8:
for x := 0; x < d.width; x++ {
gray.SetGray(x, y, color.Gray{cdat[x]})
}
copy(gray.Pix[pixOffset:], cdat)
pixOffset += gray.Stride
case cbGA8:
for x := 0; x < d.width; x++ {
ycol := cdat[2*x+0]
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
pix, i, j := rgba.Pix, pixOffset, 0
for x := 0; x < d.width; x++ {
rgba.SetRGBA(x, y, color.RGBA{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
pix[i+0] = cdat[j+0]
pix[i+1] = cdat[j+1]
pix[i+2] = cdat[j+2]
pix[i+3] = 0xff
i += 4
j += 3
}
pixOffset += rgba.Stride
case cbP1:
for x := 0; x < d.width; x += 8 {
b := cdat[x/8]
......@@ -472,16 +479,18 @@ func (d *decoder) decode() (image.Image, error) {
}
}
case cbP8:
for x := 0; x < d.width; x++ {
if cdat[x] > maxPalette {
return nil, FormatError("palette index out of range")
if maxPalette != 255 {
for x := 0; x < d.width; x++ {
if cdat[x] > maxPalette {
return nil, FormatError("palette index out of range")
}
}
paletted.SetColorIndex(x, y, cdat[x])
}
copy(paletted.Pix[pixOffset:], cdat)
pixOffset += paletted.Stride
case cbTCA8:
for x := 0; x < d.width; x++ {
nrgba.SetNRGBA(x, y, color.NRGBA{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
}
copy(nrgba.Pix[pixOffset:], cdat)
pixOffset += nrgba.Stride
case cbG16:
for x := 0; x < d.width; x++ {
ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
......
......@@ -10,6 +10,7 @@ import (
"image"
"image/color"
"io"
"io/ioutil"
"os"
"strings"
"testing"
......@@ -267,3 +268,41 @@ func TestReaderError(t *testing.T) {
}
}
}
func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
b.StopTimer()
data, err := ioutil.ReadFile(filename)
if err != nil {
b.Fatal(err)
}
s := string(data)
cfg, err := DecodeConfig(strings.NewReader(s))
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(cfg.Width * cfg.Height * bytesPerPixel))
b.StartTimer()
for i := 0; i < b.N; i++ {
Decode(strings.NewReader(s))
}
}
func BenchmarkDecodeGray(b *testing.B) {
benchmarkDecode(b, "testdata/benchGray.png", 1)
}
func BenchmarkDecodeNRGBAGradient(b *testing.B) {
benchmarkDecode(b, "testdata/benchNRGBA-gradient.png", 4)
}
func BenchmarkDecodeNRGBAOpaque(b *testing.B) {
benchmarkDecode(b, "testdata/benchNRGBA-opaque.png", 4)
}
func BenchmarkDecodePaletted(b *testing.B) {
benchmarkDecode(b, "testdata/benchPaletted.png", 1)
}
func BenchmarkDecodeRGB(b *testing.B) {
benchmarkDecode(b, "testdata/benchRGB.png", 4)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment