Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion colorconv/colorconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ func (c *ConvertColor) gamutMapChromaScale(L, a, b float64) (r, g, bl float64) {
hi := 1.0
var mid float64
var foundR, foundG, foundB float64
found := false
// If even fully desaturated (a=b=0) is out of gamut, we'll clip
for range 24 {
mid = (lo + hi) / 2.0
Expand All @@ -392,14 +393,15 @@ func (c *ConvertColor) gamutMapChromaScale(L, a, b float64) (r, g, bl float64) {
r0, g0, b0 := c.LabToSRGBNoGamutMap(L, a2, b2)
if inGamut(r0, g0, b0) {
foundR, foundG, foundB = r0, g0, b0
found = true
// can try to keep more chroma
lo = mid
} else {
hi = mid
}
}
// If we never found a valid in-gamut during binary search, try a= b =0
if !(inGamut(foundR, foundG, foundB)) {
if !found {
r0, g0, b0 := c.LabToSRGBNoGamutMap(L, 0, 0)
// if still out-of-gamut (very unlikely), clip
return clamp01(r0), clamp01(g0), clamp01(b0)
Expand Down
19 changes: 14 additions & 5 deletions prism/meta/icc/pcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,25 +188,34 @@ func NewUniformFunctionTransformer(name string, f func(unit_float) unit_float) *
}

type XYZtosRGB struct {
c *colorconv.ConvertColor
t func(l, a, b unit_float) (x, y, z unit_float)
c *colorconv.ConvertColor
t func(l, a, b unit_float) (x, y, z unit_float)
map_gamut bool
}

func NewXYZtosRGB(whitepoint XYZType, clamp, map_gamut bool) *XYZtosRGB {
c := colorconv.NewConvertColor(whitepoint.X, whitepoint.Y, whitepoint.Z, 1)
if clamp {
if map_gamut {
return &XYZtosRGB{c, c.XYZToSRGB}
return &XYZtosRGB{c, c.XYZToSRGB, true}
}
return &XYZtosRGB{c, c.XYZToSRGBNoGamutMap}
return &XYZtosRGB{c, c.XYZToSRGBNoGamutMap, false}
}
return &XYZtosRGB{c, c.XYZToSRGBNoClamp}
return &XYZtosRGB{c, c.XYZToSRGBNoClamp, false}
}

func (n *XYZtosRGB) AddPreviousMatrix(m Matrix3) {
n.c.AddPreviousMatrix(m[0], m[1], m[2])
}

// CanAbsorbMatrix reports whether it is safe for the pipeline optimizer to
// fuse preceding matrices into this transformer. When gamut mapping is
// active, the fallback path converts via Lab which requires the input to be
// actual XYZ values, so matrix absorption would break that invariant.
func (n *XYZtosRGB) CanAbsorbMatrix() bool {
return !n.map_gamut
}

func (c *XYZtosRGB) Transform(l, a, b unit_float) (unit_float, unit_float, unit_float) {
return c.t(l, a, b)
}
Expand Down
2 changes: 1 addition & 1 deletion prism/meta/icc/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (p *Pipeline) finalize(optimize bool) {
// Check if the last transform can absorb previous matrices
if len(p.transformers) > 1 {
last := p.transformers[len(p.transformers)-1]
if apm, ok := last.(*XYZtosRGB); ok {
if apm, ok := last.(*XYZtosRGB); ok && apm.CanAbsorbMatrix() {
p.transformers = p.transformers[:len(p.transformers)-1]
for {
m := p.remove_last_matrix3()
Expand Down
Loading