在Golang中使用TrueType对齐文本。

huangapple go评论82阅读模式
英文:

Aligning text in golang with Truetype

问题

我正在尝试在一个使用freetype/truetype的Golang项目中将一些文本渲染到png上。如附件所示,我正在尝试在列中渲染4个字母,每个字母都居中于列中。我已经使用truetype API获取了字形的边界和宽度,但是无法将它们转换为给我每个字形的准确偏移量。例如,对于O字形,给定我使用的字体,我得到了以下尺寸:

Bounds {XMin:0 YMin:-64 XMax:512 YMax:704}
Advance width: 512

最后一个尺寸是从GlyphBuf返回的。

我使用以下代码进行渲染:

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

我该如何使用truetype返回的字形尺寸来正确偏移字母?我尝试使用AdvanceWidth,如这个plotinum代码(第160行)中所述,但是这并不能给我在所有字形上得到一致的结果。

在Golang中使用TrueType对齐文本。

英文:

I am trying to render some text on a png in a Golang project using freetype/truetype. As you can see from the attachment, I am trying to render 4 letters in columns - each letter centered in the column. Have used the truetype api to get bounds and widths of the glyphs but have been unable to convert these to give me an accurate offset for each glyph. For example with the O glyph, given the font I using. I get the following dimensions:

Bounds {XMin:0 YMin:-64 XMax:512 YMax:704}
Advance width: 512

With the last dimension being returned from GlyphBuf.

I rendered it using the following:

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

How can I use the glyph dimensions returned by truetype to offset the letters correctly? I have tried using the AdvanceWidth as detailed in this plotinum code (line 160) but that does not give me a consistent result across all glyphs.

在Golang中使用TrueType对齐文本。

答案1

得分: 11

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

粗略示例:

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, "屏幕每英寸的分辨率")
	fontfile = flag.String("fontfile", "/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", "ttf字体文件的文件名")
	hinting  = flag.String("hinting", "none", "none | full")
	size     = flag.Float64("size", 125, "字体大小(以点为单位)")
	spacing  = flag.Float64("spacing", 1.5, "行间距(例如,2表示双倍行距)")
	wonb     = flag.Bool("whiteonblack", false, "白色文本在黑色背景上")
	text 	 = string("JOJO")
)


func main() {
	flag.Parse()
	fmt.Printf("加载字体文件 %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 上下文
	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)
	}

	// 创建一些背景

	// 绘制指南线。
	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 相关
	opts := truetype.Options{}
	opts.Size = 125.0
	face := truetype.NewFace(f, &opts)
	
	
	// 计算宽度并打印到图像上
	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)
	}
	

	// 将该RGBA图像保存到磁盘。
	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("已成功写入 out.png。")
}

在Golang中使用TrueType对齐文本。

英文:

As suggested by Simon the correct solution is to use AdvanceWidth:

在Golang中使用TrueType对齐文本。

Crude example:

package main
import (
&quot;flag&quot;
&quot;fmt&quot;
&quot;io/ioutil&quot;
&quot;log&quot;
&quot;image&quot;
&quot;bufio&quot;
&quot;image/draw&quot;
&quot;image/png&quot;
&quot;image/color&quot;
&quot;github.com/golang/freetype/truetype&quot;
&quot;golang.org/x/image/font&quot;
&quot;github.com/golang/freetype&quot;
&quot;os&quot;
)
var (
dpi      = flag.Float64(&quot;dpi&quot;, 72, &quot;screen resolution in Dots Per Inch&quot;)
fontfile = flag.String(&quot;fontfile&quot;, &quot;/usr/share/fonts/liberation/LiberationSerif-Regular.ttf&quot;, &quot;filename of the ttf font&quot;)
hinting  = flag.String(&quot;hinting&quot;, &quot;none&quot;, &quot;none | full&quot;)
size     = flag.Float64(&quot;size&quot;, 125, &quot;font size in points&quot;)
spacing  = flag.Float64(&quot;spacing&quot;, 1.5, &quot;line spacing (e.g. 2 means double spaced)&quot;)
wonb     = flag.Bool(&quot;whiteonblack&quot;, false, &quot;white text on a black background&quot;)
text 	 = string(&quot;JOJO&quot;)
)
func main() {
flag.Parse()
fmt.Printf(&quot;Loading fontfile %q\n&quot;, *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 &quot;full&quot;:
c.SetHinting(font.HintingFull)
}
// Make some background
// Draw the guidelines.
ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
for rcount := 0; rcount &lt; 4; rcount ++ {
for i := 0; i &lt; 200; i++ {
rgba.Set(250*rcount, i, ruler)
}
}
// Truetype stuff
opts := truetype.Options{}
opts.Size = 125.0
face := truetype.NewFace(f, &amp;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(&quot;%+v\n&quot;, iwidthf)
pt := freetype.Pt(i*250+(125-iwidthf/2), 128)
c.DrawString(string(x), pt)
fmt.Printf(&quot;%+v\n&quot;, awidth)
}
// Save that RGBA image to disk.
outFile, err := os.Create(&quot;out.png&quot;)
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(&quot;Wrote out.png OK.&quot;)
}

huangapple
  • 本文由 发表于 2015年3月18日 01:15:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/29105540.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定