mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
1 parent
bec13d523f
commit
b3c4bbc844
45 files changed
+1885
-1453
No files matched your search
+19
-147
@@ -15,165 +15,37 @@
|
||||
package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"io"
|
||||
|
||||
baseimage "github.com/xiaoqidun/ofdgo/internal/base/image"
|
||||
codecpdf "github.com/xiaoqidun/ofdgo/internal/codec/pdf"
|
||||
"github.com/xiaoqidun/pdfgo"
|
||||
)
|
||||
|
||||
// writePDF 合并图像、文字、导航修正及压缩,直接写出最终PDF
|
||||
// writePDF 传递后端资源记录及OFD导航修正,写出最终PDF
|
||||
// 入参: ctx 取消上下文, data 后端PDF数据, writer 输出流, optimization 优化配置
|
||||
// 返回: error 资源、压缩或写入错误
|
||||
func (r *pdfRenderer) writePDF(ctx context.Context, data []byte, writer io.Writer, optimization pdfgo.OptimizeOptions) error {
|
||||
if r.imageError != nil {
|
||||
return r.imageError
|
||||
}
|
||||
nativeWrite := r.navigation != nil && r.navigation.nativeWrite
|
||||
if !r.exactImages && !r.exactText && !nativeWrite && optimization.Compression.Mode == CompressionUnchanged {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := writer.Write(data)
|
||||
if err == nil && n != len(data) {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
return err
|
||||
options := codecpdf.WriteOptions{
|
||||
Images: r.images,
|
||||
Text: r.text,
|
||||
ExactImages: r.exactImages,
|
||||
ExactText: r.exactText,
|
||||
Optimization: optimization,
|
||||
}
|
||||
reader, err := pdfgo.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
return err
|
||||
if r.navigation != nil && r.navigation.nativeWrite {
|
||||
options.Links = make(map[int][]*pdfgo.LinkRegion, len(r.navigation.Link))
|
||||
for page, links := range r.navigation.Link {
|
||||
regions := make([]*pdfgo.LinkRegion, len(links))
|
||||
for i, link := range links {
|
||||
regions[i] = link.Region
|
||||
}
|
||||
options.Links[page] = regions
|
||||
}
|
||||
options.PrepareRewrite = r.navigation.prepareRewrite
|
||||
}
|
||||
defer reader.Close()
|
||||
if !r.exactImages && !r.exactText && !nativeWrite {
|
||||
_, err := reader.OptimizeTo(ctx, writer, optimization)
|
||||
return err
|
||||
}
|
||||
images := make(map[pdfgo.Reference]image.Image)
|
||||
links := make(map[pdfgo.AnnotationLocation]pdfgo.LinkRegion)
|
||||
texts := make(map[pdfgo.Reference][]pdfgo.TextReplacement)
|
||||
references := make([]pdfgo.Reference, len(r.images))
|
||||
pages := 0
|
||||
err = reader.WalkPages(ctx, func(index int, page *pdfgo.Page) error {
|
||||
if index >= len(r.images) {
|
||||
return fmt.Errorf("unexpected PDF output page")
|
||||
}
|
||||
pages++
|
||||
references[index] = page.Reference
|
||||
if nativeWrite {
|
||||
annotations, err := page.AnnotationsContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
expected := r.navigation.Link[index]
|
||||
if len(annotations) != len(expected) {
|
||||
return fmt.Errorf("PDF output link count differs")
|
||||
}
|
||||
for i, link := range expected {
|
||||
if annotations[i].Subtype != pdfgo.Name("Link") {
|
||||
return fmt.Errorf("unexpected PDF output annotation")
|
||||
}
|
||||
if link.Region != nil {
|
||||
links[pdfgo.AnnotationLocation{Page: page.Reference, Index: i}] = *link.Region
|
||||
}
|
||||
}
|
||||
}
|
||||
if !r.exactImages && !r.exactText {
|
||||
return nil
|
||||
}
|
||||
value, err := reader.Resolve(page.Resources["XObject"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources, _ := value.(pdfgo.Dictionary)
|
||||
var content bytes.Buffer
|
||||
if _, err := page.WriteContent(ctx, &content); err != nil {
|
||||
return err
|
||||
}
|
||||
position := 0
|
||||
textCount := 0
|
||||
if err := pdfgo.WalkOperations(ctx, content.Bytes(), func(operation pdfgo.Operation) error {
|
||||
if operation.Operator == "BT" {
|
||||
textCount++
|
||||
}
|
||||
if !r.exactImages {
|
||||
return nil
|
||||
}
|
||||
if operation.Operator != "Do" {
|
||||
return nil
|
||||
}
|
||||
if len(operation.Operands) != 1 || position >= len(r.images[index]) {
|
||||
return fmt.Errorf("unexpected PDF output image")
|
||||
}
|
||||
name, ok := operation.Operands[0].(pdfgo.Name)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid PDF output image name")
|
||||
}
|
||||
ref, ok := resources[name].(pdfgo.Reference)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid PDF output image reference")
|
||||
}
|
||||
original := r.images[index][position]
|
||||
position++
|
||||
if original == nil {
|
||||
return nil
|
||||
}
|
||||
image, err := reader.ReadImage(ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if image.Width != original.Bounds().Dx() || image.Height != original.Bounds().Dy() {
|
||||
return fmt.Errorf("PDF output image dimensions differ")
|
||||
}
|
||||
if previous := images[ref]; previous != nil && previous != original {
|
||||
return fmt.Errorf("PDF output image reference conflicts")
|
||||
}
|
||||
images[ref] = original
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if r.exactImages && position != len(r.images[index]) {
|
||||
return fmt.Errorf("PDF output image missing")
|
||||
}
|
||||
if r.exactText {
|
||||
if index >= len(r.text) || textCount != r.text[index].count {
|
||||
return fmt.Errorf("PDF output text count differs")
|
||||
}
|
||||
if len(r.text[index].replacements) != 0 {
|
||||
texts[page.Reference] = r.text[index].replacements
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pages != len(r.images) {
|
||||
return fmt.Errorf("PDF output page missing")
|
||||
}
|
||||
options := pdfgo.RewriteOptions{Images: images, ImageOptions: pdfgo.ImageWriteOptions{PreblendBinary: true}, LinkRegions: links, TextReplacements: texts, Optimization: optimization}
|
||||
if nativeWrite {
|
||||
if err := r.navigation.prepareRewrite(ctx, reader, references, &options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for ref, original := range images {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
pixels, err := baseimage.PixelDataContext(ctx, original)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pixels == nil || pixels.Bounds() != original.Bounds() {
|
||||
return fmt.Errorf("PDF output image pixel bounds differ")
|
||||
}
|
||||
images[ref] = pixels
|
||||
}
|
||||
_, err = reader.RewriteTo(ctx, writer, options)
|
||||
return err
|
||||
return codecpdf.Write(ctx, data, writer, options)
|
||||
}
|
||||
Reference in new issue
Block a user