resampling.go (4873B)
1 // Copyright 2019 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package images
15
16 import "math"
17
18 // We moved from imaging to the gift package for image processing at some point.
19 // That package had more, but also less resampling filters. So we add the missing
20 // ones here. They are fairly exotic, but someone may use them, so keep them here
21 // for now.
22 //
23 // The filters below are ported from https://github.com/disintegration/imaging/blob/9aab30e6aa535fe3337b489b76759ef97dfaf362/resize.go#L369
24 // MIT License.
25
26 var (
27 // Hermite cubic spline filter (BC-spline; B=0; C=0).
28 hermiteResampling = resamp{
29 name: "Hermite",
30 support: 1.0,
31 kernel: func(x float32) float32 {
32 x = absf32(x)
33 if x < 1.0 {
34 return bcspline(x, 0.0, 0.0)
35 }
36 return 0
37 },
38 }
39
40 // Mitchell-Netravali cubic filter (BC-spline; B=1/3; C=1/3).
41 mitchellNetravaliResampling = resamp{
42 name: "MitchellNetravali",
43 support: 2.0,
44 kernel: func(x float32) float32 {
45 x = absf32(x)
46 if x < 2.0 {
47 return bcspline(x, 1.0/3.0, 1.0/3.0)
48 }
49 return 0
50 },
51 }
52
53 // Catmull-Rom - sharp cubic filter (BC-spline; B=0; C=0.5).
54 catmullRomResampling = resamp{
55 name: "CatmullRomResampling",
56 support: 2.0,
57 kernel: func(x float32) float32 {
58 x = absf32(x)
59 if x < 2.0 {
60 return bcspline(x, 0.0, 0.5)
61 }
62 return 0
63 },
64 }
65
66 // BSpline is a smooth cubic filter (BC-spline; B=1; C=0).
67 bSplineResampling = resamp{
68 name: "BSplineResampling",
69 support: 2.0,
70 kernel: func(x float32) float32 {
71 x = absf32(x)
72 if x < 2.0 {
73 return bcspline(x, 1.0, 0.0)
74 }
75 return 0
76 },
77 }
78
79 // Gaussian blurring filter.
80 gaussianResampling = resamp{
81 name: "GaussianResampling",
82 support: 2.0,
83 kernel: func(x float32) float32 {
84 x = absf32(x)
85 if x < 2.0 {
86 return float32(math.Exp(float64(-2 * x * x)))
87 }
88 return 0
89 },
90 }
91
92 // Hann-windowed sinc filter (3 lobes).
93 hannResampling = resamp{
94 name: "HannResampling",
95 support: 3.0,
96 kernel: func(x float32) float32 {
97 x = absf32(x)
98 if x < 3.0 {
99 return sinc(x) * float32(0.5+0.5*math.Cos(math.Pi*float64(x)/3.0))
100 }
101 return 0
102 },
103 }
104
105 hammingResampling = resamp{
106 name: "HammingResampling",
107 support: 3.0,
108 kernel: func(x float32) float32 {
109 x = absf32(x)
110 if x < 3.0 {
111 return sinc(x) * float32(0.54+0.46*math.Cos(math.Pi*float64(x)/3.0))
112 }
113 return 0
114 },
115 }
116
117 // Blackman-windowed sinc filter (3 lobes).
118 blackmanResampling = resamp{
119 name: "BlackmanResampling",
120 support: 3.0,
121 kernel: func(x float32) float32 {
122 x = absf32(x)
123 if x < 3.0 {
124 return sinc(x) * float32(0.42-0.5*math.Cos(math.Pi*float64(x)/3.0+math.Pi)+0.08*math.Cos(2.0*math.Pi*float64(x)/3.0))
125 }
126 return 0
127 },
128 }
129
130 bartlettResampling = resamp{
131 name: "BartlettResampling",
132 support: 3.0,
133 kernel: func(x float32) float32 {
134 x = absf32(x)
135 if x < 3.0 {
136 return sinc(x) * (3.0 - x) / 3.0
137 }
138 return 0
139 },
140 }
141
142 // Welch-windowed sinc filter (parabolic window, 3 lobes).
143 welchResampling = resamp{
144 name: "WelchResampling",
145 support: 3.0,
146 kernel: func(x float32) float32 {
147 x = absf32(x)
148 if x < 3.0 {
149 return sinc(x) * (1.0 - (x * x / 9.0))
150 }
151 return 0
152 },
153 }
154
155 // Cosine-windowed sinc filter (3 lobes).
156 cosineResampling = resamp{
157 name: "CosineResampling",
158 support: 3.0,
159 kernel: func(x float32) float32 {
160 x = absf32(x)
161 if x < 3.0 {
162 return sinc(x) * float32(math.Cos((math.Pi/2.0)*(float64(x)/3.0)))
163 }
164 return 0
165 },
166 }
167 )
168
169 // The following code is borrowed from https://raw.githubusercontent.com/disintegration/gift/master/resize.go
170 // MIT licensed.
171 type resamp struct {
172 name string
173 support float32
174 kernel func(float32) float32
175 }
176
177 func (r resamp) String() string {
178 return r.name
179 }
180
181 func (r resamp) Support() float32 {
182 return r.support
183 }
184
185 func (r resamp) Kernel(x float32) float32 {
186 return r.kernel(x)
187 }
188
189 func bcspline(x, b, c float32) float32 {
190 if x < 0 {
191 x = -x
192 }
193 if x < 1 {
194 return ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
195 }
196 if x < 2 {
197 return ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
198 }
199 return 0
200 }
201
202 func absf32(x float32) float32 {
203 if x < 0 {
204 return -x
205 }
206 return x
207 }
208
209 func sinc(x float32) float32 {
210 if x == 0 {
211 return 1
212 }
213 return float32(math.Sin(math.Pi*float64(x)) / (math.Pi * float64(x)))
214 }