使用Truetype在golang中对齐文本

15

我正在使用freetype/truetype在Golang项目中尝试将一些文本呈现在png上。正如您从附件中可以看到的那样,我正在尝试在列中呈现4个字母 - 每个字母都居中于列中。我已经使用truetype api来获取字形的边界和宽度,但是无法将这些转换为给我每个字形的准确偏移量。例如,在给定所使用的字体的情况下,对于字形O,我获得以下维度:

Hmetric {AdvanceWidth:543 LeftSideBearing:36} Bounds {XMin:0 YMin:-64 XMax:512 YMax:704} Advance width: 512

最后一个维度是从GlyphBuf返回的。

我使用以下方法渲染它:

size := 125.00 tileOffset := (int(tileWidth) * i) + int(tileWidth/2) pt := freetype.Pt(tileOffset, (imgH-newCharHeight)-int(size))

我如何使用truetype返回的字形维度来正确地偏移字母?我尝试使用AdvanceWidth,就像这个plotinum代码(第160行)中所详细描述的那样,但这不能在所有字形上给我一致的结果。

Example of rendering


1
嘿...有趣的是,上周我在工作中也在研究这个问题。每种字体都有上升和下降属性...悬挂/下挂等等。基本上,你需要一个API来提供没有上升部分的尺寸,这样你就可以正确地定位它。在该API中尝试使用“Extents”方法以及上升和下降属性。今天我有空了会给出一个正式的答案。 - Simon Whitehead
1
抱歉,我的术语有些不准确。Ascent和Descent是与垂直定位有关的,你需要的是每个字符的Advance或Bounds。我想知道您是否可以分享使用AdvanceWidth的完整代码段? - Simon Whitehead
1个回答

12

正如Simon所建议的,正确的解决方案是使用AdvanceWidth:

enter image description here

一个简单的示例:

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "image"
    "bufio"
    "image/draw"
    "image/png"
    "image/color"
    "github.com/golang/freetype/truetype"
    "golang.org/x/image/font"
    "github.com/golang/freetype"
    "os"
)

var (
    dpi      = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
    fontfile = flag.String("fontfile", "/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", "filename of the ttf font")
    hinting  = flag.String("hinting", "none", "none | full")
    size     = flag.Float64("size", 125, "font size in points")
    spacing  = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
    wonb     = flag.Bool("whiteonblack", false, "white text on a black background")
    text     = string("JOJO")
)


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
    }

    // Freetype context
    fg, bg := image.Black, image.White
    rgba := image.NewRGBA(image.Rect(0, 0, 1000, 200))
    draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
    c := freetype.NewContext()
    c.SetDPI(*dpi)
    c.SetFont(f)
    c.SetFontSize(*size)
    c.SetClip(rgba.Bounds())
    c.SetDst(rgba)
    c.SetSrc(fg)
    switch *hinting {
    default:
        c.SetHinting(font.HintingNone)
    case "full":
        c.SetHinting(font.HintingFull)
    }

    // Make some background

    // Draw the guidelines.
    ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
    for rcount := 0; rcount < 4; rcount ++ {
        for i := 0; i < 200; i++ {
            rgba.Set(250*rcount, i, ruler)
        }
    }

    // Truetype stuff
    opts := truetype.Options{}
    opts.Size = 125.0
    face := truetype.NewFace(f, &opts)


    // Calculate the widths and print to image
    for i, x := range(text) {
        awidth, ok := face.GlyphAdvance(rune(x))
        if ok != true {
            log.Println(err)
            return
        }
        iwidthf := int(float64(awidth) / 64)
        fmt.Printf("%+v\n", iwidthf)

        pt := freetype.Pt(i*250+(125-iwidthf/2), 128)
        c.DrawString(string(x), pt)
        fmt.Printf("%+v\n", awidth)
    }


    // Save that RGBA image to disk.
    outFile, err := os.Create("out.png")
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }
    defer outFile.Close()
    bf := bufio.NewWriter(outFile)
    err = png.Encode(bf, rgba)
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }
    err = bf.Flush()
    if err != nil {
        log.Println(err)
        os.Exit(1)
    }
    fmt.Println("Wrote out.png OK.")


}

在Go语言中,是否可以计算使用TrueType字体渲染的字符串的上升/下降或边界矩形? - Aaron
3
谢谢提供的好例子。您能解释一下这两行代码吗: iwidthf := int(float64(awidth) / 64)pt := freetype.Pt(i*250+(125-iwidthf/2), 128) - 这里的常量是什么?这两行代码中的常量是:64,250,125和128。其中,64是用来计算iwidthf变量的除数,250和128分别是用来计算pt变量的x和y坐标,而125是用来调整iwidthf对x坐标的影响。 - kirhgoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接