Exemplo n.º 1
0
func (t *Text) GetFontMetrics(scale int) FontMetrics {
	// Adapted from: https://code.google.com/p/plotinum/

	// Converts truetype.FUnit to float64
	fUnit2Float64 := float64(t.size) / float64(t.font.FUnitsPerEm())

	width := 0
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range t.content {
		index := t.font.Index(rune)
		if hasPrev {
			width += int(t.font.Kerning(t.font.FUnitsPerEm(), prev, index))
		}
		width += int(t.font.HMetric(t.font.FUnitsPerEm(), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	widthFloat := float64(width) * fUnit2Float64 * float64(scale)

	bounds := t.font.Bounds(t.font.FUnitsPerEm())
	height := float64(bounds.YMax-bounds.YMin) * fUnit2Float64 * float64(scale)
	ascent := float64(bounds.YMax) * fUnit2Float64 * float64(scale)
	descent := float64(bounds.YMin) * fUnit2Float64 * float64(scale)

	return FontMetrics{widthFloat, height, ascent, descent}
}
Exemplo n.º 2
0
// GetStringBounds returns the approximate pixel bounds of the string s at x, y.
// 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(int32(gc.Current.Scale), prev, index))
		}
		if err := gc.glyphBuf.Load(gc.Current.Font, int32(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(int32(gc.Current.Scale), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	return left, top, right, bottom
}
Exemplo n.º 3
0
// Implements the Font interface.
func (f *TruetypeFont) Measure(i FontIndex) (*GlyphMetrics, error) {
	// Load into glyph buffer.
	if f.buf == nil {
		f.buf = truetype.NewGlyphBuf()
	}
	index := truetype.Index(i)
	scale := f.Font.FUnitsPerEm()
	err := f.buf.Load(f.Font, scale, index, f.Hinting)
	if err != nil {
		return nil, err
	}

	hMetric := f.Font.HMetric(scale, index)
	vMetric := f.Font.VMetric(scale, index)
	b := f.buf.B
	return &GlyphMetrics{
		Bounds: GlyphBounds{
			Min: Point{X: int(b.XMin), Y: int(b.YMin)},
			Max: Point{X: int(b.XMax), Y: int(b.YMax)},
		},
		BearingX: int(hMetric.LeftSideBearing),
		AdvanceX: int(hMetric.AdvanceWidth),
		BearingY: int(vMetric.TopSideBearing),
		AdvanceY: int(vMetric.AdvanceHeight),
	}, nil
}
Exemplo n.º 4
0
// 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 {
			p.X += raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
		}
		mask, offset, err := c.glyph(index, p)
		if err != nil {
			return raster.Point{}, err
		}
		p.X += raster.Fix32(c.font.HMetric(c.scale, index).AdvanceWidth) << 2
		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
}
Exemplo n.º 5
0
// MeasureString returns the width and height of the string in s, in terms of
// raster.Fix32 units.
//
// BUG(burntsushi): I don't think negative x-coordinates are handled at all, so
// that the bounding box could be smaller than what it actually is. (i.e., the
// first letter is an italic 'J'.)
func (c *Context) MeasureString(s string) (raster.Fix32, raster.Fix32, error) {
	if c.font == nil {
		return 0, 0, errors.New("freetype: DrawText called with a nil font")
	}

	var width, height, heightMax raster.Fix32
	oneLine := c.PointToFix32(c.fontSize) & 0xff
	height = c.PointToFix32(c.fontSize)
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := c.font.Index(rune)
		if hasPrev {
			width += raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
		}

		if err := c.glyphBuf.Load(c.font, c.scale, index, truetype.NoHinting); err != nil {
			return 0, 0, err
		}
		ymax := oneLine - raster.Fix32(c.glyphBuf.B.YMin<<2) + 0xff
		heightMax = max(heightMax, ymax)

		width += raster.Fix32(c.font.HMetric(c.scale, index).AdvanceWidth) << 2
		prev, hasPrev = index, true
	}

	if heightMax > 0 {
		height += heightMax
	}
	return width, height, nil
}
Exemplo n.º 6
0
Arquivo: font.go Projeto: velour/ui
func (f *font) width(s string) int {
	em := f.FUnitsPerEm()
	var width int32
	prev, hasPrev := truetype.Index(0), false
	for _, r := range s {
		index := f.Index(r)
		if hasPrev {
			width += f.Kerning(em, prev, index)
		}
		width += f.HMetric(em, index).AdvanceWidth
		prev, hasPrev = index, true
	}
	return int(float64(width)*f.scale() + 0.5)
}
Exemplo n.º 7
0
// Width returns width of a string when drawn using the font.
func (f *Font) Width(s string) Length {
	// scale converts truetype.FUnit to float64
	scale := f.Size / Points(float64(f.font.FUnitsPerEm()))

	width := 0
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := f.font.Index(rune)
		if hasPrev {
			width += int(f.font.Kerning(f.font.FUnitsPerEm(), prev, index))
		}
		width += int(f.font.HMetric(f.font.FUnitsPerEm(), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	return Points(float64(width)) * scale
}
Exemplo n.º 8
0
func (ig *ImageGraphics) TextLen(s string, font chart.Font) int {
	c := freetype.NewContext()
	c.SetDPI(dpi)
	c.SetFont(ig.font)
	c.SetFontSize(ig.relFontsizeToPixel(font.Size))

	var p raster.Point
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := ig.font.Index(rune)
		if hasPrev {
			p.X += c.FUnitToFix32(int(ig.font.Kerning(prev, index)))
		}
		p.X += c.FUnitToFix32(int(ig.font.HMetric(index).AdvanceWidth))
		prev, hasPrev = index, true
	}
	return int((p.X + 127) / 256)
}
Exemplo n.º 9
0
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)
}
Exemplo n.º 10
0
func (f Font) textSize(s string) (int, int, int) {
	// scale converts truetype.FUnit to float64
	scale := f.sz / float64(f.fnt.FUnitsPerEm()) * (dpi / ptInch)

	width := 0
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := f.fnt.Index(rune)
		if hasPrev {
			width += int(f.fnt.Kerning(f.fnt.FUnitsPerEm(), prev, index))
		}
		width += int(f.fnt.HMetric(f.fnt.FUnitsPerEm(), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	width = int(float64(width)*scale + 0.5)

	b := f.fnt.Bounds(f.fnt.FUnitsPerEm())
	height := int(float64(b.YMax-b.YMin)*scale + 0.5)
	descent := int(float64(b.YMin)*scale + 0.5)
	return width, height, descent
}
Exemplo n.º 11
0
// 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(int32(gc.Current.Scale), prev, index))
		}
		err := gc.drawGlyph(index, x, y)
		if err != nil {
			log.Println(err)
			return startx - x
		}
		x += fUnitsToFloat64(font.HMetric(int32(gc.Current.Scale), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	return x - startx
}
Exemplo n.º 12
0
// Implements the Font interface.
func (f *TruetypeFont) Lookup(i FontIndex) (glyphData interface{}, err error) {
	// Load into glyph buffer.
	if f.buf == nil {
		f.buf = truetype.NewGlyphBuf()
	}
	index := truetype.Index(i)
	scale := f.Font.FUnitsPerEm()
	err = f.buf.Load(f.Font, scale, index, f.Hinting)
	if err != nil {
		return nil, err
	}

	// Expand each contour.
	var (
		glyph QuadGlyph
		e0    int
	)
	for _, e1 := range f.buf.End {
		f.expandContour(&glyph, f.buf.Point[e0:e1])
		e0 = e1
	}
	return glyph, nil
}
Exemplo n.º 13
0
// Implements the Font interface.
func (f *TruetypeFont) Kerning(a, b FontIndex) (x, y int) {
	x = int(f.Font.Kerning(f.Font.FUnitsPerEm(), truetype.Index(a), truetype.Index(b)))
	y = -1
	return
}