diff options
Diffstat (limited to 'vendor/github.com/disintegration/imaging/adjust.go')
-rw-r--r-- | vendor/github.com/disintegration/imaging/adjust.go | 256 |
1 files changed, 139 insertions, 117 deletions
diff --git a/vendor/github.com/disintegration/imaging/adjust.go b/vendor/github.com/disintegration/imaging/adjust.go index daee893cc..fb3a9ce3c 100644 --- a/vendor/github.com/disintegration/imaging/adjust.go +++ b/vendor/github.com/disintegration/imaging/adjust.go @@ -6,50 +6,95 @@ import ( "math" ) -// AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image. +// Grayscale produces a grayscale version of the image. +func Grayscale(img image.Image) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + r := dst.Pix[i+0] + g := dst.Pix[i+1] + b := dst.Pix[i+2] + f := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b) + y := uint8(f + 0.5) + dst.Pix[i+0] = y + dst.Pix[i+1] = y + dst.Pix[i+2] = y + i += 4 + } + } + }) + return dst +} + +// Invert produces an inverted (negated) version of the image. +func Invert(img image.Image) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + dst.Pix[i+0] = 255 - dst.Pix[i+0] + dst.Pix[i+1] = 255 - dst.Pix[i+1] + dst.Pix[i+2] = 255 - dst.Pix[i+2] + i += 4 + } + } + }) + return dst +} + +// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image. +// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. +// The percentage = -100 gives solid gray image. // -// Example: +// Examples: // -// dstImage = imaging.AdjustFunc( -// srcImage, -// func(c color.NRGBA) color.NRGBA { -// // shift the red channel by 16 -// r := int(c.R) + 16 -// if r > 255 { -// r = 255 -// } -// return color.NRGBA{uint8(r), c.G, c.B, c.A} -// } -// ) +// dstImage = imaging.AdjustContrast(srcImage, -10) // decrease image contrast by 10% +// dstImage = imaging.AdjustContrast(srcImage, 20) // increase image contrast by 20% // -func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGBA { - src := toNRGBA(img) - width := src.Bounds().Max.X - height := src.Bounds().Max.Y - dst := image.NewNRGBA(image.Rect(0, 0, width, height)) - - parallel(height, func(partStart, partEnd int) { - for y := partStart; y < partEnd; y++ { - for x := 0; x < width; x++ { - i := y*src.Stride + x*4 - j := y*dst.Stride + x*4 - - r := src.Pix[i+0] - g := src.Pix[i+1] - b := src.Pix[i+2] - a := src.Pix[i+3] - - c := fn(color.NRGBA{r, g, b, a}) +func AdjustContrast(img image.Image, percentage float64) *image.NRGBA { + percentage = math.Min(math.Max(percentage, -100.0), 100.0) + lut := make([]uint8, 256) - dst.Pix[j+0] = c.R - dst.Pix[j+1] = c.G - dst.Pix[j+2] = c.B - dst.Pix[j+3] = c.A - } + v := (100.0 + percentage) / 100.0 + for i := 0; i < 256; i++ { + if 0 <= v && v <= 1 { + lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0) + } else if 1 < v && v < 2 { + lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0) + } else { + lut[i] = uint8(float64(i)/255.0+0.5) * 255 } - }) + } - return dst + return adjustLUT(img, lut) +} + +// AdjustBrightness changes the brightness of the image using the percentage parameter and returns the adjusted image. +// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. +// The percentage = -100 gives solid black image. The percentage = 100 gives solid white image. +// +// Examples: +// +// dstImage = imaging.AdjustBrightness(srcImage, -15) // decrease image brightness by 15% +// dstImage = imaging.AdjustBrightness(srcImage, 10) // increase image brightness by 10% +// +func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA { + percentage = math.Min(math.Max(percentage, -100.0), 100.0) + lut := make([]uint8, 256) + + shift := 255.0 * percentage / 100.0 + for i := 0; i < 256; i++ { + lut[i] = clamp(float64(i) + shift) + } + + return adjustLUT(img, lut) } // AdjustGamma performs a gamma correction on the image and returns the adjusted image. @@ -68,15 +113,7 @@ func AdjustGamma(img image.Image, gamma float64) *image.NRGBA { lut[i] = clamp(math.Pow(float64(i)/255.0, e) * 255.0) } - fn := func(c color.NRGBA) color.NRGBA { - return color.NRGBA{lut[c.R], lut[c.G], lut[c.B], c.A} - } - - return AdjustFunc(img, fn) -} - -func sigmoid(a, b, x float64) float64 { - return 1 / (1 + math.Exp(b*(a-x))) + return adjustLUT(img, lut) } // AdjustSigmoid changes the contrast of the image using a sigmoidal function and returns the adjusted image. @@ -118,83 +155,68 @@ func AdjustSigmoid(img image.Image, midpoint, factor float64) *image.NRGBA { } } - fn := func(c color.NRGBA) color.NRGBA { - return color.NRGBA{lut[c.R], lut[c.G], lut[c.B], c.A} - } - - return AdjustFunc(img, fn) + return adjustLUT(img, lut) } -// AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image. -// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. -// The percentage = -100 gives solid grey image. -// -// Examples: -// -// dstImage = imaging.AdjustContrast(srcImage, -10) // decrease image contrast by 10% -// dstImage = imaging.AdjustContrast(srcImage, 20) // increase image contrast by 20% -// -func AdjustContrast(img image.Image, percentage float64) *image.NRGBA { - percentage = math.Min(math.Max(percentage, -100.0), 100.0) - lut := make([]uint8, 256) +func sigmoid(a, b, x float64) float64 { + return 1 / (1 + math.Exp(b*(a-x))) +} - v := (100.0 + percentage) / 100.0 - for i := 0; i < 256; i++ { - if 0 <= v && v <= 1 { - lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0) - } else if 1 < v && v < 2 { - lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0) - } else { - lut[i] = uint8(float64(i)/255.0+0.5) * 255 +// adjustLUT applies the given lookup table to the colors of the image. +func adjustLUT(img image.Image, lut []uint8) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + dst.Pix[i+0] = lut[dst.Pix[i+0]] + dst.Pix[i+1] = lut[dst.Pix[i+1]] + dst.Pix[i+2] = lut[dst.Pix[i+2]] + i += 4 + } } - } - - fn := func(c color.NRGBA) color.NRGBA { - return color.NRGBA{lut[c.R], lut[c.G], lut[c.B], c.A} - } - - return AdjustFunc(img, fn) + }) + return dst } -// AdjustBrightness changes the brightness of the image using the percentage parameter and returns the adjusted image. -// The percentage must be in range (-100, 100). The percentage = 0 gives the original image. -// The percentage = -100 gives solid black image. The percentage = 100 gives solid white image. +// AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image. // -// Examples: +// Example: // -// dstImage = imaging.AdjustBrightness(srcImage, -15) // decrease image brightness by 15% -// dstImage = imaging.AdjustBrightness(srcImage, 10) // increase image brightness by 10% +// dstImage = imaging.AdjustFunc( +// srcImage, +// func(c color.NRGBA) color.NRGBA { +// // shift the red channel by 16 +// r := int(c.R) + 16 +// if r > 255 { +// r = 255 +// } +// return color.NRGBA{uint8(r), c.G, c.B, c.A} +// } +// ) // -func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA { - percentage = math.Min(math.Max(percentage, -100.0), 100.0) - lut := make([]uint8, 256) - - shift := 255.0 * percentage / 100.0 - for i := 0; i < 256; i++ { - lut[i] = clamp(float64(i) + shift) - } - - fn := func(c color.NRGBA) color.NRGBA { - return color.NRGBA{lut[c.R], lut[c.G], lut[c.B], c.A} - } - - return AdjustFunc(img, fn) -} - -// Grayscale produces grayscale version of the image. -func Grayscale(img image.Image) *image.NRGBA { - fn := func(c color.NRGBA) color.NRGBA { - f := 0.299*float64(c.R) + 0.587*float64(c.G) + 0.114*float64(c.B) - y := uint8(f + 0.5) - return color.NRGBA{y, y, y, c.A} - } - return AdjustFunc(img, fn) -} - -// Invert produces inverted (negated) version of the image. -func Invert(img image.Image) *image.NRGBA { - fn := func(c color.NRGBA) color.NRGBA { - return color.NRGBA{255 - c.R, 255 - c.G, 255 - c.B, c.A} - } - return AdjustFunc(img, fn) +func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGBA { + src := newScanner(img) + dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) + parallel(0, src.h, func(ys <-chan int) { + for y := range ys { + i := y * dst.Stride + src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) + for x := 0; x < src.w; x++ { + r := dst.Pix[i+0] + g := dst.Pix[i+1] + b := dst.Pix[i+2] + a := dst.Pix[i+3] + c := fn(color.NRGBA{r, g, b, a}) + dst.Pix[i+0] = c.R + dst.Pix[i+1] = c.G + dst.Pix[i+2] = c.B + dst.Pix[i+3] = c.A + i += 4 + } + } + }) + return dst } |