mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 13:56:32 +08:00
1 parent
28b524ae84
commit
b5a00f47c3
3 files changed
+139
-1
No files matched your search
@@ -72,6 +72,7 @@ type pdfCompositeCache struct {
|
||||
images map[*pdfgo.Image]*pdfgo.ImageComponents
|
||||
masks map[*pdfgo.SoftMask][]pdfCompositeNode
|
||||
meshes map[*pdfgo.MeshGradient][]pdfMeshTriangle
|
||||
patterns map[pdfgo.Paint]*pdfCompositePattern
|
||||
}
|
||||
|
||||
// compositingCache 按需创建单页合成缓存,页面切换时由导入器释放
|
||||
|
||||
@@ -109,6 +109,17 @@ func (c *pdfCompositor) drawPaint(node pdfCompositeNode, outline bool, paint pdf
|
||||
compatible := overprint && style.OverprintMode == 1 && node.image == nil && space.Model == "DeviceCMYK" && !space.Calibrated() && (paint.CMYK != nil || paint.Space != nil && paint.Space.Model == "DeviceCMYK" && !paint.Space.Calibrated())
|
||||
step := 25.4 / c.importer.rasterDPI
|
||||
uniform := node.image == nil && paint.Axial == nil && paint.Radial == nil && paint.Tiling == nil && paint.Mesh == nil
|
||||
var pattern []pdfCompositePixel
|
||||
if paint.Tiling != nil && (node.image == nil || node.image.Image.ImageMask) {
|
||||
backdrop := pixels
|
||||
if initial != nil {
|
||||
backdrop = initial
|
||||
}
|
||||
pattern, err = c.tiling(paint, backdrop, space)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var mesh []pdfMeshPixel
|
||||
if paint.Mesh != nil {
|
||||
mesh, err = c.mesh(paint.Mesh, space)
|
||||
@@ -133,7 +144,20 @@ func (c *pdfCompositor) drawPaint(node pdfCompositeNode, outline bool, paint pdf
|
||||
opacity *= mask[index]
|
||||
}
|
||||
var values [4]float64
|
||||
if mesh != nil {
|
||||
if pattern != nil {
|
||||
sample := pattern[index]
|
||||
values = sample.values
|
||||
shape *= sample.shape
|
||||
if sample.shape != 0 {
|
||||
opacity *= sample.alpha / sample.shape
|
||||
}
|
||||
if node.image != nil {
|
||||
point := c.inverse.Apply(pdfgo.Point{X: c.box.X + (float64(x)+.5)*step, Y: c.box.Y + (float64(y)+.5)*step})
|
||||
var alpha float64
|
||||
_, alpha, err = c.imageColor(*node.image, point, space)
|
||||
opacity *= alpha
|
||||
}
|
||||
} else if mesh != nil {
|
||||
values = mesh[index].values
|
||||
shape *= mesh[index].shape
|
||||
} else if uniform {
|
||||
@@ -442,6 +466,9 @@ func (c *pdfCompositor) imageColor(mark pdfgo.ImageMark, point pdfgo.Point, spac
|
||||
}
|
||||
}
|
||||
if mark.Image.ImageMask {
|
||||
if mark.Style.Fill.Tiling != nil {
|
||||
return [4]float64{}, alpha * (1 - values[0]), nil
|
||||
}
|
||||
color, visible, err := pdfCompositeColor(mark.Style.Fill, mark.Matrix.Apply(point), space, mark.Style.RenderingIntent)
|
||||
if !visible {
|
||||
return color, 0, err
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/xiaoqidun/pdfgo"
|
||||
)
|
||||
|
||||
// pdfCompositePattern 保存图案单元的原始图元和独立几何缓存
|
||||
type pdfCompositePattern struct {
|
||||
nodes []pdfCompositeNode
|
||||
local pdfImporter
|
||||
box Box
|
||||
}
|
||||
|
||||
// tiling 将图案作为非隔离组绘制,保留背景贡献及单元间隙
|
||||
// 入参: paint 图案画刷, backdrop 初始背景, space 混合空间
|
||||
// 返回: []pdfCompositePixel 去除背景贡献的图案像素, error 解析或绘制错误
|
||||
func (c *pdfCompositor) tiling(paint pdfgo.Paint, backdrop []pdfCompositePixel, space *pdfgo.ColorSpace) ([]pdfCompositePixel, error) {
|
||||
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)
|
||||
inverse, ok := matrix.Inverse()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid PDF tiling pattern matrix")
|
||||
}
|
||||
if pattern == nil {
|
||||
nodes, err := pdfCompositeNodes(func(v pdfgo.Visitor) error { return source.Walk(c.importer.ctx, paint, v) }, c.importer.warning)
|
||||
if err != nil {
|
||||
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)
|
||||
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 + c.box.W, Y: c.box.Y + c.box.H}), inverse.Apply(pdfgo.Point{X: c.box.X, Y: c.box.Y + c.box.H}),
|
||||
})
|
||||
left, right := math.Ceil((area.X-source.BBox.XMax)/xstep), math.Floor((area.X+area.W-source.BBox.XMin)/xstep)
|
||||
top, bottom := math.Ceil((area.Y-source.BBox.YMax)/ystep), math.Floor((area.Y+area.H-source.BBox.YMin)/ystep)
|
||||
limit := float64(int(^uint(0) >> 1))
|
||||
for _, value := range []float64{left, right, top, bottom} {
|
||||
if !finite(value) || value <= -limit || value >= limit {
|
||||
return nil, fmt.Errorf("PDF tiling pattern instance range overflow")
|
||||
}
|
||||
}
|
||||
result := make([]pdfCompositePixel, len(backdrop))
|
||||
for i, pixel := range backdrop {
|
||||
result[i] = pdfCompositePixel{values: pixel.values, alpha: pixel.alpha}
|
||||
}
|
||||
localInverse, _ := pattern.local.matrix.Inverse()
|
||||
for row := int(top); row <= int(bottom); row++ {
|
||||
for column := int(left); column <= int(right); column++ {
|
||||
if err := c.importer.ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x, y := float64(column)*xstep, float64(row)*ystep
|
||||
dx, dy := matrix[0]*x+matrix[2]*y+pattern.box.X, matrix[1]*x+matrix[3]*y+pattern.box.Y
|
||||
cell := pdfCompositor{importer: &pattern.local, box: Box{X: c.box.X - dx, Y: c.box.Y - dy, W: c.box.W, H: c.box.H},
|
||||
width: c.width, height: c.height, inverse: localInverse, cache: pattern.local.compositingCache(), masks: map[*pdfgo.SoftMask][]float64{}}
|
||||
if err := cell.draw(pattern.nodes, result, space); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range result {
|
||||
pixel := &result[i]
|
||||
if pixel.effect != 0 {
|
||||
for j := 0; j < space.Components(); j++ {
|
||||
pixel.values[j] = math.Max(0, math.Min(1, (pixel.values[j]*pixel.alpha-backdrop[i].values[j]*backdrop[i].alpha*(1-pixel.effect))/pixel.effect))
|
||||
}
|
||||
}
|
||||
pixel.alpha = pixel.effect
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in new issue
Block a user