draw: add Transformer and Option types.
Just stub implementations for now. Actual implementations will be follow-up changes. Change-Id: Id21d9042a2073c2dc0f78c9977c4940f000a41df Reviewed-on: https://go-review.googlesource.com/6805 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
7bd522e167
commit
08593990c4
37
draw/gen.go
37
draw/gen.go
|
@ -24,10 +24,15 @@ func main() {
|
||||||
|
|
||||||
w := new(bytes.Buffer)
|
w := new(bytes.Buffer)
|
||||||
w.WriteString("// generated by \"go run gen.go\". DO NOT EDIT.\n\n" +
|
w.WriteString("// generated by \"go run gen.go\". DO NOT EDIT.\n\n" +
|
||||||
"package draw\n\nimport (\n\"image\"\n\"image/color\"\n)\n")
|
"package draw\n\nimport (\n" +
|
||||||
|
"\"image\"\n" +
|
||||||
|
"\"image/color\"\n" +
|
||||||
|
"\n" +
|
||||||
|
"\"golang.org/x/image/math/f64\"\n" +
|
||||||
|
")\n")
|
||||||
|
|
||||||
gen(w, "nnInterpolator", codeNNLeaf)
|
gen(w, "nnInterpolator", codeNNScaleLeaf)
|
||||||
gen(w, "ablInterpolator", codeABLLeaf)
|
gen(w, "ablInterpolator", codeABLScaleLeaf)
|
||||||
genKernel(w)
|
genKernel(w)
|
||||||
|
|
||||||
if *debug {
|
if *debug {
|
||||||
|
@ -99,12 +104,12 @@ func gen(w *bytes.Buffer, receiver string, code string) {
|
||||||
func genKernel(w *bytes.Buffer) {
|
func genKernel(w *bytes.Buffer) {
|
||||||
expn(w, codeKernelRoot, &data{})
|
expn(w, codeKernelRoot, &data{})
|
||||||
for _, sType := range sTypes {
|
for _, sType := range sTypes {
|
||||||
expn(w, codeKernelLeafX, &data{
|
expn(w, codeKernelScaleLeafX, &data{
|
||||||
sType: sType,
|
sType: sType,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, dType := range dTypes {
|
for _, dType := range dTypes {
|
||||||
expn(w, codeKernelLeafY, &data{
|
expn(w, codeKernelScaleLeafY, &data{
|
||||||
dType: dType,
|
dType: dType,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -407,7 +412,7 @@ func relName(s string) string {
|
||||||
|
|
||||||
const (
|
const (
|
||||||
codeRoot = `
|
codeRoot = `
|
||||||
func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
// 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)
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
|
@ -422,9 +427,13 @@ const (
|
||||||
$switch z.scale_$dTypeRN_$sTypeRN(dst, dr, adr, src, sr)
|
$switch z.scale_$dTypeRN_$sTypeRN(dst, dr, adr, src, sr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z $receiver) Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
codeNNLeaf = `
|
codeNNScaleLeaf = `
|
||||||
func (nnInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
|
func (nnInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
|
||||||
dw2 := uint64(dr.Dx()) * 2
|
dw2 := uint64(dr.Dx()) * 2
|
||||||
dh2 := uint64(dr.Dy()) * 2
|
dh2 := uint64(dr.Dy()) * 2
|
||||||
|
@ -443,7 +452,7 @@ const (
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
codeABLLeaf = `
|
codeABLScaleLeaf = `
|
||||||
func (ablInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
|
func (ablInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
|
||||||
sw := int32(sr.Dx())
|
sw := int32(sr.Dx())
|
||||||
sh := int32(sr.Dy())
|
sh := int32(sr.Dy())
|
||||||
|
@ -491,9 +500,9 @@ const (
|
||||||
`
|
`
|
||||||
|
|
||||||
codeKernelRoot = `
|
codeKernelRoot = `
|
||||||
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
|
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
|
||||||
z.kernel.Scale(dst, dr, src, sr)
|
z.kernel.Scale(dst, dr, src, sr, opts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// adr is the affected destination pixels, relative to dr.Min.
|
// adr is the affected destination pixels, relative to dr.Min.
|
||||||
|
@ -518,9 +527,13 @@ const (
|
||||||
|
|
||||||
$switchD z.scaleY_$dTypeRN(dst, dr, adr, tmp)
|
$switchD z.scaleY_$dTypeRN(dst, dr, adr, tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *Kernel) Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
codeKernelLeafX = `
|
codeKernelScaleLeafX = `
|
||||||
func (z *kernelScaler) scaleX_$sTypeRN(tmp [][4]float64, src $sType, sr image.Rectangle) {
|
func (z *kernelScaler) scaleX_$sTypeRN(tmp [][4]float64, src $sType, sr image.Rectangle) {
|
||||||
t := 0
|
t := 0
|
||||||
for y := int32(0); y < z.sh; y++ {
|
for y := int32(0); y < z.sh; y++ {
|
||||||
|
@ -541,7 +554,7 @@ const (
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
codeKernelLeafY = `
|
codeKernelScaleLeafY = `
|
||||||
func (z *kernelScaler) scaleY_$dTypeRN(dst $dType, dr, adr image.Rectangle, tmp [][4]float64) {
|
func (z *kernelScaler) scaleY_$dTypeRN(dst $dType, dr, adr image.Rectangle, tmp [][4]float64) {
|
||||||
$preOuter
|
$preOuter
|
||||||
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
|
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
|
||||||
|
|
22
draw/impl.go
22
draw/impl.go
|
@ -5,9 +5,11 @@ package draw
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
"golang.org/x/image/math/f64"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
// 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)
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
|
@ -44,6 +46,10 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z nnInterpolator) Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (nnInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
|
func (nnInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
|
||||||
dw2 := uint64(dr.Dx()) * 2
|
dw2 := uint64(dr.Dx()) * 2
|
||||||
dh2 := uint64(dr.Dy()) * 2
|
dh2 := uint64(dr.Dy()) * 2
|
||||||
|
@ -189,7 +195,7 @@ func (nnInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
// 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)
|
||||||
if adr.Empty() || sr.Empty() {
|
if adr.Empty() || sr.Empty() {
|
||||||
|
@ -226,6 +232,10 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z ablInterpolator) Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (ablInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
|
func (ablInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
|
||||||
sw := int32(sr.Dx())
|
sw := int32(sr.Dx())
|
||||||
sh := int32(sr.Dy())
|
sh := int32(sr.Dy())
|
||||||
|
@ -754,9 +764,9 @@ func (ablInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
|
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
|
||||||
z.kernel.Scale(dst, dr, src, sr)
|
z.kernel.Scale(dst, dr, src, sr, opts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// adr is the affected destination pixels, relative to dr.Min.
|
// adr is the affected destination pixels, relative to dr.Min.
|
||||||
|
@ -800,6 +810,10 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *Kernel) Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle) {
|
func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle) {
|
||||||
t := 0
|
t := 0
|
||||||
for y := int32(0); y < z.sh; y++ {
|
for y := int32(0); y < z.sh; y++ {
|
||||||
|
|
|
@ -6,12 +6,11 @@
|
||||||
|
|
||||||
package draw
|
package draw
|
||||||
|
|
||||||
// TODO: add an Options type a la
|
|
||||||
// https://groups.google.com/forum/#!topic/golang-dev/fgn_xM0aeq4
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"golang.org/x/image/math/f64"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -19,7 +18,32 @@ import (
|
||||||
//
|
//
|
||||||
// A Scaler is safe to use concurrently.
|
// A Scaler is safe to use concurrently.
|
||||||
type Scaler interface {
|
type Scaler interface {
|
||||||
Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle)
|
Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transformer transforms the part of the source image defined by src and sr
|
||||||
|
// and writes to the part of the destination image defined by dst and the
|
||||||
|
// affine transform m applied to sr.
|
||||||
|
//
|
||||||
|
// For example, if m is the matrix
|
||||||
|
//
|
||||||
|
// m00 m01 m02
|
||||||
|
// m10 m11 m12
|
||||||
|
//
|
||||||
|
// then the src-space point (sx, sy) maps to the dst-space point
|
||||||
|
// (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12).
|
||||||
|
//
|
||||||
|
// A Transformer is safe to use concurrently.
|
||||||
|
type Transformer interface {
|
||||||
|
Transform(dst Image, m *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options are optional parameters to Scale and Transform.
|
||||||
|
//
|
||||||
|
// A nil *Options means to use the default (zero) values of each field.
|
||||||
|
type Options struct {
|
||||||
|
// TODO: add fields a la
|
||||||
|
// https://groups.google.com/forum/#!topic/golang-dev/fgn_xM0aeq4
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolator is an interpolation algorithm, when dst and src pixels don't
|
// Interpolator is an interpolation algorithm, when dst and src pixels don't
|
||||||
|
@ -35,7 +59,7 @@ type Scaler interface {
|
||||||
// non-kernel interpolators, especially when scaling down.
|
// non-kernel interpolators, especially when scaling down.
|
||||||
type Interpolator interface {
|
type Interpolator interface {
|
||||||
Scaler
|
Scaler
|
||||||
// TODO: Transformer
|
Transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kernel is an interpolator that blends source pixels weighted by a symmetric
|
// Kernel is an interpolator that blends source pixels weighted by a symmetric
|
||||||
|
@ -50,8 +74,8 @@ type Kernel struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale implements the Scaler interface.
|
// Scale implements the Scaler interface.
|
||||||
func (k *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle) {
|
func (k *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
|
||||||
k.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy()).Scale(dst, dr, src, sr)
|
k.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy()).Scale(dst, dr, src, sr, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScaler returns a Scaler that is optimized for scaling multiple times with
|
// NewScaler returns a Scaler that is optimized for scaling multiple times with
|
||||||
|
|
|
@ -47,7 +47,7 @@ func testScale(t *testing.T, w int, h int, direction, srcFilename string) {
|
||||||
gotFilename := fmt.Sprintf("../testdata/go-turns-two-%s-%s.png", direction, name)
|
gotFilename := fmt.Sprintf("../testdata/go-turns-two-%s-%s.png", direction, name)
|
||||||
|
|
||||||
got := image.NewRGBA(image.Rect(0, 0, w, h))
|
got := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||||
q.Scale(got, got.Bounds(), src, src.Bounds())
|
q.Scale(got, got.Bounds(), src, src.Bounds(), nil)
|
||||||
if *genScaleFiles {
|
if *genScaleFiles {
|
||||||
g, err := os.Create(gotFilename)
|
g, err := os.Create(gotFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -112,12 +112,12 @@ func TestScaleClipCommute(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale then clip.
|
// Scale then clip.
|
||||||
q.Scale(dst0, outer, src, src.Bounds())
|
q.Scale(dst0, outer, src, src.Bounds(), nil)
|
||||||
dst0 = dst0.SubImage(inner).(*image.RGBA)
|
dst0 = dst0.SubImage(inner).(*image.RGBA)
|
||||||
|
|
||||||
// Clip then scale.
|
// Clip then scale.
|
||||||
dst1 = dst1.SubImage(inner).(*image.RGBA)
|
dst1 = dst1.SubImage(inner).(*image.RGBA)
|
||||||
q.Scale(dst1, outer, src, src.Bounds())
|
q.Scale(dst1, outer, src, src.Bounds(), nil)
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
for y := inner.Min.Y; y < inner.Max.Y; y++ {
|
for y := inner.Min.Y; y < inner.Max.Y; y++ {
|
||||||
|
@ -187,8 +187,8 @@ func TestFastPaths(t *testing.T) {
|
||||||
dst1 := image.NewRGBA(drs[0])
|
dst1 := image.NewRGBA(drs[0])
|
||||||
Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src)
|
Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src)
|
||||||
Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src)
|
Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src)
|
||||||
q.Scale(dst0, dr, src, sr)
|
q.Scale(dst0, dr, src, sr, nil)
|
||||||
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr)
|
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, nil)
|
||||||
if !bytes.Equal(dst0.Pix, dst1.Pix) {
|
if !bytes.Equal(dst0.Pix, dst1.Pix) {
|
||||||
t.Errorf("pix differ for dr=%v, src=%T, sr=%v, q=%T", dr, src, sr, q)
|
t.Errorf("pix differ for dr=%v, src=%T, sr=%v, q=%T", dr, src, sr, q)
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ func benchScale(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
scaler.Scale(dst, dr, src, sr)
|
scaler.Scale(dst, dr, src, sr, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user