mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 23:22:25 -06:00 
			
		
		
		
	* use disintegration/imaging instead of nfnt/resize * update tests * use disintegration lib for thumbing (if necessary)
		
			
				
	
	
		
			169 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package imaging
 | 
						|
 | 
						|
import (
 | 
						|
	"image"
 | 
						|
	"math"
 | 
						|
)
 | 
						|
 | 
						|
func gaussianBlurKernel(x, sigma float64) float64 {
 | 
						|
	return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi))
 | 
						|
}
 | 
						|
 | 
						|
// Blur produces a blurred version of the image using a Gaussian function.
 | 
						|
// Sigma parameter must be positive and indicates how much the image will be blurred.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//	dstImage := imaging.Blur(srcImage, 3.5)
 | 
						|
//
 | 
						|
func Blur(img image.Image, sigma float64) *image.NRGBA {
 | 
						|
	if sigma <= 0 {
 | 
						|
		return Clone(img)
 | 
						|
	}
 | 
						|
 | 
						|
	radius := int(math.Ceil(sigma * 3.0))
 | 
						|
	kernel := make([]float64, radius+1)
 | 
						|
 | 
						|
	for i := 0; i <= radius; i++ {
 | 
						|
		kernel[i] = gaussianBlurKernel(float64(i), sigma)
 | 
						|
	}
 | 
						|
 | 
						|
	return blurVertical(blurHorizontal(img, kernel), kernel)
 | 
						|
}
 | 
						|
 | 
						|
func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
 | 
						|
	src := newScanner(img)
 | 
						|
	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
						|
	radius := len(kernel) - 1
 | 
						|
 | 
						|
	parallel(0, src.h, func(ys <-chan int) {
 | 
						|
		scanLine := make([]uint8, src.w*4)
 | 
						|
		scanLineF := make([]float64, len(scanLine))
 | 
						|
		for y := range ys {
 | 
						|
			src.scan(0, y, src.w, y+1, scanLine)
 | 
						|
			for i, v := range scanLine {
 | 
						|
				scanLineF[i] = float64(v)
 | 
						|
			}
 | 
						|
			for x := 0; x < src.w; x++ {
 | 
						|
				min := x - radius
 | 
						|
				if min < 0 {
 | 
						|
					min = 0
 | 
						|
				}
 | 
						|
				max := x + radius
 | 
						|
				if max > src.w-1 {
 | 
						|
					max = src.w - 1
 | 
						|
				}
 | 
						|
				var r, g, b, a, wsum float64
 | 
						|
				for ix := min; ix <= max; ix++ {
 | 
						|
					i := ix * 4
 | 
						|
					weight := kernel[absint(x-ix)]
 | 
						|
					wsum += weight
 | 
						|
					s := scanLineF[i : i+4 : i+4]
 | 
						|
					wa := s[3] * weight
 | 
						|
					r += s[0] * wa
 | 
						|
					g += s[1] * wa
 | 
						|
					b += s[2] * wa
 | 
						|
					a += wa
 | 
						|
				}
 | 
						|
				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 / wsum)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	})
 | 
						|
 | 
						|
	return dst
 | 
						|
}
 | 
						|
 | 
						|
func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
 | 
						|
	src := newScanner(img)
 | 
						|
	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
						|
	radius := len(kernel) - 1
 | 
						|
 | 
						|
	parallel(0, src.w, func(xs <-chan int) {
 | 
						|
		scanLine := make([]uint8, src.h*4)
 | 
						|
		scanLineF := make([]float64, len(scanLine))
 | 
						|
		for x := range xs {
 | 
						|
			src.scan(x, 0, x+1, src.h, scanLine)
 | 
						|
			for i, v := range scanLine {
 | 
						|
				scanLineF[i] = float64(v)
 | 
						|
			}
 | 
						|
			for y := 0; y < src.h; y++ {
 | 
						|
				min := y - radius
 | 
						|
				if min < 0 {
 | 
						|
					min = 0
 | 
						|
				}
 | 
						|
				max := y + radius
 | 
						|
				if max > src.h-1 {
 | 
						|
					max = src.h - 1
 | 
						|
				}
 | 
						|
				var r, g, b, a, wsum float64
 | 
						|
				for iy := min; iy <= max; iy++ {
 | 
						|
					i := iy * 4
 | 
						|
					weight := kernel[absint(y-iy)]
 | 
						|
					wsum += weight
 | 
						|
					s := scanLineF[i : i+4 : i+4]
 | 
						|
					wa := s[3] * weight
 | 
						|
					r += s[0] * wa
 | 
						|
					g += s[1] * wa
 | 
						|
					b += s[2] * wa
 | 
						|
					a += wa
 | 
						|
				}
 | 
						|
				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 / wsum)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	})
 | 
						|
 | 
						|
	return dst
 | 
						|
}
 | 
						|
 | 
						|
// Sharpen produces a sharpened version of the image.
 | 
						|
// Sigma parameter must be positive and indicates how much the image will be sharpened.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//	dstImage := imaging.Sharpen(srcImage, 3.5)
 | 
						|
//
 | 
						|
func Sharpen(img image.Image, sigma float64) *image.NRGBA {
 | 
						|
	if sigma <= 0 {
 | 
						|
		return Clone(img)
 | 
						|
	}
 | 
						|
 | 
						|
	src := newScanner(img)
 | 
						|
	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
 | 
						|
	blurred := Blur(img, sigma)
 | 
						|
 | 
						|
	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)
 | 
						|
			j := y * dst.Stride
 | 
						|
			for i := 0; i < src.w*4; i++ {
 | 
						|
				val := int(scanLine[i])<<1 - int(blurred.Pix[j])
 | 
						|
				if val < 0 {
 | 
						|
					val = 0
 | 
						|
				} else if val > 0xff {
 | 
						|
					val = 0xff
 | 
						|
				}
 | 
						|
				dst.Pix[j] = uint8(val)
 | 
						|
				j++
 | 
						|
			}
 | 
						|
		}
 | 
						|
	})
 | 
						|
 | 
						|
	return dst
 | 
						|
}
 |