git clone https://git.lucas.co/go_mono.git
draw: distinguish YCbCr fast paths by their chroma subsample ratios.
These code paths aren't actually fast yet. That will be a follow-up
change.
Change-Id: I814992573cc6af422e49d0ddf336003e662897a5
Reviewed-on: https://go-review.googlesource.com/7791
Reviewed-by: Rob Pike <[email protected]>
draw/gen.go | 64 ++-
draw/impl.go | 1495 ++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 1307 insertions(+), 252 deletions(-)
diff --git a/draw/gen.go b/draw/gen.go
index eccafee..a34432f 100644
--- a/draw/gen.go
+++ b/draw/gen.go
@@ -64,8 +64,14 @@ var (
{"*image.RGBA", "image.Image"},
{"Image", "image.Image"},
}
- dTypes, sTypes []string
- sTypesForDType = map[string][]string{}
+ dTypes, sTypes []string
+ sTypesForDType = map[string][]string{}
+ subsampleRatios = []string{
+ "444",
+ "422",
+ "420",
+ "440",
+ }
)
func init() {
@@ -88,6 +94,7 @@ func init() {
type data struct {
dType string
sType string
+ sratio string
receiver string
}
@@ -125,6 +132,15 @@ func genKernel(w *bytes.Buffer) {
}
func expn(w *bytes.Buffer, code string, d *data) {
+ if d.sType == "*image.YCbCr" && d.sratio == "" {
+ for _, sratio := range subsampleRatios {
+ e := *d
+ e.sratio = sratio
+ expn(w, code, &e)
+ }
+ return
+ }
+
for _, line := range strings.Split(code, "\n") {
line = expnLine(line, d)
if line == ";" {
@@ -169,6 +185,8 @@ func expnDollar(prefix, dollar, suffix string, d *data) string {
return prefix + d.dType + suffix
case "dTypeRN":
return prefix + relName(d.dType) + suffix
+ case "sratio":
+ return prefix + d.sratio + suffix
case "sType":
return prefix + d.sType + suffix
case "sTypeRN":
@@ -482,7 +500,11 @@ func expnSwitch(dType string, expandBoth bool, template string) string {
}
if dType != "" {
- lines = append(lines, expnLine(template, &data{dType: dType, sType: v}))
+ if v == "*image.YCbCr" {
+ lines = append(lines, expnSwitchYCbCr(dType, template))
+ } else {
+ lines = append(lines, expnLine(template, &data{dType: dType, sType: v}))
+ }
} else if !expandBoth {
lines = append(lines, expnLine(template, &data{dType: v}))
} else {
@@ -494,6 +516,22 @@ func expnSwitch(dType string, expandBoth bool, template string) string {
return strings.Join(lines, "\n")
}
+func expnSwitchYCbCr(dType, template string) string {
+ lines := []string{
+ "switch src.SubsampleRatio {",
+ "default:",
+ expnLine(template, &data{dType: dType, sType: "image.Image"}),
+ }
+ for _, sratio := range subsampleRatios {
+ lines = append(lines,
+ fmt.Sprintf("case image.YCbCrSubsampleRatio%s:", sratio),
+ expnLine(template, &data{dType: dType, sType: "*image.YCbCr", sratio: sratio}),
+ )
+ }
+ lines = append(lines, "}")
+ return strings.Join(lines, "\n")
+}
+
func split(s, sep string) (string, string) {
if i := strings.Index(s, sep); i >= 0 {
return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
@@ -551,7 +589,7 @@ const (
if !sr.In(src.Bounds()) {
z.scale_Image_Image(dst, dr, adr, src, sr)
} else {
- $switch z.scale_$dTypeRN_$sTypeRN(dst, dr, adr, src, sr)
+ $switch z.scale_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, src, sr)
}
}
@@ -569,13 +607,13 @@ const (
if !sr.In(src.Bounds()) {
z.transform_Image_Image(dst, dr, adr, &d2s, src, sr)
} else {
- $switch z.transform_$dTypeRN_$sTypeRN(dst, dr, adr, &d2s, src, sr)
+ $switch z.transform_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, &d2s, src, sr)
}
}
`
codeNNScaleLeaf = `
- func (nnInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
+ func (nnInterpolator) scale_$dTypeRN_$sTypeRN$sratio(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())
@@ -594,7 +632,7 @@ const (
`
codeNNTransformLeaf = `
- func (nnInterpolator) transform_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle) {
+ func (nnInterpolator) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle) {
$preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5
@@ -615,7 +653,7 @@ const (
`
codeABLScaleLeaf = `
- func (ablInterpolator) scale_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle) {
+ func (ablInterpolator) scale_$dTypeRN_$sTypeRN$sratio(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())
@@ -669,7 +707,7 @@ const (
`
codeABLTransformLeaf = `
- func (ablInterpolator) transform_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle) {
+ func (ablInterpolator) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle) {
$preOuter
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y + int(dy)) + 0.5
@@ -747,7 +785,7 @@ const (
if !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr)
} else {
- $switchS z.scaleX_$sTypeRN(tmp, src, sr)
+ $switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr)
}
$switchD z.scaleY_$dTypeRN(dst, dr, adr, tmp)
@@ -777,13 +815,13 @@ const (
if !sr.In(src.Bounds()) {
q.transform_Image_Image(dst, dr, adr, &d2s, src, sr, xscale, yscale)
} else {
- $switch q.transform_$dTypeRN_$sTypeRN(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ $switch q.transform_$dTypeRN_$sTypeRN$sratio(dst, dr, adr, &d2s, src, sr, xscale, yscale)
}
}
`
codeKernelScaleLeafX = `
- func (z *kernelScaler) scaleX_$sTypeRN(tmp [][4]float64, src $sType, sr image.Rectangle) {
+ func (z *kernelScaler) scaleX_$sTypeRN$sratio(tmp [][4]float64, src $sType, sr image.Rectangle) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
@@ -826,7 +864,7 @@ const (
`
codeKernelTransformLeaf = `
- func (q *Kernel) transform_$dTypeRN_$sTypeRN(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, xscale, yscale float64) {
+ func (q *Kernel) transform_$dTypeRN_$sTypeRN$sratio(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
diff --git a/draw/impl.go b/draw/impl.go
index cc0ed77..02eaabf 100644
--- a/draw/impl.go
+++ b/draw/impl.go
@@ -34,7 +34,18 @@ func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr
case *image.Uniform:
z.scale_RGBA_Uniform(dst, dr, adr, src, sr)
case *image.YCbCr:
- z.scale_RGBA_YCbCr(dst, dr, adr, src, sr)
+ switch src.SubsampleRatio {
+ 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)
+ }
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
}
@@ -73,7 +84,18 @@ func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
case *image.Uniform:
z.transform_RGBA_Uniform(dst, dr, adr, &d2s, src, sr)
case *image.YCbCr:
- z.transform_RGBA_YCbCr(dst, dr, adr, &d2s, src, sr)
+ switch src.SubsampleRatio {
+ default:
+ z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio444:
+ z.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio422:
+ z.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio420:
+ z.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio440:
+ z.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr)
+ }
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr)
}
@@ -168,7 +190,64 @@ func (nnInterpolator) scale_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rectangl
}
}
-func (nnInterpolator) scale_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
+func (nnInterpolator) scale_RGBA_YCbCr444(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())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr422(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())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr420(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())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr440(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())
@@ -317,7 +396,70 @@ func (nnInterpolator) transform_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rect
}
}
-func (nnInterpolator) transform_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+func (nnInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx0 := int(math.Floor(d2s[0]*dxf + d2s[1]*dyf + d2s[2]))
+ sy0 := int(math.Floor(d2s[3]*dxf + d2s[4]*dyf + d2s[5]))
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx0 := int(math.Floor(d2s[0]*dxf + d2s[1]*dyf + d2s[2]))
+ sy0 := int(math.Floor(d2s[3]*dxf + d2s[4]*dyf + d2s[5]))
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx0 := int(math.Floor(d2s[0]*dxf + d2s[1]*dyf + d2s[2]))
+ sy0 := int(math.Floor(d2s[3]*dxf + d2s[4]*dyf + d2s[5]))
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ dst.Pix[d+0] = uint8(uint32(pr) >> 8)
+ dst.Pix[d+1] = uint8(uint32(pg) >> 8)
+ dst.Pix[d+2] = uint8(uint32(pb) >> 8)
+ dst.Pix[d+3] = uint8(uint32(pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
@@ -406,7 +548,18 @@ func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, s
case *image.Uniform:
z.scale_RGBA_Uniform(dst, dr, adr, src, sr)
case *image.YCbCr:
- z.scale_RGBA_YCbCr(dst, dr, adr, src, sr)
+ switch src.SubsampleRatio {
+ 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)
+ }
default:
z.scale_RGBA_Image(dst, dr, adr, src, sr)
}
@@ -445,7 +598,18 @@ func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr
case *image.Uniform:
z.transform_RGBA_Uniform(dst, dr, adr, &d2s, src, sr)
case *image.YCbCr:
- z.transform_RGBA_YCbCr(dst, dr, adr, &d2s, src, sr)
+ switch src.SubsampleRatio {
+ default:
+ z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio444:
+ z.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio422:
+ z.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio420:
+ z.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr)
+ case image.YCbCrSubsampleRatio440:
+ z.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr)
+ }
default:
z.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr)
}
@@ -774,7 +938,7 @@ func (ablInterpolator) scale_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rectang
}
}
-func (ablInterpolator) scale_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
+func (ablInterpolator) scale_RGBA_YCbCr444(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())
@@ -853,7 +1017,7 @@ func (ablInterpolator) scale_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle
}
}
-func (ablInterpolator) scale_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
+func (ablInterpolator) scale_RGBA_YCbCr422(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())
@@ -932,14 +1096,12 @@ 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_RGBA_YCbCr420(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())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
- dstColorRGBA64 := &color.RGBA64{}
- dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (float64(dy)+0.5)*yscale - 0.5
@@ -957,8 +1119,9 @@ func (ablInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
sy0, sy1 = shMinus1, shMinus1
yFrac0, yFrac1 = 1, 0
}
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
- 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 = dx+1, d+4 {
sx := (float64(dx)+0.5)*xscale - 0.5
sx0 := int32(sx)
xFrac0 := sx - float64(sx0)
@@ -1004,94 +1167,332 @@ func (ablInterpolator) scale_Image_Image(dst Image, dr, adr image.Rectangle, src
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
s11a = yFrac1*s10a + yFrac0*s11a
- dstColorRGBA64.R = uint16(s11r)
- dstColorRGBA64.G = uint16(s11g)
- dstColorRGBA64.B = uint16(s11b)
- dstColorRGBA64.A = uint16(s11a)
- dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
}
}
}
-func (ablInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle) {
+func (ablInterpolator) scale_RGBA_YCbCr440(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())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
- dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
- for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
- dxf := float64(dr.Min.X+int(dx)) + 0.5
- // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
- sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
- sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
- if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
- continue
- }
- sx -= 0.5
- sxf := math.Floor(sx)
- xFrac0 := sx - sxf
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
- sx0 := int(sxf)
sx1 := sx0 + 1
- if sx0 < sr.Min.X {
- sx0, sx1 = sr.Min.X, sr.Min.X
+ if sx < 0 {
+ sx0, sx1 = 0, 0
xFrac0, xFrac1 = 0, 1
- } else if sx1 >= sr.Max.X {
- sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
xFrac0, xFrac1 = 1, 0
}
- sy -= 0.5
- syf := math.Floor(sy)
- yFrac0 := sy - syf
- yFrac1 := 1 - yFrac0
- sy0 := int(syf)
- sy1 := sy0 + 1
- if sy0 < sr.Min.Y {
- sy0, sy1 = sr.Min.Y, sr.Min.Y
- yFrac0, yFrac1 = 0, 1
- } else if sy1 >= sr.Max.Y {
- sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
- yFrac0, yFrac1 = 1, 0
- }
-
- s00i := src.PixOffset(sx0, sy0)
- s00ru := uint32(src.Pix[s00i]) * 0x101
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
s00r := float64(s00ru)
- s10i := src.PixOffset(sx1, sy0)
- s10ru := uint32(src.Pix[s10i]) * 0x101
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
s10r = xFrac1*s00r + xFrac0*s10r
- s01i := src.PixOffset(sx0, sy1)
- s01ru := uint32(src.Pix[s01i]) * 0x101
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
s01r := float64(s01ru)
- s11i := src.PixOffset(sx1, sy1)
- s11ru := uint32(src.Pix[s11i]) * 0x101
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
s11r = yFrac1*s10r + yFrac0*s11r
- out := uint8(uint32(s11r) >> 8)
- dst.Pix[d+0] = out
- dst.Pix[d+1] = out
- dst.Pix[d+2] = out
- dst.Pix[d+3] = 0xff
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
}
}
}
-func (ablInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle) {
- for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
- dyf := float64(dr.Min.Y+int(dy)) + 0.5
- d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
- for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
- dxf := float64(dr.Min.X+int(dx)) + 0.5
- // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
- sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
- sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
- if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
- continue
- }
+func (ablInterpolator) scale_RGBA_Image(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())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
- sx -= 0.5
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_Image_Image(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())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dstColorRGBA64.R = uint16(s11r)
+ dstColorRGBA64.G = uint16(s11g)
+ dstColorRGBA64.B = uint16(s11b)
+ dstColorRGBA64.A = uint16(s11a)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sxf := math.Floor(sx)
+ xFrac0 := sx - sxf
+ xFrac1 := 1 - xFrac0
+ sx0 := int(sxf)
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ syf := math.Floor(sy)
+ yFrac0 := sy - syf
+ yFrac1 := 1 - yFrac0
+ sy0 := int(syf)
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := src.PixOffset(sx0, sy0)
+ s00ru := uint32(src.Pix[s00i]) * 0x101
+ s00r := float64(s00ru)
+ s10i := src.PixOffset(sx1, sy0)
+ s10ru := uint32(src.Pix[s10i]) * 0x101
+ s10r := float64(s10ru)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s01i := src.PixOffset(sx0, sy1)
+ s01ru := uint32(src.Pix[s01i]) * 0x101
+ s01r := float64(s01ru)
+ s11i := src.PixOffset(sx1, sy1)
+ s11ru := uint32(src.Pix[s11i]) * 0x101
+ s11r := float64(s11ru)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11r = yFrac1*s10r + yFrac0*s11r
+ out := uint8(uint32(s11r) >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
sxf := math.Floor(sx)
xFrac0 := sx - sxf
xFrac1 := 1 - xFrac0
@@ -1337,7 +1738,7 @@ func (ablInterpolator) transform_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rec
}
}
-func (ablInterpolator) transform_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+func (ablInterpolator) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
@@ -1418,7 +1819,7 @@ func (ablInterpolator) transform_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Recta
}
}
-func (ablInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle) {
+func (ablInterpolator) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
@@ -1499,12 +1900,11 @@ 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) {
- dstColorRGBA64 := &color.RGBA64{}
- dstColor := color.Color(dstColorRGBA64)
+func (ablInterpolator) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
- for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
dxf := float64(dr.Min.X+int(dx)) + 0.5
// TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
@@ -1573,23 +1973,267 @@ func (ablInterpolator) transform_Image_Image(dst Image, dr, adr image.Rectangle,
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
s11a = yFrac1*s10a + yFrac0*s11a
- dstColorRGBA64.R = uint16(s11r)
- dstColorRGBA64.G = uint16(s11g)
- dstColorRGBA64.B = uint16(s11b)
- dstColorRGBA64.A = uint16(s11a)
- dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
}
}
}
-func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
- if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
- z.kernel.Scale(dst, dr, src, sr, opts)
- return
- }
- // adr is the affected destination pixels, relative to dr.Min.
- adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
- if adr.Empty() || sr.Empty() {
+func (ablInterpolator) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sxf := math.Floor(sx)
+ xFrac0 := sx - sxf
+ xFrac1 := 1 - xFrac0
+ sx0 := int(sxf)
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ syf := math.Floor(sy)
+ yFrac0 := sy - syf
+ yFrac1 := 1 - yFrac0
+ sy0 := int(syf)
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_Image(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sxf := math.Floor(sx)
+ xFrac0 := sx - sxf
+ xFrac1 := 1 - xFrac0
+ sx0 := int(sxf)
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ syf := math.Floor(sy)
+ yFrac0 := sy - syf
+ yFrac1 := 1 - yFrac0
+ sy0 := int(syf)
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dst.Pix[d+0] = uint8(uint32(s11r) >> 8)
+ dst.Pix[d+1] = uint8(uint32(s11g) >> 8)
+ dst.Pix[d+2] = uint8(uint32(s11b) >> 8)
+ dst.Pix[d+3] = uint8(uint32(s11a) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_Image_Image(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle) {
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sxf := math.Floor(sx)
+ xFrac0 := sx - sxf
+ xFrac1 := 1 - xFrac0
+ sx0 := int(sxf)
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ syf := math.Floor(sy)
+ yFrac0 := sy - syf
+ yFrac1 := 1 - yFrac0
+ sy0 := int(syf)
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ dstColorRGBA64.R = uint16(s11r)
+ dstColorRGBA64.G = uint16(s11g)
+ dstColorRGBA64.B = uint16(s11b)
+ dstColorRGBA64.A = uint16(s11a)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
+ z.kernel.Scale(dst, dr, src, sr, opts)
+ return
+ }
+ // adr is the affected destination pixels, relative to dr.Min.
+ adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
+ if adr.Empty() || sr.Empty() {
return
}
// Create a temporary buffer:
@@ -1614,7 +2258,18 @@ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr
case *image.Uniform:
z.scaleX_Uniform(tmp, src, sr)
case *image.YCbCr:
- z.scaleX_YCbCr(tmp, src, sr)
+ switch src.SubsampleRatio {
+ default:
+ z.scaleX_Image(tmp, src, sr)
+ case image.YCbCrSubsampleRatio444:
+ z.scaleX_YCbCr444(tmp, src, sr)
+ case image.YCbCrSubsampleRatio422:
+ z.scaleX_YCbCr422(tmp, src, sr)
+ case image.YCbCrSubsampleRatio420:
+ z.scaleX_YCbCr420(tmp, src, sr)
+ case image.YCbCrSubsampleRatio440:
+ z.scaleX_YCbCr440(tmp, src, sr)
+ }
default:
z.scaleX_Image(tmp, src, sr)
}
@@ -1664,7 +2319,18 @@ func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.R
case *image.Uniform:
q.transform_RGBA_Uniform(dst, dr, adr, &d2s, src, sr, xscale, yscale)
case *image.YCbCr:
- q.transform_RGBA_YCbCr(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ switch src.SubsampleRatio {
+ default:
+ q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ case image.YCbCrSubsampleRatio444:
+ q.transform_RGBA_YCbCr444(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ case image.YCbCrSubsampleRatio422:
+ q.transform_RGBA_YCbCr422(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ case image.YCbCrSubsampleRatio420:
+ q.transform_RGBA_YCbCr420(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ case image.YCbCrSubsampleRatio440:
+ q.transform_RGBA_YCbCr440(dst, dr, adr, &d2s, src, sr, xscale, yscale)
+ }
default:
q.transform_RGBA_Image(dst, dr, adr, &d2s, src, sr, xscale, yscale)
}
@@ -1711,157 +2377,511 @@ func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, sr image
pb += float64(pbu) * c.weight
pa += float64(pau) * c.weight
}
- tmp[t] = [4]float64{
- pr * s.invTotalWeightFFFF,
- pg * s.invTotalWeightFFFF,
- pb * s.invTotalWeightFFFF,
- pa * s.invTotalWeightFFFF,
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := src.PixOffset(sr.Min.X+int(c.coord), sr.Min.Y+int(y))
+ pru := uint32(src.Pix[pi+0]) * 0x101
+ pgu := uint32(src.Pix[pi+1]) * 0x101
+ pbu := uint32(src.Pix[pi+2]) * 0x101
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_Uniform(tmp [][4]float64, src *image.Uniform, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_RGBA(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64) {
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ d := dst.PixOffset(dr.Min.X+int(dx), dr.Min.Y+adr.Min.Y)
+ for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+ dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8)
+ dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8)
+ dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8)
+ dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8)
+ d += dst.Stride
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_Image(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++ {
+ for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+ dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
+ dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
+ dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
+ dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, xscale, yscale float64) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr float64
+ for ky := iy; ky < jy; ky++ {
+ yWeight := yWeights[ky-iy]
+ for kx := ix; kx < jx; kx++ {
+ pi := src.PixOffset(kx, ky)
+ pru := uint32(src.Pix[pi]) * 0x101
+ pr += float64(pru) * xWeights[kx-ix] * yWeight
+ }
+ }
+ out := uint8(fffftou(pr) >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, xscale, yscale float64) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
}
- t++
- }
- }
-}
-func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.Rectangle) {
- t := 0
- for y := int32(0); y < z.sh; y++ {
- for _, s := range z.horizontal.sources {
var pr, pg, pb, pa float64
- for _, c := range z.horizontal.contribs[s.i:s.j] {
- pi := src.PixOffset(sr.Min.X+int(c.coord), sr.Min.Y+int(y))
- pru := uint32(src.Pix[pi+0]) * 0x101
- pgu := uint32(src.Pix[pi+1]) * 0x101
- pbu := uint32(src.Pix[pi+2]) * 0x101
- pau := uint32(src.Pix[pi+3]) * 0x101
- pr += float64(pru) * c.weight
- pg += float64(pgu) * c.weight
- pb += float64(pbu) * c.weight
- pa += float64(pau) * c.weight
- }
- tmp[t] = [4]float64{
- pr * s.invTotalWeightFFFF,
- pg * s.invTotalWeightFFFF,
- pb * s.invTotalWeightFFFF,
- pa * s.invTotalWeightFFFF,
+ for ky := iy; ky < jy; ky++ {
+ yWeight := yWeights[ky-iy]
+ for kx := ix; kx < jx; kx++ {
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ pr += float64(pru) * xWeights[kx-ix] * yWeight
+ pg += float64(pgu) * xWeights[kx-ix] * yWeight
+ pb += float64(pbu) * xWeights[kx-ix] * yWeight
+ pa += float64(pau) * xWeights[kx-ix] * yWeight
+ }
}
- t++
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
-func (z *kernelScaler) scaleX_Uniform(tmp [][4]float64, src *image.Uniform, sr image.Rectangle) {
- t := 0
- for y := int32(0); y < z.sh; y++ {
- for _, s := range z.horizontal.sources {
- var pr, pg, pb, pa float64
- for _, c := range z.horizontal.contribs[s.i:s.j] {
- pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
- pr += float64(pru) * c.weight
- pg += float64(pgu) * c.weight
- pb += float64(pbu) * c.weight
- pa += float64(pau) * c.weight
+func (q *Kernel) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, xscale, yscale float64) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ // TODO: change the src origin so that we can say int(f) instead of int(math.Floor(f)).
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(math.Floor(sx)), int(math.Floor(sy))}).In(sr) {
+ continue
}
- tmp[t] = [4]float64{
- pr * s.invTotalWeightFFFF,
- pg * s.invTotalWeightFFFF,
- pb * s.invTotalWeightFFFF,
- pa * s.invTotalWeightFFFF,
+
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
}
- t++
- }
- }
-}
-func (z *kernelScaler) scaleX_YCbCr(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle) {
- t := 0
- for y := int32(0); y < z.sh; y++ {
- for _, s := range z.horizontal.sources {
- var pr, pg, pb, pa float64
- for _, c := range z.horizontal.contribs[s.i:s.j] {
- pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
- pr += float64(pru) * c.weight
- pg += float64(pgu) * c.weight
- pb += float64(pbu) * c.weight
- pa += float64(pau) * c.weight
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
}
- tmp[t] = [4]float64{
- pr * s.invTotalWeightFFFF,
- pg * s.invTotalWeightFFFF,
- pb * s.invTotalWeightFFFF,
- pa * s.invTotalWeightFFFF,
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
}
- t++
- }
- }
-}
-func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle) {
- t := 0
- for y := int32(0); y < z.sh; y++ {
- for _, s := range z.horizontal.sources {
- var pr, pg, pb, pa float64
- for _, c := range z.horizontal.contribs[s.i:s.j] {
- pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
- pr += float64(pru) * c.weight
- pg += float64(pgu) * c.weight
- pb += float64(pbu) * c.weight
- pa += float64(pau) * c.weight
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
}
- tmp[t] = [4]float64{
- pr * s.invTotalWeightFFFF,
- pg * s.invTotalWeightFFFF,
- pb * s.invTotalWeightFFFF,
- pa * s.invTotalWeightFFFF,
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
}
- t++
- }
- }
-}
-func (z *kernelScaler) scaleY_RGBA(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64) {
- for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
- d := dst.PixOffset(dr.Min.X+int(dx), dr.Min.Y+adr.Min.Y)
- for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
- var pr, pg, pb, pa float64
- for _, c := range z.vertical.contribs[s.i:s.j] {
- p := &tmp[c.coord*z.dw+dx]
- pr += p[0] * c.weight
- pg += p[1] * c.weight
- pb += p[2] * c.weight
- pa += p[3] * c.weight
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
}
- dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8)
- dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8)
- dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8)
- dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8)
- d += dst.Stride
- }
- }
-}
-func (z *kernelScaler) scaleY_Image(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++ {
- for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
var pr, pg, pb, pa float64
- for _, c := range z.vertical.contribs[s.i:s.j] {
- p := &tmp[c.coord*z.dw+dx]
- pr += p[0] * c.weight
- pg += p[1] * c.weight
- pb += p[2] * c.weight
- pa += p[3] * c.weight
+ for ky := iy; ky < jy; ky++ {
+ yWeight := yWeights[ky-iy]
+ for kx := ix; kx < jx; kx++ {
+ pi := src.PixOffset(kx, ky)
+ pru := uint32(src.Pix[pi+0]) * 0x101
+ pgu := uint32(src.Pix[pi+1]) * 0x101
+ pbu := uint32(src.Pix[pi+2]) * 0x101
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pr += float64(pru) * xWeights[kx-ix] * yWeight
+ pg += float64(pgu) * xWeights[kx-ix] * yWeight
+ pb += float64(pbu) * xWeights[kx-ix] * yWeight
+ pa += float64(pau) * xWeights[kx-ix] * yWeight
+ }
}
- dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
- dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
- dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
- dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
- dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
-func (q *Kernel) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, xscale, yscale float64) {
+func (q *Kernel) transform_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@@ -1936,25 +2956,26 @@ func (q *Kernel) transform_RGBA_Gray(dst *image.RGBA, dr, adr image.Rectangle, d
yWeights[y] /= totalYWeight
}
- var pr float64
+ var pr, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
yWeight := yWeights[ky-iy]
for kx := ix; kx < jx; kx++ {
- pi := src.PixOffset(kx, ky)
- pru := uint32(src.Pix[pi]) * 0x101
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(pru) * xWeights[kx-ix] * yWeight
+ pg += float64(pgu) * xWeights[kx-ix] * yWeight
+ pb += float64(pbu) * xWeights[kx-ix] * yWeight
+ pa += float64(pau) * xWeights[kx-ix] * yWeight
}
}
- out := uint8(fffftou(pr) >> 8)
- dst.Pix[d+0] = out
- dst.Pix[d+1] = out
- dst.Pix[d+2] = out
- dst.Pix[d+3] = 0xff
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
}
}
}
-func (q *Kernel) transform_RGBA_NRGBA(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, xscale, yscale float64) {
+func (q *Kernel) transform_RGBA_YCbCr444(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@@ -2048,7 +3069,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, xscale, yscale float64) {
+func (q *Kernel) transform_RGBA_YCbCr422(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@@ -2127,11 +3148,7 @@ func (q *Kernel) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d
for ky := iy; ky < jy; ky++ {
yWeight := yWeights[ky-iy]
for kx := ix; kx < jx; kx++ {
- pi := src.PixOffset(kx, ky)
- pru := uint32(src.Pix[pi+0]) * 0x101
- pgu := uint32(src.Pix[pi+1]) * 0x101
- pbu := uint32(src.Pix[pi+2]) * 0x101
- pau := uint32(src.Pix[pi+3]) * 0x101
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(pru) * xWeights[kx-ix] * yWeight
pg += float64(pgu) * xWeights[kx-ix] * yWeight
pb += float64(pbu) * xWeights[kx-ix] * yWeight
@@ -2146,7 +3163,7 @@ func (q *Kernel) transform_RGBA_RGBA(dst *image.RGBA, dr, adr image.Rectangle, d
}
}
-func (q *Kernel) transform_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, xscale, yscale float64) {
+func (q *Kernel) transform_RGBA_YCbCr420(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
@@ -2240,7 +3257,7 @@ func (q *Kernel) transform_RGBA_Uniform(dst *image.RGBA, dr, adr image.Rectangle
}
}
-func (q *Kernel) transform_RGBA_YCbCr(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, xscale, yscale float64) {
+func (q *Kernel) transform_RGBA_YCbCr440(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0