Depenancy upgrades and movign to dep. (#8630)
16
vendor/github.com/disintegration/imaging/.travis.yml
сгенерированный
поставляемый
@@ -1,17 +1,13 @@
|
||||
language: go
|
||||
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.7.x"
|
||||
- "1.8.x"
|
||||
- "1.9.x"
|
||||
- "1.10.x"
|
||||
|
||||
before_install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out
|
||||
- go test -v -race -cover
|
||||
- $GOPATH/bin/goveralls -service=travis-ci
|
||||
|
||||
2
vendor/github.com/disintegration/imaging/LICENSE
сгенерированный
поставляемый
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2017 Grigory Dryapak
|
||||
Copyright (c) 2012-2018 Grigory Dryapak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
63
vendor/github.com/disintegration/imaging/README.md
сгенерированный
поставляемый
@@ -2,19 +2,16 @@
|
||||
|
||||
[](https://godoc.org/github.com/disintegration/imaging)
|
||||
[](https://travis-ci.org/disintegration/imaging)
|
||||
[](https://coveralls.io/github/disintegration/imaging?branch=master)
|
||||
[](https://coveralls.io/github/disintegration/imaging?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/disintegration/imaging)
|
||||
|
||||
Package imaging provides basic image manipulation functions (resize, rotate, flip, crop, etc.).
|
||||
This package is based on the standard Go image package and works best along with it.
|
||||
Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
|
||||
|
||||
Image manipulation functions provided by the package take any image type
|
||||
that implements `image.Image` interface as an input, and return a new image of
|
||||
`*image.NRGBA` type (32bit RGBA colors, not premultiplied by alpha).
|
||||
All the image processing functions provided by the package accept any image type that implements `image.Image` interface
|
||||
as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, not premultiplied by alpha).
|
||||
|
||||
## Installation
|
||||
|
||||
Imaging requires Go version 1.2 or greater.
|
||||
|
||||
go get -u github.com/disintegration/imaging
|
||||
|
||||
## Documentation
|
||||
@@ -46,19 +43,19 @@ Imaging supports image resizing using various resampling filters. The most notab
|
||||
- `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor.
|
||||
- `Linear` - Bilinear filter, smooth and reasonably fast.
|
||||
- `MitchellNetravali` - А smooth bicubic filter.
|
||||
- `CatmullRom` - A sharp bicubic filter.
|
||||
- `CatmullRom` - A sharp bicubic filter.
|
||||
- `Gaussian` - Blurring filter that uses gaussian function, useful for noise removal.
|
||||
- `Lanczos` - High-quality resampling filter for photographic images yielding sharp results, but it's slower than cubic filters.
|
||||
- `Lanczos` - High-quality resampling filter for photographic images yielding sharp results, slower than cubic filters.
|
||||
|
||||
The full list of supported filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct.
|
||||
|
||||
**Resampling filters comparison**
|
||||
|
||||
The original image.
|
||||
Original image:
|
||||
|
||||

|
||||

|
||||
|
||||
The same image resized from 512x512px to 128x128px using different resampling filters.
|
||||
The same image resized from 600x400px to 150x100px using different resampling filters.
|
||||
From faster (lower quality) to slower (higher quality):
|
||||
|
||||
Filter | Resize result
|
||||
@@ -79,7 +76,7 @@ Sigma parameter allows to control the strength of the blurring effect.
|
||||
|
||||
Original image | Sigma = 0.5 | Sigma = 1.5
|
||||
-----------------------------------|----------------------------------------|---------------------------------------
|
||||
 |  | 
|
||||
 |  | 
|
||||
|
||||
### Sharpening
|
||||
|
||||
@@ -91,7 +88,7 @@ dstImage := imaging.Sharpen(srcImage, 0.5)
|
||||
|
||||
Original image | Sigma = 0.5 | Sigma = 1.5
|
||||
-----------------------------------|-------------------------------------------|------------------------------------------
|
||||
 |  | 
|
||||
 |  | 
|
||||
|
||||
### Gamma correction
|
||||
|
||||
@@ -101,7 +98,7 @@ dstImage := imaging.AdjustGamma(srcImage, 0.75)
|
||||
|
||||
Original image | Gamma = 0.75 | Gamma = 1.25
|
||||
-----------------------------------|------------------------------------------|-----------------------------------------
|
||||
 |  | 
|
||||
 |  | 
|
||||
|
||||
### Contrast adjustment
|
||||
|
||||
@@ -109,9 +106,9 @@ Original image | Gamma = 0.75 |
|
||||
dstImage := imaging.AdjustContrast(srcImage, 20)
|
||||
```
|
||||
|
||||
Original image | Contrast = 10 | Contrast = -10
|
||||
Original image | Contrast = 15 | Contrast = -15
|
||||
-----------------------------------|--------------------------------------------|-------------------------------------------
|
||||
 |  | 
|
||||
 |  | 
|
||||
|
||||
### Brightness adjustment
|
||||
|
||||
@@ -121,7 +118,7 @@ dstImage := imaging.AdjustBrightness(srcImage, 20)
|
||||
|
||||
Original image | Brightness = 10 | Brightness = -10
|
||||
-----------------------------------|----------------------------------------------|---------------------------------------------
|
||||
 |  | 
|
||||
 |  | 
|
||||
|
||||
## Example code
|
||||
|
||||
@@ -137,20 +134,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Open the test image.
|
||||
src, err := imaging.Open("testdata/lena_512.png")
|
||||
// Open a test image.
|
||||
src, err := imaging.Open("testdata/flowers.png")
|
||||
if err != nil {
|
||||
log.Fatalf("Open failed: %v", err)
|
||||
log.Fatalf("failed to open image: %v", err)
|
||||
}
|
||||
|
||||
// Crop the original image to 350x350px size using the center anchor.
|
||||
src = imaging.CropAnchor(src, 350, 350, imaging.Center)
|
||||
// Crop the original image to 300x300px size using the center anchor.
|
||||
src = imaging.CropAnchor(src, 300, 300, imaging.Center)
|
||||
|
||||
// Resize the cropped image to width = 256px preserving the aspect ratio.
|
||||
src = imaging.Resize(src, 256, 0, imaging.Lanczos)
|
||||
// Resize the cropped image to width = 200px preserving the aspect ratio.
|
||||
src = imaging.Resize(src, 200, 0, imaging.Lanczos)
|
||||
|
||||
// Create a blurred version of the image.
|
||||
img1 := imaging.Blur(src, 2)
|
||||
img1 := imaging.Blur(src, 5)
|
||||
|
||||
// Create a grayscale version of the image with higher contrast and sharpness.
|
||||
img2 := imaging.Grayscale(src)
|
||||
@@ -172,16 +169,16 @@ func main() {
|
||||
)
|
||||
|
||||
// Create a new image and paste the four produced images into it.
|
||||
dst := imaging.New(512, 512, color.NRGBA{0, 0, 0, 0})
|
||||
dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0})
|
||||
dst = imaging.Paste(dst, img1, image.Pt(0, 0))
|
||||
dst = imaging.Paste(dst, img2, image.Pt(0, 256))
|
||||
dst = imaging.Paste(dst, img3, image.Pt(256, 0))
|
||||
dst = imaging.Paste(dst, img4, image.Pt(256, 256))
|
||||
dst = imaging.Paste(dst, img2, image.Pt(0, 200))
|
||||
dst = imaging.Paste(dst, img3, image.Pt(200, 0))
|
||||
dst = imaging.Paste(dst, img4, image.Pt(200, 200))
|
||||
|
||||
// Save the resulting image using JPEG format.
|
||||
// Save the resulting image as JPEG.
|
||||
err = imaging.Save(dst, "testdata/out_example.jpg")
|
||||
if err != nil {
|
||||
log.Fatalf("Save failed: %v", err)
|
||||
log.Fatalf("failed to save image: %v", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
260
vendor/github.com/disintegration/imaging/adjust.go
сгенерированный
поставляемый
@@ -6,52 +6,97 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// 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 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})
|
||||
|
||||
dst.Pix[j+0] = c.R
|
||||
dst.Pix[j+1] = c.G
|
||||
dst.Pix[j+2] = c.B
|
||||
dst.Pix[j+3] = c.A
|
||||
// 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.
|
||||
//
|
||||
// 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)
|
||||
|
||||
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 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.
|
||||
// Gamma parameter must be positive. Gamma = 1.0 gives the original image.
|
||||
// Gamma less than 1.0 darkens the image and gamma greater than 1.0 lightens it.
|
||||
@@ -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
|
||||
}
|
||||
|
||||
564
vendor/github.com/disintegration/imaging/adjust_test.go
сгенерированный
поставляемый
@@ -1,564 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGrayscale(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Grayscale 3x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x3d, 0x3d, 0x3d, 0x01, 0x78, 0x78, 0x78, 0x02, 0x17, 0x17, 0x17, 0x03,
|
||||
0x1f, 0x1f, 0x1f, 0xff, 0x25, 0x25, 0x25, 0xff, 0x66, 0x66, 0x66, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Grayscale(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvert(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Invert 3x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x33, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x02, 0xff, 0xff, 0x33, 0x03,
|
||||
0xee, 0xdd, 0xcc, 0xff, 0xcc, 0xdd, 0xee, 0xff, 0x55, 0xcc, 0x44, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Invert(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustContrast(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustContrast 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xd5, 0x00, 0x00, 0x01, 0x00, 0xd5, 0x00, 0x02, 0x00, 0x00, 0xd5, 0x03,
|
||||
0x05, 0x18, 0x2b, 0xff, 0x2b, 0x18, 0x05, 0xff, 0xaf, 0x2b, 0xc2, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0xff, 0x03,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 -10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xc4, 0x0d, 0x0d, 0x01, 0x0d, 0xc4, 0x0d, 0x02, 0x0d, 0x0d, 0xc4, 0x03,
|
||||
0x1c, 0x2b, 0x3b, 0xff, 0x3b, 0x2b, 0x1c, 0xff, 0xa6, 0x3b, 0xb5, 0xff,
|
||||
0x0d, 0x0d, 0x0d, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xf2, 0xf2, 0xf2, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 -100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x80, 0x80, 0x80, 0x01, 0x80, 0x80, 0x80, 0x02, 0x80, 0x80, 0x80, 0x03,
|
||||
0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
|
||||
0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustContrast 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustContrast(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustContrastGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_128.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, p := range map[string]float64{
|
||||
"out_contrast_m10.png": -10,
|
||||
"out_contrast_p10.png": 10,
|
||||
} {
|
||||
got := AdjustContrast(src, p)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustBrightness(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustBrightness 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xe6, 0x1a, 0x1a, 0x01, 0x1a, 0xe6, 0x1a, 0x02, 0x1a, 0x1a, 0xe6, 0x03,
|
||||
0x2b, 0x3c, 0x4d, 0xff, 0x4d, 0x3c, 0x2b, 0xff, 0xc4, 0x4d, 0xd5, 0xff,
|
||||
0x1a, 0x1a, 0x1a, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x03,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 -10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xb3, 0x00, 0x00, 0x01, 0x00, 0xb3, 0x00, 0x02, 0x00, 0x00, 0xb3, 0x03,
|
||||
0x00, 0x09, 0x1a, 0xff, 0x1a, 0x09, 0x00, 0xff, 0x91, 0x1a, 0xa2, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 -100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustBrightness 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustBrightness(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustBrightnessGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_128.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, p := range map[string]float64{
|
||||
"out_brightness_m10.png": -10,
|
||||
"out_brightness_p10.png": 10,
|
||||
} {
|
||||
got := AdjustBrightness(src, p)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustGamma(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustGamma 3x3 0.75",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.75,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xbd, 0x00, 0x00, 0x01, 0x00, 0xbd, 0x00, 0x02, 0x00, 0x00, 0xbd, 0x03,
|
||||
0x07, 0x11, 0x1e, 0xff, 0x1e, 0x11, 0x07, 0xff, 0x95, 0x1e, 0xa9, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustGamma 3x3 1.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xdc, 0x00, 0x00, 0x01, 0x00, 0xdc, 0x00, 0x02, 0x00, 0x00, 0xdc, 0x03,
|
||||
0x2a, 0x43, 0x57, 0xff, 0x57, 0x43, 0x2a, 0xff, 0xc3, 0x57, 0xcf, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x57, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustGamma 3x3 1.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustGamma(d.src, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustGammaGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_128.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, g := range map[string]float64{
|
||||
"out_gamma_0.75.png": 0.75,
|
||||
"out_gamma_1.25.png": 1.25,
|
||||
} {
|
||||
got := AdjustGamma(src, g)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdjustSigmoid(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
m float64
|
||||
p float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 3.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
3.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xd4, 0x00, 0x00, 0x01, 0x00, 0xd4, 0x00, 0x02, 0x00, 0x00, 0xd4, 0x03,
|
||||
0x0d, 0x1b, 0x2b, 0xff, 0x2b, 0x1b, 0x0d, 0xff, 0xb1, 0x2b, 0xc3, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 -3.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
-3.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xc4, 0x00, 0x00, 0x01, 0x00, 0xc4, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x03,
|
||||
0x16, 0x2a, 0x3b, 0xff, 0x3b, 0x2a, 0x16, 0xff, 0xa4, 0x3b, 0xb3, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"AdjustSigmoid 3x3 0.5 0.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
0.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
|
||||
0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := AdjustSigmoid(d.src, d.m, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
312
vendor/github.com/disintegration/imaging/clone.go
сгенерированный
поставляемый
@@ -1,312 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// Clone returns a copy of the given image.
|
||||
func Clone(img image.Image) *image.NRGBA {
|
||||
dstBounds := img.Bounds().Sub(img.Bounds().Min)
|
||||
dst := image.NewNRGBA(dstBounds)
|
||||
|
||||
switch src := img.(type) {
|
||||
case *image.NRGBA:
|
||||
copyNRGBA(dst, src)
|
||||
case *image.NRGBA64:
|
||||
copyNRGBA64(dst, src)
|
||||
case *image.RGBA:
|
||||
copyRGBA(dst, src)
|
||||
case *image.RGBA64:
|
||||
copyRGBA64(dst, src)
|
||||
case *image.Gray:
|
||||
copyGray(dst, src)
|
||||
case *image.Gray16:
|
||||
copyGray16(dst, src)
|
||||
case *image.YCbCr:
|
||||
copyYCbCr(dst, src)
|
||||
case *image.Paletted:
|
||||
copyPaletted(dst, src)
|
||||
default:
|
||||
copyImage(dst, src)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
rowSize := dstW * 4
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
dst.Pix[di+3] = src.Pix[si+6]
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+3]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+1]
|
||||
dst.Pix[di+2] = src.Pix[si+2]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+6]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray(dst *image.NRGBA, src *image.Gray) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray16(dst *image.NRGBA, src *image.Gray16) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si += 2
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
srcY := srcMinY + dstY
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := srcMinX + dstX
|
||||
|
||||
siy := (srcY-srcMinY)*src.YStride + (srcX - srcMinX)
|
||||
|
||||
var sic int
|
||||
switch src.SubsampleRatio {
|
||||
case image.YCbCrSubsampleRatio444:
|
||||
sic = (srcY-srcMinY)*src.CStride + (srcX - srcMinX)
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
sic = (srcY-srcMinY)*src.CStride + (srcX/2 - srcMinX/2)
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX/2 - srcMinX/2)
|
||||
case image.YCbCrSubsampleRatio440:
|
||||
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX - srcMinX)
|
||||
default:
|
||||
sic = src.COffset(srcX, srcY)
|
||||
}
|
||||
|
||||
y := int32(src.Y[siy])
|
||||
cb := int32(src.Cb[sic]) - 128
|
||||
cr := int32(src.Cr[sic]) - 128
|
||||
|
||||
r := (y<<16 + 91881*cr + 1<<15) >> 16
|
||||
if r > 255 {
|
||||
r = 255
|
||||
} else if r < 0 {
|
||||
r = 0
|
||||
}
|
||||
|
||||
g := (y<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
|
||||
if g > 255 {
|
||||
g = 255
|
||||
} else if g < 0 {
|
||||
g = 0
|
||||
}
|
||||
|
||||
b := (y<<16 + 116130*cb + 1<<15) >> 16
|
||||
if b > 255 {
|
||||
b = 255
|
||||
} else if b < 0 {
|
||||
b = 0
|
||||
}
|
||||
|
||||
dst.Pix[di+0] = uint8(r)
|
||||
dst.Pix[di+1] = uint8(g)
|
||||
dst.Pix[di+2] = uint8(b)
|
||||
dst.Pix[di+3] = 255
|
||||
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
plen := len(src.Palette)
|
||||
pnew := make([]color.NRGBA, plen)
|
||||
for i := 0; i < plen; i++ {
|
||||
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
|
||||
}
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := pnew[src.Pix[si]]
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyImage(dst *image.NRGBA, src image.Image) {
|
||||
srcMinX := src.Bounds().Min.X
|
||||
srcMinY := src.Bounds().Min.Y
|
||||
dstW := dst.Bounds().Dx()
|
||||
dstH := dst.Bounds().Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
|
||||
func toNRGBA(img image.Image) *image.NRGBA {
|
||||
if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
|
||||
return img
|
||||
}
|
||||
return Clone(img)
|
||||
}
|
||||
247
vendor/github.com/disintegration/imaging/clone_test.go
сгенерированный
поставляемый
@@ -1,247 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Clone NRGBA",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone NRGBA64",
|
||||
&image.NRGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA",
|
||||
&image.RGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA64",
|
||||
&image.RGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray",
|
||||
&image.Gray{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray16",
|
||||
&image.Gray16{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 2,
|
||||
Pix: []uint8{0x11, 0x11, 0xee, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Alpha",
|
||||
&image.Alpha{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr",
|
||||
&image.YCbCr{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
YStride: 6,
|
||||
CStride: 6,
|
||||
Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
|
||||
Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
|
||||
Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 444",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 440",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio440,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 422",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
|
||||
Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 420",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
|
||||
Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
|
||||
YStride: 4, CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Paletted",
|
||||
&image.Paletted{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
Stride: 6 * 1,
|
||||
Palette: color.Palette{
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
|
||||
},
|
||||
Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := Clone(d.src)
|
||||
want := d.want
|
||||
|
||||
delta := 0
|
||||
if _, ok := d.src.(*image.YCbCr); ok {
|
||||
delta = 1
|
||||
}
|
||||
|
||||
if !compareNRGBA(got, want, delta) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
6
vendor/github.com/disintegration/imaging/convolution.go
сгенерированный
поставляемый
@@ -58,8 +58,6 @@ func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *imag
|
||||
m = 1
|
||||
case 25:
|
||||
m = 2
|
||||
default:
|
||||
return dst
|
||||
}
|
||||
|
||||
i := 0
|
||||
@@ -72,8 +70,8 @@ func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *imag
|
||||
}
|
||||
}
|
||||
|
||||
parallel(h, func(partStart, partEnd int) {
|
||||
for y := partStart; y < partEnd; y++ {
|
||||
parallel(0, h, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
for x := 0; x < w; x++ {
|
||||
var r, g, b float64
|
||||
for _, c := range coefs {
|
||||
|
||||
275
vendor/github.com/disintegration/imaging/convolution_test.go
сгенерированный
поставляемый
@@ -1,275 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConvolve3x3(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
kernel [9]float64
|
||||
options *ConvolveOptions
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Convolve3x3 0x0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
[9]float64{
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
},
|
||||
nil,
|
||||
&image.NRGBA{Rect: image.Rect(0, 0, 0, 0)},
|
||||
},
|
||||
{
|
||||
"Convolve3x3 4x4 identity",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
[9]float64{
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
},
|
||||
nil,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Convolve3x3 4x4 abs",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
[9]float64{
|
||||
0, 0, 0,
|
||||
0, -1, 0,
|
||||
0, 0, 0,
|
||||
},
|
||||
&ConvolveOptions{Abs: true},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Convolve3x3 4x4 bias",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
[9]float64{
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
},
|
||||
&ConvolveOptions{Bias: 0x10},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x11, 0x12, 0x03, 0x14, 0x15, 0x16, 0x07, 0x18, 0x19, 0x1a, 0x0b, 0x1c, 0x1d, 0x1e, 0x0f,
|
||||
0x20, 0x21, 0x22, 0x13, 0x24, 0x25, 0x26, 0x17, 0x28, 0x29, 0x2a, 0x1b, 0x2c, 0x2d, 0x2e, 0x1f,
|
||||
0x30, 0x31, 0x32, 0x23, 0x34, 0x35, 0x36, 0x27, 0x38, 0x39, 0x3a, 0x2b, 0x3c, 0x3d, 0x3e, 0x2f,
|
||||
0x40, 0x41, 0x42, 0x33, 0x44, 0x45, 0x46, 0x37, 0x48, 0x49, 0x4a, 0x3b, 0x4c, 0x4d, 0x4e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Convolve3x3 4x4 norm",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
[9]float64{
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
},
|
||||
&ConvolveOptions{Normalize: true},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x07, 0x08, 0x09, 0x03, 0x09, 0x0a, 0x0b, 0x07, 0x0d, 0x0e, 0x0f, 0x0b, 0x10, 0x11, 0x12, 0x0f,
|
||||
0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1b, 0x1c, 0x1d, 0x1f,
|
||||
0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2b, 0x2c, 0x2d, 0x2f,
|
||||
0x2c, 0x2d, 0x2e, 0x33, 0x2f, 0x30, 0x31, 0x37, 0x33, 0x34, 0x35, 0x3b, 0x35, 0x36, 0x37, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Convolve3x3 3x3 laplacian",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x01, 0xff, 0x00, 0x01, 0x02, 0xff, 0x00, 0x01, 0x03, 0xff,
|
||||
0x00, 0x01, 0x04, 0xff, 0x10, 0x10, 0x10, 0xff, 0x00, 0x01, 0x05, 0xff,
|
||||
0x00, 0x01, 0x06, 0xff, 0x00, 0x01, 0x07, 0xff, 0x00, 0x01, 0x08, 0xff,
|
||||
},
|
||||
},
|
||||
[9]float64{
|
||||
-1, -1, -1,
|
||||
-1, 8, -1,
|
||||
-1, -1, -1,
|
||||
},
|
||||
nil,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x80, 0x78, 0x5c, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
got := Convolve3x3(tc.src, tc.kernel, tc.options)
|
||||
want := tc.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: want %#v got %#v", tc.desc, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvolve5x5(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
kernel [25]float64
|
||||
options *ConvolveOptions
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Convolve5x5 4x4 translate",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
[25]float64{
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1,
|
||||
},
|
||||
nil,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x28, 0x29, 0x2a, 0x03, 0x2c, 0x2d, 0x2e, 0x07, 0x2c, 0x2d, 0x2e, 0x0b, 0x2c, 0x2d, 0x2e, 0x0f,
|
||||
0x38, 0x39, 0x3a, 0x13, 0x3c, 0x3d, 0x3e, 0x17, 0x3c, 0x3d, 0x3e, 0x1b, 0x3c, 0x3d, 0x3e, 0x1f,
|
||||
0x38, 0x39, 0x3a, 0x23, 0x3c, 0x3d, 0x3e, 0x27, 0x3c, 0x3d, 0x3e, 0x2b, 0x3c, 0x3d, 0x3e, 0x2f,
|
||||
0x38, 0x39, 0x3a, 0x33, 0x3c, 0x3d, 0x3e, 0x37, 0x3c, 0x3d, 0x3e, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
got := Convolve5x5(tc.src, tc.kernel, tc.options)
|
||||
want := tc.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: want %#v got %#v", tc.desc, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvolve3x3(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img, err := Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
b.Fatalf("Open: %v", err)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Convolve3x3(
|
||||
img,
|
||||
[9]float64{
|
||||
-1, -1, 0,
|
||||
-1, 0, 1,
|
||||
0, 1, 1,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvolve5x5(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img, err := Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
b.Fatalf("Open: %v", err)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Convolve5x5(
|
||||
img,
|
||||
[25]float64{
|
||||
-1, -1, -1, -1, 0,
|
||||
-1, -1, -1, 0, 1,
|
||||
-1, -1, 0, 1, 1,
|
||||
-1, 0, 1, 1, 1,
|
||||
0, 1, 1, 1, 1,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
}
|
||||
}
|
||||
7
vendor/github.com/disintegration/imaging/doc.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.).
|
||||
|
||||
All the image processing functions provided by the package accept any image type that implements image.Image interface
|
||||
as an input, and return a new image of *image.NRGBA type (32bit RGBA colors, not premultiplied by alpha).
|
||||
*/
|
||||
package imaging
|
||||
174
vendor/github.com/disintegration/imaging/effects.go
сгенерированный
поставляемый
@@ -18,11 +18,9 @@ func gaussianBlurKernel(x, sigma float64) float64 {
|
||||
//
|
||||
func Blur(img image.Image, sigma float64) *image.NRGBA {
|
||||
if sigma <= 0 {
|
||||
// sigma parameter must be positive!
|
||||
return Clone(img)
|
||||
}
|
||||
|
||||
src := toNRGBA(img)
|
||||
radius := int(math.Ceil(sigma * 3.0))
|
||||
kernel := make([]float64, radius+1)
|
||||
|
||||
@@ -30,54 +28,50 @@ func Blur(img image.Image, sigma float64) *image.NRGBA {
|
||||
kernel[i] = gaussianBlurKernel(float64(i), sigma)
|
||||
}
|
||||
|
||||
var dst *image.NRGBA
|
||||
dst = blurHorizontal(src, kernel)
|
||||
dst = blurVertical(dst, kernel)
|
||||
|
||||
return dst
|
||||
return blurVertical(blurHorizontal(img, kernel), kernel)
|
||||
}
|
||||
|
||||
func blurHorizontal(src *image.NRGBA, kernel []float64) *image.NRGBA {
|
||||
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
|
||||
width := src.Bounds().Max.X
|
||||
height := src.Bounds().Max.Y
|
||||
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
parallel(width, func(partStart, partEnd int) {
|
||||
for x := partStart; x < partEnd; x++ {
|
||||
start := x - radius
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
end := x + radius
|
||||
if end > width-1 {
|
||||
end = width - 1
|
||||
}
|
||||
|
||||
weightSum := 0.0
|
||||
for ix := start; ix <= end; ix++ {
|
||||
weightSum += kernel[absint(x-ix)]
|
||||
}
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
var r, g, b, a float64
|
||||
for ix := start; ix <= end; ix++ {
|
||||
var r, g, b, a, wsum float64
|
||||
for ix := min; ix <= max; ix++ {
|
||||
i := ix * 4
|
||||
weight := kernel[absint(x-ix)]
|
||||
i := y*src.Stride + ix*4
|
||||
wa := float64(src.Pix[i+3]) * weight
|
||||
r += float64(src.Pix[i+0]) * wa
|
||||
g += float64(src.Pix[i+1]) * wa
|
||||
b += float64(src.Pix[i+2]) * wa
|
||||
wsum += weight
|
||||
wa := float64(scanLine[i+3]) * weight
|
||||
r += float64(scanLine[i+0]) * wa
|
||||
g += float64(scanLine[i+1]) * wa
|
||||
b += float64(scanLine[i+2]) * wa
|
||||
a += wa
|
||||
}
|
||||
if a != 0 {
|
||||
r /= a
|
||||
g /= a
|
||||
b /= a
|
||||
}
|
||||
|
||||
j := y*dst.Stride + x*4
|
||||
dst.Pix[j+0] = clamp(r / a)
|
||||
dst.Pix[j+1] = clamp(g / a)
|
||||
dst.Pix[j+2] = clamp(b / a)
|
||||
dst.Pix[j+3] = clamp(a / weightSum)
|
||||
dst.Pix[j+0] = clamp(r)
|
||||
dst.Pix[j+1] = clamp(g)
|
||||
dst.Pix[j+2] = clamp(b)
|
||||
dst.Pix[j+3] = clamp(a / wsum)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -85,47 +79,47 @@ func blurHorizontal(src *image.NRGBA, kernel []float64) *image.NRGBA {
|
||||
return dst
|
||||
}
|
||||
|
||||
func blurVertical(src *image.NRGBA, kernel []float64) *image.NRGBA {
|
||||
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
|
||||
width := src.Bounds().Max.X
|
||||
height := src.Bounds().Max.Y
|
||||
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||
parallel(0, src.w, func(xs <-chan int) {
|
||||
scanLine := make([]uint8, src.h*4)
|
||||
for x := range xs {
|
||||
src.scan(x, 0, x+1, src.h, scanLine)
|
||||
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
|
||||
}
|
||||
|
||||
parallel(height, func(partStart, partEnd int) {
|
||||
for y := partStart; y < partEnd; y++ {
|
||||
start := y - radius
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
end := y + radius
|
||||
if end > height-1 {
|
||||
end = height - 1
|
||||
}
|
||||
|
||||
weightSum := 0.0
|
||||
for iy := start; iy <= end; iy++ {
|
||||
weightSum += kernel[absint(y-iy)]
|
||||
}
|
||||
|
||||
for x := 0; x < width; x++ {
|
||||
var r, g, b, a float64
|
||||
for iy := start; iy <= end; iy++ {
|
||||
var r, g, b, a, wsum float64
|
||||
for iy := min; iy <= max; iy++ {
|
||||
i := iy * 4
|
||||
weight := kernel[absint(y-iy)]
|
||||
i := iy*src.Stride + x*4
|
||||
wa := float64(src.Pix[i+3]) * weight
|
||||
r += float64(src.Pix[i+0]) * wa
|
||||
g += float64(src.Pix[i+1]) * wa
|
||||
b += float64(src.Pix[i+2]) * wa
|
||||
wsum += weight
|
||||
wa := float64(scanLine[i+3]) * weight
|
||||
r += float64(scanLine[i+0]) * wa
|
||||
g += float64(scanLine[i+1]) * wa
|
||||
b += float64(scanLine[i+2]) * wa
|
||||
a += wa
|
||||
}
|
||||
if a != 0 {
|
||||
r /= a
|
||||
g /= a
|
||||
b /= a
|
||||
}
|
||||
|
||||
j := y*dst.Stride + x*4
|
||||
dst.Pix[j+0] = clamp(r / a)
|
||||
dst.Pix[j+1] = clamp(g / a)
|
||||
dst.Pix[j+2] = clamp(b / a)
|
||||
dst.Pix[j+3] = clamp(a / weightSum)
|
||||
dst.Pix[j+0] = clamp(r)
|
||||
dst.Pix[j+1] = clamp(g)
|
||||
dst.Pix[j+2] = clamp(b)
|
||||
dst.Pix[j+3] = clamp(a / wsum)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -142,31 +136,27 @@ func blurVertical(src *image.NRGBA, kernel []float64) *image.NRGBA {
|
||||
//
|
||||
func Sharpen(img image.Image, sigma float64) *image.NRGBA {
|
||||
if sigma <= 0 {
|
||||
// sigma parameter must be positive!
|
||||
return Clone(img)
|
||||
}
|
||||
|
||||
src := toNRGBA(img)
|
||||
src := newScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
|
||||
blurred := Blur(img, sigma)
|
||||
|
||||
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
|
||||
for j := 0; j < 4; j++ {
|
||||
k := i + j
|
||||
val := int(src.Pix[k])<<1 - int(blurred.Pix[k])
|
||||
if val < 0 {
|
||||
val = 0
|
||||
} else if val > 255 {
|
||||
val = 255
|
||||
}
|
||||
dst.Pix[k] = uint8(val)
|
||||
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++
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
254
vendor/github.com/disintegration/imaging/effects_test.go
сгенерированный
поставляемый
@@ -1,254 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBlur(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
sigma float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Blur 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
0.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Blur 3x3 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0xaa, 0xff, 0x04, 0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x04,
|
||||
0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x9e, 0x66, 0xaa, 0xff, 0x18,
|
||||
0x66, 0xaa, 0xff, 0x04, 0x66, 0xaa, 0xff, 0x18, 0x66, 0xaa, 0xff, 0x04,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Blur 3x3 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c,
|
||||
0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c,
|
||||
0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c, 0x66, 0xaa, 0xff, 0x1c,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Blur(d.src, d.sigma)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlurGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_128.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, sigma := range map[string]float64{
|
||||
"out_blur_0.5.png": 0.5,
|
||||
"out_blur_1.5.png": 1.5,
|
||||
} {
|
||||
got := Blur(src, sigma)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBlur(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img, err := Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
b.Fatalf("Open: %v", err)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Blur(img, 3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharpen(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
sigma float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Sharpen 3x3 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x3 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
|
||||
0x64, 0x64, 0x64, 0x64, 0x7d, 0x7d, 0x7d, 0x7e, 0x64, 0x64, 0x64, 0x64,
|
||||
0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x3 100",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
},
|
||||
},
|
||||
100,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 3),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x86, 0x86, 0x86, 0x86, 0x64, 0x64, 0x64, 0x64,
|
||||
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Sharpen 3x1 10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 0),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 1),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Sharpen(d.src, d.sigma)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharpenGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_128.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, sigma := range map[string]float64{
|
||||
"out_sharpen_0.5.png": 0.5,
|
||||
"out_sharpen_1.5.png": 1.5,
|
||||
} {
|
||||
got := Sharpen(src, sigma)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSharpen(b *testing.B) {
|
||||
b.StopTimer()
|
||||
img, err := Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
b.Fatalf("Open: %v", err)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sharpen(img, 3)
|
||||
}
|
||||
}
|
||||
58
vendor/github.com/disintegration/imaging/example_test.go
сгенерированный
поставляемый
@@ -1,58 +0,0 @@
|
||||
package imaging_test
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"log"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
// Open the test image.
|
||||
src, err := imaging.Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
log.Fatalf("Open failed: %v", err)
|
||||
}
|
||||
|
||||
// Crop the original image to 350x350px size using the center anchor.
|
||||
src = imaging.CropAnchor(src, 350, 350, imaging.Center)
|
||||
|
||||
// Resize the cropped image to width = 256px preserving the aspect ratio.
|
||||
src = imaging.Resize(src, 256, 0, imaging.Lanczos)
|
||||
|
||||
// Create a blurred version of the image.
|
||||
img1 := imaging.Blur(src, 2)
|
||||
|
||||
// Create a grayscale version of the image with higher contrast and sharpness.
|
||||
img2 := imaging.Grayscale(src)
|
||||
img2 = imaging.AdjustContrast(img2, 20)
|
||||
img2 = imaging.Sharpen(img2, 2)
|
||||
|
||||
// Create an inverted version of the image.
|
||||
img3 := imaging.Invert(src)
|
||||
|
||||
// Create an embossed version of the image using a convolution filter.
|
||||
img4 := imaging.Convolve3x3(
|
||||
src,
|
||||
[9]float64{
|
||||
-1, -1, 0,
|
||||
-1, 1, 1,
|
||||
0, 1, 1,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
// Create a new image and paste the four produced images into it.
|
||||
dst := imaging.New(512, 512, color.NRGBA{0, 0, 0, 0})
|
||||
dst = imaging.Paste(dst, img1, image.Pt(0, 0))
|
||||
dst = imaging.Paste(dst, img2, image.Pt(0, 256))
|
||||
dst = imaging.Paste(dst, img3, image.Pt(256, 0))
|
||||
dst = imaging.Paste(dst, img4, image.Pt(256, 256))
|
||||
|
||||
// Save the resulting image using JPEG format.
|
||||
err = imaging.Save(dst, "testdata/out_example.jpg")
|
||||
if err != nil {
|
||||
log.Fatalf("Save failed: %v", err)
|
||||
}
|
||||
}
|
||||
134
vendor/github.com/disintegration/imaging/helpers.go
сгенерированный
поставляемый
@@ -1,15 +1,10 @@
|
||||
// Package imaging provides basic image manipulation functions (resize, rotate, flip, crop, etc.).
|
||||
// This package is based on the standard Go image package and works best along with it.
|
||||
//
|
||||
// Image manipulation functions provided by the package take any image type
|
||||
// that implements `image.Image` interface as an input, and return a new image of
|
||||
// `*image.NRGBA` type (32bit RGBA colors, not premultiplied by alpha).
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
@@ -56,32 +51,48 @@ var (
|
||||
ErrUnsupportedFormat = errors.New("imaging: unsupported image format")
|
||||
)
|
||||
|
||||
type fileSystem interface {
|
||||
Create(string) (io.WriteCloser, error)
|
||||
Open(string) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
type localFS struct{}
|
||||
|
||||
func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) }
|
||||
func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
|
||||
|
||||
var fs fileSystem = localFS{}
|
||||
|
||||
// Decode reads an image from r.
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
img, _, err := image.Decode(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return toNRGBA(img), nil
|
||||
return img, err
|
||||
}
|
||||
|
||||
// Open loads an image from file
|
||||
func Open(filename string) (image.Image, error) {
|
||||
file, err := os.Open(filename)
|
||||
file, err := fs.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
img, err := Decode(file)
|
||||
return img, err
|
||||
return Decode(file)
|
||||
}
|
||||
|
||||
type encodeConfig struct {
|
||||
jpegQuality int
|
||||
jpegQuality int
|
||||
gifNumColors int
|
||||
gifQuantizer draw.Quantizer
|
||||
gifDrawer draw.Drawer
|
||||
pngCompressionLevel png.CompressionLevel
|
||||
}
|
||||
|
||||
var defaultEncodeConfig = encodeConfig{
|
||||
jpegQuality: 95,
|
||||
jpegQuality: 95,
|
||||
gifNumColors: 256,
|
||||
gifQuantizer: nil,
|
||||
gifDrawer: nil,
|
||||
pngCompressionLevel: png.DefaultCompression,
|
||||
}
|
||||
|
||||
// EncodeOption sets an optional parameter for the Encode and Save functions.
|
||||
@@ -95,6 +106,38 @@ func JPEGQuality(quality int) EncodeOption {
|
||||
}
|
||||
}
|
||||
|
||||
// GIFNumColors returns an EncodeOption that sets the maximum number of colors
|
||||
// used in the GIF-encoded image. It ranges from 1 to 256. Default is 256.
|
||||
func GIFNumColors(numColors int) EncodeOption {
|
||||
return func(c *encodeConfig) {
|
||||
c.gifNumColors = numColors
|
||||
}
|
||||
}
|
||||
|
||||
// GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce
|
||||
// a palette of the GIF-encoded image.
|
||||
func GIFQuantizer(quantizer draw.Quantizer) EncodeOption {
|
||||
return func(c *encodeConfig) {
|
||||
c.gifQuantizer = quantizer
|
||||
}
|
||||
}
|
||||
|
||||
// GIFDrawer returns an EncodeOption that sets the drawer that is used to convert
|
||||
// the source image to the desired palette of the GIF-encoded image.
|
||||
func GIFDrawer(drawer draw.Drawer) EncodeOption {
|
||||
return func(c *encodeConfig) {
|
||||
c.gifDrawer = drawer
|
||||
}
|
||||
}
|
||||
|
||||
// PNGCompressionLevel returns an EncodeOption that sets the compression level
|
||||
// of the PNG-encoded image. Default is png.DefaultCompression.
|
||||
func PNGCompressionLevel(level png.CompressionLevel) EncodeOption {
|
||||
return func(c *encodeConfig) {
|
||||
c.pngCompressionLevel = level
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP).
|
||||
func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error {
|
||||
cfg := defaultEncodeConfig
|
||||
@@ -122,13 +165,22 @@ func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) e
|
||||
}
|
||||
|
||||
case PNG:
|
||||
err = png.Encode(w, img)
|
||||
enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel}
|
||||
err = enc.Encode(w, img)
|
||||
|
||||
case GIF:
|
||||
err = gif.Encode(w, img, &gif.Options{NumColors: 256})
|
||||
err = gif.Encode(w, img, &gif.Options{
|
||||
NumColors: cfg.gifNumColors,
|
||||
Quantizer: cfg.gifQuantizer,
|
||||
Drawer: cfg.gifDrawer,
|
||||
})
|
||||
|
||||
case TIFF:
|
||||
err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true})
|
||||
|
||||
case BMP:
|
||||
err = bmp.Encode(w, img)
|
||||
|
||||
default:
|
||||
err = ErrUnsupportedFormat
|
||||
}
|
||||
@@ -163,11 +215,17 @@ func Save(img image.Image, filename string, opts ...EncodeOption) (err error) {
|
||||
return ErrUnsupportedFormat
|
||||
}
|
||||
|
||||
file, err := os.Create(filename)
|
||||
file, err := fs.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
defer func() {
|
||||
cerr := file.Close()
|
||||
if err == nil {
|
||||
err = cerr
|
||||
}
|
||||
}()
|
||||
|
||||
return Encode(file, img, f, opts...)
|
||||
}
|
||||
@@ -185,16 +243,38 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
|
||||
return dst
|
||||
}
|
||||
|
||||
cs := []uint8{c.R, c.G, c.B, c.A}
|
||||
|
||||
// fill the first row
|
||||
// Fill the first row.
|
||||
i := 0
|
||||
for x := 0; x < width; x++ {
|
||||
copy(dst.Pix[x*4:(x+1)*4], cs)
|
||||
}
|
||||
// copy the first row to other rows
|
||||
for y := 1; y < height; y++ {
|
||||
copy(dst.Pix[y*dst.Stride:y*dst.Stride+width*4], dst.Pix[0:width*4])
|
||||
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
|
||||
}
|
||||
|
||||
// Copy the first row to other rows.
|
||||
size := width * 4
|
||||
parallel(1, height, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
i = y * dst.Stride
|
||||
copy(dst.Pix[i:i+size], dst.Pix[0:size])
|
||||
}
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Clone returns a copy of the given image.
|
||||
func Clone(img image.Image) *image.NRGBA {
|
||||
src := newScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h))
|
||||
size := src.w * 4
|
||||
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+size])
|
||||
}
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
159
vendor/github.com/disintegration/imaging/helpers_test.go
сгенерированный
поставляемый
@@ -1,159 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func compareNRGBA(img1, img2 *image.NRGBA, delta int) bool {
|
||||
if !img1.Rect.Eq(img2.Rect) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(img1.Pix) != len(img2.Pix) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(img1.Pix); i++ {
|
||||
if absint(int(img1.Pix[i])-int(img2.Pix[i])) > delta {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
imgWithAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
|
||||
imgWithAlpha.Pix = []uint8{
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
|
||||
127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
|
||||
244, 245, 246, 247, 248, 249, 250, 252, 252, 253, 254, 255,
|
||||
}
|
||||
|
||||
imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
|
||||
imgWithoutAlpha.Pix = []uint8{
|
||||
0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 10, 255,
|
||||
127, 128, 129, 255, 131, 132, 133, 255, 135, 136, 137, 255,
|
||||
244, 245, 246, 255, 248, 249, 250, 255, 252, 253, 254, 255,
|
||||
}
|
||||
|
||||
for _, format := range []Format{JPEG, PNG, GIF, BMP, TIFF} {
|
||||
img := imgWithoutAlpha
|
||||
if format == PNG {
|
||||
img = imgWithAlpha
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := Encode(buf, img, format)
|
||||
if err != nil {
|
||||
t.Errorf("fail encoding format %s", format)
|
||||
continue
|
||||
}
|
||||
|
||||
img2, err := Decode(buf)
|
||||
if err != nil {
|
||||
t.Errorf("fail decoding format %s", format)
|
||||
continue
|
||||
}
|
||||
img2cloned := Clone(img2)
|
||||
|
||||
delta := 0
|
||||
if format == JPEG {
|
||||
delta = 3
|
||||
} else if format == GIF {
|
||||
delta = 16
|
||||
}
|
||||
|
||||
if !compareNRGBA(img, img2cloned, delta) {
|
||||
t.Errorf("test [DecodeEncode %s] failed: %#v %#v", format, img, img2cloned)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err := Encode(buf, imgWithAlpha, JPEG)
|
||||
if err != nil {
|
||||
t.Errorf("failed encoding alpha to JPEG format %s", err)
|
||||
}
|
||||
|
||||
buf = &bytes.Buffer{}
|
||||
err = Encode(buf, imgWithAlpha, Format(100))
|
||||
if err != ErrUnsupportedFormat {
|
||||
t.Errorf("expected ErrUnsupportedFormat")
|
||||
}
|
||||
|
||||
buf = bytes.NewBuffer([]byte("bad data"))
|
||||
_, err = Decode(buf)
|
||||
if err == nil {
|
||||
t.Errorf("decoding bad data, expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
w, h int
|
||||
c color.Color
|
||||
dstBounds image.Rectangle
|
||||
dstPix []uint8
|
||||
}{
|
||||
{
|
||||
"New 1x1 black",
|
||||
1, 1,
|
||||
color.NRGBA{0, 0, 0, 0},
|
||||
image.Rect(0, 0, 1, 1),
|
||||
[]uint8{0x00, 0x00, 0x00, 0x00},
|
||||
},
|
||||
{
|
||||
"New 1x2 red",
|
||||
1, 2,
|
||||
color.NRGBA{255, 0, 0, 255},
|
||||
image.Rect(0, 0, 1, 2),
|
||||
[]uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff},
|
||||
},
|
||||
{
|
||||
"New 2x1 white",
|
||||
2, 1,
|
||||
color.NRGBA{255, 255, 255, 255},
|
||||
image.Rect(0, 0, 2, 1),
|
||||
[]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
},
|
||||
{
|
||||
"New 0x0 white",
|
||||
0, 0,
|
||||
color.NRGBA{255, 255, 255, 255},
|
||||
image.Rect(0, 0, 0, 0),
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := New(d.w, d.h, d.c)
|
||||
want := image.NewNRGBA(d.dstBounds)
|
||||
want.Pix = d.dstPix
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormats(t *testing.T) {
|
||||
formatNames := map[Format]string{
|
||||
JPEG: "JPEG",
|
||||
PNG: "PNG",
|
||||
GIF: "GIF",
|
||||
BMP: "BMP",
|
||||
TIFF: "TIFF",
|
||||
Format(-1): "Unsupported",
|
||||
}
|
||||
for format, name := range formatNames {
|
||||
got := format.String()
|
||||
if got != name {
|
||||
t.Errorf("test [Format names] failed: got %#v want %#v", got, name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/disintegration/imaging/histogram.go
сгенерированный
поставляемый
@@ -2,6 +2,7 @@ package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Histogram returns a normalized histogram of an image.
|
||||
@@ -9,35 +10,42 @@ import (
|
||||
// Resulting histogram is represented as an array of 256 floats, where
|
||||
// histogram[i] is a probability of a pixel being of a particular luminance i.
|
||||
func Histogram(img image.Image) [256]float64 {
|
||||
src := toNRGBA(img)
|
||||
width := src.Bounds().Max.X
|
||||
height := src.Bounds().Max.Y
|
||||
|
||||
var mu sync.Mutex
|
||||
var histogram [256]float64
|
||||
var total float64
|
||||
|
||||
if width == 0 || height == 0 {
|
||||
src := newScanner(img)
|
||||
if src.w == 0 || src.h == 0 {
|
||||
return histogram
|
||||
}
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
i := y*src.Stride + x*4
|
||||
|
||||
r := src.Pix[i+0]
|
||||
g := src.Pix[i+1]
|
||||
b := src.Pix[i+2]
|
||||
|
||||
y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
|
||||
|
||||
histogram[int(y+0.5)]++
|
||||
total++
|
||||
parallel(0, src.h, func(ys <-chan int) {
|
||||
var tmpHistogram [256]float64
|
||||
var tmpTotal float64
|
||||
scanLine := make([]uint8, src.w*4)
|
||||
for y := range ys {
|
||||
src.scan(0, y, src.w, y+1, scanLine)
|
||||
i := 0
|
||||
for x := 0; x < src.w; x++ {
|
||||
r := scanLine[i+0]
|
||||
g := scanLine[i+1]
|
||||
b := scanLine[i+2]
|
||||
y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
|
||||
tmpHistogram[int(y+0.5)]++
|
||||
tmpTotal++
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
mu.Lock()
|
||||
for i := 0; i < 256; i++ {
|
||||
histogram[i] += tmpHistogram[i]
|
||||
}
|
||||
total += tmpTotal
|
||||
mu.Unlock()
|
||||
})
|
||||
|
||||
for i := 0; i < 256; i++ {
|
||||
histogram[i] = histogram[i] / total
|
||||
}
|
||||
|
||||
return histogram
|
||||
}
|
||||
|
||||
42
vendor/github.com/disintegration/imaging/histogram_test.go
сгенерированный
поставляемый
@@ -1,42 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHistogram(t *testing.T) {
|
||||
b := image.Rectangle{image.Point{0, 0}, image.Point{2, 2}}
|
||||
|
||||
i1 := image.NewRGBA(b)
|
||||
i1.Set(0, 0, image.Black)
|
||||
i1.Set(1, 0, image.White)
|
||||
i1.Set(1, 1, image.White)
|
||||
i1.Set(0, 1, color.Gray{123})
|
||||
|
||||
h := Histogram(i1)
|
||||
if h[0] != 0.25 || h[123] != 0.25 || h[255] != 0.5 {
|
||||
t.Errorf("Incorrect histogram for image i1")
|
||||
}
|
||||
|
||||
i2 := image.NewRGBA(b)
|
||||
i2.Set(0, 0, color.Gray{51})
|
||||
i2.Set(0, 1, color.Gray{14})
|
||||
i2.Set(1, 0, color.Gray{14})
|
||||
|
||||
h = Histogram(i2)
|
||||
if h[14] != 0.5 || h[51] != 0.25 || h[0] != 0.25 {
|
||||
t.Errorf("Incorrect histogram for image i2")
|
||||
}
|
||||
|
||||
b = image.Rectangle{image.Point{0, 0}, image.Point{0, 0}}
|
||||
i3 := image.NewRGBA(b)
|
||||
h = Histogram(i3)
|
||||
for _, val := range h {
|
||||
if val != 0 {
|
||||
t.Errorf("Histogram for an empty image should be a zero histogram.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
221
vendor/github.com/disintegration/imaging/resize.go
сгенерированный
поставляемый
@@ -24,17 +24,17 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
|
||||
for v := 0; v < dstSize; v++ {
|
||||
fu := (float64(v)+0.5)*du - 0.5
|
||||
|
||||
startu := int(math.Ceil(fu - ru))
|
||||
if startu < 0 {
|
||||
startu = 0
|
||||
begin := int(math.Ceil(fu - ru))
|
||||
if begin < 0 {
|
||||
begin = 0
|
||||
}
|
||||
endu := int(math.Floor(fu + ru))
|
||||
if endu > srcSize-1 {
|
||||
endu = srcSize - 1
|
||||
end := int(math.Floor(fu + ru))
|
||||
if end > srcSize-1 {
|
||||
end = srcSize - 1
|
||||
}
|
||||
|
||||
var sum float64
|
||||
for u := startu; u <= endu; u++ {
|
||||
for u := begin; u <= end; u++ {
|
||||
w := filter.Kernel((float64(u) - fu) / scale)
|
||||
if w != 0 {
|
||||
sum += w
|
||||
@@ -67,7 +67,6 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
|
||||
//
|
||||
func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NRGBA {
|
||||
dstW, dstH := width, height
|
||||
|
||||
if dstW < 0 || dstH < 0 {
|
||||
return &image.NRGBA{}
|
||||
}
|
||||
@@ -75,16 +74,13 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
|
||||
return &image.NRGBA{}
|
||||
}
|
||||
|
||||
src := toNRGBA(img)
|
||||
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
|
||||
srcW := img.Bounds().Dx()
|
||||
srcH := img.Bounds().Dy()
|
||||
if srcW <= 0 || srcH <= 0 {
|
||||
return &image.NRGBA{}
|
||||
}
|
||||
|
||||
// if new width or height is 0 then preserve aspect ratio, minimum 1px
|
||||
// If new width or height is 0 then preserve aspect ratio, minimum 1px.
|
||||
if dstW == 0 {
|
||||
tmpW := float64(dstH) * float64(srcW) / float64(srcH)
|
||||
dstW = int(math.Max(1.0, math.Floor(tmpW+0.5)))
|
||||
@@ -94,57 +90,45 @@ func Resize(img image.Image, width, height int, filter ResampleFilter) *image.NR
|
||||
dstH = int(math.Max(1.0, math.Floor(tmpH+0.5)))
|
||||
}
|
||||
|
||||
var dst *image.NRGBA
|
||||
|
||||
if filter.Support <= 0.0 {
|
||||
// nearest-neighbor special case
|
||||
dst = resizeNearest(src, dstW, dstH)
|
||||
|
||||
} else {
|
||||
// two-pass resize
|
||||
if srcW != dstW {
|
||||
dst = resizeHorizontal(src, dstW, filter)
|
||||
} else {
|
||||
dst = src
|
||||
}
|
||||
|
||||
if srcH != dstH {
|
||||
dst = resizeVertical(dst, dstH, filter)
|
||||
}
|
||||
if filter.Support <= 0 {
|
||||
// Nearest-neighbor special case.
|
||||
return resizeNearest(img, dstW, dstH)
|
||||
}
|
||||
|
||||
return dst
|
||||
if srcW != dstW && srcH != dstH {
|
||||
return resizeVertical(resizeHorizontal(img, dstW, filter), dstH, filter)
|
||||
}
|
||||
if srcW != dstW {
|
||||
return resizeHorizontal(img, dstW, filter)
|
||||
}
|
||||
if srcH != dstH {
|
||||
return resizeVertical(img, dstH, filter)
|
||||
}
|
||||
return Clone(img)
|
||||
}
|
||||
|
||||
func resizeHorizontal(src *image.NRGBA, width int, filter ResampleFilter) *image.NRGBA {
|
||||
srcBounds := src.Bounds()
|
||||
srcW := srcBounds.Max.X
|
||||
srcH := srcBounds.Max.Y
|
||||
|
||||
dstW := width
|
||||
dstH := srcH
|
||||
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
weights := precomputeWeights(dstW, srcW, filter)
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
i0 := dstY * src.Stride
|
||||
j0 := dstY * dst.Stride
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
func resizeHorizontal(img image.Image, width int, filter ResampleFilter) *image.NRGBA {
|
||||
src := newScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, width, src.h))
|
||||
weights := precomputeWeights(width, src.w, filter)
|
||||
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)
|
||||
j0 := y * dst.Stride
|
||||
for x := 0; x < width; x++ {
|
||||
var r, g, b, a float64
|
||||
for _, w := range weights[dstX] {
|
||||
i := i0 + w.index*4
|
||||
aw := float64(src.Pix[i+3]) * w.weight
|
||||
r += float64(src.Pix[i+0]) * aw
|
||||
g += float64(src.Pix[i+1]) * aw
|
||||
b += float64(src.Pix[i+2]) * aw
|
||||
for _, w := range weights[x] {
|
||||
i := w.index * 4
|
||||
aw := float64(scanLine[i+3]) * w.weight
|
||||
r += float64(scanLine[i+0]) * aw
|
||||
g += float64(scanLine[i+1]) * aw
|
||||
b += float64(scanLine[i+2]) * aw
|
||||
a += aw
|
||||
}
|
||||
if a != 0 {
|
||||
aInv := 1 / a
|
||||
j := j0 + dstX*4
|
||||
j := j0 + x*4
|
||||
dst.Pix[j+0] = clamp(r * aInv)
|
||||
dst.Pix[j+1] = clamp(g * aInv)
|
||||
dst.Pix[j+2] = clamp(b * aInv)
|
||||
@@ -153,37 +137,30 @@ func resizeHorizontal(src *image.NRGBA, width int, filter ResampleFilter) *image
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func resizeVertical(src *image.NRGBA, height int, filter ResampleFilter) *image.NRGBA {
|
||||
srcBounds := src.Bounds()
|
||||
srcW := srcBounds.Max.X
|
||||
srcH := srcBounds.Max.Y
|
||||
|
||||
dstW := srcW
|
||||
dstH := height
|
||||
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
weights := precomputeWeights(dstH, srcH, filter)
|
||||
|
||||
parallel(dstW, func(partStart, partEnd int) {
|
||||
for dstX := partStart; dstX < partEnd; dstX++ {
|
||||
for dstY := 0; dstY < dstH; dstY++ {
|
||||
func resizeVertical(img image.Image, height int, filter ResampleFilter) *image.NRGBA {
|
||||
src := newScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, src.w, height))
|
||||
weights := precomputeWeights(height, src.h, filter)
|
||||
parallel(0, src.w, func(xs <-chan int) {
|
||||
scanLine := make([]uint8, src.h*4)
|
||||
for x := range xs {
|
||||
src.scan(x, 0, x+1, src.h, scanLine)
|
||||
for y := 0; y < height; y++ {
|
||||
var r, g, b, a float64
|
||||
for _, w := range weights[dstY] {
|
||||
i := w.index*src.Stride + dstX*4
|
||||
aw := float64(src.Pix[i+3]) * w.weight
|
||||
r += float64(src.Pix[i+0]) * aw
|
||||
g += float64(src.Pix[i+1]) * aw
|
||||
b += float64(src.Pix[i+2]) * aw
|
||||
for _, w := range weights[y] {
|
||||
i := w.index * 4
|
||||
aw := float64(scanLine[i+3]) * w.weight
|
||||
r += float64(scanLine[i+0]) * aw
|
||||
g += float64(scanLine[i+1]) * aw
|
||||
b += float64(scanLine[i+2]) * aw
|
||||
a += aw
|
||||
}
|
||||
if a != 0 {
|
||||
aInv := 1 / a
|
||||
j := dstY*dst.Stride + dstX*4
|
||||
j := y*dst.Stride + x*4
|
||||
dst.Pix[j+0] = clamp(r * aInv)
|
||||
dst.Pix[j+1] = clamp(g * aInv)
|
||||
dst.Pix[j+2] = clamp(b * aInv)
|
||||
@@ -192,45 +169,44 @@ func resizeVertical(src *image.NRGBA, height int, filter ResampleFilter) *image.
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// resizeNearest is a fast nearest-neighbor resize, no filtering.
|
||||
func resizeNearest(src *image.NRGBA, width, height int) *image.NRGBA {
|
||||
dstW, dstH := width, height
|
||||
func resizeNearest(img image.Image, width, height int) *image.NRGBA {
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, width, height))
|
||||
dx := float64(img.Bounds().Dx()) / float64(width)
|
||||
dy := float64(img.Bounds().Dy()) / float64(height)
|
||||
|
||||
srcBounds := src.Bounds()
|
||||
srcW := srcBounds.Max.X
|
||||
srcH := srcBounds.Max.Y
|
||||
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
dx := float64(srcW) / float64(dstW)
|
||||
dy := float64(srcH) / float64(dstH)
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
srcY := int((float64(dstY) + 0.5) * dy)
|
||||
if srcY > srcH-1 {
|
||||
srcY = srcH - 1
|
||||
}
|
||||
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := int((float64(dstX) + 0.5) * dx)
|
||||
if srcX > srcW-1 {
|
||||
srcX = srcW - 1
|
||||
if dx > 1 && dy > 1 {
|
||||
src := newScanner(img)
|
||||
parallel(0, height, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
srcY := int((float64(y) + 0.5) * dy)
|
||||
dstOff := y * dst.Stride
|
||||
for x := 0; x < width; x++ {
|
||||
srcX := int((float64(x) + 0.5) * dx)
|
||||
src.scan(srcX, srcY, srcX+1, srcY+1, dst.Pix[dstOff:dstOff+4])
|
||||
dstOff += 4
|
||||
}
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
} else {
|
||||
src := toNRGBA(img)
|
||||
parallel(0, height, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
srcY := int((float64(y) + 0.5) * dy)
|
||||
srcOff0 := srcY * src.Stride
|
||||
dstOff := y * dst.Stride
|
||||
for x := 0; x < width; x++ {
|
||||
srcX := int((float64(x) + 0.5) * dx)
|
||||
srcOff := srcOff0 + srcX*4
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
dstOff += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
@@ -344,27 +320,28 @@ func Thumbnail(img image.Image, width, height int, filter ResampleFilter) *image
|
||||
// General filter recommendations:
|
||||
//
|
||||
// - Lanczos
|
||||
// Probably the best resampling filter for photographic images yielding sharp results,
|
||||
// but it's slower than cubic filters (see below).
|
||||
// High-quality resampling filter for photographic images yielding sharp results.
|
||||
// It's slower than cubic filters (see below).
|
||||
//
|
||||
// - CatmullRom
|
||||
// A sharp cubic filter. It's a good filter for both upscaling and downscaling if sharp results are needed.
|
||||
//
|
||||
// - MitchellNetravali
|
||||
// A high quality cubic filter that produces smoother results with less ringing than CatmullRom.
|
||||
// A high quality cubic filter that produces smoother results with less ringing artifacts than CatmullRom.
|
||||
//
|
||||
// - BSpline
|
||||
// A good filter if a very smooth output is needed.
|
||||
//
|
||||
// - Linear
|
||||
// Bilinear interpolation filter, produces reasonably good, smooth output. It's faster than cubic filters.
|
||||
// Bilinear interpolation filter, produces reasonably good, smooth output.
|
||||
// It's faster than cubic filters.
|
||||
//
|
||||
// - Box
|
||||
// Simple and fast resampling filter appropriate for downscaling.
|
||||
// Simple and fast averaging filter appropriate for downscaling.
|
||||
// When upscaling it's similar to NearestNeighbor.
|
||||
//
|
||||
// - NearestNeighbor
|
||||
// Fastest resample filter, no antialiasing at all. Rarely used.
|
||||
// Fastest resampling filter, no antialiasing.
|
||||
//
|
||||
type ResampleFilter struct {
|
||||
Support float64
|
||||
@@ -417,14 +394,14 @@ var Welch ResampleFilter
|
||||
var Cosine ResampleFilter
|
||||
|
||||
func bcspline(x, b, c float64) float64 {
|
||||
var y float64
|
||||
x = math.Abs(x)
|
||||
if x < 1.0 {
|
||||
return ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
|
||||
y = ((12-9*b-6*c)*x*x*x + (-18+12*b+6*c)*x*x + (6 - 2*b)) / 6
|
||||
} else if x < 2.0 {
|
||||
y = ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
|
||||
}
|
||||
if x < 2.0 {
|
||||
return ((-b-6*c)*x*x*x + (6*b+30*c)*x*x + (-12*b-48*c)*x + (8*b + 24*c)) / 6
|
||||
}
|
||||
return 0
|
||||
return y
|
||||
}
|
||||
|
||||
func sinc(x float64) float64 {
|
||||
|
||||
628
vendor/github.com/disintegration/imaging/resize_test.go
сгенерированный
поставляемый
@@ -1,628 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResize(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Resize 2x2 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x55, 0x55, 0x55, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 2x2 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 3x1 1x1 nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 2, 0),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0xff, 0x00, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 0x4 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 4,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 4x0 linear",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
4, 0,
|
||||
Linear,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x40, 0xff, 0x00, 0x00, 0xbf, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0x40, 0x6e, 0x6d, 0x25, 0x70, 0xb0, 0x14, 0x3b, 0xcf, 0xbf, 0x00, 0x40, 0xff,
|
||||
0x00, 0xff, 0x00, 0xbf, 0x14, 0xb0, 0x3b, 0xcf, 0x33, 0x33, 0x99, 0xef, 0x40, 0x00, 0xbf, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xbf, 0x40, 0xff, 0x00, 0x40, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Resize 0x0 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, -1, -1),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 0x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Resize 2x2 -1x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-1, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Resize(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
|
||||
for i, filter := range []ResampleFilter{
|
||||
NearestNeighbor,
|
||||
Box,
|
||||
Linear,
|
||||
Hermite,
|
||||
MitchellNetravali,
|
||||
CatmullRom,
|
||||
BSpline,
|
||||
Gaussian,
|
||||
Lanczos,
|
||||
Hann,
|
||||
Hamming,
|
||||
Blackman,
|
||||
Bartlett,
|
||||
Welch,
|
||||
Cosine,
|
||||
} {
|
||||
src := image.NewNRGBA(image.Rect(-1, -1, 2, 3))
|
||||
got := Resize(src, 5, 6, filter)
|
||||
want := image.NewNRGBA(image.Rect(0, 0, 5, 6))
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [Resize all filters #%d] failed: %#v", i, got)
|
||||
}
|
||||
|
||||
if filter.Kernel != nil {
|
||||
x := filter.Kernel(filter.Support + 0.0001)
|
||||
if x != 0 {
|
||||
t.Errorf("test [ResampleFilter edge cases #%d] failed: %f", i, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bcs2 := bcspline(2, 1, 0)
|
||||
if bcs2 != 0 {
|
||||
t.Errorf("test [bcspline 2] failed: %f", bcs2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResizeGolden(t *testing.T) {
|
||||
src, err := Open("testdata/lena_512.png")
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
for name, filter := range map[string]ResampleFilter{
|
||||
"out_resize_nearest.png": NearestNeighbor,
|
||||
"out_resize_linear.png": Linear,
|
||||
"out_resize_catrom.png": CatmullRom,
|
||||
"out_resize_lanczos.png": Lanczos,
|
||||
} {
|
||||
got := Resize(src, 128, 0, filter)
|
||||
want, err := Open("testdata/" + name)
|
||||
if err != nil {
|
||||
t.Errorf("Open: %v", err)
|
||||
}
|
||||
if !compareNRGBA(got, toNRGBA(want), 0) {
|
||||
t.Errorf("resulting image differs from golden: %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFit(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Fit 2x2 1x10 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 10,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x55, 0x55, 0x55, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 10x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x55, 0x55, 0x55, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 10x10 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
10, 10,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fit 0x0 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, -1, -1),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 0x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fit 2x2 -1x0 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
-1, 0,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Fit(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFill(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
a Anchor
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Fill 4x4 2x2 Center Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Center,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 1x4 TopLeft Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
1, 4,
|
||||
TopLeft,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 4),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
0x20, 0x21, 0x22, 0x23,
|
||||
0x30, 0x31, 0x32, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 8x2 Bottom Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
8, 2,
|
||||
Bottom,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 8, 2),
|
||||
Stride: 8 * 4,
|
||||
Pix: []uint8{
|
||||
0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 2x8 Top Nearest",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 8,
|
||||
Top,
|
||||
NearestNeighbor,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 8),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 4x4 TopRight Box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
4, 4,
|
||||
TopRight,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Fill 4x4 0x4 Left Box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 4,
|
||||
Left,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
{
|
||||
"Fill 0x0 4x4 Right Box",
|
||||
&image.NRGBA{},
|
||||
4, 4,
|
||||
Right,
|
||||
Box,
|
||||
&image.NRGBA{},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Fill(d.src, d.w, d.h, d.a, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestThumbnail(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
f ResampleFilter
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Thumbnail 6x2 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 5, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x55, 0x55, 0x55, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Thumbnail 2x6 1x1 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 5),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
1, 1,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x55, 0x55, 0x55, 0xc0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Thumbnail 1x3 2x2 box",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Box,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Thumbnail(d.src, d.w, d.h, d.f)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkResizeLanczosUp(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_128.png", 512, Lanczos)
|
||||
}
|
||||
|
||||
func BenchmarkResizeLinearUp(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_128.png", 512, Linear)
|
||||
}
|
||||
|
||||
func BenchmarkResizeNearestNeighborUp(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_128.png", 512, NearestNeighbor)
|
||||
}
|
||||
|
||||
func BenchmarkResizeLanczosDown(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_512.png", 128, Lanczos)
|
||||
}
|
||||
|
||||
func BenchmarkResizeLinearDown(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_512.png", 128, Linear)
|
||||
}
|
||||
|
||||
func BenchmarkResizeNearestNeighborDown(b *testing.B) {
|
||||
benchmarkResize(b, "testdata/lena_512.png", 128, NearestNeighbor)
|
||||
}
|
||||
|
||||
func benchmarkResize(b *testing.B, filename string, size int, f ResampleFilter) {
|
||||
b.StopTimer()
|
||||
img, err := Open(filename)
|
||||
if err != nil {
|
||||
b.Fatalf("Open: %v", err)
|
||||
}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Resize(img, size, size, f)
|
||||
}
|
||||
}
|
||||
250
vendor/github.com/disintegration/imaging/scanner.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,250 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type scanner struct {
|
||||
image image.Image
|
||||
w, h int
|
||||
palette []color.NRGBA
|
||||
}
|
||||
|
||||
func newScanner(img image.Image) *scanner {
|
||||
s := &scanner{
|
||||
image: img,
|
||||
w: img.Bounds().Dx(),
|
||||
h: img.Bounds().Dy(),
|
||||
}
|
||||
if img, ok := img.(*image.Paletted); ok {
|
||||
s.palette = make([]color.NRGBA, len(img.Palette))
|
||||
for i := 0; i < len(img.Palette); i++ {
|
||||
s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// scan scans the given rectangular region of the image into dst.
|
||||
func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) {
|
||||
switch img := s.image.(type) {
|
||||
case *image.NRGBA:
|
||||
size := (x2 - x1) * 4
|
||||
j := 0
|
||||
i := y1*img.Stride + x1*4
|
||||
for y := y1; y < y2; y++ {
|
||||
copy(dst[j:j+size], img.Pix[i:i+size])
|
||||
j += size
|
||||
i += img.Stride
|
||||
}
|
||||
|
||||
case *image.NRGBA64:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1*8
|
||||
for x := x1; x < x2; x++ {
|
||||
dst[j+0] = img.Pix[i+0]
|
||||
dst[j+1] = img.Pix[i+2]
|
||||
dst[j+2] = img.Pix[i+4]
|
||||
dst[j+3] = img.Pix[i+6]
|
||||
j += 4
|
||||
i += 8
|
||||
}
|
||||
}
|
||||
|
||||
case *image.RGBA:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1*4
|
||||
for x := x1; x < x2; x++ {
|
||||
a := img.Pix[i+3]
|
||||
switch a {
|
||||
case 0:
|
||||
dst[j+0] = 0
|
||||
dst[j+1] = 0
|
||||
dst[j+2] = 0
|
||||
case 0xff:
|
||||
dst[j+0] = img.Pix[i+0]
|
||||
dst[j+1] = img.Pix[i+1]
|
||||
dst[j+2] = img.Pix[i+2]
|
||||
default:
|
||||
r16 := uint16(img.Pix[i+0])
|
||||
g16 := uint16(img.Pix[i+1])
|
||||
b16 := uint16(img.Pix[i+2])
|
||||
a16 := uint16(a)
|
||||
dst[j+0] = uint8(r16 * 0xff / a16)
|
||||
dst[j+1] = uint8(g16 * 0xff / a16)
|
||||
dst[j+2] = uint8(b16 * 0xff / a16)
|
||||
}
|
||||
dst[j+3] = a
|
||||
j += 4
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
|
||||
case *image.RGBA64:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1*8
|
||||
for x := x1; x < x2; x++ {
|
||||
a := img.Pix[i+6]
|
||||
switch a {
|
||||
case 0:
|
||||
dst[j+0] = 0
|
||||
dst[j+1] = 0
|
||||
dst[j+2] = 0
|
||||
case 0xff:
|
||||
dst[j+0] = img.Pix[i+0]
|
||||
dst[j+1] = img.Pix[i+2]
|
||||
dst[j+2] = img.Pix[i+4]
|
||||
default:
|
||||
r32 := uint32(img.Pix[i+0])<<8 | uint32(img.Pix[i+1])
|
||||
g32 := uint32(img.Pix[i+2])<<8 | uint32(img.Pix[i+3])
|
||||
b32 := uint32(img.Pix[i+4])<<8 | uint32(img.Pix[i+5])
|
||||
a32 := uint32(img.Pix[i+6])<<8 | uint32(img.Pix[i+7])
|
||||
dst[j+0] = uint8((r32 * 0xffff / a32) >> 8)
|
||||
dst[j+1] = uint8((g32 * 0xffff / a32) >> 8)
|
||||
dst[j+2] = uint8((b32 * 0xffff / a32) >> 8)
|
||||
}
|
||||
dst[j+3] = a
|
||||
j += 4
|
||||
i += 8
|
||||
}
|
||||
}
|
||||
|
||||
case *image.Gray:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1
|
||||
for x := x1; x < x2; x++ {
|
||||
c := img.Pix[i]
|
||||
dst[j+0] = c
|
||||
dst[j+1] = c
|
||||
dst[j+2] = c
|
||||
dst[j+3] = 0xff
|
||||
j += 4
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
case *image.Gray16:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1*2
|
||||
for x := x1; x < x2; x++ {
|
||||
c := img.Pix[i]
|
||||
dst[j+0] = c
|
||||
dst[j+1] = c
|
||||
dst[j+2] = c
|
||||
dst[j+3] = 0xff
|
||||
j += 4
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
case *image.YCbCr:
|
||||
j := 0
|
||||
x1 += img.Rect.Min.X
|
||||
x2 += img.Rect.Min.X
|
||||
y1 += img.Rect.Min.Y
|
||||
y2 += img.Rect.Min.Y
|
||||
for y := y1; y < y2; y++ {
|
||||
iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X)
|
||||
for x := x1; x < x2; x++ {
|
||||
var ic int
|
||||
switch img.SubsampleRatio {
|
||||
case image.YCbCrSubsampleRatio444:
|
||||
ic = (y-img.Rect.Min.Y)*img.CStride + (x - img.Rect.Min.X)
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
ic = (y-img.Rect.Min.Y)*img.CStride + (x/2 - img.Rect.Min.X/2)
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x/2 - img.Rect.Min.X/2)
|
||||
case image.YCbCrSubsampleRatio440:
|
||||
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x - img.Rect.Min.X)
|
||||
default:
|
||||
ic = img.COffset(x, y)
|
||||
}
|
||||
|
||||
yy := int(img.Y[iy])
|
||||
cb := int(img.Cb[ic]) - 128
|
||||
cr := int(img.Cr[ic]) - 128
|
||||
|
||||
r := (yy<<16 + 91881*cr + 1<<15) >> 16
|
||||
if r > 0xff {
|
||||
r = 0xff
|
||||
} else if r < 0 {
|
||||
r = 0
|
||||
}
|
||||
|
||||
g := (yy<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
|
||||
if g > 0xff {
|
||||
g = 0xff
|
||||
} else if g < 0 {
|
||||
g = 0
|
||||
}
|
||||
|
||||
b := (yy<<16 + 116130*cb + 1<<15) >> 16
|
||||
if b > 0xff {
|
||||
b = 0xff
|
||||
} else if b < 0 {
|
||||
b = 0
|
||||
}
|
||||
|
||||
dst[j+0] = uint8(r)
|
||||
dst[j+1] = uint8(g)
|
||||
dst[j+2] = uint8(b)
|
||||
dst[j+3] = 0xff
|
||||
|
||||
iy++
|
||||
j += 4
|
||||
}
|
||||
}
|
||||
|
||||
case *image.Paletted:
|
||||
j := 0
|
||||
for y := y1; y < y2; y++ {
|
||||
i := y*img.Stride + x1
|
||||
for x := x1; x < x2; x++ {
|
||||
c := s.palette[img.Pix[i]]
|
||||
dst[j+0] = c.R
|
||||
dst[j+1] = c.G
|
||||
dst[j+2] = c.B
|
||||
dst[j+3] = c.A
|
||||
j += 4
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
j := 0
|
||||
b := s.image.Bounds()
|
||||
x1 += b.Min.X
|
||||
x2 += b.Min.X
|
||||
y1 += b.Min.Y
|
||||
y2 += b.Min.Y
|
||||
for y := y1; y < y2; y++ {
|
||||
for x := x1; x < x2; x++ {
|
||||
r16, g16, b16, a16 := s.image.At(x, y).RGBA()
|
||||
switch a16 {
|
||||
case 0xffff:
|
||||
dst[j+0] = uint8(r16 >> 8)
|
||||
dst[j+1] = uint8(g16 >> 8)
|
||||
dst[j+2] = uint8(b16 >> 8)
|
||||
dst[j+3] = 0xff
|
||||
case 0:
|
||||
dst[j+0] = 0
|
||||
dst[j+1] = 0
|
||||
dst[j+2] = 0
|
||||
dst[j+3] = 0
|
||||
default:
|
||||
dst[j+0] = uint8(((r16 * 0xffff) / a16) >> 8)
|
||||
dst[j+1] = uint8(((g16 * 0xffff) / a16) >> 8)
|
||||
dst[j+2] = uint8(((b16 * 0xffff) / a16) >> 8)
|
||||
dst[j+3] = uint8(a16 >> 8)
|
||||
}
|
||||
j += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/lena_128.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 49 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/lena_512.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 465 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_blur_0.5.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 28 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_blur_1.5.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 21 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_brightness_m10.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_brightness_p10.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_contrast_m10.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 30 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_contrast_p10.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 32 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_example.jpg
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 134 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_gamma_0.75.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_gamma_1.25.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_resize_catrom.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 30 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_resize_lanczos.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 31 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_resize_linear.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 29 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_resize_nearest.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 35 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_sharpen_0.5.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 33 KiB |
Двоичные данные
vendor/github.com/disintegration/imaging/testdata/out_sharpen_1.5.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 36 KiB |
133
vendor/github.com/disintegration/imaging/tools.go
сгенерированный
поставляемый
@@ -58,10 +58,20 @@ func anchorPt(b image.Rectangle, w, h int, anchor Anchor) image.Point {
|
||||
// Crop cuts out a rectangular region with the specified bounds
|
||||
// from the image and returns the cropped image.
|
||||
func Crop(img image.Image, rect image.Rectangle) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcRect := rect.Sub(img.Bounds().Min)
|
||||
sub := src.SubImage(srcRect)
|
||||
return Clone(sub) // New image Bounds().Min point will be (0, 0)
|
||||
r := rect.Intersect(img.Bounds()).Sub(img.Bounds().Min)
|
||||
if r.Empty() {
|
||||
return &image.NRGBA{}
|
||||
}
|
||||
src := newScanner(img)
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy()))
|
||||
rowSize := r.Dx() * 4
|
||||
parallel(r.Min.Y, r.Max.Y, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
i := (y - r.Min.Y) * dst.Stride
|
||||
src.scan(r.Min.X, y, r.Max.X, y+1, dst.Pix[i:i+rowSize])
|
||||
}
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
// CropAnchor cuts out a rectangular region with the specified size
|
||||
@@ -82,34 +92,25 @@ func CropCenter(img image.Image, width, height int) *image.NRGBA {
|
||||
|
||||
// Paste pastes the img image to the background image at the specified position and returns the combined image.
|
||||
func Paste(background, img image.Image, pos image.Point) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
dst := Clone(background) // cloned image bounds start at (0, 0)
|
||||
startPt := pos.Sub(background.Bounds().Min) // so we should translate start point
|
||||
endPt := startPt.Add(src.Bounds().Size())
|
||||
pasteBounds := image.Rectangle{startPt, endPt}
|
||||
|
||||
if dst.Bounds().Overlaps(pasteBounds) {
|
||||
intersectBounds := dst.Bounds().Intersect(pasteBounds)
|
||||
|
||||
rowSize := intersectBounds.Dx() * 4
|
||||
numRows := intersectBounds.Dy()
|
||||
|
||||
srcStartX := intersectBounds.Min.X - pasteBounds.Min.X
|
||||
srcStartY := intersectBounds.Min.Y - pasteBounds.Min.Y
|
||||
|
||||
i0 := dst.PixOffset(intersectBounds.Min.X, intersectBounds.Min.Y)
|
||||
j0 := src.PixOffset(srcStartX, srcStartY)
|
||||
|
||||
di := dst.Stride
|
||||
dj := src.Stride
|
||||
|
||||
for row := 0; row < numRows; row++ {
|
||||
copy(dst.Pix[i0:i0+rowSize], src.Pix[j0:j0+rowSize])
|
||||
i0 += di
|
||||
j0 += dj
|
||||
}
|
||||
dst := Clone(background)
|
||||
pos = pos.Sub(background.Bounds().Min)
|
||||
pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())}
|
||||
interRect := pasteRect.Intersect(dst.Bounds())
|
||||
if interRect.Empty() {
|
||||
return dst
|
||||
}
|
||||
|
||||
src := newScanner(img)
|
||||
parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
|
||||
for y := range ys {
|
||||
x1 := interRect.Min.X - pasteRect.Min.X
|
||||
x2 := interRect.Max.X - pasteRect.Min.X
|
||||
y1 := y - pasteRect.Min.Y
|
||||
y2 := y1 + 1
|
||||
i1 := y*dst.Stride + interRect.Min.X*4
|
||||
i2 := i1 + interRect.Dx()*4
|
||||
src.scan(x1, y1, x2, y2, dst.Pix[i1:i2])
|
||||
}
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
@@ -136,49 +137,59 @@ func PasteCenter(background, img image.Image) *image.NRGBA {
|
||||
//
|
||||
// Usage examples:
|
||||
//
|
||||
// // draw the sprite over the background at position (50, 50)
|
||||
// // Draw spriteImage over backgroundImage at the given position (x=50, y=50).
|
||||
// dstImage := imaging.Overlay(backgroundImage, spriteImage, image.Pt(50, 50), 1.0)
|
||||
//
|
||||
// // blend two opaque images of the same size
|
||||
// // Blend two opaque images of the same size.
|
||||
// dstImage := imaging.Overlay(imageOne, imageTwo, image.Pt(0, 0), 0.5)
|
||||
//
|
||||
func Overlay(background, img image.Image, pos image.Point, opacity float64) *image.NRGBA {
|
||||
opacity = math.Min(math.Max(opacity, 0.0), 1.0) // check: 0.0 <= opacity <= 1.0
|
||||
|
||||
src := toNRGBA(img)
|
||||
dst := Clone(background) // cloned image bounds start at (0, 0)
|
||||
startPt := pos.Sub(background.Bounds().Min) // so we should translate start point
|
||||
endPt := startPt.Add(src.Bounds().Size())
|
||||
pasteBounds := image.Rectangle{startPt, endPt}
|
||||
|
||||
if dst.Bounds().Overlaps(pasteBounds) {
|
||||
intersectBounds := dst.Bounds().Intersect(pasteBounds)
|
||||
|
||||
for y := intersectBounds.Min.Y; y < intersectBounds.Max.Y; y++ {
|
||||
for x := intersectBounds.Min.X; x < intersectBounds.Max.X; x++ {
|
||||
i := y*dst.Stride + x*4
|
||||
|
||||
srcX := x - pasteBounds.Min.X
|
||||
srcY := y - pasteBounds.Min.Y
|
||||
j := srcY*src.Stride + srcX*4
|
||||
|
||||
opacity = math.Min(math.Max(opacity, 0.0), 1.0) // Ensure 0.0 <= opacity <= 1.0.
|
||||
dst := Clone(background)
|
||||
pos = pos.Sub(background.Bounds().Min)
|
||||
pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())}
|
||||
interRect := pasteRect.Intersect(dst.Bounds())
|
||||
if interRect.Empty() {
|
||||
return dst
|
||||
}
|
||||
src := newScanner(img)
|
||||
parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) {
|
||||
scanLine := make([]uint8, interRect.Dx()*4)
|
||||
for y := range ys {
|
||||
x1 := interRect.Min.X - pasteRect.Min.X
|
||||
x2 := interRect.Max.X - pasteRect.Min.X
|
||||
y1 := y - pasteRect.Min.Y
|
||||
y2 := y1 + 1
|
||||
src.scan(x1, y1, x2, y2, scanLine)
|
||||
i := y*dst.Stride + interRect.Min.X*4
|
||||
j := 0
|
||||
for x := interRect.Min.X; x < interRect.Max.X; x++ {
|
||||
r1 := float64(dst.Pix[i+0])
|
||||
g1 := float64(dst.Pix[i+1])
|
||||
b1 := float64(dst.Pix[i+2])
|
||||
a1 := float64(dst.Pix[i+3])
|
||||
a2 := float64(src.Pix[j+3])
|
||||
|
||||
coef2 := opacity * a2 / 255.0
|
||||
coef1 := (1 - coef2) * a1 / 255.0
|
||||
r2 := float64(scanLine[j+0])
|
||||
g2 := float64(scanLine[j+1])
|
||||
b2 := float64(scanLine[j+2])
|
||||
a2 := float64(scanLine[j+3])
|
||||
|
||||
coef2 := opacity * a2 / 255
|
||||
coef1 := (1 - coef2) * a1 / 255
|
||||
coefSum := coef1 + coef2
|
||||
coef1 /= coefSum
|
||||
coef2 /= coefSum
|
||||
|
||||
dst.Pix[i+0] = uint8(float64(dst.Pix[i+0])*coef1 + float64(src.Pix[j+0])*coef2)
|
||||
dst.Pix[i+1] = uint8(float64(dst.Pix[i+1])*coef1 + float64(src.Pix[j+1])*coef2)
|
||||
dst.Pix[i+2] = uint8(float64(dst.Pix[i+2])*coef1 + float64(src.Pix[j+2])*coef2)
|
||||
dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255.0-a1)/255.0, 255.0))
|
||||
dst.Pix[i+0] = uint8(r1*coef1 + r2*coef2)
|
||||
dst.Pix[i+1] = uint8(g1*coef1 + g2*coef2)
|
||||
dst.Pix[i+2] = uint8(b1*coef1 + b2*coef2)
|
||||
dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255))
|
||||
|
||||
i += 4
|
||||
j += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
|
||||
652
vendor/github.com/disintegration/imaging/tools_test.go
сгенерированный
поставляемый
@@ -1,652 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCrop(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
r image.Rectangle
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Crop 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
image.Rect(-1, 0, 1, 1),
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Crop(d.src, d.r)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCropCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"CropCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
2, 1,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropCenter 2x3 0x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
0, 1,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropCenter 2x3 5x5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
5, 5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := CropCenter(d.src, d.w, d.h)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCropAnchor(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
w, h int
|
||||
anchor Anchor
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"CropAnchor 4x4 2x2 TopLeft",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
TopLeft,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Top",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Top,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 TopRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
TopRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Left",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Left,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Center",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Center,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Right",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Right,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 BottomLeft",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
BottomLeft,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 Bottom",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
Bottom,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 2x2 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
2, 2,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 0x0 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 0,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 100x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
100, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 1x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
1, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 4),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CropAnchor 4x4 0x100 BottomRight",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
},
|
||||
},
|
||||
0, 100,
|
||||
BottomRight,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := CropAnchor(d.src, d.w, d.h, d.anchor)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPaste(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
p image.Point
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Paste 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, 0),
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Paste(d.src1, d.src2, d.p)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasteCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"PasteCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := PasteCenter(d.src1, d.src2)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlay(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
p image.Point
|
||||
a float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Overlay 2x3 2x1 1.0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, 0),
|
||||
1.0,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Overlay 2x2 2x2 0.5",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
|
||||
},
|
||||
},
|
||||
image.Pt(-1, -1),
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Overlay(d.src1, d.src2, d.p, d.a)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlayCenter(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src1 image.Image
|
||||
src2 image.Image
|
||||
a float64
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"OverlayCenter 2x3 2x1",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(1, 1, 3, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
},
|
||||
},
|
||||
0.5,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff,
|
||||
0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := OverlayCenter(d.src1, d.src2, 0.5)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
217
vendor/github.com/disintegration/imaging/transform.go
сгенерированный
поставляемый
@@ -8,197 +8,124 @@ import (
|
||||
|
||||
// FlipH flips the image horizontally (from left to right) and returns the transformed image.
|
||||
func FlipH(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcW
|
||||
dstH := srcH
|
||||
src := newScanner(img)
|
||||
dstW := src.w
|
||||
dstH := src.h
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstW - dstX - 1
|
||||
srcY := dstY
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcY := dstY
|
||||
src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
|
||||
reverse(dst.Pix[i : i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// FlipV flips the image vertically (from top to bottom) and returns the transformed image.
|
||||
func FlipV(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcW
|
||||
dstH := srcH
|
||||
src := newScanner(img)
|
||||
dstW := src.w
|
||||
dstH := src.h
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstX
|
||||
srcY := dstH - dstY - 1
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcY := dstH - dstY - 1
|
||||
src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Transpose flips the image horizontally and rotates 90 degrees counter-clockwise.
|
||||
func Transpose(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcH
|
||||
dstH := srcW
|
||||
src := newScanner(img)
|
||||
dstW := src.h
|
||||
dstH := src.w
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstY
|
||||
srcY := dstX
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcX := dstY
|
||||
src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Transverse flips the image vertically and rotates 90 degrees counter-clockwise.
|
||||
func Transverse(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcH
|
||||
dstH := srcW
|
||||
src := newScanner(img)
|
||||
dstW := src.h
|
||||
dstH := src.w
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstH - dstY - 1
|
||||
srcY := dstW - dstX - 1
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcX := dstH - dstY - 1
|
||||
src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
|
||||
reverse(dst.Pix[i : i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Rotate90 rotates the image 90 degrees counterclockwise and returns the transformed image.
|
||||
// Rotate90 rotates the image 90 degrees counter-clockwise and returns the transformed image.
|
||||
func Rotate90(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcH
|
||||
dstH := srcW
|
||||
src := newScanner(img)
|
||||
dstW := src.h
|
||||
dstH := src.w
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstH - dstY - 1
|
||||
srcY := dstX
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcX := dstH - dstY - 1
|
||||
src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Rotate180 rotates the image 180 degrees counterclockwise and returns the transformed image.
|
||||
// Rotate180 rotates the image 180 degrees counter-clockwise and returns the transformed image.
|
||||
func Rotate180(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcW
|
||||
dstH := srcH
|
||||
src := newScanner(img)
|
||||
dstW := src.w
|
||||
dstH := src.h
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstW - dstX - 1
|
||||
srcY := dstH - dstY - 1
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcY := dstH - dstY - 1
|
||||
src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
|
||||
reverse(dst.Pix[i : i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Rotate270 rotates the image 270 degrees counterclockwise and returns the transformed image.
|
||||
// Rotate270 rotates the image 270 degrees counter-clockwise and returns the transformed image.
|
||||
func Rotate270(img image.Image) *image.NRGBA {
|
||||
src := toNRGBA(img)
|
||||
srcW := src.Bounds().Max.X
|
||||
srcH := src.Bounds().Max.Y
|
||||
dstW := srcH
|
||||
dstH := srcW
|
||||
src := newScanner(img)
|
||||
dstW := src.h
|
||||
dstH := src.w
|
||||
rowSize := dstW * 4
|
||||
dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := dstY
|
||||
srcY := dstW - dstX - 1
|
||||
|
||||
srcOff := srcY*src.Stride + srcX*4
|
||||
dstOff := dstY*dst.Stride + dstX*4
|
||||
|
||||
copy(dst.Pix[dstOff:dstOff+4], src.Pix[srcOff:srcOff+4])
|
||||
}
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
i := dstY * dst.Stride
|
||||
srcX := dstY
|
||||
src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize])
|
||||
reverse(dst.Pix[i : i+rowSize])
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
@@ -237,8 +164,8 @@ func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA {
|
||||
bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA)
|
||||
sin, cos := math.Sincos(math.Pi * angle / 180)
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
parallel(0, dstH, func(ys <-chan int) {
|
||||
for dstY := range ys {
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
xf, yf := rotatePoint(float64(dstX)-dstXOff, float64(dstY)-dstYOff, sin, cos)
|
||||
xf, yf = xf+srcXOff, yf+srcYOff
|
||||
|
||||
581
vendor/github.com/disintegration/imaging/transform_test.go
сгенерированный
поставляемый
@@ -1,581 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFlipH(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"FlipH 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
|
||||
0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := FlipH(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlipV(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"FlipV 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := FlipV(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Transpose 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Transpose(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransverse(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Transverse 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Transverse(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate90(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate90 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate90(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate180(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate180 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 3),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
|
||||
0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate180(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate270(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate270 2x3",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 1, 2),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 3, 2),
|
||||
Stride: 3 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, d := range td {
|
||||
got := Rotate270(d.src)
|
||||
want := d.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRotate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
angle float64
|
||||
bg color.Color
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Rotate 0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
0,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 90",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
90,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 180",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
180,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 45",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 3, 3),
|
||||
Stride: 4 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
45,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 6),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x61, 0x00, 0x00, 0xff, 0x58, 0x08, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x61, 0x00, 0x00, 0xff, 0xe9, 0x16, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x30, 0x30, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x61, 0x00, 0x00, 0xff, 0xe9, 0x16, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x80, 0x80, 0xff, 0x35, 0x35, 0xff, 0xff, 0x58, 0x58, 0x61, 0xff,
|
||||
0x58, 0x08, 0x00, 0xff, 0x35, 0xca, 0x00, 0xff, 0x00, 0x80, 0x80, 0xff, 0x35, 0x35, 0xff, 0xff, 0xe9, 0xe9, 0xff, 0xff, 0x61, 0x61, 0x61, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x30, 0x30, 0xff, 0x35, 0x35, 0xff, 0xff, 0xe9, 0xe9, 0xff, 0xff, 0x61, 0x61, 0x61, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x58, 0x58, 0x61, 0xff, 0x61, 0x61, 0x61, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 0x0",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
123,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 0, 0),
|
||||
Stride: 0,
|
||||
Pix: []uint8{},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate -90",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
-90,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate -360*10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
-360 * 10,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate -360*10 + 90",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
-360*10 + 90,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate -360*10 + 180",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
-360*10 + 180,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate -360*10 + 270",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
-360*10 + 270,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 360*10",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
360 * 10,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 360*10 + 90",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
360*10 + 90,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 360*10 + 180",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
360*10 + 180,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Rotate 360*10 + 270",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{
|
||||
0xff, 0x00, 0x00, 0xff,
|
||||
0x00, 0xff, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
360*10 + 270,
|
||||
color.Black,
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 2, 1),
|
||||
Stride: 2 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
got := Rotate(test.src, test.angle, test.bg)
|
||||
want := test.want
|
||||
if !compareNRGBA(got, want, 0) {
|
||||
t.Errorf("test [%s] failed: %#v", test.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
92
vendor/github.com/disintegration/imaging/utils.go
сгенерированный
поставляемый
@@ -1,53 +1,38 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// parallel starts parallel image processing based on the current GOMAXPROCS value.
|
||||
// If GOMAXPROCS = 1 it uses no parallelization.
|
||||
// If GOMAXPROCS > 1 it spawns N=GOMAXPROCS workers in separate goroutines.
|
||||
func parallel(dataSize int, fn func(partStart, partEnd int)) {
|
||||
numGoroutines := 1
|
||||
partSize := dataSize
|
||||
|
||||
numProcs := runtime.GOMAXPROCS(0)
|
||||
if numProcs > 1 {
|
||||
numGoroutines = numProcs
|
||||
partSize = dataSize / (numGoroutines * 10)
|
||||
if partSize < 1 {
|
||||
partSize = 1
|
||||
}
|
||||
// parallel processes the data in separate goroutines.
|
||||
func parallel(start, stop int, fn func(<-chan int)) {
|
||||
count := stop - start
|
||||
if count < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
if numGoroutines == 1 {
|
||||
fn(0, dataSize)
|
||||
} else {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numGoroutines)
|
||||
idx := uint64(0)
|
||||
|
||||
for p := 0; p < numGoroutines; p++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
partStart := int(atomic.AddUint64(&idx, uint64(partSize))) - partSize
|
||||
if partStart >= dataSize {
|
||||
break
|
||||
}
|
||||
partEnd := partStart + partSize
|
||||
if partEnd > dataSize {
|
||||
partEnd = dataSize
|
||||
}
|
||||
fn(partStart, partEnd)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
procs := runtime.GOMAXPROCS(0)
|
||||
if procs > count {
|
||||
procs = count
|
||||
}
|
||||
|
||||
c := make(chan int, count)
|
||||
for i := start; i < stop; i++ {
|
||||
c <- i
|
||||
}
|
||||
close(c)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < procs; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
fn(c)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// absint returns the absolute value of i.
|
||||
@@ -69,3 +54,30 @@ func clamp(x float64) uint8 {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func reverse(pix []uint8) {
|
||||
if len(pix) <= 4 {
|
||||
return
|
||||
}
|
||||
i := 0
|
||||
j := len(pix) - 4
|
||||
for i < j {
|
||||
pix[i+0], pix[j+0] = pix[j+0], pix[i+0]
|
||||
pix[i+1], pix[j+1] = pix[j+1], pix[i+1]
|
||||
pix[i+2], pix[j+2] = pix[j+2], pix[i+2]
|
||||
pix[i+3], pix[j+3] = pix[j+3], pix[i+3]
|
||||
i += 4
|
||||
j -= 4
|
||||
}
|
||||
}
|
||||
|
||||
func toNRGBA(img image.Image) *image.NRGBA {
|
||||
if img, ok := img.(*image.NRGBA); ok {
|
||||
return &image.NRGBA{
|
||||
Pix: img.Pix,
|
||||
Stride: img.Stride,
|
||||
Rect: img.Rect.Sub(img.Rect.Min),
|
||||
}
|
||||
}
|
||||
return Clone(img)
|
||||
}
|
||||
|
||||
61
vendor/github.com/disintegration/imaging/utils_test.go
сгенерированный
поставляемый
@@ -1,61 +0,0 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testParallelN(enabled bool, n, procs int) bool {
|
||||
data := make([]bool, n)
|
||||
before := runtime.GOMAXPROCS(0)
|
||||
runtime.GOMAXPROCS(procs)
|
||||
parallel(n, func(start, end int) {
|
||||
for i := start; i < end; i++ {
|
||||
data[i] = true
|
||||
}
|
||||
})
|
||||
for i := 0; i < n; i++ {
|
||||
if !data[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
runtime.GOMAXPROCS(before)
|
||||
return true
|
||||
}
|
||||
|
||||
func TestParallel(t *testing.T) {
|
||||
for _, e := range []bool{true, false} {
|
||||
for _, n := range []int{1, 10, 100, 1000} {
|
||||
for _, p := range []int{1, 2, 4, 8, 16, 100} {
|
||||
if !testParallelN(e, n, p) {
|
||||
t.Errorf("test [parallel %v %d %d] failed", e, n, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClamp(t *testing.T) {
|
||||
td := []struct {
|
||||
f float64
|
||||
u uint8
|
||||
}{
|
||||
{0, 0},
|
||||
{255, 255},
|
||||
{128, 128},
|
||||
{0.49, 0},
|
||||
{0.50, 1},
|
||||
{254.9, 255},
|
||||
{254.0, 254},
|
||||
{256, 255},
|
||||
{2500, 255},
|
||||
{-10, 0},
|
||||
{127.6, 128},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
if clamp(d.f) != d.u {
|
||||
t.Errorf("test [clamp %v %v] failed: %v", d.f, d.u, clamp(d.f))
|
||||
}
|
||||
}
|
||||
}
|
||||