func drawText(font *truetype.Font, c *freetype.Context, color color.Color, rgba *image.RGBA, text string) (int, int) { fg := image.NewUniform(color) bg := image.Transparent draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c.SetFont(font) c.SetDst(rgba) c.SetSrc(fg) c.SetClip(rgba.Bounds()) // height is the fraction of the font that is above the line, 1.0 would mean // that the font never falls below the line // TODO: wtf - this is all wrong! // fix fonts - we can't change the font size easily height := 1.3 pt := freetype.Pt(0, int(float64(c.PointToFixed(*size)>>8)*height)) adv, _ := c.DrawString(text, pt) pt.X += adv.X py := int(float64(pt.Y>>8)/height + 0.01) return int(pt.X >> 8), py }
// CenterX returns the Point at which string s will be centered within rect r // along the X coordinate when passed to c.DrawString. The Y coordinate will be 0. // Clip is set to r before returning. func CenterX(c *freetype.Context, s string, r image.Rectangle) (fixed.Point26_6, error) { w, err := DrawWidth(c, s) c.SetClip(r) if err != nil { return fixed.Point26_6{}, err } half := Int26_6(0.5) xmin := freetype.Pt(r.Min.X, 0) return freetype.Pt(r.Dx(), 0).Mul(half).Sub(w.Mul(half)).Add(xmin), nil }
func NewFontFace(path string, size float64, fg, bg color.Color) (fontface *FontFace, err error) { var ( font *truetype.Font fontbytes []byte bounds truetype.Bounds context *freetype.Context scale float32 ) if fontbytes, err = ioutil.ReadFile(path); err != nil { return } if font, err = freetype.ParseFont(fontbytes); err != nil { return } bounds = font.Bounds(1) fmt.Printf("bounds %v\n", bounds) context = freetype.NewContext() context.SetFont(font) context.SetFontSize(size) context.SetDPI(72) scale = float32(context.PointToFixed(size) / 64) fontface = &FontFace{ font: font, charw: scale * float32(bounds.XMax-bounds.XMin), charh: scale * float32(bounds.YMax-bounds.YMin), fg: fg, bg: bg, context: context, } return }
func NewFontFace(path string, pixels float32, fg, bg color.Color) (fontface *FontFace, err error) { var ( font *truetype.Font fontbytes []byte bounds fixed.Rectangle26_6 context *freetype.Context points float32 dpi float32 = 96 ) if fontbytes, err = ioutil.ReadFile(path); err != nil { return } if font, err = freetype.ParseFont(fontbytes); err != nil { return } points = pixels * 72 / dpi bounds = font.Bounds(fixed.I(int(pixels))) context = freetype.NewContext() context.SetFont(font) context.SetFontSize(float64(points)) context.SetDPI(float64(dpi)) fontface = &FontFace{ font: font, charw: float32(bounds.Max.X-bounds.Min.X) / 64, charh: float32(bounds.Max.Y-bounds.Min.Y) / 64, offy: float32(bounds.Min.Y) / 64, fg: fg, bg: bg, context: context, } return }
// DrawWidth simulates drawing s using Context c and returns the raster.Point // where X is the width of the drawn string. The context's src and dst are // unused, but the font should already be set. Clip is set to an empty Rectangle // and should be reset afterwards. func DrawWidth(c *freetype.Context, s string) (fixed.Point26_6, error) { // nil rectangle is always empty so draw is never called c.SetClip(image.Rectangle{}) p, err := c.DrawString(s, fixed.Point26_6{}) // 0,0 return p, err }