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 {
|
func expnSwitch(op, dType string, expandBoth bool, template string) string {
|
||||||
if op == "" && dType != "anyDType" {
|
if op == "" && dType != "anyDType" {
|
||||||
lines := []string{"switch op {"}
|
lines := []string{"switch o.Op {"}
|
||||||
for _, op = range ops {
|
for _, op = range ops {
|
||||||
lines = append(lines,
|
lines = append(lines,
|
||||||
fmt.Sprintf("case %s:", op),
|
fmt.Sprintf("case %s:", op),
|
||||||
|
@ -818,51 +818,65 @@ func relName(s string) string {
|
||||||
const (
|
const (
|
||||||
codeRoot = `
|
codeRoot = `
|
||||||
func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
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 is the affected destination pixels, relative to dr.Min.
|
||||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
||||||
case Src:
|
case Src:
|
||||||
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
||||||
}
|
}
|
||||||
} else if _, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
$switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr)
|
$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) {
|
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)
|
dr := transformRect(s2d, &sr)
|
||||||
// adr is the affected destination pixels.
|
// adr is the affected destination pixels.
|
||||||
adr := dst.Bounds().Intersect(dr)
|
adr := dst.Bounds().Intersect(dr)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d2s := invert(s2d)
|
d2s := invert(s2d)
|
||||||
// bias is a translation of the mapping from dst co-ordinates to
|
// bias is a translation of the mapping from dst coordinates to src
|
||||||
// src co-ordinates such that the latter temporarily have
|
// coordinates such that the latter temporarily have non-negative X
|
||||||
// non-negative X and Y co-ordinates. This allows us to write
|
// and Y coordinates. This allows us to write int(f) instead of
|
||||||
// int(f) instead of int(math.Floor(f)), since "round to zero" and
|
// int(math.Floor(f)), since "round to zero" and "round down" are
|
||||||
// "round down" are equivalent when f >= 0, but the former is much
|
// equivalent when f >= 0, but the former is much cheaper. The X--
|
||||||
// cheaper. The X-- and Y-- are because the TransformLeaf methods
|
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
|
||||||
// have a "sx -= 0.5" adjustment.
|
// adjustment.
|
||||||
bias := transformRect(&d2s, &adr).Min
|
bias := transformRect(&d2s, &adr).Min
|
||||||
bias.X--
|
bias.X--
|
||||||
bias.Y--
|
bias.Y--
|
||||||
|
@ -873,15 +887,17 @@ const (
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
case Src:
|
case Src:
|
||||||
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
}
|
}
|
||||||
} else if u, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
$switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias)
|
$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)
|
z.kernel.Scale(dst, dr, src, sr, opts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var o Options
|
||||||
|
if opts != nil {
|
||||||
|
o = *opts
|
||||||
|
}
|
||||||
|
|
||||||
// adr is the affected destination pixels, relative to dr.Min.
|
// adr is the affected destination pixels, relative to dr.Min.
|
||||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
|
if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
|
||||||
Draw(dst, dr, src, src.Bounds().Min, op)
|
Draw(dst, dr, src, src.Bounds().Min, o.Op)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1072,34 +1094,42 @@ const (
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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)
|
z.scaleX_Image(tmp, src, sr)
|
||||||
} else {
|
} else {
|
||||||
$switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr)
|
$switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: honor o.DstMask.
|
||||||
$switchD z.scaleY_$dTypeRN_$op(dst, dr, adr, tmp)
|
$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) {
|
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)
|
dr := transformRect(s2d, &sr)
|
||||||
// adr is the affected destination pixels.
|
// adr is the affected destination pixels.
|
||||||
adr := dst.Bounds().Intersect(dr)
|
adr := dst.Bounds().Intersect(dr)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
d2s := invert(s2d)
|
d2s := invert(s2d)
|
||||||
// bias is a translation of the mapping from dst co-ordinates to
|
// bias is a translation of the mapping from dst coordinates to src
|
||||||
// src co-ordinates such that the latter temporarily have
|
// coordinates such that the latter temporarily have non-negative X
|
||||||
// non-negative X and Y co-ordinates. This allows us to write
|
// and Y coordinates. This allows us to write int(f) instead of
|
||||||
// int(f) instead of int(math.Floor(f)), since "round to zero" and
|
// int(math.Floor(f)), since "round to zero" and "round down" are
|
||||||
// "round down" are equivalent when f >= 0, but the former is much
|
// equivalent when f >= 0, but the former is much cheaper. The X--
|
||||||
// cheaper. The X-- and Y-- are because the TransformLeaf methods
|
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
|
||||||
// have a "sx -= 0.5" adjustment.
|
// adjustment.
|
||||||
bias := transformRect(&d2s, &adr).Min
|
bias := transformRect(&d2s, &adr).Min
|
||||||
bias.X--
|
bias.X--
|
||||||
bias.Y--
|
bias.Y--
|
||||||
|
@ -1108,8 +1138,8 @@ const (
|
||||||
// Make adr relative to dr.Min.
|
// Make adr relative to dr.Min.
|
||||||
adr = adr.Sub(dr.Min)
|
adr = adr.Sub(dr.Min)
|
||||||
|
|
||||||
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
|
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, op)
|
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,8 +1155,10 @@ const (
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
||||||
case Src:
|
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) {
|
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 is the affected destination pixels, relative to dr.Min.
|
||||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
||||||
case Src:
|
case Src:
|
||||||
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
||||||
}
|
}
|
||||||
} else if _, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
switch op {
|
switch o.Op {
|
||||||
case Over:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
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) {
|
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)
|
dr := transformRect(s2d, &sr)
|
||||||
// adr is the affected destination pixels.
|
// adr is the affected destination pixels.
|
||||||
adr := dst.Bounds().Intersect(dr)
|
adr := dst.Bounds().Intersect(dr)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d2s := invert(s2d)
|
d2s := invert(s2d)
|
||||||
// bias is a translation of the mapping from dst co-ordinates to
|
// bias is a translation of the mapping from dst coordinates to src
|
||||||
// src co-ordinates such that the latter temporarily have
|
// coordinates such that the latter temporarily have non-negative X
|
||||||
// non-negative X and Y co-ordinates. This allows us to write
|
// and Y coordinates. This allows us to write int(f) instead of
|
||||||
// int(f) instead of int(math.Floor(f)), since "round to zero" and
|
// int(math.Floor(f)), since "round to zero" and "round down" are
|
||||||
// "round down" are equivalent when f >= 0, but the former is much
|
// equivalent when f >= 0, but the former is much cheaper. The X--
|
||||||
// cheaper. The X-- and Y-- are because the TransformLeaf methods
|
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
|
||||||
// have a "sx -= 0.5" adjustment.
|
// adjustment.
|
||||||
bias := transformRect(&d2s, &adr).Min
|
bias := transformRect(&d2s, &adr).Min
|
||||||
bias.X--
|
bias.X--
|
||||||
bias.Y--
|
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,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
case Src:
|
case Src:
|
||||||
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
}
|
}
|
||||||
} else if u, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
switch op {
|
switch o.Op {
|
||||||
case Over:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
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) {
|
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 is the affected destination pixels, relative to dr.Min.
|
||||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sr is the source pixels. If it extends beyond the src bounds,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Over(dst, dr, adr, src, sr)
|
||||||
case Src:
|
case Src:
|
||||||
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
|
||||||
}
|
}
|
||||||
} else if _, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
switch op {
|
switch o.Op {
|
||||||
case Over:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
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) {
|
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)
|
dr := transformRect(s2d, &sr)
|
||||||
// adr is the affected destination pixels.
|
// adr is the affected destination pixels.
|
||||||
adr := dst.Bounds().Intersect(dr)
|
adr := dst.Bounds().Intersect(dr)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d2s := invert(s2d)
|
d2s := invert(s2d)
|
||||||
// bias is a translation of the mapping from dst co-ordinates to
|
// bias is a translation of the mapping from dst coordinates to src
|
||||||
// src co-ordinates such that the latter temporarily have
|
// coordinates such that the latter temporarily have non-negative X
|
||||||
// non-negative X and Y co-ordinates. This allows us to write
|
// and Y coordinates. This allows us to write int(f) instead of
|
||||||
// int(f) instead of int(math.Floor(f)), since "round to zero" and
|
// int(math.Floor(f)), since "round to zero" and "round down" are
|
||||||
// "round down" are equivalent when f >= 0, but the former is much
|
// equivalent when f >= 0, but the former is much cheaper. The X--
|
||||||
// cheaper. The X-- and Y-- are because the TransformLeaf methods
|
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
|
||||||
// have a "sx -= 0.5" adjustment.
|
// adjustment.
|
||||||
bias := transformRect(&d2s, &adr).Min
|
bias := transformRect(&d2s, &adr).Min
|
||||||
bias.X--
|
bias.X--
|
||||||
bias.Y--
|
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,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
case Src:
|
case Src:
|
||||||
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
|
||||||
}
|
}
|
||||||
} else if u, ok := src.(*image.Uniform); ok {
|
} 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 {
|
} else {
|
||||||
switch op {
|
switch o.Op {
|
||||||
case Over:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
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)
|
z.kernel.Scale(dst, dr, src, sr, opts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var o Options
|
||||||
|
if opts != nil {
|
||||||
|
o = *opts
|
||||||
|
}
|
||||||
|
|
||||||
// adr is the affected destination pixels, relative to dr.Min.
|
// adr is the affected destination pixels, relative to dr.Min.
|
||||||
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
|
if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
|
||||||
Draw(dst, dr, src, src.Bounds().Min, op)
|
Draw(dst, dr, src, src.Bounds().Min, o.Op)
|
||||||
return
|
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,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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)
|
z.scaleX_Image(tmp, src, sr)
|
||||||
} else {
|
} else {
|
||||||
switch src := src.(type) {
|
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:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
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) {
|
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)
|
dr := transformRect(s2d, &sr)
|
||||||
// adr is the affected destination pixels.
|
// adr is the affected destination pixels.
|
||||||
adr := dst.Bounds().Intersect(dr)
|
adr := dst.Bounds().Intersect(dr)
|
||||||
|
// TODO: clip adr to o.DstMask.Bounds().
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
op := opts.op()
|
if o.Op == Over && o.SrcMask == nil && opaque(src) {
|
||||||
if op == Over && opaque(src) { // TODO: also check that opts.SrcMask == nil.
|
o.Op = Src
|
||||||
op = Src
|
|
||||||
}
|
}
|
||||||
d2s := invert(s2d)
|
d2s := invert(s2d)
|
||||||
// bias is a translation of the mapping from dst co-ordinates to
|
// bias is a translation of the mapping from dst coordinates to src
|
||||||
// src co-ordinates such that the latter temporarily have
|
// coordinates such that the latter temporarily have non-negative X
|
||||||
// non-negative X and Y co-ordinates. This allows us to write
|
// and Y coordinates. This allows us to write int(f) instead of
|
||||||
// int(f) instead of int(math.Floor(f)), since "round to zero" and
|
// int(math.Floor(f)), since "round to zero" and "round down" are
|
||||||
// "round down" are equivalent when f >= 0, but the former is much
|
// equivalent when f >= 0, but the former is much cheaper. The X--
|
||||||
// cheaper. The X-- and Y-- are because the TransformLeaf methods
|
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
|
||||||
// have a "sx -= 0.5" adjustment.
|
// adjustment.
|
||||||
bias := transformRect(&d2s, &adr).Min
|
bias := transformRect(&d2s, &adr).Min
|
||||||
bias.X--
|
bias.X--
|
||||||
bias.Y--
|
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.
|
// Make adr relative to dr.Min.
|
||||||
adr = adr.Sub(dr.Min)
|
adr = adr.Sub(dr.Min)
|
||||||
|
|
||||||
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
|
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, op)
|
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, o.Op)
|
||||||
return
|
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,
|
// sr is the source pixels. If it extends beyond the src bounds,
|
||||||
// we cannot use the type-specific fast paths, as they access
|
// we cannot use the type-specific fast paths, as they access
|
||||||
// the Pix fields directly without bounds checking.
|
// 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:
|
case Over:
|
||||||
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
||||||
case Src:
|
case Src:
|
||||||
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch op {
|
switch o.Op {
|
||||||
case Over:
|
case Over:
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *image.RGBA:
|
case *image.RGBA:
|
||||||
|
|
|
@ -19,12 +19,13 @@ import (
|
||||||
// the part of the destination image defined by dst and the translation of sr
|
// the part of the destination image defined by dst and the translation of sr
|
||||||
// so that sr.Min translates to dp.
|
// so that sr.Min translates to dp.
|
||||||
func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, opts *Options) {
|
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 {
|
if opts != nil {
|
||||||
// TODO: set mask and mp.
|
o = *opts
|
||||||
}
|
}
|
||||||
dr := sr.Add(dp.Sub(sr.Min))
|
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
|
// 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 is the compositing operator. The default value is Over.
|
||||||
Op Op
|
Op Op
|
||||||
|
|
||||||
// TODO: add fields a la
|
// Masks limit what parts of the dst image are drawn to and what parts of
|
||||||
// https://groups.google.com/forum/#!topic/golang-dev/fgn_xM0aeq4
|
// 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 {
|
// TODO: a smooth vs sharp edges option, for arbitrary rotations?
|
||||||
if o == nil {
|
|
||||||
return Over
|
|
||||||
}
|
|
||||||
return o.Op
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolator is an interpolation algorithm, when dst and src pixels don't
|
// 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
|
// Make the sources slice, one source for each column or row, and temporarily
|
||||||
// appropriate its elements' fields so that invTotalWeight is the scaled
|
// 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
|
// upper bounds of the range of destination columns or rows affected by the
|
||||||
// source column or row.
|
// source column or row.
|
||||||
n, sources := int32(0), make([]source, dw)
|
n, sources := int32(0), make([]source, dw)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user