mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
+17
-117
@@ -1018,14 +1018,17 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
face := ff.Face(sizePt, fillPaint, fontStyle, canvas.FontNormal)
|
face := ff.Face(sizePt, fillPaint, fontStyle, canvas.FontNormal)
|
||||||
glyphRunes := r.textObjectGlyphRunes(fontID, obj)
|
glyphTransforms := r.textObjectGlyphTransforms(fontID, obj)
|
||||||
codePos := 0
|
codePos := 0
|
||||||
for _, tc := range obj.TextCode {
|
for _, tc := range obj.TextCode {
|
||||||
var runes []rune
|
var runes []rune
|
||||||
|
var glyphs []textGlyph
|
||||||
if tc.Index != "" {
|
if tc.Index != "" {
|
||||||
runes = r.parseIndexRunes(tc.Index, fontID)
|
runes = r.parseIndexRunes(tc.Index, fontID)
|
||||||
|
glyphs = textRuneGlyphs(runes)
|
||||||
} else {
|
} else {
|
||||||
runes = []rune(tc.Value)
|
runes = textCodeRunes(tc.Value)
|
||||||
|
glyphs = textCodeGlyphs(runes, glyphTransforms, codePos)
|
||||||
}
|
}
|
||||||
dxs, dys := parseFloats(tc.DeltaX), parseFloats(tc.DeltaY)
|
dxs, dys := parseFloats(tc.DeltaX), parseFloats(tc.DeltaY)
|
||||||
xs, ys := parseFloats(tc.X), parseFloats(tc.Y)
|
xs, ys := parseFloats(tc.X), parseFloats(tc.Y)
|
||||||
@@ -1037,20 +1040,15 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
if len(ys) > 0 {
|
if len(ys) > 0 {
|
||||||
cy = ys[0]
|
cy = ys[0]
|
||||||
}
|
}
|
||||||
for i, run := range runes {
|
for i, glyph := range glyphs {
|
||||||
str := string(run)
|
str := glyph.Text
|
||||||
if embeddedFont && tc.Index == "" && glyphRunes != nil {
|
|
||||||
if mapped, ok := glyphRunes[codePos+i]; ok {
|
|
||||||
str = string(mapped)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i < len(xs) {
|
if i < len(xs) {
|
||||||
cx = xs[i]
|
cx = xs[i]
|
||||||
} else if i > 0 {
|
} else if i > 0 {
|
||||||
if dx, ok := textDelta(dxs, i-1); ok {
|
if dx, ok := textDelta(dxs, i-1); ok {
|
||||||
cx += dx
|
cx += dx
|
||||||
} else if len(dys) == 0 {
|
} else if len(dys) == 0 {
|
||||||
cx += face.TextWidth(str) * hScale
|
cx += textGlyphWidth(face, glyph) * hScale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if i < len(ys) {
|
if i < len(ys) {
|
||||||
@@ -1069,17 +1067,17 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
tx, ty := ctm.Transform(cx, cy)
|
tx, ty := ctm.Transform(cx, cy)
|
||||||
canvasX, canvasY = tx+bx, pageH-(ty+by)
|
canvasX, canvasY = tx+bx, pageH-(ty+by)
|
||||||
}
|
}
|
||||||
textWidth := face.TextWidth(str) * hScale
|
textWidth := textGlyphWidth(face, glyph) * hScale
|
||||||
glyphFillPaint := fillPaint
|
glyphFillPaint := fillPaint
|
||||||
if fillColorNode != nil && fillColorNode.AxialShd != nil {
|
if fillColorNode != nil && fillColorNode.AxialShd != nil {
|
||||||
glyphFillPaint = parseFillPaint(fillColorNode, bx, by, pageH, canvasX, canvasY)
|
glyphFillPaint = parseFillPaint(fillColorNode, bx, by, pageH, canvasX, canvasY)
|
||||||
}
|
}
|
||||||
advanceLimit := textGlyphAdvanceLimit(dxs, dys, xs, i, len(runes), cx)
|
advanceLimit := textGlyphAdvanceLimit(dxs, dys, xs, i, len(glyphs), cx)
|
||||||
if glyphFillPaint != nil {
|
if glyphFillPaint != nil {
|
||||||
ctx.SetFill(glyphFillPaint)
|
ctx.SetFill(glyphFillPaint)
|
||||||
drawGlyph := func(x, y float64) {
|
drawGlyph := func(x, y float64) {
|
||||||
if drawAsPath {
|
if drawAsPath || glyph.GlyphID >= 0 {
|
||||||
path, width := face.ToPath(str)
|
path, width := textGlyphPath(face, glyph)
|
||||||
scaleX := hScale
|
scaleX := hScale
|
||||||
if advanceLimit > 0 && width*scaleX > advanceLimit {
|
if advanceLimit > 0 && width*scaleX > advanceLimit {
|
||||||
scaleX = advanceLimit / width
|
scaleX = advanceLimit / width
|
||||||
@@ -1095,12 +1093,12 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
ctx.DrawPath(x, y, path)
|
ctx.DrawPath(x, y, path)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if hScale != 1 {
|
scaled := hScale != 1
|
||||||
|
if scaled {
|
||||||
ctx.Push()
|
ctx.Push()
|
||||||
ctx.Translate(x, y)
|
ctx.Translate(x, y)
|
||||||
ctx.Scale(hScale, 1)
|
ctx.Scale(hScale, 1)
|
||||||
x, y = 0, 0
|
x, y = 0, 0
|
||||||
defer ctx.Pop()
|
|
||||||
}
|
}
|
||||||
textFace := face
|
textFace := face
|
||||||
if fillColorNode != nil && fillColorNode.AxialShd != nil {
|
if fillColorNode != nil && fillColorNode.AxialShd != nil {
|
||||||
@@ -1108,6 +1106,9 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
}
|
}
|
||||||
text := canvas.NewTextLine(textFace, str, canvas.Left)
|
text := canvas.NewTextLine(textFace, str, canvas.Left)
|
||||||
ctx.DrawText(x, y, text)
|
ctx.DrawText(x, y, text)
|
||||||
|
if scaled {
|
||||||
|
ctx.Pop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if useTextMatrix {
|
if useTextMatrix {
|
||||||
@@ -1144,47 +1145,6 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64
|
|||||||
ctx.Pop()
|
ctx.Pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// textGlyphAdvanceLimit 获取显式字形推进宽度
|
|
||||||
// 入参: dxs X方向偏移, dys Y方向偏移, xs X坐标列表, index 字形索引, count 字形数量, currentX 当前X坐标
|
|
||||||
// 返回: float64 推进宽度
|
|
||||||
func textGlyphAdvanceLimit(dxs, dys, xs []float64, index int, count int, currentX float64) float64 {
|
|
||||||
if index+1 >= count || len(dys) > 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if index+1 < len(xs) {
|
|
||||||
if advance := xs[index+1] - currentX; advance > 0 {
|
|
||||||
return advance
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if advance, ok := textDelta(dxs, index); ok && advance > 0 {
|
|
||||||
return advance
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// textCodePositioned 判断文本编码是否带显式定位
|
|
||||||
// 入参: textCode 文本编码
|
|
||||||
// 返回: bool 是否带显式定位
|
|
||||||
func textCodePositioned(textCode TextCode) bool {
|
|
||||||
return strings.TrimSpace(textCode.DeltaX) != "" ||
|
|
||||||
strings.TrimSpace(textCode.DeltaY) != "" ||
|
|
||||||
len(parseFloats(textCode.X)) > 1 ||
|
|
||||||
len(parseFloats(textCode.Y)) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// textDelta 获取文本偏移量
|
|
||||||
// 入参: deltas 偏移量数组, index 偏移量索引
|
|
||||||
// 返回: float64 偏移量, bool 是否存在
|
|
||||||
func textDelta(deltas []float64, index int) (float64, bool) {
|
|
||||||
if len(deltas) == 0 {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
if index < len(deltas) {
|
|
||||||
return deltas[index], true
|
|
||||||
}
|
|
||||||
return deltas[len(deltas)-1], true
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasTextMatrix 判断文本是否需要应用字形变换
|
// hasTextMatrix 判断文本是否需要应用字形变换
|
||||||
// 入参: ctm 变换矩阵
|
// 入参: ctm 变换矩阵
|
||||||
// 返回: bool 是否需要变换
|
// 返回: bool 是否需要变换
|
||||||
@@ -1384,66 +1344,6 @@ func (r *Renderer) textObjectFontID(text TextObject) string {
|
|||||||
return fontID
|
return fontID
|
||||||
}
|
}
|
||||||
|
|
||||||
// textObjectGlyphRunes 获取文本对象的字形映射
|
|
||||||
// 入参: fontID 字体ID, text 文本对象
|
|
||||||
// 返回: map[int]rune 文本位置到包装字体字符的映射
|
|
||||||
func (r *Renderer) textObjectGlyphRunes(fontID string, text TextObject) map[int]rune {
|
|
||||||
if fontID == "" || len(text.CGTransform) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := make(map[int]rune)
|
|
||||||
for _, transform := range text.CGTransform {
|
|
||||||
glyphs := parseInts(transform.Glyphs)
|
|
||||||
count := len(glyphs)
|
|
||||||
if transform.GlyphCount > 0 && transform.GlyphCount < count {
|
|
||||||
count = transform.GlyphCount
|
|
||||||
}
|
|
||||||
if transform.CodeCount > 0 && transform.CodeCount < count {
|
|
||||||
count = transform.CodeCount
|
|
||||||
}
|
|
||||||
if count == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if transform.CodeCount > 0 && transform.GlyphCount > 0 && transform.CodeCount != transform.GlyphCount {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
if mapped, ok := r.fontGlyphRune(fontID, glyphs[i]); ok {
|
|
||||||
result[transform.CodePosition+i] = mapped
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(result) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// fontGlyphRune 获取字形ID对应的包装字体字符
|
|
||||||
// 入参: fontID 字体ID, glyphID 字形ID或CID
|
|
||||||
// 返回: rune 包装字体字符, bool 是否存在
|
|
||||||
func (r *Renderer) fontGlyphRune(fontID string, glyphID int) (rune, bool) {
|
|
||||||
if glyphID < 0 || glyphID > 0xFFFF {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
id := uint16(glyphID)
|
|
||||||
if r.FontCIDMap != nil {
|
|
||||||
if mapping := r.FontCIDMap[fontID]; mapping != nil {
|
|
||||||
if mapped, ok := mapping[id]; ok {
|
|
||||||
return mapped, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.FontGIDMap != nil {
|
|
||||||
if mapping := r.FontGIDMap[fontID]; mapping != nil {
|
|
||||||
if mapped, ok := mapping[id]; ok {
|
|
||||||
return mapped, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderStamp 渲染印章
|
// renderStamp 渲染印章
|
||||||
// 入参: ctx 画布上下文, s 印章对象, pageH 页面高度
|
// 入参: ctx 画布上下文, s 印章对象, pageH 页面高度
|
||||||
func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) {
|
func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) {
|
||||||
|
|||||||
+202
@@ -20,6 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tdewolff/canvas"
|
"github.com/tdewolff/canvas"
|
||||||
|
"github.com/tdewolff/font"
|
||||||
)
|
)
|
||||||
|
|
||||||
// parseColorWithAlpha 解析带透明度的颜色
|
// parseColorWithAlpha 解析带透明度的颜色
|
||||||
@@ -225,6 +226,207 @@ func parseStrokePaint(strokeColor *StrokeColor, x, y, pageH, originX, originY fl
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// textGlyph 绘制字形
|
||||||
|
type textGlyph struct {
|
||||||
|
Text string
|
||||||
|
GlyphID int
|
||||||
|
}
|
||||||
|
|
||||||
|
// textGlyphTransform 字符到字形变换
|
||||||
|
type textGlyphTransform struct {
|
||||||
|
CodeCount int
|
||||||
|
Glyphs []textGlyph
|
||||||
|
}
|
||||||
|
|
||||||
|
// textObjectGlyphTransforms 获取文本对象的字形变换
|
||||||
|
// 入参: fontID 字体ID, text 文本对象
|
||||||
|
// 返回: map[int]textGlyphTransform 文本位置到字形变换的映射
|
||||||
|
func (r *Renderer) textObjectGlyphTransforms(fontID string, text TextObject) map[int]textGlyphTransform {
|
||||||
|
if fontID == "" || len(text.CGTransform) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := make(map[int]textGlyphTransform)
|
||||||
|
for _, transform := range text.CGTransform {
|
||||||
|
ids := parseInts(transform.Glyphs)
|
||||||
|
glyphCount := len(ids)
|
||||||
|
if transform.GlyphCount > 0 && transform.GlyphCount < glyphCount {
|
||||||
|
glyphCount = transform.GlyphCount
|
||||||
|
}
|
||||||
|
if glyphCount == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
codeCount := transform.CodeCount
|
||||||
|
if codeCount <= 0 {
|
||||||
|
codeCount = 1
|
||||||
|
}
|
||||||
|
glyphs := make([]textGlyph, 0, glyphCount)
|
||||||
|
for i := 0; i < glyphCount; i++ {
|
||||||
|
glyphs = append(glyphs, r.textGlyphFromID(fontID, ids[i]))
|
||||||
|
}
|
||||||
|
result[transform.CodePosition] = textGlyphTransform{
|
||||||
|
CodeCount: codeCount,
|
||||||
|
Glyphs: glyphs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(result) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// textCodeGlyphs 获取文本编码对应的绘制字形
|
||||||
|
// 入参: runes 文本字符, transforms 字形变换, codeOffset 文本编码偏移
|
||||||
|
// 返回: []textGlyph 绘制字形列表
|
||||||
|
func textCodeGlyphs(runes []rune, transforms map[int]textGlyphTransform, codeOffset int) []textGlyph {
|
||||||
|
if len(transforms) == 0 {
|
||||||
|
return textRuneGlyphs(runes)
|
||||||
|
}
|
||||||
|
glyphs := make([]textGlyph, 0, len(runes))
|
||||||
|
for i := 0; i < len(runes); {
|
||||||
|
if transform, ok := transforms[codeOffset+i]; ok && i+transform.CodeCount <= len(runes) {
|
||||||
|
glyphs = append(glyphs, transform.Glyphs...)
|
||||||
|
i += transform.CodeCount
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
glyphs = append(glyphs, textGlyph{Text: string(runes[i]), GlyphID: -1})
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return glyphs
|
||||||
|
}
|
||||||
|
|
||||||
|
// textRuneGlyphs 转换文本字符为绘制字形
|
||||||
|
// 入参: runes 文本字符
|
||||||
|
// 返回: []textGlyph 绘制字形列表
|
||||||
|
func textRuneGlyphs(runes []rune) []textGlyph {
|
||||||
|
glyphs := make([]textGlyph, 0, len(runes))
|
||||||
|
for _, r := range runes {
|
||||||
|
glyphs = append(glyphs, textGlyph{Text: string(r), GlyphID: -1})
|
||||||
|
}
|
||||||
|
return glyphs
|
||||||
|
}
|
||||||
|
|
||||||
|
// textGlyphFromID 获取字形ID对应的绘制字形
|
||||||
|
// 入参: fontID 字体ID, glyphID 字形ID或CID
|
||||||
|
// 返回: textGlyph 绘制字形
|
||||||
|
func (r *Renderer) textGlyphFromID(fontID string, glyphID int) textGlyph {
|
||||||
|
if mapped, ok := r.fontGlyphRune(fontID, glyphID); ok {
|
||||||
|
return textGlyph{Text: string(mapped), GlyphID: -1}
|
||||||
|
}
|
||||||
|
return textGlyph{GlyphID: glyphID}
|
||||||
|
}
|
||||||
|
|
||||||
|
// textGlyphWidth 获取绘制字形宽度
|
||||||
|
// 入参: face 字体, glyph 绘制字形
|
||||||
|
// 返回: float64 字形宽度
|
||||||
|
func textGlyphWidth(face *canvas.FontFace, glyph textGlyph) float64 {
|
||||||
|
if glyph.GlyphID >= 0 && glyph.GlyphID <= 0xFFFF {
|
||||||
|
return face.MmPerEm * float64(face.Font.GlyphAdvance(uint16(glyph.GlyphID)))
|
||||||
|
}
|
||||||
|
return face.TextWidth(glyph.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// textGlyphPath 获取绘制字形路径
|
||||||
|
// 入参: face 字体, glyph 绘制字形
|
||||||
|
// 返回: *canvas.Path 字形路径, float64 字形宽度
|
||||||
|
func textGlyphPath(face *canvas.FontFace, glyph textGlyph) (*canvas.Path, float64) {
|
||||||
|
if glyph.GlyphID < 0 || glyph.GlyphID > 0xFFFF {
|
||||||
|
return face.ToPath(glyph.Text)
|
||||||
|
}
|
||||||
|
p := &canvas.Path{}
|
||||||
|
glyphID := uint16(glyph.GlyphID)
|
||||||
|
_ = face.Font.GlyphPath(p, glyphID, face.PPEM(canvas.DefaultResolution), 0, 0, face.MmPerEm, font.NoHinting)
|
||||||
|
if face.FauxBold != 0 {
|
||||||
|
d := face.FauxBold * face.Size
|
||||||
|
if face.Font.IsTrueType {
|
||||||
|
d = -d
|
||||||
|
}
|
||||||
|
origFastStroke := canvas.FastStroke
|
||||||
|
canvas.FastStroke = true
|
||||||
|
p = p.Offset(d, canvas.Tolerance)
|
||||||
|
canvas.FastStroke = origFastStroke
|
||||||
|
}
|
||||||
|
if face.FauxItalic != 0 {
|
||||||
|
p = p.Transform(canvas.Identity.Shear(face.FauxItalic, 0))
|
||||||
|
}
|
||||||
|
return p, face.MmPerEm * float64(face.Font.GlyphAdvance(glyphID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// fontGlyphRune 获取字形ID对应的包装字体字符
|
||||||
|
// 入参: fontID 字体ID, glyphID 字形ID或CID
|
||||||
|
// 返回: rune 包装字体字符, bool 是否存在
|
||||||
|
func (r *Renderer) fontGlyphRune(fontID string, glyphID int) (rune, bool) {
|
||||||
|
if glyphID < 0 || glyphID > 0xFFFF {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
id := uint16(glyphID)
|
||||||
|
if r.FontCIDMap != nil {
|
||||||
|
if mapping := r.FontCIDMap[fontID]; mapping != nil {
|
||||||
|
if mapped, ok := mapping[id]; ok {
|
||||||
|
return mapped, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.FontGIDMap != nil {
|
||||||
|
if mapping := r.FontGIDMap[fontID]; mapping != nil {
|
||||||
|
if mapped, ok := mapping[id]; ok {
|
||||||
|
return mapped, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// textGlyphAdvanceLimit 获取显式字形推进宽度
|
||||||
|
// 入参: dxs X方向偏移, dys Y方向偏移, xs X坐标列表, index 字形索引, count 字形数量, currentX 当前X坐标
|
||||||
|
// 返回: float64 推进宽度
|
||||||
|
func textGlyphAdvanceLimit(dxs, dys, xs []float64, index int, count int, currentX float64) float64 {
|
||||||
|
if index+1 >= count || len(dys) > 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if index+1 < len(xs) {
|
||||||
|
if advance := xs[index+1] - currentX; advance > 0 {
|
||||||
|
return advance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if advance, ok := textDelta(dxs, index); ok && advance > 0 {
|
||||||
|
return advance
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// textCodePositioned 判断文本编码是否带显式定位
|
||||||
|
// 入参: textCode 文本编码
|
||||||
|
// 返回: bool 是否带显式定位
|
||||||
|
func textCodePositioned(textCode TextCode) bool {
|
||||||
|
return strings.TrimSpace(textCode.DeltaX) != "" ||
|
||||||
|
strings.TrimSpace(textCode.DeltaY) != "" ||
|
||||||
|
len(parseFloats(textCode.X)) > 1 ||
|
||||||
|
len(parseFloats(textCode.Y)) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// textDelta 获取文本偏移量
|
||||||
|
// 入参: deltas 偏移量数组, index 偏移量索引
|
||||||
|
// 返回: float64 偏移量, bool 是否存在
|
||||||
|
func textDelta(deltas []float64, index int) (float64, bool) {
|
||||||
|
if len(deltas) == 0 {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
if index < len(deltas) {
|
||||||
|
return deltas[index], true
|
||||||
|
}
|
||||||
|
return deltas[len(deltas)-1], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// textCodeRunes 获取文本编码字符
|
||||||
|
// 入参: value 文本编码内容
|
||||||
|
// 返回: []rune 文本字符
|
||||||
|
func textCodeRunes(value string) []rune {
|
||||||
|
if strings.ContainsAny(value, "\r\n") {
|
||||||
|
value = strings.TrimSpace(value)
|
||||||
|
}
|
||||||
|
return []rune(value)
|
||||||
|
}
|
||||||
|
|
||||||
// parseAxialShdColor 解析轴向渐变颜色
|
// parseAxialShdColor 解析轴向渐变颜色
|
||||||
// 入参: axialShd 轴向渐变节点, alpha 透明度
|
// 入参: axialShd 轴向渐变节点, alpha 透明度
|
||||||
// 返回: color.Color 颜色对象
|
// 返回: color.Color 颜色对象
|
||||||
|
|||||||
Reference in New Issue
Block a user