package typeset import "image" import "unicode" import "image/draw" import "image/color" import "golang.org/x/image/font" import "golang.org/x/image/math/fixed" // Draw draws the contents of a TypeSetter to an image at the given offset. It // returns a rectangle containing all pixels in the image that were updated. func Draw (destination draw.Image, setter *TypeSetter, offset fixed.Point26_6, col color.Color) image.Rectangle { source := image.NewUniform(col) face := setter.Face() var updatedRegion image.Rectangle bounds := destination.Bounds() setter.Runes()(func (position fixed.Point26_6, run rune) bool { // leave empty space for space characters if unicode.IsSpace(run) { return true } dot := offset.Add(position) destinationRectangle, mask, maskPoint, _, ok := face.Glyph(dot, run) if ok { // don't bother drawing runes that are out of bounds if destinationRectangle.Min.Y > bounds.Max.Y { return false } if destinationRectangle.Intersect(bounds).Empty() { return true } // draw rune draw.DrawMask ( destination, destinationRectangle, source, image.Point { }, mask, maskPoint, draw.Over) } else { // draw tofu drawTofu(run, destination, dot, face, col) } updatedRegion = updatedRegion.Union(destinationRectangle) return true }) return updatedRegion } // DrawBounds draws the LayoutBounds, MinimumSize, and LayoutBoundsSpace of a // TypeSetter to the given image using these colors: // - Red: LayoutBounds // - Green: MinimumSize // - Blue: LayoutBoundsSpace func DrawBounds (destination draw.Image, setter *TypeSetter, offset fixed.Point26_6) { blue := color.RGBA { B: 255, A: 255 } red := color.RGBA { R: 255, A: 255 } green := color.RGBA { G: 255, A: 255 } layoutBoundsSpace := setter.LayoutBoundsSpace() layoutBounds := setter.LayoutBounds() minimum := setter.MinimumSize() minimumRect := roundRect(fixed.Rectangle26_6 { Max: minimum }.Add(offset).Add(layoutBounds.Min)) drawRectangleOutline(destination, minimumRect, green) drawRectangleOutline(destination, roundRect(layoutBoundsSpace.Add(offset)), blue) drawRectangleOutline(destination, roundRect(layoutBounds.Add(offset)), red) } func drawTofu ( char rune, destination draw.Image, position fixed.Point26_6, face font.Face, col color.Color, ) { bounds, _ := tofuBounds(face) rectBounds := roundRect(bounds).Add(image.Pt ( position.X.Round(), position.Y.Round())) drawRectangleOutline(destination, rectBounds, col) } func drawRectangleOutline (destination draw.Image, bounds image.Rectangle, col color.Color) { for x := bounds.Min.X; x < bounds.Max.X; x ++ { destination.Set(x, bounds.Min.Y, col) } for y := bounds.Min.Y; y < bounds.Max.Y; y ++ { destination.Set(bounds.Min.X, y, col) destination.Set(bounds.Max.X - 1, y, col) } for x := bounds.Min.X; x < bounds.Max.X; x ++ { destination.Set(x, bounds.Max.Y - 1, col) } } func roundRect (rectangle fixed.Rectangle26_6) image.Rectangle { return image.Rect ( rectangle.Min.X.Round(), rectangle.Min.Y.Round(), rectangle.Max.X.Round(), rectangle.Max.Y.Round()) }