feat(转换能力): 优化色料转换采样
build.yaml / build (push) Successful in 52s

This commit is contained in:
xiaoqidun committed 2026-10-08 12:59:00 +08:00
1 parent 0351dd54f5
commit 245fffed84
5 files changed
+56 -39

No files matched your search

+1 -1
View File
@@ -10,7 +10,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-20261008021024-e8f1cc0a7ad9 github.com/xiaoqidun/pdfgo v0.0.0-20261008045044-ada80114c916
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
+2 -2
View File
@@ -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-20261008021024-e8f1cc0a7ad9 h1:aHEEZYzIL7cCLW9IXMlBC+LyCxkYrge3Zw/GfioDT2I= github.com/xiaoqidun/pdfgo v0.0.0-20261008045044-ada80114c916 h1:SwXbZ6zLtTCxMeV7A5GBSxgNhyVfdzWLhPh38IdkVTc=
github.com/xiaoqidun/pdfgo v0.0.0-20261008021024-e8f1cc0a7ad9/go.mod h1:4Pf0JO0BEf1uzRY+uZjlMjN/OPn3PYa0YMi6cqPPTLQ= github.com/xiaoqidun/pdfgo v0.0.0-20261008045044-ada80114c916/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=
+11 -16
View File
@@ -789,8 +789,12 @@ func (c *pdfCompositor) imageColor(mark *pdfgo.ImageMark, point pdfgo.Point, spa
if point.X < 0 || point.X > 1 || point.Y < 0 || point.Y > 1 { if point.X < 0 || point.X > 1 || point.Y < 0 || point.Y > 1 {
return [4]float64{}, 0, nil return [4]float64{}, 0, nil
} }
process, err := c.cache.imageProcess(c.importer, mark.Image, space, c.softMask)
if err != nil {
return [4]float64{}, 0, err
}
source := c.cache.images[mark.Image] source := c.cache.images[mark.Image]
if source == nil { if process == nil && source == nil {
var err error var err error
source, err = mark.Image.DecodeComponentsViewContext(c.importer.ctx) source, err = mark.Image.DecodeComponentsViewContext(c.importer.ctx)
if err != nil { if err != nil {
@@ -798,22 +802,13 @@ func (c *pdfCompositor) imageColor(mark *pdfgo.ImageMark, point pdfgo.Point, spa
} }
c.cache.images[mark.Image] = source c.cache.images[mark.Image] = source
} }
x, y := point.X*float64(source.Rect.Dx())-.5, (1-point.Y)*float64(source.Rect.Dy())-.5 bounds := process.Bounds()
key := pdfImageProcessKey{image: mark.Image, space: space, softMask: c.softMask} if process == nil {
process, prepared := c.cache.imageProcesses[key] bounds = source.Rect
if !prepared {
var err error
process, err = source.PrepareProcess(&pdfgo.ColorantDevice{Space: space}, space, c.softMask)
if err != nil {
return [4]float64{}, 0, err
}
if c.cache.imageProcesses == nil {
c.cache.imageProcesses = make(map[pdfImageProcessKey]*pdfgo.ImageProcess)
}
c.cache.imageProcesses[key] = process
} }
x, y := point.X*float64(bounds.Dx())-.5, (1-point.Y)*float64(bounds.Dy())-.5
sample := func(x, y int) ([4]float64, float64) { sample := func(x, y int) ([4]float64, float64) {
x, y = source.Rect.Min.X+max(0, min(source.Rect.Dx()-1, x)), source.Rect.Min.Y+max(0, min(source.Rect.Dy()-1, y)) x, y = bounds.Min.X+max(0, min(bounds.Dx()-1, x)), bounds.Min.Y+max(0, min(bounds.Dy()-1, y))
if process != nil { if process != nil {
return process.ValuesAt(x, y) return process.ValuesAt(x, y)
} }
@@ -862,7 +857,7 @@ func (c *pdfCompositor) imageColor(mark *pdfgo.ImageMark, point pdfgo.Point, spa
if process != nil || space.Equal(source.Space) { if process != nil || space.Equal(source.Space) {
return values, alpha, nil return values, alpha, nil
} }
values, err := space.ConvertWith(values[:source.Space.Components()], source.Space, mark.Style.RenderingIntent, mark.Style.ColorConversion) values, err = space.ConvertWith(values[:source.Space.Components()], source.Space, mark.Style.RenderingIntent, mark.Style.ColorConversion)
return values, alpha, err return values, alpha, err
} }
+15 -10
View File
@@ -246,17 +246,22 @@ func (p *pdfImporter) directCompositeNode(node pdfCompositeNode, space *pdfgo.Co
} }
if space.Model == "DeviceCMYK" && style.ColorConversion != (pdfgo.ColorConversion{}) { if space.Model == "DeviceCMYK" && style.ColorConversion != (pdfgo.ColorConversion{}) {
if node.image != nil && !node.image.Image.ImageMask { if node.image != nil && !node.image.Image.ImageMask {
source := p.compositingCache().images[node.image.Image] _, native, err := pdfImageProcessColorants(node.image.Image)
if source == nil { if err != nil {
var err error return false, err
source, err = node.image.Image.DecodeComponentsViewContext(p.ctx)
if err != nil {
return false, err
}
p.compositingCache().images[node.image.Image] = source
} }
if source.Space.Model == "DeviceRGB" && source.Space.Device() { if !native {
return false, nil source := p.compositingCache().images[node.image.Image]
if source == nil {
source, err = node.image.Image.DecodeComponentsViewContext(p.ctx)
if err != nil {
return false, err
}
p.compositingCache().images[node.image.Image] = source
}
if source.Space.Model == "DeviceRGB" && source.Space.Device() {
return false, nil
}
} }
} else { } else {
for i, paint := range [2]pdfgo.Paint{style.Fill, style.Stroke} { for i, paint := range [2]pdfgo.Paint{style.Fill, style.Stroke} {
+27 -10
View File
@@ -53,17 +53,8 @@ func (p *pdfImporter) imageProcessModel(source *pdfgo.Image) (pdfgo.Name, error)
// 返回: image.Image 只读图像, error 解码或分量映射错误 // 返回: image.Image 只读图像, error 解码或分量映射错误
func (p *pdfImporter) imageProcess(source *pdfgo.Image, model pdfgo.Name) (image.Image, error) { func (p *pdfImporter) imageProcess(source *pdfgo.Image, model pdfgo.Name) (image.Image, error) {
cache := p.compositingCache() cache := p.compositingCache()
components := cache.images[source]
if components == nil {
var err error
components, err = source.DecodeComponentsViewContext(p.ctx)
if err != nil {
return nil, err
}
cache.images[source] = components
}
space := &pdfgo.ColorSpace{Model: model} space := &pdfgo.ColorSpace{Model: model}
process, err := components.PrepareProcess(&pdfgo.ColorantDevice{Space: space}, space, false) process, err := cache.imageProcess(p, source, space, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -73,6 +64,32 @@ func (p *pdfImporter) imageProcess(source *pdfgo.Image, model pdfgo.Name) (image
return &pdfNativeImage{source: process, space: space}, nil return &pdfNativeImage{source: process, space: space}, nil
} }
// imageProcess 复用同组原生采样,仅在需要备用颜色时保留完整分量
// 入参: importer 导入器, source 源图像, space 组混合空间, softMask 是否用于软蒙版
// 返回: *pdfgo.ImageProcess 原生采样,需要备用色时为nil, error 解码或布局错误
func (c *pdfCompositeCache) imageProcess(importer *pdfImporter, source *pdfgo.Image, space *pdfgo.ColorSpace, softMask bool) (*pdfgo.ImageProcess, error) {
key := pdfImageProcessKey{image: source, space: space, softMask: softMask}
if process, found := c.imageProcesses[key]; found {
return process, nil
}
device := &pdfgo.ColorantDevice{Space: space}
var process *pdfgo.ImageProcess
var err error
if components := c.images[source]; components != nil {
process, err = components.PrepareProcess(device, space, softMask)
} else {
process, err = source.DecodeProcessContext(importer.ctx, device, space, softMask)
}
if err != nil {
return nil, err
}
if c.imageProcesses == nil {
c.imageProcesses = make(map[pdfImageProcessKey]*pdfgo.ImageProcess)
}
c.imageProcesses[key] = process
return process, nil
}
// ColorModel 保留16位原生分量与源透明度 // ColorModel 保留16位原生分量与源透明度
// 返回: color.Model 非预乘颜色模型 // 返回: color.Model 非预乘颜色模型
func (s *pdfNativeImage) ColorModel() color.Model { return color.NRGBA64Model } func (s *pdfNativeImage) ColorModel() color.Model { return color.NRGBA64Model }