1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::opbasics::*;
use std::cmp;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OpBaseCurve {
pub points: Vec<(f32, f32)>,
}
impl OpBaseCurve {
pub fn new(_img: &RawImage) -> OpBaseCurve {
OpBaseCurve{
points: vec![
(0.00, 0.00),
(0.50, 0.60),
(1.00, 1.00),
],
}
}
}
impl<'a> ImageOp<'a> for OpBaseCurve {
fn name(&self) -> &str {"basecurve"}
fn run(&self, _pipeline: &PipelineGlobals, buf: Arc<OpBuffer>) -> Arc<OpBuffer> {
let func = SplineFunc::new(self.points.clone());
Arc::new(buf.mutate_lines_copying(&(|line: &mut [f32], _| {
for pix in line.chunks_exact_mut(3) {
pix[0] = func.interpolate(pix[0]);
pix[1] = pix[1];
pix[2] = pix[2];
}
})))
}
}
struct SplineFunc {
points: Vec<(f32,f32)>,
c1s: Vec<f32>,
c2s: Vec<f32>,
c3s: Vec<f32>,
}
impl SplineFunc {
fn new(points: Vec<(f32,f32)>) -> SplineFunc {
if points.len() < 2 { panic!("Need at least 2 points for Spline"); }
let mut dxs = Vec::new();
let mut dys = Vec::new();
let mut slopes = Vec::new();
for i in 0..(points.len()-1) {
let dx = points[i+1].0 - points[i].0;
let dy = points[i+1].1 - points[i].1;
dxs.push(dx);
dys.push(dy);
slopes.push(dy/dx);
}
let mut c1s = vec![slopes[0]];
for i in 0..(dxs.len()-1) {
let m = slopes[i];
let next = slopes[i+1];
if m*next <= 0.0 {
c1s.push(0.0);
} else {
let dx = dxs[i];
let dxnext = dxs[i+1];
let common = dx + dxnext;
c1s.push(3.0*common/((common+dxnext)/m + (common + dx)/next));
}
}
c1s.push(slopes[slopes.len()-1]);
let mut c2s = Vec::new();
let mut c3s = Vec::new();
for i in 0..(c1s.len()-1) {
let c1 = c1s[i];
let slope = slopes[i];
let invdx = 1.0 / dxs[i];
let common = c1+c1s[i+1] - slope - slope;
c2s.push((slope-c1-common)*invdx);
c3s.push(common*invdx*invdx);
}
SplineFunc {
points: points,
c1s: c1s,
c2s: c2s,
c3s: c3s,
}
}
fn interpolate(&self, val: f32) -> f32 {
let end = self.points[self.points.len()-1].0;
if val >= end {
return self.points[self.points.len()-1].1;
}
let mut low: isize = 0;
let mut mid: isize;
let mut high: isize = (self.c3s.len() - 1) as isize;
while low <= high {
mid = (low+high)/2;
let xhere = self.points[mid as usize].0;
if xhere < val { low = mid + 1; }
else if xhere > val { high = mid - 1; }
else { return self.points[mid as usize].1 }
}
let i = cmp::max(0, high) as usize;
let diff = val - self.points[i].0;
self.points[i].1 + self.c1s[i]*diff + self.c2s[i]*diff*diff + self.c3s[i]*diff*diff*diff
}
}