mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
e4af1e7318
commit
59a2c4d8fe
9 files changed
+177
-73
No files matched your search
@@ -9,7 +9,7 @@ require (
|
|||||||
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/jbig2 v1.1.1
|
||||||
github.com/xiaoqidun/pdfgo v0.0.0-20260930062146-7c39a20d9430
|
github.com/xiaoqidun/pdfgo v0.0.0-20260930081439-0ce33d5532fb
|
||||||
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
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ 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/jbig2 v1.1.1 h1:SjliS9ZO0e9HX5oYUfBuXrfFsXhWricrSz+XY4zORDI=
|
||||||
github.com/xiaoqidun/jbig2 v1.1.1/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
github.com/xiaoqidun/jbig2 v1.1.1/go.mod h1:8QonVWtENmh2kc6l+leqeGl7psb79DWlHDkCpdChjfQ=
|
||||||
github.com/xiaoqidun/pdfgo v0.0.0-20260930062146-7c39a20d9430 h1:UBP+ZmqxoxQ7p6dFZI/6yGSLmgqfTQUvO7h+DUfWsWY=
|
github.com/xiaoqidun/pdfgo v0.0.0-20260930081439-0ce33d5532fb h1:OKuM5n02cLQB0rIcJoNfnQl+udhBNWgjLMAUlAk087s=
|
||||||
github.com/xiaoqidun/pdfgo v0.0.0-20260930062146-7c39a20d9430/go.mod h1:4Pf0JO0BEf1uzRY+uZjlMjN/OPn3PYa0YMi6cqPPTLQ=
|
github.com/xiaoqidun/pdfgo v0.0.0-20260930081439-0ce33d5532fb/go.mod h1:4Pf0JO0BEf1uzRY+uZjlMjN/OPn3PYa0YMi6cqPPTLQ=
|
||||||
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=
|
||||||
|
|||||||
+9
-23
@@ -2987,14 +2987,18 @@ func styleObjects(args []js.Value) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
patterns := make(map[bool]*ofdgo.PatternStyle)
|
appearance := ofdgo.ObjectAppearance{SetLink: !linkField.IsUndefined(), Link: link, Border: border}
|
||||||
for key, stroke := range map[string]bool{"fillPatternStyle": false, "strokePatternStyle": true} {
|
for i, key := range []string{"fillPatternStyle", "strokePatternStyle"} {
|
||||||
if field := args[2].Get(key); !field.IsUndefined() {
|
if field := args[2].Get(key); !field.IsUndefined() {
|
||||||
var pattern ofdgo.PatternStyle
|
var pattern ofdgo.PatternStyle
|
||||||
if err := json.Unmarshal([]byte(field.String()), &pattern); err != nil {
|
if err := json.Unmarshal([]byte(field.String()), &pattern); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
patterns[stroke] = &pattern
|
if i == 0 {
|
||||||
|
appearance.FillPattern = &pattern
|
||||||
|
} else {
|
||||||
|
appearance.StrokePattern = &pattern
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if field := args[2].Get("fillPaint"); !field.IsUndefined() {
|
if field := args[2].Get("fillPaint"); !field.IsUndefined() {
|
||||||
@@ -3008,36 +3012,18 @@ func styleObjects(args []js.Value) (any, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changeObjects(func() error {
|
return changeObjects(func() error {
|
||||||
return currentEditor.Transaction(func(editor *ofdgo.Editor) error {
|
|
||||||
page, ids := args[0].Int(), stringsFromJS(args[1])
|
|
||||||
if !linkField.IsUndefined() {
|
|
||||||
if err := editor.SetObjectLink(page, ids, link); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if border != nil {
|
if border != nil {
|
||||||
if err := resolveStylePaint((*ofdgo.FillColor)(border.Color)); err != nil {
|
if err := resolveStylePaint((*ofdgo.FillColor)(border.Color)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := editor.StyleImageBorders(page, ids, *border); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, paint := range []*ofdgo.FillColor{style.FillColor, (*ofdgo.FillColor)(style.StrokeColor)} {
|
for _, paint := range []*ofdgo.FillColor{style.FillColor, (*ofdgo.FillColor)(style.StrokeColor)} {
|
||||||
if err := resolveStylePaint(paint); err != nil {
|
if err := resolveStylePaint(paint); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := editor.StyleObjects(page, ids, style); err != nil {
|
appearance.Style = style
|
||||||
return err
|
return currentEditor.ApplyAppearance(args[0].Int(), stringsFromJS(args[1]), appearance)
|
||||||
}
|
|
||||||
for stroke, pattern := range patterns {
|
|
||||||
if err := editor.StylePatterns(page, ids, stroke, *pattern); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -562,8 +562,12 @@ func (e *Editor) updateObjectOrigins(page int, objects []GraphicObject, preserve
|
|||||||
if origin != nil {
|
if origin != nil {
|
||||||
capability := e.objectCapabilities(before[i], orderable)
|
capability := e.objectCapabilities(before[i], orderable)
|
||||||
if !capability.Transform {
|
if !capability.Transform {
|
||||||
|
beforeBox, beforeCTM := editorGeometry(before[i])
|
||||||
|
afterBox, afterCTM := editorGeometry(object)
|
||||||
|
if !capability.Update && !(preserved && capability.Delete) || before[i].Type != object.Type || beforeBox != afterBox || beforeCTM != afterCTM {
|
||||||
return fmt.Errorf("object %q is read-only for this operation: %w", ids[i], capability.editError())
|
return fmt.Errorf("object %q is read-only for this operation: %w", ids[i], capability.editError())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !preserved && !capability.Update && editorPreservedObject(before[i], object) && capability.Paint {
|
if !preserved && !capability.Update && editorPreservedObject(before[i], object) && capability.Paint {
|
||||||
if err := e.validatePreservedAppearance(before[i], object); err != nil {
|
if err := e.validatePreservedAppearance(before[i], object); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -208,8 +208,9 @@ func (e *Editor) RGBColor(value color.NRGBA) (*FillColor, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, resource := range e.resources {
|
for _, resource := range e.resources {
|
||||||
if resource.space != nil {
|
space := resource.space
|
||||||
result.ColorSpace = resource.space.ID
|
if space != nil && space.Type == "RGB" && (space.BitsPerComponent == 0 || space.BitsPerComponent == 8) && len(space.Palette) == 0 {
|
||||||
|
result.ColorSpace = space.ID
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,46 @@ type ImageBorderStyle struct {
|
|||||||
Color *StrokeColor
|
Color *StrokeColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObjectAppearance 对象外观组合更新,nil字段保持原值
|
||||||
|
// SetLink为true时更新链接,Link为nil时删除链接
|
||||||
|
type ObjectAppearance struct {
|
||||||
|
Style ObjectStyle
|
||||||
|
SetLink bool
|
||||||
|
Link *AnnotationLink
|
||||||
|
Border *ImageBorderStyle
|
||||||
|
FillPattern *PatternStyle
|
||||||
|
StrokePattern *PatternStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyAppearance 原子更新外观、链接、图片边框及图案布局,支持一次撤销
|
||||||
|
// 入参: page 页面索引, ids 对象标识, appearance 外观增量
|
||||||
|
// 返回: error 错误信息
|
||||||
|
func (e *Editor) ApplyAppearance(page int, ids []string, appearance ObjectAppearance) error {
|
||||||
|
return e.Transaction(func(editor *Editor) error {
|
||||||
|
if appearance.SetLink {
|
||||||
|
if err := editor.SetObjectLink(page, ids, appearance.Link); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if appearance.Border != nil {
|
||||||
|
if err := editor.StyleImageBorders(page, ids, *appearance.Border); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := editor.StyleObjects(page, ids, appearance.Style); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, pattern := range []*PatternStyle{appearance.FillPattern, appearance.StrokePattern} {
|
||||||
|
if pattern != nil {
|
||||||
|
if err := editor.StylePatterns(page, ids, i == 1, *pattern); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// DrawParam 读取绘制参数,resolved为true时合并继承链,返回独立副本
|
// DrawParam 读取绘制参数,resolved为true时合并继承链,返回独立副本
|
||||||
// 入参: id 资源标识, resolved 是否解析继承
|
// 入参: id 资源标识, resolved 是否解析继承
|
||||||
// 返回: *DrawParam 绘制参数, error 错误信息
|
// 返回: *DrawParam 绘制参数, error 错误信息
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ func ImportPDF(ctx context.Context, source io.ReaderAt, size int64, options PDFI
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, PDFImportReport{}, err
|
return nil, PDFImportReport{}, err
|
||||||
}
|
}
|
||||||
|
defer reader.Close()
|
||||||
editor := NewEditor()
|
editor := NewEditor()
|
||||||
editor.SetRenderBackends(renderer.Backends())
|
editor.SetRenderBackends(renderer.Backends())
|
||||||
editor.fontDirs, editor.fontFS = renderer.FontSources()
|
editor.fontDirs, editor.fontFS = renderer.FontSources()
|
||||||
|
|||||||
+10
-21
@@ -207,25 +207,7 @@ func (p *pdfImporter) compositePage(space *pdfgo.ColorSpace, walk func(pdfgo.Vis
|
|||||||
}
|
}
|
||||||
if space == nil {
|
if space == nil {
|
||||||
space = &pdfgo.ColorSpace{Model: "DeviceRGB"}
|
space = &pdfgo.ColorSpace{Model: "DeviceRGB"}
|
||||||
var needsProcess func([]pdfCompositeNode) (bool, error)
|
found, err := p.processOverprint(nodes)
|
||||||
needsProcess = func(items []pdfCompositeNode) (bool, error) {
|
|
||||||
for _, item := range items {
|
|
||||||
if item.group != nil {
|
|
||||||
found, err := needsProcess(item.children)
|
|
||||||
if err != nil || found {
|
|
||||||
return found, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if item.image != nil && item.image.Style.FillOverprint {
|
|
||||||
_, found, err := pdfImageProcessColorants(item.image.Image)
|
|
||||||
if err != nil || found {
|
|
||||||
return found, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
found, err := needsProcess(nodes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -244,7 +226,11 @@ func (p *pdfImporter) compositePage(space *pdfgo.ColorSpace, walk func(pdfgo.Vis
|
|||||||
func (p *pdfImporter) compositeObjects(nodes []pdfCompositeNode) error {
|
func (p *pdfImporter) compositeObjects(nodes []pdfCompositeNode) error {
|
||||||
space := p.compositeSpace
|
space := p.compositeSpace
|
||||||
for i, node := range nodes {
|
for i, node := range nodes {
|
||||||
if node.opaque(space) || space.SRGBEquivalent() && node.direct() {
|
direct, err := p.directCompositeNode(node, space)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("inspect graphic %d: %w", i+1, err)
|
||||||
|
}
|
||||||
|
if direct {
|
||||||
if err := node.emit(p.visitor()); err != nil {
|
if err := node.emit(p.visitor()); err != nil {
|
||||||
return fmt.Errorf("convert graphic %d: %w", i+1, err)
|
return fmt.Errorf("convert graphic %d: %w", i+1, err)
|
||||||
}
|
}
|
||||||
@@ -445,11 +431,14 @@ func (p *pdfImporter) compositeRegion(backdrop []pdfCompositeNode, node pdfCompo
|
|||||||
output := image.NewNRGBA(image.Rect(0, 0, w, h))
|
output := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||||
cache := p.compositingCache()
|
cache := p.compositingCache()
|
||||||
step := 25.4 / p.rasterDPI
|
step := 25.4 / p.rasterDPI
|
||||||
|
buffer := make([]pdfCompositePixel, min(256, w)*min(256, h))
|
||||||
for y := 0; y < h; y += 256 {
|
for y := 0; y < h; y += 256 {
|
||||||
for x := 0; x < w; x += 256 {
|
for x := 0; x < w; x += 256 {
|
||||||
|
runtime.Gosched()
|
||||||
width, height := min(256, w-x), min(256, h-y)
|
width, height := min(256, w-x), min(256, h-y)
|
||||||
c := pdfCompositor{importer: p, box: Box{X: box.X + float64(x)*step, Y: box.Y + float64(y)*step, W: float64(width) * step, H: float64(height) * step}, width: width, height: height, inverse: inverse, cache: cache, masks: map[*pdfgo.SoftMask][]float64{}}
|
c := pdfCompositor{importer: p, box: Box{X: box.X + float64(x)*step, Y: box.Y + float64(y)*step, W: float64(width) * step, H: float64(height) * step}, width: width, height: height, inverse: inverse, cache: cache, masks: map[*pdfgo.SoftMask][]float64{}}
|
||||||
pixels := make([]pdfCompositePixel, width*height)
|
pixels := buffer[:width*height]
|
||||||
|
clear(pixels)
|
||||||
if err := c.draw(backdrop, pixels, space); err != nil {
|
if err := c.draw(backdrop, pixels, space); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-24
@@ -33,38 +33,15 @@ type pdfCompositePattern struct {
|
|||||||
// 返回: []pdfCompositePixel 去除背景贡献的图案像素, error 解析或绘制错误
|
// 返回: []pdfCompositePixel 去除背景贡献的图案像素, error 解析或绘制错误
|
||||||
func (c *pdfCompositor) tiling(paint pdfgo.Paint, backdrop []pdfCompositePixel, space *pdfgo.ColorSpace) ([]pdfCompositePixel, error) {
|
func (c *pdfCompositor) tiling(paint pdfgo.Paint, backdrop []pdfCompositePixel, space *pdfgo.ColorSpace) ([]pdfCompositePixel, error) {
|
||||||
source := paint.Tiling
|
source := paint.Tiling
|
||||||
paint.Alpha = 1
|
|
||||||
if c.cache.patterns == nil {
|
|
||||||
c.cache.patterns = make(map[pdfgo.Paint]*pdfCompositePattern)
|
|
||||||
}
|
|
||||||
pattern := c.cache.patterns[paint]
|
|
||||||
matrix := c.importer.matrix.Mul(source.Matrix)
|
matrix := c.importer.matrix.Mul(source.Matrix)
|
||||||
inverse, ok := matrix.Inverse()
|
inverse, ok := matrix.Inverse()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("invalid PDF tiling pattern matrix")
|
return nil, fmt.Errorf("invalid PDF tiling pattern matrix")
|
||||||
}
|
}
|
||||||
if pattern == nil {
|
pattern, err := c.importer.compositePattern(paint)
|
||||||
nodes, err := c.importer.collectCompositeNodes(func(v pdfgo.Visitor) error { return source.Walk(c.importer.ctx, paint, v) })
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
b := source.BBox
|
|
||||||
box := pdfBounds([]pdfgo.Point{
|
|
||||||
matrix.Apply(pdfgo.Point{X: b.XMin, Y: b.YMin}), matrix.Apply(pdfgo.Point{X: b.XMax, Y: b.YMin}),
|
|
||||||
matrix.Apply(pdfgo.Point{X: b.XMax, Y: b.YMax}), matrix.Apply(pdfgo.Point{X: b.XMin, Y: b.YMax}),
|
|
||||||
})
|
|
||||||
if box.W <= 0 || box.H <= 0 {
|
|
||||||
return nil, fmt.Errorf("invalid PDF tiling pattern bounds")
|
|
||||||
}
|
|
||||||
local := *c.importer
|
|
||||||
local.matrix = matrix
|
|
||||||
local.matrix[4] -= box.X
|
|
||||||
local.matrix[5] -= box.Y
|
|
||||||
local.pageWidth, local.pageHeight = box.W, box.H
|
|
||||||
local.compositeCache = nil
|
|
||||||
pattern = &pdfCompositePattern{nodes: nodes, local: local, box: box}
|
|
||||||
c.cache.patterns[paint] = pattern
|
|
||||||
}
|
|
||||||
xstep, ystep := math.Abs(source.XStep), math.Abs(source.YStep)
|
xstep, ystep := math.Abs(source.XStep), math.Abs(source.YStep)
|
||||||
area := pdfBounds([]pdfgo.Point{
|
area := pdfBounds([]pdfgo.Point{
|
||||||
inverse.Apply(pdfgo.Point{X: c.box.X, Y: c.box.Y}), inverse.Apply(pdfgo.Point{X: c.box.X + c.box.W, Y: c.box.Y}),
|
inverse.Apply(pdfgo.Point{X: c.box.X, Y: c.box.Y}), inverse.Apply(pdfgo.Point{X: c.box.X + c.box.W, Y: c.box.Y}),
|
||||||
@@ -108,3 +85,109 @@ func (c *pdfCompositor) tiling(paint pdfgo.Paint, backdrop []pdfCompositePixel,
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compositePattern 复用图案单元解析及几何上下文,供检查和局部合成共同使用
|
||||||
|
// 入参: paint 图案画刷
|
||||||
|
// 返回: *pdfCompositePattern 单元内容, error 解析或边界错误
|
||||||
|
func (p *pdfImporter) compositePattern(paint pdfgo.Paint) (*pdfCompositePattern, error) {
|
||||||
|
paint.Alpha = 1
|
||||||
|
cache := p.compositingCache()
|
||||||
|
if cache.patterns == nil {
|
||||||
|
cache.patterns = make(map[pdfgo.Paint]*pdfCompositePattern)
|
||||||
|
}
|
||||||
|
if pattern := cache.patterns[paint]; pattern != nil {
|
||||||
|
return pattern, nil
|
||||||
|
}
|
||||||
|
source := paint.Tiling
|
||||||
|
nodes, err := p.collectCompositeNodes(func(v pdfgo.Visitor) error { return source.Walk(p.ctx, paint, v) })
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matrix := p.matrix.Mul(source.Matrix)
|
||||||
|
b := source.BBox
|
||||||
|
box := pdfBounds([]pdfgo.Point{
|
||||||
|
matrix.Apply(pdfgo.Point{X: b.XMin, Y: b.YMin}), matrix.Apply(pdfgo.Point{X: b.XMax, Y: b.YMin}),
|
||||||
|
matrix.Apply(pdfgo.Point{X: b.XMax, Y: b.YMax}), matrix.Apply(pdfgo.Point{X: b.XMin, Y: b.YMax}),
|
||||||
|
})
|
||||||
|
if box.W <= 0 || box.H <= 0 {
|
||||||
|
return nil, fmt.Errorf("invalid PDF tiling pattern bounds")
|
||||||
|
}
|
||||||
|
local := *p
|
||||||
|
local.matrix = matrix
|
||||||
|
local.matrix[4] -= box.X
|
||||||
|
local.matrix[5] -= box.Y
|
||||||
|
local.pageWidth, local.pageHeight = box.W, box.H
|
||||||
|
local.compositeCache = nil
|
||||||
|
pattern := &pdfCompositePattern{nodes: nodes, local: local, box: box}
|
||||||
|
cache.patterns[paint] = pattern
|
||||||
|
return pattern, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// directCompositeNode 检查图元及其图案单元能否独立保留,不忽略单元内的背景混合
|
||||||
|
// 入参: node 图元, space 混合空间
|
||||||
|
// 返回: bool 是否可直接转换, error 图案解析错误
|
||||||
|
func (p *pdfImporter) directCompositeNode(node pdfCompositeNode, space *pdfgo.ColorSpace) (bool, error) {
|
||||||
|
if !node.opaque(space) && !(space.SRGBEquivalent() && node.direct()) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if node.group != nil {
|
||||||
|
for _, child := range node.children {
|
||||||
|
if direct, err := p.directCompositeNode(child, space); err != nil || !direct {
|
||||||
|
return direct, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
style, fill, stroke := node.style()
|
||||||
|
for i, paint := range []pdfgo.Paint{style.Fill, style.Stroke} {
|
||||||
|
if i == 0 && !fill || i == 1 && !stroke || paint.Tiling == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pattern, err := p.compositePattern(paint)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, child := range pattern.nodes {
|
||||||
|
if direct, err := pattern.local.directCompositeNode(child, space); err != nil || !direct {
|
||||||
|
return direct, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// processOverprint 检查图元、透明组和图案单元是否需要设备四色套印
|
||||||
|
// 入参: nodes 原始图元
|
||||||
|
// 返回: bool 是否需要四色混合, error 图像或图案解析错误
|
||||||
|
func (p *pdfImporter) processOverprint(nodes []pdfCompositeNode) (bool, error) {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.group != nil {
|
||||||
|
if found, err := p.processOverprint(node.children); err != nil || found {
|
||||||
|
return found, err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
style, fill, stroke := node.style()
|
||||||
|
if node.image != nil && style.FillOverprint {
|
||||||
|
if _, found, err := pdfImageProcessColorants(node.image.Image); err != nil || found {
|
||||||
|
return found, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fill && style.FillOverprint && pdfOverprintNeedsSeparation(style.Fill) || stroke && style.StrokeOverprint && pdfOverprintNeedsSeparation(style.Stroke) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
for i, paint := range []pdfgo.Paint{style.Fill, style.Stroke} {
|
||||||
|
if i == 0 && !fill || i == 1 && !stroke || paint.Tiling == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pattern, err := p.compositePattern(paint)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if found, err := pattern.local.processOverprint(pattern.nodes); err != nil || found {
|
||||||
|
return found, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
Reference in new issue
Block a user