mirror of
https://github.com/golang/go
synced 2024-11-22 02:04:40 -07:00
image/png: optimize encoding image.Gray and image.NRGBA images.
benchmark old ns/op new ns/op delta BenchmarkEncodeGray 23616080 5624558 -76.18% BenchmarkEncodeNRGBOpaque 34181260 17144380 -49.84% BenchmarkEncodeNRGBA 41235820 20345990 -50.66% BenchmarkEncodePaletted 5594652 5620362 +0.46% BenchmarkEncodeRGBOpaque 17242210 17168820 -0.43% BenchmarkEncodeRGBA 66515720 67243560 +1.09% R=r CC=golang-dev https://golang.org/cl/6490099
This commit is contained in:
parent
e7d7ea21d4
commit
237ee39269
@ -290,26 +290,42 @@ func writeImage(w io.Writer, m image.Image, cb int) error {
|
||||
}
|
||||
pr := make([]uint8, 1+bpp*b.Dx())
|
||||
|
||||
gray, _ := m.(*image.Gray)
|
||||
rgba, _ := m.(*image.RGBA)
|
||||
paletted, _ := m.(*image.Paletted)
|
||||
nrgba, _ := m.(*image.NRGBA)
|
||||
|
||||
for y := b.Min.Y; y < b.Max.Y; y++ {
|
||||
// Convert from colors to bytes.
|
||||
i := 1
|
||||
switch cb {
|
||||
case cbG8:
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
|
||||
cr[0][i] = c.Y
|
||||
i++
|
||||
if gray != nil {
|
||||
offset := (y - b.Min.Y) * gray.Stride
|
||||
copy(cr[0][1:], gray.Pix[offset:offset+b.Dx()])
|
||||
} else {
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
c := color.GrayModel.Convert(m.At(x, y)).(color.Gray)
|
||||
cr[0][i] = c.Y
|
||||
i++
|
||||
}
|
||||
}
|
||||
case cbTC8:
|
||||
// We have previously verified that the alpha value is fully opaque.
|
||||
cr0 := cr[0]
|
||||
if rgba, _ := m.(*image.RGBA); rgba != nil {
|
||||
j0 := (y - b.Min.Y) * rgba.Stride
|
||||
stride, pix := 0, []byte(nil)
|
||||
if rgba != nil {
|
||||
stride, pix = rgba.Stride, rgba.Pix
|
||||
} else if nrgba != nil {
|
||||
stride, pix = nrgba.Stride, nrgba.Pix
|
||||
}
|
||||
if stride != 0 {
|
||||
j0 := (y - b.Min.Y) * stride
|
||||
j1 := j0 + b.Dx()*4
|
||||
for j := j0; j < j1; j += 4 {
|
||||
cr0[i+0] = rgba.Pix[j+0]
|
||||
cr0[i+1] = rgba.Pix[j+1]
|
||||
cr0[i+2] = rgba.Pix[j+2]
|
||||
cr0[i+0] = pix[j+0]
|
||||
cr0[i+1] = pix[j+1]
|
||||
cr0[i+2] = pix[j+2]
|
||||
i += 3
|
||||
}
|
||||
} else {
|
||||
@ -322,9 +338,9 @@ func writeImage(w io.Writer, m image.Image, cb int) error {
|
||||
}
|
||||
}
|
||||
case cbP8:
|
||||
if p, _ := m.(*image.Paletted); p != nil {
|
||||
offset := (y - b.Min.Y) * p.Stride
|
||||
copy(cr[0][1:], p.Pix[offset:offset+b.Dx()])
|
||||
if paletted != nil {
|
||||
offset := (y - b.Min.Y) * paletted.Stride
|
||||
copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
|
||||
} else {
|
||||
pi := m.(image.PalettedImage)
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
@ -333,14 +349,19 @@ func writeImage(w io.Writer, m image.Image, cb int) error {
|
||||
}
|
||||
}
|
||||
case cbTCA8:
|
||||
// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
|
||||
cr[0][i+0] = c.R
|
||||
cr[0][i+1] = c.G
|
||||
cr[0][i+2] = c.B
|
||||
cr[0][i+3] = c.A
|
||||
i += 4
|
||||
if nrgba != nil {
|
||||
offset := (y - b.Min.Y) * nrgba.Stride
|
||||
copy(cr[0][1:], nrgba.Pix[offset:offset+b.Dx()*4])
|
||||
} else {
|
||||
// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
c := color.NRGBAModel.Convert(m.At(x, y)).(color.NRGBA)
|
||||
cr[0][i+0] = c.R
|
||||
cr[0][i+1] = c.G
|
||||
cr[0][i+2] = c.B
|
||||
cr[0][i+3] = c.A
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
case cbG16:
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
|
@ -101,6 +101,49 @@ func TestSubImage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeGray(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img := image.NewGray(image.Rect(0, 0, 640, 480))
|
||||
b.SetBytes(640 * 480 * 1)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ioutil.Discard, img)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeNRGBOpaque(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img := image.NewNRGBA(image.Rect(0, 0, 640, 480))
|
||||
// Set all pixels to 0xFF alpha to force opaque mode.
|
||||
bo := img.Bounds()
|
||||
for y := bo.Min.Y; y < bo.Max.Y; y++ {
|
||||
for x := bo.Min.X; x < bo.Max.X; x++ {
|
||||
img.Set(x, y, color.NRGBA{0, 0, 0, 255})
|
||||
}
|
||||
}
|
||||
if !img.Opaque() {
|
||||
b.Fatal("expected image to be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ioutil.Discard, img)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeNRGBA(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img := image.NewNRGBA(image.Rect(0, 0, 640, 480))
|
||||
if img.Opaque() {
|
||||
b.Fatal("expected image not to be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(ioutil.Discard, img)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodePaletted(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img := image.NewPaletted(image.Rect(0, 0, 640, 480), color.Palette{
|
||||
@ -138,7 +181,7 @@ func BenchmarkEncodeRGBA(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
|
||||
if img.Opaque() {
|
||||
b.Fatal("expected image to not be opaque")
|
||||
b.Fatal("expected image not to be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
|
Loading…
Reference in New Issue
Block a user