gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

effects.go (3773B)


      1 package imaging
      2 
      3 import (
      4 	"image"
      5 	"math"
      6 )
      7 
      8 func gaussianBlurKernel(x, sigma float64) float64 {
      9 	return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi))
     10 }
     11 
     12 // Blur produces a blurred version of the image using a Gaussian function.
     13 // Sigma parameter must be positive and indicates how much the image will be blurred.
     14 //
     15 // Example:
     16 //
     17 //	dstImage := imaging.Blur(srcImage, 3.5)
     18 //
     19 func Blur(img image.Image, sigma float64) *image.NRGBA {
     20 	if sigma <= 0 {
     21 		return Clone(img)
     22 	}
     23 
     24 	radius := int(math.Ceil(sigma * 3.0))
     25 	kernel := make([]float64, radius+1)
     26 
     27 	for i := 0; i <= radius; i++ {
     28 		kernel[i] = gaussianBlurKernel(float64(i), sigma)
     29 	}
     30 
     31 	return blurVertical(blurHorizontal(img, kernel), kernel)
     32 }
     33 
     34 func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA {
     35 	src := newScanner(img)
     36 	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
     37 	radius := len(kernel) - 1
     38 
     39 	parallel(0, src.h, func(ys <-chan int) {
     40 		scanLine := make([]uint8, src.w*4)
     41 		scanLineF := make([]float64, len(scanLine))
     42 		for y := range ys {
     43 			src.scan(0, y, src.w, y+1, scanLine)
     44 			for i, v := range scanLine {
     45 				scanLineF[i] = float64(v)
     46 			}
     47 			for x := 0; x < src.w; x++ {
     48 				min := x - radius
     49 				if min < 0 {
     50 					min = 0
     51 				}
     52 				max := x + radius
     53 				if max > src.w-1 {
     54 					max = src.w - 1
     55 				}
     56 				var r, g, b, a, wsum float64
     57 				for ix := min; ix <= max; ix++ {
     58 					i := ix * 4
     59 					weight := kernel[absint(x-ix)]
     60 					wsum += weight
     61 					s := scanLineF[i : i+4 : i+4]
     62 					wa := s[3] * weight
     63 					r += s[0] * wa
     64 					g += s[1] * wa
     65 					b += s[2] * wa
     66 					a += wa
     67 				}
     68 				if a != 0 {
     69 					aInv := 1 / a
     70 					j := y*dst.Stride + x*4
     71 					d := dst.Pix[j : j+4 : j+4]
     72 					d[0] = clamp(r * aInv)
     73 					d[1] = clamp(g * aInv)
     74 					d[2] = clamp(b * aInv)
     75 					d[3] = clamp(a / wsum)
     76 				}
     77 			}
     78 		}
     79 	})
     80 
     81 	return dst
     82 }
     83 
     84 func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
     85 	src := newScanner(img)
     86 	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
     87 	radius := len(kernel) - 1
     88 
     89 	parallel(0, src.w, func(xs <-chan int) {
     90 		scanLine := make([]uint8, src.h*4)
     91 		scanLineF := make([]float64, len(scanLine))
     92 		for x := range xs {
     93 			src.scan(x, 0, x+1, src.h, scanLine)
     94 			for i, v := range scanLine {
     95 				scanLineF[i] = float64(v)
     96 			}
     97 			for y := 0; y < src.h; y++ {
     98 				min := y - radius
     99 				if min < 0 {
    100 					min = 0
    101 				}
    102 				max := y + radius
    103 				if max > src.h-1 {
    104 					max = src.h - 1
    105 				}
    106 				var r, g, b, a, wsum float64
    107 				for iy := min; iy <= max; iy++ {
    108 					i := iy * 4
    109 					weight := kernel[absint(y-iy)]
    110 					wsum += weight
    111 					s := scanLineF[i : i+4 : i+4]
    112 					wa := s[3] * weight
    113 					r += s[0] * wa
    114 					g += s[1] * wa
    115 					b += s[2] * wa
    116 					a += wa
    117 				}
    118 				if a != 0 {
    119 					aInv := 1 / a
    120 					j := y*dst.Stride + x*4
    121 					d := dst.Pix[j : j+4 : j+4]
    122 					d[0] = clamp(r * aInv)
    123 					d[1] = clamp(g * aInv)
    124 					d[2] = clamp(b * aInv)
    125 					d[3] = clamp(a / wsum)
    126 				}
    127 			}
    128 		}
    129 	})
    130 
    131 	return dst
    132 }
    133 
    134 // Sharpen produces a sharpened version of the image.
    135 // Sigma parameter must be positive and indicates how much the image will be sharpened.
    136 //
    137 // Example:
    138 //
    139 //	dstImage := imaging.Sharpen(srcImage, 3.5)
    140 //
    141 func Sharpen(img image.Image, sigma float64) *image.NRGBA {
    142 	if sigma <= 0 {
    143 		return Clone(img)
    144 	}
    145 
    146 	src := newScanner(img)
    147 	dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
    148 	blurred := Blur(img, sigma)
    149 
    150 	parallel(0, src.h, func(ys <-chan int) {
    151 		scanLine := make([]uint8, src.w*4)
    152 		for y := range ys {
    153 			src.scan(0, y, src.w, y+1, scanLine)
    154 			j := y * dst.Stride
    155 			for i := 0; i < src.w*4; i++ {
    156 				val := int(scanLine[i])<<1 - int(blurred.Pix[j])
    157 				if val < 0 {
    158 					val = 0
    159 				} else if val > 0xff {
    160 					val = 0xff
    161 				}
    162 				dst.Pix[j] = uint8(val)
    163 				j++
    164 			}
    165 		}
    166 	})
    167 
    168 	return dst
    169 }