]> Cypherpunks repositories - gostls13.git/commitdiff
image/png: speed up PNG decoding for common color models: Gray, NRGBA,
authorNigel Tao <nigeltao@golang.org>
Fri, 27 Apr 2012 06:03:58 +0000 (16:03 +1000)
committerNigel Tao <nigeltao@golang.org>
Fri, 27 Apr 2012 06:03:58 +0000 (16:03 +1000)
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

src/pkg/image/png/reader.go
src/pkg/image/png/reader_test.go
src/pkg/image/png/testdata/benchGray.png [new file with mode: 0644]
src/pkg/image/png/testdata/benchNRGBA-gradient.png [new file with mode: 0644]
src/pkg/image/png/testdata/benchNRGBA-opaque.png [new file with mode: 0644]
src/pkg/image/png/testdata/benchPaletted.png [new file with mode: 0644]
src/pkg/image/png/testdata/benchRGB.png [new file with mode: 0644]

index fe07d60a91adc5635588467f803c114a4a78f062..c781be1837512d5f758f753ac42927090a9e64f1 100644 (file)
@@ -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])
index 24c4ea448081d964fa373e5a93cdbf30864f611e..0d8c1d9cb9a0f3582a72e8723a89805c105a4822 100644 (file)
@@ -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)
+}
diff --git a/src/pkg/image/png/testdata/benchGray.png b/src/pkg/image/png/testdata/benchGray.png
new file mode 100644 (file)
index 0000000..42bc6c3
Binary files /dev/null and b/src/pkg/image/png/testdata/benchGray.png differ
diff --git a/src/pkg/image/png/testdata/benchNRGBA-gradient.png b/src/pkg/image/png/testdata/benchNRGBA-gradient.png
new file mode 100644 (file)
index 0000000..961934c
Binary files /dev/null and b/src/pkg/image/png/testdata/benchNRGBA-gradient.png differ
diff --git a/src/pkg/image/png/testdata/benchNRGBA-opaque.png b/src/pkg/image/png/testdata/benchNRGBA-opaque.png
new file mode 100644 (file)
index 0000000..ca4f4a0
Binary files /dev/null and b/src/pkg/image/png/testdata/benchNRGBA-opaque.png differ
diff --git a/src/pkg/image/png/testdata/benchPaletted.png b/src/pkg/image/png/testdata/benchPaletted.png
new file mode 100644 (file)
index 0000000..4b4d5b9
Binary files /dev/null and b/src/pkg/image/png/testdata/benchPaletted.png differ
diff --git a/src/pkg/image/png/testdata/benchRGB.png b/src/pkg/image/png/testdata/benchRGB.png
new file mode 100644 (file)
index 0000000..31ac65a
Binary files /dev/null and b/src/pkg/image/png/testdata/benchRGB.png differ