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 }