canvas/text.go

161 lines
3.4 KiB
Go

package canvas
import (
"image"
"image/color"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// SetFont 设置字体
func (c *Context) SetFont(face font.Face) {
c.state.fontFace = face
}
// SetTextAlign 设置文本对齐
func (c *Context) SetTextAlign(align string) {
c.state.textAlign = align
}
// SetTextBaseline 设置文本基线
func (c *Context) SetTextBaseline(baseline string) {
c.state.textBaseline = baseline
}
// FillText 绘制填充文本
func (c *Context) FillText(text string, x, y float64) {
if c.state.fontFace == nil {
return
}
// 应用阴影
if c.state.shadowBlur > 0 || c.state.shadowOffsetX != 0 || c.state.shadowOffsetY != 0 {
c.drawTextShadow(text, x, y, true)
}
c.drawText(text, x, y, true)
}
// StrokeText 绘制描边文本
func (c *Context) StrokeText(text string, x, y float64) {
if c.state.fontFace == nil {
return
}
// 应用阴影
if c.state.shadowBlur > 0 || c.state.shadowOffsetX != 0 || c.state.shadowOffsetY != 0 {
c.drawTextShadow(text, x, y, false)
}
c.drawText(text, x, y, false)
}
// MeasureText 测量文本宽度
func (c *Context) MeasureText(text string) float64 {
if c.state.fontFace == nil {
return 0
}
width := 0
for _, r := range text {
aw, _ := c.state.fontFace.GlyphAdvance(r)
width += aw.Round()
}
return float64(width)
}
// 绘制文本
func (c *Context) drawText(text string, x, y float64, fill bool) {
pt := c.transformPoint(x, y)
// 计算文本宽度用于对齐
textWidth := c.MeasureText(text)
// 应用对齐
switch c.state.textAlign {
case "center":
pt.X -= int(textWidth / 2)
case "end", "right":
pt.X -= int(textWidth)
}
// 应用基线
metrics := c.state.fontFace.Metrics()
switch c.state.textBaseline {
case "top":
pt.Y += metrics.Ascent.Round()
case "middle":
pt.Y += (metrics.Ascent + metrics.Descent).Round() / 2
case "bottom":
pt.Y += metrics.Descent.Round()
}
// 创建文本绘制器
drawer := font.Drawer{
Dst: c.img,
Face: c.state.fontFace,
Dot: fixed.P(pt.X, pt.Y),
}
// 设置颜色
if fill {
switch style := c.state.fillStyle.(type) {
case color.Color:
drawer.Src = image.NewUniform(c.applyAlpha(style))
case Gradient:
drawer.Src = &gradientImage{grad: style, alpha: c.state.globalAlpha}
}
} else {
// 描边文本 - 简单实现,实际应使用路径
switch style := c.state.strokeStyle.(type) {
case color.Color:
drawer.Src = image.NewUniform(c.applyAlpha(style))
case Gradient:
drawer.Src = &gradientImage{grad: style, alpha: c.state.globalAlpha}
}
}
// 绘制文本
if fill {
drawer.DrawString(text)
} else {
// 简单描边实现 - 实际应用中应使用更高级的路径方法
offset := 1
for dx := -offset; dx <= offset; dx++ {
for dy := -offset; dy <= offset; dy++ {
if dx != 0 || dy != 0 {
drawer.Dot = fixed.P(pt.X+dx, pt.Y+dy)
drawer.DrawString(text)
}
}
}
}
}
// 绘制文本阴影
func (c *Context) drawTextShadow(text string, x, y float64, fill bool) {
// 保存当前状态
c.Save()
// 设置阴影样式
shadowStyle := c.state.shadowColor
c.SetFillColor(shadowStyle)
c.SetStrokeColor(shadowStyle)
c.SetGlobalAlpha(0.5 * c.state.globalAlpha) // 阴影透明度
// 应用阴影偏移
x += c.state.shadowOffsetX
y += c.state.shadowOffsetY
// 绘制阴影文本
if fill {
c.FillText(text, x, y)
} else {
c.StrokeText(text, x, y)
}
// 恢复状态
c.Restore()
}