draw: implement srcMask.
Change-Id: Ibf710521f466847afaf2d005dc8a2bb817169298
Reviewed-on: https://go-review.googlesource.com/9276
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/draw/example_test.go b/draw/example_test.go
index 948be8d..6a2cacf 100644
--- a/draw/example_test.go
+++ b/draw/example_test.go
@@ -10,6 +10,7 @@
"image/color"
"image/png"
"log"
+ "math"
"os"
"golang.org/x/image/draw"
@@ -27,7 +28,6 @@
log.Fatal(err)
}
- sr := src.Bounds()
dst := image.NewRGBA(image.Rect(0, 0, 400, 300))
green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff})
draw.Copy(dst, image.Point{}, green, dst.Bounds(), nil)
@@ -42,11 +42,11 @@
+2 * sin60, +2 * cos60, 100,
}
- draw.Copy(dst, image.Point{20, 30}, src, sr, nil)
+ draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), nil)
for i, q := range qs {
- q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, sr, nil)
+ q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), nil)
}
- draw.NearestNeighbor.Transform(dst, t, src, sr, nil)
+ draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), nil)
red := image.NewNRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
@@ -75,6 +75,31 @@
q.Transform(dst, t, red, red.Bounds(), opts)
}
+ dr := image.Rect(0, 0, 128, 128)
+ checkerboard := image.NewAlpha(dr)
+ for y := dr.Min.Y; y < dr.Max.Y; y++ {
+ for x := dr.Min.X; x < dr.Max.X; x++ {
+ if (x/20)%2 == (y/20)%2 {
+ checkerboard.SetAlpha(x, y, color.Alpha{0xff})
+ }
+ }
+ }
+ sr := image.Rect(0, 0, 16, 16)
+ circle := image.NewAlpha(sr)
+ for y := sr.Min.Y; y < sr.Max.Y; y++ {
+ for x := sr.Min.X; x < sr.Max.X; x++ {
+ dx, dy := x-10, y-8
+ if d := 32 * math.Sqrt(float64(dx*dx)+float64(dy*dy)); d < 0xff {
+ circle.SetAlpha(x, y, color.Alpha{0xff - uint8(d)})
+ }
+ }
+ }
+ cyan := image.NewUniform(color.RGBA{0x00, 0xff, 0xff, 0xff})
+ draw.NearestNeighbor.Scale(dst, dr, cyan, sr, &draw.Options{
+ DstMask: checkerboard,
+ SrcMask: circle,
+ })
+
// Change false to true to write the resultant image to disk.
if false {
fDst, err := os.Create("out.png")
diff --git a/draw/gen.go b/draw/gen.go
index 33830ac..8cb3e74 100644
--- a/draw/gen.go
+++ b/draw/gen.go
@@ -232,7 +232,11 @@
default:
return ";"
case "Image":
- return "" +
+ s := ""
+ if d.sType == "image.Image" {
+ s = "srcMask, smp := opts.SrcMask, opts.SrcMaskP\n"
+ }
+ return s +
"dstMask, dmp := opts.DstMask, opts.DstMaskP\n" +
"dstColorRGBA64 := &color.RGBA64{}\n" +
"dstColor := color.Color(dstColorRGBA64)"
@@ -246,6 +250,14 @@
return "d := " + pixOffset("dst", "dr.Min.X+adr.Min.X", "dr.Min.Y+int(dy)", "*4", "*dst.Stride")
}
+ case "preKernelOuter":
+ switch d.sType {
+ default:
+ return ";"
+ case "image.Image":
+ return "srcMask, smp := opts.SrcMask, opts.SrcMaskP"
+ }
+
case "preKernelInner":
switch d.dType {
default:
@@ -547,6 +559,22 @@
"%sr%s, %sg%s, %sb%s, %sa%s := src.At(%s, %s).RGBA()\n",
lhs, tmp, lhs, tmp, lhs, tmp, lhs, tmp, args[0], args[1],
)
+ if d.dType == "" || d.dType == "Image" {
+ fmt.Fprintf(buf, ""+
+ "if srcMask != nil {\n"+
+ " _, _, _, ma := srcMask.At(smp.X+%s, smp.Y+%s).RGBA()\n"+
+ " %sr%s = %sr%s * ma / 0xffff\n"+
+ " %sg%s = %sg%s * ma / 0xffff\n"+
+ " %sb%s = %sb%s * ma / 0xffff\n"+
+ " %sa%s = %sa%s * ma / 0xffff\n"+
+ "}\n",
+ args[0], args[1],
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ )
+ }
case "*image.Gray":
fmt.Fprintf(buf, ""+
"%si := %s\n"+
@@ -1218,6 +1246,7 @@
codeKernelScaleLeafX = `
func (z *kernelScaler) scaleX_$sTypeRN$sratio(tmp [][4]float64, src $sType, sr image.Rectangle, opts *Options) {
t := 0
+ $preKernelOuter
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64 $tweakVarP
diff --git a/draw/impl.go b/draw/impl.go
index 69ba309..0bf27e9 100644
--- a/draw/impl.go
+++ b/draw/impl.go
@@ -529,6 +529,7 @@
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -537,6 +538,13 @@
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
@@ -560,6 +568,7 @@
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -568,6 +577,13 @@
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
@@ -930,6 +946,7 @@
}
func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -943,6 +960,13 @@
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
if dstMask != nil {
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
@@ -962,6 +986,7 @@
}
func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -975,6 +1000,13 @@
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
if dstMask != nil {
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
@@ -2522,6 +2554,7 @@
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -2558,11 +2591,25 @@
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
@@ -2572,11 +2619,25 @@
s10b = xFrac1*s00b + xFrac0*s10b
s10a = xFrac1*s00a + xFrac0*s10a
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
@@ -2617,6 +2678,7 @@
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -2653,11 +2715,25 @@
}
s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
@@ -2667,11 +2743,25 @@
s10b = xFrac1*s00b + xFrac0*s10b
s10a = xFrac1*s00a + xFrac0*s10a
s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
@@ -4053,6 +4143,7 @@
}
func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -4095,11 +4186,25 @@
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
@@ -4109,11 +4214,25 @@
s10b = xFrac1*s00b + xFrac0*s10b
s10a = xFrac1*s00a + xFrac0*s10a
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
@@ -4149,6 +4268,7 @@
}
func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -4191,11 +4311,25 @@
}
s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
@@ -4205,11 +4339,25 @@
s10b = xFrac1*s00b + xFrac0*s10b
s10a = xFrac1*s00a + xFrac0*s10a
s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
@@ -4729,11 +4877,19 @@
func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) {
t := 0
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
pr += float64(pru) * c.weight
pg += float64(pgu) * c.weight
pb += float64(pbu) * c.weight
@@ -6224,6 +6380,7 @@
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -6293,6 +6450,13 @@
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
@@ -6351,6 +6515,7 @@
xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
dstMask, dmp := opts.DstMask, opts.DstMaskP
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
@@ -6420,6 +6585,13 @@
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
diff --git a/draw/scale.go b/draw/scale.go
index db67f88..07cd20b 100644
--- a/draw/scale.go
+++ b/draw/scale.go
@@ -25,8 +25,7 @@
}
dr := sr.Add(dp.Sub(sr.Min))
if o.DstMask == nil {
- // TODO: honor o.SrcMask.
- DrawMask(dst, dr, src, sr.Min, nil, image.Point{}, o.Op)
+ DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), o.Op)
} else {
NearestNeighbor.Scale(dst, dr, src, sr, opts)
}
@@ -93,7 +92,6 @@
DstMaskP image.Point
SrcMask image.Image
SrcMaskP image.Point
- // TODO: actually implement SrcMask.
// TODO: a smooth vs sharp edges option, for arbitrary rotations?
}
diff --git a/draw/scale_test.go b/draw/scale_test.go
index 233c70e..d9265a1 100644
--- a/draw/scale_test.go
+++ b/draw/scale_test.go
@@ -316,6 +316,41 @@
}
}
+func TestSrcMask(t *testing.T) {
+ srcMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
+ srcMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})
+ srcMask.SetRGBA(20, 0, color.RGBA{0x00, 0x00, 0x00, 0xff})
+ srcMask.SetRGBA(21, 0, color.RGBA{0x00, 0x00, 0x00, 0x3f})
+ srcMask.SetRGBA(22, 0, color.RGBA{0x00, 0x00, 0x00, 0x00})
+ red := image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff})
+ blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
+ dst := image.NewRGBA(image.Rect(0, 0, 6, 1))
+ Copy(dst, image.Point{}, blue, dst.Bounds(), nil)
+ NearestNeighbor.Scale(dst, dst.Bounds(), red, image.Rect(0, 0, 3, 1), &Options{
+ SrcMask: srcMask,
+ SrcMaskP: image.Point{20, 0},
+ })
+ got := [6]color.RGBA{
+ dst.RGBAAt(0, 0),
+ dst.RGBAAt(1, 0),
+ dst.RGBAAt(2, 0),
+ dst.RGBAAt(3, 0),
+ dst.RGBAAt(4, 0),
+ dst.RGBAAt(5, 0),
+ }
+ want := [6]color.RGBA{
+ {0xff, 0x00, 0x00, 0xff},
+ {0xff, 0x00, 0x00, 0xff},
+ {0x3f, 0x00, 0xc0, 0xff},
+ {0x3f, 0x00, 0xc0, 0xff},
+ {0x00, 0x00, 0xff, 0xff},
+ {0x00, 0x00, 0xff, 0xff},
+ }
+ if got != want {
+ t.Errorf("\ngot %v\nwant %v", got, want)
+ }
+}
+
func TestDstMask(t *testing.T) {
dstMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
dstMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})