package typeset import "image" import "unicode" import "image/draw" import "image/color" import "golang.org/x/image/math/fixed" // Drawer is an extended TypeSetter that is able to draw text. Much like // TypeSetter, It has no constructor and its zero value can be used safely. type Drawer struct { TypeSetter } // Draw draws the drawer's text onto the specified canvas at the given offset. func (drawer Drawer) Draw ( destination draw.Image, col color.Color, offset image.Point, ) ( updatedRegion image.Rectangle, ) { source := image.NewUniform(col) drawer.ForRunes (func ( index int, char rune, position fixed.Point26_6, ) bool { // leave empty space for space characters if unicode.IsSpace(char) { return true } dot := fixed.P ( offset.X + position.X.Round(), offset.Y + position.Y.Round()) destinationRectangle, mask, maskPoint, _, ok := drawer.face.Glyph(dot, char) // tofu if !ok { drawer.drawTofu(char, destination, col, dot) return true } // FIXME:? clip destination rectangle if we are on the cusp of // the maximum height. draw.DrawMask ( destination, destinationRectangle, source, image.Point { }, mask, maskPoint, draw.Over) updatedRegion = updatedRegion.Union(destinationRectangle) return true }) return } func (drawer Drawer) drawTofu ( char rune, destination draw.Image, col color.Color, position fixed.Point26_6, ) { bounds, _ := tofuBounds(drawer.face) rectBounds := image.Rect ( bounds.Min.X.Round(), bounds.Min.Y.Round(), bounds.Max.X.Round(), bounds.Max.Y.Round()).Add(image.Pt( position.X.Round(), position.Y.Round())) for x := rectBounds.Min.X; x < rectBounds.Max.X; x ++ { destination.Set(x, rectBounds.Min.Y, col) } for y := rectBounds.Min.Y; y < rectBounds.Max.Y; y ++ { destination.Set(rectBounds.Min.X, y, col) destination.Set(rectBounds.Max.X - 1, y, col) } for x := rectBounds.Min.X; x < rectBounds.Max.X; x ++ { destination.Set(x, rectBounds.Max.Y - 1, col) } }