feat(图像处理): 接入J2KGo,精简规范代码
build.yaml / build (push) Successful in 48s

This commit is contained in:
xiaoqidun committed 2026-10-09 10:39:51 +08:00
1 parent 28175723e6
commit 32585c6343
46 files changed
+84 -168

No files matched your search

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