draw: switch on the Op compositing operator.

This change only *prepares* the codegen to handle multiple Ops. The
actual generated code still only supports one Op (Src) and not the other
(Over). A follow-up change will add Over.

This Op switch (an eventual x2 multiplier in the amount of code
generated) should be the last of the codegen LoC multipliers. The dst
and src mask options will be implemented in the slow path fallback.

Change-Id: Iecbcc6fad063e2aac36d78d5380c0a0947c709df
Reviewed-on: https://go-review.googlesource.com/8488
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Nigel Tao 2015-04-07 11:22:25 +10:00
parent c53fa16781
commit b293696c81
4 changed files with 382 additions and 286 deletions

View File

@ -71,6 +71,7 @@ var (
"420",
"440",
}
ops = []string{"Src"} // TODO: add "Over".
)
func init() {
@ -95,17 +96,21 @@ type data struct {
sType string
sratio string
receiver string
op string
}
func gen(w *bytes.Buffer, receiver string, codes ...string) {
expn(w, codeRoot, &data{receiver: receiver})
for _, code := range codes {
for _, t := range dsTypes {
expn(w, code, &data{
dType: t.dType,
sType: t.sType,
receiver: receiver,
})
for _, op := range ops {
expn(w, code, &data{
dType: t.dType,
sType: t.sType,
receiver: receiver,
op: op,
})
}
}
}
}
@ -118,15 +123,21 @@ func genKernel(w *bytes.Buffer) {
})
}
for _, dType := range dTypes {
expn(w, codeKernelScaleLeafY, &data{
dType: dType,
})
for _, op := range ops {
expn(w, codeKernelScaleLeafY, &data{
dType: dType,
op: op,
})
}
}
for _, t := range dsTypes {
expn(w, codeKernelTransformLeaf, &data{
dType: t.dType,
sType: t.sType,
})
for _, op := range ops {
expn(w, codeKernelTransformLeaf, &data{
dType: t.dType,
sType: t.sType,
op: op,
})
}
}
}
@ -192,13 +203,15 @@ func expnDollar(prefix, dollar, suffix string, d *data) string {
return prefix + relName(d.sType) + suffix
case "receiver":
return prefix + d.receiver + suffix
case "op":
return prefix + d.op + suffix
case "switch":
return expnSwitch("", true, suffix)
return expnSwitch("", "", true, suffix)
case "switchD":
return expnSwitch("", false, suffix)
return expnSwitch("", "", false, suffix)
case "switchS":
return expnSwitch("anyDType", false, suffix)
return expnSwitch("", "anyDType", false, suffix)
case "preOuter":
switch d.dType {
@ -568,7 +581,19 @@ func expnDollar(prefix, dollar, suffix string, d *data) string {
return ""
}
func expnSwitch(dType string, expandBoth bool, template string) string {
func expnSwitch(op, dType string, expandBoth bool, template string) string {
if op == "" && dType != "anyDType" {
lines := []string{"switch opts.op() {"}
for _, op = range ops {
lines = append(lines,
fmt.Sprintf("case %s:", op),
expnSwitch(op, dType, expandBoth, template),
)
}
lines = append(lines, "}")
return strings.Join(lines, "\n")
}
switchVar := "dst"
if dType != "" {
switchVar = "src"
@ -588,14 +613,14 @@ func expnSwitch(dType string, expandBoth bool, template string) string {
if dType != "" {
if v == "*image.YCbCr" {
lines = append(lines, expnSwitchYCbCr(dType, template))
lines = append(lines, expnSwitchYCbCr(op, dType, template))
} else {
lines = append(lines, expnLine(template, &data{dType: dType, sType: v}))
lines = append(lines, expnLine(template, &data{dType: dType, sType: v, op: op}))
}
} else if !expandBoth {
lines = append(lines, expnLine(template, &data{dType: v}))
lines = append(lines, expnLine(template, &data{dType: v, op: op}))
} else {
lines = append(lines, expnSwitch(v, false, template))
lines = append(lines, expnSwitch(op, v, false, template))
}
}
@ -603,16 +628,16 @@ func expnSwitch(dType string, expandBoth bool, template string) string {
return strings.Join(lines, "\n")
}
func expnSwitchYCbCr(dType, template string) string {
func expnSwitchYCbCr(op, dType, template string) string {
lines := []string{
"switch src.SubsampleRatio {",
"default:",
expnLine(template, &data{dType: dType, sType: "image.Image"}),
expnLine(template, &data{dType: dType, sType: "image.Image", op: op}),
}
for _, sratio := range subsampleRatios {
lines = append(lines,
fmt.Sprintf("case image.YCbCrSubsampleRatio%s:", sratio),
expnLine(template, &data{dType: dType, sType: "*image.YCbCr", sratio: sratio}),
expnLine(template, &data{dType: dType, sType: "*image.YCbCr", sratio: sratio, op: op}),
)
}
lines = append(lines, "}")
@ -722,12 +747,16 @@ const (
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.scale_Image_Image(dst, dr, adr, src, sr)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
Draw(dst, dr, src, src.Bounds().Min, Src)
Draw(dst, dr, src, src.Bounds().Min, opts.op())
} else {
$switch z.scale_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, src, sr)
$switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr)
}
}
@ -757,18 +786,22 @@ const (
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
} else {
$switch z.transform_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, &d2s, src, sr, bias)
$switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias)
}
}
`
codeNNScaleLeaf = `
func (nnInterpolator) scale_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
func (nnInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -787,7 +820,7 @@ const (
`
codeNNTransformLeaf = `
func (nnInterpolator) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point) {
$preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5
@ -807,7 +840,7 @@ const (
`
codeABLScaleLeaf = `
func (ablInterpolator) scale_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
func (ablInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -861,7 +894,7 @@ const (
`
codeABLTransformLeaf = `
func (ablInterpolator) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point) {
$preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5
@ -928,8 +961,7 @@ const (
}
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts.
Draw(dst, dr, src, src.Bounds().Min, Src)
Draw(dst, dr, src, src.Bounds().Min, opts.op())
return
}
@ -954,7 +986,7 @@ const (
$switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr)
}
$switchD z.scaleY_$dTypeRN(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) {
@ -981,8 +1013,7 @@ const (
adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts.
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
return
}
@ -999,9 +1030,14 @@ const (
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
q.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
switch opts.op() {
case Over:
// TODO: 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 q.transform_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
$switch q.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
}
`
@ -1029,7 +1065,7 @@ const (
`
codeKernelScaleLeafY = `
func (z *kernelScaler) scaleY_$dTypeRN(dst $dType, dr, adr image.Rectangle, tmp [][4]float64) {
func (z *kernelScaler) scaleY_$dTypeRN_$op(dst $dType, dr, adr image.Rectangle, tmp [][4]float64) {
$preOuter
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
$preKernelInner
@ -1050,7 +1086,7 @@ const (
`
codeKernelTransformLeaf = `
func (q *Kernel) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0

View File

@ -20,40 +20,47 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.scale_Image_Image(dst, dr, adr, src, sr)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
Draw(dst, dr, src, src.Bounds().Min, Src)
Draw(dst, dr, src, src.Bounds().Min, opts.op())
} else {
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA(dst, dr, adr, src, sr)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scale_RGBA_RGBA(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440(dst, dr, adr, src, sr)
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image(dst, dr, adr, src, sr)
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
}
}
}
@ -85,46 +92,53 @@ func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
} else {
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA(dst, dr, adr, &d2s, src, sr, bias)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr, bias)
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias)
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
}
}
}
}
func (nnInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -145,7 +159,7 @@ func (nnInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (nnInterpolator) scale_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -168,7 +182,7 @@ func (nnInterpolator) scale_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (nnInterpolator) scale_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -191,7 +205,7 @@ func (nnInterpolator) scale_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (nnInterpolator) scale_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -234,7 +248,7 @@ func (nnInterpolator) scale_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) scale_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -277,7 +291,7 @@ func (nnInterpolator) scale_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) scale_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -320,7 +334,7 @@ func (nnInterpolator) scale_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) scale_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -363,7 +377,7 @@ func (nnInterpolator) scale_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) scale_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -382,7 +396,7 @@ func (nnInterpolator) scale_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (nnInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
func (nnInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
@ -403,7 +417,7 @@ func (nnInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
}
}
func (nnInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -425,7 +439,7 @@ func (nnInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -449,7 +463,7 @@ func (nnInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectan
}
}
func (nnInterpolator) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -473,7 +487,7 @@ func (nnInterpolator) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectang
}
}
func (nnInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -517,7 +531,7 @@ func (nnInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rec
}
}
func (nnInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -561,7 +575,7 @@ func (nnInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rec
}
}
func (nnInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -605,7 +619,7 @@ func (nnInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rec
}
}
func (nnInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -649,7 +663,7 @@ func (nnInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rec
}
}
func (nnInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -669,7 +683,7 @@ func (nnInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectan
}
}
func (nnInterpolator) transform_Image_Image(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
@ -701,40 +715,47 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.scale_Image_Image(dst, dr, adr, src, sr)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
Draw(dst, dr, src, src.Bounds().Min, Src)
Draw(dst, dr, src, src.Bounds().Min, opts.op())
} else {
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA(dst, dr, adr, src, sr)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scale_RGBA_RGBA(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440(dst, dr, adr, src, sr)
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image(dst, dr, adr, src, sr)
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
}
}
}
@ -766,46 +787,53 @@ func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias)
switch opts.op() {
case Over:
// TODO: 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 {
// TODO: get the Op from opts.
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
} else {
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA(dst, dr, adr, &d2s, src, sr, bias)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr, bias)
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias)
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
}
}
}
}
func (ablInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -868,7 +896,7 @@ func (ablInterpolator) scale_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (ablInterpolator) scale_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -963,7 +991,7 @@ func (ablInterpolator) scale_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle
}
}
func (ablInterpolator) scale_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1058,7 +1086,7 @@ func (ablInterpolator) scale_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (ablInterpolator) scale_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1230,7 +1258,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) scale_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1402,7 +1430,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) scale_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1574,7 +1602,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) scale_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1746,7 +1774,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) scale_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1825,7 +1853,7 @@ func (ablInterpolator) scale_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle
}
}
func (ablInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
@ -1906,7 +1934,7 @@ func (ablInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
}
}
func (ablInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -1970,7 +1998,7 @@ func (ablInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2066,7 +2094,7 @@ func (ablInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Recta
}
}
func (ablInterpolator) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2162,7 +2190,7 @@ func (ablInterpolator) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectan
}
}
func (ablInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2335,7 +2363,7 @@ func (ablInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Re
}
}
func (ablInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2508,7 +2536,7 @@ func (ablInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Re
}
}
func (ablInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2681,7 +2709,7 @@ func (ablInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Re
}
}
func (ablInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2854,7 +2882,7 @@ func (ablInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Re
}
}
func (ablInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
@ -2934,7 +2962,7 @@ func (ablInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Recta
}
}
func (ablInterpolator) transform_Image_Image(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
@ -3028,8 +3056,7 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
}
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts.
Draw(dst, dr, src, src.Bounds().Min, Src)
Draw(dst, dr, src, src.Bounds().Min, opts.op())
return
}
@ -3076,11 +3103,14 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
}
}
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA(dst, dr, adr, tmp)
default:
z.scaleY_Image(dst, dr, adr, tmp)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Src(dst, dr, adr, tmp)
default:
z.scaleY_Image_Src(dst, dr, adr, tmp)
}
}
}
@ -3108,8 +3138,7 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts.
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
return
}
@ -3126,37 +3155,45 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
if !sr.In(src.Bounds()) {
q.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
switch opts.op() {
case Over:
// TODO: 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 dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
q.transform_RGBA_Gray(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.NRGBA:
q.transform_RGBA_NRGBA(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
q.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.YCbCr:
switch src.SubsampleRatio {
switch src := src.(type) {
case *image.Gray:
q.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.NRGBA:
q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.RGBA:
q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio444:
q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio422:
q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio420:
q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio440:
q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
default:
q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio444:
q.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio422:
q.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio420:
q.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio440:
q.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
default:
q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
switch src := src.(type) {
default:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
}
}
}
@ -3449,7 +3486,7 @@ func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.
}
}
func (z *kernelScaler) scaleY_RGBA(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64) {
func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64) {
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
@ -3470,7 +3507,7 @@ func (z *kernelScaler) scaleY_RGBA(dst *image.RGBA, dr, adr image.Rectangle, tmp
}
}
func (z *kernelScaler) scaleY_Image(dst Image, dr, adr image.Rectangle, tmp [][4]float64) {
func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
@ -3492,7 +3529,7 @@ func (z *kernelScaler) scaleY_Image(dst Image, dr, adr image.Rectangle, tmp [][4
}
}
func (q *Kernel) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -3591,7 +3628,7 @@ func (q *Kernel) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d
}
}
func (q *Kernel) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -3695,7 +3732,7 @@ func (q *Kernel) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (q *Kernel) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -3799,7 +3836,7 @@ func (q *Kernel) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d
}
}
func (q *Kernel) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -3923,7 +3960,7 @@ func (q *Kernel) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangl
}
}
func (q *Kernel) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -4047,7 +4084,7 @@ func (q *Kernel) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangl
}
}
func (q *Kernel) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -4171,7 +4208,7 @@ func (q *Kernel) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangl
}
}
func (q *Kernel) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -4295,7 +4332,7 @@ func (q *Kernel) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangl
}
}
func (q *Kernel) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@ -4395,7 +4432,7 @@ func (q *Kernel) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle,
}
}
func (q *Kernel) transform_Image_Image(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0

View File

@ -19,12 +19,12 @@ 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, op := image.Image(nil), image.Point{}, Over
mask, mp := image.Image(nil), image.Point{}
if opts != nil {
// TODO: set mask, mp and op.
// TODO: set mask and mp.
}
dr := sr.Add(dp.Sub(sr.Min))
DrawMask(dst, dr, src, sr.Min, mask, mp, op)
DrawMask(dst, dr, src, sr.Min, mask, mp, opts.op())
}
// Scaler scales the part of the source image defined by src and sr and writes
@ -56,10 +56,20 @@ type Transformer interface {
//
// A nil *Options means to use the default (zero) values of each field.
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
}
func (o *Options) op() Op {
if o == nil {
return Over
}
return o.Op
}
// Interpolator is an interpolation algorithm, when dst and src pixels don't
// have a 1:1 correspondence.
//
@ -371,6 +381,7 @@ func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) {
}
func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) {
// TODO: implement op == Over.
switch dst := dst.(type) {
case *image.RGBA:
pr, pg, pb, pa := src.C.RGBA()

View File

@ -59,6 +59,9 @@ func testInterp(t *testing.T, w int, h int, direction, srcFilename string) {
if err != nil {
t.Fatalf("Decode: %v", err)
}
opts := &Options{
Op: Src,
}
testCases := map[string]Interpolator{
"nn": NearestNeighbor,
"ab": ApproxBiLinear,
@ -70,9 +73,9 @@ func testInterp(t *testing.T, w int, h int, direction, srcFilename string) {
got := image.NewRGBA(image.Rect(0, 0, w, h))
if direction == "rotate" {
q.Transform(got, transformMatrix(40, 10), src, src.Bounds(), nil)
q.Transform(got, transformMatrix(40, 10), src, src.Bounds(), opts)
} else {
q.Scale(got, got.Bounds(), src, src.Bounds(), nil)
q.Scale(got, got.Bounds(), src, src.Bounds(), opts)
}
if *genGoldenFiles {
@ -276,7 +279,7 @@ func TestFastPaths(t *testing.T) {
srcGray,
srcNRGBA,
srcRGBA,
srcUniform,
srcUnif,
srcYCbCr,
}
var srcs []image.Image
@ -293,6 +296,9 @@ func TestFastPaths(t *testing.T) {
CatmullRom,
}
blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f})
opts := &Options{
Op: Src,
}
for _, dr := range drs {
for _, src := range srcs {
@ -306,11 +312,11 @@ func TestFastPaths(t *testing.T) {
if transform {
m := transformMatrix(2, 1)
q.Transform(dst0, m, src, sr, nil)
q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, nil)
q.Transform(dst0, m, src, sr, opts)
q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, opts)
} else {
q.Scale(dst0, dr, src, sr, nil)
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, nil)
q.Scale(dst0, dr, src, sr, opts)
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, opts)
}
if !bytes.Equal(dst0.Pix, dst1.Pix) {
@ -349,7 +355,7 @@ func srcRGBA(boundsHint image.Rectangle) (image.Image, error) {
return m, nil
}
func srcUniform(boundsHint image.Rectangle) (image.Image, error) {
func srcUnif(boundsHint image.Rectangle) (image.Image, error) {
return image.NewUniform(color.RGBA64{0x1234, 0x5555, 0x9181, 0xbeef}), nil
}
@ -359,7 +365,7 @@ func srcYCbCr(boundsHint image.Rectangle) (image.Image, error) {
return m, nil
}
func srcYCbCrLarge(boundsHint image.Rectangle) (image.Image, error) {
func srcLarge(boundsHint image.Rectangle) (image.Image, error) {
// 3072 x 2304 is over 7 million pixels at 4:3, comparable to a
// 2015 smart-phone camera's output.
return srcYCbCr(image.Rect(0, 0, 3072, 2304))
@ -379,7 +385,7 @@ func srcTux(boundsHint image.Rectangle) (image.Image, error) {
return src, nil
}
func benchScale(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w int, h int, q Interpolator) {
func benchScale(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil {
@ -392,15 +398,18 @@ func benchScale(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w
}); ok {
scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy())
}
opts := &Options{
Op: op,
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
scaler.Scale(dst, dr, src, sr, nil)
scaler.Scale(dst, dr, src, sr, opts)
}
}
func benchTform(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w int, h int, q Interpolator) {
func benchTform(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil {
@ -408,51 +417,54 @@ func benchTform(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w
}
sr := src.Bounds()
m := transformMatrix(40, 10)
opts := &Options{
Op: op,
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
q.Transform(dst, m, src, sr, nil)
q.Transform(dst, m, src, sr, opts)
}
}
func BenchmarkScaleNNLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, NearestNeighbor) }
func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, ApproxBiLinear) }
func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, BiLinear) }
func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, CatmullRom) }
func BenchmarkScaleNNLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, NearestNeighbor) }
func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, ApproxBiLinear) }
func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, BiLinear) }
func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, CatmullRom) }
func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, srcTux, 120, 80, NearestNeighbor) }
func BenchmarkScaleABDown(b *testing.B) { benchScale(b, srcTux, 120, 80, ApproxBiLinear) }
func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, srcTux, 120, 80, BiLinear) }
func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, srcTux, 120, 80, CatmullRom) }
func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, BiLinear) }
func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, srcTux, 800, 600, NearestNeighbor) }
func BenchmarkScaleABUp(b *testing.B) { benchScale(b, srcTux, 800, 600, ApproxBiLinear) }
func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, srcTux, 800, 600, BiLinear) }
func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, srcTux, 800, 600, CatmullRom) }
func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, BiLinear) }
func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, NearestNeighbor) }
func BenchmarkScaleNNSrcUniform(b *testing.B) { benchScale(b, srcUniform, 200, 150, NearestNeighbor) }
func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkScaleNNSrcUniform(b *testing.B) { benchScale(b, 200, 150, Src, srcUnif, NearestNeighbor) }
func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, srcRGBA, 200, 150, NearestNeighbor) }
func BenchmarkTformNNSrcUniform(b *testing.B) { benchTform(b, srcUniform, 200, 150, NearestNeighbor) }
func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkTformNNSrcUniform(b *testing.B) { benchTform(b, 200, 150, Src, srcUnif, NearestNeighbor) }
func BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, srcGray, 200, 150, ApproxBiLinear) }
func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, srcNRGBA, 200, 150, ApproxBiLinear) }
func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, ApproxBiLinear) }
func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, srcYCbCr, 200, 150, ApproxBiLinear) }
func BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
func BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, srcGray, 200, 150, ApproxBiLinear) }
func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, srcNRGBA, 200, 150, ApproxBiLinear) }
func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, srcRGBA, 200, 150, ApproxBiLinear) }
func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, srcYCbCr, 200, 150, ApproxBiLinear) }
func BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
func BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, srcGray, 200, 150, CatmullRom) }
func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, srcNRGBA, 200, 150, CatmullRom) }
func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, CatmullRom) }
func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, srcYCbCr, 200, 150, CatmullRom) }
func BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, CatmullRom) }
func BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, srcGray, 200, 150, CatmullRom) }
func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, srcNRGBA, 200, 150, CatmullRom) }
func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, srcRGBA, 200, 150, CatmullRom) }
func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, srcYCbCr, 200, 150, CatmullRom) }
func BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, CatmullRom) }