mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
149 lines
5.2 KiB
Go
149 lines
5.2 KiB
Go
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package ofdgo
|
|
|
|
import (
|
|
"context"
|
|
"image"
|
|
"io/fs"
|
|
)
|
|
|
|
// Renderer 渲染器实现
|
|
// 通过NewRenderer创建,实例及共享的Reader需串行使用
|
|
// 外部字体缺失且无可用回退时不绘制对应文字,其余内容继续;字体状态可通过FontInfos查询
|
|
// OnPageText可选,接收页面绘制时同步提取的文字,不包含图案和签名外观
|
|
// OnExportProgress可选,同步回报文档导出的已处理页数及总页数,返回错误则停止,页数完成不代表写入成功
|
|
// TransparentBackground关闭页面白底,供嵌套图案和印章保持透明背景
|
|
// Compression仅控制导出编码,OutputContext可取消输出压缩,nil使用后台上下文
|
|
type Renderer struct {
|
|
Reader *Reader
|
|
DPI float64
|
|
Compression CompressionOptions
|
|
OutputContext context.Context
|
|
RenderAnnotations bool
|
|
OnPageText func(*PageContent, *PageText)
|
|
OnExportProgress func(completed, total int) error
|
|
DrawParams map[string]*DrawParam
|
|
CompositeGraphicUnits map[string]*CompositeGraphicUnit
|
|
templatePageCache map[string]*PageContent
|
|
imageCache renderCache[string, image.Image]
|
|
fontDirs []string
|
|
fontFS []fs.FS
|
|
decodeImages bool
|
|
pageText *PageText
|
|
pageContext context.Context
|
|
textOnly bool
|
|
backends RenderBackends
|
|
backendStates map[any]any
|
|
sharedBackendStates map[any]any
|
|
resolvedFonts map[resolvedFontKey]resolvedFontResult
|
|
preparedFonts map[string]*PreparedFont
|
|
fontDigests *renderCache[fontDataKey, [32]byte]
|
|
fontPreparations *renderCache[[32]byte, PreparedFont]
|
|
fontSourcesCache *fontSourceCache
|
|
fontMetrics *renderCache[[32]byte, FontMetrics]
|
|
glyphOutlines renderCache[glyphOutlineKey, GeometryPath]
|
|
renderError error
|
|
patternReferences map[*Pattern]bool
|
|
patternPage *Matrix
|
|
TransparentBackground bool
|
|
}
|
|
|
|
// RendererOption 渲染器配置选项
|
|
type RendererOption func(*Renderer)
|
|
|
|
// ClearCache 释放派生字体、图片、模板与后端缓存,不改变文档和渲染配置
|
|
func (r *Renderer) ClearCache() {
|
|
r.backendStates = make(map[any]any)
|
|
r.imageCache = renderCache[string, image.Image]{limit: imageCacheLimit}
|
|
r.templatePageCache = make(map[string]*PageContent)
|
|
r.resetFontCache()
|
|
}
|
|
|
|
// SetFontFS 替换外部字体文件系统并重置字体缓存
|
|
// 入参: fsys 字体文件系统
|
|
func (r *Renderer) SetFontFS(fsys ...fs.FS) {
|
|
r.fontFS = append([]fs.FS(nil), fsys...)
|
|
r.resetFontCache()
|
|
}
|
|
|
|
// FontSources 返回外部字体配置副本,供自定义编译器和导出后端读取
|
|
// 内嵌字体通过Reader.FontData读取,系统字体由各实现自行匹配
|
|
// 返回: []string 字体目录, []fs.FS 字体文件系统
|
|
func (r *Renderer) FontSources() ([]string, []fs.FS) {
|
|
return append([]string(nil), r.fontDirs...), append([]fs.FS(nil), r.fontFS...)
|
|
}
|
|
|
|
// childRenderer 继承配置并复用字体文件索引与数据,文档匹配结果保持独立
|
|
// 入参: reader 子阅读器
|
|
// 返回: *Renderer 子渲染器
|
|
func (r *Renderer) childRenderer(reader *Reader) *Renderer {
|
|
opts := []RendererOption{
|
|
WithDPI(r.DPI),
|
|
WithAnnotations(r.RenderAnnotations),
|
|
WithRenderBackends(r.backends),
|
|
}
|
|
if len(r.fontDirs) > 0 {
|
|
opts = append(opts, WithFontDirs(r.fontDirs...))
|
|
}
|
|
if len(r.fontFS) > 0 {
|
|
opts = append(opts, WithFontFS(r.fontFS...))
|
|
}
|
|
renderer := NewRenderer(reader, opts...)
|
|
renderer.sharedBackendStates = r.sharedBackendStates
|
|
renderer.fontPreparations = r.fontPreparations
|
|
renderer.fontDigests = r.fontDigests
|
|
renderer.fontMetrics = r.fontMetrics
|
|
renderer.fontSourcesCache = r.fontSourcesCache.child()
|
|
renderer.decodeImages = r.decodeImages
|
|
renderer.pageContext = r.pageContext
|
|
renderer.TransparentBackground = r.TransparentBackground
|
|
return renderer
|
|
}
|
|
|
|
// loadTemplate 加载模板页面并复用解析结果
|
|
// 入参: templateID 模板ID
|
|
// 返回: *PageContent 模板页面
|
|
func (r *Renderer) loadTemplate(templateID string) *PageContent {
|
|
if page := r.templatePageCache[templateID]; page != nil {
|
|
return page
|
|
}
|
|
for _, tpl := range r.Reader.doc.CommonData.TemplatePage {
|
|
if tpl.ID != templateID {
|
|
continue
|
|
}
|
|
page, err := r.Reader.PageContent(Page{BaseLoc: tpl.BaseLoc})
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
r.templatePageCache[templateID] = page
|
|
return page
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// layerOrder 获取图层类型的绘制顺序
|
|
// 入参: kind 图层类型
|
|
// 返回: int 绘制顺序
|
|
func layerOrder(kind string) int {
|
|
switch kind {
|
|
case "Background":
|
|
return 0
|
|
case "Foreground":
|
|
return 2
|
|
}
|
|
return 1
|
|
}
|