mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
147 lines
4.0 KiB
Go
147 lines
4.0 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 (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"io"
|
|
|
|
"github.com/tdewolff/canvas"
|
|
"github.com/tdewolff/canvas/renderers"
|
|
"github.com/tdewolff/canvas/renderers/pdf"
|
|
"github.com/tdewolff/canvas/renderers/rasterizer"
|
|
)
|
|
|
|
// RenderToImage 渲染为光栅图
|
|
// 入参: page 页面内容
|
|
// 返回: image.Image 图像对象, error 错误信息
|
|
func (r *Renderer) RenderToImage(page *PageContent) (image.Image, error) {
|
|
c, err := r.RenderPage(page)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dpmm := r.DPI / 25.4
|
|
return rasterizer.Draw(c, canvas.DPMM(dpmm), canvas.DefaultColorSpace), nil
|
|
}
|
|
|
|
// RenderToSVG 渲染为SVG
|
|
// 入参: page 页面内容, writer 输出流
|
|
// 返回: error 错误信息
|
|
func (r *Renderer) RenderToSVG(page *PageContent, writer io.Writer) error {
|
|
c, err := r.renderPage(page)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Write(writer, renderers.SVG())
|
|
}
|
|
|
|
// replacePDFProducer 替换PDF的Producer属性
|
|
// 入参: data PDF字节数据
|
|
// 返回: []byte 替换后的PDF字节数据
|
|
func replacePDFProducer(data []byte) []byte {
|
|
old := []byte("/Producer(tdewolff/canvas)")
|
|
idx := bytes.LastIndex(data, old)
|
|
if idx < 0 {
|
|
return data
|
|
}
|
|
dst := []byte("/Producer(xiaoqidun/ofdgo)")
|
|
copy(data[idx:idx+len(old)], dst)
|
|
return data
|
|
}
|
|
|
|
// RenderToPDF 渲染为PDF
|
|
// 入参: page 页面内容, writer 输出流
|
|
// 返回: error 错误信息
|
|
func (r *Renderer) RenderToPDF(page *PageContent, writer io.Writer) error {
|
|
c, err := r.renderPage(page)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
box, err := r.GetPageBox(page)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
pages := []pdfPage{{Content: page, Box: box}}
|
|
navigation := newPDFNavigation(r, r.Reader.doc, pages)
|
|
var buf bytes.Buffer
|
|
p := pdf.New(&buf, c.W, c.H, nil)
|
|
p.SetInfo("", "", "", "", "xiaoqidun/ofdgo")
|
|
navigation.apply(p, 0)
|
|
c.RenderTo(p)
|
|
if err := p.Close(); err != nil {
|
|
return err
|
|
}
|
|
_, err = writer.Write(replacePDFProducer(buf.Bytes()))
|
|
return err
|
|
}
|
|
|
|
// RenderToEPS 渲染为EPS
|
|
// 入参: page 页面内容, writer 输出流
|
|
// 返回: error 错误信息
|
|
func (r *Renderer) RenderToEPS(page *PageContent, writer io.Writer) error {
|
|
c, err := r.renderPage(page)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Write(writer, renderers.EPS())
|
|
}
|
|
|
|
// RenderToMultiPagePDF 将整个文档导出为多页PDF
|
|
// 入参: writer 输出流
|
|
// 返回: error 错误信息
|
|
func (r *Renderer) RenderToMultiPagePDF(writer io.Writer) error {
|
|
doc, err := r.Reader.Doc()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(doc.Pages.Page) == 0 {
|
|
return fmt.Errorf("no pages found")
|
|
}
|
|
pages := make([]pdfPage, len(doc.Pages.Page))
|
|
for i, pageRef := range doc.Pages.Page {
|
|
page, err := r.Reader.PageContent(pageRef)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read page %d: %w", i+1, err)
|
|
}
|
|
box, err := r.GetPageBox(page)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read page %d area: %w", i+1, err)
|
|
}
|
|
pages[i] = pdfPage{Content: page, Box: box}
|
|
}
|
|
navigation := newPDFNavigation(r, doc, pages)
|
|
var buf bytes.Buffer
|
|
p := pdf.New(&buf, pages[0].Box.W, pages[0].Box.H, nil)
|
|
p.SetInfo("", "", "", "", "xiaoqidun/ofdgo")
|
|
for i, page := range pages {
|
|
c, err := r.renderPage(page.Content)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to render page %d: %w", i+1, err)
|
|
}
|
|
if i > 0 {
|
|
p.NewPage(c.W, c.H)
|
|
}
|
|
navigation.apply(p, i)
|
|
c.RenderTo(p)
|
|
}
|
|
if err := p.Close(); err != nil {
|
|
return err
|
|
}
|
|
_, err = writer.Write(replacePDFProducer(buf.Bytes()))
|
|
return err
|
|
}
|