mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
feat(加强兼容): 强化图形和字体绘制
This commit is contained in:
@@ -54,6 +54,16 @@ func fixTrueType(data []byte, fixCmap, fixName bool) (bool, []byte, map[rune]uin
|
|||||||
isCFFSfnt = true
|
isCFFSfnt = true
|
||||||
}
|
}
|
||||||
missingHead := existingTables["head"] == nil
|
missingHead := existingTables["head"] == nil
|
||||||
|
if !missingHead {
|
||||||
|
head := existingTables["head"]
|
||||||
|
if len(head) > 54 {
|
||||||
|
existingTables["head"] = head[:54]
|
||||||
|
malformedDirectory = true
|
||||||
|
}
|
||||||
|
if len(existingTables["head"]) != 54 || binary.BigEndian.Uint16(existingTables["head"][18:20]) == 0 {
|
||||||
|
missingHead = true
|
||||||
|
}
|
||||||
|
}
|
||||||
missingMaxp := existingTables["maxp"] == nil
|
missingMaxp := existingTables["maxp"] == nil
|
||||||
missingHhea := existingTables["hhea"] == nil
|
missingHhea := existingTables["hhea"] == nil
|
||||||
missingHmtx := existingTables["hmtx"] == nil
|
missingHmtx := existingTables["hmtx"] == nil
|
||||||
|
|||||||
+1
-1
@@ -185,7 +185,7 @@ func (c *CompositeGraphicUnit) decodeObject(d *xml.Decoder, start xml.StartEleme
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Clips = &clips
|
c.Clips = &clips
|
||||||
case "PageBlock":
|
case "Content", "PageBlock":
|
||||||
return c.decodePageBlock(d, start)
|
return c.decodePageBlock(d, start)
|
||||||
default:
|
default:
|
||||||
return d.Skip()
|
return d.Skip()
|
||||||
|
|||||||
+42
-34
@@ -247,7 +247,7 @@ func (r *Renderer) renderAnnotations(ctx *canvas.Context, pageID string, pageH f
|
|||||||
box, _ := ParseBox(annot.Appearance.Boundary)
|
box, _ := ParseBox(annot.Appearance.Boundary)
|
||||||
ctm := Matrix{a: 1, d: 1, e: box.X, f: box.Y}
|
ctm := Matrix{a: 1, d: 1, e: box.X, f: box.Y}
|
||||||
for _, obj := range annot.Appearance.Objects {
|
for _, obj := range annot.Appearance.Objects {
|
||||||
r.renderObject(ctx, obj, pageH, nil, nil, 0, &ctm)
|
r.renderObject(ctx, obj, pageH, nil, nil, 0, &ctm, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ func (r *Renderer) renderLayer(ctx *canvas.Context, layer Layer, pageH float64,
|
|||||||
}
|
}
|
||||||
if len(layer.Objects) > 0 {
|
if len(layer.Objects) > 0 {
|
||||||
for _, obj := range layer.Objects {
|
for _, obj := range layer.Objects {
|
||||||
r.renderObject(ctx, obj, pageH, defaultFill, defaultStroke, defaultLW, parentCTM)
|
r.renderObject(ctx, obj, pageH, defaultFill, defaultStroke, defaultLW, parentCTM, false)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -302,19 +302,19 @@ func (r *Renderer) renderLayer(ctx *canvas.Context, layer Layer, pageH float64,
|
|||||||
r.renderText(ctx, textObj, pageH, defaultFill, defaultStroke, parentCTM)
|
r.renderText(ctx, textObj, pageH, defaultFill, defaultStroke, parentCTM)
|
||||||
}
|
}
|
||||||
for _, pathObj := range layer.PathObject {
|
for _, pathObj := range layer.PathObject {
|
||||||
r.renderPath(ctx, pathObj, pageH, defaultFill, defaultStroke, defaultLW, parentCTM)
|
r.renderPath(ctx, pathObj, pageH, defaultFill, defaultStroke, defaultLW, parentCTM, false)
|
||||||
}
|
}
|
||||||
for _, imgObj := range layer.ImageObject {
|
for _, imgObj := range layer.ImageObject {
|
||||||
r.renderImage(ctx, imgObj, pageH, parentCTM)
|
r.renderImage(ctx, imgObj, pageH, parentCTM)
|
||||||
}
|
}
|
||||||
for _, cgu := range layer.CompositeGraphicUnit {
|
for _, cgu := range layer.CompositeGraphicUnit {
|
||||||
r.renderCompositeGraphicUnit(ctx, cgu, pageH, defaultFill, defaultStroke, defaultLW, parentCTM)
|
r.renderCompositeGraphicUnit(ctx, cgu, pageH, defaultFill, defaultStroke, defaultLW, parentCTM, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderCompositeGraphicUnit 渲染复合图元
|
// renderCompositeGraphicUnit 渲染复合图元
|
||||||
// 入参: ctx 画布上下文, cgu 复合图元对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM
|
// 入参: ctx 画布上下文, cgu 复合图元对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM, boundaryInCTM 边界是否参与CTM变换
|
||||||
func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu CompositeGraphicUnit, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix) {
|
func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu CompositeGraphicUnit, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix, boundaryInCTM bool) {
|
||||||
if cgu.Visible != nil && !*cgu.Visible {
|
if cgu.Visible != nil && !*cgu.Visible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -327,7 +327,7 @@ func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu Composite
|
|||||||
if ref, ok := r.CompositeGraphicUnits[cgu.ResourceID]; ok {
|
if ref, ok := r.CompositeGraphicUnits[cgu.ResourceID]; ok {
|
||||||
refCopy := *ref
|
refCopy := *ref
|
||||||
refCopy.Alpha = mergeAlpha(refCopy.Alpha, cgu.Alpha)
|
refCopy.Alpha = mergeAlpha(refCopy.Alpha, cgu.Alpha)
|
||||||
r.renderCompositeGraphicUnit(ctx, refCopy, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM)
|
r.renderCompositeGraphicUnit(ctx, refCopy, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cgu.DrawParam != "" {
|
if cgu.DrawParam != "" {
|
||||||
@@ -346,7 +346,7 @@ func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu Composite
|
|||||||
if len(cgu.Objects) > 0 {
|
if len(cgu.Objects) > 0 {
|
||||||
for _, obj := range cgu.Objects {
|
for _, obj := range cgu.Objects {
|
||||||
obj = mergeGraphicObjectAlpha(obj, cgu.Alpha)
|
obj = mergeGraphicObjectAlpha(obj, cgu.Alpha)
|
||||||
r.renderObject(ctx, obj, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM)
|
r.renderObject(ctx, obj, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM, boundaryInCTM)
|
||||||
}
|
}
|
||||||
ctx.Pop()
|
ctx.Pop()
|
||||||
return
|
return
|
||||||
@@ -357,7 +357,7 @@ func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu Composite
|
|||||||
}
|
}
|
||||||
for _, pathObj := range cgu.PathObject {
|
for _, pathObj := range cgu.PathObject {
|
||||||
pathObj.Alpha = mergeAlpha(pathObj.Alpha, cgu.Alpha)
|
pathObj.Alpha = mergeAlpha(pathObj.Alpha, cgu.Alpha)
|
||||||
r.renderPath(ctx, pathObj, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM)
|
r.renderPath(ctx, pathObj, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM, boundaryInCTM)
|
||||||
}
|
}
|
||||||
for _, textObj := range cgu.TextObject {
|
for _, textObj := range cgu.TextObject {
|
||||||
textObj.Alpha = mergeAlpha(textObj.Alpha, cgu.Alpha)
|
textObj.Alpha = mergeAlpha(textObj.Alpha, cgu.Alpha)
|
||||||
@@ -365,23 +365,23 @@ func (r *Renderer) renderCompositeGraphicUnit(ctx *canvas.Context, cgu Composite
|
|||||||
}
|
}
|
||||||
for _, subCgu := range cgu.CompositeGraphicUnit {
|
for _, subCgu := range cgu.CompositeGraphicUnit {
|
||||||
subCgu.Alpha = mergeAlpha(subCgu.Alpha, cgu.Alpha)
|
subCgu.Alpha = mergeAlpha(subCgu.Alpha, cgu.Alpha)
|
||||||
r.renderCompositeGraphicUnit(ctx, subCgu, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM)
|
r.renderCompositeGraphicUnit(ctx, subCgu, pageH, defaultFill, defaultStroke, defaultLW, ¤tCTM, boundaryInCTM)
|
||||||
}
|
}
|
||||||
ctx.Pop()
|
ctx.Pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderObject 渲染图形对象
|
// renderObject 渲染图形对象
|
||||||
// 入参: ctx 画布上下文, obj 图形对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM
|
// 入参: ctx 画布上下文, obj 图形对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM, boundaryInCTM 边界是否参与CTM变换
|
||||||
func (r *Renderer) renderObject(ctx *canvas.Context, obj GraphicObject, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix) {
|
func (r *Renderer) renderObject(ctx *canvas.Context, obj GraphicObject, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix, boundaryInCTM bool) {
|
||||||
switch obj.Type {
|
switch obj.Type {
|
||||||
case "TextObject":
|
case "TextObject":
|
||||||
r.renderText(ctx, obj.TextObject, pageH, defaultFill, defaultStroke, parentCTM)
|
r.renderText(ctx, obj.TextObject, pageH, defaultFill, defaultStroke, parentCTM)
|
||||||
case "PathObject":
|
case "PathObject":
|
||||||
r.renderPath(ctx, obj.PathObject, pageH, defaultFill, defaultStroke, defaultLW, parentCTM)
|
r.renderPath(ctx, obj.PathObject, pageH, defaultFill, defaultStroke, defaultLW, parentCTM, boundaryInCTM)
|
||||||
case "ImageObject":
|
case "ImageObject":
|
||||||
r.renderImage(ctx, obj.ImageObject, pageH, parentCTM)
|
r.renderImage(ctx, obj.ImageObject, pageH, parentCTM)
|
||||||
case "CompositeGraphicUnit", "CompositeObject":
|
case "CompositeGraphicUnit", "CompositeObject":
|
||||||
r.renderCompositeGraphicUnit(ctx, obj.CompositeGraphicUnit, pageH, defaultFill, defaultStroke, defaultLW, parentCTM)
|
r.renderCompositeGraphicUnit(ctx, obj.CompositeGraphicUnit, pageH, defaultFill, defaultStroke, defaultLW, parentCTM, boundaryInCTM)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,8 +532,8 @@ func imageWithAlpha(img image.Image, alpha *int) image.Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// renderPath 渲染路径
|
// renderPath 渲染路径
|
||||||
// 入参: ctx 画布上下文, obj 路径对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM
|
// 入参: ctx 画布上下文, obj 路径对象, pageH 页面高度, defaultFill 默认填充色, defaultStroke 默认描边色, defaultLW 默认线宽, parentCTM 父级CTM, boundaryInCTM 边界是否参与CTM变换
|
||||||
func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix) {
|
func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64, defaultFill, defaultStroke color.Color, defaultLW float64, parentCTM *Matrix, boundaryInCTM bool) {
|
||||||
if obj.Visible != nil && !*obj.Visible {
|
if obj.Visible != nil && !*obj.Visible {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -638,7 +638,7 @@ func (r *Renderer) renderPath(ctx *canvas.Context, obj PathObject, pageH float64
|
|||||||
dashPattern[i] *= scale
|
dashPattern[i] *= scale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p := r.buildPath(obj, pageH, ctm)
|
p := r.buildPath(obj, pageH, ctm, boundaryInCTM)
|
||||||
if rectPath := r.buildTinyFillRectPath(obj, pageH, ctm, bx, by); rectPath != nil {
|
if rectPath := r.buildTinyFillRectPath(obj, pageH, ctm, bx, by); rectPath != nil {
|
||||||
p = rectPath
|
p = rectPath
|
||||||
}
|
}
|
||||||
@@ -755,7 +755,7 @@ func (r *Renderer) renderPattern(ctx *canvas.Context, pattern *Pattern, defaultC
|
|||||||
for iy := startY; iy <= endY; iy++ {
|
for iy := startY; iy <= endY; iy++ {
|
||||||
tileCTM := patternCTM.Multiply(TranslationMatrix(float64(ix)*xStep, float64(iy)*yStep))
|
tileCTM := patternCTM.Multiply(TranslationMatrix(float64(ix)*xStep, float64(iy)*yStep))
|
||||||
for _, obj := range pattern.CellContent.Objects {
|
for _, obj := range pattern.CellContent.Objects {
|
||||||
r.renderObject(ctx, obj, pageH, defaultColor, defaultColor, 0, &tileCTM)
|
r.renderObject(ctx, obj, pageH, defaultColor, defaultColor, 0, &tileCTM, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1273,15 +1273,23 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// buildPath 解析路径并返回Canvas Path
|
// buildPath 解析路径并返回Canvas Path
|
||||||
// 入参: obj 路径对象, pageH 页面高度, ctm 变换矩阵
|
// 入参: obj 路径对象, pageH 页面高度, ctm 变换矩阵, boundaryInCTM 边界是否参与CTM变换
|
||||||
// 返回: *canvas.Path 路径对象
|
// 返回: *canvas.Path 路径对象
|
||||||
func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.Path {
|
func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix, boundaryInCTM bool) *canvas.Path {
|
||||||
bx, by := 0.0, 0.0
|
bx, by := 0.0, 0.0
|
||||||
if obj.Boundary != "" {
|
if obj.Boundary != "" {
|
||||||
if box, err := ParseBox(obj.Boundary); err == nil {
|
if box, err := ParseBox(obj.Boundary); err == nil {
|
||||||
bx, by = box.X, box.Y
|
bx, by = box.X, box.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
point := func(x, y float64) (float64, float64) {
|
||||||
|
if boundaryInCTM {
|
||||||
|
tx, ty := ctm.Transform(x+bx, y+by)
|
||||||
|
return tx, pageH - ty
|
||||||
|
}
|
||||||
|
tx, ty := ctm.Transform(x, y)
|
||||||
|
return tx + bx, pageH - (ty + by)
|
||||||
|
}
|
||||||
p := &canvas.Path{}
|
p := &canvas.Path{}
|
||||||
tokens := strings.Fields(obj.AbbreviatedData)
|
tokens := strings.Fields(obj.AbbreviatedData)
|
||||||
for i := 0; i < len(tokens); {
|
for i := 0; i < len(tokens); {
|
||||||
@@ -1292,16 +1300,16 @@ func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.
|
|||||||
if i+1 < len(tokens) {
|
if i+1 < len(tokens) {
|
||||||
x, _ := strconv.ParseFloat(tokens[i], 64)
|
x, _ := strconv.ParseFloat(tokens[i], 64)
|
||||||
y, _ := strconv.ParseFloat(tokens[i+1], 64)
|
y, _ := strconv.ParseFloat(tokens[i+1], 64)
|
||||||
tx, ty := ctm.Transform(x, y)
|
tx, ty := point(x, y)
|
||||||
p.MoveTo(tx+bx, pageH-(ty+by))
|
p.MoveTo(tx, ty)
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
case "L":
|
case "L":
|
||||||
if i+1 < len(tokens) {
|
if i+1 < len(tokens) {
|
||||||
x, _ := strconv.ParseFloat(tokens[i], 64)
|
x, _ := strconv.ParseFloat(tokens[i], 64)
|
||||||
y, _ := strconv.ParseFloat(tokens[i+1], 64)
|
y, _ := strconv.ParseFloat(tokens[i+1], 64)
|
||||||
tx, ty := ctm.Transform(x, y)
|
tx, ty := point(x, y)
|
||||||
p.LineTo(tx+bx, pageH-(ty+by))
|
p.LineTo(tx, ty)
|
||||||
i += 2
|
i += 2
|
||||||
}
|
}
|
||||||
case "B":
|
case "B":
|
||||||
@@ -1312,10 +1320,10 @@ func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.
|
|||||||
y2, _ := strconv.ParseFloat(tokens[i+3], 64)
|
y2, _ := strconv.ParseFloat(tokens[i+3], 64)
|
||||||
x3, _ := strconv.ParseFloat(tokens[i+4], 64)
|
x3, _ := strconv.ParseFloat(tokens[i+4], 64)
|
||||||
y3, _ := strconv.ParseFloat(tokens[i+5], 64)
|
y3, _ := strconv.ParseFloat(tokens[i+5], 64)
|
||||||
tx1, ty1 := ctm.Transform(x1, y1)
|
tx1, ty1 := point(x1, y1)
|
||||||
tx2, ty2 := ctm.Transform(x2, y2)
|
tx2, ty2 := point(x2, y2)
|
||||||
tx3, ty3 := ctm.Transform(x3, y3)
|
tx3, ty3 := point(x3, y3)
|
||||||
p.CubeTo(tx1+bx, pageH-(ty1+by), tx2+bx, pageH-(ty2+by), tx3+bx, pageH-(ty3+by))
|
p.CubeTo(tx1, ty1, tx2, ty2, tx3, ty3)
|
||||||
i += 6
|
i += 6
|
||||||
}
|
}
|
||||||
case "Q":
|
case "Q":
|
||||||
@@ -1324,9 +1332,9 @@ func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.
|
|||||||
y1, _ := strconv.ParseFloat(tokens[i+1], 64)
|
y1, _ := strconv.ParseFloat(tokens[i+1], 64)
|
||||||
x2, _ := strconv.ParseFloat(tokens[i+2], 64)
|
x2, _ := strconv.ParseFloat(tokens[i+2], 64)
|
||||||
y2, _ := strconv.ParseFloat(tokens[i+3], 64)
|
y2, _ := strconv.ParseFloat(tokens[i+3], 64)
|
||||||
tx1, ty1 := ctm.Transform(x1, y1)
|
tx1, ty1 := point(x1, y1)
|
||||||
tx2, ty2 := ctm.Transform(x2, y2)
|
tx2, ty2 := point(x2, y2)
|
||||||
p.QuadTo(tx1+bx, pageH-(ty1+by), tx2+bx, pageH-(ty2+by))
|
p.QuadTo(tx1, ty1, tx2, ty2)
|
||||||
i += 4
|
i += 4
|
||||||
}
|
}
|
||||||
case "A":
|
case "A":
|
||||||
@@ -1341,9 +1349,9 @@ func (r *Renderer) buildPath(obj PathObject, pageH float64, ctm Matrix) *canvas.
|
|||||||
sx := math.Hypot(ctm.a, ctm.c)
|
sx := math.Hypot(ctm.a, ctm.c)
|
||||||
sy := math.Hypot(ctm.b, ctm.d)
|
sy := math.Hypot(ctm.b, ctm.d)
|
||||||
ctmRot := math.Atan2(ctm.b, ctm.a) * 180 / math.Pi
|
ctmRot := math.Atan2(ctm.b, ctm.a) * 180 / math.Pi
|
||||||
tx, ty := ctm.Transform(x, y)
|
tx, ty := point(x, y)
|
||||||
sweep = !sweep
|
sweep = !sweep
|
||||||
p.ArcTo(rx*sx, ry*sy, -(rot + ctmRot), large, sweep, tx+bx, pageH-(ty+by))
|
p.ArcTo(rx*sx, ry*sy, -(rot + ctmRot), large, sweep, tx, ty)
|
||||||
i += 7
|
i += 7
|
||||||
}
|
}
|
||||||
case "C":
|
case "C":
|
||||||
@@ -1370,7 +1378,7 @@ func (r *Renderer) buildClipPath(clips *Clips, pageH float64, bx, by float64, ob
|
|||||||
}
|
}
|
||||||
for _, pathObj := range area.Path {
|
for _, pathObj := range area.Path {
|
||||||
ctm := areaCTM.Multiply(NewMatrix(pathObj.CTM))
|
ctm := areaCTM.Multiply(NewMatrix(pathObj.CTM))
|
||||||
cp := r.buildPath(pathObj, pageH, ctm)
|
cp := r.buildPath(pathObj, pageH, ctm, true)
|
||||||
cp.Translate(bx, -by)
|
cp.Translate(bx, -by)
|
||||||
cp.Close()
|
cp.Close()
|
||||||
if clipPath == nil {
|
if clipPath == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user