github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/resources/images/resampling.go (about)

     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  }