From fc890a65cdeb65bc1a7754491600da952f735208 Mon Sep 17 00:00:00 2001 From: mpl Date: Sat, 5 Sep 2015 01:03:09 +0200 Subject: [PATCH] pkg/images/resize: use golang.org/x/image/draw for YCbCr Later, we should look into using it for more cases. First, to see if we can phase "halving in place" out, and also to see the gains with other image types (non YCbCr). Change-Id: I4b95e2039407f1a91e04cb502674819f17680e02 --- pkg/images/resize/bench_test.go | 10 ----- pkg/images/resize/resize.go | 67 ++------------------------------ pkg/images/resize/resize_test.go | 26 ++----------- 3 files changed, 6 insertions(+), 97 deletions(-) diff --git a/pkg/images/resize/bench_test.go b/pkg/images/resize/bench_test.go index 7726b3640..875290f14 100644 --- a/pkg/images/resize/bench_test.go +++ b/pkg/images/resize/bench_test.go @@ -47,16 +47,6 @@ func BenchmarkHalveRGBA(b *testing.B) { } func BenchmarkResizeYCrCb(b *testing.B) { - withXDraw = false - m := image.NewYCbCr(orig, image.YCbCrSubsampleRatio422) - b.ResetTimer() - for i := 0; i < b.N; i++ { - resize(m) - } -} - -func BenchmarkNewResizeYCrCb(b *testing.B) { - withXDraw = true m := image.NewYCbCr(orig, image.YCbCrSubsampleRatio422) b.ResetTimer() for i := 0; i < b.N; i++ { diff --git a/pkg/images/resize/resize.go b/pkg/images/resize/resize.go index 02c1b206c..d92404083 100644 --- a/pkg/images/resize/resize.go +++ b/pkg/images/resize/resize.go @@ -116,73 +116,12 @@ func average(sum []uint64, w, h int, n uint64) image.Image { return ret } -// TODO(mpl): it will be gone in next commit -// it is just to control whether we use Scale from golang.org/x/image/draw in tests/benchs, -// so we have a good commit history showing it was justified to switch to using it. -var withXDraw = false - // resizeYCbCr returns a scaled copy of the YCbCr image slice r of m. // The returned image has width w and height h. func resizeYCbCr(m *image.YCbCr, r image.Rectangle, w, h int) (image.Image, bool) { - if withXDraw { - dst := image.NewRGBA(image.Rect(0, 0, w, h)) - xdraw.ApproxBiLinear.Scale(dst, dst.Bounds(), m, m.Bounds(), xdraw.Src, nil) - return dst, true - } - var verticalRes int - switch m.SubsampleRatio { - case image.YCbCrSubsampleRatio420: - verticalRes = 2 - case image.YCbCrSubsampleRatio422: - verticalRes = 1 - default: - // TODO(wathiede, mpl): add 410 and 411 support ? - return nil, false - } - ww, hh := uint64(w), uint64(h) - dx, dy := uint64(r.Dx()), uint64(r.Dy()) - // See comment in Resize. - n, sum := dx*dy, make([]uint64, 4*w*h) - for y := r.Min.Y; y < r.Max.Y; y++ { - Y := m.Y[y*m.YStride:] - Cb := m.Cb[y/verticalRes*m.CStride:] - Cr := m.Cr[y/verticalRes*m.CStride:] - for x := r.Min.X; x < r.Max.X; x++ { - // Get the source pixel. - r8, g8, b8 := color.YCbCrToRGB(Y[x], Cb[x/2], Cr[x/2]) - r64 := uint64(r8) - g64 := uint64(g8) - b64 := uint64(b8) - // Spread the source pixel over 1 or more destination rows. - py := uint64(y-r.Min.Y) * hh - for remy := hh; remy > 0; { - qy := dy - (py % dy) - if qy > remy { - qy = remy - } - // Spread the source pixel over 1 or more destination columns. - px := uint64(x-r.Min.X) * ww - index := 4 * ((py/dy)*ww + (px / dx)) - for remx := ww; remx > 0; { - qx := dx - (px % dx) - if qx > remx { - qx = remx - } - qxy := qx * qy - sum[index+0] += r64 * qxy - sum[index+1] += g64 * qxy - sum[index+2] += b64 * qxy - sum[index+3] += 0xFFFF * qxy - index += 4 - px += qx - remx -= qx - } - py += qy - remy -= qy - } - } - } - return average(sum, w, h, n), true + dst := image.NewRGBA(image.Rect(0, 0, w, h)) + xdraw.ApproxBiLinear.Scale(dst, dst.Bounds(), m, m.Bounds(), xdraw.Src, nil) + return dst, true } // resizeRGBA returns a scaled copy of the RGBA image slice r of m. diff --git a/pkg/images/resize/resize_test.go b/pkg/images/resize/resize_test.go index 6264bf0a6..1d4358ad1 100644 --- a/pkg/images/resize/resize_test.go +++ b/pkg/images/resize/resize_test.go @@ -270,41 +270,21 @@ func getFilename(im image.Image, method string) string { return fmt.Sprintf("%s.%s.png", imgType, method) } -func TestCompareOldResizeToHalveInplace(t *testing.T) { - if testing.Short() { - t.Skip("Skipping TestCompareOldResizeToHalveInplace in short mode.") - } - testCompareResizeMethods(t, "customResize", "halveInPlace") -} - -func TestCompareNewResizeToHalveInplace(t *testing.T) { +func TestCompareResizeToHalveInplace(t *testing.T) { if testing.Short() { t.Skip("Skipping TestCompareNewResizeToHalveInplace in short mode.") } - testCompareResizeMethods(t, "xDraw", "halveInPlace") -} - -func TestCompareOldResizeToNewResize(t *testing.T) { - if testing.Short() { - t.Skip("Skipping TestCompareOldResizeToNewResize in short mode.") - } - testCompareResizeMethods(t, "customResize", "xDraw") + testCompareResizeMethods(t, "resize", "halveInPlace") } var resizeMethods = map[string]func(image.Image) image.Image{ - "customResize": func(im image.Image) image.Image { - withXDraw = false + "resize": func(im image.Image) image.Image { s := im.Bounds().Size() return Resize(im, im.Bounds(), s.X/2, s.Y/2) }, "halveInPlace": func(im image.Image) image.Image { return HalveInplace(im) }, - "xDraw": func(im image.Image) image.Image { - withXDraw = true - s := im.Bounds().Size() - return Resize(im, im.Bounds(), s.X/2, s.Y/2) - }, } func testCompareResizeMethods(t *testing.T, method1, method2 string) {