79 lines
1.9 KiB
Go
79 lines
1.9 KiB
Go
|
package goeffects
|
||
|
|
||
|
// Package copied from https://github.com/markdaws/go-effects
|
||
|
|
||
|
import "image"
|
||
|
import "runtime"
|
||
|
|
||
|
// GSAlgo the type of algorithm to use when converting an image to it's grayscale equivalent
|
||
|
type GSAlgo int
|
||
|
|
||
|
const (
|
||
|
// GSLIGHTNESS is the average of the min and max r,g,b value
|
||
|
GSLIGHTNESS GSAlgo = iota
|
||
|
|
||
|
// GSAVERAGE is the average of the r,g,b values of each pixel
|
||
|
GSAVERAGE
|
||
|
|
||
|
// GSLUMINOSITY used a weighting for r,g,b based on how the human eye perceives colors
|
||
|
GSLUMINOSITY
|
||
|
)
|
||
|
|
||
|
type grayscale struct {
|
||
|
algo GSAlgo
|
||
|
}
|
||
|
|
||
|
func (gs *grayscale) Apply(img *Image, numRoutines int) (*Image, error) {
|
||
|
if numRoutines == 0 {
|
||
|
numRoutines = runtime.GOMAXPROCS(0)
|
||
|
}
|
||
|
|
||
|
pf := func(ri, x, y, offset, inStride int, inPix, outPix []uint8) {
|
||
|
var r, g, b uint8 = inPix[offset], inPix[offset+1], inPix[offset+2]
|
||
|
switch gs.algo {
|
||
|
case GSLIGHTNESS:
|
||
|
maximum := float64(max(max(r, g), b))
|
||
|
minimum := float64(max(min(r, g), b))
|
||
|
r = uint8(maximum + minimum/2)
|
||
|
g = r
|
||
|
b = r
|
||
|
case GSAVERAGE:
|
||
|
r = (r + g + b) / 3
|
||
|
g = r
|
||
|
b = r
|
||
|
case GSLUMINOSITY:
|
||
|
r = uint8(0.21*float64(r) + 0.72*float64(g) + 0.07*float64(b))
|
||
|
g = r
|
||
|
b = r
|
||
|
}
|
||
|
outPix[offset] = r
|
||
|
outPix[offset+1] = g
|
||
|
outPix[offset+2] = b
|
||
|
outPix[offset+3] = 255
|
||
|
}
|
||
|
|
||
|
out := &Image{
|
||
|
img: image.NewRGBA(image.Rectangle{
|
||
|
Min: image.Point{X: 0, Y: 0},
|
||
|
Max: image.Point{X: img.Width, Y: img.Height},
|
||
|
}),
|
||
|
Width: img.Width,
|
||
|
Height: img.Height,
|
||
|
Bounds: Rect{
|
||
|
X: img.Bounds.X,
|
||
|
Y: img.Bounds.Y,
|
||
|
Width: img.Bounds.Width,
|
||
|
Height: img.Bounds.Height,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
runParallel(numRoutines, img, out.Bounds, out, pf, 0)
|
||
|
return out, nil
|
||
|
}
|
||
|
|
||
|
// NewGrayscale renders the input image as a grayscale image. numRoutines specifies how many
|
||
|
// goroutines should be used to process the image in parallel, use 0 to let the library decide
|
||
|
func NewGrayscale(algo GSAlgo) Effect {
|
||
|
return &grayscale{algo: algo}
|
||
|
}
|