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>
This commit is contained in:
parent
e83a2376af
commit
69a0d8f9aa
112
draw/gen.go
112
draw/gen.go
|
@ -644,7 +644,7 @@ func expnDollar(prefix, dollar, suffix string, d *data) string {
|
|||
|
||||
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 @@ func relName(s string) string {
|
|||
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 @@ const (
|
|||
// 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 @@ const (
|
|||
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 @@ const (
|
|||
// 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 @@ const (
|
|||
// 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 @@ const (
|
|||
// 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:
|
||||
|
|
176
draw/impl.go
176
draw/impl.go
|
@ -11,29 +11,37 @@ import (
|
|||
)
|
||||
|
||||
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) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
}
|
||||
|
||||
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 @@ func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
|
|||
// 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 (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectang
|
|||
}
|
||||
|
||||
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) Scale(dst Image, dr image.Rectangle, src image.Image, s
|
|||
}
|
||||
|
||||
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 @@ func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
|
|||
// 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 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
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 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
// 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 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
}
|
||||
}
|
||||
|
||||
switch op {
|
||||
// TODO: honor o.DstMask.
|
||||
switch o.Op {
|
||||
case Over:
|
||||
switch dst := dst.(type) {
|
||||
case *image.RGBA:
|
||||
|
@ -4110,24 +4151,29 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
|||
}
|
||||
|
||||
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 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
|
|||
// 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 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
|
|||
// 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:
|
||||
|
|
|
@ -19,12 +19,13 @@ import (
|
|||
// 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 @@ type Options struct {
|
|||
// 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 @@ func newDistrib(q *Kernel, dw, sw int32) distrib {
|
|||
|
||||
// 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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user