Depenancy upgrades and movign to dep. (#8630)

Этот коммит содержится в:
Christopher Speller
2018-04-16 05:37:14 -07:00
коммит произвёл Joram Wilander
родитель bf24f51c4e
Коммит 6e2cb00008
5345 изменённых файлов: 17051 добавлений и 1634753 удалений

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 @@
[![GoDoc](https://godoc.org/github.com/disintegration/imaging?status.svg)](https://godoc.org/github.com/disintegration/imaging)
[![Build Status](https://travis-ci.org/disintegration/imaging.svg?branch=master)](https://travis-ci.org/disintegration/imaging)
[![Coverage Status](https://coveralls.io/repos/github/disintegration/imaging/badge.svg?branch=master)](https://coveralls.io/github/disintegration/imaging?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/disintegration/imaging/badge.svg?branch=master&service=github)](https://coveralls.io/github/disintegration/imaging?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/disintegration/imaging)](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:
![srcImage](testdata/lena_512.png)
![srcImage](testdata/branches.png)
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
-----------------------------------|----------------------------------------|---------------------------------------
![srcImage](testdata/lena_128.png) | ![dstImage](testdata/out_blur_0.5.png) | ![dstImage](testdata/out_blur_1.5.png)
![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_blur_0.5.png) | ![dstImage](testdata/out_blur_1.5.png)
### Sharpening
@@ -91,7 +88,7 @@ dstImage := imaging.Sharpen(srcImage, 0.5)
Original image | Sigma = 0.5 | Sigma = 1.5
-----------------------------------|-------------------------------------------|------------------------------------------
![srcImage](testdata/lena_128.png) | ![dstImage](testdata/out_sharpen_0.5.png) | ![dstImage](testdata/out_sharpen_1.5.png)
![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_sharpen_0.5.png) | ![dstImage](testdata/out_sharpen_1.5.png)
### Gamma correction
@@ -101,7 +98,7 @@ dstImage := imaging.AdjustGamma(srcImage, 0.75)
Original image | Gamma = 0.75 | Gamma = 1.25
-----------------------------------|------------------------------------------|-----------------------------------------
![srcImage](testdata/lena_128.png) | ![dstImage](testdata/out_gamma_0.75.png) | ![dstImage](testdata/out_gamma_1.25.png)
![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_gamma_0.75.png) | ![dstImage](testdata/out_gamma_1.25.png)
### 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
-----------------------------------|--------------------------------------------|-------------------------------------------
![srcImage](testdata/lena_128.png) | ![dstImage](testdata/out_contrast_p10.png) | ![dstImage](testdata/out_contrast_m10.png)
![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_contrast_p15.png) | ![dstImage](testdata/out_contrast_m15.png)
### Brightness adjustment
@@ -121,7 +118,7 @@ dstImage := imaging.AdjustBrightness(srcImage, 20)
Original image | Brightness = 10 | Brightness = -10
-----------------------------------|----------------------------------------------|---------------------------------------------
![srcImage](testdata/lena_128.png) | ![dstImage](testdata/out_brightness_p10.png) | ![dstImage](testdata/out_brightness_m10.png)
![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_brightness_p10.png) | ![dstImage](testdata/out_brightness_m10.png)
## 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))
}
}
}