func (ig *ImageGraphics) TextLen(s string, font chart.Font) int { c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) fontsize := ig.relFontsizeToPixel(font.Size) c.SetFontSize(fontsize) scale := int32(fontsize * dpi * (64.0 / 72.0)) var p raster.Point prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := ig.font.Index(rune) if hasPrev { p.X += raster.Fix32(ig.font.Kerning(scale, prev, index)) << 2 } p.X += raster.Fix32(ig.font.HMetric(scale, index).AdvanceWidth) << 2 prev, hasPrev = index, true } return int((p.X + 127) / 256) }
// textBox renders t into a tight fitting image func (ig *ImageGraphics) textBox(t string, font chart.Font) image.Image { // Initialize the context. fg := image.NewUniform(color.Alpha{0xff}) bg := image.NewUniform(color.Alpha{0x00}) width := ig.TextLen(t, font) size := ig.relFontsizeToPixel(font.Size) bb := ig.font.Bounds(int32(size)) // TODO: Ugly, manual, heuristic hack to get "nicer" text for common latin characters bb.YMin++ if size >= 15 { bb.YMin++ bb.YMax-- } if size >= 20 { bb.YMax-- } if size >= 25 { bb.YMin++ bb.YMax-- } dy := int(bb.YMax - bb.YMin) canvas := image.NewAlpha(image.Rect(0, 0, width, dy)) draw.Draw(canvas, canvas.Bounds(), bg, image.ZP, draw.Src) c := freetype.NewContext() c.SetDPI(dpi) c.SetFont(ig.font) c.SetFontSize(size) c.SetClip(canvas.Bounds()) c.SetDst(canvas) c.SetSrc(fg) // Draw the text. pt := freetype.Pt(0, dy+int(bb.YMin)-1) extent, err := c.DrawString(t, pt) if err != nil { log.Println(err) return nil } // log.Printf("text %q, extent: %v", t, extent) return canvas.SubImage(image.Rect(0, 0, int((extent.X+127)/256), dy)) }