From 24265d1c918675302a50cb5e1adc10d1a2b708b3 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Mon, 24 Aug 2015 15:51:50 +1000 Subject: [PATCH] Implement GlyphBounds and GlyphAdvance. --- example/drawer/main.go | 18 +++++++++++++---- truetype/face.go | 44 +++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/example/drawer/main.go b/example/drawer/main.go index 402c277..44d5928 100644 --- a/example/drawer/main.go +++ b/example/drawer/main.go @@ -37,6 +37,8 @@ var ( wonb = flag.Bool("whiteonblack", false, "white text on a black background") ) +const title = "Jabberwocky" + var text = []string{ "’Twas brillig, and the slithy toves", "Did gyre and gimble in the wabe;", @@ -96,7 +98,8 @@ func main() { fg, bg = image.White, image.Black ruler = color.RGBA{0x22, 0x22, 0x22, 0xff} } - rgba := image.NewRGBA(image.Rect(0, 0, 640, 480)) + const imgW, imgH = 640, 480 + rgba := image.NewRGBA(image.Rect(0, 0, imgW, imgH)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) for i := 0; i < 200; i++ { rgba.Set(10, 10+i, ruler) @@ -118,11 +121,18 @@ func main() { Hinting: h, }), } - dy0 := int(math.Ceil(*size * *dpi / 72)) + y := 10 + int(math.Ceil(*size**dpi/72)) dy := int(math.Ceil(*size * *spacing * *dpi / 72)) - for i, s := range text { - d.Dot = fixed.P(10, 10+dy0+i*dy) + d.Dot = fixed.Point26_6{ + X: (fixed.I(imgW) - d.MeasureString(title)) / 2, + Y: fixed.I(y), + } + d.DrawString(title) + y += dy + for _, s := range text { + d.Dot = fixed.P(10, y) d.DrawString(s) + y += dy } // Save that RGBA image to disk. diff --git a/truetype/face.go b/truetype/face.go index 8350a70..fe621ff 100644 --- a/truetype/face.go +++ b/truetype/face.go @@ -132,6 +132,36 @@ func (a *face) Glyph(dot fixed.Point26_6, r rune) ( return newDot, dr, a.mask, image.Point{}, true } +func (a *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { + if err := a.glyphBuf.Load(a.f, a.scale, a.f.Index(r), a.hinting); err != nil { + return fixed.Rectangle26_6{}, 0, false + } + xmin := +a.glyphBuf.B.XMin + ymin := -a.glyphBuf.B.YMax + xmax := +a.glyphBuf.B.XMax + ymax := -a.glyphBuf.B.YMin + if xmin > xmax || ymin > ymax { + return fixed.Rectangle26_6{}, 0, false + } + return fixed.Rectangle26_6{ + Min: fixed.Point26_6{ + X: xmin, + Y: ymin, + }, + Max: fixed.Point26_6{ + X: xmax, + Y: ymax, + }, + }, a.glyphBuf.AdvanceWidth, true +} + +func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { + if err := a.glyphBuf.Load(a.f, a.scale, a.f.Index(r), a.hinting); err != nil { + return 0, false + } + return a.glyphBuf.AdvanceWidth, true +} + // rasterize returns the advance width, integer-pixel offset to render at, and // the width and height of the given glyph at the given sub-pixel offsets. // @@ -143,10 +173,10 @@ func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) ( return 0, image.Point{}, 0, 0, false } // Calculate the integer-pixel bounds for the glyph. - xmin := int(fx+fixed.Int26_6(a.glyphBuf.B.XMin)) >> 6 - ymin := int(fy-fixed.Int26_6(a.glyphBuf.B.YMax)) >> 6 - xmax := int(fx+fixed.Int26_6(a.glyphBuf.B.XMax)+0x3f) >> 6 - ymax := int(fy-fixed.Int26_6(a.glyphBuf.B.YMin)+0x3f) >> 6 + xmin := int(fx+a.glyphBuf.B.XMin) >> 6 + ymin := int(fy-a.glyphBuf.B.YMax) >> 6 + xmax := int(fx+a.glyphBuf.B.XMax+0x3f) >> 6 + ymax := int(fy-a.glyphBuf.B.YMin+0x3f) >> 6 if xmin > xmax || ymin > ymax { return 0, image.Point{}, 0, 0, false } @@ -155,8 +185,8 @@ func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) ( // 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) + fx -= fixed.Int26_6(xmin << 6) + fy -= fixed.Int26_6(ymin << 6) // Rasterize the glyph's vectors. a.r.Clear() clear(a.mask.Pix) @@ -166,7 +196,7 @@ func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) ( e0 = e1 } a.r.Rasterize(a.p) - return fixed.Int26_6(a.glyphBuf.AdvanceWidth), image.Point{xmin, ymin}, xmax-xmin, ymax-ymin, true + return a.glyphBuf.AdvanceWidth, image.Point{xmin, ymin}, xmax - xmin, ymax - ymin, true } func clear(pix []byte) {