From d56f68b2e751ba7dcf5a9defefc2466c1aa5ebca Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Thu, 2 May 2019 13:06:24 +0200 Subject: [PATCH] implemented software image pattern filling, added a test --- backend/softwarebackend/fill.go | 32 ++++++++++++++++++++++++++++++++ canvas_test.go | 14 ++++++++++++++ testdata/ImagePattern2.png | Bin 0 -> 4235 bytes 3 files changed, 46 insertions(+) create mode 100755 testdata/ImagePattern2.png diff --git a/backend/softwarebackend/fill.go b/backend/softwarebackend/fill.go index a9398d7..2800db7 100644 --- a/backend/softwarebackend/fill.go +++ b/backend/softwarebackend/fill.go @@ -58,6 +58,38 @@ func (b *SoftwareBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) { col := rg.data.ColorAt(o) b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y))) }) + } else if ip := style.ImagePattern; ip != nil { + ip := ip.(*ImagePattern) + img := ip.data.Image.(*Image) + mip := img.mips[0] // todo select the right mip size + w, h := img.Size() + fw, fh := float64(w), float64(h) + rx := ip.data.Repeat == backendbase.Repeat || ip.data.Repeat == backendbase.RepeatX + ry := ip.data.Repeat == backendbase.Repeat || ip.data.Repeat == backendbase.RepeatY + b.fillTriangles(pts, func(x, y int) { + pos := [2]float64{float64(x), float64(y)} + tfptx := pos[0]*ip.data.Transform[0] + pos[1]*ip.data.Transform[1] + ip.data.Transform[2] + tfpty := pos[0]*ip.data.Transform[3] + pos[1]*ip.data.Transform[4] + ip.data.Transform[5] + + if !rx && (tfptx < 0 || tfptx >= fw) { + return + } + if !ry && (tfpty < 0 || tfpty >= fh) { + return + } + + mx := int(math.Floor(tfptx)) % w + if mx < 0 { + mx += w + } + my := int(math.Floor(tfpty)) % h + if my < 0 { + my += h + } + + col := mip.At(mx, my) + b.Image.SetRGBA(x, y, mix(col, b.Image.RGBAAt(x, y))) + }) } else { b.fillTriangles(pts, func(x, y int) { b.Image.SetRGBA(x, y, mix(style.Color, b.Image.RGBAAt(x, y))) diff --git a/canvas_test.go b/canvas_test.go index 7714682..6725470 100644 --- a/canvas_test.go +++ b/canvas_test.go @@ -585,6 +585,20 @@ func TestImagePattern(t *testing.T) { }) } +func TestImagePattern2(t *testing.T) { + run(t, func(cv *canvas.Canvas) { + ptrn := cv.CreatePattern("testdata/cat.jpg", canvas.NoRepeat) + ptrn.SetTransform([6]float64{0, 0.1, 0.1, 0, 0, 0}) + + cv.Translate(50, 50) + cv.Scale(0.95, 1.05) + cv.Rotate(-math.Pi * 0.1) + + cv.SetFillStyle(ptrn) + cv.FillRect(-40, -40, 80, 80) + }) +} + func TestShadow(t *testing.T) { run(t, func(cv *canvas.Canvas) { cv.SetFillStyle("#800") diff --git a/testdata/ImagePattern2.png b/testdata/ImagePattern2.png new file mode 100755 index 0000000000000000000000000000000000000000..3f766a1541f74f00fb7cf17520c7c0f7631e2fb4 GIT binary patch literal 4235 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 literal 0 HcmV?d00001