// DrawString draws s at p and returns p advanced by the text extent. The text // is placed so that the left edge of the em square of the first character of s // and the baseline intersect at p. The majority of the affected pixels will be // above and to the right of the point, but some may be below or to the left. // For example, drawing a string that starts with a 'J' in an italic font may // affect pixels below and left of the point. // p is a raster.Point and can therefore represent sub-pixel positions. func (c *Context) DrawString(s string, p raster.Point) (raster.Point, error) { if c.font == nil { return raster.Point{}, errors.New("freetype: DrawText called with a nil font") } prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := c.font.Index(rune) if hasPrev { kern := raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2 if c.hinting != NoHinting { kern = (kern + 128) &^ 255 } p.X += kern } advanceWidth, mask, offset, err := c.glyph(index, p) if err != nil { return raster.Point{}, err } p.X += advanceWidth glyphRect := mask.Bounds().Add(offset) dr := c.clip.Intersect(glyphRect) if !dr.Empty() { mp := image.Point{0, dr.Min.Y - glyphRect.Min.Y} draw.DrawMask(c.dst, dr, c.src, image.ZP, mask, mp, draw.Over) } prev, hasPrev = index, true } return p, nil }
// GetStringBounds returns the approximate pixel bounds of the string s at x, y. // The the left edge of the em square of the first character of s // and the baseline intersect at 0, 0 in the returned coordinates. // Therefore the top and left coordinates may well be negative. func (gc *ImageGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64) { font, err := gc.loadCurrentFont() if err != nil { log.Println(err) return 0, 0, 0, 0 } top, left, bottom, right = 10e6, 10e6, -10e6, -10e6 cursor := 0.0 prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := font.Index(rune) if hasPrev { cursor += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index)) } if err := gc.glyphBuf.Load(gc.Current.font, gc.Current.scale, index, truetype.NoHinting); err != nil { log.Println(err) return 0, 0, 0, 0 } e0 := 0 for _, e1 := range gc.glyphBuf.End { ps := gc.glyphBuf.Point[e0:e1] for _, p := range ps { x, y := pointToF64Point(p) top = math.Min(top, y) bottom = math.Max(bottom, y) left = math.Min(left, x+cursor) right = math.Max(right, x+cursor) } } cursor += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth) prev, hasPrev = index, true } return left, top, right, bottom }
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) }
// CreateStringPath creates a path from the string s at x, y, and returns the string width. // The text is placed so that the left edge of the em square of the first character of s // and the baseline intersect at x, y. The majority of the affected pixels will be // above and to the right of the point, but some may be below or to the left. // For example, drawing a string that starts with a 'J' in an italic font may // affect pixels below and left of the point. func (gc *ImageGraphicContext) CreateStringPath(s string, x, y float64) float64 { font, err := gc.loadCurrentFont() if err != nil { log.Println(err) return 0.0 } startx := x prev, hasPrev := truetype.Index(0), false for _, rune := range s { index := font.Index(rune) if hasPrev { x += fUnitsToFloat64(font.Kerning(gc.Current.scale, prev, index)) } err := gc.drawGlyph(index, x, y) if err != nil { log.Println(err) return startx - x } x += fUnitsToFloat64(font.HMetric(gc.Current.scale, index).AdvanceWidth) prev, hasPrev = index, true } return x - startx }