Initial QSfera import
This commit is contained in:
+166
@@ -0,0 +1,166 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"math"
|
||||
|
||||
"github.com/kovidgoyal/imaging/nrgba"
|
||||
)
|
||||
|
||||
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 {
|
||||
w, h := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
src := nrgba.NewNRGBAScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||
radius := len(kernel) - 1
|
||||
|
||||
if err := run_in_parallel_over_range(0, func(start, limit int) {
|
||||
scanLine := make([]uint8, w*4)
|
||||
scanLineF := make([]float64, len(scanLine))
|
||||
for y := start; y < limit; y++ {
|
||||
src.Scan(0, y, w, y+1, scanLine)
|
||||
for i, v := range scanLine {
|
||||
scanLineF[i] = float64(v)
|
||||
}
|
||||
for x := range w {
|
||||
minv := max(0, x-radius)
|
||||
maxv := min(x+radius, w-1)
|
||||
var r, g, b, a, wsum float64
|
||||
for ix := minv; ix <= maxv; 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, h); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func blurVertical(img image.Image, kernel []float64) *image.NRGBA {
|
||||
w, h := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
src := nrgba.NewNRGBAScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||
radius := len(kernel) - 1
|
||||
|
||||
if err := run_in_parallel_over_range(0, func(start, limit int) {
|
||||
scanLine := make([]uint8, h*4)
|
||||
scanLineF := make([]float64, len(scanLine))
|
||||
for x := start; x < limit; x++ {
|
||||
src.Scan(x, 0, x+1, h, scanLine)
|
||||
for i, v := range scanLine {
|
||||
scanLineF[i] = float64(v)
|
||||
}
|
||||
for y := range h {
|
||||
minv := max(0, y-radius)
|
||||
maxv := min(y+radius, h-1)
|
||||
var r, g, b, a, wsum float64
|
||||
for iy := minv; iy <= maxv; 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, w); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
w, h := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
src := nrgba.NewNRGBAScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, w, h))
|
||||
blurred := Blur(img, sigma)
|
||||
|
||||
if err := run_in_parallel_over_range(0, func(start, limit int) {
|
||||
scanLine := make([]uint8, w*4)
|
||||
for y := start; y < limit; y++ {
|
||||
src.Scan(0, y, w, y+1, scanLine)
|
||||
j := y * dst.Stride
|
||||
for i := 0; i < 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++
|
||||
}
|
||||
}
|
||||
}, 0, h); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
Reference in New Issue
Block a user