Files
ngzz-mc/internal/cjkfont/cjkfont.go

77 lines
2.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package cjkfont 中文字体渲染:加载系统 CJK 字体(微软雅黑)光栅化文本(UI还原.md §4 中文回退)。
//
// 素材包位图字体只含 ASCII;中文(如「年糕历险记」)用系统字体渲染,
// 保持像素风(最近邻采样、整数缩放),字形不追求与原版一致。
package cjkfont
import (
"image"
"image/color"
"os"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"golang.org/x/image/math/fixed"
)
// Renderer CJK 文本渲染器。
type Renderer struct {
face font.Face
}
// Load 加载字体文件(如 C:\Windows\Fonts\msyh.ttc)。
func Load(path string, sizePx float64) (*Renderer, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
// 兼容 .ttc 字体集合(如 msyh.ttc)与单字体 .ttf/.otf
var f *opentype.Font
if col, err := opentype.ParseCollection(data); err == nil && col != nil && col.NumFonts() > 0 {
f, err = col.Font(0)
if err != nil {
return nil, err
}
} else {
f, err = opentype.Parse(data)
if err != nil {
return nil, err
}
}
face, err := opentype.NewFace(f, &opentype.FaceOptions{
Size: sizePx,
DPI: 72,
Hinting: font.HintingNone,
})
if err != nil {
return nil, err
}
return &Renderer{face: face}, nil
}
// Width 文本像素宽度。
func (r *Renderer) Width(s string) int {
d := &font.Drawer{Face: r.face}
return d.MeasureString(s).Ceil()
}
// Draw 渲染文本为 RGBA 图像(含 1px 阴影,UI还原.md §4)。
func (r *Renderer) Draw(s string, c color.RGBA) image.Image {
w := r.Width(s) + 1
h := int(r.face.Metrics().Height.Ceil()) + 1
img := image.NewRGBA(image.Rect(0, 0, w, h))
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(c),
Face: r.face,
}
// 阴影
sh := &font.Drawer{Dst: img, Src: image.NewUniform(color.RGBA{10, 10, 10, 220}), Face: r.face}
sh.Dot = fixed.P(1, int(r.face.Metrics().Ascent.Ceil())+1)
sh.DrawString(s)
// 正文
d.Dot = fixed.P(0, int(r.face.Metrics().Ascent.Ceil()))
d.DrawString(s)
return img
}