Beispiel #1
0
// rasterize returns the advance width, glyph mask and integer-pixel offset
// to render the given glyph at the given sub-pixel offsets.
// The 26.6 fixed point arguments fx and fy must be in the range [0, 1).
func (c *Context) rasterize(glyph truetype.Index, fx, fy fixed.Int26_6) (
	fixed.Int26_6, *image.Alpha, image.Point, error) {

	if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil {
		return 0, nil, image.Point{}, err
	}
	// Calculate the integer-pixel bounds for the glyph.
	xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6
	ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6
	xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6
	ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6
	if xmin > xmax || ymin > ymax {
		return 0, nil, image.Point{}, errors.New("freetype: negative sized glyph")
	}
	// A TrueType's glyph's nodes can have negative co-ordinates, but the
	// rasterizer clips anything left of x=0 or above y=0. xmin and ymin are
	// the pixel offsets, based on the font's FUnit metrics, that let a
	// negative co-ordinate in TrueType space be non-negative in rasterizer
	// space. xmin and ymin are typically <= 0.
	fx -= fixed.Int26_6(xmin << 6)
	fy -= fixed.Int26_6(ymin << 6)
	// Rasterize the glyph's vectors.
	c.r.Clear()
	e0 := 0
	for _, e1 := range c.glyphBuf.Ends {
		c.drawContour(c.glyphBuf.Points[e0:e1], fx, fy)
		e0 = e1
	}
	a := image.NewAlpha(image.Rect(0, 0, xmax-xmin, ymax-ymin))
	c.r.Rasterize(raster.NewAlphaSrcPainter(a))
	return c.glyphBuf.AdvanceWidth, a, image.Point{xmin, ymin}, nil
}
Beispiel #2
0
func TestNewFontFaceItalic(t *testing.T) {
	base, _ := NewFontWithName("Verdana")
	defer base.Close()

	face := base.Face(text.FaceData{
		Size:  20.0,
		Style: font.StyleItalic,
	})
	defer face.Close()

	if data := face.Data(); data != (text.FaceData{
		Size:    20.0,
		DPI:     72.0,
		Hinting: font.HintingNone,
		Stretch: font.StretchNormal,
		Style:   font.StyleItalic,
		Weight:  font.WeightNormal,
	}) {
		t.Error("invalid font face data:", data)
	}

	if metrics := face.Metrics(); metrics != (font.Metrics{
		Height:  fixed.Int26_6((24 << 6) | 18),
		Ascent:  fixed.Int26_6((20 << 6) | 6),
		Descent: fixed.Int26_6((4 << 6) | 12),
	}) {
		t.Error("invalid font face metrics:", metrics)
	}

	if s := fmt.Sprint(face); s != "Verdana Italic { size: 20, DPI: 72 }" {
		t.Error("invalid face representation:", s)
	}
}
Beispiel #3
0
func p(n node) fixed.Point26_6 {
	x, y := 20+n.x/4, 380-n.y/4
	return fixed.Point26_6{
		X: fixed.Int26_6(x << 6),
		Y: fixed.Int26_6(y << 6),
	}
}
Beispiel #4
0
// pRot45CCW returns the vector p rotated counter-clockwise by 45 degrees.
//
// Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}.
func pRot45CCW(p fixed.Point26_6) fixed.Point26_6 {
	// 181/256 is approximately 1/√2, or sin(π/4).
	px, py := int64(p.X), int64(p.Y)
	qx := (+px + py) * 181 / 256
	qy := (-px + py) * 181 / 256
	return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)}
}
Beispiel #5
0
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
// the given index. yMax is the top of the glyph's bounding box.
func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) {
	j := int(i)
	if j < 0 || f.nGlyph <= j {
		return VMetric{}
	}
	if 4*j+4 <= len(f.vmtx) {
		return VMetric{
			AdvanceHeight:  fixed.Int26_6(u16(f.vmtx, 4*j)),
			TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))),
		}
	}
	// The OS/2 table has grown over time.
	// https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html
	// says that it was originally 68 bytes. Optional fields, including
	// the ascender and descender, are described at
	// http://www.microsoft.com/typography/otspec/os2.htm
	if len(f.os2) >= 72 {
		sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68)))
		sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70)))
		return VMetric{
			AdvanceHeight:  sTypoAscender - sTypoDescender,
			TopSideBearing: sTypoAscender - yMax,
		}
	}
	return VMetric{
		AdvanceHeight:  fixed.Int26_6(f.fUnitsPerEm),
		TopSideBearing: 0,
	}
}
Beispiel #6
0
// 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 *GraphicContext) 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(int32(font.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)))
		}
		if err := gc.glyphBuf.Load(gc.Current.Font, fixed.Int26_6(gc.Current.Scale), index, expfont.HintingNone); 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(int32(font.HMetric(fixed.Int26_6(gc.Current.Scale), index).AdvanceWidth))
		prev, hasPrev = index, true
	}
	return left, top, right, bottom
}
Beispiel #7
0
func TestGlyphBounds(t *testing.T) {
	base, _ := NewFontWithName("Verdana")
	defer base.Close()

	face := base.Face(text.FaceData{
		Size: 20.0,
	})
	defer face.Close()

	bounds, advance, ok := face.GlyphBounds('A')

	if !ok {
		t.Error("failed to get glyph bounds for 'A'")
		return
	}

	if advance != fixed.Int26_6((13<<6)|43) {
		t.Error("invalid glyph advance for 'A':", advance)
		return
	}

	if bounds != (fixed.Rectangle26_6{
		Min: fixed.Point26_6{
			X: fixed.Int26_6((0 << 6) | 16),
			Y: fixed.Int26_6(0),
		},
		Max: fixed.Point26_6{
			X: fixed.Int26_6((13 << 6) | 26),
			Y: fixed.Int26_6((14 << 6) | 34),
		},
	}) {
		t.Error("invalid glyph bounds for 'A':", bounds)
	}
}
Beispiel #8
0
// TestParse tests that the luxisr.ttf metrics and glyphs are parsed correctly.
// The numerical values can be manually verified by examining luxisr.ttx.
func TestParse(t *testing.T) {
	f, _, err := parseTestdataFont("luxisr")
	if err != nil {
		t.Fatal(err)
	}
	if got, want := f.FUnitsPerEm(), int32(2048); got != want {
		t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
	}
	fupe := fixed.Int26_6(f.FUnitsPerEm())
	if got, want := f.Bounds(fupe), mkBounds(-441, -432, 2024, 2033); got != want {
		t.Errorf("Bounds: got %v, want %v", got, want)
	}

	i0 := f.Index('A')
	i1 := f.Index('V')
	if i0 != 36 || i1 != 57 {
		t.Fatalf("Index: i0, i1 = %d, %d, want 36, 57", i0, i1)
	}
	if got, want := f.HMetric(fupe, i0), (HMetric{1366, 19}); got != want {
		t.Errorf("HMetric: got %v, want %v", got, want)
	}
	if got, want := f.VMetric(fupe, i0), (VMetric{2465, 553}); got != want {
		t.Errorf("VMetric: got %v, want %v", got, want)
	}
	if got, want := f.Kern(fupe, i0, i1), fixed.Int26_6(-144); got != want {
		t.Errorf("Kern: got %v, want %v", got, want)
	}

	g := &GlyphBuf{}
	err = g.Load(f, fupe, i0, font.HintingNone)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	g0 := &GlyphBuf{
		Bounds: g.Bounds,
		Points: g.Points,
		Ends:   g.Ends,
	}
	g1 := &GlyphBuf{
		Bounds: mkBounds(19, 0, 1342, 1480),
		Points: []Point{
			{19, 0, 51},
			{581, 1480, 1},
			{789, 1480, 51},
			{1342, 0, 1},
			{1116, 0, 35},
			{962, 410, 3},
			{368, 410, 33},
			{214, 0, 3},
			{428, 566, 19},
			{904, 566, 33},
			{667, 1200, 3},
		},
		Ends: []int{8, 11},
	}
	if got, want := fmt.Sprint(g0), fmt.Sprint(g1); got != want {
		t.Errorf("GlyphBuf:\ngot  %v\nwant %v", got, want)
	}
}
Beispiel #9
0
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 {
	if x >= 0 {
		x += fixed.Int26_6(f.fUnitsPerEm) / 2
	} else {
		x -= fixed.Int26_6(f.fUnitsPerEm) / 2
	}
	return x / fixed.Int26_6(f.fUnitsPerEm)
}
Beispiel #10
0
// Metrics satisfies the font.Face interface.
func (a *face) Metrics() font.Metrics {
	scale := float64(a.scale)
	fupe := float64(a.f.FUnitsPerEm())
	return font.Metrics{
		Height:  a.scale,
		Ascent:  fixed.Int26_6(math.Ceil(scale * float64(+a.f.ascent) / fupe)),
		Descent: fixed.Int26_6(math.Ceil(scale * float64(-a.f.descent) / fupe)),
	}
}
Beispiel #11
0
// pNorm returns the vector p normalized to the given length, or zero if p is
// degenerate.
func pNorm(p fixed.Point26_6, length fixed.Int26_6) fixed.Point26_6 {
	d := pLen(p)
	if d == 0 {
		return fixed.Point26_6{}
	}
	s, t := int64(length), int64(d)
	x := int64(p.X) * s / t
	y := int64(p.Y) * s / t
	return fixed.Point26_6{fixed.Int26_6(x), fixed.Int26_6(y)}
}
Beispiel #12
0
func (s *Sparkline) scale(idx int, n, min, max float32, dx, dy int) fixed.Point26_6 {
	// 26.6 format, so shift by 6
	x := float32(idx) / float32(s.items) * float32(dx)
	y := (1.0 - ((n - min) / max)) * float32(dy)
	p := fixed.Point26_6{
		X: fixed.Int26_6(x)<<6 | (fixed.Int26_6(x*64) & (1<<6 - 1)),
		Y: fixed.Int26_6(y)<<6 | (fixed.Int26_6(y*64) & (1<<6 - 1)),
	}
	return p
}
Beispiel #13
0
// NewFace returns a new font.Face for the given Font.
func NewFace(f *Font, opts *Options) font.Face {
	a := &face{
		f:          f,
		hinting:    opts.hinting(),
		scale:      fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)),
		glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()),
	}
	a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX()
	a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY()

	// Fill the cache with invalid entries. Valid glyph cache entries have fx
	// and fy in the range [0, 64). Valid index cache entries have rune >= 0.
	for i := range a.glyphCache {
		a.glyphCache[i].key.fy = 0xff
	}
	for i := range a.indexCache {
		a.indexCache[i].rune = -1
	}

	// Set the rasterizer's bounds to be big enough to handle the largest glyph.
	b := f.Bounds(a.scale)
	xmin := +int(b.Min.X) >> 6
	ymin := -int(b.Max.Y) >> 6
	xmax := +int(b.Max.X+63) >> 6
	ymax := -int(b.Min.Y-63) >> 6
	a.maxw = xmax - xmin
	a.maxh = ymax - ymin
	a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache)))
	a.r.SetBounds(a.maxw, a.maxh)
	a.p = facePainter{a}

	return a
}
Beispiel #14
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.Kern(fixed.Int26_6(f.font.FUnitsPerEm()), prev, index))
		}
		width += int(f.font.HMetric(fixed.Int26_6(f.font.FUnitsPerEm()), index).AdvanceWidth)
		prev, hasPrev = index, true
	}
	return Points(float64(width)) * scale
}
Beispiel #15
0
func (f *face) Glyph(dot fixed.Point26_6, r rune) (
	newDot fixed.Point26_6, dr image.Rectangle, mask image.Image, maskp image.Point, ok bool) {

	r -= f.firstRune
	if r < 0 || f.n <= int(r) {
		return fixed.Point26_6{}, image.Rectangle{}, nil, image.Point{}, false
	}
	i := &f.fontchars[r+0]
	j := &f.fontchars[r+1]

	newDot = fixed.Point26_6{
		X: dot.X + fixed.Int26_6(i.width)<<6,
		Y: dot.Y,
	}
	minX := int(dot.X+32)>>6 + int(i.left)
	minY := int(dot.Y+32)>>6 + int(i.top) - f.ascent
	dr = image.Rectangle{
		Min: image.Point{
			X: minX,
			Y: minY,
		},
		Max: image.Point{
			X: minX + int(j.x-i.x),
			Y: minY + int(i.bottom) - int(i.top),
		},
	}
	return newDot, dr, f.img, image.Point{int(i.x), int(i.top)}, true
}
Beispiel #16
0
func Measure(r io.RuneReader, f font.Face) (size fixed.Point26_6, err error) {
	var char rune
	var prev rune

	w := fixed.Int26_6(0)
	m := f.Metrics()
	size.Y = m.Height + m.Descent

	for {
		if char, _, err = r.ReadRune(); err != nil {
			if err == io.EOF {
				err = nil
			}
			size.X = maxInt26_6(size.X, w)
			return
		}

		if char == '\n' {
			size.X = maxInt26_6(size.X, w)
			size.Y += m.Height
			w, prev = 0, 0
			continue
		}

		if prev != 0 {
			w += f.Kern(prev, char)
		}

		w += advance(f, char)
		prev = char
	}
}
Beispiel #17
0
// dotProduct returns the dot product of [x, y] and q. It is almost the same as
//	px := int64(x)
//	py := int64(y)
//	qx := int64(q[0])
//	qy := int64(q[1])
//	return fixed.Int26_6((px*qx + py*qy + 1<<13) >> 14)
// except that the computation is done with 32-bit integers to produce exactly
// the same rounding behavior as C Freetype.
func dotProduct(x, y fixed.Int26_6, q [2]f2dot14) fixed.Int26_6 {
	// Compute x*q[0] as 64-bit value.
	l := uint32((int32(x) & 0xFFFF) * int32(q[0]))
	m := (int32(x) >> 16) * int32(q[0])

	lo1 := l + (uint32(m) << 16)
	hi1 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo1 < l)

	// Compute y*q[1] as 64-bit value.
	l = uint32((int32(y) & 0xFFFF) * int32(q[1]))
	m = (int32(y) >> 16) * int32(q[1])

	lo2 := l + (uint32(m) << 16)
	hi2 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo2 < l)

	// Add them.
	lo := lo1 + lo2
	hi := hi1 + hi2 + bool2int32(lo < lo1)

	// Divide the result by 2^14 with rounding.
	s := hi >> 31
	l = lo + uint32(s)
	hi += s + bool2int32(l < lo)
	lo = l

	l = lo + 0x2000
	hi += bool2int32(l < lo)

	return fixed.Int26_6((uint32(hi) << 18) | (l >> 14))
}
Beispiel #18
0
func main() {
	flag.Parse()
	fmt.Printf("Loading fontfile %q\n", *fontfile)
	b, err := ioutil.ReadFile(*fontfile)
	if err != nil {
		log.Println(err)
		return
	}
	f, err := truetype.Parse(b)
	if err != nil {
		log.Println(err)
		return
	}
	fupe := fixed.Int26_6(f.FUnitsPerEm())
	printBounds(f.Bounds(fupe))
	fmt.Printf("FUnitsPerEm:%d\n\n", fupe)

	c0, c1 := 'A', 'V'

	i0 := f.Index(c0)
	hm := f.HMetric(fupe, i0)
	g := &truetype.GlyphBuf{}
	err = g.Load(f, fupe, i0, font.HintingNone)
	if err != nil {
		log.Println(err)
		return
	}
	fmt.Printf("'%c' glyph\n", c0)
	fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
	printGlyph(g)
	i1 := f.Index(c1)
	fmt.Printf("\n'%c', '%c' Kern:%d\n", c0, c1, f.Kern(fupe, i0, i1))
}
Beispiel #19
0
func (f *subface) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
	r -= f.firstRune
	if r < 0 || f.n <= int(r) {
		return 0, false
	}
	return fixed.Int26_6(f.fontchars[r].width) << 6, true
}
Beispiel #20
0
// https://code.google.com/p/plotinum/source/browse/vg/font.go#160
func widthOfString(font *truetype.Font, size float64, s string) float64 {
	// scale converts truetype.FUnit to float64
	scale := size / float64(font.FUnitsPerEm())

	width := 0
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := font.Index(rune)
		if hasPrev {
			width += int(font.Kern(fixed.Int26_6(font.FUnitsPerEm()), prev, index))
		}
		width += int(font.HMetric(fixed.Int26_6(font.FUnitsPerEm()), index).AdvanceWidth)
		prev, hasPrev = index, true
	}

	return float64(width) * scale
}
Beispiel #21
0
// unscaledHMetric returns the unscaled horizontal metrics for the glyph with
// the given index.
func (f *Font) unscaledHMetric(i Index) (h HMetric) {
	j := int(i)
	if j < 0 || f.nGlyph <= j {
		return HMetric{}
	}
	if j >= f.nHMetric {
		p := 4 * (f.nHMetric - 1)
		return HMetric{
			AdvanceWidth:    fixed.Int26_6(u16(f.hmtx, p)),
			LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
		}
	}
	return HMetric{
		AdvanceWidth:    fixed.Int26_6(u16(f.hmtx, 4*j)),
		LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))),
	}
}
Beispiel #22
0
// Add2 adds a quadratic segment to the current curve.
func (r *Rasterizer) Add2(b, c fixed.Point26_6) {
	// Calculate nSplit (the number of recursive decompositions) based on how
	// 'curvy' it is. Specifically, how much the middle point b deviates from
	// (a+c)/2.
	dev := maxAbs(r.a.X-2*b.X+c.X, r.a.Y-2*b.Y+c.Y) / fixed.Int26_6(r.splitScale2)
	nsplit := 0
	for dev > 0 {
		dev /= 4
		nsplit++
	}
	// dev is 32-bit, and nsplit++ every time we shift off 2 bits, so maxNsplit
	// is 16.
	const maxNsplit = 16
	if nsplit > maxNsplit {
		panic("freetype/raster: Add2 nsplit too large: " + strconv.Itoa(nsplit))
	}
	// Recursively decompose the curve nSplit levels deep.
	var (
		pStack [2*maxNsplit + 3]fixed.Point26_6
		sStack [maxNsplit + 1]int
		i      int
	)
	sStack[0] = nsplit
	pStack[0] = c
	pStack[1] = b
	pStack[2] = r.a
	for i >= 0 {
		s := sStack[i]
		p := pStack[2*i:]
		if s > 0 {
			// Split the quadratic curve p[:3] into an equivalent set of two
			// shorter curves: p[:3] and p[2:5]. The new p[4] is the old p[2],
			// and p[0] is unchanged.
			mx := p[1].X
			p[4].X = p[2].X
			p[3].X = (p[4].X + mx) / 2
			p[1].X = (p[0].X + mx) / 2
			p[2].X = (p[1].X + p[3].X) / 2
			my := p[1].Y
			p[4].Y = p[2].Y
			p[3].Y = (p[4].Y + my) / 2
			p[1].Y = (p[0].Y + my) / 2
			p[2].Y = (p[1].Y + p[3].Y) / 2
			// The two shorter curves have one less split to do.
			sStack[i] = s - 1
			sStack[i+1] = s - 1
			i++
		} else {
			// Replace the level-0 quadratic with a two-linear-piece
			// approximation.
			midx := (p[0].X + 2*p[1].X + p[2].X) / 4
			midy := (p[0].Y + 2*p[1].Y + p[2].Y) / 4
			r.Add1(fixed.Point26_6{midx, midy})
			r.Add1(p[0])
			i--
		}
	}
}
Beispiel #23
0
// Extents returns the FontExtents for a font.
// TODO needs to read this https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html#intro
func Extents(font *truetype.Font, size float64) FontExtents {
	bounds := font.Bounds(fixed.Int26_6(font.FUnitsPerEm()))
	scale := size / float64(font.FUnitsPerEm())
	return FontExtents{
		Ascent:  float64(bounds.YMax) * scale,
		Descent: float64(bounds.YMin) * scale,
		Height:  float64(bounds.YMax-bounds.YMin) * scale,
	}
}
Beispiel #24
0
// Extents returns the FontExtents for a font.
func (f *Font) Extents() FontExtents {
	bounds := f.font.Bounds(fixed.Int26_6(f.Font().FUnitsPerEm()))
	scale := f.Size / Points(float64(f.Font().FUnitsPerEm()))
	return FontExtents{
		Ascent:  Points(float64(bounds.Max.Y)) * scale,
		Descent: Points(float64(bounds.Min.Y)) * scale,
		Height:  Points(float64(bounds.Max.Y-bounds.Min.Y)) * scale,
	}
}
Beispiel #25
0
func (f *Font) parseHead() error {
	if len(f.head) != 54 {
		return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
	}
	f.fUnitsPerEm = int32(u16(f.head, 18))
	f.bounds.Min.X = fixed.Int26_6(int16(u16(f.head, 36)))
	f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38)))
	f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40)))
	f.bounds.Max.Y = fixed.Int26_6(int16(u16(f.head, 42)))
	switch i := u16(f.head, 50); i {
	case 0:
		f.locaOffsetFormat = locaOffsetFormatShort
	case 1:
		f.locaOffsetFormat = locaOffsetFormatLong
	default:
		return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i))
	}
	return nil
}
Beispiel #26
0
func (gc *GraphicContext) drawGlyph(glyph truetype.Index, dx, dy float64) error {
	if err := gc.glyphBuf.Load(gc.Current.Font, fixed.Int26_6(gc.Current.Scale), glyph, expfont.HintingNone); err != nil {
		return err
	}
	e0 := 0
	for _, e1 := range gc.glyphBuf.End {
		DrawContour(gc, gc.glyphBuf.Point[e0:e1], dx, dy)
		e0 = e1
	}
	return nil
}
Beispiel #27
0
func (f *Font) TextDimensions(text string) (int, int, int) {
	fnt := f.ttf
	size := f.Size
	var (
		totalWidth  = fixed.Int26_6(0)
		totalHeight = fixed.Int26_6(size)
		maxYBearing = fixed.Int26_6(0)
	)
	fupe := fixed.Int26_6(fnt.FUnitsPerEm())
	for _, char := range text {
		idx := fnt.Index(char)
		hm := fnt.HMetric(fupe, idx)
		vm := fnt.VMetric(fupe, idx)
		g := truetype.GlyphBuf{}
		err := g.Load(fnt, fupe, idx, font.HintingNone)
		if err != nil {
			log.Println(err)
			return 0, 0, 0
		}
		totalWidth += hm.AdvanceWidth
		yB := (vm.TopSideBearing * fixed.Int26_6(size)) / fupe
		if yB > maxYBearing {
			maxYBearing = yB
		}
	}

	// Scale to actual pixel size
	totalWidth *= fixed.Int26_6(size)
	totalWidth /= fupe

	return int(totalWidth), int(totalHeight), int(maxYBearing)
}
Beispiel #28
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 *GraphicContext) 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(int32(font.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)))
		}
		err := gc.drawGlyph(index, x, y)
		if err != nil {
			log.Println(err)
			return startx - x
		}
		x += fUnitsToFloat64(int32(font.HMetric(fixed.Int26_6(gc.Current.Scale), index).AdvanceWidth))
		prev, hasPrev = index, true
	}
	return x - startx
}
Beispiel #29
0
func TestKern(t *testing.T) {
	base, _ := NewFontWithName("Verdana")
	defer base.Close()

	face := base.Face(text.FaceData{
		Size: 20.0,
		DPI:  144,
	})
	defer face.Close()

	if kern := face.Kern('W', '\\'); kern != -fixed.Int26_6(12) {
		t.Error("invalid kerning for characters 'W' and '\\':", kern)
	}
}
Beispiel #30
0
func (h *hinter) move(p *Point, distance fixed.Int26_6, touch bool) {
	fvx := int64(h.gs.fv[0])
	pvx := int64(h.gs.pv[0])
	if fvx == 0x4000 && pvx == 0x4000 {
		p.X += fixed.Int26_6(distance)
		if touch {
			p.Flags |= flagTouchedX
		}
		return
	}

	fvy := int64(h.gs.fv[1])
	pvy := int64(h.gs.pv[1])
	if fvy == 0x4000 && pvy == 0x4000 {
		p.Y += fixed.Int26_6(distance)
		if touch {
			p.Flags |= flagTouchedY
		}
		return
	}

	fvDotPv := (fvx*pvx + fvy*pvy) >> 14

	if fvx != 0 {
		p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv))
		if touch {
			p.Flags |= flagTouchedX
		}
	}

	if fvy != 0 {
		p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv))
		if touch {
			p.Flags |= flagTouchedY
		}
	}
}