mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 06:52:26 -05:00 
			
		
		
		
	* use disintegration/imaging instead of nfnt/resize * update tests * use disintegration lib for thumbing (if necessary)
		
			
				
	
	
		
			148 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			148 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package imaging
 | |
| 
 | |
| import (
 | |
| 	"image"
 | |
| )
 | |
| 
 | |
| // ConvolveOptions are convolution parameters.
 | |
| type ConvolveOptions struct {
 | |
| 	// If Normalize is true the kernel is normalized before convolution.
 | |
| 	Normalize bool
 | |
| 
 | |
| 	// If Abs is true the absolute value of each color channel is taken after convolution.
 | |
| 	Abs bool
 | |
| 
 | |
| 	// Bias is added to each color channel value after convolution.
 | |
| 	Bias int
 | |
| }
 | |
| 
 | |
| // Convolve3x3 convolves the image with the specified 3x3 convolution kernel.
 | |
| // Default parameters are used if a nil *ConvolveOptions is passed.
 | |
| func Convolve3x3(img image.Image, kernel [9]float64, options *ConvolveOptions) *image.NRGBA {
 | |
| 	return convolve(img, kernel[:], options)
 | |
| }
 | |
| 
 | |
| // Convolve5x5 convolves the image with the specified 5x5 convolution kernel.
 | |
| // Default parameters are used if a nil *ConvolveOptions is passed.
 | |
| func Convolve5x5(img image.Image, kernel [25]float64, options *ConvolveOptions) *image.NRGBA {
 | |
| 	return convolve(img, kernel[:], options)
 | |
| }
 | |
| 
 | |
| func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *image.NRGBA {
 | |
| 	src := toNRGBA(img)
 | |
| 	w := src.Bounds().Max.X
 | |
| 	h := src.Bounds().Max.Y
 | |
| 	dst := image.NewNRGBA(image.Rect(0, 0, w, h))
 | |
| 
 | |
| 	if w < 1 || h < 1 {
 | |
| 		return dst
 | |
| 	}
 | |
| 
 | |
| 	if options == nil {
 | |
| 		options = &ConvolveOptions{}
 | |
| 	}
 | |
| 
 | |
| 	if options.Normalize {
 | |
| 		normalizeKernel(kernel)
 | |
| 	}
 | |
| 
 | |
| 	type coef struct {
 | |
| 		x, y int
 | |
| 		k    float64
 | |
| 	}
 | |
| 	var coefs []coef
 | |
| 	var m int
 | |
| 
 | |
| 	switch len(kernel) {
 | |
| 	case 9:
 | |
| 		m = 1
 | |
| 	case 25:
 | |
| 		m = 2
 | |
| 	}
 | |
| 
 | |
| 	i := 0
 | |
| 	for y := -m; y <= m; y++ {
 | |
| 		for x := -m; x <= m; x++ {
 | |
| 			if kernel[i] != 0 {
 | |
| 				coefs = append(coefs, coef{x: x, y: y, k: kernel[i]})
 | |
| 			}
 | |
| 			i++
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	parallel(0, h, func(ys <-chan int) {
 | |
| 		for y := range ys {
 | |
| 			for x := 0; x < w; x++ {
 | |
| 				var r, g, b float64
 | |
| 				for _, c := range coefs {
 | |
| 					ix := x + c.x
 | |
| 					if ix < 0 {
 | |
| 						ix = 0
 | |
| 					} else if ix >= w {
 | |
| 						ix = w - 1
 | |
| 					}
 | |
| 
 | |
| 					iy := y + c.y
 | |
| 					if iy < 0 {
 | |
| 						iy = 0
 | |
| 					} else if iy >= h {
 | |
| 						iy = h - 1
 | |
| 					}
 | |
| 
 | |
| 					off := iy*src.Stride + ix*4
 | |
| 					s := src.Pix[off : off+3 : off+3]
 | |
| 					r += float64(s[0]) * c.k
 | |
| 					g += float64(s[1]) * c.k
 | |
| 					b += float64(s[2]) * c.k
 | |
| 				}
 | |
| 
 | |
| 				if options.Abs {
 | |
| 					if r < 0 {
 | |
| 						r = -r
 | |
| 					}
 | |
| 					if g < 0 {
 | |
| 						g = -g
 | |
| 					}
 | |
| 					if b < 0 {
 | |
| 						b = -b
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if options.Bias != 0 {
 | |
| 					r += float64(options.Bias)
 | |
| 					g += float64(options.Bias)
 | |
| 					b += float64(options.Bias)
 | |
| 				}
 | |
| 
 | |
| 				srcOff := y*src.Stride + x*4
 | |
| 				dstOff := y*dst.Stride + x*4
 | |
| 				d := dst.Pix[dstOff : dstOff+4 : dstOff+4]
 | |
| 				d[0] = clamp(r)
 | |
| 				d[1] = clamp(g)
 | |
| 				d[2] = clamp(b)
 | |
| 				d[3] = src.Pix[srcOff+3]
 | |
| 			}
 | |
| 		}
 | |
| 	})
 | |
| 
 | |
| 	return dst
 | |
| }
 | |
| 
 | |
| func normalizeKernel(kernel []float64) {
 | |
| 	var sum, sumpos float64
 | |
| 	for i := range kernel {
 | |
| 		sum += kernel[i]
 | |
| 		if kernel[i] > 0 {
 | |
| 			sumpos += kernel[i]
 | |
| 		}
 | |
| 	}
 | |
| 	if sum != 0 {
 | |
| 		for i := range kernel {
 | |
| 			kernel[i] /= sum
 | |
| 		}
 | |
| 	} else if sumpos != 0 {
 | |
| 		for i := range kernel {
 | |
| 			kernel[i] /= sumpos
 | |
| 		}
 | |
| 	}
 | |
| }
 |