From 8ed4ff0a338111c9375ebfdc4d397e95293d0010 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 10 Apr 2015 19:58:30 +1000 Subject: [PATCH] draw: implement the Over operator. Change-Id: Id207b8f2fa5233175285800477e60f111ef4af63 Reviewed-on: https://go-review.googlesource.com/8744 Reviewed-by: Rob Pike --- draw/example_test.go | 30 +++ draw/gen.go | 339 ++++++++++++++++++---------- draw/impl.go | 228 +++++++++++-------- draw/scale.go | 128 +++++++---- draw/scale_test.go | 132 ++++++++--- testdata/go-turns-two-rotate-ab.png | Bin 8761 -> 7654 bytes testdata/go-turns-two-rotate-bl.png | Bin 8764 -> 7653 bytes testdata/go-turns-two-rotate-cr.png | Bin 9000 -> 7808 bytes testdata/go-turns-two-rotate-nn.png | Bin 4993 -> 4915 bytes testdata/tux-rotate-ab.png | Bin 0 -> 3237 bytes testdata/tux-rotate-bl.png | Bin 0 -> 3751 bytes testdata/tux-rotate-cr.png | Bin 0 -> 3753 bytes testdata/tux-rotate-nn.png | Bin 0 -> 3055 bytes 13 files changed, 572 insertions(+), 285 deletions(-) create mode 100644 testdata/tux-rotate-ab.png create mode 100644 testdata/tux-rotate-bl.png create mode 100644 testdata/tux-rotate-cr.png create mode 100644 testdata/tux-rotate-nn.png diff --git a/draw/example_test.go b/draw/example_test.go index f8545ad..948be8d 100644 --- a/draw/example_test.go +++ b/draw/example_test.go @@ -7,6 +7,7 @@ package draw_test import ( "fmt" "image" + "image/color" "image/png" "log" "os" @@ -28,6 +29,8 @@ func ExampleDraw() { sr := src.Bounds() dst := image.NewRGBA(image.Rect(0, 0, 400, 300)) + green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff}) + draw.Copy(dst, image.Point{}, green, dst.Bounds(), nil) qs := []draw.Interpolator{ draw.NearestNeighbor, draw.ApproxBiLinear, @@ -45,6 +48,33 @@ func ExampleDraw() { } draw.NearestNeighbor.Transform(dst, t, src, sr, nil) + red := image.NewNRGBA(image.Rect(0, 0, 16, 16)) + for y := 0; y < 16; y++ { + for x := 0; x < 16; x++ { + red.SetNRGBA(x, y, color.NRGBA{ + R: uint8(x * 0x11), + A: uint8(y * 0x11), + }) + } + } + red.SetNRGBA(0, 0, color.NRGBA{0xff, 0xff, 0x00, 0xff}) + red.SetNRGBA(15, 15, color.NRGBA{0xff, 0xff, 0x00, 0xff}) + + ops := []draw.Op{ + draw.Over, + draw.Src, + } + for i, op := range ops { + q, opts := draw.NearestNeighbor, &draw.Options{Op: op} + dr := image.Rect(120+10*i, 150+60*i, 170+10*i, 200+60*i) + q.Scale(dst, dr, red, red.Bounds(), opts) + t := &f64.Aff3{ + +cos60, -sin60, float64(190 + 10*i), + +sin60, +cos60, float64(140 + 50*i), + } + q.Transform(dst, t, red, red.Bounds(), opts) + } + // Change false to true to write the resultant image to disk. if false { fDst, err := os.Create("out.png") diff --git a/draw/gen.go b/draw/gen.go index 3295c2d..048434c 100644 --- a/draw/gen.go +++ b/draw/gen.go @@ -305,161 +305,256 @@ func expnDollar(prefix, dollar, suffix string, d *data) string { ` case "outputu": - // TODO: handle op==Over, not just op==Src. args, _ := splitArgs(suffix) if len(args) != 3 { return "" } - switch d.dType { - default: - log.Fatalf("bad dType %q", d.dType) - case "Image": - switch d.sType { + + switch d.op { + case "Over": + switch d.dType { default: + log.Fatalf("bad dType %q", d.dType) + case "Image": return fmt.Sprintf(""+ - "dstColorRGBA64.R = uint16(%sr)\n"+ - "dstColorRGBA64.G = uint16(%sg)\n"+ - "dstColorRGBA64.B = uint16(%sb)\n"+ - "dstColorRGBA64.A = uint16(%sa)\n"+ + "qr, qg, qb, qa := dst.At(%s, %s).RGBA()\n"+ + "%sa1 := 0xffff - uint32(%sa)\n"+ + "dstColorRGBA64.R = uint16(qr*%sa1/0xffff + uint32(%sr))\n"+ + "dstColorRGBA64.G = uint16(qg*%sa1/0xffff + uint32(%sg))\n"+ + "dstColorRGBA64.B = uint16(qb*%sa1/0xffff + uint32(%sb))\n"+ + "dstColorRGBA64.A = uint16(qa*%sa1/0xffff + uint32(%sa))\n"+ "dst.Set(%s, %s, dstColor)", - args[2], args[2], args[2], args[2], + args[0], args[1], + args[2], args[2], + args[2], args[2], + args[2], args[2], + args[2], args[2], + args[2], args[2], args[0], args[1], ) - case "*image.Gray": + case "*image.RGBA": return fmt.Sprintf(""+ - "out := uint16(%sr)\n"+ - "dstColorRGBA64.R = out\n"+ - "dstColorRGBA64.G = out\n"+ - "dstColorRGBA64.B = out\n"+ - "dstColorRGBA64.A = 0xffff\n"+ - "dst.Set(%s, %s, dstColor)", - args[2], - args[0], args[1], - ) - case "*image.YCbCr": - return fmt.Sprintf(""+ - "dstColorRGBA64.R = uint16(%sr)\n"+ - "dstColorRGBA64.G = uint16(%sg)\n"+ - "dstColorRGBA64.B = uint16(%sb)\n"+ - "dstColorRGBA64.A = 0xffff\n"+ - "dst.Set(%s, %s, dstColor)", - args[2], args[2], args[2], - args[0], args[1], + "%sa1 := (0xffff - uint32(%sa)) * 0x101\n"+ + "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*%sa1/0xffff + uint32(%sr)) >> 8)\n"+ + "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*%sa1/0xffff + uint32(%sg)) >> 8)\n"+ + "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*%sa1/0xffff + uint32(%sb)) >> 8)\n"+ + "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*%sa1/0xffff + uint32(%sa)) >> 8)", + args[2], args[2], + args[2], args[2], + args[2], args[2], + args[2], args[2], + args[2], args[2], ) } - case "*image.RGBA": - switch d.sType { + + case "Src": + switch d.dType { default: - return fmt.Sprintf(""+ - "dst.Pix[d+0] = uint8(uint32(%sr) >> 8)\n"+ - "dst.Pix[d+1] = uint8(uint32(%sg) >> 8)\n"+ - "dst.Pix[d+2] = uint8(uint32(%sb) >> 8)\n"+ - "dst.Pix[d+3] = uint8(uint32(%sa) >> 8)", - args[2], args[2], args[2], args[2], - ) - case "*image.Gray": - return fmt.Sprintf(""+ - "out := uint8(uint32(%sr) >> 8)\n"+ - "dst.Pix[d+0] = out\n"+ - "dst.Pix[d+1] = out\n"+ - "dst.Pix[d+2] = out\n"+ - "dst.Pix[d+3] = 0xff", - args[2], - ) - case "*image.YCbCr": - return fmt.Sprintf(""+ - "dst.Pix[d+0] = uint8(uint32(%sr) >> 8)\n"+ - "dst.Pix[d+1] = uint8(uint32(%sg) >> 8)\n"+ - "dst.Pix[d+2] = uint8(uint32(%sb) >> 8)\n"+ - "dst.Pix[d+3] = 0xff", - args[2], args[2], args[2], - ) + log.Fatalf("bad dType %q", d.dType) + case "Image": + switch d.sType { + default: + return fmt.Sprintf(""+ + "dstColorRGBA64.R = uint16(%sr)\n"+ + "dstColorRGBA64.G = uint16(%sg)\n"+ + "dstColorRGBA64.B = uint16(%sb)\n"+ + "dstColorRGBA64.A = uint16(%sa)\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], args[2], args[2], args[2], + args[0], args[1], + ) + case "*image.Gray": + return fmt.Sprintf(""+ + "out := uint16(%sr)\n"+ + "dstColorRGBA64.R = out\n"+ + "dstColorRGBA64.G = out\n"+ + "dstColorRGBA64.B = out\n"+ + "dstColorRGBA64.A = 0xffff\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], + args[0], args[1], + ) + case "*image.YCbCr": + return fmt.Sprintf(""+ + "dstColorRGBA64.R = uint16(%sr)\n"+ + "dstColorRGBA64.G = uint16(%sg)\n"+ + "dstColorRGBA64.B = uint16(%sb)\n"+ + "dstColorRGBA64.A = 0xffff\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], args[2], args[2], + args[0], args[1], + ) + } + case "*image.RGBA": + switch d.sType { + default: + return fmt.Sprintf(""+ + "dst.Pix[d+0] = uint8(uint32(%sr) >> 8)\n"+ + "dst.Pix[d+1] = uint8(uint32(%sg) >> 8)\n"+ + "dst.Pix[d+2] = uint8(uint32(%sb) >> 8)\n"+ + "dst.Pix[d+3] = uint8(uint32(%sa) >> 8)", + args[2], args[2], args[2], args[2], + ) + case "*image.Gray": + return fmt.Sprintf(""+ + "out := uint8(uint32(%sr) >> 8)\n"+ + "dst.Pix[d+0] = out\n"+ + "dst.Pix[d+1] = out\n"+ + "dst.Pix[d+2] = out\n"+ + "dst.Pix[d+3] = 0xff", + args[2], + ) + case "*image.YCbCr": + return fmt.Sprintf(""+ + "dst.Pix[d+0] = uint8(uint32(%sr) >> 8)\n"+ + "dst.Pix[d+1] = uint8(uint32(%sg) >> 8)\n"+ + "dst.Pix[d+2] = uint8(uint32(%sb) >> 8)\n"+ + "dst.Pix[d+3] = 0xff", + args[2], args[2], args[2], + ) + } } } case "outputf": - // TODO: handle op==Over, not just op==Src. args, _ := splitArgs(suffix) if len(args) != 5 { return "" } ret := "" - switch d.dType { - default: - log.Fatalf("bad dType %q", d.dType) - case "Image": - switch d.sType { + + switch d.op { + case "Over": + switch d.dType { default: + log.Fatalf("bad dType %q", d.dType) + case "Image": ret = fmt.Sprintf(""+ - "dstColorRGBA64.R = %s(%sr * %s)\n"+ - "dstColorRGBA64.G = %s(%sg * %s)\n"+ - "dstColorRGBA64.B = %s(%sb * %s)\n"+ - "dstColorRGBA64.A = %s(%sa * %s)\n"+ + "qr, qg, qb, qa := dst.At(%s, %s).RGBA()\n"+ + "%sr0 := uint32(%s(%sr * %s))\n"+ + "%sg0 := uint32(%s(%sg * %s))\n"+ + "%sb0 := uint32(%s(%sb * %s))\n"+ + "%sa0 := uint32(%s(%sa * %s))\n"+ + "%sa1 := 0xffff - %sa0\n"+ + "dstColorRGBA64.R = uint16(qr*%sa1/0xffff + %sr0)\n"+ + "dstColorRGBA64.G = uint16(qg*%sa1/0xffff + %sg0)\n"+ + "dstColorRGBA64.B = uint16(qb*%sa1/0xffff + %sb0)\n"+ + "dstColorRGBA64.A = uint16(qa*%sa1/0xffff + %sa0)\n"+ "dst.Set(%s, %s, dstColor)", - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], + args[0], args[1], + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[3], + args[3], args[3], + args[3], args[3], + args[3], args[3], + args[3], args[3], args[0], args[1], ) - case "*image.Gray": + case "*image.RGBA": ret = fmt.Sprintf(""+ - "out := %s(%sr * %s)\n"+ - "dstColorRGBA64.R = out\n"+ - "dstColorRGBA64.G = out\n"+ - "dstColorRGBA64.B = out\n"+ - "dstColorRGBA64.A = 0xffff\n"+ - "dst.Set(%s, %s, dstColor)", - args[2], args[3], args[4], - args[0], args[1], - ) - case "*image.YCbCr": - ret = fmt.Sprintf(""+ - "dstColorRGBA64.R = %s(%sr * %s)\n"+ - "dstColorRGBA64.G = %s(%sg * %s)\n"+ - "dstColorRGBA64.B = %s(%sb * %s)\n"+ - "dstColorRGBA64.A = 0xffff\n"+ - "dst.Set(%s, %s, dstColor)", - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], - args[0], args[1], + "%sr0 := uint32(%s(%sr * %s))\n"+ + "%sg0 := uint32(%s(%sg * %s))\n"+ + "%sb0 := uint32(%s(%sb * %s))\n"+ + "%sa0 := uint32(%s(%sa * %s))\n"+ + "%sa1 := (0xffff - uint32(%sa0)) * 0x101\n"+ + "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*%sa1/0xffff + %sr0) >> 8)\n"+ + "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*%sa1/0xffff + %sg0) >> 8)\n"+ + "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*%sa1/0xffff + %sb0) >> 8)\n"+ + "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*%sa1/0xffff + %sa0) >> 8)", + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[2], args[3], args[4], + args[3], args[3], + args[3], args[3], + args[3], args[3], + args[3], args[3], + args[3], args[3], ) } - case "*image.RGBA": - switch d.sType { + + case "Src": + switch d.dType { default: - ret = fmt.Sprintf(""+ - "dst.Pix[d+0] = uint8(%s(%sr * %s) >> 8)\n"+ - "dst.Pix[d+1] = uint8(%s(%sg * %s) >> 8)\n"+ - "dst.Pix[d+2] = uint8(%s(%sb * %s) >> 8)\n"+ - "dst.Pix[d+3] = uint8(%s(%sa * %s) >> 8)", - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], - ) - case "*image.Gray": - ret = fmt.Sprintf(""+ - "out := uint8(%s(%sr * %s) >> 8)\n"+ - "dst.Pix[d+0] = out\n"+ - "dst.Pix[d+1] = out\n"+ - "dst.Pix[d+2] = out\n"+ - "dst.Pix[d+3] = 0xff", - args[2], args[3], args[4], - ) - case "*image.YCbCr": - ret = fmt.Sprintf(""+ - "dst.Pix[d+0] = uint8(%s(%sr * %s) >> 8)\n"+ - "dst.Pix[d+1] = uint8(%s(%sg * %s) >> 8)\n"+ - "dst.Pix[d+2] = uint8(%s(%sb * %s) >> 8)\n"+ - "dst.Pix[d+3] = 0xff", - args[2], args[3], args[4], - args[2], args[3], args[4], - args[2], args[3], args[4], - ) + log.Fatalf("bad dType %q", d.dType) + case "Image": + switch d.sType { + default: + ret = fmt.Sprintf(""+ + "dstColorRGBA64.R = %s(%sr * %s)\n"+ + "dstColorRGBA64.G = %s(%sg * %s)\n"+ + "dstColorRGBA64.B = %s(%sb * %s)\n"+ + "dstColorRGBA64.A = %s(%sa * %s)\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + args[0], args[1], + ) + case "*image.Gray": + ret = fmt.Sprintf(""+ + "out := %s(%sr * %s)\n"+ + "dstColorRGBA64.R = out\n"+ + "dstColorRGBA64.G = out\n"+ + "dstColorRGBA64.B = out\n"+ + "dstColorRGBA64.A = 0xffff\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], args[3], args[4], + args[0], args[1], + ) + case "*image.YCbCr": + ret = fmt.Sprintf(""+ + "dstColorRGBA64.R = %s(%sr * %s)\n"+ + "dstColorRGBA64.G = %s(%sg * %s)\n"+ + "dstColorRGBA64.B = %s(%sb * %s)\n"+ + "dstColorRGBA64.A = 0xffff\n"+ + "dst.Set(%s, %s, dstColor)", + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + args[0], args[1], + ) + } + case "*image.RGBA": + switch d.sType { + default: + ret = fmt.Sprintf(""+ + "dst.Pix[d+0] = uint8(%s(%sr * %s) >> 8)\n"+ + "dst.Pix[d+1] = uint8(%s(%sg * %s) >> 8)\n"+ + "dst.Pix[d+2] = uint8(%s(%sb * %s) >> 8)\n"+ + "dst.Pix[d+3] = uint8(%s(%sa * %s) >> 8)", + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + ) + case "*image.Gray": + ret = fmt.Sprintf(""+ + "out := uint8(%s(%sr * %s) >> 8)\n"+ + "dst.Pix[d+0] = out\n"+ + "dst.Pix[d+1] = out\n"+ + "dst.Pix[d+2] = out\n"+ + "dst.Pix[d+3] = 0xff", + args[2], args[3], args[4], + ) + case "*image.YCbCr": + ret = fmt.Sprintf(""+ + "dst.Pix[d+0] = uint8(%s(%sr * %s) >> 8)\n"+ + "dst.Pix[d+1] = uint8(%s(%sg * %s) >> 8)\n"+ + "dst.Pix[d+2] = uint8(%s(%sb * %s) >> 8)\n"+ + "dst.Pix[d+3] = 0xff", + args[2], args[3], args[4], + args[2], args[3], args[4], + args[2], args[3], args[4], + ) + } } } + return strings.Replace(ret, " * 1)", ")", -1) case "srcf", "srcu": diff --git a/draw/impl.go b/draw/impl.go index 4ad48ca..5292ced 100644 --- a/draw/impl.go +++ b/draw/impl.go @@ -216,10 +216,11 @@ func (nnInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Recta 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) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -262,10 +263,11 @@ func (nnInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectan 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) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -476,10 +478,11 @@ func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Recta for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { sx := (2*uint64(dx) + 1) * sw / dw2 pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA() - dst.Pix[d+0] = uint8(uint32(pr) >> 8) - dst.Pix[d+1] = uint8(uint32(pg) >> 8) - dst.Pix[d+2] = uint8(uint32(pb) >> 8) - dst.Pix[d+3] = uint8(uint32(pa) >> 8) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -515,10 +518,12 @@ func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { 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) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + pa1 := 0xffff - uint32(pa) + dstColorRGBA64.R = uint16(qr*pa1/0xffff + uint32(pr)) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + uint32(pg)) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + uint32(pb)) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + uint32(pa)) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } @@ -583,10 +588,11 @@ func (nnInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.R 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) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -631,10 +637,11 @@ func (nnInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Re 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) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -851,10 +858,11 @@ func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.R 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) + pa1 := (0xffff - uint32(pa)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + uint32(pr)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + uint32(pg)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + uint32(pb)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + uint32(pa)) >> 8) } } } @@ -892,10 +900,12 @@ func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectan 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) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + pa1 := 0xffff - uint32(pa) + dstColorRGBA64.R = uint16(qr*pa1/0xffff + uint32(pr)) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + uint32(pg)) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + uint32(pb)) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + uint32(pa)) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } @@ -1243,10 +1253,11 @@ func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rect 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -1433,10 +1444,11 @@ func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Recta 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -2295,10 +2307,11 @@ func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rect 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -2454,10 +2467,12 @@ func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle s11g = yFrac1*s10g + yFrac0*s11g s11b = yFrac1*s10b + yFrac0*s11b s11a = yFrac1*s10a + yFrac0*s11a - dstColorRGBA64.R = uint16(s11r) - dstColorRGBA64.G = uint16(s11g) - dstColorRGBA64.B = uint16(s11b) - dstColorRGBA64.A = uint16(s11a) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + s11a1 := 0xffff - uint32(s11a) + dstColorRGBA64.R = uint16(qr*s11a1/0xffff + uint32(s11r)) + dstColorRGBA64.G = uint16(qg*s11a1/0xffff + uint32(s11g)) + dstColorRGBA64.B = uint16(qb*s11a1/0xffff + uint32(s11b)) + dstColorRGBA64.A = uint16(qa*s11a1/0xffff + uint32(s11a)) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } @@ -2696,10 +2711,11 @@ func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image. 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -2888,10 +2904,11 @@ func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.R 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -3756,10 +3773,11 @@ func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image. 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) + s11a1 := (0xffff - uint32(s11a)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*s11a1/0xffff + uint32(s11r)) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*s11a1/0xffff + uint32(s11g)) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*s11a1/0xffff + uint32(s11b)) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*s11a1/0xffff + uint32(s11a)) >> 8) } } } @@ -3917,10 +3935,12 @@ func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Recta 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) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + s11a1 := 0xffff - uint32(s11a) + dstColorRGBA64.R = uint16(qr*s11a1/0xffff + uint32(s11r)) + dstColorRGBA64.G = uint16(qg*s11a1/0xffff + uint32(s11g)) + dstColorRGBA64.B = uint16(qb*s11a1/0xffff + uint32(s11b)) + dstColorRGBA64.A = uint16(qa*s11a1/0xffff + uint32(s11a)) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } @@ -4505,10 +4525,15 @@ func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle pb = pa } - 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) + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) d += dst.Stride } } @@ -4570,10 +4595,16 @@ func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp pb = pa } - dstColorRGBA64.R = ftou(pr * s.invTotalWeight) - dstColorRGBA64.G = ftou(pg * s.invTotalWeight) - dstColorRGBA64.B = ftou(pb * s.invTotalWeight) - dstColorRGBA64.A = ftou(pa * s.invTotalWeight) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA() + pr0 := uint32(ftou(pr * s.invTotalWeight)) + pg0 := uint32(ftou(pg * s.invTotalWeight)) + pb0 := uint32(ftou(pb * s.invTotalWeight)) + pa0 := uint32(ftou(pa * s.invTotalWeight)) + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor) } } @@ -4818,10 +4849,15 @@ func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectan pb = pa } - 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) + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } @@ -5048,10 +5084,15 @@ func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectang pb = pa } - 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) + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } @@ -5770,10 +5811,15 @@ func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectan pb = pa } - 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) + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := (0xffff - uint32(pa0)) * 0x101 + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8) } } } @@ -5993,10 +6039,16 @@ func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, pb = pa } - dstColorRGBA64.R = fffftou(pr) - dstColorRGBA64.G = fffftou(pg) - dstColorRGBA64.B = fffftou(pb) - dstColorRGBA64.A = fffftou(pa) + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + pr0 := uint32(fffftou(pr)) + pg0 := uint32(fffftou(pg)) + pb0 := uint32(fffftou(pb)) + pa0 := uint32(fffftou(pa)) + pa1 := 0xffff - pa0 + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0) dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } diff --git a/draw/scale.go b/draw/scale.go index 00ef1d3..8207e81 100644 --- a/draw/scale.go +++ b/draw/scale.go @@ -381,52 +381,102 @@ func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) { } func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) { - // TODO: implement op == Over. - switch dst := dst.(type) { - case *image.RGBA: - pr, pg, pb, pa := src.C.RGBA() - pr8 := uint8(pr >> 8) - pg8 := uint8(pg >> 8) - pb8 := uint8(pb >> 8) - pa8 := uint8(pa >> 8) + switch op { + case Over: + switch dst := dst.(type) { + case *image.RGBA: + pr, pg, pb, pa := src.C.RGBA() + pa1 := (0xffff - pa) * 0x101 - for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { - dyf := float64(dr.Min.Y+int(dy)) + 0.5 - d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy)) - for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { - dxf := float64(dr.Min.X+int(dx)) + 0.5 - 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 + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy)) + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + 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 + } + dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8) + dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8) + dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8) + dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8) + } + } + + default: + pr, pg, pb, pa := src.C.RGBA() + pa1 := 0xffff - pa + 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 + } + qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA() + dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr) + dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg) + dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb) + dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa) + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } - dst.Pix[d+0] = pr8 - dst.Pix[d+1] = pg8 - dst.Pix[d+2] = pb8 - dst.Pix[d+3] = pa8 } } - default: - pr, pg, pb, pa := src.C.RGBA() - dstColorRGBA64 := &color.RGBA64{ - uint16(pr), - uint16(pg), - uint16(pb), - uint16(pa), - } - dstColor := color.Color(dstColorRGBA64) + case Src: + switch dst := dst.(type) { + case *image.RGBA: + pr, pg, pb, pa := src.C.RGBA() + pr8 := uint8(pr >> 8) + pg8 := uint8(pg >> 8) + pb8 := uint8(pb >> 8) + pa8 := uint8(pa >> 8) - 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 + for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ { + dyf := float64(dr.Min.Y+int(dy)) + 0.5 + d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy)) + for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 { + dxf := float64(dr.Min.X+int(dx)) + 0.5 + 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 + } + dst.Pix[d+0] = pr8 + dst.Pix[d+1] = pg8 + dst.Pix[d+2] = pb8 + dst.Pix[d+3] = pa8 + } + } + + default: + pr, pg, pb, pa := src.C.RGBA() + dstColorRGBA64 := &color.RGBA64{ + uint16(pr), + uint16(pg), + uint16(pb), + uint16(pa), + } + 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 + } + dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } - dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor) } } } diff --git a/draw/scale_test.go b/draw/scale_test.go index 47a06bf..a1fb5cc 100644 --- a/draw/scale_test.go +++ b/draw/scale_test.go @@ -23,8 +23,8 @@ import ( var genGoldenFiles = flag.Bool("gen_golden_files", false, "whether to generate the TestXxx golden files.") -var transformMatrix = func(tx, ty float64) *f64.Aff3 { - const scale, cos30, sin30 = 3.75, 0.866025404, 0.5 +var transformMatrix = func(scale, tx, ty float64) *f64.Aff3 { + const cos30, sin30 = 0.866025404, 0.5 return &f64.Aff3{ +scale * cos30, -scale * sin30, tx, +scale * sin30, +scale * cos30, ty, @@ -49,8 +49,8 @@ func encode(filename string, m image.Image) error { // algorithm or kernel used by any particular quality setting will obviously // change the resultant pixels. In such a case, use the gen_golden_files flag // to regenerate the golden files. -func testInterp(t *testing.T, w int, h int, direction, srcFilename string) { - f, err := os.Open("../testdata/go-turns-two-" + srcFilename) +func testInterp(t *testing.T, w int, h int, direction, prefix, suffix string) { + f, err := os.Open("../testdata/" + prefix + suffix) if err != nil { t.Fatalf("Open: %v", err) } @@ -59,9 +59,16 @@ func testInterp(t *testing.T, w int, h int, direction, srcFilename string) { if err != nil { t.Fatalf("Decode: %v", err) } - opts := &Options{ - Op: Src, + + op, scale := Src, 3.75 + if prefix == "tux" { + op, scale = Over, 0.125 } + opts := &Options{ + Op: op, + } + green := image.NewUniform(color.RGBA{0x00, 0x22, 0x11, 0xff}) + testCases := map[string]Interpolator{ "nn": NearestNeighbor, "ab": ApproxBiLinear, @@ -69,11 +76,12 @@ func testInterp(t *testing.T, w int, h int, direction, srcFilename string) { "cr": CatmullRom, } for name, q := range testCases { - goldenFilename := fmt.Sprintf("../testdata/go-turns-two-%s-%s.png", direction, name) + goldenFilename := fmt.Sprintf("../testdata/%s-%s-%s.png", prefix, direction, name) got := image.NewRGBA(image.Rect(0, 0, w, h)) + Copy(got, image.Point{}, green, got.Bounds(), nil) if direction == "rotate" { - q.Transform(got, transformMatrix(40, 10), src, src.Bounds(), opts) + q.Transform(got, transformMatrix(scale, 40, 10), src, src.Bounds(), opts) } else { q.Scale(got, got.Bounds(), src, src.Bounds(), opts) } @@ -111,9 +119,31 @@ func testInterp(t *testing.T, w int, h int, direction, srcFilename string) { } } -func TestScaleDown(t *testing.T) { testInterp(t, 100, 100, "down", "280x360.jpeg") } -func TestScaleUp(t *testing.T) { testInterp(t, 75, 100, "up", "14x18.png") } -func TestTransform(t *testing.T) { testInterp(t, 100, 100, "rotate", "14x18.png") } +func TestScaleDown(t *testing.T) { testInterp(t, 100, 100, "down", "go-turns-two", "-280x360.jpeg") } +func TestScaleUp(t *testing.T) { testInterp(t, 75, 100, "up", "go-turns-two", "-14x18.png") } +func TestTformSrc(t *testing.T) { testInterp(t, 100, 100, "rotate", "go-turns-two", "-14x18.png") } +func TestTformOver(t *testing.T) { testInterp(t, 100, 100, "rotate", "tux", ".png") } + +func TestOps(t *testing.T) { + blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff}) + testCases := map[Op]color.RGBA{ + Over: color.RGBA{0x7f, 0x00, 0x80, 0xff}, + Src: color.RGBA{0x7f, 0x00, 0x00, 0x7f}, + } + for op, want := range testCases { + dst := image.NewRGBA(image.Rect(0, 0, 2, 2)) + Copy(dst, image.Point{}, blue, dst.Bounds(), nil) + + src := image.NewRGBA(image.Rect(0, 0, 1, 1)) + src.SetRGBA(0, 0, color.RGBA{0x7f, 0x00, 0x00, 0x7f}) + + NearestNeighbor.Scale(dst, dst.Bounds(), src, src.Bounds(), &Options{Op: op}) + + if got := dst.RGBAAt(0, 0); got != want { + t.Errorf("op=%v: got %v, want %v", op, got, want) + } + } +} // TestNegativeWeights tests that scaling by a kernel that produces negative // weights, such as the Catmull-Rom kernel, doesn't produce an invalid color @@ -183,7 +213,7 @@ func TestInterpClipCommute(t *testing.T) { var interp func(dst *image.RGBA) if transform { interp = func(dst *image.RGBA) { - q.Transform(dst, transformMatrix(2, 1), src, src.Bounds(), nil) + q.Transform(dst, transformMatrix(3.75, 2, 1), src, src.Bounds(), nil) } } else { interp = func(dst *image.RGBA) { @@ -256,7 +286,7 @@ func TestSrcTranslationInvariance(t *testing.T) { {-8, +8}, {-8, -8}, } - m00 := transformMatrix(0, 0) + m00 := transformMatrix(3.75, 0, 0) for _, transform := range []bool{false, true} { for _, q := range qs { @@ -332,33 +362,37 @@ func TestFastPaths(t *testing.T) { ApproxBiLinear, CatmullRom, } - blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f}) - opts := &Options{ - Op: Src, + ops := []Op{ + Over, + Src, } + blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f}) for _, dr := range drs { for _, src := range srcs { for _, sr := range srs { for _, transform := range []bool{false, true} { for _, q := range qs { - dst0 := image.NewRGBA(drs[0]) - dst1 := image.NewRGBA(drs[0]) - Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src) - Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src) + for _, op := range ops { + opts := &Options{Op: op} + dst0 := image.NewRGBA(drs[0]) + dst1 := image.NewRGBA(drs[0]) + Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src) + Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src) - if transform { - m := transformMatrix(2, 1) - q.Transform(dst0, m, src, sr, opts) - q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, opts) - } else { - q.Scale(dst0, dr, src, sr, opts) - q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, opts) - } + if transform { + m := transformMatrix(3.75, 2, 1) + q.Transform(dst0, m, src, sr, opts) + q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, opts) + } else { + q.Scale(dst0, dr, src, sr, opts) + q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, opts) + } - if !bytes.Equal(dst0.Pix, dst1.Pix) { - t.Errorf("pix differ for dr=%v, src=%T, sr=%v, transform=%t, q=%T", - dr, src, sr, transform, q) + if !bytes.Equal(dst0.Pix, dst1.Pix) { + t.Errorf("pix differ for dr=%v, src=%T, sr=%v, transform=%t, q=%T", + dr, src, sr, transform, q) + } } } } @@ -453,7 +487,7 @@ func benchTform(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (i b.Fatal(err) } sr := src.Bounds() - m := transformMatrix(40, 10) + m := transformMatrix(3.75, 40, 10) opts := &Options{ Op: op, } @@ -480,28 +514,54 @@ func BenchmarkScaleABUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, App func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, BiLinear) } func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, CatmullRom) } -func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) } -func BenchmarkScaleNNSrcUniform(b *testing.B) { benchScale(b, 200, 150, Src, srcUnif, NearestNeighbor) } +func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) } +func BenchmarkScaleNNSrcUnif(b *testing.B) { benchScale(b, 200, 150, Src, srcUnif, NearestNeighbor) } -func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) } -func BenchmarkTformNNSrcUniform(b *testing.B) { benchTform(b, 200, 150, Src, srcUnif, NearestNeighbor) } +func BenchmarkScaleNNOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, NearestNeighbor) } +func BenchmarkScaleNNOverUnif(b *testing.B) { benchScale(b, 200, 150, Over, srcUnif, NearestNeighbor) } + +func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) } +func BenchmarkTformNNSrcUnif(b *testing.B) { benchTform(b, 200, 150, Src, srcUnif, NearestNeighbor) } + +func BenchmarkTformNNOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, NearestNeighbor) } +func BenchmarkTformNNOverUnif(b *testing.B) { benchTform(b, 200, 150, Over, srcUnif, NearestNeighbor) } func BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, ApproxBiLinear) } func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) } func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, ApproxBiLinear) } func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) } +func BenchmarkScaleABOverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, ApproxBiLinear) } +func BenchmarkScaleABOverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) } +func BenchmarkScaleABOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, ApproxBiLinear) } +func BenchmarkScaleABOverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) } + func BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, ApproxBiLinear) } func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) } func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, ApproxBiLinear) } func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) } +func BenchmarkTformABOverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, ApproxBiLinear) } +func BenchmarkTformABOverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) } +func BenchmarkTformABOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, ApproxBiLinear) } +func BenchmarkTformABOverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) } + func BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, CatmullRom) } func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, CatmullRom) } func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, CatmullRom) } func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, CatmullRom) } +func BenchmarkScaleCROverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, CatmullRom) } +func BenchmarkScaleCROverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, CatmullRom) } +func BenchmarkScaleCROverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, CatmullRom) } +func BenchmarkScaleCROverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, CatmullRom) } + func BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, CatmullRom) } func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, CatmullRom) } func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, CatmullRom) } func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, CatmullRom) } + +func BenchmarkTformCROverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, CatmullRom) } +func BenchmarkTformCROverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, CatmullRom) } +func BenchmarkTformCROverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, CatmullRom) } +func BenchmarkTformCROverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, CatmullRom) } diff --git a/testdata/go-turns-two-rotate-ab.png b/testdata/go-turns-two-rotate-ab.png index b04ab3ccab2f37ce43aa7b4589020447fa8337db..04fceaa77cf773ccef36f3291f55dfeceb7f226c 100644 GIT binary patch literal 7654 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 UQNQP(A^-pY07*qoM6N<$f+6j@VgLXD literal 8761 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 diff --git a/testdata/go-turns-two-rotate-bl.png b/testdata/go-turns-two-rotate-bl.png index b4e1279d98f34d9eb6982da994bad974b738d39b..c8b717e2220c3dd6c36eff35eabd7fb0394141d9 100644 GIT binary patch literal 7653 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 SqJYu>0000E1cE07;sIWG z<`sz-egoo(Cj@FGX$9L!x7$vqNxR)ij(yI))vl^_zf8Vw%vJlCbhl$4?@R4yPiwjM zF4wNAHNQE=_`Wg5oc82)?9{jgWXHxWAUig00ok!}3&@U*TR?Vf+yb&=;}(z|8@GV$ z*ti8`$HvYBa`*?Y+w1-gS2@gee}NAhKMBUY&wP2OzwbqiowgA36Vre6&d!0-#}1hP0skTl3e5Q549v#!eenZc zflTjxZYS^ISx0c)U*Jy~9;|?faPqfc4EVwQY{lol;cN|FlOO%QHTXF@`0URFFgte> z_2V~fKMc}!Rys_0KZsr}{?*~?2^3sb6a|vRfrOzife%+^tW55_vUB(IamUVC2<95D z%E%yAC%^4Pn%+v?bdp!C)NQZ9K8Zt_PGXs)p~R6VL11Ka^p@Jt^zNU#vB2!q7w?Z~ z9k7OOkh1Betb3`NL8^9;ylmxcQ^}@m)P+sbNcQK6?BSYbApmlg;_;4@30Rpwck=@O zPFVq;%8synzR4-@W57&N$i{n@Co8@MlD5LT2P z3*M_b{$1|YkPZi-qr9FU z;5DM)#khjNYH+upV8F>K7vubLclwrPeDW5%4a`meqI!dVpLqkFL0AA>kMH+*-oS-f zX38-)K-?L`&XLk;iYX^jeF{o3)gj#@sRnFCp9~77n z%RGrdaWkvH%%>B%vp)m7nn;3~CLq4A)C$@KtgLQvQL|WeTPbMsgzk@^P}9Jz#g@PT zl;ZnV7ecx_YX4dRdH;Lgvb}Y>qvr(K5fnIkh7>@cu_DW23E_95Fp~K!lfA_h&!qq) z#&dxx`UZrc>T1ambJm4pYIIvk>%nS7uQWo?#|ILu7<4Yi=MhZ1`M&BGGrfL`xi&yf ze(-I}i2-w!7JxJZe7~W~@{~o<(R%@6MAFMloCTz?i0L$gwIp~xmN-uE+EBr(`c{gz zm1U0iUJcR!0S56D=1?>uv&NS!f(r}Xl>wX#|BddBmc);!Pv6$>G`V|yf&bb7@jXwK zIO7KdI3^QJ2!I5kk;L;|Y)CW%x#sZmU> z^G=S>T6zDtQc&o&2*|y?P!8rkKrjFX&t;wz6M&V0C;*t0>6bAU5tR4dbs6UuKK-RD z1?E}+;f;0*hA0?^a51L^Gq|11fRsVtjbg0agz6jM;P=q8m|T|u_I+9o`I4t%!&CL* zE;~TCY#RB|<3gUCRBDBL(@>tf6UlQ2q1;;pasX>-L63P+|8%`C9juX{C_&I%zfr6F z@gKfniOBPx{`o5b=E?!tyaPqfWFf%VlyEWmpn#m@PF>en?c!05_sXzHR|9B`IAY>) z)GFtNP5?kN8#-u=4xn}7*-r9JDM!b-{P;-)R|e1lNQEC5=(+kSbx4y{p8#y%r}e=? zJST&^ZK)C>(^#X=J^rKbSb}x;g}-pAz+5>XoDfb@USp!@^8v(h4wqGE)dRu~fJg&L z0m{p)E?iXtEuu0z+|Gs58A8EWby8Q2v`rSy?;Dl{rv?T<8oH{C0>W!eOIc&3WA(;OahZU51u_R1lf)|Xis8C^LlQwZIJok0FD|2Ooz)N%Dt&|Bi{rOd zSY`(o2h5cLLKf8FCTj?_92T;o%K{jiiW5s_)PNy@6=4?E>q>?OtJz{z8_-(|tx+TB zf(>l}se7`sR*sgHJUOl8(NQUX_-KR20>ZG<9M^-pseJCGxqR;BeYp!jCRrpih|Kvk zlEox|#dylNQq?AKVg`f)2=t)P16-#azcZ_suov;k3=wE(IDzKcJhhqClQ-@B{>8Yl zD*@!>t^ciM*|ztT=3-&1%i<$_`ljsV6wK%p6Wb%eEHUX#9*Sw8Ke`l?lSs306Bxm@ z7-*En(#k+{LDlHCj+V88x`FFsY*=KWJh(TNPd%8)%P-9I=e=2~ps<(~k}QBEgs_U3 z2}re$-kC%vWBIt(;uz`lF!V~HqmX34)5l=2=LNB&AAi@<#ohnZCu3t*0tmjT^azj* zR$A3L5m+=vf9F-V)DUn147`Z;E4ZsV$4YD~#DNw!&8%+>KoLhe#*sie`0!fi&Zxpy zZ;y$g%AZdYnNA|v-%DjNW0@CJcOHZKW-`a~AtsabxI@emoz!7WGJ7t$2C><*mZFu) zPRhCwE+|fZ6jEH`d-T2o#dB3kJ60**hsJvF(z7@8T{ej$Y2!;{T z-)?XWhm&DO^QXd+}LWG%mXvVR>f=+>3c6cMoFC_7;dq zDHJ^ey6-!7M4Fq$6oHOe^-%E^SKBu-u=3aqE`=hj<9Eu+)>t{G>l&cc`WkPvkSyW* zgor(XOTBpJk2Uo@>$r4481uR_0YwYw4^Zs z$;o6z(E6@Z%S$;K0c(Yre3o{7#3HO_yypx`oMO`DlkHgA4AOIE76=wGdHCtSxVtWE`Sx$xZ9f&K zgl>z8L=X9&OoeZn|W1Gp$fV8*0O zp&k#W9+Y}7P3wa0G=}QOYZsq0dzGMA<)@jW{QlIi~fF>ak# z4wTazkEOaex<9%;#uHjx61tR&wHIS0mj=k$_rJC6Y||u!&oA6L@kMY51l>!+;0fKa zy`fMer>{DLtBy5}vTQJE_^Pm$2-7(sOqk#TtCmSIin$1?KAj7nMUT#8~1i)l68A4C}@KY$gufPMtA^xl&*jV0`GA?4kl z#&R%Aq)%PD62JSym%s9fA-O~g8B4KP)`6xee4Wgou^NEszDQkL1!N40R_#IE3x97B zM+&aeC0xjKkP-p9&sZMnuG%b@NuyaOZ)7?{xnW>bP{uOLQ) z9?S@_h-om;0mi5pgrSB2tzaDu+?b_O7t!wEu(jZnnILHuZdY7$c zg%Xc1e)g-oOM6#uf76n~>&^MD$V5M%5Rd|^6Rd_n&}F$Bazc!&o}x@y8D_G9Gv7d? ztd^aeP4GAct%X}l0F-HSO!ArJd7-)_*`Lb9TZo@#5<=O-m}EotR(sM_4PIa4f?KK> z?0wf<$Fxjy2fGv#cuI_f#1bu&(w9RK6BKcNc$@6g%=+N81smuZwvukFEHMu;fXqD5)wY9* z?b_D0X}VOUO%Q|~V#x-p=jf=` zMCB=HFZ+tKmT)7ojmN^JQ3kGd)*JDidOwsE ztn1NP2fACUAY?6{fUwg(9FvPIcKz}%{q@~Vzbk$1d#!b_4Tl9MRs?AwC4%i4oY^ z)@kT+r);iB0!^FHO|j+ZAN;*vzLX->g#hyQH~yO?%_NOoVCayC=Kchm)F5cKursRk~s}gBYs%W*EQloi^)9dOYxgR zJOpYFl-6fr#qYHdZiq0s&>T6e?FcOE@sc^IRzp?Qy8KyzFZ*O#L${C$y3#Hal{Hm5 zv`PtU?LnWXlf-3sLzf$&Wv~(Nvc`n~($}rDyph(Iv)WYwS(e?@6n{QqD<&8pHQ)y0 zDAu-~+06A;>82d4_?|I^#h{MyhnDrUlSYVNIO=H&jauzwb(a_rBD#JCgegsN)Q)FcdlwUJV=B#Md6GIF8_p zBlX8gV6+ZFRnBA|Syk^1+S9A4NYiWfmTF&Pjh{idL6MJJ5%``gc(Gw22ap|`BVb|v zz$g@|T4$rSu=^2z6OHMaL9+n8elC-flt3*r2&B+slGA65V_H9T;*l02*2T#G@UOqV z!(Aso_#?5aLfRz)#0L{$l9_wLO+~mluply(l#B|qXH~6tW4W|* zfw}LrC}mioQ+-0|jg>E8 z;F{!gi$bVEj#@_Bb<9Sy!kjcuwFWGe)PMhP{?YDsF21pM z*D^8K!Oyp*L7c!u_)xxaC3e#3%4OBaOD8%h69mp_%7TukEun@P-M$~)l(P&63ZDM} z7-Ae4E;;EwTOauLT+LCS&DXP8rW4B&aK-v}uSFPjQ=Is%@+XrLZHjZrPP$Tmd{ej8 z+EoMh0mdGzWCm~u>{V`7ekMTNu@|C~(1IeiJ|+Qz%(h!F67ePz32~*EkQp?=Eb6q~ z#vcPYt$T8frYRi*ja~>fB7$d{mKye*nqsY|G?V8ZC}?KzZ9JDq>|CNkgERv+OG4YL*VMa~s5Dit z=&Rdtg(IT@*iqG<%?8t085RRIzt7;huT{XgjalaW(sKHEh>Z^8EQMe&c;DTN<=%dx zpggsXs~sN;kk=l*Y?&$_I_F|~orD%5tf9GxqpMb91UMD|=wybNF@?@Zy+O|?8OFWk zq`d5lG6aMm!m_l7wso6$TpOp=`r-B;4xL+AN2px|tmsAhp6sFGHHfQ74qoqAk#-`; zc@u(0AoJ80@_E+9?<^vDa3_`L4ib$YY_#L+e*HK8{tjc%)q9;Di*SMxIo9^muMRhdnQtC zaPuJa0^PkEM*evmnP(#)w2oQi@>bV$>c~e1L?=*0CzNhWD}4;GEPqZB#P?D$@V%0e z*lm1r)!&!lAue16- zbbX8|WL`nwG>1RBDyBeyfo^A;XTBW30$6Cu5Z_2=`R+_G9w68q%v|#u+1aaq<8STm zmbN!vc-hkL>o=rmV-1|ElZB-T!I+5LnMi^a7B4(0W=6^cZo?<7^|Vy0wH()M=qBB| z{1Z(_!P(xvQqwVoV(fTM)(8n*o*lc>t&1_9xR@1cpDtsIQL><&M9eed`IMvrfE-MH zdEp?Ihxaqto2M!SSpehfxkERLTzjaws5ZoB7#|4`7YtpGuIUGzGdp~~!>g)mM`AwHV~ z&$4TzXMZrBM_il7R_?)&AI_{im{O?nMqF*AbIB~%aD9!|!SSJhy!HHN#_f;xse5PI z0h8^ga8(NcvA2+D0V~N8@wwSzg22w6TAnjfK*jfkv~`6QOaBq;1R3U)0`DpPR6}s? zNMnO_^$kaQhp|`7o*#&5MvFRkTh?k#gWC!wEd2tQ9G_F`ZktZKCa3Uc`|%+AQLmeT z5^1<2&b29>o2HRZzxqqpipWO`>Q7^>6Ih&W3cpDvK{gRT#ze=FcA^_hNDB>6cW_uG z*w$t(?Wz`f}C^~fW=D^-tjT6o-X%JxV7PGixyN%kEah9_E$61Q2 zVffm5``x2>;)PHdn$h=Sy$zx*rLYaa3;fY3Vh+x>sX zw2nJeeOEV7YjI?Tf*bxCtG{oguQoEkI@-gP)Q4-SR+Ur({B<~ypy4rnSfOdADRfTp zR@AAm8@e%wTSu>3*T2Q$k{vBnj7x-Iuio~|z_BeK$I6z8#xuOu+h$2qm6c;6cS4l7W_C5jFD^65uf>fv z+M+tR-B6_EJn4bk2)J$T5G-Rp2kSy$H!;&W&@Xg%_VSt*KJNI)!tj;%-*v#;d(mnk zq_*S1V}rU1_!a4jTso}4ysf1;SxN~|>b#K({<}1(RLM++Y>wD7$Ll82CK=RytQA1A zE@Q?f#&I&eZIOxWPQe-lA~UzXH-3Fgx^J|5g$K^CE1j?MwXzuMaUEPqI6ii^_m#sRneQDuZ*|pfD{f3Q!eY$XN;-(E5^<#2AdbMD zbw!PdveJO=*3m@lWFf(94{mNDW-^rlZmW-@@yI^6txbUlL(Lj<1C3Jc!3jxq^_sc$ zl^PFBFmh|d*rm>6Wc#rKsE48P2o566x(LVzfug%pzCcao?F<$=o~a)4%E=?Wi#Hb! z9WcEvPex7Yw6hOXvq7u?-Hl2n8d;Xbstz_{i&EP@2Ut8>&^tH<`%YK~kiJBa~aQ2?w%y$S3)9ylg9)yB*D6|TyD4}7_j+E+9N}i3N0P1^#1WPZdiiVr^xy6zA{V|tGtHdEFh)>wGw|;>PF1~R65FFBXCP$ z?EV)O6b%h~YjYk&-og?ZJ#e6eYpi;!k8Lxk!jE9F3u$Bzz|8P%Vhf-&twnt%KuQ4#9l2ICH?jVt8s_OoAKmga$+g3PYw#7?csT zGX`WlKOvnSNNH<{@?4_zT9VCLCICW;HNb$Sz-@82uAb~bKv^RhyBPcHxY1`A*Lt$` ztFV~=Gdr+MUofUb#vL#-bkHzmBf$zTX}OVTfz>|&`vPkU@z{L%=?xgye)juU)-Jxh0XF7Ymm;y_DVd&^yHpBuPf*=9 zgJ5hL@s3UvkV#&NMIa9l$k|2TjWrE_JUv3|_SPNNd{f4?1F{`IKhosa=l89ivaD6g zLNmM+fC6jr(op+%EvzKk6p{io3rg!F$m=m3BD(R@3*Ds$F#(XTuZkOC9UMFRMVX4x z%4FoaTl_Q@6Ng$I)Z}5?NL^G?1DG1FizoRo&CU$5(c?wkcIRI`Ioa8J{FBDcSjbNf zrea>3-Pc2GsJblzJP!(E>YWqsF`nr0Os?HDSqDVode?<@w`9YoPCqVjaxy#ednRw9%!tmPmdjr+NU!9AHWFCFB~7bIHRjt?ETfb7_~1!Tv@Eg(BK{$Bt90RR60Sz0Dyz!c;F O0000eTCmB-)fRo&`tt=29}Uho25S;gea`K3``+8{wQO~(7o|%7 zI`wqk>8sc8{rcSd?(({I((EE>S`(8d*C+6&q-j`5Xc|@$nue8xreP(aX;?{U8degT zhLwb-VI`rQ!5ZBAd9L0%Wyv`i?uevjY*?TD6G%Nu88y1j4hw>6&MRW$(mfd$xHqR$1<*XX&bsD=X#CDMsXkh;#upFJ# zO_WtwEUlRA&LEf~sMAG;n+|5{q>@lpVHxxqF!TpT11$c*-gD~0z-y`@%U+x1ZracM zFWZM|%B*bnk6&Iw=ZOawLs|(ZNACkgtMALoIo?D$YqPos9Oy7opbz)79zNNtE^HS- z=TKS7tf9|7g{|3al%i=RzSMSkfcdj(N|?WTS-DtDuhqiV@@KicS7sx#kQB)6_96TIM4ukn_t!?qf|EJl7j4+tqN$Wt>}AjXscKao|-`Q_pti)>lbU zUSNzA6Y$CjvW&yJx^s^@2)r0F)TaAaz*gkN)O0QYhQ3C_JF(g4mGL%>&?ud=W zPsf_7DU?4Lw%)xuy(h0$24VGmvNsUoy>oZ7x;T`^B5#Yi#z`En!k{cKn+Nf||!*)~hB)qzRzq(DoSE>#z< zEX!ZIXs$Yb?7VV3WFK+;X5TQFx^VBl#+1+Yrpi=iL0XBs?;P}PxN`>j6_vaLrI(yy zv9dCnR{g^+Oe@qIza{>!UR{j40E@j;U7}lcs|9_ho7dUOwGETK29>hWbpTSZ-Ftjc ziYEmsD=q}1ei^TT7cO2^ALoUiwSp-~!S-;wQ(d@s-#)N3oV}ooWLD2k+6&caHAsp{ ztFb-#@J#fpi*+m>@;bDZGPZl@7)`6j(=JRa)XJr$=zQ}Ya$`kUsO57DLP2kAFCxBa z<=VBAxEij^W>z>97I%RZY`5;}0#g?bIqCh8kpeX=$`3h))P;8(8WTy;*)t(vE5gmqxVzbb?;sC6$fD{25H5DvMk#V9|TM3%7`*j4S^RJq?IE6=C)RK;pRgv zCyrlH$B`G)TR(jWw!jOFkz%qIv2HDIt*-RB&vrS~M^2enIvaRMD{*(*X;K|^N zc}HwvolPv}^O5wgSex9EWjZrU7vbF;Bn2uf(2Jx{&-}+>Fe#pt$7HOlwW$xgU{28w zpIgp$krZgv;tEAck9$OCG=WL+q(H~o`IrGof%^6(w$F&Y$*i9%kGR$}n=AJl=V3$MDhKpg~L3>oT!-KStH@?vs(gJ9_A zrW%gy;kT`$y<{Z2RlzP|J4^) zF<7A44?Qr!3uH=XHOw=aB^$43ND5S1Rs<%Nw1&ps`mhyDiYEo~9QXu`?l|e7Z~a_{ z#hIXcVU@jLBB_Gnx>bv+!PJHIvfR-_dlD&-k|qyJtbnMy=bOP4!HcIa+6t6G5b*k7 z7pKsEh%R|?UV?tNbq|;nODm=&wF#O+;I;h|Wseucc%>la@G4maoFp&w76QVn=M`}8 zX>XND>hZ(@LSB(!ep7q)PV#9Xugwq75(}?(kOrtpCROj~N#0ZgFKfv2#4`=J8+MVV z9eH)SlmkP9mdxJxL(YHQ!Y2h&ODk!TnKk(P9q0hEw)5B31*%L0C8QOLjM+yVavqqv zaC_5n=5JU|XCPKb&Vh-=fD~*$e6LZ8kzxv89{@xDA7AI|vM)Y*`-HFQMoMR!b*Zfb zou6&v*Wes;Rm`kZ7Y1IKR;VR~QPy%kv3R|G*ky6iSqdbD0$!j0ALo0ei}q1~mq-fL zH{bySXWe%nOXiy5lsc@o|9yABLF@nd9(oPHiy;#Qyucu>#Naz8d|>LrO$XZl?Tto7 z5O^_UsA3)IUIH%>87kjE4E6js=CL^PN?9qw0#fKOUQAnC4UvEs4E*!`ag%TlKeUMX z7McDd@Y;RividEM7o-)7y!`f=AOH6OFm>U7cYtvu(N*0{DfY7% zEYOalq<6RWR?-XsDY4isix=+RPeI&L#b-QnCE0eCF^UAt{rv1$K$OQm-4NaH(sFVcOUC!@xS}tItB~0VkvC_W>s4!NlHo$R`Y+oX)fTsJA{Sm3-LIR zLI-(?uxwf~#lQNTFVR^ZOIM z!f})$EOY>wNUGCE*KdqE(h@OPAcKFjt&=ubNQ&v`u8*02;XJ+U=NGy~QlPE~>1W#e z$v}s}0%=XA4fFW85@De>Z{pKllP4vm&}K1GpbwAAeo3z`;|m%Uq+oknT_KpFq%PoC zy^%ho%t(QLea3v^8i$3XKt<){A}Q3~^FA;sp47&B=M0Y|SoN8VlIxV7D5wvqg2=1a z$3d*TqlSc`e-Jh(3fG!R!$0aHR|TXnh`cVG=k1`~Mg9?al~%=#rHd;`kV%Ho2S6kg(DGul9pIo3CNI|LOLD!_#v%sco8W|D;1e0SQOHV`I^SV_K~owZZ_`r zN;Tw<&H%P@S(*4>9+xZN^MM)ijAMg*pi`g^n2cJFpHd6Po>y3O`(jz2-+6`3*pyUa zJ19pN93pTKb_AV4Hs_nbJT7m^41QzLXf$^$EcN*50n?RMQp)|TBQ@lS*z$v9s)&+` zNf!=+p+6jLk5TsCYwF_^TMb}dVQQ(ZmE1b-U6){hQdDfwYbgRC#o{ILQyPzLBxzM_ z(SfCrlr(Wz$A5m>hU9WGI6{G8naBQjAoFlyqhxFQ&_X_4lv^ULrE4VjFGX{chgT2VS0F zL|qtoVOohQDYJnoi|Tc2dRQSN(XuM2@`y>O!5MGnd2W9U3)K?Yu}yd&YIp zke6O~ZvOj^l7B~D-9yTykjd-jnbqtomh-LZI3V-S=VQH<<#g4=tXF1DFz7EWwSq}8 zQcM92rxgg%#vYI@m^VZHjzN9&Gt=`Acut*lX0>f*b%F)7w5OFc@oEUXz#y#@@tT&; z)P+q!yH!hDrJ%5ykGz=ldO`|#5eq3h6AdfrgKYt!#x0m_Sx}o`E(~~KTA`l(_cZj^ z)w)SFgtQWO3&zMDebh!eI9H#hA06;AFP<++$|X2C5sh#|??{ zLe5z;j8_K9SPw|CIPfwCT|OP1NBz;0w@EQxKEHYlmJv;~%__F=MzrdsE$9F;q^3|H znu8us+!~in?*~&CmVF79TYwjs7^%0ASwP?=#Yiz#7U;mxU;Ve=x%tJUs&QepdwIXf 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 LNkvXXu0mjfRReuA diff --git a/testdata/tux-rotate-ab.png b/testdata/tux-rotate-ab.png new file mode 100644 index 0000000000000000000000000000000000000000..181966caecc87ea63e6fd78b0f6aad3edda257b9 GIT binary patch literal 3237 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 iy8h?Ddrf