draw: add a fast path for an image.Rectangle DstMask.
Change-Id: Id5227b9d217b56a342bc1ffc735dababa8a9e3e9 Reviewed-on: https://go-review.googlesource.com/9233 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
b621bdc118
commit
24b0de15f1
20
draw/gen.go
20
draw/gen.go
|
@ -854,12 +854,14 @@ const (
|
|||
o = *opts
|
||||
}
|
||||
|
||||
// adr is the affected destination pixels, relative to dr.Min.
|
||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
// Make adr relative to dr.Min.
|
||||
adr = adr.Sub(dr.Min)
|
||||
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||
o.Op = Src
|
||||
}
|
||||
|
@ -892,7 +894,7 @@ const (
|
|||
dr := transformRect(s2d, &sr)
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
|
@ -1097,12 +1099,14 @@ const (
|
|||
o = *opts
|
||||
}
|
||||
|
||||
// adr is the affected destination pixels, relative to dr.Min.
|
||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
// Make adr relative to dr.Min.
|
||||
adr = adr.Sub(dr.Min)
|
||||
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||
o.Op = Src
|
||||
}
|
||||
|
@ -1156,7 +1160,7 @@ const (
|
|||
dr := transformRect(s2d, &sr)
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
|
|
30
draw/impl.go
30
draw/impl.go
|
@ -16,12 +16,14 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
o = *opts
|
||||
}
|
||||
|
||||
// adr is the affected destination pixels, relative to dr.Min.
|
||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
// Make adr relative to dr.Min.
|
||||
adr = adr.Sub(dr.Min)
|
||||
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||
o.Op = Src
|
||||
}
|
||||
|
@ -104,7 +106,7 @@ func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
|
|||
dr := transformRect(s2d, &sr)
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
|
@ -1003,12 +1005,14 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s
|
|||
o = *opts
|
||||
}
|
||||
|
||||
// adr is the affected destination pixels, relative to dr.Min.
|
||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
// Make adr relative to dr.Min.
|
||||
adr = adr.Sub(dr.Min)
|
||||
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||
o.Op = Src
|
||||
}
|
||||
|
@ -1091,7 +1095,7 @@ func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
|
|||
dr := transformRect(s2d, &sr)
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
|
@ -4257,12 +4261,14 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
o = *opts
|
||||
}
|
||||
|
||||
// adr is the affected destination pixels, relative to dr.Min.
|
||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
// Make adr relative to dr.Min.
|
||||
adr = adr.Sub(dr.Min)
|
||||
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||
o.Op = Src
|
||||
}
|
||||
|
@ -4353,7 +4359,7 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
|
|||
dr := transformRect(s2d, &sr)
|
||||
// adr is the affected destination pixels.
|
||||
adr := dst.Bounds().Intersect(dr)
|
||||
// TODO: clip adr to o.DstMask.Bounds().
|
||||
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
|
||||
if adr.Empty() || sr.Empty() {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -408,6 +408,17 @@ func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) {
|
|||
return dr
|
||||
}
|
||||
|
||||
func clipAffectedDestRect(adr image.Rectangle, dstMask image.Image, dstMaskP image.Point) (image.Rectangle, image.Image) {
|
||||
if dstMask == nil {
|
||||
return adr, nil
|
||||
}
|
||||
if r, ok := dstMask.(image.Rectangle); ok {
|
||||
return adr.Intersect(r.Sub(dstMaskP)), nil
|
||||
}
|
||||
// TODO: clip to dstMask.Bounds() if the color model implies that out-of-bounds means 0 alpha?
|
||||
return adr, dstMask
|
||||
}
|
||||
|
||||
func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) {
|
||||
switch op {
|
||||
case Over:
|
||||
|
|
|
@ -373,30 +373,55 @@ func TestRectDstMask(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
mk := func(q Transformer, dstMask image.Image) *image.RGBA {
|
||||
mk := func(q Transformer, dstMask image.Image, dstMaskP image.Point) *image.RGBA {
|
||||
m := image.NewRGBA(bounds)
|
||||
Copy(m, bounds.Min, dstOutside, bounds, nil)
|
||||
q.Transform(m, m00, src, src.Bounds(), &Options{DstMask: dstMask})
|
||||
q.Transform(m, m00, src, src.Bounds(), &Options{
|
||||
DstMask: dstMask,
|
||||
DstMaskP: dstMaskP,
|
||||
})
|
||||
return m
|
||||
}
|
||||
|
||||
rect := image.Rect(20, 10, 30, 40)
|
||||
qs := []Interpolator{
|
||||
NearestNeighbor,
|
||||
ApproxBiLinear,
|
||||
CatmullRom,
|
||||
}
|
||||
dstMaskPs := []image.Point{
|
||||
{0, 0},
|
||||
{5, 7},
|
||||
{-3, 0},
|
||||
}
|
||||
rect := image.Rect(10, 10, 30, 40)
|
||||
for _, q := range qs {
|
||||
dstInside := mk(q, nil)
|
||||
dst := mk(q, rect)
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
which := dstOutside
|
||||
if (image.Point{x, y}).In(rect) {
|
||||
which = dstInside
|
||||
for _, dstMaskP := range dstMaskPs {
|
||||
dstInside := mk(q, nil, image.Point{})
|
||||
for _, wrap := range []bool{false, true} {
|
||||
dstMask := image.Image(rect)
|
||||
if wrap {
|
||||
dstMask = srcWrapper{dstMask}
|
||||
}
|
||||
if got, want := dst.RGBAAt(x, y), which.RGBAAt(x, y); got != want {
|
||||
t.Errorf("x=%3d y=%3d: got %v, want %v", x, y, got, want)
|
||||
dst := mk(q, dstMask, dstMaskP)
|
||||
|
||||
nError := 0
|
||||
loop:
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
which := dstOutside
|
||||
if (image.Point{x, y}).Add(dstMaskP).In(rect) {
|
||||
which = dstInside
|
||||
}
|
||||
if got, want := dst.RGBAAt(x, y), which.RGBAAt(x, y); got != want {
|
||||
if nError == 10 {
|
||||
t.Errorf("q=%T dmp=%v wrap=%v: ...and more errors", q, dstMaskP, wrap)
|
||||
break loop
|
||||
}
|
||||
nError++
|
||||
t.Errorf("q=%T dmp=%v wrap=%v: x=%3d y=%3d: got %v, want %v",
|
||||
q, dstMaskP, wrap, x, y, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user