mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:42:25 -05:00 
			
		
		
		
	* use disintegration/imaging instead of nfnt/resize * update tests * use disintegration lib for thumbing (if necessary)
		
			
				
	
	
		
			595 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			595 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package imaging
 | |
| 
 | |
| import (
 | |
| 	"image"
 | |
| 	"math"
 | |
| )
 | |
| 
 | |
| type indexWeight struct {
 | |
| 	index  int
 | |
| 	weight float64
 | |
| }
 | |
| 
 | |
| func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWeight {
 | |
| 	du := float64(srcSize) / float64(dstSize)
 | |
| 	scale := du
 | |
| 	if scale < 1.0 {
 | |
| 		scale = 1.0
 | |
| 	}
 | |
| 	ru := math.Ceil(scale * filter.Support)
 | |
| 
 | |
| 	out := make([][]indexWeight, dstSize)
 | |
| 	tmp := make([]indexWeight, 0, dstSize*int(ru+2)*2)
 | |
| 
 | |
| 	for v := 0; v < dstSize; v++ {
 | |
| 		fu := (float64(v)+0.5)*du - 0.5
 | |
| 
 | |
| 		begin := int(math.Ceil(fu - ru))
 | |
| 		if begin < 0 {
 | |
| 			begin = 0
 | |
| 		}
 | |
| 		end := int(math.Floor(fu + ru))
 | |
| 		if end > srcSize-1 {
 | |
| 			end = srcSize - 1
 | |
| 		}
 | |
| 
 | |
| 		var sum float64
 | |
| 		for u := begin; u <= end; u++ {
 | |
| 			w := filter.Kernel((float64(u) - fu) / scale)
 | |
| 			if w != 0 {
 | |
| 				sum += w
 | |
| 				tmp = append(tmp, indexWeight{index: u, weight: w})
 | |
| 			}
 | |
| 		}
 | |
| 		if sum != 0 {
 | |
| 			for i := range tmp {
 | |
| 				tmp[i].weight /= sum
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		out[v] = tmp
 | |
| 		tmp = tmp[len(tmp):]
 | |
| 	}
 | |
| 
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // Resize resizes the image to the specified width and height using the specified resampling
 | |
| // filter and returns the transformed image. If one of width or height is 0, the image aspect
 | |
| // ratio is preserved.
 | |
| //
 | |
| // Example:
 | |
| //
 | |
| //	dstImage := imaging.Resize(srcImage, 800, 600, imaging.Lanczos)
 | |
| //
 | |
| func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
 | |
| 	dstW, dstH := width, height
 | |
| 	if dstW < 0 || dstH < 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 	if dstW == 0 && dstH == 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	srcW := img.Bounds().Dx()
 | |
| 	srcH := img.Bounds().Dy()
 | |
| 	if srcW <= 0 || srcH <= 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	// If new width or height is 0 then preserve aspect ratio, minimum 1px.
 | |
| 	if dstW == 0 {
 | |
| 		tmpW := float64(dstH) * float64(srcW) / float64(srcH)
 | |
| 		dstW = int(math.Max(1.0, math.Floor(tmpW+0.5)))
 | |
| 	}
 | |
| 	if dstH == 0 {
 | |
| 		tmpH := float64(dstW) * float64(srcH) / float64(srcW)
 | |
| 		dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
 | |
| 	}
 | |
| 
 | |
| 	if filter.Support <= 0 {
 | |
| 		// Nearest-neighbor special case.
 | |
| 		return resizeNearest(img, dstW, dstH)
 | |
| 	}
 | |
| 
 | |
| 	if srcW != dstW && srcH != dstH {
 | |
| 		return resizeVertical(resizeHorizontal(img, dstW, filter), dstH, filter)
 | |
| 	}
 | |
| 	if srcW != dstW {
 | |
| 		return resizeHorizontal(img, dstW, filter)
 | |
| 	}
 | |
| 	if srcH != dstH {
 | |
| 		return resizeVertical(img, dstH, filter)
 | |
| 	}
 | |
| 	return Clone(img)
 | |
| }
 | |
| 
 | |
| func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA {
 | |
| 	src := newScanner(img)
 | |
| 	dst := image.NewNRGBA(image.Rect(0, 0, width, src.h))
 | |
| 	weights := precomputeWeights(width, src.w, filter)
 | |
| 	parallel(0, src.h, func(ys <-chan int) {
 | |
| 		scanLine := make([]uint8, src.w*4)
 | |
| 		for y := range ys {
 | |
| 			src.scan(0, y, src.w, y+1, scanLine)
 | |
| 			j0 := y * dst.Stride
 | |
| 			for x := range weights {
 | |
| 				var r, g, b, a float64
 | |
| 				for _, w := range weights[x] {
 | |
| 					i := w.index * 4
 | |
| 					s := scanLine[i : i+4 : i+4]
 | |
| 					aw := float64(s[3]) * w.weight
 | |
| 					r += float64(s[0]) * aw
 | |
| 					g += float64(s[1]) * aw
 | |
| 					b += float64(s[2]) * aw
 | |
| 					a += aw
 | |
| 				}
 | |
| 				if a != 0 {
 | |
| 					aInv := 1 / a
 | |
| 					j := j0 + x*4
 | |
| 					d := dst.Pix[j : j+4 : j+4]
 | |
| 					d[0] = clamp(r * aInv)
 | |
| 					d[1] = clamp(g * aInv)
 | |
| 					d[2] = clamp(b * aInv)
 | |
| 					d[3] = clamp(a)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	})
 | |
| 	return dst
 | |
| }
 | |
| 
 | |
| func resizeVertical(img image.Image, height int, filter ResampleFilter) *image.NRGBA {
 | |
| 	src := newScanner(img)
 | |
| 	dst := image.NewNRGBA(image.Rect(0, 0, src.w, height))
 | |
| 	weights := precomputeWeights(height, src.h, filter)
 | |
| 	parallel(0, src.w, func(xs <-chan int) {
 | |
| 		scanLine := make([]uint8, src.h*4)
 | |
| 		for x := range xs {
 | |
| 			src.scan(x, 0, x+1, src.h, scanLine)
 | |
| 			for y := range weights {
 | |
| 				var r, g, b, a float64
 | |
| 				for _, w := range weights[y] {
 | |
| 					i := w.index * 4
 | |
| 					s := scanLine[i : i+4 : i+4]
 | |
| 					aw := float64(s[3]) * w.weight
 | |
| 					r += float64(s[0]) * aw
 | |
| 					g += float64(s[1]) * aw
 | |
| 					b += float64(s[2]) * aw
 | |
| 					a += aw
 | |
| 				}
 | |
| 				if a != 0 {
 | |
| 					aInv := 1 / a
 | |
| 					j := y*dst.Stride + x*4
 | |
| 					d := dst.Pix[j : j+4 : j+4]
 | |
| 					d[0] = clamp(r * aInv)
 | |
| 					d[1] = clamp(g * aInv)
 | |
| 					d[2] = clamp(b * aInv)
 | |
| 					d[3] = clamp(a)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	})
 | |
| 	return dst
 | |
| }
 | |
| 
 | |
| // resizeNearest is a fast nearest-neighbor resize, no filtering.
 | |
| func resizeNearest(img image.Image, width, height int) *image.NRGBA {
 | |
| 	dst := image.NewNRGBA(image.Rect(0, 0, width, height))
 | |
| 	dx := float64(img.Bounds().Dx()) / float64(width)
 | |
| 	dy := float64(img.Bounds().Dy()) / float64(height)
 | |
| 
 | |
| 	if dx > 1 && dy > 1 {
 | |
| 		src := newScanner(img)
 | |
| 		parallel(0, height, func(ys <-chan int) {
 | |
| 			for y := range ys {
 | |
| 				srcY := int((float64(y) + 0.5) * dy)
 | |
| 				dstOff := y * dst.Stride
 | |
| 				for x := 0; x < width; x++ {
 | |
| 					srcX := int((float64(x) + 0.5) * dx)
 | |
| 					src.scan(srcX, srcY, srcX+1, srcY+1, dst.Pix[dstOff:dstOff+4])
 | |
| 					dstOff += 4
 | |
| 				}
 | |
| 			}
 | |
| 		})
 | |
| 	} else {
 | |
| 		src := toNRGBA(img)
 | |
| 		parallel(0, height, func(ys <-chan int) {
 | |
| 			for y := range ys {
 | |
| 				srcY := int((float64(y) + 0.5) * dy)
 | |
| 				srcOff0 := srcY * src.Stride
 | |
| 				dstOff := y * dst.Stride
 | |
| 				for x := 0; x < width; x++ {
 | |
| 					srcX := int((float64(x) + 0.5) * dx)
 | |
| 					srcOff := srcOff0 + srcX*4
 | |
| 					copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
 | |
| 					dstOff += 4
 | |
| 				}
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	return dst
 | |
| }
 | |
| 
 | |
| // Fit scales down the image using the specified resample filter to fit the specified
 | |
| // maximum width and height and returns the transformed image.
 | |
| //
 | |
| // Example:
 | |
| //
 | |
| //	dstImage := imaging.Fit(srcImage, 800, 600, imaging.Lanczos)
 | |
| //
 | |
| func Fit(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
 | |
| 	maxW, maxH := width, height
 | |
| 
 | |
| 	if maxW <= 0 || maxH <= 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	srcBounds := img.Bounds()
 | |
| 	srcW := srcBounds.Dx()
 | |
| 	srcH := srcBounds.Dy()
 | |
| 
 | |
| 	if srcW <= 0 || srcH <= 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	if srcW <= maxW && srcH <= maxH {
 | |
| 		return Clone(img)
 | |
| 	}
 | |
| 
 | |
| 	srcAspectRatio := float64(srcW) / float64(srcH)
 | |
| 	maxAspectRatio := float64(maxW) / float64(maxH)
 | |
| 
 | |
| 	var newW, newH int
 | |
| 	if srcAspectRatio > maxAspectRatio {
 | |
| 		newW = maxW
 | |
| 		newH = int(float64(newW) / srcAspectRatio)
 | |
| 	} else {
 | |
| 		newH = maxH
 | |
| 		newW = int(float64(newH) * srcAspectRatio)
 | |
| 	}
 | |
| 
 | |
| 	return Resize(img, newW, newH, filter)
 | |
| }
 | |
| 
 | |
| // Fill creates an image with the specified dimensions and fills it with the scaled source image.
 | |
| // To achieve the correct aspect ratio without stretching, the source image will be cropped.
 | |
| //
 | |
| // Example:
 | |
| //
 | |
| //	dstImage := imaging.Fill(srcImage, 800, 600, imaging.Center, imaging.Lanczos)
 | |
| //
 | |
| func Fill(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | |
| 	dstW, dstH := width, height
 | |
| 
 | |
| 	if dstW <= 0 || dstH <= 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	srcBounds := img.Bounds()
 | |
| 	srcW := srcBounds.Dx()
 | |
| 	srcH := srcBounds.Dy()
 | |
| 
 | |
| 	if srcW <= 0 || srcH <= 0 {
 | |
| 		return &image.NRGBA{}
 | |
| 	}
 | |
| 
 | |
| 	if srcW == dstW && srcH == dstH {
 | |
| 		return Clone(img)
 | |
| 	}
 | |
| 
 | |
| 	if srcW >= 100 && srcH >= 100 {
 | |
| 		return cropAndResize(img, dstW, dstH, anchor, filter)
 | |
| 	}
 | |
| 	return resizeAndCrop(img, dstW, dstH, anchor, filter)
 | |
| }
 | |
| 
 | |
| // cropAndResize crops the image to the smallest possible size that has the required aspect ratio using
 | |
| // the given anchor point, then scales it to the specified dimensions and returns the transformed image.
 | |
| //
 | |
| // This is generally faster than resizing first, but may result in inaccuracies when used on small source images.
 | |
| func cropAndResize(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | |
| 	dstW, dstH := width, height
 | |
| 
 | |
| 	srcBounds := img.Bounds()
 | |
| 	srcW := srcBounds.Dx()
 | |
| 	srcH := srcBounds.Dy()
 | |
| 	srcAspectRatio := float64(srcW) / float64(srcH)
 | |
| 	dstAspectRatio := float64(dstW) / float64(dstH)
 | |
| 
 | |
| 	var tmp *image.NRGBA
 | |
| 	if srcAspectRatio < dstAspectRatio {
 | |
| 		cropH := float64(srcW) * float64(dstH) / float64(dstW)
 | |
| 		tmp = CropAnchor(img, srcW, int(math.Max(1, cropH)+0.5), anchor)
 | |
| 	} else {
 | |
| 		cropW := float64(srcH) * float64(dstW) / float64(dstH)
 | |
| 		tmp = CropAnchor(img, int(math.Max(1, cropW)+0.5), srcH, anchor)
 | |
| 	}
 | |
| 
 | |
| 	return Resize(tmp, dstW, dstH, filter)
 | |
| }
 | |
| 
 | |
| // resizeAndCrop resizes the image to the smallest possible size that will cover the specified dimensions,
 | |
| // crops the resized image to the specified dimensions using the given anchor point and returns
 | |
| // the transformed image.
 | |
| func resizeAndCrop(img image.Image, width, height int, anchor Anchor, filter ResampleFilter) *image.NRGBA {
 | |
| 	dstW, dstH := width, height
 | |
| 
 | |
| 	srcBounds := img.Bounds()
 | |
| 	srcW := srcBounds.Dx()
 | |
| 	srcH := srcBounds.Dy()
 | |
| 	srcAspectRatio := float64(srcW) / float64(srcH)
 | |
| 	dstAspectRatio := float64(dstW) / float64(dstH)
 | |
| 
 | |
| 	var tmp *image.NRGBA
 | |
| 	if srcAspectRatio < dstAspectRatio {
 | |
| 		tmp = Resize(img, dstW, 0, filter)
 | |
| 	} else {
 | |
| 		tmp = Resize(img, 0, dstH, filter)
 | |
| 	}
 | |
| 
 | |
| 	return CropAnchor(tmp, dstW, dstH, anchor)
 | |
| }
 | |
| 
 | |
| // Thumbnail scales the image up or down using the specified resample filter, crops it
 | |
| // to the specified width and hight and returns the transformed image.
 | |
| //
 | |
| // Example:
 | |
| //
 | |
| //	dstImage := imaging.Thumbnail(srcImage, 100, 100, imaging.Lanczos)
 | |
| //
 | |
| func Thumbnail(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
 | |
| 	return Fill(img, width, height, Center, filter)
 | |
| }
 | |
| 
 | |
| // ResampleFilter specifies a resampling filter to be used for image resizing.
 | |
| //
 | |
| //	General filter recommendations:
 | |
| //
 | |
| //	- Lanczos
 | |
| //		A high-quality resampling filter for photographic images yielding sharp results.
 | |
| //
 | |
| //	- CatmullRom
 | |
| //		A sharp cubic filter that is faster than Lanczos filter while providing similar results.
 | |
| //
 | |
| //	- MitchellNetravali
 | |
| //		A cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
 | |
| //
 | |
| //	- Linear
 | |
| //		Bilinear resampling filter, produces a smooth output. Faster than cubic filters.
 | |
| //
 | |
| //	- Box
 | |
| //		Simple and fast averaging filter appropriate for downscaling.
 | |
| //		When upscaling it's similar to NearestNeighbor.
 | |
| //
 | |
| //	- NearestNeighbor
 | |
| //		Fastest resampling filter, no antialiasing.
 | |
| //
 | |
| type ResampleFilter struct {
 | |
| 	Support float64
 | |
| 	Kernel  func(float64) float64
 | |
| }
 | |
| 
 | |
| // NearestNeighbor is a nearest-neighbor filter (no anti-aliasing).
 | |
| var NearestNeighbor ResampleFilter
 | |
| 
 | |
| // Box filter (averaging pixels).
 | |
| var Box ResampleFilter
 | |
| 
 | |
| // Linear filter.
 | |
| var Linear ResampleFilter
 | |
| 
 | |
| // Hermite cubic spline filter (BC-spline; B=0; C=0).
 | |
| var Hermite ResampleFilter
 | |
| 
 | |
| // MitchellNetravali is Mitchell-Netravali cubic filter (BC-spline; B=1/3; C=1/3).
 | |
| var MitchellNetravali ResampleFilter
 | |
| 
 | |
| // CatmullRom is a Catmull-Rom - sharp cubic filter (BC-spline; B=0; C=0.5).
 | |
| var CatmullRom ResampleFilter
 | |
| 
 | |
| // BSpline is a smooth cubic filter (BC-spline; B=1; C=0).
 | |
| var BSpline ResampleFilter
 | |
| 
 | |
| // Gaussian is a Gaussian blurring filter.
 | |
| var Gaussian ResampleFilter
 | |
| 
 | |
| // Bartlett is a Bartlett-windowed sinc filter (3 lobes).
 | |
| var Bartlett ResampleFilter
 | |
| 
 | |
| // Lanczos filter (3 lobes).
 | |
| var Lanczos ResampleFilter
 | |
| 
 | |
| // Hann is a Hann-windowed sinc filter (3 lobes).
 | |
| var Hann ResampleFilter
 | |
| 
 | |
| // Hamming is a Hamming-windowed sinc filter (3 lobes).
 | |
| var Hamming ResampleFilter
 | |
| 
 | |
| // Blackman is a Blackman-windowed sinc filter (3 lobes).
 | |
| var Blackman ResampleFilter
 | |
| 
 | |
| // Welch is a Welch-windowed sinc filter (parabolic window, 3 lobes).
 | |
| var Welch ResampleFilter
 | |
| 
 | |
| // Cosine is a Cosine-windowed sinc filter (3 lobes).
 | |
| var Cosine ResampleFilter
 | |
| 
 | |
| func bcspline(x, b, c float64) float64 {
 | |
| 	var y float64
 | |
| 	x = math.Abs(x)
 | |
| 	if x < 1.0 {
 | |
| 		y = ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
 | |
| 	} else if x < 2.0 {
 | |
| 		y = ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
 | |
| 	}
 | |
| 	return y
 | |
| }
 | |
| 
 | |
| func sinc(x float64) float64 {
 | |
| 	if x == 0 {
 | |
| 		return 1
 | |
| 	}
 | |
| 	return math.Sin(math.Pi*x) / (math.Pi * x)
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	NearestNeighbor = ResampleFilter{
 | |
| 		Support: 0.0, // special case - not applying the filter
 | |
| 	}
 | |
| 
 | |
| 	Box = ResampleFilter{
 | |
| 		Support: 0.5,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x <= 0.5 {
 | |
| 				return 1.0
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Linear = ResampleFilter{
 | |
| 		Support: 1.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 1.0 {
 | |
| 				return 1.0 - x
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Hermite = ResampleFilter{
 | |
| 		Support: 1.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 1.0 {
 | |
| 				return bcspline(x, 0.0, 0.0)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	MitchellNetravali = ResampleFilter{
 | |
| 		Support: 2.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 2.0 {
 | |
| 				return bcspline(x, 1.0/3.0, 1.0/3.0)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	CatmullRom = ResampleFilter{
 | |
| 		Support: 2.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 2.0 {
 | |
| 				return bcspline(x, 0.0, 0.5)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	BSpline = ResampleFilter{
 | |
| 		Support: 2.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 2.0 {
 | |
| 				return bcspline(x, 1.0, 0.0)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Gaussian = ResampleFilter{
 | |
| 		Support: 2.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 2.0 {
 | |
| 				return math.Exp(-2 * x * x)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Bartlett = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * (3.0 - x) / 3.0
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Lanczos = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * sinc(x/3.0)
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Hann = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * (0.5 + 0.5*math.Cos(math.Pi*x/3.0))
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Hamming = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * (0.54 + 0.46*math.Cos(math.Pi*x/3.0))
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Blackman = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * (0.42 - 0.5*math.Cos(math.Pi*x/3.0+math.Pi) + 0.08*math.Cos(2.0*math.Pi*x/3.0))
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Welch = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * (1.0 - (x * x / 9.0))
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	Cosine = ResampleFilter{
 | |
| 		Support: 3.0,
 | |
| 		Kernel: func(x float64) float64 {
 | |
| 			x = math.Abs(x)
 | |
| 			if x < 3.0 {
 | |
| 				return sinc(x) * math.Cos((math.Pi/2.0)*(x/3.0))
 | |
| 			}
 | |
| 			return 0
 | |
| 		},
 | |
| 	}
 | |
| }
 |