github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/emask/impl_default.go (about) 1 package emask 2 3 import "image" 4 import "image/draw" 5 6 import "golang.org/x/image/vector" 7 import "golang.org/x/image/math/fixed" 8 import "golang.org/x/image/font/sfnt" 9 10 // The DefaultRasterizer is a wrapper to make [golang.org/x/image/vector.Rasterizer] 11 // conform to the [Rasterizer] interface. 12 type DefaultRasterizer struct { 13 rasterizer vector.Rasterizer 14 rectOffset image.Point // offset to align the final mask rect to the bounds 15 normOffset fixed.Point26_6 // offset to normalize points to the positive 16 // quadrant starting from the fractional coords 17 18 cacheSignature uint64 19 onChange func(Rasterizer) 20 21 // Notice that the x/image/vector rasterizer expects coords in the 22 // positive quadrant, which is why we need so many offsets here. 23 } 24 25 // Satisfies the [UserCfgCacheSignature] interface. 26 func (self *DefaultRasterizer) SetHighByte(value uint8) { 27 self.cacheSignature = uint64(value) << 56 28 if self.onChange != nil { 29 self.onChange(self) 30 } 31 } 32 33 // Satisfies the [Rasterizer] interface. 34 func (self *DefaultRasterizer) SetOnChangeFunc(onChange func(Rasterizer)) { 35 self.onChange = onChange 36 } 37 38 // Satisfies the [Rasterizer] interface. 39 func (self *DefaultRasterizer) CacheSignature() uint64 { 40 return self.cacheSignature 41 } 42 43 // Moves the current position to the given point. 44 func (self *DefaultRasterizer) MoveTo(point fixed.Point26_6) { 45 x, y := self.fixedToFloat32Coords(point) 46 self.rasterizer.MoveTo(x, y) 47 } 48 49 // Creates a straight boundary from the current position to the given point. 50 func (self *DefaultRasterizer) LineTo(point fixed.Point26_6) { 51 x, y := self.fixedToFloat32Coords(point) 52 self.rasterizer.LineTo(x, y) 53 } 54 55 // Creates a quadratic Bézier curve (also known as a conic Bézier curve) 56 // to the given target passing through the given control point. 57 func (self *DefaultRasterizer) QuadTo(control, target fixed.Point26_6) { 58 cx, cy := self.fixedToFloat32Coords(control) 59 tx, ty := self.fixedToFloat32Coords(target) 60 self.rasterizer.QuadTo(cx, cy, tx, ty) 61 } 62 63 // Creates a cubic Bézier curve to the given target passing through 64 // the given control points. 65 func (self *DefaultRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6) { 66 cax, cay := self.fixedToFloat32Coords(controlA) 67 cbx, cby := self.fixedToFloat32Coords(controlB) 68 tx, ty := self.fixedToFloat32Coords(target) 69 self.rasterizer.CubeTo(cax, cay, cbx, cby, tx, ty) 70 } 71 72 // Satisfies the Rasterizer interface. 73 func (self *DefaultRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error) { 74 // prepare rasterizer 75 var size image.Point 76 size, self.normOffset, self.rectOffset = figureOutBounds(outline.Bounds(), fract) 77 self.rasterizer.Reset(size.X, size.Y) 78 self.rasterizer.DrawOp = draw.Src 79 80 // allocate glyph mask 81 mask := image.NewAlpha(self.rasterizer.Bounds()) 82 83 // process outline 84 processOutline(self, outline) 85 86 // since the source texture is a uniform (an image that returns the same 87 // color for any coordinate), the value of the point at which we want to 88 // start sampling the texture (the fourth parameter) is unimportant. 89 self.rasterizer.Draw(mask, mask.Bounds(), image.Opaque, image.Point{}) 90 91 // translate the mask to its final position 92 mask.Rect = mask.Rect.Add(self.rectOffset) 93 return mask, nil 94 } 95 96 func (self *DefaultRasterizer) fixedToFloat32Coords(point fixed.Point26_6) (float32, float32) { 97 x := float32(point.X+self.normOffset.X) / 64 98 y := float32(point.Y+self.normOffset.Y) / 64 99 return x, y 100 }