golang-image/draw/impl.go

4536 lines
138 KiB
Go
Raw Normal View History

// generated by "go run gen.go". DO NOT EDIT.
package draw
import (
"image"
"image/color"
"math"
"golang.org/x/image/math/f64"
)
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
// adr is the affected destination pixels, relative to dr.Min.
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
if adr.Empty() || sr.Empty() {
return
}
// 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.
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
if !sr.In(src.Bounds()) {
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 {
Draw(dst, dr, src, src.Bounds().Min, opts.op())
} else {
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
}
}
}
}
func (z nnInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
if adr.Empty() || sr.Empty() {
return
}
d2s := invert(s2d)
// bias is a translation of the mapping from dst co-ordinates to
// src co-ordinates such that the latter temporarily have
// non-negative X and Y co-ordinates. 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)
// 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.
if !sr.In(src.Bounds()) {
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 {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
} else {
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
}
}
}
}
func (nnInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pr := uint32(src.Pix[pi]) * 0x101
out := uint8(uint32(pr) >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
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_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
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_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sx := (2*uint64(dx) + 1) * sw / dw2
pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
dw2 := uint64(dr.Dx()) * 2
dh2 := uint64(dr.Dy()) * 2
sw := uint64(sr.Dx())
sh := uint64(sr.Dy())
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sy := (2*uint64(dy) + 1) * sh / dh2
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
sx := (2*uint64(dx) + 1) * sw / dw2
pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
pr := uint32(src.Pix[pi]) * 0x101
out := uint8(uint32(pr) >> 8)
dst.Pix[d+0] = out
dst.Pix[d+1] = out
dst.Pix[d+2] = out
dst.Pix[d+3] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pa := uint32(src.Pix[pi+3]) * 0x101
pr := uint32(src.Pix[pi+0]) * pa / 0xff
pg := uint32(src.Pix[pi+1]) * pa / 0xff
pb := uint32(src.Pix[pi+2]) * pa / 0xff
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_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
pr := uint32(src.Pix[pi+0]) * 0x101
pg := uint32(src.Pix[pi+1]) * 0x101
pb := uint32(src.Pix[pi+2]) * 0x101
pa := uint32(src.Pix[pi+3]) * 0x101
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_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
pj := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
pj := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pr := (pyy1 + 91881*pcr1) >> 8
pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pb := (pyy1 + 116130*pcb1) >> 8
if pr < 0 {
pr = 0
} else if pr > 0xffff {
pr = 0xffff
}
if pg < 0 {
pg = 0
} else if pg > 0xffff {
pg = 0xffff
}
if pb < 0 {
pb = 0
} else if pb > 0xffff {
pb = 0xffff
}
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] = 0xff
}
}
}
func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
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_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
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
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
if !(image.Point{sx0, sy0}).In(sr) {
continue
}
pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
dstColorRGBA64.R = uint16(pr)
dstColorRGBA64.G = uint16(pg)
dstColorRGBA64.B = uint16(pb)
dstColorRGBA64.A = uint16(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}
func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
// adr is the affected destination pixels, relative to dr.Min.
adr := dst.Bounds().Intersect(dr).Sub(dr.Min)
if adr.Empty() || sr.Empty() {
return
}
// 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.
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
if !sr.In(src.Bounds()) {
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 {
Draw(dst, dr, src, src.Bounds().Min, opts.op())
} else {
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr)
case *image.NRGBA:
z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr)
case *image.RGBA:
z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio444:
z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio422:
z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio420:
z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr)
case image.YCbCrSubsampleRatio440:
z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr)
}
default:
z.scale_RGBA_Image_Src(dst, dr, adr, src, sr)
}
default:
switch src := src.(type) {
default:
z.scale_Image_Image_Src(dst, dr, adr, src, sr)
}
}
}
}
}
func (z ablInterpolator) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
if adr.Empty() || sr.Empty() {
return
}
d2s := invert(s2d)
// bias is a translation of the mapping from dst co-ordinates to
// src co-ordinates such that the latter temporarily have
// non-negative X and Y co-ordinates. 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)
// 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.
if !sr.In(src.Bounds()) {
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 {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.op())
} else {
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
switch src := src.(type) {
case *image.Gray:
z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.NRGBA:
z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.RGBA:
z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio444:
z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio422:
z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio420:
z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias)
case image.YCbCrSubsampleRatio440:
z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
default:
switch src := src.(type) {
default:
z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias)
}
}
}
}
}
func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00ru := uint32(src.Pix[s00i]) * 0x101
s00r := float64(s00ru)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10ru := uint32(src.Pix[s10i]) * 0x101
s10r := float64(s10ru)
s10r = xFrac1*s00r + xFrac0*s10r
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01ru := uint32(src.Pix[s01i]) * 0x101
s01r := float64(s01ru)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
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) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
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
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
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_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
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
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
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_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
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++ {
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
}
s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
xscale := float64(sw) / float64(dr.Dx())
swMinus1, shMinus1 := sw-1, sh-1
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle) {
sw := int32(sr.Dx())
sh := int32(sr.Dy())
yscale := float64(sh) / float64(dr.Dy())
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_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
s00ru := uint32(src.Pix[s00i]) * 0x101
s00r := float64(s00ru)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
s10ru := uint32(src.Pix[s10i]) * 0x101
s10r := float64(s10ru)
s10r = xFrac1*s00r + xFrac0*s10r
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
s01ru := uint32(src.Pix[s01i]) * 0x101
s01r := float64(s01ru)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
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_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10au := uint32(src.Pix[s10i+3]) * 0x101
s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
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
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11au := uint32(src.Pix[s11i+3]) * 0x101
s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
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_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s00ru := uint32(src.Pix[s00i+0]) * 0x101
s00gu := uint32(src.Pix[s00i+1]) * 0x101
s00bu := uint32(src.Pix[s00i+2]) * 0x101
s00au := uint32(src.Pix[s00i+3]) * 0x101
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s00a := float64(s00au)
s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s10ru := uint32(src.Pix[s10i+0]) * 0x101
s10gu := uint32(src.Pix[s10i+1]) * 0x101
s10bu := uint32(src.Pix[s10i+2]) * 0x101
s10au := uint32(src.Pix[s10i+3]) * 0x101
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
s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
s01ru := uint32(src.Pix[s01i+0]) * 0x101
s01gu := uint32(src.Pix[s01i+1]) * 0x101
s01bu := uint32(src.Pix[s01i+2]) * 0x101
s01au := uint32(src.Pix[s01i+3]) * 0x101
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s01a := float64(s01au)
s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
s11ru := uint32(src.Pix[s11i+0]) * 0x101
s11gu := uint32(src.Pix[s11i+1]) * 0x101
s11bu := uint32(src.Pix[s11i+2]) * 0x101
s11au := uint32(src.Pix[s11i+3]) * 0x101
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_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s00j := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s10j := (sy0-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s01j := (sy1-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s11j := (sy1-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s00j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s10j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s01j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s11j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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 := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s00yy1 := int(src.Y[s00i])<<16 + 1<<15
s00cb1 := int(src.Cb[s00j]) - 128
s00cr1 := int(src.Cr[s00j]) - 128
s00ru := (s00yy1 + 91881*s00cr1) >> 8
s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
s00bu := (s00yy1 + 116130*s00cb1) >> 8
if s00ru < 0 {
s00ru = 0
} else if s00ru > 0xffff {
s00ru = 0xffff
}
if s00gu < 0 {
s00gu = 0
} else if s00gu > 0xffff {
s00gu = 0xffff
}
if s00bu < 0 {
s00bu = 0
} else if s00bu > 0xffff {
s00bu = 0xffff
}
s00r := float64(s00ru)
s00g := float64(s00gu)
s00b := float64(s00bu)
s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s10yy1 := int(src.Y[s10i])<<16 + 1<<15
s10cb1 := int(src.Cb[s10j]) - 128
s10cr1 := int(src.Cr[s10j]) - 128
s10ru := (s10yy1 + 91881*s10cr1) >> 8
s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
s10bu := (s10yy1 + 116130*s10cb1) >> 8
if s10ru < 0 {
s10ru = 0
} else if s10ru > 0xffff {
s10ru = 0xffff
}
if s10gu < 0 {
s10gu = 0
} else if s10gu > 0xffff {
s10gu = 0xffff
}
if s10bu < 0 {
s10bu = 0
} else if s10bu > 0xffff {
s10bu = 0xffff
}
s10r := float64(s10ru)
s10g := float64(s10gu)
s10b := float64(s10bu)
s10r = xFrac1*s00r + xFrac0*s10r
s10g = xFrac1*s00g + xFrac0*s10g
s10b = xFrac1*s00b + xFrac0*s10b
s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s01yy1 := int(src.Y[s01i])<<16 + 1<<15
s01cb1 := int(src.Cb[s01j]) - 128
s01cr1 := int(src.Cr[s01j]) - 128
s01ru := (s01yy1 + 91881*s01cr1) >> 8
s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
s01bu := (s01yy1 + 116130*s01cb1) >> 8
if s01ru < 0 {
s01ru = 0
} else if s01ru > 0xffff {
s01ru = 0xffff
}
if s01gu < 0 {
s01gu = 0
} else if s01gu > 0xffff {
s01gu = 0xffff
}
if s01bu < 0 {
s01bu = 0
} else if s01bu > 0xffff {
s01bu = 0xffff
}
s01r := float64(s01ru)
s01g := float64(s01gu)
s01b := float64(s01bu)
s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
s11yy1 := int(src.Y[s11i])<<16 + 1<<15
s11cb1 := int(src.Cb[s11j]) - 128
s11cr1 := int(src.Cr[s11j]) - 128
s11ru := (s11yy1 + 91881*s11cr1) >> 8
s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
s11bu := (s11yy1 + 116130*s11cb1) >> 8
if s11ru < 0 {
s11ru = 0
} else if s11ru > 0xffff {
s11ru = 0xffff
}
if s11gu < 0 {
s11gu = 0
} else if s11gu > 0xffff {
s11gu = 0xffff
}
if s11bu < 0 {
s11bu = 0
} else if s11bu > 0xffff {
s11bu = 0xffff
}
s11r := float64(s11ru)
s11g := float64(s11gu)
s11b := float64(s11bu)
s11r = xFrac1*s01r + xFrac0*s11r
s11g = xFrac1*s01g + xFrac0*s11g
s11b = xFrac1*s01b + xFrac0*s11b
s11r = yFrac1*s10r + yFrac0*s11r
s11g = yFrac1*s10g + yFrac0*s11g
s11b = yFrac1*s10b + yFrac0*s11b
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] = 0xff
}
}
}
func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
dyf := float64(dr.Min.Y+int(dy)) + 0.5
d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
sx -= 0.5
sx0 := int(sx)
xFrac0 := sx - float64(sx0)
xFrac1 := 1 - xFrac0
sx0 += bias.X
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
sy0 := int(sy)
yFrac0 := sy - float64(sy0)
yFrac1 := 1 - yFrac0
sy0 += bias.Y
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
}
if _, ok := src.(*image.Uniform); ok && sr.In(src.Bounds()) {
Draw(dst, dr, src, src.Bounds().Min, opts.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.
draw: use a sync.Pool for kernel scaling's temporary buffers. benchmark old ns/op new ns/op delta BenchmarkScaleBLLargeDown 257715146 260286012 +1.00% BenchmarkScaleCRLargeDown 426797448 430078734 +0.77% BenchmarkScaleBLDown 4449939 4222542 -5.11% BenchmarkScaleCRDown 8160446 8010056 -1.84% BenchmarkScaleBLUp 22290312 21044122 -5.59% BenchmarkScaleCRUp 33010722 32021468 -3.00% BenchmarkScaleCRSrcGray 13307961 13020192 -2.16% BenchmarkScaleCRSrcNRGBA 40567431 40801939 +0.58% BenchmarkScaleCRSrcRGBA 39892971 40240558 +0.87% BenchmarkScaleCRSrcYCbCr 59020222 59686699 +1.13% benchmark old allocs new allocs delta BenchmarkScaleBLLargeDown 1 1 +0.00% BenchmarkScaleCRLargeDown 1 2 +100.00% BenchmarkScaleBLDown 1 0 -100.00% BenchmarkScaleCRDown 1 0 -100.00% BenchmarkScaleBLUp 1 0 -100.00% BenchmarkScaleCRUp 1 0 -100.00% BenchmarkScaleCRSrcGray 1 0 -100.00% BenchmarkScaleCRSrcNRGBA 1 0 -100.00% BenchmarkScaleCRSrcRGBA 1 0 -100.00% BenchmarkScaleCRSrcYCbCr 1 0 -100.00% benchmark old bytes new bytes delta BenchmarkScaleBLLargeDown 14745600 2949200 -80.00% BenchmarkScaleCRLargeDown 14745600 4915333 -66.67% BenchmarkScaleBLDown 1523712 5079 -99.67% BenchmarkScaleCRDown 1523712 7619 -99.50% BenchmarkScaleBLUp 10117120 101175 -99.00% BenchmarkScaleCRUp 10117120 202350 -98.00% BenchmarkScaleCRSrcGray 4915200 49156 -99.00% BenchmarkScaleCRSrcNRGBA 4915200 163853 -96.67% BenchmarkScaleCRSrcRGBA 4915200 163853 -96.67% BenchmarkScaleCRSrcYCbCr 4915200 245780 -95.00% The increase in BenchmarkScale??LargeDown number of allocs I think is an accounting error due to the low number of iterations: a low denominator. I suspect that there are one or two extra allocs up front for using the sync.Pool, but one fewer alloc per iteration. The number of iterations is only 5 for BL and 3 for CR, for the default timeout. If I increase the -test.benchtime value to 5s, then the reported average (allocs/op) drop from 2 to 0, so the delta should actually be -100% instead of +0 or +100%. Change-Id: I21d9bb0086bdb25517b6a430e8a21bdf3db026f6 Reviewed-on: https://go-review.googlesource.com/8150 Reviewed-by: Rob Pike <r@golang.org>
2015-03-27 01:21:16 +01:00
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.
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
if !sr.In(src.Bounds()) {
z.scaleX_Image(tmp, src, sr)
} else {
switch src := src.(type) {
case *image.Gray:
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
z.scaleX_Gray(tmp, src, sr)
case *image.NRGBA:
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
z.scaleX_NRGBA(tmp, src, sr)
case *image.RGBA:
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
z.scaleX_RGBA(tmp, src, sr)
case *image.YCbCr:
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:
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
z.scaleX_Image(tmp, src, sr)
}
}
switch opts.op() {
case Src:
switch dst := dst.(type) {
case *image.RGBA:
z.scaleY_RGBA_Src(dst, dr, adr, tmp)
default:
z.scaleY_Image_Src(dst, dr, adr, tmp)
}
}
}
func (q *Kernel) Transform(dst Image, s2d *f64.Aff3, src image.Image, sr image.Rectangle, opts *Options) {
dr := transformRect(s2d, &sr)
// adr is the affected destination pixels.
adr := dst.Bounds().Intersect(dr)
if adr.Empty() || sr.Empty() {
return
}
d2s := invert(s2d)
// bias is a translation of the mapping from dst co-ordinates to
// src co-ordinates such that the latter temporarily have
// non-negative X and Y co-ordinates. 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 && sr.In(src.Bounds()) {
transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, opts.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.
if !sr.In(src.Bounds()) {
switch opts.op() {
case Over:
// TODO: q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case Src:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
} else {
switch opts.op() {
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)
case *image.NRGBA:
q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.RGBA:
q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case *image.YCbCr:
switch src.SubsampleRatio {
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio444:
q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio422:
q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio420:
q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
case image.YCbCrSubsampleRatio440:
q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
default:
q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
default:
switch src := src.(type) {
default:
q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale)
}
}
}
}
}
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle) {
t := 0
for y := int32(0); y < z.sh; y++ {
for _, s := range z.horizontal.sources {
var pr float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pru := uint32(src.Pix[pi]) * 0x101
pr += float64(pru) * c.weight
}
pr *= s.invTotalWeightFFFF
tmp[t] = [4]float64{
pr,
pr,
pr,
1,
}
t++
}
}
}
draw: make Scale an Interpolator method instead of a function. This means that only Kernel values have a NewScaler method, which re-uses computation when scaling multiple images of the same dst and src dimensions. The NearestNeighbor and ApproxBiLinear scalers don't get any pre-computation to re-use, so don't need a NewScaler method just to satisfy the previous Interpolator interface. As a small bonus, NN.Scale and ABL.Scale should no longer allocate on the fast paths. This change is consistent the upcoming Transformer method, so that the Interpolator interface will be type Interpolator interface { Scale(etc) Transform(etc) } instead of type Interpolator interface { NewScaler(etc) Scaler Transform(etc) } I don't have a good theory for why the "func (ablInterpolator) scale_RGBA_RGBA" benchmark is such a dramatic improvement, but at least it's in the right direction. I'm calling the other benchmark changes as noise. benchmark old ns/op new ns/op delta BenchmarkScaleLargeDownNN 3233406 3169060 -1.99% BenchmarkScaleLargeDownAB 12018178 12011348 -0.06% BenchmarkScaleLargeDownBL 1420827834 1409335695 -0.81% BenchmarkScaleLargeDownCR 2820669690 2795534035 -0.89% BenchmarkScaleDownNN 866628 869241 +0.30% BenchmarkScaleDownAB 3175963 3216041 +1.26% BenchmarkScaleDownBL 26639767 26677003 +0.14% BenchmarkScaleDownCR 51720996 51621628 -0.19% BenchmarkScaleUpNN 42758485 43258611 +1.17% BenchmarkScaleUpAB 156693813 156943367 +0.16% BenchmarkScaleUpBL 69511444 69621698 +0.16% BenchmarkScaleUpCR 124530191 124885601 +0.29% BenchmarkScaleSrcGray 8992205 9129321 +1.52% BenchmarkScaleSrcNRGBA 9807837 9894466 +0.88% BenchmarkScaleSrcRGBA 1333188 1104282 -17.17% BenchmarkScaleSrcUniform 1147788 1162488 +1.28% BenchmarkScaleSrcYCbCr 12164542 12305373 +1.16% Change-Id: I2aee6c392eb7437e843260775aed97ce145b4d47 Reviewed-on: https://go-review.googlesource.com/6556 Reviewed-by: Rob Pike <r@golang.org>
2015-03-03 06:54:53 +01:00
func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, 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 := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
pau := uint32(src.Pix[pi+3]) * 0x101
pru := uint32(src.Pix[pi+0]) * pau / 0xff
pgu := uint32(src.Pix[pi+1]) * pau / 0xff
pbu := uint32(src.Pix[pi+2]) * pau / 0xff
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_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 := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
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_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 float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * c.weight
pg += float64(pgu) * c.weight
pb += float64(pbu) * c.weight
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
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 float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * c.weight
pg += float64(pgu) * c.weight
pb += float64(pbu) * c.weight
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
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 float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * c.weight
pg += float64(pgu) * c.weight
pb += float64(pbu) * c.weight
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
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 float64
for _, c := range z.horizontal.contribs[s.i:s.j] {
pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * c.weight
pg += float64(pgu) * c.weight
pb += float64(pbu) * c.weight
}
tmp[t] = [4]float64{
pr * s.invTotalWeightFFFF,
pg * s.invTotalWeightFFFF,
pb * s.invTotalWeightFFFF,
1,
}
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_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64) {
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
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_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64) {
dstColorRGBA64 := &color.RGBA64{}
dstColor := color.Color(dstColorRGBA64)
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
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_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X)
pru := uint32(src.Pix[pi]) * 0x101
pr += float64(pru) * w
}
}
}
}
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_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
pau := uint32(src.Pix[pi+3]) * 0x101
pru := uint32(src.Pix[pi+0]) * pau / 0xff
pgu := uint32(src.Pix[pi+1]) * pau / 0xff
pbu := uint32(src.Pix[pi+2]) * pau / 0xff
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
pa += float64(pau) * w
}
}
}
}
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_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
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) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
pa += float64(pau) * w
}
}
}
}
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_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
}
}
}
}
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] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
}
}
}
}
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] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
}
}
}
}
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] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X)
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
pyy1 := int(src.Y[pi])<<16 + 1<<15
pcb1 := int(src.Cb[pj]) - 128
pcr1 := int(src.Cr[pj]) - 128
pru := (pyy1 + 91881*pcr1) >> 8
pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
pbu := (pyy1 + 116130*pcb1) >> 8
if pru < 0 {
pru = 0
} else if pru > 0xffff {
pru = 0xffff
}
if pgu < 0 {
pgu = 0
} else if pgu > 0xffff {
pgu = 0xffff
}
if pbu < 0 {
pbu = 0
} else if pbu > 0xffff {
pbu = 0xffff
}
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
}
}
}
}
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] = 0xff
}
}
}
func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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 := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
pa += float64(pau) * w
}
}
}
}
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_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64) {
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
xHalfWidth, xKernelArgScale := q.Support, 1.0
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)))
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
sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
continue
}
// TODO: adjust the bias so that we can use int(f) instead
// of math.Floor(f) and math.Ceil(f).
sx += float64(bias.X)
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 += float64(bias.Y)
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, pg, pb, pa float64
for ky := iy; ky < jy; ky++ {
if yWeight := yWeights[ky-iy]; yWeight != 0 {
for kx := ix; kx < jx; kx++ {
if w := xWeights[kx-ix] * yWeight; w != 0 {
pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
pr += float64(pru) * w
pg += float64(pgu) * w
pb += float64(pbu) * w
pa += float64(pau) * w
}
}
}
}
dstColorRGBA64.R = fffftou(pr)
dstColorRGBA64.G = fffftou(pg)
dstColorRGBA64.B = fffftou(pb)
dstColorRGBA64.A = fffftou(pa)
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
}
}
}