in draw/impl.go [4435:4533]
func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
z.kernel.Scale(dst, dr, src, sr, op, opts)
return
}
var o Options
if opts != nil {
o = *opts
}
// 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
}
// Make adr relative to dr.Min.
adr = adr.Sub(dr.Min)
if op == Over && o.SrcMask == nil && opaque(src) {
op = Src
}
if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
Draw(dst, dr, src, src.Bounds().Min, op)
return
}
// Create a temporary buffer:
// scaleX distributes the source image's columns over the temporary image.
// scaleY distributes the temporary image's rows over the destination image.
var tmp [][4]float64
if z.pool.New != nil {
tmpp := z.pool.Get().(*[][4]float64)
defer z.pool.Put(tmpp)
tmp = *tmpp
} else {
tmp = z.makeTmpBuf()
}
// 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.SrcMask != nil || !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr, &o)
} else {
switch src := src.(type) {
case *image.Gray:
z.scaleX_Gray(tmp, src, sr, &o)
case *image.NRGBA:
z.scaleX_NRGBA(tmp, src, sr, &o)
case *image.RGBA:
z.scaleX_RGBA(tmp, src, sr, &o)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scaleX_Image(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio444:
z.scaleX_YCbCr444(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio422:
z.scaleX_YCbCr422(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio420:
z.scaleX_YCbCr420(tmp, src, sr, &o)
case image.YCbCrSubsampleRatio440:
z.scaleX_YCbCr440(tmp, src, sr, &o)
}
default:
z.scaleX_Image(tmp, src, sr, &o)
}
}
if o.DstMask != nil {
switch op {
case Over:
z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
case Src:
z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
}
} else {
switch op {
case Over:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o)
default:
z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
}
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o)
default:
z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
}
}
}
}