vector: implement arbitrary dst and src image types.
Change-Id: Ib0d0961c69cabc3bb01d7b1d244796f0f713b819 Reviewed-on: https://go-review.googlesource.com/29691 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
50ce1ebf58
commit
b077ed42b3
|
@ -61,7 +61,7 @@ func (z *Rasterizer) floatingLineTo(b f32.Vec2) {
|
||||||
x = xNext
|
x = xNext
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf := z.area[y*width:]
|
buf := z.bufF32[y*width:]
|
||||||
d := dy * dir
|
d := dy * dir
|
||||||
x0, x1 := x, xNext
|
x0, x1 := x, xNext
|
||||||
if x > xNext {
|
if x > xNext {
|
||||||
|
@ -178,3 +178,18 @@ func floatingAccumulateOpOver(dst []uint8, src []float32) {
|
||||||
dst[i] = uint8(outA >> 8)
|
dst[i] = uint8(outA >> 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func floatingAccumulateMask(dst []uint32, src []float32) {
|
||||||
|
acc := float32(0)
|
||||||
|
for i, v := range src {
|
||||||
|
acc += v
|
||||||
|
a := acc
|
||||||
|
if a < 0 {
|
||||||
|
a = -a
|
||||||
|
}
|
||||||
|
if a > 1 {
|
||||||
|
a = 1
|
||||||
|
}
|
||||||
|
dst[i] = uint32(almost65536 * a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package vector // import "golang.org/x/image/vector"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
@ -52,14 +53,32 @@ func clamp(i, width int32) uint {
|
||||||
// by the given width and height.
|
// by the given width and height.
|
||||||
func NewRasterizer(w, h int) *Rasterizer {
|
func NewRasterizer(w, h int) *Rasterizer {
|
||||||
return &Rasterizer{
|
return &Rasterizer{
|
||||||
area: make([]float32, w*h),
|
bufF32: make([]float32, w*h),
|
||||||
size: image.Point{w, h},
|
size: image.Point{w, h},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raster is a 2-D vector graphics rasterizer.
|
// Raster is a 2-D vector graphics rasterizer.
|
||||||
type Rasterizer struct {
|
type Rasterizer struct {
|
||||||
area []float32
|
// bufXxx are buffers of float32 or uint32 values, holding either the
|
||||||
|
// individual or cumulative area values.
|
||||||
|
//
|
||||||
|
// We don't actually need both values at any given time, and to conserve
|
||||||
|
// memory, the integration of the individual to the cumulative could modify
|
||||||
|
// the buffer in place. In other words, we could use a single buffer, say
|
||||||
|
// of type []uint32, and add some math.Float32bits and math.Float32frombits
|
||||||
|
// calls to satisfy the compiler's type checking. As of Go 1.7, though,
|
||||||
|
// there is a performance penalty between:
|
||||||
|
// bufF32[i] += x
|
||||||
|
// and
|
||||||
|
// bufU32[i] = math.Float32bits(x + math.Float32frombits(bufU32[i]))
|
||||||
|
//
|
||||||
|
// See golang.org/issue/17220 for some discussion.
|
||||||
|
//
|
||||||
|
// TODO: use bufU32 in the fixed point math implementation.
|
||||||
|
bufF32 []float32
|
||||||
|
bufU32 []uint32
|
||||||
|
|
||||||
size image.Point
|
size image.Point
|
||||||
first f32.Vec2
|
first f32.Vec2
|
||||||
pen f32.Vec2
|
pen f32.Vec2
|
||||||
|
@ -77,12 +96,12 @@ type Rasterizer struct {
|
||||||
//
|
//
|
||||||
// This includes setting z.DrawOp to draw.Over.
|
// This includes setting z.DrawOp to draw.Over.
|
||||||
func (z *Rasterizer) Reset(w, h int) {
|
func (z *Rasterizer) Reset(w, h int) {
|
||||||
if n := w * h; n > cap(z.area) {
|
if n := w * h; n > cap(z.bufF32) {
|
||||||
z.area = make([]float32, n)
|
z.bufF32 = make([]float32, n)
|
||||||
} else {
|
} else {
|
||||||
z.area = z.area[:n]
|
z.bufF32 = z.bufF32[:n]
|
||||||
for i := range z.area {
|
for i := range z.bufF32 {
|
||||||
z.area[i] = 0
|
z.bufF32[i] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
z.size = image.Point{w, h}
|
z.size = image.Point{w, h}
|
||||||
|
@ -202,6 +221,9 @@ func devSquared(a, b, c f32.Vec2) float32 {
|
||||||
// The vector paths previously added via the XxxTo calls become the mask for
|
// The vector paths previously added via the XxxTo calls become the mask for
|
||||||
// drawing src onto dst.
|
// drawing src onto dst.
|
||||||
func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||||
|
// TODO: adjust r and sp (and mp?) if src.Bounds() doesn't contain
|
||||||
|
// r.Add(sp.Sub(r.Min)).
|
||||||
|
|
||||||
if src, ok := src.(*image.Uniform); ok {
|
if src, ok := src.(*image.Uniform); ok {
|
||||||
_, _, _, srcA := src.RGBA()
|
_, _, _, srcA := src.RGBA()
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
|
@ -217,7 +239,19 @@ func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("TODO: the general case")
|
|
||||||
|
if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
|
||||||
|
z.bufU32 = make([]uint32, n)
|
||||||
|
} else {
|
||||||
|
z.bufU32 = z.bufU32[:n]
|
||||||
|
}
|
||||||
|
floatingAccumulateMask(z.bufU32, z.bufF32)
|
||||||
|
|
||||||
|
if z.DrawOp == draw.Over {
|
||||||
|
z.rasterizeOpOver(dst, r, src, sp)
|
||||||
|
} else {
|
||||||
|
z.rasterizeOpSrc(dst, r, src, sp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.Rectangle) {
|
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.Rectangle) {
|
||||||
|
@ -225,7 +259,7 @@ func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.R
|
||||||
// TODO: add a fixed point math implementation.
|
// TODO: add a fixed point math implementation.
|
||||||
// TODO: non-zero vs even-odd winding?
|
// TODO: non-zero vs even-odd winding?
|
||||||
if r == dst.Bounds() && r == z.Bounds() {
|
if r == dst.Bounds() && r == z.Bounds() {
|
||||||
floatingAccumulateOpSrc(dst.Pix, z.area)
|
floatingAccumulateOpSrc(dst.Pix, z.bufF32)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println("TODO: the general case")
|
println("TODO: the general case")
|
||||||
|
@ -236,8 +270,50 @@ func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpOver(dst *image.Alpha, r image.
|
||||||
// TODO: add a fixed point math implementation.
|
// TODO: add a fixed point math implementation.
|
||||||
// TODO: non-zero vs even-odd winding?
|
// TODO: non-zero vs even-odd winding?
|
||||||
if r == dst.Bounds() && r == z.Bounds() {
|
if r == dst.Bounds() && r == z.Bounds() {
|
||||||
floatingAccumulateOpOver(dst.Pix, z.area)
|
floatingAccumulateOpOver(dst.Pix, z.bufF32)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println("TODO: the general case")
|
println("TODO: the general case")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||||
|
out := color.RGBA64{}
|
||||||
|
outc := color.Color(&out)
|
||||||
|
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||||
|
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||||
|
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
|
||||||
|
ma := z.bufU32[y*z.size.X+x]
|
||||||
|
|
||||||
|
// This algorithm comes from the standard library's image/draw
|
||||||
|
// package.
|
||||||
|
dr, dg, db, da := dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
|
||||||
|
a := 0xffff - (sa * ma / 0xffff)
|
||||||
|
out.R = uint16((dr*a + sr*ma) / 0xffff)
|
||||||
|
out.G = uint16((dg*a + sg*ma) / 0xffff)
|
||||||
|
out.B = uint16((db*a + sb*ma) / 0xffff)
|
||||||
|
out.A = uint16((da*a + sa*ma) / 0xffff)
|
||||||
|
|
||||||
|
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *Rasterizer) rasterizeOpSrc(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||||
|
out := color.RGBA64{}
|
||||||
|
outc := color.Color(&out)
|
||||||
|
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||||
|
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||||
|
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
|
||||||
|
ma := z.bufU32[y*z.size.X+x]
|
||||||
|
|
||||||
|
// This algorithm comes from the standard library's image/draw
|
||||||
|
// package.
|
||||||
|
out.R = uint16(sr * ma / 0xffff)
|
||||||
|
out.G = uint16(sg * ma / 0xffff)
|
||||||
|
out.B = uint16(sb * ma / 0xffff)
|
||||||
|
out.A = uint16(sa * ma / 0xffff)
|
||||||
|
|
||||||
|
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -32,35 +32,39 @@ func encodePNG(dstFilename string, src image.Image) error {
|
||||||
return closeErr
|
return closeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicPath(t *testing.T) {
|
var basicMask = []byte{
|
||||||
mask := []byte{
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xaa, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xaa, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x5f, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x5f, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x24, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x24, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x14, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x14, 0x00, 0x00,
|
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x4a, 0x00, 0x00,
|
0x00, 0x00, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x00, 0x00,
|
||||||
0x00, 0x00, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0x00, 0x00,
|
0x00, 0x00, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xe4, 0xff, 0xff, 0xff, 0xb6, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x66, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xe4, 0xff, 0xff, 0xff, 0xb6, 0x00, 0x00,
|
0x00, 0x00, 0x0c, 0xf2, 0xff, 0xff, 0xfe, 0x9e, 0x15, 0x00, 0x15, 0x96, 0xff, 0xce, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x0c, 0xf2, 0xff, 0xff, 0xfe, 0x9e, 0x15, 0x00, 0x15, 0x96, 0xff, 0xce, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x88, 0xfc, 0xe3, 0x43, 0x00, 0x00, 0x00, 0x00, 0x06, 0xcd, 0xdc, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x88, 0xfc, 0xe3, 0x43, 0x00, 0x00, 0x00, 0x00, 0x06, 0xcd, 0xdc, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xde, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xde, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
func basicRasterizer() *Rasterizer {
|
||||||
|
z := NewRasterizer(16, 16)
|
||||||
|
z.MoveTo(f32.Vec2{2, 2})
|
||||||
|
z.LineTo(f32.Vec2{8, 2})
|
||||||
|
z.QuadTo(f32.Vec2{14, 2}, f32.Vec2{14, 14})
|
||||||
|
z.CubeTo(f32.Vec2{8, 2}, f32.Vec2{5, 20}, f32.Vec2{2, 8})
|
||||||
|
z.ClosePath()
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicPathDstAlpha(t *testing.T) {
|
||||||
for _, background := range []uint8{0x00, 0x80} {
|
for _, background := range []uint8{0x00, 0x80} {
|
||||||
for _, op := range []draw.Op{draw.Over, draw.Src} {
|
for _, op := range []draw.Op{draw.Over, draw.Src} {
|
||||||
z := NewRasterizer(16, 16)
|
z := basicRasterizer()
|
||||||
z.MoveTo(f32.Vec2{2, 2})
|
|
||||||
z.LineTo(f32.Vec2{8, 2})
|
|
||||||
z.QuadTo(f32.Vec2{14, 2}, f32.Vec2{14, 14})
|
|
||||||
z.CubeTo(f32.Vec2{8, 2}, f32.Vec2{5, 20}, f32.Vec2{2, 8})
|
|
||||||
z.ClosePath()
|
|
||||||
|
|
||||||
dst := image.NewAlpha(z.Bounds())
|
dst := image.NewAlpha(z.Bounds())
|
||||||
for i := range dst.Pix {
|
for i := range dst.Pix {
|
||||||
dst.Pix[i] = background
|
dst.Pix[i] = background
|
||||||
|
@ -69,13 +73,13 @@ func TestBasicPath(t *testing.T) {
|
||||||
z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
|
z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
|
||||||
got := dst.Pix
|
got := dst.Pix
|
||||||
|
|
||||||
want := make([]byte, len(mask))
|
want := make([]byte, len(basicMask))
|
||||||
if op == draw.Over && background == 0x80 {
|
if op == draw.Over && background == 0x80 {
|
||||||
for i, ma := range mask {
|
for i, ma := range basicMask {
|
||||||
want[i] = 0xff - (0xff-ma)/2
|
want[i] = 0xff - (0xff-ma)/2
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
copy(want, mask)
|
copy(want, basicMask)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(got) != len(want) {
|
if len(got) != len(want) {
|
||||||
|
@ -96,6 +100,66 @@ func TestBasicPath(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBasicPathDstRGBA(t *testing.T) {
|
||||||
|
blue := color.RGBA{0x00, 0x00, 0xff, 0xff}
|
||||||
|
|
||||||
|
for _, op := range []draw.Op{draw.Over, draw.Src} {
|
||||||
|
z := basicRasterizer()
|
||||||
|
dst := image.NewRGBA(z.Bounds())
|
||||||
|
for y := 0; y < 16; y++ {
|
||||||
|
for x := 0; x < 16; x++ {
|
||||||
|
dst.SetRGBA(x, y, color.RGBA{
|
||||||
|
R: uint8(y*0x11) / 2,
|
||||||
|
G: uint8(x*0x11) / 2,
|
||||||
|
B: 0x00,
|
||||||
|
A: 0x80,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
z.DrawOp = op
|
||||||
|
z.Draw(dst, dst.Bounds(), image.NewUniform(blue), image.Point{})
|
||||||
|
got := dst.Pix
|
||||||
|
|
||||||
|
want := make([]byte, len(basicMask)*4)
|
||||||
|
if op == draw.Over {
|
||||||
|
for y := 0; y < 16; y++ {
|
||||||
|
for x := 0; x < 16; x++ {
|
||||||
|
i := 16*y + x
|
||||||
|
ma := basicMask[i]
|
||||||
|
want[4*i+0] = uint8((uint32(0xff-ma) * uint32(y*0x11/2)) / 0xff)
|
||||||
|
want[4*i+1] = uint8((uint32(0xff-ma) * uint32(x*0x11/2)) / 0xff)
|
||||||
|
want[4*i+2] = ma
|
||||||
|
want[4*i+3] = ma/2 + 0x80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for y := 0; y < 16; y++ {
|
||||||
|
for x := 0; x < 16; x++ {
|
||||||
|
i := 16*y + x
|
||||||
|
ma := basicMask[i]
|
||||||
|
want[4*i+0] = 0x00
|
||||||
|
want[4*i+1] = 0x00
|
||||||
|
want[4*i+2] = ma
|
||||||
|
want[4*i+3] = ma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(got) != len(want) {
|
||||||
|
t.Errorf("op=%v: len(got)=%d and len(want)=%d differ", op, len(got), len(want))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := range got {
|
||||||
|
delta := int(got[i]) - int(want[i])
|
||||||
|
// The +/- 2 allows different implementations to give different
|
||||||
|
// rounding errors.
|
||||||
|
if delta < -2 || +2 < delta {
|
||||||
|
t.Errorf("op=%v: i=%d: got %#02x, want %#02x", op, i, got[i], want[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
benchmarkGlyphWidth = 893
|
benchmarkGlyphWidth = 893
|
||||||
benchmarkGlyphHeight = 1122
|
benchmarkGlyphHeight = 1122
|
||||||
|
@ -167,6 +231,12 @@ func benchGlyph(b *testing.B, cm color.Model, height int, op draw.Op) {
|
||||||
case color.AlphaModel:
|
case color.AlphaModel:
|
||||||
dst = image.NewAlpha(z.Bounds())
|
dst = image.NewAlpha(z.Bounds())
|
||||||
src = image.Opaque
|
src = image.Opaque
|
||||||
|
case color.NRGBAModel:
|
||||||
|
dst = image.NewNRGBA(z.Bounds())
|
||||||
|
src = image.NewUniform(color.NRGBA{0x40, 0x80, 0xc0, 0xff})
|
||||||
|
case color.RGBAModel:
|
||||||
|
dst = image.NewRGBA(z.Bounds())
|
||||||
|
src = image.NewUniform(color.RGBA{0x40, 0x80, 0xc0, 0xff})
|
||||||
default:
|
default:
|
||||||
b.Fatal("unsupported color model")
|
b.Fatal("unsupported color model")
|
||||||
}
|
}
|
||||||
|
@ -200,4 +270,24 @@ func BenchmarkGlyphAlpha128Src(b *testing.B) { benchGlyph(b, color.AlphaModel,
|
||||||
func BenchmarkGlyphAlpha256Over(b *testing.B) { benchGlyph(b, color.AlphaModel, 256, draw.Over) }
|
func BenchmarkGlyphAlpha256Over(b *testing.B) { benchGlyph(b, color.AlphaModel, 256, draw.Over) }
|
||||||
func BenchmarkGlyphAlpha256Src(b *testing.B) { benchGlyph(b, color.AlphaModel, 256, draw.Src) }
|
func BenchmarkGlyphAlpha256Src(b *testing.B) { benchGlyph(b, color.AlphaModel, 256, draw.Src) }
|
||||||
|
|
||||||
// TODO: color.RGBAModel benchmarks.
|
func BenchmarkGlyphNRGBA16Over(b *testing.B) { benchGlyph(b, color.NRGBAModel, 16, draw.Over) }
|
||||||
|
func BenchmarkGlyphNRGBA16Src(b *testing.B) { benchGlyph(b, color.NRGBAModel, 16, draw.Src) }
|
||||||
|
func BenchmarkGlyphNRGBA32Over(b *testing.B) { benchGlyph(b, color.NRGBAModel, 32, draw.Over) }
|
||||||
|
func BenchmarkGlyphNRGBA32Src(b *testing.B) { benchGlyph(b, color.NRGBAModel, 32, draw.Src) }
|
||||||
|
func BenchmarkGlyphNRGBA64Over(b *testing.B) { benchGlyph(b, color.NRGBAModel, 64, draw.Over) }
|
||||||
|
func BenchmarkGlyphNRGBA64Src(b *testing.B) { benchGlyph(b, color.NRGBAModel, 64, draw.Src) }
|
||||||
|
func BenchmarkGlyphNRGBA128Over(b *testing.B) { benchGlyph(b, color.NRGBAModel, 128, draw.Over) }
|
||||||
|
func BenchmarkGlyphNRGBA128Src(b *testing.B) { benchGlyph(b, color.NRGBAModel, 128, draw.Src) }
|
||||||
|
func BenchmarkGlyphNRGBA256Over(b *testing.B) { benchGlyph(b, color.NRGBAModel, 256, draw.Over) }
|
||||||
|
func BenchmarkGlyphNRGBA256Src(b *testing.B) { benchGlyph(b, color.NRGBAModel, 256, draw.Src) }
|
||||||
|
|
||||||
|
func BenchmarkGlyphRGBA16Over(b *testing.B) { benchGlyph(b, color.RGBAModel, 16, draw.Over) }
|
||||||
|
func BenchmarkGlyphRGBA16Src(b *testing.B) { benchGlyph(b, color.RGBAModel, 16, draw.Src) }
|
||||||
|
func BenchmarkGlyphRGBA32Over(b *testing.B) { benchGlyph(b, color.RGBAModel, 32, draw.Over) }
|
||||||
|
func BenchmarkGlyphRGBA32Src(b *testing.B) { benchGlyph(b, color.RGBAModel, 32, draw.Src) }
|
||||||
|
func BenchmarkGlyphRGBA64Over(b *testing.B) { benchGlyph(b, color.RGBAModel, 64, draw.Over) }
|
||||||
|
func BenchmarkGlyphRGBA64Src(b *testing.B) { benchGlyph(b, color.RGBAModel, 64, draw.Src) }
|
||||||
|
func BenchmarkGlyphRGBA128Over(b *testing.B) { benchGlyph(b, color.RGBAModel, 128, draw.Over) }
|
||||||
|
func BenchmarkGlyphRGBA128Src(b *testing.B) { benchGlyph(b, color.RGBAModel, 128, draw.Src) }
|
||||||
|
func BenchmarkGlyphRGBA256Over(b *testing.B) { benchGlyph(b, color.RGBAModel, 256, draw.Over) }
|
||||||
|
func BenchmarkGlyphRGBA256Src(b *testing.B) { benchGlyph(b, color.RGBAModel, 256, draw.Src) }
|
||||||
|
|
Loading…
Reference in New Issue
Block a user