draw: add mask fields to Options.
This change only adds the fields, more or less. Follow-up changes will
actually honor the masks.
Change-Id: I81411dc1aac4b3c846dcdf13e2cb0b5cd60fb2b4
Reviewed-on: https://go-review.googlesource.com/8902
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/draw/gen.go b/draw/gen.go
index 345c7fd..5d560df 100644
--- a/draw/gen.go
+++ b/draw/gen.go
@@ -644,7 +644,7 @@
func expnSwitch(op, dType string, expandBoth bool, template string) string {
if op == "" && dType != "anyDType" {
- lines := []string{"switch op {"}
+ lines := []string{"switch o.Op {"}
for _, op = range ops {
lines = append(lines,
fmt.Sprintf("case %s:", op),
@@ -818,51 +818,65 @@
const (
codeRoot = `
func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ 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().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
case Src:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
} else if _, ok := src.(*image.Uniform); ok {
- Draw(dst, dr, src, src.Bounds().Min, op)
+ Draw(dst, dr, src, src.Bounds().Min, o.Op)
} else {
$switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr)
}
}
func (z $receiver) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
+ // TODO: clip adr to o.DstMask.Bounds().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
d2s := invert(s2d)
- // bias is a translation of the mapping from dst co-ordinates to
- // src co-ordinates such that the latter temporarily have
- // non-negative X and Y co-ordinates. This allows us to write
- // int(f) instead of int(math.Floor(f)), since "round to zero" and
- // "round down" are equivalent when f >= 0, but the former is much
- // cheaper. The X-- and Y-- are because the TransformLeaf methods
- // have a "sx -= 0.5" adjustment.
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
@@ -873,15 +887,17 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
case Src:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
} else if u, ok := src.(*image.Uniform); ok {
- transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
} else {
$switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias)
}
@@ -1042,18 +1058,24 @@
z.kernel.Scale(dst, dr, src, sr, opts)
return
}
+
+ var o Options
+ if opts != nil {
+ 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().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
- if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
- Draw(dst, dr, src, src.Bounds().Min, op)
+ if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
+ Draw(dst, dr, src, src.Bounds().Min, o.Op)
return
}
@@ -1072,34 +1094,42 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.SrcMask != nil || !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr)
} else {
$switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr)
}
+ // TODO: honor o.DstMask.
$switchD z.scaleY_$dTypeRN_$op(dst, dr, adr, tmp)
}
func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
+ // TODO: clip adr to o.DstMask.Bounds().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
d2s := invert(s2d)
- // bias is a translation of the mapping from dst co-ordinates to
- // src co-ordinates such that the latter temporarily have
- // non-negative X and Y co-ordinates. This allows us to write
- // int(f) instead of int(math.Floor(f)), since "round to zero" and
- // "round down" are equivalent when f >= 0, but the former is much
- // cheaper. The X-- and Y-- are because the TransformLeaf methods
- // have a "sx -= 0.5" adjustment.
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
@@ -1108,8 +1138,8 @@
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
- if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
- transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
return
}
@@ -1125,8 +1155,10 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case Src:
diff --git a/draw/impl.go b/draw/impl.go
index 5292ced..789b8a3 100644
--- a/draw/impl.go
+++ b/draw/impl.go
@@ -11,29 +11,37 @@
)
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ 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().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
case Src:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
} else if _, ok := src.(*image.Uniform); ok {
- Draw(dst, dr, src, src.Bounds().Min, op)
+ Draw(dst, dr, src, src.Bounds().Min, o.Op)
} else {
- switch op {
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
@@ -88,24 +96,30 @@
}
func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
+ // TODO: clip adr to o.DstMask.Bounds().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
d2s := invert(s2d)
- // bias is a translation of the mapping from dst co-ordinates to
- // src co-ordinates such that the latter temporarily have
- // non-negative X and Y co-ordinates. This allows us to write
- // int(f) instead of int(math.Floor(f)), since "round to zero" and
- // "round down" are equivalent when f >= 0, but the former is much
- // cheaper. The X-- and Y-- are because the TransformLeaf methods
- // have a "sx -= 0.5" adjustment.
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
@@ -116,17 +130,19 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
case Src:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
} else if u, ok := src.(*image.Uniform); ok {
- transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
} else {
- switch op {
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
@@ -934,29 +950,37 @@
}
func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ 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().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
case Src:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
} else if _, ok := src.(*image.Uniform); ok {
- Draw(dst, dr, src, src.Bounds().Min, op)
+ Draw(dst, dr, src, src.Bounds().Min, o.Op)
} else {
- switch op {
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
@@ -1011,24 +1035,30 @@
}
func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
+ // TODO: clip adr to o.DstMask.Bounds().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
+
d2s := invert(s2d)
- // bias is a translation of the mapping from dst co-ordinates to
- // src co-ordinates such that the latter temporarily have
- // non-negative X and Y co-ordinates. This allows us to write
- // int(f) instead of int(math.Floor(f)), since "round to zero" and
- // "round down" are equivalent when f >= 0, but the former is much
- // cheaper. The X-- and Y-- are because the TransformLeaf methods
- // have a "sx -= 0.5" adjustment.
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
@@ -1039,17 +1069,19 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
case Src:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
} else if u, ok := src.(*image.Uniform); ok {
- transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
} else {
- switch op {
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
@@ -4033,18 +4065,24 @@
z.kernel.Scale(dst, dr, src, sr, opts)
return
}
+
+ var o Options
+ if opts != nil {
+ 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().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
- if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
- Draw(dst, dr, src, src.Bounds().Min, op)
+ if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
+ Draw(dst, dr, src, src.Bounds().Min, o.Op)
return
}
@@ -4063,7 +4101,9 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.SrcMask != nil || !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr)
} else {
switch src := src.(type) {
@@ -4091,7 +4131,8 @@
}
}
- switch op {
+ // TODO: honor o.DstMask.
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
@@ -4110,24 +4151,29 @@
}
func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
+ // TODO: clip adr to o.DstMask.Bounds().
if adr.Empty() || sr.Empty() {
return
}
- op := opts.op()
- if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
- op = Src
+ if o.Op == Over && o.SrcMask == nil && opaque(src) {
+ o.Op = Src
}
d2s := invert(s2d)
- // bias is a translation of the mapping from dst co-ordinates to
- // src co-ordinates such that the latter temporarily have
- // non-negative X and Y co-ordinates. This allows us to write
- // int(f) instead of int(math.Floor(f)), since "round to zero" and
- // "round down" are equivalent when f >= 0, but the former is much
- // cheaper. The X-- and Y-- are because the TransformLeaf methods
- // have a "sx -= 0.5" adjustment.
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
@@ -4136,8 +4182,8 @@
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
- if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
- transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
return
}
@@ -4153,15 +4199,17 @@
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
- if !sr.In(src.Bounds()) {
- switch op {
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch o.Op {
case Over:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case Src:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
} else {
- switch op {
+ switch o.Op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
diff --git a/draw/scale.go b/draw/scale.go
index 8207e81..85659cf 100644
--- a/draw/scale.go
+++ b/draw/scale.go
@@ -19,12 +19,13 @@
// the part of the destination image defined by dst and the translation of sr
// so that sr.Min translates to dp.
func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, opts *Options) {
- mask, mp := image.Image(nil), image.Point{}
+ var o Options
if opts != nil {
- // TODO: set mask and mp.
+ o = *opts
}
dr := sr.Add(dp.Sub(sr.Min))
- DrawMask(dst, dr, src, sr.Min, mask, mp, opts.op())
+ // TODO: honor o.DstMask and o.SrcMask.
+ DrawMask(dst, dr, src, sr.Min, nil, image.Point{}, o.Op)
}
// Scaler scales the part of the source image defined by src and sr and writes
@@ -59,15 +60,38 @@
// Op is the compositing operator. The default value is Over.
Op Op
- // TODO: add fields a la
- // https://groups.google.com/forum/#!topic/golang-dev/fgn_xM0aeq4
-}
+ // Masks limit what parts of the dst image are drawn to and what parts of
+ // the src image are drawn from.
+ //
+ // A dst or src mask image having a zero alpha (transparent) pixel value in
+ // the respective coordinate space means that that dst pixel is entirely
+ // unaffected or that src pixel is considered transparent black. A full
+ // alpha (opaque) value means that the dst pixel is maximally affected or
+ // the src pixel contributes maximally. The default values, nil, are
+ // equivalent to fully opaque, infinitely large mask images.
+ //
+ // The DstMask is otherwise known as a clip mask, and its pixels map 1:1 to
+ // the dst image's pixels. DstMaskP in DstMask space corresponds to
+ // image.Point{X:0, Y:0} in dst space. For example, when limiting
+ // repainting to a 'dirty rectangle', use that image.Rectangle and a zero
+ // image.Point as the DstMask and DstMaskP.
+ //
+ // The SrcMask's pixels map 1:1 to the src image's pixels. SrcMaskP in
+ // SrcMask space corresponds to image.Point{X:0, Y:0} in src space. For
+ // example, when drawing font glyphs in a uniform color, use an
+ // *image.Uniform as the src, and use the glyph atlas image and the
+ // per-glyph offset as SrcMask and SrcMaskP:
+ // Copy(dst, dp, image.NewUniform(color), image.Rect(0, 0, glyphWidth, glyphHeight), &Options{
+ // SrcMask: glyphAtlas,
+ // SrcMaskP: glyphOffset,
+ // })
+ DstMask image.Image
+ DstMaskP image.Point
+ SrcMask image.Image
+ SrcMaskP image.Point
+ // TODO: actually implement DstMask and SrcMask.
-func (o *Options) op() Op {
- if o == nil {
- return Over
- }
- return o.Op
+ // TODO: a smooth vs sharp edges option, for arbitrary rotations?
}
// Interpolator is an interpolation algorithm, when dst and src pixels don't
@@ -218,7 +242,7 @@
// Make the sources slice, one source for each column or row, and temporarily
// appropriate its elements' fields so that invTotalWeight is the scaled
- // co-ordinate of the source column or row, and i and j are the lower and
+ // coordinate of the source column or row, and i and j are the lower and
// upper bounds of the range of destination columns or rows affected by the
// source column or row.
n, sources := int32(0), make([]source, dw)