diff options
Diffstat (limited to 'vendor/github.com/disintegration/imaging/effects.go')
-rw-r--r-- | vendor/github.com/disintegration/imaging/effects.go | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/vendor/github.com/disintegration/imaging/effects.go b/vendor/github.com/disintegration/imaging/effects.go new file mode 100644 index 00000000..47316b70 --- /dev/null +++ b/vendor/github.com/disintegration/imaging/effects.go @@ -0,0 +1,169 @@ +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 +} |