in draw/impl.go [4535:4646]
func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
var o Options
if opts != nil {
o = *opts
}
dr := transformRect(&s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
if adr.Empty() || sr.Empty() {
return
}
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
d2s := invert(&s2d)
// bias is a translation of the mapping from dst coordinates to src
// coordinates such that the latter temporarily have non-negative X
// and Y coordinates. This allows us to write int(f) instead of
// int(math.Floor(f)), since "round to zero" and "round down" are
// equivalent when f >= 0, but the former is much cheaper. The X--
// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
// adjustment.
bias := transformRect(&d2s, &adr).Min
bias.X--
bias.Y--
d2s[2] -= float64(bias.X)
d2s[5] -= float64(bias.Y)
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
return
}
xscale := abs(d2s[0])
if s := abs(d2s[1]); xscale < s {
xscale = s
}
yscale := abs(d2s[3])
if s := abs(d2s[4]); yscale < s {
yscale = s
}
// sr is the source pixels. If it extends beyond the src bounds,
// we cannot use the type-specific fast paths, as they access
// the Pix fields directly without bounds checking.
//
// Similarly, the fast paths assume that the masks are nil.
if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
switch op {
case Over:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case Src:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.NRGBA:
q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.RGBA:
q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
default:
q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
q.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.NRGBA:
q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.RGBA:
q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio444:
q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio422:
q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio420:
q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
case image.YCbCrSubsampleRatio440:
q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
}
}
}
}
}