mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 14:18:04 +08:00
1 parent
d07972346b
commit
70003486b8
37 files changed
+2386
-2509
No files matched your search
+132
@@ -23,6 +23,9 @@ import (
|
||||
"github.com/xiaoqidun/pdfgo"
|
||||
)
|
||||
|
||||
// pdfObjectChunkLimit 限制导入暂存片段的容量,不限制页面对象数量
|
||||
const pdfObjectChunkLimit = 256
|
||||
|
||||
// ErrPDFPassword 表示PDF需要正确的用户或所有者密码
|
||||
var ErrPDFPassword = pdfgo.ErrPassword
|
||||
|
||||
@@ -118,6 +121,12 @@ type pdfImporter struct {
|
||||
compression CompressionOptions
|
||||
}
|
||||
|
||||
// pdfObjectBuffer 分块收集导入对象,提交前只整理一次连续数据
|
||||
type pdfObjectBuffer struct {
|
||||
parts [][]GraphicObject
|
||||
size int
|
||||
}
|
||||
|
||||
// ImportPDF 将PDF内容转换为独立OFD编辑文档,失败时不返回部分结果
|
||||
// 入参: ctx 取消上下文, source PDF数据, size 字节数, options 转换选项
|
||||
// 返回: *Editor 编辑文档, PDFImportReport 转换统计, error 错误信息
|
||||
@@ -321,3 +330,126 @@ func (p *pdfImporter) referencePage(ctx context.Context, source *pdfgo.Reader, r
|
||||
}
|
||||
return p.references.Resolve(ctx, source, reference, p.resolveFile, p.resolveReference, p.warning)
|
||||
}
|
||||
|
||||
// objectValidation 在单次导入中共享不可变资源的校验结果,隔离局部编辑器
|
||||
// 返回: *editorValidation 当前编辑器的构建校验会话
|
||||
func (p *pdfImporter) objectValidation() *editorValidation {
|
||||
if p.validation == nil || p.validation.Editor != p.editor {
|
||||
p.validation = &editorValidation{Editor: p.editor}
|
||||
}
|
||||
return p.validation
|
||||
}
|
||||
|
||||
// appendObject 追加本次导入对象,按需建立独立暂存缓冲
|
||||
// 入参: object 独立导入对象
|
||||
func (p *pdfImporter) appendObject(object GraphicObject) {
|
||||
if p.objects == nil {
|
||||
p.objects = &pdfObjectBuffer{}
|
||||
}
|
||||
p.objects.append(object)
|
||||
}
|
||||
|
||||
// append 追加对象,小批量连续存储,超过阈值后不复制前序片段
|
||||
// 入参: object 独立对象
|
||||
func (b *pdfObjectBuffer) append(object GraphicObject) {
|
||||
index := len(b.parts) - 1
|
||||
if index == 0 && len(b.parts[0]) == cap(b.parts[0]) && cap(b.parts[0]) < pdfObjectChunkLimit {
|
||||
part := b.parts[0]
|
||||
next := make([]GraphicObject, len(part), min(pdfObjectChunkLimit, max(1, cap(part)*2)))
|
||||
copy(next, part)
|
||||
b.parts[0] = next
|
||||
}
|
||||
if index < 0 || len(b.parts[index]) == cap(b.parts[index]) {
|
||||
capacity := pdfObjectChunkLimit
|
||||
if index < 0 {
|
||||
capacity = 1
|
||||
}
|
||||
b.parts = append(b.parts, make([]GraphicObject, 0, capacity))
|
||||
index++
|
||||
}
|
||||
b.parts[index] = append(b.parts[index], object)
|
||||
b.size++
|
||||
}
|
||||
|
||||
// len 获取暂存对象数量,空缓冲返回零
|
||||
// 返回: int 对象数量
|
||||
func (b *pdfObjectBuffer) len() int {
|
||||
if b == nil {
|
||||
return 0
|
||||
}
|
||||
return b.size
|
||||
}
|
||||
|
||||
// truncate 回滚到已有对象位置,清理丢弃对象及片段引用
|
||||
// 入参: size 保留对象数量
|
||||
func (b *pdfObjectBuffer) truncate(size int) {
|
||||
if size < 0 || size > b.len() {
|
||||
panic("invalid PDF object buffer size")
|
||||
}
|
||||
if size == b.len() {
|
||||
return
|
||||
}
|
||||
remaining := size
|
||||
for index, part := range b.parts {
|
||||
if remaining <= len(part) {
|
||||
clear(part[remaining:])
|
||||
b.parts[index] = part[:remaining]
|
||||
clear(b.parts[index+1:])
|
||||
b.parts = b.parts[:index+1]
|
||||
b.size = size
|
||||
return
|
||||
}
|
||||
remaining -= len(part)
|
||||
}
|
||||
}
|
||||
|
||||
// data 按绘制顺序整理独立对象数组,取消时保留原片段供重试
|
||||
// 入参: ctx 取消上下文
|
||||
// 返回: []GraphicObject 暂存数据, error 取消错误
|
||||
func (b *pdfObjectBuffer) data(ctx context.Context) ([]GraphicObject, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b.len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if len(b.parts) == 1 {
|
||||
return b.parts[0][:b.size:b.size], nil
|
||||
}
|
||||
objects := make([]GraphicObject, b.size)
|
||||
offset := 0
|
||||
for _, part := range b.parts {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset += copy(objects[offset:], part)
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.parts[0] = objects
|
||||
clear(b.parts[1:])
|
||||
b.parts = b.parts[:1]
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
// commitObjects 将当前页面待转换对象写入编辑文档
|
||||
// 返回: error 对象写入错误
|
||||
func (p *pdfImporter) commitObjects() error {
|
||||
if p.objects.len() == 0 {
|
||||
return nil
|
||||
}
|
||||
objects, err := p.objects.data(p.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objects, err = p.sharedClipObjects(objects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.objectValidation().appendOwnedObjects(p.ctx, p.page, objects); err != nil {
|
||||
return err
|
||||
}
|
||||
p.objects = nil
|
||||
return nil
|
||||
}
|
||||
Reference in new issue
Block a user