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", "420",
"440", "440",
} }
ops = []string{"Src"} // TODO: add "Over".
) )
func init() { func init() {
@ -95,17 +96,21 @@ type data struct {
sType string sType string
sratio string sratio string
receiver string receiver string
op string
} }
func gen(w *bytes.Buffer, receiver string, codes ...string) { func gen(w *bytes.Buffer, receiver string, codes ...string) {
expn(w, codeRoot, &data{receiver: receiver}) expn(w, codeRoot, &data{receiver: receiver})
for _, code := range codes { for _, code := range codes {
for _, t := range dsTypes { for _, t := range dsTypes {
expn(w, code, &data{ for _, op := range ops {
dType: t.dType, expn(w, code, &data{
sType: t.sType, dType: t.dType,
receiver: receiver, sType: t.sType,
}) receiver: receiver,
op: op,
})
}
} }
} }
} }
@ -118,15 +123,21 @@ func genKernel(w *bytes.Buffer) {
}) })
} }
for _, dType := range dTypes { for _, dType := range dTypes {
expn(w, codeKernelScaleLeafY, &data{ for _, op := range ops {
dType: dType, expn(w, codeKernelScaleLeafY, &data{
}) dType: dType,
op: op,
})
}
} }
for _, t := range dsTypes { for _, t := range dsTypes {
expn(w, codeKernelTransformLeaf, &data{ for _, op := range ops {
dType: t.dType, expn(w, codeKernelTransformLeaf, &data{
sType: t.sType, 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 return prefix + relName(d.sType) + suffix
case "receiver": case "receiver":
return prefix + d.receiver + suffix return prefix + d.receiver + suffix
case "op":
return prefix + d.op + suffix
case "switch": case "switch":
return expnSwitch("", true, suffix) return expnSwitch("", "", true, suffix)
case "switchD": case "switchD":
return expnSwitch("", false, suffix) return expnSwitch("", "", false, suffix)
case "switchS": case "switchS":
return expnSwitch("anyDType", false, suffix) return expnSwitch("", "anyDType", false, suffix)
case "preOuter": case "preOuter":
switch d.dType { switch d.dType {
@ -568,7 +581,19 @@ func expnDollar(prefix, dollar, suffix string, d *data) string {
return "" 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" switchVar := "dst"
if dType != "" { if dType != "" {
switchVar = "src" switchVar = "src"
@ -588,14 +613,14 @@ func expnSwitch(dType string, expandBoth bool, template string) string {
if dType != "" { if dType != "" {
if v == "*image.YCbCr" { if v == "*image.YCbCr" {
lines = append(lines, expnSwitchYCbCr(dType, template)) lines = append(lines, expnSwitchYCbCr(op, dType, template))
} else { } 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 { } else if !expandBoth {
lines = append(lines, expnLine(template, &data{dType: v})) lines = append(lines, expnLine(template, &data{dType: v, op: op}))
} else { } 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") return strings.Join(lines, "\n")
} }
func expnSwitchYCbCr(dType, template string) string { func expnSwitchYCbCr(op, dType, template string) string {
lines := []string{ lines := []string{
"switch src.SubsampleRatio {", "switch src.SubsampleRatio {",
"default:", "default:",
expnLine(template, &data{dType: dType, sType: "image.Image"}), expnLine(template, &data{dType: dType, sType: "image.Image", op: op}),
} }
for _, sratio := range subsampleRatios { for _, sratio := range subsampleRatios {
lines = append(lines, lines = append(lines,
fmt.Sprintf("case image.YCbCrSubsampleRatio%s:", sratio), 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, "}") lines = append(lines, "}")
@ -722,12 +747,16 @@ const (
// 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()) { 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 { } else if _, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. Draw(dst, dr, src, src.Bounds().Min, opts.op())
Draw(dst, dr, src, src.Bounds().Min, Src)
} else { } 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 // 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()) { 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 { } else if u, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
} else { } 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 = ` 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) sw := uint64(sr.Dx())
@ -787,7 +820,7 @@ const (
` `
codeNNTransformLeaf = ` 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 $preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5 dyf := float64(dr.Min.Y + int(dy)) + 0.5
@ -807,7 +840,7 @@ const (
` `
codeABLScaleLeaf = ` 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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy()) yscale := float64(sh) / float64(dr.Dy())
@ -861,7 +894,7 @@ const (
` `
codeABLTransformLeaf = ` 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 $preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5 dyf := float64(dr.Min.Y + int(dy)) + 0.5
@ -928,8 +961,7 @@ const (
} }
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) { if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts. Draw(dst, dr, src, src.Bounds().Min, opts.op())
Draw(dst, dr, src, src.Bounds().Min, Src)
return return
} }
@ -954,7 +986,7 @@ const (
$switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr) $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) { 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) adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) { 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, opts.op())
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
return return
} }
@ -999,9 +1030,14 @@ const (
// 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()) { 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 { } 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 = ` 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 $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++ {
$preKernelInner $preKernelInner
@ -1050,7 +1086,7 @@ const (
` `
codeKernelTransformLeaf = ` 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // 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()) { 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 { } else if _, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. Draw(dst, dr, src, src.Bounds().Min, opts.op())
Draw(dst, dr, src, src.Bounds().Min, Src)
} else { } else {
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
switch src := src.(type) { switch dst := dst.(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)
case *image.RGBA: case *image.RGBA:
z.scale_RGBA_RGBA(dst, dr, adr, src, sr) switch src := src.(type) {
case *image.YCbCr: case *image.Gray:
switch src.SubsampleRatio { 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: default:
z.scale_RGBA_Image(dst, dr, adr, src, sr) z.scale_RGBA_Image_Src(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)
} }
default: default:
z.scale_RGBA_Image(dst, dr, adr, src, sr) switch src := src.(type) {
} default:
default: z.scale_Image_Image_Src(dst, dr, adr, src, sr)
switch src := src.(type) { }
default:
z.scale_Image_Image(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 // 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()) { 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 { } else if u, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
} else { } else {
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
switch src := src.(type) { switch dst := dst.(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)
case *image.RGBA: case *image.RGBA:
z.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias) switch src := src.(type) {
case *image.YCbCr: case *image.Gray:
switch src.SubsampleRatio { 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: default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias) z.transform_RGBA_Image_Src(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)
} }
default: default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias) switch src := src.(type) {
} default:
default: z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
switch src := src.(type) { }
default:
z.transform_Image_Image(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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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 dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2 dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx()) 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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{} dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64) dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { 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 // 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()) { 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 { } else if _, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. Draw(dst, dr, src, src.Bounds().Min, opts.op())
Draw(dst, dr, src, src.Bounds().Min, Src)
} else { } else {
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
switch src := src.(type) { switch dst := dst.(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)
case *image.RGBA: case *image.RGBA:
z.scale_RGBA_RGBA(dst, dr, adr, src, sr) switch src := src.(type) {
case *image.YCbCr: case *image.Gray:
switch src.SubsampleRatio { 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: default:
z.scale_RGBA_Image(dst, dr, adr, src, sr) z.scale_RGBA_Image_Src(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)
} }
default: default:
z.scale_RGBA_Image(dst, dr, adr, src, sr) switch src := src.(type) {
} default:
default: z.scale_Image_Image_Src(dst, dr, adr, src, sr)
switch src := src.(type) { }
default:
z.scale_Image_Image(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 // 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()) { 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 { } else if u, ok := src.(*image.Uniform); ok {
// TODO: get the Op from opts. transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
} else { } else {
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
switch src := src.(type) { switch dst := dst.(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)
case *image.RGBA: case *image.RGBA:
z.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias) switch src := src.(type) {
case *image.YCbCr: case *image.Gray:
switch src.SubsampleRatio { 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: default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias) z.transform_RGBA_Image_Src(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)
} }
default: default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias) switch src := src.(type) {
} default:
default: z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
switch src := src.(type) { }
default:
z.transform_Image_Image(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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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()) sw := int32(sr.Dx())
sh := int32(sr.Dy()) sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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++ { for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5 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 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{} dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64) dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { 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()) { if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
// TODO: get the Op from opts. Draw(dst, dr, src, src.Bounds().Min, opts.op())
Draw(dst, dr, src, src.Bounds().Min, Src)
return return
} }
@ -3076,11 +3103,14 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
} }
} }
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
z.scaleY_RGBA(dst, dr, adr, tmp) switch dst := dst.(type) {
default: case *image.RGBA:
z.scaleY_Image(dst, dr, adr, tmp) 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) adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) { 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, opts.op())
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, Src)
return 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 // 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()) { 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 { } else {
switch dst := dst.(type) { switch opts.op() {
case *image.RGBA: case Src:
switch src := src.(type) { switch dst := dst.(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)
case *image.RGBA: case *image.RGBA:
q.transform_RGBA_RGBA(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale) switch src := src.(type) {
case *image.YCbCr: case *image.Gray:
switch src.SubsampleRatio { 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: default:
q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale) q.transform_RGBA_Image_Src(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)
} }
default: default:
q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale) switch src := src.(type) {
} default:
default: q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
switch src := src.(type) { }
default:
q.transform_Image_Image(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++ { 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 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] { 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{} dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64) dstColor := color.Color(dstColorRGBA64)
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // When shrinking, broaden the effective kernel support so that we still
// visit every source pixel. // visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0 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 // 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, op := image.Image(nil), image.Point{}, Over mask, mp := image.Image(nil), image.Point{}
if opts != nil { if opts != nil {
// TODO: set mask, mp and op. // TODO: set mask and mp.
} }
dr := sr.Add(dp.Sub(sr.Min)) 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 // 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. // A nil *Options means to use the default (zero) values of each field.
type Options struct { type Options struct {
// Op is the compositing operator. The default value is Over.
Op Op
// TODO: add fields a la // TODO: add fields a la
// https://groups.google.com/forum/#!topic/golang-dev/fgn_xM0aeq4 // 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 // Interpolator is an interpolation algorithm, when dst and src pixels don't
// have a 1:1 correspondence. // 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) { 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) { switch dst := dst.(type) {
case *image.RGBA: case *image.RGBA:
pr, pg, pb, pa := src.C.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 { if err != nil {
t.Fatalf("Decode: %v", err) t.Fatalf("Decode: %v", err)
} }
opts := &Options{
Op: Src,
}
testCases := map[string]Interpolator{ testCases := map[string]Interpolator{
"nn": NearestNeighbor, "nn": NearestNeighbor,
"ab": ApproxBiLinear, "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)) got := image.NewRGBA(image.Rect(0, 0, w, h))
if direction == "rotate" { if direction == "rotate" {
q.Transform(got, transformMatrix(40, 10), src, src.Bounds(), nil) q.Transform(got, transformMatrix(40, 10), src, src.Bounds(), opts)
} else { } else {
q.Scale(got, got.Bounds(), src, src.Bounds(), nil) q.Scale(got, got.Bounds(), src, src.Bounds(), opts)
} }
if *genGoldenFiles { if *genGoldenFiles {
@ -276,7 +279,7 @@ func TestFastPaths(t *testing.T) {
srcGray, srcGray,
srcNRGBA, srcNRGBA,
srcRGBA, srcRGBA,
srcUniform, srcUnif,
srcYCbCr, srcYCbCr,
} }
var srcs []image.Image var srcs []image.Image
@ -293,6 +296,9 @@ func TestFastPaths(t *testing.T) {
CatmullRom, CatmullRom,
} }
blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f}) blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f})
opts := &Options{
Op: Src,
}
for _, dr := range drs { for _, dr := range drs {
for _, src := range srcs { for _, src := range srcs {
@ -306,11 +312,11 @@ func TestFastPaths(t *testing.T) {
if transform { if transform {
m := transformMatrix(2, 1) m := transformMatrix(2, 1)
q.Transform(dst0, m, src, sr, nil) q.Transform(dst0, m, src, sr, opts)
q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, nil) q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, opts)
} else { } else {
q.Scale(dst0, dr, src, sr, nil) q.Scale(dst0, dr, src, sr, opts)
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, nil) q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, opts)
} }
if !bytes.Equal(dst0.Pix, dst1.Pix) { if !bytes.Equal(dst0.Pix, dst1.Pix) {
@ -349,7 +355,7 @@ func srcRGBA(boundsHint image.Rectangle) (image.Image, error) {
return m, nil 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 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 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 // 3072 x 2304 is over 7 million pixels at 4:3, comparable to a
// 2015 smart-phone camera's output. // 2015 smart-phone camera's output.
return srcYCbCr(image.Rect(0, 0, 3072, 2304)) return srcYCbCr(image.Rect(0, 0, 3072, 2304))
@ -379,7 +385,7 @@ func srcTux(boundsHint image.Rectangle) (image.Image, error) {
return src, nil 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)) dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768)) src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil { if err != nil {
@ -392,15 +398,18 @@ func benchScale(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w
}); ok { }); ok {
scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy()) scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy())
} }
opts := &Options{
Op: op,
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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)) dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768)) src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil { if err != nil {
@ -408,51 +417,54 @@ func benchTform(b *testing.B, srcf func(image.Rectangle) (image.Image, error), w
} }
sr := src.Bounds() sr := src.Bounds()
m := transformMatrix(40, 10) m := transformMatrix(40, 10)
opts := &Options{
Op: op,
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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 BenchmarkScaleNNLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, NearestNeighbor) }
func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, ApproxBiLinear) } func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, ApproxBiLinear) }
func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, BiLinear) } func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, BiLinear) }
func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, srcYCbCrLarge, 200, 150, CatmullRom) } func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, CatmullRom) }
func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, srcTux, 120, 80, NearestNeighbor) } func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABDown(b *testing.B) { benchScale(b, srcTux, 120, 80, ApproxBiLinear) } func BenchmarkScaleABDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, srcTux, 120, 80, BiLinear) } func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, BiLinear) }
func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, srcTux, 120, 80, CatmullRom) } func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, srcTux, 800, 600, NearestNeighbor) } func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABUp(b *testing.B) { benchScale(b, srcTux, 800, 600, ApproxBiLinear) } func BenchmarkScaleABUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, srcTux, 800, 600, BiLinear) } func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, BiLinear) }
func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, srcTux, 800, 600, CatmullRom) } func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, NearestNeighbor) } func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkScaleNNSrcUniform(b *testing.B) { benchScale(b, srcUniform, 200, 150, 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 BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkTformNNSrcUniform(b *testing.B) { benchTform(b, srcUniform, 200, 150, 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 BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, srcNRGBA, 200, 150, ApproxBiLinear) } func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, ApproxBiLinear) } func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, srcYCbCr, 200, 150, 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 BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, srcNRGBA, 200, 150, ApproxBiLinear) } func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, srcRGBA, 200, 150, ApproxBiLinear) } func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, srcYCbCr, 200, 150, 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 BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, srcNRGBA, 200, 150, CatmullRom) } func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, srcRGBA, 200, 150, CatmullRom) } func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, srcYCbCr, 200, 150, 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 BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, srcNRGBA, 200, 150, CatmullRom) } func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, srcRGBA, 200, 150, CatmullRom) } func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, srcYCbCr, 200, 150, CatmullRom) } func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, CatmullRom) }