diff --git a/ofdgo_font_cff.go b/ofdgo_font_cff.go index b515cb3..d819949 100644 --- a/ofdgo_font_cff.go +++ b/ofdgo_font_cff.go @@ -803,10 +803,9 @@ func getCmapFromCFF(data []byte, numGlyphs int) map[rune]uint16 { if gid == 0 { continue } + mapping[packedGlyphRune(uint16(gid))] = uint16(gid) if r, ok := adobeGB1CIDToUnicode(cid); ok { mapping[r] = uint16(gid) - } else { - mapping[0xE000+rune(gid)] = uint16(gid) } } return mapping @@ -816,7 +815,7 @@ func getCmapFromCFF(data []byte, numGlyphs int) map[rune]uint16 { if gid == 0 { continue } - mapping[0xE000+rune(gid)] = uint16(gid) + mapping[packedGlyphRune(uint16(gid))] = uint16(gid) } return mapping } @@ -838,8 +837,9 @@ func getCmapFromCFF(data []byte, numGlyphs int) map[rune]uint16 { r = getUnicodeFromName(name) } if r == 0 { - r = 0xE000 + rune(gid) + r = packedGlyphRune(uint16(gid)) } + mapping[packedGlyphRune(uint16(gid))] = uint16(gid) mapping[r] = uint16(gid) } return mapping @@ -867,7 +867,14 @@ func getCFFCIDRuneMap(data []byte) map[uint16]rune { } gidRunes := make(map[uint16]rune) for run, gid := range mapping { - gidRunes[gid] = run + if run != packedGlyphRune(gid) { + gidRunes[gid] = run + } + } + for run, gid := range mapping { + if _, ok := gidRunes[gid]; !ok { + gidRunes[gid] = run + } } result := make(map[uint16]rune) for gid, cid := range sids { diff --git a/ofdgo_font_ttf.go b/ofdgo_font_ttf.go index 192f466..3a4bebf 100644 --- a/ofdgo_font_ttf.go +++ b/ofdgo_font_ttf.go @@ -143,7 +143,7 @@ func fixTrueType(data []byte, fixCmap, fixName bool) (bool, []byte, map[rune]uin if len(mapping) == 0 { mapping = make(map[rune]uint16) for i := uint16(0); i < numGlyphs; i++ { - mapping[rune(i)] = i + mapping[packedGlyphRune(i)] = i } } newTables["cmap"] = buildCmapTable(numGlyphs, mapping) diff --git a/ofdgo_font_util.go b/ofdgo_font_util.go index 80dee86..e2fc428 100644 --- a/ofdgo_font_util.go +++ b/ofdgo_font_util.go @@ -27,6 +27,13 @@ func align4(n uint32) uint32 { return (n + 3) & ^uint32(3) } +// packedGlyphRune 获取包装字体字符 +// 入参: gid 字形ID +// 返回: rune 包装字体字符 +func packedGlyphRune(gid uint16) rune { + return 0xF0000 + rune(gid) +} + // calcTableChecksum 计算字体表校验和 // 入参: data 表数据 // 返回: uint32 校验和 diff --git a/ofdgo_renderer.go b/ofdgo_renderer.go index 3d26395..8661071 100644 --- a/ofdgo_renderer.go +++ b/ofdgo_renderer.go @@ -602,11 +602,20 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 if fillColor == nil { fillColor = canvas.Black } + var fillPaint any = fillColor + var fillColorNode *FillColor if dp != nil && dp.FillColor != nil { fillColor = parseFillColor(dp.FillColor) + fillColorNode = dp.FillColor + fillPaint = parseFillPaint(dp.FillColor, bx, by, pageH, 0, 0) } if obj.FillColor != nil { fillColor = parseFillColor(obj.FillColor) + fillColorNode = obj.FillColor + fillPaint = parseFillPaint(obj.FillColor, bx, by, pageH, 0, 0) + } + if fillPaint == nil { + fillPaint = fillColor } fontStyle := canvas.FontRegular weight := obj.Weight @@ -638,7 +647,7 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 if ff == nil { return } - face := ff.Face(sizePt, fillColor, fontStyle, canvas.FontNormal) + face := ff.Face(sizePt, fillPaint, fontStyle, canvas.FontNormal) glyphRunes := r.textObjectGlyphRunes(fontID, obj) codePos := 0 for _, tc := range obj.TextCode { @@ -683,14 +692,22 @@ func (r *Renderer) renderText(ctx *canvas.Context, obj TextObject, pageH float64 tx, ty := ctm.Transform(cx, cy) canvasX, canvasY := tx+bx, pageH-(ty+by) textWidth := face.TextWidth(str) - if fillColor != nil { - ctx.SetFillColor(fillColor) + glyphFillPaint := fillPaint + if fillColorNode != nil && fillColorNode.AxialShd != nil { + glyphFillPaint = parseFillPaint(fillColorNode, bx, by, pageH, canvasX, canvasY) + } + if glyphFillPaint != nil { + ctx.SetFill(glyphFillPaint) if embeddedFont { path, width := face.ToPath(str) textWidth = width ctx.DrawPath(canvasX, canvasY, path) } else { - text := canvas.NewTextLine(face, str, canvas.Left) + textFace := face + if fillColorNode != nil && fillColorNode.AxialShd != nil { + textFace = ff.Face(sizePt, glyphFillPaint, fontStyle, canvas.FontNormal) + } + text := canvas.NewTextLine(textFace, str, canvas.Left) ctx.DrawText(canvasX, canvasY, text) } } @@ -738,7 +755,14 @@ func (r *Renderer) loadFont(fontID string) *canvas.FontFamily { } inv := make(map[uint16]rune) for k, v := range mapping { - inv[v] = k + if k == packedGlyphRune(v) { + inv[v] = k + } + } + for k, v := range mapping { + if _, ok := inv[v]; !ok { + inv[v] = k + } } r.FontGIDMap[fontID] = inv } diff --git a/ofdgo_text.go b/ofdgo_text.go index b4d5a26..5d15b1f 100644 --- a/ofdgo_text.go +++ b/ofdgo_text.go @@ -18,6 +18,7 @@ import ( "image/color" "strconv" "strings" + "github.com/tdewolff/canvas" ) // parseColor 解析颜色字符串 @@ -58,6 +59,22 @@ func parseFillColor(fillColor *FillColor) color.Color { return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha) } +// parseFillPaint 解析填充画刷 +// 入参: fillColor 填充颜色节点, x X坐标, y Y坐标, pageH 页面高度, originX 原点X坐标, originY 原点Y坐标 +// 返回: any 填充画刷 +func parseFillPaint(fillColor *FillColor, x, y, pageH, originX, originY float64) any { + if fillColor == nil { + return nil + } + if strings.TrimSpace(fillColor.Value) != "" { + return parseColorWithAlpha(fillColor.Value, fillColor.Alpha) + } + if gradient := parseAxialShdGradient(fillColor.AxialShd, fillColor.Alpha, x, y, pageH, originX, originY); gradient != nil { + return gradient + } + return parseAxialShdColor(fillColor.AxialShd, fillColor.Alpha) +} + // parseStrokeColor 解析勾边颜色 // 入参: strokeColor 勾边颜色节点 // 返回: color.Color 颜色对象 @@ -89,6 +106,48 @@ func parseAxialShdColor(axialShd *AxialShd, alpha *int) color.Color { return color.Black } +// parseAxialShdGradient 解析轴向渐变 +// 入参: axialShd 轴向渐变节点, alpha 透明度, x X坐标, y Y坐标, pageH 页面高度, originX 原点X坐标, originY 原点Y坐标 +// 返回: canvas.Gradient 渐变对象 +func parseAxialShdGradient(axialShd *AxialShd, alpha *int, x, y, pageH, originX, originY float64) canvas.Gradient { + if axialShd == nil { + return nil + } + start := parseFloats(axialShd.StartPoint) + end := parseFloats(axialShd.EndPoint) + if len(start) < 2 || len(end) < 2 { + return nil + } + grad := canvas.NewGradient() + for _, segment := range axialShd.Segment { + if strings.TrimSpace(segment.Color.Value) == "" { + continue + } + segmentAlpha := alpha + if segmentAlpha == nil { + segmentAlpha = segment.Color.Alpha + } + grad.Add(segment.Position, colorToRGBA(parseColorWithAlpha(segment.Color.Value, segmentAlpha))) + } + if len(grad) == 0 { + return nil + } + startPoint := canvas.Point{X: x + start[0] - originX, Y: pageH - (y + start[1]) - originY} + endPoint := canvas.Point{X: x + end[0] - originX, Y: pageH - (y + end[1]) - originY} + if startPoint.Equals(endPoint) { + return nil + } + return grad.ToLinear(startPoint, endPoint) +} + +// colorToRGBA 转换颜色对象 +// 入参: c 颜色对象 +// 返回: color.RGBA RGBA颜色 +func colorToRGBA(c color.Color) color.RGBA { + r, g, b, a := c.RGBA() + return color.RGBA{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: uint8(a >> 8)} +} + // GetDeltaX 获取X轴偏移量数组 // 返回: []float64 偏移量数组 func (tc *TextCode) GetDeltaX() []float64 {