mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
1 parent
28175723e6
commit
32585c6343
46 files changed
+84
-168
No files matched your search
@@ -6,11 +6,11 @@ require (
|
||||
github.com/emmansun/gmsm v0.45.0
|
||||
github.com/go-fonts/latin-modern v0.3.3
|
||||
github.com/go-text/typesetting v0.3.5
|
||||
github.com/mububoki/jpeg2000 v1.0.0
|
||||
github.com/tdewolff/canvas v0.0.0-20260923214215-09804640d00c
|
||||
github.com/tdewolff/font v0.0.0-20260913163313-54f98bb59ee6
|
||||
github.com/xiaoqidun/jbig2 v1.1.1
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261008074859-a724a7b51281
|
||||
github.com/xiaoqidun/j2kgo v0.0.0-20261009021143-70af958df87b
|
||||
github.com/xiaoqidun/jbig2 v1.1.2
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261009023208-1da0dd4ed99d
|
||||
golang.org/x/crypto v0.57.0
|
||||
golang.org/x/image v0.46.0
|
||||
golang.org/x/text v0.42.0
|
||||
|
||||
@@ -38,8 +38,6 @@ github.com/go-text/typesetting-utils v0.0.0-20260419141703-4ffe8874dabc h1:8FGo2
|
||||
github.com/go-text/typesetting-utils v0.0.0-20260419141703-4ffe8874dabc/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/mububoki/jpeg2000 v1.0.0 h1:1ha5mqCg0DMK6zbbBp9bkUjEds4HYwQqmU3ItF3k9qs=
|
||||
github.com/mububoki/jpeg2000 v1.0.0/go.mod h1:q+kfbMgsqawC9I10Zk+goSZ8+ac4cOzcWdIL1vpsDLs=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||
@@ -60,10 +58,12 @@ github.com/tdewolff/parse/v2 v2.8.16 h1:bLk5svUOQRkW/Y2SJ+DeENSIkZBcTIkq+Atyv5D8
|
||||
github.com/tdewolff/parse/v2 v2.8.16/go.mod h1:XdsoSFThlVIRIajAuqz1evNY7bagZS8LBOPA3aVopwQ=
|
||||
github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
|
||||
github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||
github.com/xiaoqidun/jbig2 v1.1.1 h1:SjliS9ZO0e9HX5oYUfBuXrfFsXhWricrSz+XY4zORDI=
|
||||
github.com/xiaoqidun/jbig2 v1.1.1/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261008074859-a724a7b51281 h1:xtRrxDRoPCN+IzqaAC8BR334Uif9VScpwTa4fk2gfBg=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261008074859-a724a7b51281/go.mod h1:4Pf0JO0BEf1uzRY+uZjlMjN/OPn3PYa0YMi6cqPPTLQ=
|
||||
github.com/xiaoqidun/j2kgo v0.0.0-20261009021143-70af958df87b h1:hKZ0usKYqWQt9Cg0OePzdf9McTMOTIHpRhAt8f7Qa1c=
|
||||
github.com/xiaoqidun/j2kgo v0.0.0-20261009021143-70af958df87b/go.mod h1:DCwAfuDzCDYqUiAlZ7BDwigTjaXw7o9L1FtEma/D1aA=
|
||||
github.com/xiaoqidun/jbig2 v1.1.2 h1:w3BszJmnzvp49sWHIEB+D5znXEnGEFtx4PBpkbSuOfw=
|
||||
github.com/xiaoqidun/jbig2 v1.1.2/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261009023208-1da0dd4ed99d h1:NEfcN+Cwpfbx2rhSLtBErDvab6kPZCeePpYk6tQmr7U=
|
||||
github.com/xiaoqidun/pdfgo v0.0.0-20261009023208-1da0dd4ed99d/go.mod h1:vJEUu1qEqaKOHsovEXk0M/tT2RPEtMPaHB8yPFcnNhQ=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yuin/goldmark v1.8.5 h1:r6N5afV5qj/5S4UTch8agZHJ8UxNCMwX7WjkkJam2NA=
|
||||
|
||||
@@ -1724,7 +1724,7 @@ func captureEditorSelection(page int, ids []string) (*editorClipboard, error) {
|
||||
}
|
||||
|
||||
// pasteEditorSelection 原子粘贴正文和注解,共享字体与图片数据
|
||||
// 入参: page 目标页, clipboard 快照, dx、dy 位移
|
||||
// 入参: page 目标页, clipboard 快照, dx 横向位移, dy 纵向位移
|
||||
// 返回: []string 新画布标识, error 错误信息
|
||||
func pasteEditorSelection(page int, clipboard *editorClipboard, dx, dy float64) ([]string, error) {
|
||||
ids, annotations, err := currentEditor.PasteSelection(page, clipboard.selection, dx, dy)
|
||||
@@ -2747,7 +2747,7 @@ func pasteObjects(args []js.Value) (any, error) {
|
||||
}
|
||||
|
||||
// copyEditorObjects 复制快照并更新预览,返回新对象标识
|
||||
// 入参: page 目标页, objects 对象快照, dx、dy 毫米位移
|
||||
// 入参: page 目标页, objects 对象快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: any 文档信息及新选区, error 错误信息
|
||||
func copyEditorObjects(page int, objects []ofdgo.GraphicObject, dx, dy float64) (any, error) {
|
||||
ids, err := currentEditor.CopyObjects(page, objects, dx, dy)
|
||||
|
||||
@@ -379,6 +379,8 @@ func (s *Session) PageText(index int) (*ofdgo.PageText, error) {
|
||||
}
|
||||
|
||||
// cachedPageText 获取缓存索引并更新最近访问顺序
|
||||
// 入参: index 页面索引
|
||||
// 返回: *ofdgo.PageText 文字索引,未缓存时为nil
|
||||
func (s *Session) cachedPageText(index int) *ofdgo.PageText {
|
||||
text := s.textCache[index]
|
||||
if text != nil {
|
||||
@@ -388,6 +390,7 @@ func (s *Session) cachedPageText(index int) *ofdgo.PageText {
|
||||
}
|
||||
|
||||
// cachePageText 保留最近访问的文字索引,避免全文搜索持续占用内存
|
||||
// 入参: index 页面索引, text 文字索引
|
||||
func (s *Session) cachePageText(index int, text *ofdgo.PageText) {
|
||||
if position := slices.Index(s.textOrder, index); position >= 0 {
|
||||
s.textOrder = slices.Delete(s.textOrder, position, position+1)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SVG输出模式,控制资源内嵌和对象结构
|
||||
const (
|
||||
SVGEmbedded SVGMode = iota
|
||||
SVGExternalFonts
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/xiaoqidun/pdfgo"
|
||||
)
|
||||
|
||||
// 与PDFGo共用输出压缩模式和有损压缩等级
|
||||
const (
|
||||
CompressionUnchanged = pdfgo.CompressionUnchanged
|
||||
CompressionLossless = pdfgo.CompressionLossless
|
||||
@@ -42,6 +43,7 @@ const (
|
||||
CompressionStrong = pdfgo.CompressionStrong
|
||||
)
|
||||
|
||||
// outputOptimizationBufferLimit 限制压缩时的单个输出缓冲,单位为字节
|
||||
const outputOptimizationBufferLimit = 64 << 20
|
||||
|
||||
// CompressionMode 选择默认、无损或有损输出策略
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"slices"
|
||||
)
|
||||
|
||||
// 底纹去重的最小编码长度、候选数量及引用数量上限
|
||||
const (
|
||||
compressionPatternMinimum = 4096
|
||||
compressionPatternLimit = 4096
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
package ofdgo
|
||||
|
||||
// defaultPathLineWidth 为默认描边宽度,单位为毫米
|
||||
const defaultPathLineWidth = 0.353
|
||||
|
||||
// defaultMiterLimit 为默认尖角限制
|
||||
const defaultMiterLimit = 3.528
|
||||
|
||||
// mergeGraphicObjectAlpha 合并图形对象透明度
|
||||
|
||||
@@ -471,6 +471,8 @@ func (e *Editor) AddImage(data []byte) (string, error) {
|
||||
}
|
||||
|
||||
// addImage 注册图片资源,复用调用方已完成解码的像素数据
|
||||
// 入参: data 图片编码数据, config 图片配置, format 图片格式, decoded 已解码图像,可为nil
|
||||
// 返回: string 资源标识, error 格式或资源错误
|
||||
func (e *Editor) addImage(data []byte, config image.Config, format string, decoded image.Image) (string, error) {
|
||||
if (format != "png" && format != "jpeg" && format != "jbig2") || config.Width <= 0 || config.Height <= 0 {
|
||||
return "", fmt.Errorf("only PNG, JPEG and JBIG2 images are supported")
|
||||
|
||||
@@ -70,7 +70,7 @@ func (e *Editor) CaptureAnnotations(page int, ids []string) (*AnnotationSelectio
|
||||
|
||||
// PasteAnnotations 将注解快照粘贴到指定页并平移,保留动作目标和原有外观
|
||||
// 全部标识重新分配,页级资源提升为文档资源,一次操作计入一条撤销记录
|
||||
// 入参: page 目标页面索引, selection 当前编辑器快照, dx、dy 页面毫米位移
|
||||
// 入参: page 目标页面索引, selection 当前编辑器快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: []string 新注解标识, error 错误信息
|
||||
func (e *Editor) PasteAnnotations(page int, selection *AnnotationSelection, dx, dy float64) ([]string, error) {
|
||||
if selection == nil || selection.editor != e || !finite(dx) || !finite(dy) {
|
||||
|
||||
@@ -71,14 +71,14 @@ func (e *Editor) Objects(page int, ids []string) ([]GraphicObject, error) {
|
||||
|
||||
// CopyObjects 将对象快照按输入顺序复制到目标页并平移,分配新ID,提交一次撤销记录
|
||||
// 对象引用当前Editor已注册的资源,保留段落信息,不修改输入快照
|
||||
// 入参: page 目标页面索引, objects 对象快照, dx、dy 毫米位移
|
||||
// 入参: page 目标页面索引, objects 对象快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: []string 按绘制顺序排列的新对象标识, error 错误信息
|
||||
func (e *Editor) CopyObjects(page int, objects []GraphicObject, dx, dy float64) ([]string, error) {
|
||||
return e.CopyObjectsContext(context.Background(), page, objects, dx, dy)
|
||||
}
|
||||
|
||||
// CopyObjectsContext 复制对象快照,准备期间取消不提交对象或撤销记录
|
||||
// 入参: ctx 取消上下文, page 目标页, objects 对象快照, dx、dy 毫米位移
|
||||
// 入参: ctx 取消上下文, page 目标页, objects 对象快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: []string 新对象标识, error 校验或取消错误
|
||||
func (e *Editor) CopyObjectsContext(ctx context.Context, page int, objects []GraphicObject, dx, dy float64) ([]string, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
@@ -392,7 +392,7 @@ func (e *Editor) UpdateObjects(page int, objects []GraphicObject) error {
|
||||
}
|
||||
|
||||
// TransformObjects 同页对象以页面原点等比缩放后统一平移,保持相对位置,一次撤销恢复全部
|
||||
// 入参: page 页面索引, ids 对象标识, dx、dy 位移, scale 正缩放比例
|
||||
// 入参: page 页面索引, ids 对象标识, dx 横向位移, dy 纵向位移, scale 正缩放比例
|
||||
// 返回: error 错误信息
|
||||
func (e *Editor) TransformObjects(page int, ids []string, dx, dy, scale float64) error {
|
||||
if !finite(dx) || !finite(dy) || !finite(scale) || scale <= 0 {
|
||||
@@ -477,7 +477,7 @@ func (e *Editor) DeleteObjects(page int, ids []string) error {
|
||||
}
|
||||
|
||||
// compareEditorPosition 比较对象在页面结构中的先后顺序
|
||||
// 入参: a、b 对象位置
|
||||
// 入参: a 第一个对象的位置, b 第二个对象的位置
|
||||
// 返回: int 比较结果
|
||||
func compareEditorPosition(a, b editorObjectPosition) int {
|
||||
if value := cmp.Compare(a.layer, b.layer); value != 0 {
|
||||
|
||||
@@ -149,7 +149,7 @@ func (e *Editor) CompositeObjectsAt(page int, path ObjectPath, indexes []int) ([
|
||||
}
|
||||
|
||||
// TransformCompositeObjects 在页面坐标中等比缩放并平移内部选区,只隔离被修改实例的资源
|
||||
// 入参: page 页面索引, path 父复合对象路径, indexes 成员序号, dx、dy 位移, scale 正缩放比例
|
||||
// 入参: page 页面索引, path 父复合对象路径, indexes 成员序号, dx 横向位移, dy 纵向位移, scale 正缩放比例
|
||||
// 返回: error 错误信息
|
||||
func (e *Editor) TransformCompositeObjects(page int, path ObjectPath, indexes []int, dx, dy, scale float64) error {
|
||||
if !finite(dx) || !finite(dy) || !finite(scale) || scale <= 0 {
|
||||
|
||||
@@ -35,7 +35,7 @@ type CompositeSelection struct {
|
||||
}
|
||||
|
||||
// PasteCompositeSelection 将内部对象快照粘贴到页面顶层,保持嵌套结构、源继承外观和裁剪
|
||||
// 入参: page 目标页, selection 当前编辑器内捕获的快照, dx、dy 页面位移
|
||||
// 入参: page 目标页, selection 当前编辑器内捕获的快照, dx 页面横向位移, dy 页面纵向位移
|
||||
// 返回: []string 新对象标识, error 错误信息
|
||||
func (e *Editor) PasteCompositeSelection(page int, selection *CompositeSelection, dx, dy float64) ([]string, error) {
|
||||
if !finite(dx) || !finite(dy) {
|
||||
@@ -108,7 +108,7 @@ func (e *Editor) CaptureCompositeObjects(page int, path ObjectPath, indexes []in
|
||||
// PasteCompositeObjects 将快照粘贴至内部范围末尾,不依赖源成员当前的序号或存在性
|
||||
// 同范围沿用原容器和当前继承样式,跨范围固定对象的源外观,位移使用页面毫米
|
||||
// 目标范围的父透明度及裁剪仍作用于新成员,全部成员提交一次撤销记录
|
||||
// 入参: page 页面索引, path 父复合路径, selection 捕获的快照, dx、dy 页面位移
|
||||
// 入参: page 页面索引, path 父复合路径, selection 捕获的快照, dx 页面横向位移, dy 页面纵向位移
|
||||
// 返回: []int 新成员序号, error 错误信息
|
||||
func (e *Editor) PasteCompositeObjects(page int, path ObjectPath, selection *CompositeSelection, dx, dy float64) ([]int, error) {
|
||||
if selection == nil || selection.editor != e {
|
||||
|
||||
@@ -36,7 +36,7 @@ func (e *Editor) AddCompositeObject(page int, path ObjectPath, object GraphicObj
|
||||
|
||||
// CopyObjectsToComposite 将页面坐标快照复制到内部范围,隔离目标继承样式并分配新标识
|
||||
// 保真快照保留原文,全部对象成功后提交一次撤销记录
|
||||
// 入参: page 页面索引, path 父路径, objects 当前文档快照或基本对象, dx、dy 页面位移
|
||||
// 入参: page 页面索引, path 父路径, objects 当前文档快照或基本对象, dx 页面横向位移, dy 页面纵向位移
|
||||
// 返回: []int 新成员序号, error 错误信息
|
||||
func (e *Editor) CopyObjectsToComposite(page int, path ObjectPath, objects []GraphicObject, dx, dy float64) ([]int, error) {
|
||||
if !finite(dx) || !finite(dy) {
|
||||
|
||||
@@ -34,7 +34,7 @@ func (e *Editor) DeleteCompositeObjects(page int, path ObjectPath, indexes []int
|
||||
}
|
||||
|
||||
// CopyCompositeObjects 在原容器末尾复制选区并按页面毫米平移,保留原文并重映射副本内部标识
|
||||
// 入参: page 页面索引, path 父复合路径, indexes 同一容器的成员序号, dx、dy 页面位移
|
||||
// 入参: page 页面索引, path 父复合路径, indexes 同一容器的成员序号, dx 页面横向位移, dy 页面纵向位移
|
||||
// 返回: []int 按绘制顺序排列的副本序号, error 错误信息
|
||||
func (e *Editor) CopyCompositeObjects(page int, path ObjectPath, indexes []int, dx, dy float64) ([]int, error) {
|
||||
if !finite(dx) || !finite(dy) {
|
||||
@@ -224,7 +224,7 @@ func (n *editorCompositeNode) siblings() []*editorCompositeNode {
|
||||
}
|
||||
|
||||
// copyCompositeNodes 复制成员原文并统一重映射标识,保持副本之间的引用
|
||||
// 入参: renderer 渲染器, nodes 快照, dx、dy 页面位移
|
||||
// 入参: renderer 渲染器, nodes 快照, dx 页面横向位移, dy 页面纵向位移
|
||||
// 返回: []byte 副本XML, map[string]editorCompositeState 会话信息, error 错误信息
|
||||
func (e *Editor) copyCompositeNodes(renderer *Renderer, nodes []*editorCompositeNode, dx, dy float64) ([]byte, map[string]editorCompositeState, error) {
|
||||
ids := make(map[string]string)
|
||||
|
||||
@@ -157,7 +157,7 @@ func (e *Editor) addImagePage(data []byte, options ImagePageOptions) (int, error
|
||||
}
|
||||
|
||||
// imagePageOrientation 将EXIF方向映射为单位图像到页面局部坐标的变换
|
||||
// 入参: orientation EXIF方向值, w、h 图片在页面上的宽高,单位为毫米
|
||||
// 入参: orientation EXIF方向值, w 页面上的图片宽度,单位为毫米, h 页面上的图片高度,单位为毫米
|
||||
// 返回: Matrix 图像坐标变换
|
||||
func imagePageOrientation(orientation int, w, h float64) Matrix {
|
||||
switch orientation {
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 资源引用类型,区分无引用、标识引用和文件引用
|
||||
const (
|
||||
editorReferenceNone = iota
|
||||
editorReferenceID
|
||||
@@ -40,17 +41,9 @@ type editorResourceRefs struct {
|
||||
fonts map[string]*editorFontUsage
|
||||
}
|
||||
|
||||
// compactSourceResources 在保存副本中清理无引用字体、图片和已删除附件,并裁剪可完整确认用字的原有字体
|
||||
// 按GB/T33190-2016附录A检查标识和路径引用,包括模板、注释、底纹、裁剪、版本和其他文档
|
||||
// 全包检查保留孤立XML中的引用;未知命名空间、扩展数据或无法解析的XML使本次清理跳过
|
||||
// 多文档包保留原资源,避免独立文档的同号资源和共享文件被误删或裁剪
|
||||
// 入参: parts 已修改和新增的包内条目, progress 保存进度回调
|
||||
// 返回: map[string]bool 可移除的二进制条目, error 读取错误
|
||||
func (e *Editor) compactSourceResources(parts map[string][]byte, progress editorProgress) (map[string]bool, error) {
|
||||
return e.compactSourceReferences(parts, progress, nil)
|
||||
}
|
||||
|
||||
// compactSourceReferences 合并自产页面的已知引用,其他条目仍完整扫描
|
||||
// 按GB/T33190-2016附录A检查标识和路径引用,保留孤立XML中的引用
|
||||
// 多文档、未知扩展或无法解析的XML不清理资源,避免误删共享或无法确认用途的条目
|
||||
// 入参: parts 输出条目, progress 保存进度回调, generated 自产页面及引用
|
||||
// 返回: map[string]bool 可移除条目, error 读取或取消错误
|
||||
func (e *Editor) compactSourceReferences(parts map[string][]byte, progress editorProgress, generated map[string]editorGeneratedReferences) (map[string]bool, error) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (e *Editor) CaptureSelection(page int, objects, annotations []string) (*Obj
|
||||
}
|
||||
|
||||
// PasteSelection 原子粘贴正文与注解并平移,失败回滚,一次撤销恢复全部
|
||||
// 入参: page 目标页面索引, selection 当前编辑器快照, dx、dy 页面毫米位移
|
||||
// 入参: page 目标页面索引, selection 当前编辑器快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: []string 新正文标识, []string 新注解标识, error 标识、资源或编辑错误
|
||||
func (e *Editor) PasteSelection(page int, selection *ObjectSelection, dx, dy float64) ([]string, []string, error) {
|
||||
if selection == nil || selection.editor != e || !finite(dx) || !finite(dy) {
|
||||
@@ -65,7 +65,7 @@ func (e *Editor) PasteSelection(page int, selection *ObjectSelection, dx, dy flo
|
||||
}
|
||||
|
||||
// PasteSelectionToComposite 将正文快照粘贴至内部容器,保留源外观,拒绝嵌套注解
|
||||
// 入参: page 目标页面索引, path 父复合路径, selection 当前编辑器快照, dx、dy 页面毫米位移
|
||||
// 入参: page 目标页面索引, path 父复合路径, selection 当前编辑器快照, dx 横向位移,单位为毫米, dy 纵向位移,单位为毫米
|
||||
// 返回: []int 新成员序号, error 选区、资源或编辑错误
|
||||
func (e *Editor) PasteSelectionToComposite(page int, path ObjectPath, selection *ObjectSelection, dx, dy float64) ([]int, error) {
|
||||
if selection == nil || selection.editor != e {
|
||||
|
||||
@@ -214,7 +214,7 @@ func (obj TextObject) ResizeTextFrame(offset, width float64) (TextObject, error)
|
||||
}
|
||||
|
||||
// transformObject 对原有复杂对象仅更新变换,不重建其文字、画刷或其他局部属性
|
||||
// 入参: object 对象, dx、dy 页面位移, scale 缩放比例
|
||||
// 入参: object 对象, dx 页面横向位移, dy 页面纵向位移, scale 缩放比例
|
||||
// 返回: GraphicObject 新对象, error 错误信息
|
||||
func (e *Editor) transformObject(object GraphicObject, dx, dy, scale float64) (GraphicObject, error) {
|
||||
if object.Type == "ImageObject" && object.ImageObject.Border != nil && scale != 1 {
|
||||
|
||||
+1
-1
@@ -467,7 +467,7 @@ func editorXMLMerge(data []byte, node *editorXML, oldXML, newXML []byte) ([]byte
|
||||
}
|
||||
|
||||
// editorXMLMergeContent 按字段合并子节点,保留未修改字段、扩展节点和注释
|
||||
// 入参: data、node 原文节点, oldXML、oldNode 修改前编码, newXML、newNode 修改后编码
|
||||
// 入参: data 原文数据, node 原文节点, oldXML 修改前数据, oldNode 修改前节点, newXML 修改后数据, newNode 修改后节点
|
||||
// 返回: []byte 子节点内容, error 错误信息
|
||||
func editorXMLMergeContent(data []byte, node *editorXML, oldXML []byte, oldNode *editorXML, newXML []byte, newNode *editorXML) ([]byte, error) {
|
||||
if len(oldNode.children) == 0 && len(newNode.children) == 0 {
|
||||
|
||||
@@ -916,70 +916,6 @@ func getCFFIndexData(data []byte, offset int) ([]byte, int) {
|
||||
return data[base : base+off1-1], end - offset
|
||||
}
|
||||
|
||||
// readCFFIndexItems 读取CFF索引中的所有数据项
|
||||
// 入参: data CFF数据, offset 索引偏移
|
||||
// 返回: [][]byte 数据项列表
|
||||
func readCFFIndexItems(data []byte, offset int) [][]byte {
|
||||
items, _, _ := readType2Index(data, offset)
|
||||
return items
|
||||
}
|
||||
|
||||
// parseCFFFDSelect 解析CID CFF的FDSelect
|
||||
// 入参: data CFF数据, offset FDSelect偏移, numGlyphs 字形数量
|
||||
// 返回: []int 字形对应的FD索引
|
||||
func parseCFFFDSelect(data []byte, offset int, numGlyphs int) []int {
|
||||
result := make([]int, numGlyphs)
|
||||
if offset <= 0 || offset >= len(data) {
|
||||
return result
|
||||
}
|
||||
format := data[offset]
|
||||
pos := offset + 1
|
||||
switch format {
|
||||
case 0:
|
||||
for i := 0; i < numGlyphs && pos+i < len(data); i++ {
|
||||
result[i] = int(data[pos+i])
|
||||
}
|
||||
case 3:
|
||||
if pos+2 > len(data) {
|
||||
return result
|
||||
}
|
||||
nRanges := int(binary.BigEndian.Uint16(data[pos:]))
|
||||
pos += 2
|
||||
ranges := make([]struct {
|
||||
first int
|
||||
fd int
|
||||
}, 0, nRanges)
|
||||
for i := 0; i < nRanges && pos+3 <= len(data); i++ {
|
||||
first := int(binary.BigEndian.Uint16(data[pos:]))
|
||||
fd := int(data[pos+2])
|
||||
ranges = append(ranges, struct {
|
||||
first int
|
||||
fd int
|
||||
}{first: first, fd: fd})
|
||||
pos += 3
|
||||
}
|
||||
if pos+2 > len(data) {
|
||||
return result
|
||||
}
|
||||
sentinel := int(binary.BigEndian.Uint16(data[pos:]))
|
||||
for i, item := range ranges {
|
||||
end := sentinel
|
||||
if i+1 < len(ranges) {
|
||||
end = ranges[i+1].first
|
||||
}
|
||||
if end > numGlyphs {
|
||||
end = numGlyphs
|
||||
}
|
||||
for gid := item.first; gid < end; gid++ {
|
||||
if gid >= 0 && gid < numGlyphs {
|
||||
result[gid] = item.fd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// cffSubrBias 获取Type2子程序偏移
|
||||
// 入参: count 子程序数量
|
||||
// 返回: int 偏移量
|
||||
|
||||
+9
-11
@@ -25,17 +25,15 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ fs.FS = (*FontFS)(nil)
|
||||
|
||||
var _ fs.ReadDirFS = (*FontFS)(nil)
|
||||
|
||||
var _ fs.GlobFS = (*FontFS)(nil)
|
||||
|
||||
var _ fs.File = (*fontMemFile)(nil)
|
||||
|
||||
var _ fs.ReadDirFile = (*fontDir)(nil)
|
||||
|
||||
var _ fs.DirEntry = (*fontDirEntry)(nil)
|
||||
// 字体文件系统及目录条目的接口检查
|
||||
var (
|
||||
_ fs.FS = (*FontFS)(nil)
|
||||
_ fs.ReadDirFS = (*FontFS)(nil)
|
||||
_ fs.GlobFS = (*FontFS)(nil)
|
||||
_ fs.File = (*fontMemFile)(nil)
|
||||
_ fs.ReadDirFile = (*fontDir)(nil)
|
||||
_ fs.DirEntry = (*fontDirEntry)(nil)
|
||||
)
|
||||
|
||||
// FontFile 内存字体文件
|
||||
type FontFile struct {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 字体匹配按精确、部分和模糊匹配排列,零值表示未匹配
|
||||
const (
|
||||
fontMatchNone = iota
|
||||
fontMatchExact
|
||||
@@ -27,6 +28,7 @@ const (
|
||||
fontMatchFuzzy
|
||||
)
|
||||
|
||||
// fontMatchRules 保存常用字体的名称、文件名及系统字体匹配规则
|
||||
var fontMatchRules = normalizeFontMatchRules([]fontMatchRule{
|
||||
{
|
||||
Keys: []string{"小标宋", "方正小标宋", "xiaobiaosong", "fzxiaobiaosong", "fzxbs"},
|
||||
@@ -103,6 +105,7 @@ var fontMatchRules = normalizeFontMatchRules([]fontMatchRule{
|
||||
},
|
||||
})
|
||||
|
||||
// fontNameReplacer 移除字体名称匹配时忽略的分隔符
|
||||
var fontNameReplacer = strings.NewReplacer(" ", "", "-", "", "_", "", "(", "", ")", "", "(", "", ")", "")
|
||||
|
||||
// fontMatchRule 字体匹配规则
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/tdewolff/font"
|
||||
)
|
||||
|
||||
// 字体来源:文件、文件系统和系统字体
|
||||
const (
|
||||
fontSourceFile fontSourceKind = iota
|
||||
fontSourceFS
|
||||
|
||||
@@ -323,11 +323,15 @@ func type1HexEncoded(data []byte) bool {
|
||||
}
|
||||
|
||||
// type1HexDigit 判断字节是否为十六进制数字
|
||||
// 入参: value 待检查的字节
|
||||
// 返回: bool 是否为十六进制数字
|
||||
func type1HexDigit(value byte) bool {
|
||||
return value >= '0' && value <= '9' || value >= 'a' && value <= 'f' || value >= 'A' && value <= 'F'
|
||||
}
|
||||
|
||||
// type1Space 判断PostScript空白字节
|
||||
// 入参: value 待检查的字节
|
||||
// 返回: bool 是否为空白字节
|
||||
func type1Space(value byte) bool {
|
||||
return value == ' ' || value == '\t' || value == '\r' || value == '\n' || value == '\f' || value == 0
|
||||
}
|
||||
@@ -413,6 +417,8 @@ func (s *type1Scanner) binary(length int) ([]byte, error) {
|
||||
}
|
||||
|
||||
// type1BinaryStart 判断Type1二进制数据起始操作符
|
||||
// 入参: token PostScript词项
|
||||
// 返回: bool 是否为二进制数据起始操作符
|
||||
func type1BinaryStart(token string) bool {
|
||||
return token == "RD" || token == "-|"
|
||||
}
|
||||
|
||||
@@ -179,14 +179,6 @@ func readType2Private(data []byte, values []float64, font *type2Font) (cffDict,
|
||||
return private, nil
|
||||
}
|
||||
|
||||
// normalizeType2Programs 展开组合字形和求值指令,普通字形保留原程序及提示
|
||||
// 无法规范化的字形保留原程序,由实际使用时的轮廓解析校验
|
||||
// 入参: data CFF字体数据
|
||||
// 返回: [][]byte 字形程序, bool 是否变更, error 错误信息
|
||||
func normalizeType2Programs(data []byte) ([][]byte, bool, error) {
|
||||
return normalizeType2ProgramsMatrix(data, nil)
|
||||
}
|
||||
|
||||
// normalizeType2ProgramsMatrix 规范化字形指令并按需变换轮廓与字宽
|
||||
// 入参: data CFF字体数据, matrix 设计坐标变换,nil时保留原坐标
|
||||
// 返回: [][]byte 字形程序, bool 是否变更, error 错误信息
|
||||
|
||||
+2
-2
@@ -164,7 +164,7 @@ func (m Matrix) YScale() float64 {
|
||||
}
|
||||
|
||||
// geometryEqual 比较毫米坐标,使用固定绝对误差,不受绘图库全局精度影响
|
||||
// 入参: a、b 待比较的坐标
|
||||
// 入参: a 第一个坐标, b 第二个坐标
|
||||
// 返回: bool 是否在容差内相等
|
||||
func geometryEqual(a, b float64) bool {
|
||||
return math.Abs(a-b) <= 1e-10
|
||||
@@ -178,7 +178,7 @@ func axisAlignedMatrix(m Matrix) bool {
|
||||
}
|
||||
|
||||
// matrixVector 变换位移,不包含平移分量
|
||||
// 入参: m 仿射变换矩阵, x、y 原始位移
|
||||
// 入参: m 仿射变换矩阵, x 原始横向位移, y 原始纵向位移
|
||||
// 返回: float64 变换后的X位移, float64 变换后的Y位移
|
||||
func matrixVector(m Matrix, x, y float64) (float64, float64) {
|
||||
return m.a*x + m.c*y, m.b*x + m.d*y
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// 路径填充区域的交集、并集、差集和异或运算
|
||||
const (
|
||||
GeometryIntersect GeometryOperation = iota
|
||||
GeometryUnion
|
||||
|
||||
@@ -96,7 +96,7 @@ func (p GeometryPath) Bounds() (Box, error) {
|
||||
}
|
||||
|
||||
// geometryRoots 稳定求解一元二次方程的实根
|
||||
// 入参: a、b、c 方程系数
|
||||
// 入参: a 二次项系数, b 一次项系数, c 常数项
|
||||
// 返回: []float64 实根
|
||||
func geometryRoots(a, b, c float64) []float64 {
|
||||
scale := math.Max(math.Abs(a), math.Max(math.Abs(b), math.Abs(c)))
|
||||
@@ -122,7 +122,7 @@ func geometryRoots(a, b, c float64) []float64 {
|
||||
}
|
||||
|
||||
// geometryLerp 线性插值坐标
|
||||
// 入参: a、b 端点, t 插值比例
|
||||
// 入参: a 起点, b 终点, t 插值比例
|
||||
// 返回: Point 插值坐标
|
||||
func geometryLerp(a, b Point, t float64) Point {
|
||||
return Point{(1-t)*a.X + t*b.X, (1-t)*a.Y + t*b.Y}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 几何路径指令,包括直线、曲线、椭圆弧和闭合
|
||||
const (
|
||||
GeometryMove GeometryVerb = iota
|
||||
GeometryLine
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
_ "image/gif"
|
||||
"math"
|
||||
|
||||
_ "github.com/xiaoqidun/j2kgo"
|
||||
_ "github.com/xiaoqidun/jbig2"
|
||||
_ "golang.org/x/image/bmp"
|
||||
"golang.org/x/image/draw"
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ func NewInk(points []InkPoint, width float64, pressure bool) (PathObject, error)
|
||||
}
|
||||
|
||||
// inkCircle 使用两个半圆弧构造笔迹圆点,不扁平化圆形轮廓
|
||||
// 入参: x、y 圆心, radius 半径
|
||||
// 入参: x 圆心横坐标, y 圆心纵坐标, radius 半径
|
||||
// 返回: GeometryPath 圆形路径
|
||||
func inkCircle(x, y, radius float64) GeometryPath {
|
||||
start := Point{X: x + radius, Y: y}
|
||||
|
||||
@@ -16,6 +16,7 @@ package ofdgo
|
||||
|
||||
import "image/color"
|
||||
|
||||
// 画刷类型,区分纯色、渐变和图案填充
|
||||
const (
|
||||
PaintNone PaintKind = iota
|
||||
PaintSolid
|
||||
|
||||
@@ -453,14 +453,6 @@ func (p *pdfImporter) color(paint pdfgo.Paint) *FillColor {
|
||||
return &FillColor{Value: pdfNumbers(math.Round(paint.RGB[0]*255), math.Round(paint.RGB[1]*255), math.Round(paint.RGB[2]*255)), Alpha: &alpha}
|
||||
}
|
||||
|
||||
// pathData 将PDF路径转换为相对对象边界的OFD路径
|
||||
// 入参: path PDF路径, origin 对象边界
|
||||
// 返回: string OFD路径数据
|
||||
func (p *pdfImporter) pathData(path pdfgo.Path, origin Box) string {
|
||||
data, _ := p.pathDataContext(context.Background(), path, origin)
|
||||
return data
|
||||
}
|
||||
|
||||
// pathDataContext 转换路径并在分段处理时检查取消
|
||||
// 入参: ctx 取消上下文, path PDF路径, origin 对象边界
|
||||
// 返回: string OFD路径数据, error 取消错误
|
||||
|
||||
@@ -634,13 +634,6 @@ func pdfCompositeKnockout(target *pdfCompositePixel, initial, source pdfComposit
|
||||
return nil
|
||||
}
|
||||
|
||||
// pdfCompositeGroup 移除组初始背景贡献后,将组结果合成到父空间
|
||||
// 入参: ctx 取消上下文, pixels 父组输出, initial 初始背景, result 组结果, space 组空间, parent 父空间, opacity 组不透明度, mask 蒙版, mode 混合模式, intent 渲染意图, conversion 设备转换函数
|
||||
// 返回: error 颜色或混合错误
|
||||
func pdfCompositeGroup(ctx context.Context, pixels, initial, result []pdfCompositePixel, space, parent *pdfgo.ColorSpace, opacity float64, mask []float64, mode, intent pdfgo.Name, conversion pdfgo.ColorConversion) error {
|
||||
return pdfCompositeGroupRegion(ctx, pixels, initial, result, max(1, len(pixels)), image.Rect(0, 0, len(pixels), 1), space, parent, opacity, mask, mode, intent, conversion)
|
||||
}
|
||||
|
||||
// pdfCompositeGroupRegion 在组覆盖区域合成像素,保留原栅格及形状贡献
|
||||
// 入参: ctx 取消上下文, pixels 父组输出, initial 初始背景, result 组结果, stride 行跨度, region 覆盖区域, space 组空间, parent 父空间, opacity 组不透明度, mask 蒙版, mode 混合模式, intent 渲染意图, conversion 设备转换函数
|
||||
// 返回: error 缓冲、区域、颜色或混合错误
|
||||
|
||||
+3
-1
@@ -21,6 +21,7 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// 光栅后端接收的路径指令
|
||||
const (
|
||||
RasterMove RasterVerb = iota
|
||||
RasterLine
|
||||
@@ -29,6 +30,7 @@ const (
|
||||
RasterClose
|
||||
)
|
||||
|
||||
// 光栅渐变类型:轴向、径向和网格
|
||||
const (
|
||||
RasterLinear RasterGradientKind = iota
|
||||
RasterRadial
|
||||
@@ -195,7 +197,7 @@ func (g *RasterGradient) At(x, y float64) color.RGBA {
|
||||
func rasterPositive(v float64) bool { return v > 0 && !math.IsInf(v, 0) && !math.IsNaN(v) }
|
||||
|
||||
// rasterRadialDomain 求延伸区间内半径非负的最后一个双圆参数
|
||||
// 入参: a、b、c 方程系数, radius 起始半径, delta 半径变化, extend 延伸标志
|
||||
// 入参: a 二次项系数, b 一次项系数, c 常数项, radius 起始半径, delta 半径变化, extend 延伸标志
|
||||
// 返回: float64 参数, bool 是否覆盖采样点
|
||||
func rasterRadialDomain(a, b, c, radius, delta float64, extend int) (float64, bool) {
|
||||
x, y := math.NaN(), math.NaN()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package ofdgo
|
||||
|
||||
// 场景遍历的绘制、分组及跳过指令
|
||||
const (
|
||||
sceneObject sceneCommandKind = iota
|
||||
sceneStamp
|
||||
|
||||
@@ -275,25 +275,6 @@ func (r *Renderer) preparedMetrics(prepared *PreparedFont) (FontMetrics, error)
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
// preparedOutline 按字形和字号复用只读轮廓
|
||||
// 入参: prepared 字体, metrics 度量, glyph 字形编号, size 毫米字号
|
||||
// 返回: GeometryPath 字形路径, error 能力或解析错误
|
||||
func (r *Renderer) preparedOutline(prepared *PreparedFont, metrics FontMetrics, glyph uint16, size float64) (GeometryPath, error) {
|
||||
key := glyphOutlineKey{prepared, glyph, size}
|
||||
if path, ok := r.glyphOutlines.get(key); ok {
|
||||
return path, nil
|
||||
}
|
||||
provider, ok := metrics.(FontOutlines)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("font outlines: %w", ErrBackendUnavailable)
|
||||
}
|
||||
path, err := provider.GlyphOutline(glyph, size)
|
||||
if err == nil {
|
||||
r.glyphOutlines.put(key, path, len(path)*96+128)
|
||||
}
|
||||
return path, err
|
||||
}
|
||||
|
||||
// preparedOutlines 批量提取缓存未命中的字形,保留原始编号顺序,不触发塑形
|
||||
// 入参: prepared 字体, metrics 度量, glyphs 字形编号, size 毫米字号
|
||||
// 返回: []GeometryPath 同序只读轮廓, error 能力或解析错误
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/tdewolff/font"
|
||||
)
|
||||
|
||||
// ptPerMM 为毫米转换为排版点的比例
|
||||
const ptPerMM = 72.0 / 25.4
|
||||
|
||||
// renderText 渲染文本
|
||||
|
||||
+2
-1
@@ -21,6 +21,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 基本图形标识,用于创建直线、箭头、矩形和椭圆
|
||||
const (
|
||||
ShapeLine ShapeKind = "line"
|
||||
ShapeArrow ShapeKind = "arrow"
|
||||
@@ -243,7 +244,7 @@ func (p PathObject) ReshapeLine(kind ShapeKind, box Box) (PathObject, error) {
|
||||
}
|
||||
|
||||
// sameShapePath 比较基本路径的命令与数值,忽略数值格式差异
|
||||
// 入参: a、b 路径词元
|
||||
// 入参: a 第一个路径词元, b 第二个路径词元
|
||||
// 返回: bool 是否相同
|
||||
func sameShapePath(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// GB/T35275内容类型及消息摘要属性的对象标识
|
||||
const (
|
||||
signContentData = "1.2.156.10197.6.1.4.2.1"
|
||||
signContentSignedData = "1.2.156.10197.6.1.4.2.2"
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/emmansun/gmsm/sm3"
|
||||
)
|
||||
|
||||
// SES摘要及签名算法的对象标识和ASN.1序列标签
|
||||
const (
|
||||
signDigestSM3 = "1.2.156.10197.1.401"
|
||||
signDigestSM3NoKey = "1.2.156.10197.1.401.1"
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/emmansun/gmsm/smx509"
|
||||
)
|
||||
|
||||
// CMS时间戳内容、签名属性及签署证书属性的对象标识
|
||||
const (
|
||||
signTimestampContent = "1.2.840.113549.1.9.16.1.4"
|
||||
signTimestampAttr = "1.2.840.113549.1.9.16.2.14"
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
"github.com/emmansun/gmsm/smx509"
|
||||
)
|
||||
|
||||
// signatureMethodReplacer 移除签名算法名称中的分隔符
|
||||
var signatureMethodReplacer = strings.NewReplacer("-", "", "_", "", " ", "")
|
||||
|
||||
// SignatureVerifyReport 签名验证报告
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// U3D线集增量编码的算术编码上下文
|
||||
const (
|
||||
u3dLinePositionSign = iota
|
||||
u3dLinePositionX
|
||||
@@ -176,12 +177,6 @@ func (s *u3dLineState) average(position uint32) (values [11][4]float64) {
|
||||
return values
|
||||
}
|
||||
|
||||
// accumulate 累计线段端点的独立属性,重复使用的属性按端点分别计数
|
||||
// 入参: mesh 共享属性数组, line 已完成的线段
|
||||
func (s *u3dLineState) accumulate(mesh *U3DMesh, line U3DLine) {
|
||||
s.accumulateCorners(mesh, line.Shading, line.Corners[:])
|
||||
}
|
||||
|
||||
// accumulateCorners 累计点或线端的属性,用于后续位置预测
|
||||
// 入参: mesh 属性数组, shadingIndex 着色索引, corners 新增角点
|
||||
func (s *u3dLineState) accumulateCorners(mesh *U3DMesh, shadingIndex uint32, corners []U3DCorner) {
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ofdNamespace 为OFD文档的XML命名空间
|
||||
const ofdNamespace = "http://www.ofdspec.org/2016"
|
||||
|
||||
// editorProgress 保存准备阶段的进度检查点,内存预览使用nil
|
||||
@@ -1066,7 +1067,7 @@ func (x *ofdXML) meshShading(name string, extend, columns int, points []ShdPoint
|
||||
}
|
||||
|
||||
// shadingAttrs 编码轴向和径向渐变的共同属性
|
||||
// 入参: mapType 映射方式, mapUnit 映射周期, extend 延伸方式, start、end 渐变端点
|
||||
// 入参: mapType 映射方式, mapUnit 映射周期, extend 延伸方式, start 渐变起点, end 渐变终点
|
||||
// 返回: ofdAttrs 属性集合
|
||||
func shadingAttrs(mapType string, mapUnit float64, extend, start, end string) ofdAttrs {
|
||||
var attrs ofdAttrs
|
||||
|
||||
Reference in new issue
Block a user