mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 17:27:08 +08:00
94 lines
3.4 KiB
Go
94 lines
3.4 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 (
|
|
"image/color"
|
|
"math"
|
|
)
|
|
|
|
// profileGradient 保存独立色标和只读配置,延伸及重复由几何采样器处理
|
|
type profileGradient struct {
|
|
positions []float64
|
|
colors []MeshVertex
|
|
}
|
|
|
|
// profileGradient 准备ICC渐变的源分量采样,不用转换后的端点近似非线性色彩变换
|
|
// 入参: segments 原色标, alpha 外层透明度
|
|
// 返回: func(float64) color.RGBA 单位区间采样器,无ICC时为nil, error 配置错误
|
|
func (r *Renderer) profileGradient(segments []ShdSegment, alpha *int) (func(float64) color.RGBA, error) {
|
|
profiled := false
|
|
for _, segment := range segments {
|
|
if space := r.colorDefinition(segment.Color.ColorSpace); space != nil && space.Profile != "" {
|
|
profiled = true
|
|
break
|
|
}
|
|
}
|
|
if !profiled {
|
|
return nil, nil
|
|
}
|
|
gradient := &profileGradient{positions: gradientPositions(segments), colors: make([]MeshVertex, len(segments))}
|
|
for i, segment := range segments {
|
|
kind, values, err := r.colorComponents(segment.Color.Value, segment.Color.Index, segment.Color.ColorSpace)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
profile, err := r.Reader.colorProfile(r.colorDefinition(segment.Color.ColorSpace))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
opacity := 1.0
|
|
if value := mergeAlpha(segment.Color.Alpha, alpha); value != nil {
|
|
opacity = float64(clampColor(*value)) / 255
|
|
}
|
|
gradient.colors[i] = MeshVertex{Space: kind, Values: values, Alpha: opacity, profile: profile}
|
|
}
|
|
return gradient.At, nil
|
|
}
|
|
|
|
// At 在相同源空间内插值,不同空间先转换为sRGB,保留重复位置的右侧色标
|
|
// 入参: t 单位区间位置
|
|
// 返回: color.RGBA 预乘采样颜色
|
|
func (g *profileGradient) At(t float64) color.RGBA {
|
|
if len(g.colors) == 0 || math.IsNaN(t) {
|
|
return color.RGBA{}
|
|
}
|
|
first := g.colors[0]
|
|
if t < g.positions[0] {
|
|
r, green, b := first.rgb(first.Values)
|
|
return profileColor([3]float64{r, green, b}, first.Alpha)
|
|
}
|
|
for i := 1; i < len(g.colors); i++ {
|
|
if t < g.positions[i] {
|
|
before, after := g.colors[i-1], g.colors[i]
|
|
x := (t - g.positions[i-1]) / (g.positions[i] - g.positions[i-1])
|
|
if before.sameSpace(after) {
|
|
var values [4]float64
|
|
for j := range values {
|
|
values[j] = before.Values[j]*(1-x) + after.Values[j]*x
|
|
}
|
|
r, green, b := before.rgb(values)
|
|
return profileColor([3]float64{r, green, b}, before.Alpha*(1-x)+after.Alpha*x)
|
|
}
|
|
r0, g0, b0 := before.rgb(before.Values)
|
|
r1, g1, b1 := after.rgb(after.Values)
|
|
return color.RGBA{meshByte(r0*before.Alpha*(1-x) + r1*after.Alpha*x), meshByte(g0*before.Alpha*(1-x) + g1*after.Alpha*x), meshByte(b0*before.Alpha*(1-x) + b1*after.Alpha*x), meshByte(before.Alpha*(1-x) + after.Alpha*x)}
|
|
}
|
|
}
|
|
last := g.colors[len(g.colors)-1]
|
|
r, green, b := last.rgb(last.Values)
|
|
return profileColor([3]float64{r, green, b}, last.Alpha)
|
|
}
|