mirror of
https://github.com/golang/go
synced 2024-11-18 21:44:45 -07:00
image/draw: add a fast path for Gray src images.
Grayscale PNG and JPEG images are not uncommon. We should have a fast path. Also add a benchmark for the recently added CMYK fast path. benchmark old ns/op new ns/op delta BenchmarkGray 13960348 324152 -97.68% Change-Id: I72b5838c8c3d1f2d0a4536a848e020e80b10c0f7 Reviewed-on: https://go-review.googlesource.com/6237 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
05ca0f3370
commit
c20323d2bb
@ -57,6 +57,29 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
|
||||
switch scm {
|
||||
case nil:
|
||||
src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
|
||||
case color.CMYKModel:
|
||||
src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
|
||||
for y := 0; y < srch; y++ {
|
||||
for x := 0; x < srcw; x++ {
|
||||
src1.SetCMYK(x, y, color.CMYK{
|
||||
uint8(13 * x % 0x100),
|
||||
uint8(11 * y % 0x100),
|
||||
uint8((11*x + 13*y) % 0x100),
|
||||
uint8((31*x + 37*y) % 0x100),
|
||||
})
|
||||
}
|
||||
}
|
||||
src = src1
|
||||
case color.GrayModel:
|
||||
src1 := image.NewGray(image.Rect(0, 0, srcw, srch))
|
||||
for y := 0; y < srch; y++ {
|
||||
for x := 0; x < srcw; x++ {
|
||||
src1.SetGray(x, y, color.Gray{
|
||||
uint8((11*x + 13*y) % 0x100),
|
||||
})
|
||||
}
|
||||
}
|
||||
src = src1
|
||||
case color.RGBAModel:
|
||||
src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
|
||||
for y := 0; y < srch; y++ {
|
||||
@ -179,6 +202,14 @@ func BenchmarkYCbCr(b *testing.B) {
|
||||
bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
|
||||
}
|
||||
|
||||
func BenchmarkGray(b *testing.B) {
|
||||
bench(b, color.RGBAModel, color.GrayModel, nil, Over)
|
||||
}
|
||||
|
||||
func BenchmarkCMYK(b *testing.B) {
|
||||
bench(b, color.RGBAModel, color.CMYKModel, nil, Over)
|
||||
}
|
||||
|
||||
func BenchmarkGlyphOver(b *testing.B) {
|
||||
bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
|
||||
}
|
||||
|
@ -127,6 +127,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
||||
if drawYCbCr(dst0, r, src0, sp) {
|
||||
return
|
||||
}
|
||||
case *image.Gray:
|
||||
drawGray(dst0, r, src0, sp)
|
||||
return
|
||||
case *image.CMYK:
|
||||
drawCMYK(dst0, r, src0, sp)
|
||||
return
|
||||
@ -154,6 +157,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
||||
if drawYCbCr(dst0, r, src0, sp) {
|
||||
return
|
||||
}
|
||||
case *image.Gray:
|
||||
drawGray(dst0, r, src0, sp)
|
||||
return
|
||||
case *image.CMYK:
|
||||
drawCMYK(dst0, r, src0, sp)
|
||||
return
|
||||
@ -472,6 +478,30 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
|
||||
return true
|
||||
}
|
||||
|
||||
func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
|
||||
// An image.Gray is always fully opaque, and so if the mask is implicitly nil
|
||||
// (i.e. fully opaque) then the op is effectively always Src.
|
||||
i0 := (r.Min.X - dst.Rect.Min.X) * 4
|
||||
i1 := (r.Max.X - dst.Rect.Min.X) * 4
|
||||
si0 := (sp.X - src.Rect.Min.X) * 1
|
||||
yMax := r.Max.Y - dst.Rect.Min.Y
|
||||
|
||||
y := r.Min.Y - dst.Rect.Min.Y
|
||||
sy := sp.Y - src.Rect.Min.Y
|
||||
for ; y != yMax; y, sy = y+1, sy+1 {
|
||||
dpix := dst.Pix[y*dst.Stride:]
|
||||
spix := src.Pix[sy*src.Stride:]
|
||||
|
||||
for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
|
||||
p := spix[si]
|
||||
dpix[i+0] = p
|
||||
dpix[i+1] = p
|
||||
dpix[i+2] = p
|
||||
dpix[i+3] = 255
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
|
||||
// An image.CMYK is always fully opaque, and so if the mask is implicitly nil
|
||||
// (i.e. fully opaque) then the op is effectively always Src.
|
||||
|
@ -74,6 +74,16 @@ func vgradCr() image.Image {
|
||||
return m
|
||||
}
|
||||
|
||||
func vgradGray() image.Image {
|
||||
m := image.NewGray(image.Rect(0, 0, 16, 16))
|
||||
for y := 0; y < 16; y++ {
|
||||
for x := 0; x < 16; x++ {
|
||||
m.Set(x, y, color.Gray{uint8(y * 0x11)})
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func vgradMagenta() image.Image {
|
||||
m := image.NewCMYK(image.Rect(0, 0, 16, 16))
|
||||
for y := 0; y < 16; y++ {
|
||||
@ -157,6 +167,16 @@ var drawTests = []drawTest{
|
||||
{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
|
||||
{"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
|
||||
{"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
|
||||
// Uniform mask (100%, 75%, nil) and variable Gray source.
|
||||
// At (x, y) == (8, 8):
|
||||
// The destination pixel is {136, 0, 0, 255}.
|
||||
// The source pixel is {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space.
|
||||
{"gray", vgradGray(), fillAlpha(255), Over, color.RGBA{136, 136, 136, 255}},
|
||||
{"graySrc", vgradGray(), fillAlpha(255), Src, color.RGBA{136, 136, 136, 255}},
|
||||
{"grayAlpha", vgradGray(), fillAlpha(192), Over, color.RGBA{136, 102, 102, 255}},
|
||||
{"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}},
|
||||
{"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}},
|
||||
{"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}},
|
||||
// Uniform mask (100%, 75%, nil) and variable CMYK source.
|
||||
// At (x, y) == (8, 8):
|
||||
// The destination pixel is {136, 0, 0, 255}.
|
||||
|
Loading…
Reference in New Issue
Block a user