Этот коммит содержится в:
Jack
2015-09-23 19:54:07 -07:00
родитель 396a535f10
Коммит f43d355078
46 изменённых файлов: 8 добавлений и 5388 удалений

17
Godeps/Godeps.json сгенерированный
Просмотреть файл

@@ -12,11 +12,6 @@
"Comment": "null-236",
"Rev": "69e2a90ed92d03812364aeb947b7068dc42e561e"
},
{
"ImportPath": "code.google.com/p/graphics-go/graphics",
"Comment": "null-25",
"Rev": "f843bfcd8ac420072c7f6804599995b0a229070b"
},
{
"ImportPath": "code.google.com/p/log4go",
"Comment": "go.weekly.2012-02-22-1",
@@ -31,6 +26,10 @@
"Comment": "0.3.1-2-g5280e25",
"Rev": "5280e250f2795914acbeb2bf3b55dd5a2d1fba52"
},
{
"ImportPath": "github.com/disintegration/imaging",
"Rev": "493653de80c32beeae336f3a3a3a125e7603459b"
},
{
"ImportPath": "github.com/garyburd/redigo/internal",
"Rev": "a47585eaae68b1d14b02940d2af1b9194f3caa9c"
@@ -88,10 +87,6 @@
"Comment": "v0.4.1-2-g35c7f18",
"Rev": "35c7f18f5261cc18c698a461053c119aebaf8542"
},
{
"ImportPath": "github.com/nfnt/resize",
"Rev": "dc93e1b98c579d90ee2fa15c1fd6dac34f6e7899"
},
{
"ImportPath": "github.com/rwcarlsen/goexif/exif",
"Rev": "709fab3d192d7c62f86043caff1e7e3fb0f42bd8"
@@ -136,6 +131,10 @@
"ImportPath": "golang.org/x/image/math/fixed",
"Rev": "baddd3465a05d84a6d8d3507547a91cb188c81ea"
},
{
"ImportPath": "golang.org/x/image/tiff",
"Rev": "baddd3465a05d84a6d8d3507547a91cb188c81ea"
},
{
"ImportPath": "gopkg.in/fsnotify.v1",
"Comment": "v1.2.0",

15
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,15 +0,0 @@
# Copyright 2011 The Graphics-Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=code.google.com/p/graphics-go/graphics
GOFILES=\
affine.go\
blur.go\
rotate.go\
scale.go\
thumbnail.go\
include $(GOROOT)/src/Make.pkg

174
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/affine.go сгенерированный поставляемый
Просмотреть файл

@@ -1,174 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/interp"
"errors"
"image"
"image/draw"
"math"
)
// I is the identity Affine transform matrix.
var I = Affine{
1, 0, 0,
0, 1, 0,
0, 0, 1,
}
// Affine is a 3x3 2D affine transform matrix.
// M(i,j) is Affine[i*3+j].
type Affine [9]float64
// Mul returns the multiplication of two affine transform matrices.
func (a Affine) Mul(b Affine) Affine {
return Affine{
a[0]*b[0] + a[1]*b[3] + a[2]*b[6],
a[0]*b[1] + a[1]*b[4] + a[2]*b[7],
a[0]*b[2] + a[1]*b[5] + a[2]*b[8],
a[3]*b[0] + a[4]*b[3] + a[5]*b[6],
a[3]*b[1] + a[4]*b[4] + a[5]*b[7],
a[3]*b[2] + a[4]*b[5] + a[5]*b[8],
a[6]*b[0] + a[7]*b[3] + a[8]*b[6],
a[6]*b[1] + a[7]*b[4] + a[8]*b[7],
a[6]*b[2] + a[7]*b[5] + a[8]*b[8],
}
}
func (a Affine) transformRGBA(dst *image.RGBA, src *image.RGBA, i interp.RGBA) error {
srcb := src.Bounds()
b := dst.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
sx, sy := a.pt(x, y)
if inBounds(srcb, sx, sy) {
c := i.RGBA(src, sx, sy)
off := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4
dst.Pix[off+0] = c.R
dst.Pix[off+1] = c.G
dst.Pix[off+2] = c.B
dst.Pix[off+3] = c.A
}
}
}
return nil
}
// Transform applies the affine transform to src and produces dst.
func (a Affine) Transform(dst draw.Image, src image.Image, i interp.Interp) error {
if dst == nil {
return errors.New("graphics: dst is nil")
}
if src == nil {
return errors.New("graphics: src is nil")
}
// RGBA fast path.
dstRGBA, dstOk := dst.(*image.RGBA)
srcRGBA, srcOk := src.(*image.RGBA)
interpRGBA, interpOk := i.(interp.RGBA)
if dstOk && srcOk && interpOk {
return a.transformRGBA(dstRGBA, srcRGBA, interpRGBA)
}
srcb := src.Bounds()
b := dst.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
sx, sy := a.pt(x, y)
if inBounds(srcb, sx, sy) {
dst.Set(x, y, i.Interp(src, sx, sy))
}
}
}
return nil
}
func inBounds(b image.Rectangle, x, y float64) bool {
if x < float64(b.Min.X) || x >= float64(b.Max.X) {
return false
}
if y < float64(b.Min.Y) || y >= float64(b.Max.Y) {
return false
}
return true
}
func (a Affine) pt(x0, y0 int) (x1, y1 float64) {
fx := float64(x0) + 0.5
fy := float64(y0) + 0.5
x1 = fx*a[0] + fy*a[1] + a[2]
y1 = fx*a[3] + fy*a[4] + a[5]
return x1, y1
}
// TransformCenter applies the affine transform to src and produces dst.
// Equivalent to
// a.CenterFit(dst, src).Transform(dst, src, i).
func (a Affine) TransformCenter(dst draw.Image, src image.Image, i interp.Interp) error {
if dst == nil {
return errors.New("graphics: dst is nil")
}
if src == nil {
return errors.New("graphics: src is nil")
}
return a.CenterFit(dst.Bounds(), src.Bounds()).Transform(dst, src, i)
}
// Scale produces a scaling transform of factors x and y.
func (a Affine) Scale(x, y float64) Affine {
return a.Mul(Affine{
1 / x, 0, 0,
0, 1 / y, 0,
0, 0, 1,
})
}
// Rotate produces a clockwise rotation transform of angle, in radians.
func (a Affine) Rotate(angle float64) Affine {
s, c := math.Sincos(angle)
return a.Mul(Affine{
+c, +s, +0,
-s, +c, +0,
+0, +0, +1,
})
}
// Shear produces a shear transform by the slopes x and y.
func (a Affine) Shear(x, y float64) Affine {
d := 1 - x*y
return a.Mul(Affine{
+1 / d, -x / d, 0,
-y / d, +1 / d, 0,
0, 0, 1,
})
}
// Translate produces a translation transform with pixel distances x and y.
func (a Affine) Translate(x, y float64) Affine {
return a.Mul(Affine{
1, 0, -x,
0, 1, -y,
0, 0, +1,
})
}
// Center produces the affine transform, centered around the provided point.
func (a Affine) Center(x, y float64) Affine {
return I.Translate(-x, -y).Mul(a).Translate(x, y)
}
// CenterFit produces the affine transform, centered around the rectangles.
// It is equivalent to
// I.Translate(-<center of src>).Mul(a).Translate(<center of dst>)
func (a Affine) CenterFit(dst, src image.Rectangle) Affine {
dx := float64(dst.Min.X) + float64(dst.Dx())/2
dy := float64(dst.Min.Y) + float64(dst.Dy())/2
sx := float64(src.Min.X) + float64(src.Dx())/2
sy := float64(src.Min.Y) + float64(src.Dy())/2
return I.Translate(-sx, -sy).Mul(a).Translate(dx, dy)
}

68
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/blur.go сгенерированный поставляемый
Просмотреть файл

@@ -1,68 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/convolve"
"errors"
"image"
"image/draw"
"math"
)
// DefaultStdDev is the default blurring parameter.
var DefaultStdDev = 0.5
// BlurOptions are the blurring parameters.
// StdDev is the standard deviation of the normal, higher is blurrier.
// Size is the size of the kernel. If zero, it is set to Ceil(6 * StdDev).
type BlurOptions struct {
StdDev float64
Size int
}
// Blur produces a blurred version of the image, using a Gaussian blur.
func Blur(dst draw.Image, src image.Image, opt *BlurOptions) error {
if dst == nil {
return errors.New("graphics: dst is nil")
}
if src == nil {
return errors.New("graphics: src is nil")
}
sd := DefaultStdDev
size := 0
if opt != nil {
sd = opt.StdDev
size = opt.Size
}
if size < 1 {
size = int(math.Ceil(sd * 6))
}
kernel := make([]float64, 2*size+1)
for i := 0; i <= size; i++ {
x := float64(i) / sd
x = math.Pow(1/math.SqrtE, x*x)
kernel[size-i] = x
kernel[size+i] = x
}
// Normalize the weights to sum to 1.0.
kSum := 0.0
for _, k := range kernel {
kSum += k
}
for i, k := range kernel {
kernel[i] = k / kSum
}
return convolve.Convolve(dst, src, &convolve.SeparableKernel{
X: kernel,
Y: kernel,
})
}

207
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/blur_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,207 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"image/color"
"testing"
_ "image/png"
)
var blurOneColorTests = []transformOneColorTest{
{
"1x1-blank", 1, 1, 1, 1,
&BlurOptions{0.83, 1},
[]uint8{0xff},
[]uint8{0xff},
},
{
"1x1-spreadblank", 1, 1, 1, 1,
&BlurOptions{0.83, 2},
[]uint8{0xff},
[]uint8{0xff},
},
{
"3x3-blank", 3, 3, 3, 3,
&BlurOptions{0.83, 2},
[]uint8{
0xff, 0xff, 0xff,
0xff, 0xff, 0xff,
0xff, 0xff, 0xff,
},
[]uint8{
0xff, 0xff, 0xff,
0xff, 0xff, 0xff,
0xff, 0xff, 0xff,
},
},
{
"3x3-dot", 3, 3, 3, 3,
&BlurOptions{0.34, 1},
[]uint8{
0x00, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x03, 0x00,
0x03, 0xf2, 0x03,
0x00, 0x03, 0x00,
},
},
{
"5x5-dot", 5, 5, 5, 5,
&BlurOptions{0.34, 1},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x03, 0xf2, 0x03, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
},
{
"5x5-dot-spread", 5, 5, 5, 5,
&BlurOptions{0.85, 1},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x20, 0x10, 0x00,
0x00, 0x20, 0x40, 0x20, 0x00,
0x00, 0x10, 0x20, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
},
{
"4x4-box", 4, 4, 4, 4,
&BlurOptions{0.34, 1},
[]uint8{
0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x03, 0x03, 0x00,
0x03, 0xf8, 0xf8, 0x03,
0x03, 0xf8, 0xf8, 0x03,
0x00, 0x03, 0x03, 0x00,
},
},
{
"5x5-twodots", 5, 5, 5, 5,
&BlurOptions{0.34, 1},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x96, 0x00, 0x96, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x02, 0x00,
0x02, 0x8e, 0x04, 0x8e, 0x02,
0x00, 0x02, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
},
},
}
func TestBlurOneColor(t *testing.T) {
for _, oc := range blurOneColorTests {
dst := oc.newDst()
src := oc.newSrc()
opt := oc.opt.(*BlurOptions)
if err := Blur(dst, src, opt); err != nil {
t.Fatal(err)
}
if !checkTransformTest(t, &oc, dst) {
continue
}
}
}
func TestBlurEmpty(t *testing.T) {
empty := image.NewRGBA(image.Rect(0, 0, 0, 0))
if err := Blur(empty, empty, nil); err != nil {
t.Fatal(err)
}
}
func TestBlurGopher(t *testing.T) {
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
dst := image.NewRGBA(src.Bounds())
if err = Blur(dst, src, &BlurOptions{StdDev: 1.1}); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-blur.png")
if err != nil {
t.Fatal(err)
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0x101)
if err != nil {
t.Fatal(err)
}
}
func benchBlur(b *testing.B, bounds image.Rectangle) {
b.StopTimer()
// Construct a fuzzy image.
src := image.NewRGBA(bounds)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
src.SetRGBA(x, y, color.RGBA{
uint8(5 * x % 0x100),
uint8(7 * y % 0x100),
uint8((7*x + 5*y) % 0x100),
0xff,
})
}
}
dst := image.NewRGBA(bounds)
b.StartTimer()
for i := 0; i < b.N; i++ {
Blur(dst, src, &BlurOptions{0.84, 3})
}
}
func BenchmarkBlur400x400x3(b *testing.B) {
benchBlur(b, image.Rect(0, 0, 400, 400))
}
// Exactly twice the pixel count of 400x400.
func BenchmarkBlur400x800x3(b *testing.B) {
benchBlur(b, image.Rect(0, 0, 400, 800))
}
// Exactly twice the pixel count of 400x800
func BenchmarkBlur400x1600x3(b *testing.B) {
benchBlur(b, image.Rect(0, 0, 400, 1600))
}

11
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/convolve/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +0,0 @@
# Copyright 2011 The Graphics-Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=code.google.com/p/graphics-go/graphics/convolve
GOFILES=\
convolve.go\
include $(GOROOT)/src/Make.pkg

274
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/convolve/convolve.go сгенерированный поставляемый
Просмотреть файл

@@ -1,274 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package convolve
import (
"errors"
"fmt"
"image"
"image/draw"
"math"
)
// clamp clamps x to the range [x0, x1].
func clamp(x, x0, x1 float64) float64 {
if x < x0 {
return x0
}
if x > x1 {
return x1
}
return x
}
// Kernel is a square matrix that defines a convolution.
type Kernel interface {
// Weights returns the square matrix of weights in row major order.
Weights() []float64
}
// SeparableKernel is a linearly separable, square convolution kernel.
// X and Y are the per-axis weights. Each slice must be the same length, and
// have an odd length. The middle element of each slice is the weight for the
// central pixel. For example, the horizontal Sobel kernel is:
// sobelX := &SeparableKernel{
// X: []float64{-1, 0, +1},
// Y: []float64{1, 2, 1},
// }
type SeparableKernel struct {
X, Y []float64
}
func (k *SeparableKernel) Weights() []float64 {
n := len(k.X)
w := make([]float64, n*n)
for y := 0; y < n; y++ {
for x := 0; x < n; x++ {
w[y*n+x] = k.X[x] * k.Y[y]
}
}
return w
}
// fullKernel is a square convolution kernel.
type fullKernel []float64
func (k fullKernel) Weights() []float64 { return k }
func kernelSize(w []float64) (size int, err error) {
size = int(math.Sqrt(float64(len(w))))
if size*size != len(w) {
return 0, errors.New("graphics: kernel is not square")
}
if size%2 != 1 {
return 0, errors.New("graphics: kernel size is not odd")
}
return size, nil
}
// NewKernel returns a square convolution kernel.
func NewKernel(w []float64) (Kernel, error) {
if _, err := kernelSize(w); err != nil {
return nil, err
}
return fullKernel(w), nil
}
func convolveRGBASep(dst *image.RGBA, src image.Image, k *SeparableKernel) error {
if len(k.X) != len(k.Y) {
return fmt.Errorf("graphics: kernel not square (x %d, y %d)", len(k.X), len(k.Y))
}
if len(k.X)%2 != 1 {
return fmt.Errorf("graphics: kernel length (%d) not odd", len(k.X))
}
radius := (len(k.X) - 1) / 2
// buf holds the result of vertically blurring src.
bounds := dst.Bounds()
width, height := bounds.Dx(), bounds.Dy()
buf := make([]float64, width*height*4)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
var r, g, b, a float64
// k0 is the kernel weight for the center pixel. This may be greater
// than kernel[0], near the boundary of the source image, to avoid
// vignetting.
k0 := k.X[radius]
// Add the pixels from above.
for i := 1; i <= radius; i++ {
f := k.Y[radius-i]
if y-i < bounds.Min.Y {
k0 += f
} else {
or, og, ob, oa := src.At(x, y-i).RGBA()
r += float64(or>>8) * f
g += float64(og>>8) * f
b += float64(ob>>8) * f
a += float64(oa>>8) * f
}
}
// Add the pixels from below.
for i := 1; i <= radius; i++ {
f := k.Y[radius+i]
if y+i >= bounds.Max.Y {
k0 += f
} else {
or, og, ob, oa := src.At(x, y+i).RGBA()
r += float64(or>>8) * f
g += float64(og>>8) * f
b += float64(ob>>8) * f
a += float64(oa>>8) * f
}
}
// Add the central pixel.
or, og, ob, oa := src.At(x, y).RGBA()
r += float64(or>>8) * k0
g += float64(og>>8) * k0
b += float64(ob>>8) * k0
a += float64(oa>>8) * k0
// Write to buf.
o := (y-bounds.Min.Y)*width*4 + (x-bounds.Min.X)*4
buf[o+0] = r
buf[o+1] = g
buf[o+2] = b
buf[o+3] = a
}
}
// dst holds the result of horizontally blurring buf.
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
var r, g, b, a float64
k0, off := k.X[radius], y*width*4+x*4
// Add the pixels from the left.
for i := 1; i <= radius; i++ {
f := k.X[radius-i]
if x-i < 0 {
k0 += f
} else {
o := off - i*4
r += buf[o+0] * f
g += buf[o+1] * f
b += buf[o+2] * f
a += buf[o+3] * f
}
}
// Add the pixels from the right.
for i := 1; i <= radius; i++ {
f := k.X[radius+i]
if x+i >= width {
k0 += f
} else {
o := off + i*4
r += buf[o+0] * f
g += buf[o+1] * f
b += buf[o+2] * f
a += buf[o+3] * f
}
}
// Add the central pixel.
r += buf[off+0] * k0
g += buf[off+1] * k0
b += buf[off+2] * k0
a += buf[off+3] * k0
// Write to dst, clamping to the range [0, 255].
dstOff := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4
dst.Pix[dstOff+0] = uint8(clamp(r+0.5, 0, 255))
dst.Pix[dstOff+1] = uint8(clamp(g+0.5, 0, 255))
dst.Pix[dstOff+2] = uint8(clamp(b+0.5, 0, 255))
dst.Pix[dstOff+3] = uint8(clamp(a+0.5, 0, 255))
}
}
return nil
}
func convolveRGBA(dst *image.RGBA, src image.Image, k Kernel) error {
b := dst.Bounds()
bs := src.Bounds()
w := k.Weights()
size, err := kernelSize(w)
if err != nil {
return err
}
radius := (size - 1) / 2
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
if !image.Pt(x, y).In(bs) {
continue
}
var r, g, b, a, adj float64
for cy := y - radius; cy <= y+radius; cy++ {
for cx := x - radius; cx <= x+radius; cx++ {
factor := w[(cy-y+radius)*size+cx-x+radius]
if !image.Pt(cx, cy).In(bs) {
adj += factor
} else {
sr, sg, sb, sa := src.At(cx, cy).RGBA()
r += float64(sr>>8) * factor
g += float64(sg>>8) * factor
b += float64(sb>>8) * factor
a += float64(sa>>8) * factor
}
}
}
if adj != 0 {
sr, sg, sb, sa := src.At(x, y).RGBA()
r += float64(sr>>8) * adj
g += float64(sg>>8) * adj
b += float64(sb>>8) * adj
a += float64(sa>>8) * adj
}
off := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4
dst.Pix[off+0] = uint8(clamp(r+0.5, 0, 0xff))
dst.Pix[off+1] = uint8(clamp(g+0.5, 0, 0xff))
dst.Pix[off+2] = uint8(clamp(b+0.5, 0, 0xff))
dst.Pix[off+3] = uint8(clamp(a+0.5, 0, 0xff))
}
}
return nil
}
// Convolve produces dst by applying the convolution kernel k to src.
func Convolve(dst draw.Image, src image.Image, k Kernel) (err error) {
if dst == nil || src == nil || k == nil {
return nil
}
b := dst.Bounds()
dstRgba, ok := dst.(*image.RGBA)
if !ok {
dstRgba = image.NewRGBA(b)
}
switch k := k.(type) {
case *SeparableKernel:
err = convolveRGBASep(dstRgba, src, k)
default:
err = convolveRGBA(dstRgba, src, k)
}
if err != nil {
return err
}
if !ok {
draw.Draw(dst, b, dstRgba, b.Min, draw.Src)
}
return nil
}

78
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/convolve/convolve_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,78 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package convolve
import (
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"reflect"
"testing"
_ "image/png"
)
func TestSeparableWeights(t *testing.T) {
sobelXFull := []float64{
-1, 0, 1,
-2, 0, 2,
-1, 0, 1,
}
sobelXSep := &SeparableKernel{
X: []float64{-1, 0, +1},
Y: []float64{1, 2, 1},
}
w := sobelXSep.Weights()
if !reflect.DeepEqual(w, sobelXFull) {
t.Errorf("got %v want %v", w, sobelXFull)
}
}
func TestConvolve(t *testing.T) {
kernFull, err := NewKernel([]float64{
0, 0, 0,
1, 1, 1,
0, 0, 0,
})
if err != nil {
t.Fatal(err)
}
kernSep := &SeparableKernel{
X: []float64{1, 1, 1},
Y: []float64{0, 1, 0},
}
src, err := graphicstest.LoadImage("../../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
b := src.Bounds()
sep := image.NewRGBA(b)
if err = Convolve(sep, src, kernSep); err != nil {
t.Fatal(err)
}
full := image.NewRGBA(b)
Convolve(full, src, kernFull)
err = graphicstest.ImageWithinTolerance(sep, full, 0x101)
if err != nil {
t.Fatal(err)
}
}
func TestConvolveNil(t *testing.T) {
if err := Convolve(nil, nil, nil); err != nil {
t.Fatal(err)
}
}
func TestConvolveEmpty(t *testing.T) {
empty := image.NewRGBA(image.Rect(0, 0, 0, 0))
if err := Convolve(empty, empty, nil); err != nil {
t.Fatal(err)
}
}

15
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,15 +0,0 @@
# Copyright 2011 The Graphics-Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=code.google.com/p/graphics-go/graphics
GOFILES=\
detect.go\
doc.go\
integral.go\
opencv_parser.go\
projector.go\
include $(GOROOT)/src/Make.pkg

133
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect.go сгенерированный поставляемый
Просмотреть файл

@@ -1,133 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
"math"
)
// Feature is a Haar-like feature.
type Feature struct {
Rect image.Rectangle
Weight float64
}
// Classifier is a set of features with a threshold.
type Classifier struct {
Feature []Feature
Threshold float64
Left float64
Right float64
}
// CascadeStage is a cascade of classifiers.
type CascadeStage struct {
Classifier []Classifier
Threshold float64
}
// Cascade is a degenerate tree of Haar-like classifiers.
type Cascade struct {
Stage []CascadeStage
Size image.Point
}
// Match returns true if the full image is classified as an object.
func (c *Cascade) Match(m image.Image) bool {
return c.classify(newWindow(m))
}
// Find returns a set of areas of m that match the feature cascade c.
func (c *Cascade) Find(m image.Image) []image.Rectangle {
// TODO(crawshaw): Consider de-duping strategies.
matches := []image.Rectangle{}
w := newWindow(m)
b := m.Bounds()
origScale := c.Size
for s := origScale; s.X < b.Dx() && s.Y < b.Dy(); s = s.Add(s.Div(10)) {
// translate region and classify
tx := image.Pt(s.X/10, 0)
ty := image.Pt(0, s.Y/10)
for r := image.Rect(0, 0, s.X, s.Y).Add(b.Min); r.In(b); r = r.Add(ty) {
for r1 := r; r1.In(b); r1 = r1.Add(tx) {
if c.classify(w.subWindow(r1)) {
matches = append(matches, r1)
}
}
}
}
return matches
}
type window struct {
mi *integral
miSq *integral
rect image.Rectangle
invArea float64
stdDev float64
}
func (w *window) init() {
w.invArea = 1 / float64(w.rect.Dx()*w.rect.Dy())
mean := float64(w.mi.sum(w.rect)) * w.invArea
vr := float64(w.miSq.sum(w.rect))*w.invArea - mean*mean
if vr < 0 {
vr = 1
}
w.stdDev = math.Sqrt(vr)
}
func newWindow(m image.Image) *window {
mi, miSq := newIntegrals(m)
res := &window{
mi: mi,
miSq: miSq,
rect: m.Bounds(),
}
res.init()
return res
}
func (w *window) subWindow(r image.Rectangle) *window {
res := &window{
mi: w.mi,
miSq: w.miSq,
rect: r,
}
res.init()
return res
}
func (c *Classifier) classify(w *window, pr *projector) float64 {
s := 0.0
for _, f := range c.Feature {
s += float64(w.mi.sum(pr.rect(f.Rect))) * f.Weight
}
s *= w.invArea // normalize to maintain scale invariance
if s < c.Threshold*w.stdDev {
return c.Left
}
return c.Right
}
func (s *CascadeStage) classify(w *window, pr *projector) bool {
sum := 0.0
for _, c := range s.Classifier {
sum += c.classify(w, pr)
}
return sum >= s.Threshold
}
func (c *Cascade) classify(w *window) bool {
pr := newProjector(w.rect, image.Rectangle{image.Pt(0, 0), c.Size})
for _, s := range c.Stage {
if !s.classify(w, pr) {
return false
}
}
return true
}

77
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/detect_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,77 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
"image/draw"
"testing"
)
var (
c0 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(0, 0, 3, 4), Weight: 4.0},
},
Threshold: 0.2,
Left: 0.8,
Right: 0.2,
}
c1 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(3, 4, 4, 5), Weight: 4.0},
},
Threshold: 0.2,
Left: 0.8,
Right: 0.2,
}
c2 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(0, 0, 1, 1), Weight: +4.0},
Feature{Rect: image.Rect(0, 0, 2, 2), Weight: -1.0},
},
Threshold: 0.2,
Left: 0.8,
Right: 0.2,
}
)
func TestClassifier(t *testing.T) {
m := image.NewGray(image.Rect(0, 0, 20, 20))
b := m.Bounds()
draw.Draw(m, image.Rect(0, 0, 20, 20), image.White, image.ZP, draw.Src)
draw.Draw(m, image.Rect(3, 4, 4, 5), image.Black, image.ZP, draw.Src)
w := newWindow(m)
pr := newProjector(b, b)
if res := c0.classify(w, pr); res != c0.Right {
t.Errorf("c0 got %f want %f", res, c0.Right)
}
if res := c1.classify(w, pr); res != c1.Left {
t.Errorf("c1 got %f want %f", res, c1.Left)
}
if res := c2.classify(w, pr); res != c1.Left {
t.Errorf("c2 got %f want %f", res, c1.Left)
}
}
func TestClassifierScale(t *testing.T) {
m := image.NewGray(image.Rect(0, 0, 50, 50))
b := m.Bounds()
draw.Draw(m, image.Rect(0, 0, 8, 10), image.White, b.Min, draw.Src)
draw.Draw(m, image.Rect(8, 10, 10, 13), image.Black, b.Min, draw.Src)
w := newWindow(m)
pr := newProjector(b, image.Rect(0, 0, 20, 20))
if res := c0.classify(w, pr); res != c0.Right {
t.Errorf("scaled c0 got %f want %f", res, c0.Right)
}
if res := c1.classify(w, pr); res != c1.Left {
t.Errorf("scaled c1 got %f want %f", res, c1.Left)
}
if res := c2.classify(w, pr); res != c1.Left {
t.Errorf("scaled c2 got %f want %f", res, c1.Left)
}
}

31
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -1,31 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package detect implements an object detector cascade.
The technique used is a degenerate tree of Haar-like classifiers, commonly
used for face detection. It is described in
P. Viola, M. Jones.
Rapid Object Detection using a Boosted Cascade of Simple Features, 2001
IEEE Conference on Computer Vision and Pattern Recognition
A Cascade can be constructed manually from a set of Classifiers in stages,
or can be loaded from an XML file in the OpenCV format with
classifier, _, err := detect.ParseOpenCV(r)
The classifier can be used to determine if a full image is detected as an
object using Detect
if classifier.Match(m) {
// m is an image of a face.
}
It is also possible to search an image for occurrences of an object
objs := classifier.Find(m)
*/
package detect

93
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/integral.go сгенерированный поставляемый
Просмотреть файл

@@ -1,93 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
"image/draw"
)
// integral is an image.Image-like structure that stores the cumulative
// sum of the preceding pixels. This allows for O(1) summation of any
// rectangular region within the image.
type integral struct {
// pix holds the cumulative sum of the image's pixels. The pixel at
// (x, y) starts at pix[(y-rect.Min.Y)*stride + (x-rect.Min.X)*1].
pix []uint64
stride int
rect image.Rectangle
}
func (p *integral) at(x, y int) uint64 {
return p.pix[(y-p.rect.Min.Y)*p.stride+(x-p.rect.Min.X)]
}
func (p *integral) sum(b image.Rectangle) uint64 {
c := p.at(b.Max.X-1, b.Max.Y-1)
inY := b.Min.Y > p.rect.Min.Y
inX := b.Min.X > p.rect.Min.X
if inY && inX {
c += p.at(b.Min.X-1, b.Min.Y-1)
}
if inY {
c -= p.at(b.Max.X-1, b.Min.Y-1)
}
if inX {
c -= p.at(b.Min.X-1, b.Max.Y-1)
}
return c
}
func (m *integral) integrate() {
b := m.rect
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
c := uint64(0)
if y > b.Min.Y && x > b.Min.X {
c += m.at(x-1, y)
c += m.at(x, y-1)
c -= m.at(x-1, y-1)
} else if y > b.Min.Y {
c += m.at(b.Min.X, y-1)
} else if x > b.Min.X {
c += m.at(x-1, b.Min.Y)
}
m.pix[(y-m.rect.Min.Y)*m.stride+(x-m.rect.Min.X)] += c
}
}
}
// newIntegrals returns the integral and the squared integral.
func newIntegrals(src image.Image) (*integral, *integral) {
b := src.Bounds()
srcg, ok := src.(*image.Gray)
if !ok {
srcg = image.NewGray(b)
draw.Draw(srcg, b, src, b.Min, draw.Src)
}
m := integral{
pix: make([]uint64, b.Max.Y*b.Max.X),
stride: b.Max.X,
rect: b,
}
mSq := integral{
pix: make([]uint64, b.Max.Y*b.Max.X),
stride: b.Max.X,
rect: b,
}
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
os := (y-b.Min.Y)*srcg.Stride + x - b.Min.X
om := (y-b.Min.Y)*m.stride + x - b.Min.X
c := uint64(srcg.Pix[os])
m.pix[om] = c
mSq.pix[om] = c * c
}
}
m.integrate()
mSq.integrate()
return &m, &mSq
}

156
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/integral_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,156 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"bytes"
"fmt"
"image"
"testing"
)
type integralTest struct {
x int
y int
src []uint8
res []uint8
}
var integralTests = []integralTest{
{
1, 1,
[]uint8{0x01},
[]uint8{0x01},
},
{
2, 2,
[]uint8{
0x01, 0x02,
0x03, 0x04,
},
[]uint8{
0x01, 0x03,
0x04, 0x0a,
},
},
{
4, 4,
[]uint8{
0x02, 0x03, 0x00, 0x01,
0x01, 0x02, 0x01, 0x05,
0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
},
[]uint8{
0x02, 0x05, 0x05, 0x06,
0x03, 0x08, 0x09, 0x0f,
0x04, 0x0a, 0x0c, 0x13,
0x05, 0x0c, 0x0f, 0x17,
},
},
}
func sprintBox(box []byte, width, height int) string {
buf := bytes.NewBuffer(nil)
i := 0
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
fmt.Fprintf(buf, " 0x%02x,", box[i])
i++
}
buf.WriteByte('\n')
}
return buf.String()
}
func TestIntegral(t *testing.T) {
for i, oc := range integralTests {
src := &image.Gray{
Pix: oc.src,
Stride: oc.x,
Rect: image.Rect(0, 0, oc.x, oc.y),
}
dst, _ := newIntegrals(src)
res := make([]byte, len(dst.pix))
for i, p := range dst.pix {
res[i] = byte(p)
}
if !bytes.Equal(res, oc.res) {
got := sprintBox(res, oc.x, oc.y)
want := sprintBox(oc.res, oc.x, oc.y)
t.Errorf("%d: got\n%s\n want\n%s", i, got, want)
}
}
}
func TestIntegralSum(t *testing.T) {
src := &image.Gray{
Pix: []uint8{
0x02, 0x03, 0x00, 0x01, 0x03,
0x01, 0x02, 0x01, 0x05, 0x05,
0x01, 0x01, 0x01, 0x01, 0x02,
0x01, 0x01, 0x01, 0x01, 0x07,
0x02, 0x01, 0x00, 0x03, 0x01,
},
Stride: 5,
Rect: image.Rect(0, 0, 5, 5),
}
img, _ := newIntegrals(src)
type sumTest struct {
rect image.Rectangle
sum uint64
}
var sumTests = []sumTest{
{image.Rect(0, 0, 1, 1), 2},
{image.Rect(0, 0, 2, 1), 5},
{image.Rect(0, 0, 1, 3), 4},
{image.Rect(1, 1, 3, 3), 5},
{image.Rect(2, 2, 4, 4), 4},
{image.Rect(4, 3, 5, 5), 8},
{image.Rect(2, 4, 3, 5), 0},
}
for _, st := range sumTests {
s := img.sum(st.rect)
if s != st.sum {
t.Errorf("%v: got %d want %d", st.rect, s, st.sum)
return
}
}
}
func TestIntegralSubImage(t *testing.T) {
m0 := &image.Gray{
Pix: []uint8{
0x02, 0x03, 0x00, 0x01, 0x03,
0x01, 0x02, 0x01, 0x05, 0x05,
0x01, 0x04, 0x01, 0x01, 0x02,
0x01, 0x02, 0x01, 0x01, 0x07,
0x02, 0x01, 0x09, 0x03, 0x01,
},
Stride: 5,
Rect: image.Rect(0, 0, 5, 5),
}
b := image.Rect(1, 1, 4, 4)
m1 := m0.SubImage(b)
mi0, _ := newIntegrals(m0)
mi1, _ := newIntegrals(m1)
sum0 := mi0.sum(b)
sum1 := mi1.sum(b)
if sum0 != sum1 {
t.Errorf("b got %d want %d", sum0, sum1)
}
r0 := image.Rect(2, 2, 4, 4)
sum0 = mi0.sum(r0)
sum1 = mi1.sum(r0)
if sum0 != sum1 {
t.Errorf("r0 got %d want %d", sum1, sum0)
}
}

125
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/opencv_parser.go сгенерированный поставляемый
Просмотреть файл

@@ -1,125 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"image"
"io"
"io/ioutil"
"strconv"
"strings"
)
type xmlFeature struct {
Rects []string `xml:"grp>feature>rects>grp"`
Tilted int `xml:"grp>feature>tilted"`
Threshold float64 `xml:"grp>threshold"`
Left float64 `xml:"grp>left_val"`
Right float64 `xml:"grp>right_val"`
}
type xmlStages struct {
Trees []xmlFeature `xml:"trees>grp"`
Stage_threshold float64 `xml:"stage_threshold"`
Parent int `xml:"parent"`
Next int `xml:"next"`
}
type opencv_storage struct {
Any struct {
XMLName xml.Name
Type string `xml:"type_id,attr"`
Size string `xml:"size"`
Stages []xmlStages `xml:"stages>grp"`
} `xml:",any"`
}
func buildFeature(r string) (f Feature, err error) {
var x, y, w, h int
var weight float64
_, err = fmt.Sscanf(r, "%d %d %d %d %f", &x, &y, &w, &h, &weight)
if err != nil {
return
}
f.Rect = image.Rect(x, y, x+w, y+h)
f.Weight = weight
return
}
func buildCascade(s *opencv_storage) (c *Cascade, name string, err error) {
if s.Any.Type != "opencv-haar-classifier" {
err = fmt.Errorf("got %s want opencv-haar-classifier", s.Any.Type)
return
}
name = s.Any.XMLName.Local
c = &Cascade{}
sizes := strings.Split(s.Any.Size, " ")
w, err := strconv.Atoi(sizes[0])
if err != nil {
return nil, "", err
}
h, err := strconv.Atoi(sizes[1])
if err != nil {
return nil, "", err
}
c.Size = image.Pt(w, h)
c.Stage = []CascadeStage{}
for _, stage := range s.Any.Stages {
cs := CascadeStage{
Classifier: []Classifier{},
Threshold: stage.Stage_threshold,
}
for _, tree := range stage.Trees {
if tree.Tilted != 0 {
err = errors.New("Cascade does not support tilted features")
return
}
cls := Classifier{
Feature: []Feature{},
Threshold: tree.Threshold,
Left: tree.Left,
Right: tree.Right,
}
for _, rect := range tree.Rects {
f, err := buildFeature(rect)
if err != nil {
return nil, "", err
}
cls.Feature = append(cls.Feature, f)
}
cs.Classifier = append(cs.Classifier, cls)
}
c.Stage = append(c.Stage, cs)
}
return
}
// ParseOpenCV produces a detection Cascade from an OpenCV XML file.
func ParseOpenCV(r io.Reader) (cascade *Cascade, name string, err error) {
// BUG(crawshaw): tag-based parsing doesn't seem to work with <_>
buf, err := ioutil.ReadAll(r)
if err != nil {
return
}
buf = bytes.Replace(buf, []byte("<_>"), []byte("<grp>"), -1)
buf = bytes.Replace(buf, []byte("</_>"), []byte("</grp>"), -1)
s := &opencv_storage{}
err = xml.Unmarshal(buf, s)
if err != nil {
return
}
return buildCascade(s)
}

75
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/opencv_parser_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,75 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
"os"
"reflect"
"testing"
)
var (
classifier0 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(0, 0, 3, 4), Weight: -1},
Feature{Rect: image.Rect(3, 4, 5, 6), Weight: 3.1},
},
Threshold: 0.03,
Left: 0.01,
Right: 0.8,
}
classifier1 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(3, 7, 17, 11), Weight: -3.2},
Feature{Rect: image.Rect(3, 9, 17, 11), Weight: 2.},
},
Threshold: 0.11,
Left: 0.03,
Right: 0.83,
}
classifier2 = Classifier{
Feature: []Feature{
Feature{Rect: image.Rect(1, 1, 3, 3), Weight: -1.},
Feature{Rect: image.Rect(3, 3, 5, 5), Weight: 2.5},
},
Threshold: 0.07,
Left: 0.2,
Right: 0.4,
}
cascade = Cascade{
Stage: []CascadeStage{
CascadeStage{
Classifier: []Classifier{classifier0, classifier1},
Threshold: 0.82,
},
CascadeStage{
Classifier: []Classifier{classifier2},
Threshold: 0.22,
},
},
Size: image.Pt(20, 20),
}
)
func TestParseOpenCV(t *testing.T) {
file, err := os.Open("../../testdata/opencv.xml")
if err != nil {
t.Fatal(err)
}
defer file.Close()
cascadeFile, name, err := ParseOpenCV(file)
if err != nil {
t.Fatal(err)
}
if name != "name_of_cascade" {
t.Fatalf("name: got %s want name_of_cascade", name)
}
if !reflect.DeepEqual(cascade, *cascadeFile) {
t.Errorf("got\n %v want\n %v", *cascadeFile, cascade)
}
}

55
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/projector.go сгенерированный поставляемый
Просмотреть файл

@@ -1,55 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
)
// projector allows projecting from a source Rectangle onto a target Rectangle.
type projector struct {
// rx, ry is the scaling factor.
rx, ry float64
// dx, dy is the translation factor.
dx, dy float64
// r is the clipping region of the target.
r image.Rectangle
}
// newProjector creates a Projector with source src and target dst.
func newProjector(dst image.Rectangle, src image.Rectangle) *projector {
return &projector{
rx: float64(dst.Dx()) / float64(src.Dx()),
ry: float64(dst.Dy()) / float64(src.Dy()),
dx: float64(dst.Min.X - src.Min.X),
dy: float64(dst.Min.Y - src.Min.Y),
r: dst,
}
}
// pt projects p from the source rectangle onto the target rectangle.
func (s *projector) pt(p image.Point) image.Point {
return image.Point{
clamp(s.rx*float64(p.X)+s.dx, s.r.Min.X, s.r.Max.X),
clamp(s.ry*float64(p.Y)+s.dy, s.r.Min.Y, s.r.Max.Y),
}
}
// rect projects r from the source rectangle onto the target rectangle.
func (s *projector) rect(r image.Rectangle) image.Rectangle {
return image.Rectangle{s.pt(r.Min), s.pt(r.Max)}
}
// clamp rounds and clamps o to the integer range [x0, x1].
func clamp(o float64, x0, x1 int) int {
x := int(o + 0.5)
if x < x0 {
return x0
}
if x > x1 {
return x1
}
return x
}

49
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/detect/projector_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,49 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package detect
import (
"image"
"reflect"
"testing"
)
type projectorTest struct {
dst image.Rectangle
src image.Rectangle
pdst image.Rectangle
psrc image.Rectangle
}
var projectorTests = []projectorTest{
{
image.Rect(0, 0, 6, 6),
image.Rect(0, 0, 2, 2),
image.Rect(0, 0, 6, 6),
image.Rect(0, 0, 2, 2),
},
{
image.Rect(0, 0, 6, 6),
image.Rect(0, 0, 2, 2),
image.Rect(3, 3, 6, 6),
image.Rect(1, 1, 2, 2),
},
{
image.Rect(30, 30, 40, 40),
image.Rect(10, 10, 20, 20),
image.Rect(32, 33, 34, 37),
image.Rect(12, 13, 14, 17),
},
}
func TestProjector(t *testing.T) {
for i, tt := range projectorTests {
pr := newProjector(tt.dst, tt.src)
res := pr.rect(tt.psrc)
if !reflect.DeepEqual(res, tt.pdst) {
t.Errorf("%d: got %v want %v", i, res, tt.pdst)
}
}
}

11
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/graphicstest/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,11 +0,0 @@
# Copyright 2011 The Graphics-Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=code.google.com/p/graphics-go/graphics/graphicstest
GOFILES=\
graphicstest.go\
include $(GOROOT)/src/Make.pkg

112
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/graphicstest/graphicstest.go сгенерированный поставляемый
Просмотреть файл

@@ -1,112 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphicstest
import (
"bytes"
"errors"
"fmt"
"image"
"image/color"
"os"
)
// LoadImage decodes an image from a file.
func LoadImage(path string) (img image.Image, err error) {
file, err := os.Open(path)
if err != nil {
return
}
defer file.Close()
img, _, err = image.Decode(file)
return
}
func delta(u0, u1 uint32) int {
d := int(u0) - int(u1)
if d < 0 {
return -d
}
return d
}
func withinTolerance(c0, c1 color.Color, tol int) bool {
r0, g0, b0, a0 := c0.RGBA()
r1, g1, b1, a1 := c1.RGBA()
r := delta(r0, r1)
g := delta(g0, g1)
b := delta(b0, b1)
a := delta(a0, a1)
return r <= tol && g <= tol && b <= tol && a <= tol
}
// ImageWithinTolerance checks that each pixel varies by no more than tol.
func ImageWithinTolerance(m0, m1 image.Image, tol int) error {
b0 := m0.Bounds()
b1 := m1.Bounds()
if !b0.Eq(b1) {
return errors.New(fmt.Sprintf("got bounds %v want %v", b0, b1))
}
for y := b0.Min.Y; y < b0.Max.Y; y++ {
for x := b0.Min.X; x < b0.Max.X; x++ {
c0 := m0.At(x, y)
c1 := m1.At(x, y)
if !withinTolerance(c0, c1, tol) {
e := fmt.Sprintf("got %v want %v at (%d, %d)", c0, c1, x, y)
return errors.New(e)
}
}
}
return nil
}
// SprintBox pretty prints the array as a hexidecimal matrix.
func SprintBox(box []byte, width, height int) string {
buf := bytes.NewBuffer(nil)
i := 0
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
fmt.Fprintf(buf, " 0x%02x,", box[i])
i++
}
buf.WriteByte('\n')
}
return buf.String()
}
// SprintImageR pretty prints the red channel of src. It looks like SprintBox.
func SprintImageR(src *image.RGBA) string {
w, h := src.Rect.Dx(), src.Rect.Dy()
i := 0
box := make([]byte, w*h)
for y := src.Rect.Min.Y; y < src.Rect.Max.Y; y++ {
for x := src.Rect.Min.X; x < src.Rect.Max.X; x++ {
off := (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4
box[i] = src.Pix[off]
i++
}
}
return SprintBox(box, w, h)
}
// MakeRGBA returns an image with R, G, B taken from src.
func MakeRGBA(src []uint8, width int) *image.RGBA {
b := image.Rect(0, 0, width, len(src)/width)
ret := image.NewRGBA(b)
i := 0
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
ret.SetRGBA(x, y, color.RGBA{
R: src[i],
G: src[i],
B: src[i],
A: 0xff,
})
i++
}
}
return ret
}

13
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/Makefile сгенерированный поставляемый
Просмотреть файл

@@ -1,13 +0,0 @@
# Copyright 2012 The Graphics-Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include $(GOROOT)/src/Make.inc
TARG=code.google.com/p/graphics-go/graphics/interp
GOFILES=\
bilinear.go\
doc.go\
interp.go\
include $(GOROOT)/src/Make.pkg

206
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear.go сгенерированный поставляемый
Просмотреть файл

@@ -1,206 +0,0 @@
// Copyright 2012 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
import (
"image"
"image/color"
"math"
)
// Bilinear implements bilinear interpolation.
var Bilinear Interp = bilinear{}
type bilinear struct{}
func (i bilinear) Interp(src image.Image, x, y float64) color.Color {
if src, ok := src.(*image.RGBA); ok {
return i.RGBA(src, x, y)
}
return bilinearGeneral(src, x, y)
}
func bilinearGeneral(src image.Image, x, y float64) color.Color {
p := findLinearSrc(src.Bounds(), x, y)
var fr, fg, fb, fa float64
var r, g, b, a uint32
r, g, b, a = src.At(p.low.X, p.low.Y).RGBA()
fr += float64(r) * p.frac00
fg += float64(g) * p.frac00
fb += float64(b) * p.frac00
fa += float64(a) * p.frac00
r, g, b, a = src.At(p.high.X, p.low.Y).RGBA()
fr += float64(r) * p.frac01
fg += float64(g) * p.frac01
fb += float64(b) * p.frac01
fa += float64(a) * p.frac01
r, g, b, a = src.At(p.low.X, p.high.Y).RGBA()
fr += float64(r) * p.frac10
fg += float64(g) * p.frac10
fb += float64(b) * p.frac10
fa += float64(a) * p.frac10
r, g, b, a = src.At(p.high.X, p.high.Y).RGBA()
fr += float64(r) * p.frac11
fg += float64(g) * p.frac11
fb += float64(b) * p.frac11
fa += float64(a) * p.frac11
var c color.RGBA64
c.R = uint16(fr + 0.5)
c.G = uint16(fg + 0.5)
c.B = uint16(fb + 0.5)
c.A = uint16(fa + 0.5)
return c
}
func (bilinear) RGBA(src *image.RGBA, x, y float64) color.RGBA {
p := findLinearSrc(src.Bounds(), x, y)
// Array offsets for the surrounding pixels.
off00 := offRGBA(src, p.low.X, p.low.Y)
off01 := offRGBA(src, p.high.X, p.low.Y)
off10 := offRGBA(src, p.low.X, p.high.Y)
off11 := offRGBA(src, p.high.X, p.high.Y)
var fr, fg, fb, fa float64
fr += float64(src.Pix[off00+0]) * p.frac00
fg += float64(src.Pix[off00+1]) * p.frac00
fb += float64(src.Pix[off00+2]) * p.frac00
fa += float64(src.Pix[off00+3]) * p.frac00
fr += float64(src.Pix[off01+0]) * p.frac01
fg += float64(src.Pix[off01+1]) * p.frac01
fb += float64(src.Pix[off01+2]) * p.frac01
fa += float64(src.Pix[off01+3]) * p.frac01
fr += float64(src.Pix[off10+0]) * p.frac10
fg += float64(src.Pix[off10+1]) * p.frac10
fb += float64(src.Pix[off10+2]) * p.frac10
fa += float64(src.Pix[off10+3]) * p.frac10
fr += float64(src.Pix[off11+0]) * p.frac11
fg += float64(src.Pix[off11+1]) * p.frac11
fb += float64(src.Pix[off11+2]) * p.frac11
fa += float64(src.Pix[off11+3]) * p.frac11
var c color.RGBA
c.R = uint8(fr + 0.5)
c.G = uint8(fg + 0.5)
c.B = uint8(fb + 0.5)
c.A = uint8(fa + 0.5)
return c
}
func (bilinear) Gray(src *image.Gray, x, y float64) color.Gray {
p := findLinearSrc(src.Bounds(), x, y)
// Array offsets for the surrounding pixels.
off00 := offGray(src, p.low.X, p.low.Y)
off01 := offGray(src, p.high.X, p.low.Y)
off10 := offGray(src, p.low.X, p.high.Y)
off11 := offGray(src, p.high.X, p.high.Y)
var fc float64
fc += float64(src.Pix[off00]) * p.frac00
fc += float64(src.Pix[off01]) * p.frac01
fc += float64(src.Pix[off10]) * p.frac10
fc += float64(src.Pix[off11]) * p.frac11
var c color.Gray
c.Y = uint8(fc + 0.5)
return c
}
type bilinearSrc struct {
// Top-left and bottom-right interpolation sources
low, high image.Point
// Fraction of each pixel to take. The 0 suffix indicates
// top/left, and the 1 suffix indicates bottom/right.
frac00, frac01, frac10, frac11 float64
}
func findLinearSrc(b image.Rectangle, sx, sy float64) bilinearSrc {
maxX := float64(b.Max.X)
maxY := float64(b.Max.Y)
minX := float64(b.Min.X)
minY := float64(b.Min.Y)
lowX := math.Floor(sx - 0.5)
lowY := math.Floor(sy - 0.5)
if lowX < minX {
lowX = minX
}
if lowY < minY {
lowY = minY
}
highX := math.Ceil(sx - 0.5)
highY := math.Ceil(sy - 0.5)
if highX >= maxX {
highX = maxX - 1
}
if highY >= maxY {
highY = maxY - 1
}
// In the variables below, the 0 suffix indicates top/left, and the
// 1 suffix indicates bottom/right.
// Center of each surrounding pixel.
x00 := lowX + 0.5
y00 := lowY + 0.5
x01 := highX + 0.5
y01 := lowY + 0.5
x10 := lowX + 0.5
y10 := highY + 0.5
x11 := highX + 0.5
y11 := highY + 0.5
p := bilinearSrc{
low: image.Pt(int(lowX), int(lowY)),
high: image.Pt(int(highX), int(highY)),
}
// Literally, edge cases. If we are close enough to the edge of
// the image, curtail the interpolation sources.
if lowX == highX && lowY == highY {
p.frac00 = 1.0
} else if sy-minY <= 0.5 && sx-minX <= 0.5 {
p.frac00 = 1.0
} else if maxY-sy <= 0.5 && maxX-sx <= 0.5 {
p.frac11 = 1.0
} else if sy-minY <= 0.5 || lowY == highY {
p.frac00 = x01 - sx
p.frac01 = sx - x00
} else if sx-minX <= 0.5 || lowX == highX {
p.frac00 = y10 - sy
p.frac10 = sy - y00
} else if maxY-sy <= 0.5 {
p.frac10 = x11 - sx
p.frac11 = sx - x10
} else if maxX-sx <= 0.5 {
p.frac01 = y11 - sy
p.frac11 = sy - y01
} else {
p.frac00 = (x01 - sx) * (y10 - sy)
p.frac01 = (sx - x00) * (y11 - sy)
p.frac10 = (x11 - sx) * (sy - y00)
p.frac11 = (sx - x10) * (sy - y01)
}
return p
}
// TODO(crawshaw): When we have inlining, consider func (p *RGBA) Off(x, y) int
func offRGBA(src *image.RGBA, x, y int) int {
return (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4
}
func offGray(src *image.Gray, x, y int) int {
return (y-src.Rect.Min.Y)*src.Stride + (x - src.Rect.Min.X)
}

143
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/bilinear_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,143 +0,0 @@
// Copyright 2012 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
import (
"image"
"image/color"
"testing"
)
type interpTest struct {
desc string
src []uint8
srcWidth int
x, y float64
expect uint8
}
func (p *interpTest) newSrc() *image.RGBA {
b := image.Rect(0, 0, p.srcWidth, len(p.src)/p.srcWidth)
src := image.NewRGBA(b)
i := 0
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
src.SetRGBA(x, y, color.RGBA{
R: p.src[i],
G: p.src[i],
B: p.src[i],
A: 0xff,
})
i++
}
}
return src
}
var interpTests = []interpTest{
{
desc: "center of a single white pixel should match that pixel",
src: []uint8{0x00},
srcWidth: 1,
x: 0.5,
y: 0.5,
expect: 0x00,
},
{
desc: "middle of a square is equally weighted",
src: []uint8{
0x00, 0xff,
0xff, 0x00,
},
srcWidth: 2,
x: 1.0,
y: 1.0,
expect: 0x80,
},
{
desc: "center of a pixel is just that pixel",
src: []uint8{
0x00, 0xff,
0xff, 0x00,
},
srcWidth: 2,
x: 1.5,
y: 0.5,
expect: 0xff,
},
{
desc: "asymmetry abounds",
src: []uint8{
0xaa, 0x11, 0x55,
0xff, 0x95, 0xdd,
},
srcWidth: 3,
x: 2.0,
y: 1.0,
expect: 0x76, // (0x11 + 0x55 + 0x95 + 0xdd) / 4
},
}
func TestBilinearRGBA(t *testing.T) {
for _, p := range interpTests {
src := p.newSrc()
// Fast path.
c := Bilinear.(RGBA).RGBA(src, p.x, p.y)
if c.R != c.G || c.R != c.B || c.A != 0xff {
t.Errorf("expect channels to match, got %v", c)
continue
}
if c.R != p.expect {
t.Errorf("%s: got 0x%02x want 0x%02x", p.desc, c.R, p.expect)
continue
}
// Standard Interp should use the fast path.
cStd := Bilinear.Interp(src, p.x, p.y)
if cStd != c {
t.Errorf("%s: standard mismatch got %v want %v", p.desc, cStd, c)
continue
}
// General case should match the fast path.
cGen := color.RGBAModel.Convert(bilinearGeneral(src, p.x, p.y))
r0, g0, b0, a0 := c.RGBA()
r1, g1, b1, a1 := cGen.RGBA()
if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
t.Errorf("%s: general case mismatch got %v want %v", p.desc, c, cGen)
continue
}
}
}
func TestBilinearSubImage(t *testing.T) {
b0 := image.Rect(0, 0, 4, 4)
src0 := image.NewRGBA(b0)
b1 := image.Rect(1, 1, 3, 3)
src1 := src0.SubImage(b1).(*image.RGBA)
src1.Set(1, 1, color.RGBA{0x11, 0, 0, 0xff})
src1.Set(2, 1, color.RGBA{0x22, 0, 0, 0xff})
src1.Set(1, 2, color.RGBA{0x33, 0, 0, 0xff})
src1.Set(2, 2, color.RGBA{0x44, 0, 0, 0xff})
tests := []struct {
x, y float64
want uint8
}{
{1, 1, 0x11},
{3, 1, 0x22},
{1, 3, 0x33},
{3, 3, 0x44},
{2, 2, 0x2b},
}
for _, p := range tests {
c := Bilinear.(RGBA).RGBA(src1, p.x, p.y)
if c.R != p.want {
t.Errorf("(%.0f, %.0f): got 0x%02x want 0x%02x", p.x, p.y, c.R, p.want)
}
}
}

25
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -1,25 +0,0 @@
// Copyright 2012 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package interp implements image interpolation.
An interpolator provides the Interp interface, which can be used
to interpolate a pixel:
c := interp.Bilinear.Interp(src, 1.2, 1.8)
To interpolate a large number of RGBA or Gray pixels, an implementation
may provide a fast-path by implementing the RGBA or Gray interfaces.
i1, ok := i.(interp.RGBA)
if ok {
c := i1.RGBA(src, 1.2, 1.8)
// use c.R, c.G, etc
return
}
c := i.Interp(src, 1.2, 1.8)
// use generic color.Color
*/
package interp

29
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/interp/interp.go сгенерированный поставляемый
Просмотреть файл

@@ -1,29 +0,0 @@
// Copyright 2012 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
import (
"image"
"image/color"
)
// Interp interpolates an image's color at fractional co-ordinates.
type Interp interface {
// Interp interpolates (x, y).
Interp(src image.Image, x, y float64) color.Color
}
// RGBA is a fast-path interpolation implementation for image.RGBA.
// It is common for an Interp to also implement RGBA.
type RGBA interface {
// RGBA interpolates (x, y).
RGBA(src *image.RGBA, x, y float64) color.RGBA
}
// Gray is a fast-path interpolation implementation for image.Gray.
type Gray interface {
// Gray interpolates (x, y).
Gray(src *image.Gray, x, y float64) color.Gray
}

35
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/rotate.go сгенерированный поставляемый
Просмотреть файл

@@ -1,35 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/interp"
"errors"
"image"
"image/draw"
)
// RotateOptions are the rotation parameters.
// Angle is the angle, in radians, to rotate the image clockwise.
type RotateOptions struct {
Angle float64
}
// Rotate produces a rotated version of src, drawn onto dst.
func Rotate(dst draw.Image, src image.Image, opt *RotateOptions) error {
if dst == nil {
return errors.New("graphics: dst is nil")
}
if src == nil {
return errors.New("graphics: src is nil")
}
angle := 0.0
if opt != nil {
angle = opt.Angle
}
return I.Rotate(angle).TransformCenter(dst, src, interp.Bilinear)
}

169
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/rotate_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,169 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"math"
"testing"
_ "image/png"
)
var rotateOneColorTests = []transformOneColorTest{
{
"onepixel-onequarter", 1, 1, 1, 1,
&RotateOptions{math.Pi / 2},
[]uint8{0xff},
[]uint8{0xff},
},
{
"onepixel-partial", 1, 1, 1, 1,
&RotateOptions{math.Pi * 2.0 / 3.0},
[]uint8{0xff},
[]uint8{0xff},
},
{
"onepixel-complete", 1, 1, 1, 1,
&RotateOptions{2 * math.Pi},
[]uint8{0xff},
[]uint8{0xff},
},
{
"even-onequarter", 2, 2, 2, 2,
&RotateOptions{math.Pi / 2.0},
[]uint8{
0xff, 0x00,
0x00, 0xff,
},
[]uint8{
0x00, 0xff,
0xff, 0x00,
},
},
{
"even-complete", 2, 2, 2, 2,
&RotateOptions{2.0 * math.Pi},
[]uint8{
0xff, 0x00,
0x00, 0xff,
},
[]uint8{
0xff, 0x00,
0x00, 0xff,
},
},
{
"line-partial", 3, 3, 3, 3,
&RotateOptions{math.Pi * 1.0 / 3.0},
[]uint8{
0x00, 0x00, 0x00,
0xff, 0xff, 0xff,
0x00, 0x00, 0x00,
},
[]uint8{
0xa2, 0x80, 0x00,
0x22, 0xff, 0x22,
0x00, 0x80, 0xa2,
},
},
{
"line-offset-partial", 3, 3, 3, 3,
&RotateOptions{math.Pi * 3 / 2},
[]uint8{
0x00, 0x00, 0x00,
0x00, 0xff, 0xff,
0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0x00,
},
},
{
"dot-partial", 4, 4, 4, 4,
&RotateOptions{math.Pi},
[]uint8{
0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
},
[]uint8{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00,
},
},
}
func TestRotateOneColor(t *testing.T) {
for _, oc := range rotateOneColorTests {
src := oc.newSrc()
dst := oc.newDst()
if err := Rotate(dst, src, oc.opt.(*RotateOptions)); err != nil {
t.Errorf("rotate %s: %v", oc.desc, err)
continue
}
if !checkTransformTest(t, &oc, dst) {
continue
}
}
}
func TestRotateEmpty(t *testing.T) {
empty := image.NewRGBA(image.Rect(0, 0, 0, 0))
if err := Rotate(empty, empty, nil); err != nil {
t.Fatal(err)
}
}
func TestRotateGopherSide(t *testing.T) {
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
srcb := src.Bounds()
dst := image.NewRGBA(image.Rect(0, 0, srcb.Dy(), srcb.Dx()))
if err := Rotate(dst, src, &RotateOptions{math.Pi / 2.0}); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-rotate-side.png")
if err != nil {
t.Fatal(err)
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0x101)
if err != nil {
t.Fatal(err)
}
}
func TestRotateGopherPartial(t *testing.T) {
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
srcb := src.Bounds()
dst := image.NewRGBA(image.Rect(0, 0, srcb.Dx(), srcb.Dy()))
if err := Rotate(dst, src, &RotateOptions{math.Pi / 3.0}); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-rotate-partial.png")
if err != nil {
t.Fatal(err)
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0x101)
if err != nil {
t.Fatal(err)
}
}

31
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/scale.go сгенерированный поставляемый
Просмотреть файл

@@ -1,31 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/interp"
"errors"
"image"
"image/draw"
)
// Scale produces a scaled version of the image using bilinear interpolation.
func Scale(dst draw.Image, src image.Image) error {
if dst == nil {
return errors.New("graphics: dst is nil")
}
if src == nil {
return errors.New("graphics: src is nil")
}
b := dst.Bounds()
srcb := src.Bounds()
if b.Empty() || srcb.Empty() {
return nil
}
sx := float64(b.Dx()) / float64(srcb.Dx())
sy := float64(b.Dy()) / float64(srcb.Dy())
return I.Scale(sx, sy).Transform(dst, src, interp.Bilinear)
}

153
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/scale_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,153 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"testing"
_ "image/png"
)
var scaleOneColorTests = []transformOneColorTest{
{
"down-half",
1, 1,
2, 2,
nil,
[]uint8{
0x80, 0x00,
0x00, 0x80,
},
[]uint8{
0x40,
},
},
{
"up-double",
4, 4,
2, 2,
nil,
[]uint8{
0x80, 0x00,
0x00, 0x80,
},
[]uint8{
0x80, 0x60, 0x20, 0x00,
0x60, 0x50, 0x30, 0x20,
0x20, 0x30, 0x50, 0x60,
0x00, 0x20, 0x60, 0x80,
},
},
{
"up-doublewidth",
4, 2,
2, 2,
nil,
[]uint8{
0x80, 0x00,
0x00, 0x80,
},
[]uint8{
0x80, 0x60, 0x20, 0x00,
0x00, 0x20, 0x60, 0x80,
},
},
{
"up-doubleheight",
2, 4,
2, 2,
nil,
[]uint8{
0x80, 0x00,
0x00, 0x80,
},
[]uint8{
0x80, 0x00,
0x60, 0x20,
0x20, 0x60,
0x00, 0x80,
},
},
{
"up-partial",
3, 3,
2, 2,
nil,
[]uint8{
0x80, 0x00,
0x00, 0x80,
},
[]uint8{
0x80, 0x40, 0x00,
0x40, 0x40, 0x40,
0x00, 0x40, 0x80,
},
},
}
func TestScaleOneColor(t *testing.T) {
for _, oc := range scaleOneColorTests {
dst := oc.newDst()
src := oc.newSrc()
if err := Scale(dst, src); err != nil {
t.Errorf("scale %s: %v", oc.desc, err)
continue
}
if !checkTransformTest(t, &oc, dst) {
continue
}
}
}
func TestScaleEmpty(t *testing.T) {
empty := image.NewRGBA(image.Rect(0, 0, 0, 0))
if err := Scale(empty, empty); err != nil {
t.Fatal(err)
}
}
func TestScaleGopher(t *testing.T) {
dst := image.NewRGBA(image.Rect(0, 0, 100, 150))
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Error(err)
return
}
// Down-sample.
if err := Scale(dst, src); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-100x150.png")
if err != nil {
t.Error(err)
return
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0)
if err != nil {
t.Error(err)
return
}
// Up-sample.
dst = image.NewRGBA(image.Rect(0, 0, 500, 750))
if err := Scale(dst, src); err != nil {
t.Fatal(err)
}
cmp, err = graphicstest.LoadImage("../testdata/gopher-500x750.png")
if err != nil {
t.Error(err)
return
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0)
if err != nil {
t.Error(err)
return
}
}

69
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/shared_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,69 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"bytes"
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"image/color"
"testing"
)
type transformOneColorTest struct {
desc string
dstWidth int
dstHeight int
srcWidth int
srcHeight int
opt interface{}
src []uint8
res []uint8
}
func (oc *transformOneColorTest) newSrc() *image.RGBA {
b := image.Rect(0, 0, oc.srcWidth, oc.srcHeight)
src := image.NewRGBA(b)
i := 0
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
src.SetRGBA(x, y, color.RGBA{
R: oc.src[i],
G: oc.src[i],
B: oc.src[i],
A: oc.src[i],
})
i++
}
}
return src
}
func (oc *transformOneColorTest) newDst() *image.RGBA {
return image.NewRGBA(image.Rect(0, 0, oc.dstWidth, oc.dstHeight))
}
func checkTransformTest(t *testing.T, oc *transformOneColorTest, dst *image.RGBA) bool {
for ch := 0; ch < 4; ch++ {
i := 0
res := make([]byte, len(oc.res))
for y := 0; y < oc.dstHeight; y++ {
for x := 0; x < oc.dstWidth; x++ {
off := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4
res[i] = dst.Pix[off+ch]
i++
}
}
if !bytes.Equal(res, oc.res) {
got := graphicstest.SprintBox(res, oc.dstWidth, oc.dstHeight)
want := graphicstest.SprintBox(oc.res, oc.dstWidth, oc.dstHeight)
t.Errorf("%s: ch=%d\n got\n%s\n want\n%s", oc.desc, ch, got, want)
return false
}
}
return true
}

41
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/thumbnail.go сгенерированный поставляемый
Просмотреть файл

@@ -1,41 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"image"
"image/draw"
)
// Thumbnail scales and crops src so it fits in dst.
func Thumbnail(dst draw.Image, src image.Image) error {
// Scale down src in the dimension that is closer to dst.
sb := src.Bounds()
db := dst.Bounds()
rx := float64(sb.Dx()) / float64(db.Dx())
ry := float64(sb.Dy()) / float64(db.Dy())
var b image.Rectangle
if rx < ry {
b = image.Rect(0, 0, db.Dx(), int(float64(sb.Dy())/rx))
} else {
b = image.Rect(0, 0, int(float64(sb.Dx())/ry), db.Dy())
}
buf := image.NewRGBA(b)
if err := Scale(buf, src); err != nil {
return err
}
// Crop.
// TODO(crawshaw): improve on center-alignment.
var pt image.Point
if rx < ry {
pt.Y = (b.Dy() - db.Dy()) / 2
} else {
pt.X = (b.Dx() - db.Dx()) / 2
}
draw.Draw(dst, db, buf, pt, draw.Src)
return nil
}

53
Godeps/_workspace/src/code.google.com/p/graphics-go/graphics/thumbnail_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,53 +0,0 @@
// Copyright 2011 The Graphics-Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graphics
import (
"code.google.com/p/graphics-go/graphics/graphicstest"
"image"
"testing"
_ "image/png"
)
func TestThumbnailGopher(t *testing.T) {
dst := image.NewRGBA(image.Rect(0, 0, 80, 80))
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
if err := Thumbnail(dst, src); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-thumb-80x80.png")
if err != nil {
t.Fatal(err)
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0)
if err != nil {
t.Error(err)
}
}
func TestThumbnailLongGopher(t *testing.T) {
dst := image.NewRGBA(image.Rect(0, 0, 50, 150))
src, err := graphicstest.LoadImage("../testdata/gopher.png")
if err != nil {
t.Fatal(err)
}
if err := Thumbnail(dst, src); err != nil {
t.Fatal(err)
}
cmp, err := graphicstest.LoadImage("../testdata/gopher-thumb-50x150.png")
if err != nil {
t.Fatal(err)
}
err = graphicstest.ImageWithinTolerance(dst, cmp, 0)
if err != nil {
t.Error(err)
}
}

7
Godeps/_workspace/src/github.com/nfnt/resize/.travis.yml сгенерированный поставляемый
Просмотреть файл

@@ -1,7 +0,0 @@
language: go
go:
- 1.1
- 1.2
- 1.3
- tip

13
Godeps/_workspace/src/github.com/nfnt/resize/LICENSE сгенерированный поставляемый
Просмотреть файл

@@ -1,13 +0,0 @@
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

149
Godeps/_workspace/src/github.com/nfnt/resize/README.md сгенерированный поставляемый
Просмотреть файл

@@ -1,149 +0,0 @@
Resize
======
Image resizing for the [Go programming language](http://golang.org) with common interpolation methods.
[![Build Status](https://travis-ci.org/nfnt/resize.svg)](https://travis-ci.org/nfnt/resize)
Installation
------------
```bash
$ go get github.com/nfnt/resize
```
It's that easy!
Usage
-----
This package needs at least Go 1.1. Import package with
```go
import "github.com/nfnt/resize"
```
The resize package provides 2 functions:
* `resize.Resize` creates a scaled image with new dimensions (`width`, `height`) using the interpolation function `interp`.
If either `width` or `height` is set to 0, it will be set to an aspect ratio preserving value.
* `resize.Thumbnail` downscales an image preserving its aspect ratio to the maximum dimensions (`maxWidth`, `maxHeight`).
It will return the original image if original sizes are smaller than the provided dimensions.
```go
resize.Resize(width, height uint, img image.Image, interp resize.InterpolationFunction) image.Image
resize.Thumbnail(maxWidth, maxHeight uint, img image.Image, interp resize.InterpolationFunction) image.Image
```
The provided interpolation functions are (from fast to slow execution time)
- `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation)
- `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation)
- `Bicubic`: [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation)
- `MitchellNetravali`: [Mitchell-Netravali interpolation](http://dl.acm.org/citation.cfm?id=378514)
- `Lanczos2`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=2
- `Lanczos3`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=3
Which of these methods gives the best results depends on your use case.
Sample usage:
```go
package main
import (
"github.com/nfnt/resize"
"image/jpeg"
"log"
"os"
)
func main() {
// open "test.jpg"
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}
// decode jpeg into image.Image
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
// resize to width 1000 using Lanczos resampling
// and preserve aspect ratio
m := resize.Resize(1000, 0, img, resize.Lanczos3)
out, err := os.Create("test_resized.jpg")
if err != nil {
log.Fatal(err)
}
defer out.Close()
// write new image to file
jpeg.Encode(out, m, nil)
}
```
Caveats
-------
* Optimized access routines are used for `image.RGBA`, `image.NRGBA`, `image.RGBA64`, `image.NRGBA64`, `image.YCbCr`, `image.Gray`, and `image.Gray16` types. All other image types are accessed in a generic way that will result in slow processing speed.
* JPEG images are stored in `image.YCbCr`. This image format stores data in a way that will decrease processing speed. A resize may be up to 2 times slower than with `image.RGBA`.
Downsizing Samples
-------
Downsizing is not as simple as it might look like. Images have to be filtered before they are scaled down, otherwise aliasing might occur.
Filtering is highly subjective: Applying too much will blur the whole image, too little will make aliasing become apparent.
Resize tries to provide sane defaults that should suffice in most cases.
### Artificial sample
Original image
![Rings](http://nfnt.github.com/img/rings_lg_orig.png)
<table>
<tr>
<th><img src="http://nfnt.github.com/img/rings_300_NearestNeighbor.png" /><br>Nearest-Neighbor</th>
<th><img src="http://nfnt.github.com/img/rings_300_Bilinear.png" /><br>Bilinear</th>
</tr>
<tr>
<th><img src="http://nfnt.github.com/img/rings_300_Bicubic.png" /><br>Bicubic</th>
<th><img src="http://nfnt.github.com/img/rings_300_MitchellNetravali.png" /><br>Mitchell-Netravali</th>
</tr>
<tr>
<th><img src="http://nfnt.github.com/img/rings_300_Lanczos2.png" /><br>Lanczos2</th>
<th><img src="http://nfnt.github.com/img/rings_300_Lanczos3.png" /><br>Lanczos3</th>
</tr>
</table>
### Real-Life sample
Original image
![Original](http://nfnt.github.com/img/IMG_3694_720.jpg)
<table>
<tr>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_NearestNeighbor.png" /><br>Nearest-Neighbor</th>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_Bilinear.png" /><br>Bilinear</th>
</tr>
<tr>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_Bicubic.png" /><br>Bicubic</th>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_MitchellNetravali.png" /><br>Mitchell-Netravali</th>
</tr>
<tr>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_Lanczos2.png" /><br>Lanczos2</th>
<th><img src="http://nfnt.github.com/img/IMG_3694_300_Lanczos3.png" /><br>Lanczos3</th>
</tr>
</table>
License
-------
Copyright (c) 2012 Jan Schlicht <janschlicht@gmail.com>
Resize is released under a MIT style license.

452
Godeps/_workspace/src/github.com/nfnt/resize/converter.go сгенерированный поставляемый
Просмотреть файл

@@ -1,452 +0,0 @@
/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import "image"
// Keep value in [0,255] range.
func clampUint8(in int32) uint8 {
// casting a negative int to an uint will result in an overflown
// large uint. this behavior will be exploited here and in other functions
// to achieve a higher performance.
if uint32(in) < 256 {
return uint8(in)
}
if in > 255 {
return 255
}
return 0
}
// Keep value in [0,65535] range.
func clampUint16(in int64) uint16 {
if uint64(in) < 65536 {
return uint16(in)
}
if in > 65535 {
return 65535
}
return 0
}
func resizeGeneric(in image.Image, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int64
var sum int64
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case xi < 0:
xi = 0
case xi >= maxX:
xi = maxX
}
r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
// reverse alpha-premultiplication.
if a != 0 {
r *= 0xffff
r /= a
g *= 0xffff
g /= a
b *= 0xffff
b /= a
}
rgba[0] += int64(coeff) * int64(r)
rgba[1] += int64(coeff) * int64(g)
rgba[2] += int64(coeff) * int64(b)
rgba[3] += int64(coeff) * int64(a)
sum += int64(coeff)
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := clampUint16(rgba[0] / sum)
out.Pix[offset+0] = uint8(value >> 8)
out.Pix[offset+1] = uint8(value)
value = clampUint16(rgba[1] / sum)
out.Pix[offset+2] = uint8(value >> 8)
out.Pix[offset+3] = uint8(value)
value = clampUint16(rgba[2] / sum)
out.Pix[offset+4] = uint8(value >> 8)
out.Pix[offset+5] = uint8(value)
value = clampUint16(rgba[3] / sum)
out.Pix[offset+6] = uint8(value >> 8)
out.Pix[offset+7] = uint8(value)
}
}
}
func resizeRGBA(in *image.RGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int32
var sum int32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 4
case xi >= maxX:
xi = 4 * maxX
default:
xi = 0
}
r := uint32(row[xi+0])
g := uint32(row[xi+1])
b := uint32(row[xi+2])
a := uint32(row[xi+3])
// reverse alpha-premultiplication.
if a != 0 {
r *= 0xff
r /= a
g *= 0xff
g /= a
b *= 0xff
b /= a
}
rgba[0] += int32(coeff) * int32(r)
rgba[1] += int32(coeff) * int32(g)
rgba[2] += int32(coeff) * int32(b)
rgba[3] += int32(coeff) * int32(a)
sum += int32(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
out.Pix[xo+0] = clampUint8(rgba[0] / sum)
out.Pix[xo+1] = clampUint8(rgba[1] / sum)
out.Pix[xo+2] = clampUint8(rgba[2] / sum)
out.Pix[xo+3] = clampUint8(rgba[3] / sum)
}
}
}
func resizeNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int32
var sum int32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 4
case xi >= maxX:
xi = 4 * maxX
default:
xi = 0
}
rgba[0] += int32(coeff) * int32(row[xi+0])
rgba[1] += int32(coeff) * int32(row[xi+1])
rgba[2] += int32(coeff) * int32(row[xi+2])
rgba[3] += int32(coeff) * int32(row[xi+3])
sum += int32(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
out.Pix[xo+0] = clampUint8(rgba[0] / sum)
out.Pix[xo+1] = clampUint8(rgba[1] / sum)
out.Pix[xo+2] = clampUint8(rgba[2] / sum)
out.Pix[xo+3] = clampUint8(rgba[3] / sum)
}
}
}
func resizeRGBA64(in *image.RGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int64
var sum int64
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 8
case xi >= maxX:
xi = 8 * maxX
default:
xi = 0
}
r := uint32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
g := uint32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
b := uint32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
a := uint32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
// reverse alpha-premultiplication.
if a != 0 {
r *= 0xffff
r /= a
g *= 0xffff
g /= a
b *= 0xffff
b /= a
}
rgba[0] += int64(coeff) * int64(r)
rgba[1] += int64(coeff) * int64(g)
rgba[2] += int64(coeff) * int64(b)
rgba[3] += int64(coeff) * int64(a)
sum += int64(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := clampUint16(rgba[0] / sum)
out.Pix[xo+0] = uint8(value >> 8)
out.Pix[xo+1] = uint8(value)
value = clampUint16(rgba[1] / sum)
out.Pix[xo+2] = uint8(value >> 8)
out.Pix[xo+3] = uint8(value)
value = clampUint16(rgba[2] / sum)
out.Pix[xo+4] = uint8(value >> 8)
out.Pix[xo+5] = uint8(value)
value = clampUint16(rgba[3] / sum)
out.Pix[xo+6] = uint8(value >> 8)
out.Pix[xo+7] = uint8(value)
}
}
}
func resizeNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]int64
var sum int64
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 8
case xi >= maxX:
xi = 8 * maxX
default:
xi = 0
}
rgba[0] += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
rgba[1] += int64(coeff) * int64(uint16(row[xi+2])<<8|uint16(row[xi+3]))
rgba[2] += int64(coeff) * int64(uint16(row[xi+4])<<8|uint16(row[xi+5]))
rgba[3] += int64(coeff) * int64(uint16(row[xi+6])<<8|uint16(row[xi+7]))
sum += int64(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := clampUint16(rgba[0] / sum)
out.Pix[xo+0] = uint8(value >> 8)
out.Pix[xo+1] = uint8(value)
value = clampUint16(rgba[1] / sum)
out.Pix[xo+2] = uint8(value >> 8)
out.Pix[xo+3] = uint8(value)
value = clampUint16(rgba[2] / sum)
out.Pix[xo+4] = uint8(value >> 8)
out.Pix[xo+5] = uint8(value)
value = clampUint16(rgba[3] / sum)
out.Pix[xo+6] = uint8(value >> 8)
out.Pix[xo+7] = uint8(value)
}
}
}
func resizeGray(in *image.Gray, out *image.Gray, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[(x-newBounds.Min.X)*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var gray int32
var sum int32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case xi < 0:
xi = 0
case xi >= maxX:
xi = maxX
}
gray += int32(coeff) * int32(row[xi])
sum += int32(coeff)
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
out.Pix[offset] = clampUint8(gray / sum)
}
}
}
func resizeGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []int32, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var gray int64
var sum int64
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 2
case xi >= maxX:
xi = 2 * maxX
default:
xi = 0
}
gray += int64(coeff) * int64(uint16(row[xi+0])<<8|uint16(row[xi+1]))
sum += int64(coeff)
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
value := clampUint16(gray / sum)
out.Pix[offset+0] = uint8(value >> 8)
out.Pix[offset+1] = uint8(value)
}
}
}
func resizeYCbCr(in *ycc, out *ycc, scale float64, coeffs []int16, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var p [3]int32
var sum int32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
coeff := coeffs[ci+i]
if coeff != 0 {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 3
case xi >= maxX:
xi = 3 * maxX
default:
xi = 0
}
p[0] += int32(coeff) * int32(row[xi+0])
p[1] += int32(coeff) * int32(row[xi+1])
p[2] += int32(coeff) * int32(row[xi+2])
sum += int32(coeff)
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
out.Pix[xo+0] = clampUint8(p[0] / sum)
out.Pix[xo+1] = clampUint8(p[1] / sum)
out.Pix[xo+2] = clampUint8(p[2] / sum)
}
}
}
func nearestYCbCr(in *ycc, out *ycc, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var p [3]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 3
case xi >= maxX:
xi = 3 * maxX
default:
xi = 0
}
p[0] += float32(row[xi+0])
p[1] += float32(row[xi+1])
p[2] += float32(row[xi+2])
sum++
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*3
out.Pix[xo+0] = floatToUint8(p[0] / sum)
out.Pix[xo+1] = floatToUint8(p[1] / sum)
out.Pix[xo+2] = floatToUint8(p[2] / sum)
}
}
}

43
Godeps/_workspace/src/github.com/nfnt/resize/converter_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,43 +0,0 @@
package resize
import (
"testing"
)
func Test_ClampUint8(t *testing.T) {
var testData = []struct {
in int32
expected uint8
}{
{0, 0},
{255, 255},
{128, 128},
{-2, 0},
{256, 255},
}
for _, test := range testData {
actual := clampUint8(test.in)
if actual != test.expected {
t.Fail()
}
}
}
func Test_ClampUint16(t *testing.T) {
var testData = []struct {
in int64
expected uint16
}{
{0, 0},
{65535, 65535},
{128, 128},
{-2, 0},
{65536, 65535},
}
for _, test := range testData {
actual := clampUint16(test.in)
if actual != test.expected {
t.Fail()
}
}
}

143
Godeps/_workspace/src/github.com/nfnt/resize/filters.go сгенерированный поставляемый
Просмотреть файл

@@ -1,143 +0,0 @@
/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import (
"math"
)
func nearest(in float64) float64 {
if in >= -0.5 && in < 0.5 {
return 1
}
return 0
}
func linear(in float64) float64 {
in = math.Abs(in)
if in <= 1 {
return 1 - in
}
return 0
}
func cubic(in float64) float64 {
in = math.Abs(in)
if in <= 1 {
return in*in*(1.5*in-2.5) + 1.0
}
if in <= 2 {
return in*(in*(2.5-0.5*in)-4.0) + 2.0
}
return 0
}
func mitchellnetravali(in float64) float64 {
in = math.Abs(in)
if in <= 1 {
return (7.0*in*in*in - 12.0*in*in + 5.33333333333) * 0.16666666666
}
if in <= 2 {
return (-2.33333333333*in*in*in + 12.0*in*in - 20.0*in + 10.6666666667) * 0.16666666666
}
return 0
}
func sinc(x float64) float64 {
x = math.Abs(x) * math.Pi
if x >= 1.220703e-4 {
return math.Sin(x) / x
}
return 1
}
func lanczos2(in float64) float64 {
if in > -2 && in < 2 {
return sinc(in) * sinc(in*0.5)
}
return 0
}
func lanczos3(in float64) float64 {
if in > -3 && in < 3 {
return sinc(in) * sinc(in*0.3333333333333333)
}
return 0
}
// range [-256,256]
func createWeights8(dy, filterLength int, blur, scale float64, kernel func(float64) float64) ([]int16, []int, int) {
filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
filterFactor := math.Min(1./(blur*scale), 1)
coeffs := make([]int16, dy*filterLength)
start := make([]int, dy)
for y := 0; y < dy; y++ {
interpX := scale*(float64(y)+0.5) - 0.5
start[y] = int(interpX) - filterLength/2 + 1
interpX -= float64(start[y])
for i := 0; i < filterLength; i++ {
in := (interpX - float64(i)) * filterFactor
coeffs[y*filterLength+i] = int16(kernel(in) * 256)
}
}
return coeffs, start, filterLength
}
// range [-65536,65536]
func createWeights16(dy, filterLength int, blur, scale float64, kernel func(float64) float64) ([]int32, []int, int) {
filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
filterFactor := math.Min(1./(blur*scale), 1)
coeffs := make([]int32, dy*filterLength)
start := make([]int, dy)
for y := 0; y < dy; y++ {
interpX := scale*(float64(y)+0.5) - 0.5
start[y] = int(interpX) - filterLength/2 + 1
interpX -= float64(start[y])
for i := 0; i < filterLength; i++ {
in := (interpX - float64(i)) * filterFactor
coeffs[y*filterLength+i] = int32(kernel(in) * 65536)
}
}
return coeffs, start, filterLength
}
func createWeightsNearest(dy, filterLength int, blur, scale float64) ([]bool, []int, int) {
filterLength = filterLength * int(math.Max(math.Ceil(blur*scale), 1))
filterFactor := math.Min(1./(blur*scale), 1)
coeffs := make([]bool, dy*filterLength)
start := make([]int, dy)
for y := 0; y < dy; y++ {
interpX := scale*(float64(y)+0.5) - 0.5
start[y] = int(interpX) - filterLength/2 + 1
interpX -= float64(start[y])
for i := 0; i < filterLength; i++ {
in := (interpX - float64(i)) * filterFactor
if in >= -0.5 && in < 0.5 {
coeffs[y*filterLength+i] = true
} else {
coeffs[y*filterLength+i] = false
}
}
}
return coeffs, start, filterLength
}

318
Godeps/_workspace/src/github.com/nfnt/resize/nearest.go сгенерированный поставляемый
Просмотреть файл

@@ -1,318 +0,0 @@
/*
Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import "image"
func floatToUint8(x float32) uint8 {
// Nearest-neighbor values are always
// positive no need to check lower-bound.
if x > 0xfe {
return 0xff
}
return uint8(x)
}
func floatToUint16(x float32) uint16 {
if x > 0xfffe {
return 0xffff
}
return uint16(x)
}
func nearestGeneric(in image.Image, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case xi < 0:
xi = 0
case xi >= maxX:
xi = maxX
}
r, g, b, a := in.At(xi+in.Bounds().Min.X, x+in.Bounds().Min.Y).RGBA()
rgba[0] += float32(r)
rgba[1] += float32(g)
rgba[2] += float32(b)
rgba[3] += float32(a)
sum++
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := floatToUint16(rgba[0] / sum)
out.Pix[offset+0] = uint8(value >> 8)
out.Pix[offset+1] = uint8(value)
value = floatToUint16(rgba[1] / sum)
out.Pix[offset+2] = uint8(value >> 8)
out.Pix[offset+3] = uint8(value)
value = floatToUint16(rgba[2] / sum)
out.Pix[offset+4] = uint8(value >> 8)
out.Pix[offset+5] = uint8(value)
value = floatToUint16(rgba[3] / sum)
out.Pix[offset+6] = uint8(value >> 8)
out.Pix[offset+7] = uint8(value)
}
}
}
func nearestRGBA(in *image.RGBA, out *image.RGBA, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 4
case xi >= maxX:
xi = 4 * maxX
default:
xi = 0
}
rgba[0] += float32(row[xi+0])
rgba[1] += float32(row[xi+1])
rgba[2] += float32(row[xi+2])
rgba[3] += float32(row[xi+3])
sum++
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
out.Pix[xo+0] = floatToUint8(rgba[0] / sum)
out.Pix[xo+1] = floatToUint8(rgba[1] / sum)
out.Pix[xo+2] = floatToUint8(rgba[2] / sum)
out.Pix[xo+3] = floatToUint8(rgba[3] / sum)
}
}
}
func nearestNRGBA(in *image.NRGBA, out *image.NRGBA, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 4
case xi >= maxX:
xi = 4 * maxX
default:
xi = 0
}
rgba[0] += float32(row[xi+0])
rgba[1] += float32(row[xi+1])
rgba[2] += float32(row[xi+2])
rgba[3] += float32(row[xi+3])
sum++
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*4
out.Pix[xo+0] = floatToUint8(rgba[0] / sum)
out.Pix[xo+1] = floatToUint8(rgba[1] / sum)
out.Pix[xo+2] = floatToUint8(rgba[2] / sum)
out.Pix[xo+3] = floatToUint8(rgba[3] / sum)
}
}
}
func nearestRGBA64(in *image.RGBA64, out *image.RGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 8
case xi >= maxX:
xi = 8 * maxX
default:
xi = 0
}
rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
sum++
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := floatToUint16(rgba[0] / sum)
out.Pix[xo+0] = uint8(value >> 8)
out.Pix[xo+1] = uint8(value)
value = floatToUint16(rgba[1] / sum)
out.Pix[xo+2] = uint8(value >> 8)
out.Pix[xo+3] = uint8(value)
value = floatToUint16(rgba[2] / sum)
out.Pix[xo+4] = uint8(value >> 8)
out.Pix[xo+5] = uint8(value)
value = floatToUint16(rgba[3] / sum)
out.Pix[xo+6] = uint8(value >> 8)
out.Pix[xo+7] = uint8(value)
}
}
}
func nearestNRGBA64(in *image.NRGBA64, out *image.NRGBA64, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var rgba [4]float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 8
case xi >= maxX:
xi = 8 * maxX
default:
xi = 0
}
rgba[0] += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
rgba[1] += float32(uint16(row[xi+2])<<8 | uint16(row[xi+3]))
rgba[2] += float32(uint16(row[xi+4])<<8 | uint16(row[xi+5]))
rgba[3] += float32(uint16(row[xi+6])<<8 | uint16(row[xi+7]))
sum++
}
}
xo := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*8
value := floatToUint16(rgba[0] / sum)
out.Pix[xo+0] = uint8(value >> 8)
out.Pix[xo+1] = uint8(value)
value = floatToUint16(rgba[1] / sum)
out.Pix[xo+2] = uint8(value >> 8)
out.Pix[xo+3] = uint8(value)
value = floatToUint16(rgba[2] / sum)
out.Pix[xo+4] = uint8(value >> 8)
out.Pix[xo+5] = uint8(value)
value = floatToUint16(rgba[3] / sum)
out.Pix[xo+6] = uint8(value >> 8)
out.Pix[xo+7] = uint8(value)
}
}
}
func nearestGray(in *image.Gray, out *image.Gray, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var gray float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case xi < 0:
xi = 0
case xi >= maxX:
xi = maxX
}
gray += float32(row[xi])
sum++
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x - newBounds.Min.X)
out.Pix[offset] = floatToUint8(gray / sum)
}
}
}
func nearestGray16(in *image.Gray16, out *image.Gray16, scale float64, coeffs []bool, offset []int, filterLength int) {
newBounds := out.Bounds()
maxX := in.Bounds().Dx() - 1
for x := newBounds.Min.X; x < newBounds.Max.X; x++ {
row := in.Pix[x*in.Stride:]
for y := newBounds.Min.Y; y < newBounds.Max.Y; y++ {
var gray float32
var sum float32
start := offset[y]
ci := y * filterLength
for i := 0; i < filterLength; i++ {
if coeffs[ci+i] {
xi := start + i
switch {
case uint(xi) < uint(maxX):
xi *= 2
case xi >= maxX:
xi = 2 * maxX
default:
xi = 0
}
gray += float32(uint16(row[xi+0])<<8 | uint16(row[xi+1]))
sum++
}
}
offset := (y-newBounds.Min.Y)*out.Stride + (x-newBounds.Min.X)*2
value := floatToUint16(gray / sum)
out.Pix[offset+0] = uint8(value >> 8)
out.Pix[offset+1] = uint8(value)
}
}
}

57
Godeps/_workspace/src/github.com/nfnt/resize/nearest_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,57 +0,0 @@
/*
Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import "testing"
func Test_FloatToUint8(t *testing.T) {
var testData = []struct {
in float32
expected uint8
}{
{0, 0},
{255, 255},
{128, 128},
{1, 1},
{256, 255},
}
for _, test := range testData {
actual := floatToUint8(test.in)
if actual != test.expected {
t.Fail()
}
}
}
func Test_FloatToUint16(t *testing.T) {
var testData = []struct {
in float32
expected uint16
}{
{0, 0},
{65535, 65535},
{128, 128},
{1, 1},
{65536, 65535},
}
for _, test := range testData {
actual := floatToUint16(test.in)
if actual != test.expected {
t.Fail()
}
}
}

614
Godeps/_workspace/src/github.com/nfnt/resize/resize.go сгенерированный поставляемый
Просмотреть файл

@@ -1,614 +0,0 @@
/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
// Package resize implements various image resizing methods.
//
// The package works with the Image interface described in the image package.
// Various interpolation methods are provided and multiple processors may be
// utilized in the computations.
//
// Example:
// imgResized := resize.Resize(1000, 0, imgOld, resize.MitchellNetravali)
package resize
import (
"image"
"runtime"
"sync"
)
// An InterpolationFunction provides the parameters that describe an
// interpolation kernel. It returns the number of samples to take
// and the kernel function to use for sampling.
type InterpolationFunction int
// InterpolationFunction constants
const (
// Nearest-neighbor interpolation
NearestNeighbor InterpolationFunction = iota
// Bilinear interpolation
Bilinear
// Bicubic interpolation (with cubic hermite spline)
Bicubic
// Mitchell-Netravali interpolation
MitchellNetravali
// Lanczos interpolation (a=2)
Lanczos2
// Lanczos interpolation (a=3)
Lanczos3
)
// kernal, returns an InterpolationFunctions taps and kernel.
func (i InterpolationFunction) kernel() (int, func(float64) float64) {
switch i {
case Bilinear:
return 2, linear
case Bicubic:
return 4, cubic
case MitchellNetravali:
return 4, mitchellnetravali
case Lanczos2:
return 4, lanczos2
case Lanczos3:
return 6, lanczos3
default:
// Default to NearestNeighbor.
return 2, nearest
}
}
// values <1 will sharpen the image
var blur = 1.0
// Resize scales an image to new width and height using the interpolation function interp.
// A new image with the given dimensions will be returned.
// If one of the parameters width or height is set to 0, its size will be calculated so that
// the aspect ratio is that of the originating image.
// The resizing algorithm uses channels for parallel computation.
func Resize(width, height uint, img image.Image, interp InterpolationFunction) image.Image {
scaleX, scaleY := calcFactors(width, height, float64(img.Bounds().Dx()), float64(img.Bounds().Dy()))
if width == 0 {
width = uint(0.7 + float64(img.Bounds().Dx())/scaleX)
}
if height == 0 {
height = uint(0.7 + float64(img.Bounds().Dy())/scaleY)
}
// Trivial case: return input image
if int(width) == img.Bounds().Dx() && int(height) == img.Bounds().Dy() {
return img
}
if interp == NearestNeighbor {
return resizeNearest(width, height, scaleX, scaleY, img, interp)
}
taps, kernel := interp.kernel()
cpus := runtime.GOMAXPROCS(0)
wg := sync.WaitGroup{}
// Generic access to image.Image is slow in tight loops.
// The optimal access has to be determined from the concrete image type.
switch input := img.(type) {
case *image.RGBA:
// 8-bit precision
temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
resizeRGBA(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
resizeNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.NRGBA:
// 8-bit precision
temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
resizeNRGBA(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
resizeNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.YCbCr:
// 8-bit precision
// accessing the YCbCr arrays in a tight loop is slow.
// converting the image to ycc increases performance by 2x.
temp := newYCC(image.Rect(0, 0, input.Bounds().Dy(), int(width)), input.SubsampleRatio)
result := newYCC(image.Rect(0, 0, int(width), int(height)), image.YCbCrSubsampleRatio444)
coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
in := imageYCbCrToYCC(input)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*ycc)
go func() {
defer wg.Done()
resizeYCbCr(in, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*ycc)
go func() {
defer wg.Done()
resizeYCbCr(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result.YCbCr()
case *image.RGBA64:
// 16-bit precision
temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.NRGBA64:
// 16-bit precision
temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeNRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.Gray:
// 8-bit precision
temp := image.NewGray(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewGray(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights8(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.Gray)
go func() {
defer wg.Done()
resizeGray(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights8(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.Gray)
go func() {
defer wg.Done()
resizeGray(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.Gray16:
// 16-bit precision
temp := image.NewGray16(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewGray16(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.Gray16)
go func() {
defer wg.Done()
resizeGray16(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.Gray16)
go func() {
defer wg.Done()
resizeGray16(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
default:
// 16-bit precision
temp := image.NewNRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width)))
result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeights16(temp.Bounds().Dy(), taps, blur, scaleX, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeGeneric(img, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeights16(result.Bounds().Dy(), taps, blur, scaleY, kernel)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
resizeNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
}
}
func resizeNearest(width, height uint, scaleX, scaleY float64, img image.Image, interp InterpolationFunction) image.Image {
taps, _ := interp.kernel()
cpus := runtime.GOMAXPROCS(0)
wg := sync.WaitGroup{}
switch input := img.(type) {
case *image.RGBA:
// 8-bit precision
temp := image.NewRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewRGBA(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA)
go func() {
defer wg.Done()
nearestRGBA(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA)
go func() {
defer wg.Done()
nearestRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.NRGBA:
// 8-bit precision
temp := image.NewNRGBA(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
nearestNRGBA(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA)
go func() {
defer wg.Done()
nearestNRGBA(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.YCbCr:
// 8-bit precision
// accessing the YCbCr arrays in a tight loop is slow.
// converting the image to ycc increases performance by 2x.
temp := newYCC(image.Rect(0, 0, input.Bounds().Dy(), int(width)), input.SubsampleRatio)
result := newYCC(image.Rect(0, 0, int(width), int(height)), image.YCbCrSubsampleRatio444)
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
in := imageYCbCrToYCC(input)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*ycc)
go func() {
defer wg.Done()
nearestYCbCr(in, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*ycc)
go func() {
defer wg.Done()
nearestYCbCr(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result.YCbCr()
case *image.RGBA64:
// 16-bit precision
temp := image.NewRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA64)
go func() {
defer wg.Done()
nearestRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA64)
go func() {
defer wg.Done()
nearestRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.NRGBA64:
// 16-bit precision
temp := image.NewNRGBA64(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewNRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
nearestNRGBA64(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.NRGBA64)
go func() {
defer wg.Done()
nearestNRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.Gray:
// 8-bit precision
temp := image.NewGray(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewGray(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.Gray)
go func() {
defer wg.Done()
nearestGray(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.Gray)
go func() {
defer wg.Done()
nearestGray(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
case *image.Gray16:
// 16-bit precision
temp := image.NewGray16(image.Rect(0, 0, input.Bounds().Dy(), int(width)))
result := image.NewGray16(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.Gray16)
go func() {
defer wg.Done()
nearestGray16(input, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.Gray16)
go func() {
defer wg.Done()
nearestGray16(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
default:
// 16-bit precision
temp := image.NewRGBA64(image.Rect(0, 0, img.Bounds().Dy(), int(width)))
result := image.NewRGBA64(image.Rect(0, 0, int(width), int(height)))
// horizontal filter, results in transposed temporary image
coeffs, offset, filterLength := createWeightsNearest(temp.Bounds().Dy(), taps, blur, scaleX)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(temp, i, cpus).(*image.RGBA64)
go func() {
defer wg.Done()
nearestGeneric(img, slice, scaleX, coeffs, offset, filterLength)
}()
}
wg.Wait()
// horizontal filter on transposed image, result is not transposed
coeffs, offset, filterLength = createWeightsNearest(result.Bounds().Dy(), taps, blur, scaleY)
wg.Add(cpus)
for i := 0; i < cpus; i++ {
slice := makeSlice(result, i, cpus).(*image.RGBA64)
go func() {
defer wg.Done()
nearestRGBA64(temp, slice, scaleY, coeffs, offset, filterLength)
}()
}
wg.Wait()
return result
}
}
// Calculates scaling factors using old and new image dimensions.
func calcFactors(width, height uint, oldWidth, oldHeight float64) (scaleX, scaleY float64) {
if width == 0 {
if height == 0 {
scaleX = 1.0
scaleY = 1.0
} else {
scaleY = oldHeight / float64(height)
scaleX = scaleY
}
} else {
scaleX = oldWidth / float64(width)
if height == 0 {
scaleY = scaleX
} else {
scaleY = oldHeight / float64(height)
}
}
return
}
type imageWithSubImage interface {
image.Image
SubImage(image.Rectangle) image.Image
}
func makeSlice(img imageWithSubImage, i, n int) image.Image {
return img.SubImage(image.Rect(img.Bounds().Min.X, img.Bounds().Min.Y+i*img.Bounds().Dy()/n, img.Bounds().Max.X, img.Bounds().Min.Y+(i+1)*img.Bounds().Dy()/n))
}

314
Godeps/_workspace/src/github.com/nfnt/resize/resize_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,314 +0,0 @@
package resize
import (
"image"
"image/color"
"runtime"
"testing"
)
var img = image.NewGray16(image.Rect(0, 0, 3, 3))
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
img.Set(1, 1, color.White)
}
func Test_Param1(t *testing.T) {
m := Resize(0, 0, img, NearestNeighbor)
if m.Bounds() != img.Bounds() {
t.Fail()
}
}
func Test_Param2(t *testing.T) {
m := Resize(100, 0, img, NearestNeighbor)
if m.Bounds() != image.Rect(0, 0, 100, 100) {
t.Fail()
}
}
func Test_ZeroImg(t *testing.T) {
zeroImg := image.NewGray16(image.Rect(0, 0, 0, 0))
m := Resize(0, 0, zeroImg, NearestNeighbor)
if m.Bounds() != zeroImg.Bounds() {
t.Fail()
}
}
func Test_CorrectResize(t *testing.T) {
zeroImg := image.NewGray16(image.Rect(0, 0, 256, 256))
m := Resize(60, 0, zeroImg, NearestNeighbor)
if m.Bounds() != image.Rect(0, 0, 60, 60) {
t.Fail()
}
}
func Test_SameColorWithRGBA(t *testing.T) {
img := image.NewRGBA(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetRGBA(x, y, color.RGBA{0x80, 0x80, 0x80, 0xFF})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.NRGBA)
if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
t.Errorf("%+v", color)
}
}
}
}
func Test_SameColorWithNRGBA(t *testing.T) {
img := image.NewNRGBA(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetNRGBA(x, y, color.NRGBA{0x80, 0x80, 0x80, 0xFF})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.NRGBA)
if color.R != 0x80 || color.G != 0x80 || color.B != 0x80 || color.A != 0xFF {
t.Errorf("%+v", color)
}
}
}
}
func Test_SameColorWithRGBA64(t *testing.T) {
img := image.NewRGBA64(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetRGBA64(x, y, color.RGBA64{0x8000, 0x8000, 0x8000, 0xFFFF})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.NRGBA64)
if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
t.Errorf("%+v", color)
}
}
}
}
func Test_SameColorWithNRGBA64(t *testing.T) {
img := image.NewNRGBA64(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetNRGBA64(x, y, color.NRGBA64{0x8000, 0x8000, 0x8000, 0xFFFF})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.NRGBA64)
if color.R != 0x8000 || color.G != 0x8000 || color.B != 0x8000 || color.A != 0xFFFF {
t.Errorf("%+v", color)
}
}
}
}
func Test_SameColorWithGray(t *testing.T) {
img := image.NewGray(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetGray(x, y, color.Gray{0x80})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.Gray)
if color.Y != 0x80 {
t.Errorf("%+v", color)
}
}
}
}
func Test_SameColorWithGray16(t *testing.T) {
img := image.NewGray16(image.Rect(0, 0, 20, 20))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
img.SetGray16(x, y, color.Gray16{0x8000})
}
}
out := Resize(10, 10, img, Lanczos3)
for y := out.Bounds().Min.Y; y < out.Bounds().Max.Y; y++ {
for x := out.Bounds().Min.X; x < out.Bounds().Max.X; x++ {
color := out.At(x, y).(color.Gray16)
if color.Y != 0x8000 {
t.Errorf("%+v", color)
}
}
}
}
func Test_Bounds(t *testing.T) {
img := image.NewRGBA(image.Rect(20, 10, 200, 99))
out := Resize(80, 80, img, Lanczos2)
out.At(0, 0)
}
func Test_SameSizeReturnsOriginal(t *testing.T) {
img := image.NewRGBA(image.Rect(0, 0, 10, 10))
out := Resize(0, 0, img, Lanczos2)
if img != out {
t.Fail()
}
out = Resize(10, 10, img, Lanczos2)
if img != out {
t.Fail()
}
}
func Test_PixelCoordinates(t *testing.T) {
checkers := image.NewGray(image.Rect(0, 0, 4, 4))
checkers.Pix = []uint8{
255, 0, 255, 0,
0, 255, 0, 255,
255, 0, 255, 0,
0, 255, 0, 255,
}
resized := Resize(12, 12, checkers, NearestNeighbor).(*image.Gray)
if resized.Pix[0] != 255 || resized.Pix[1] != 255 || resized.Pix[2] != 255 {
t.Fail()
}
if resized.Pix[3] != 0 || resized.Pix[4] != 0 || resized.Pix[5] != 0 {
t.Fail()
}
}
func Test_ResizeWithPremultipliedAlpha(t *testing.T) {
img := image.NewRGBA(image.Rect(0, 0, 1, 4))
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
// 0x80 = 0.5 * 0xFF.
img.SetRGBA(0, y, color.RGBA{0x80, 0x80, 0x80, 0x80})
}
out := Resize(1, 2, img, MitchellNetravali)
outputColor := out.At(0, 0).(color.NRGBA)
if outputColor.R != 0xFF {
t.Fail()
}
}
const (
// Use a small image size for benchmarks. We don't want memory performance
// to affect the benchmark results.
benchMaxX = 250
benchMaxY = 250
// Resize values near the original size require increase the amount of time
// resize spends converting the image.
benchWidth = 200
benchHeight = 200
)
func benchRGBA(b *testing.B, interp InterpolationFunction) {
m := image.NewRGBA(image.Rect(0, 0, benchMaxX, benchMaxY))
// Initialize m's pixels to create a non-uniform image.
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
i := m.PixOffset(x, y)
m.Pix[i+0] = uint8(y + 4*x)
m.Pix[i+1] = uint8(y + 4*x)
m.Pix[i+2] = uint8(y + 4*x)
m.Pix[i+3] = uint8(4*y + x)
}
}
var out image.Image
b.ResetTimer()
for i := 0; i < b.N; i++ {
out = Resize(benchWidth, benchHeight, m, interp)
}
out.At(0, 0)
}
// The names of some interpolation functions are truncated so that the columns
// of 'go test -bench' line up.
func Benchmark_Nearest_RGBA(b *testing.B) {
benchRGBA(b, NearestNeighbor)
}
func Benchmark_Bilinear_RGBA(b *testing.B) {
benchRGBA(b, Bilinear)
}
func Benchmark_Bicubic_RGBA(b *testing.B) {
benchRGBA(b, Bicubic)
}
func Benchmark_Mitchell_RGBA(b *testing.B) {
benchRGBA(b, MitchellNetravali)
}
func Benchmark_Lanczos2_RGBA(b *testing.B) {
benchRGBA(b, Lanczos2)
}
func Benchmark_Lanczos3_RGBA(b *testing.B) {
benchRGBA(b, Lanczos3)
}
func benchYCbCr(b *testing.B, interp InterpolationFunction) {
m := image.NewYCbCr(image.Rect(0, 0, benchMaxX, benchMaxY), image.YCbCrSubsampleRatio422)
// Initialize m's pixels to create a non-uniform image.
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
yi := m.YOffset(x, y)
ci := m.COffset(x, y)
m.Y[yi] = uint8(16*y + x)
m.Cb[ci] = uint8(y + 16*x)
m.Cr[ci] = uint8(y + 16*x)
}
}
var out image.Image
b.ResetTimer()
for i := 0; i < b.N; i++ {
out = Resize(benchWidth, benchHeight, m, interp)
}
out.At(0, 0)
}
func Benchmark_Nearest_YCC(b *testing.B) {
benchYCbCr(b, NearestNeighbor)
}
func Benchmark_Bilinear_YCC(b *testing.B) {
benchYCbCr(b, Bilinear)
}
func Benchmark_Bicubic_YCC(b *testing.B) {
benchYCbCr(b, Bicubic)
}
func Benchmark_Mitchell_YCC(b *testing.B) {
benchYCbCr(b, MitchellNetravali)
}
func Benchmark_Lanczos2_YCC(b *testing.B) {
benchYCbCr(b, Lanczos2)
}
func Benchmark_Lanczos3_YCC(b *testing.B) {
benchYCbCr(b, Lanczos3)
}

55
Godeps/_workspace/src/github.com/nfnt/resize/thumbnail.go сгенерированный поставляемый
Просмотреть файл

@@ -1,55 +0,0 @@
/*
Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import (
"image"
)
// Thumbnail will downscale provided image to max width and height preserving
// original aspect ratio and using the interpolation function interp.
// It will return original image, without processing it, if original sizes
// are already smaller than provided constraints.
func Thumbnail(maxWidth, maxHeight uint, img image.Image, interp InterpolationFunction) image.Image {
origBounds := img.Bounds()
origWidth := uint(origBounds.Dx())
origHeight := uint(origBounds.Dy())
newWidth, newHeight := origWidth, origHeight
// Return original image if it have same or smaller size as constraints
if maxWidth >= origWidth && maxHeight >= origHeight {
return img
}
// Preserve aspect ratio
if origWidth > maxWidth {
newHeight = uint(origHeight * maxWidth / origWidth)
if newHeight < 1 {
newHeight = 1
}
newWidth = maxWidth
}
if newHeight > maxHeight {
newWidth = uint(newWidth * maxHeight / newHeight)
if newWidth < 1 {
newWidth = 1
}
newHeight = maxHeight
}
return Resize(newWidth, newHeight, img, interp)
}

47
Godeps/_workspace/src/github.com/nfnt/resize/thumbnail_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,47 +0,0 @@
package resize
import (
"image"
"runtime"
"testing"
)
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
var thumbnailTests = []struct {
origWidth int
origHeight int
maxWidth uint
maxHeight uint
expectedWidth uint
expectedHeight uint
}{
{5, 5, 10, 10, 5, 5},
{10, 10, 5, 5, 5, 5},
{10, 50, 10, 10, 2, 10},
{50, 10, 10, 10, 10, 2},
{50, 100, 60, 90, 45, 90},
{120, 100, 60, 90, 60, 50},
{200, 250, 200, 150, 120, 150},
}
func TestThumbnail(t *testing.T) {
for i, tt := range thumbnailTests {
img := image.NewGray16(image.Rect(0, 0, tt.origWidth, tt.origHeight))
outImg := Thumbnail(tt.maxWidth, tt.maxHeight, img, NearestNeighbor)
newWidth := uint(outImg.Bounds().Dx())
newHeight := uint(outImg.Bounds().Dy())
if newWidth != tt.expectedWidth ||
newHeight != tt.expectedHeight {
t.Errorf("%d. Thumbnail(%v, %v, img, NearestNeighbor) => "+
"width: %v, height: %v, want width: %v, height: %v",
i, tt.maxWidth, tt.maxHeight,
newWidth, newHeight, tt.expectedWidth, tt.expectedHeight,
)
}
}
}

227
Godeps/_workspace/src/github.com/nfnt/resize/ycc.go сгенерированный поставляемый
Просмотреть файл

@@ -1,227 +0,0 @@
/*
Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import (
"image"
"image/color"
)
// ycc is an in memory YCbCr image. The Y, Cb and Cr samples are held in a
// single slice to increase resizing performance.
type ycc struct {
// Pix holds the image's pixels, in Y, Cb, Cr order. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*3].
Pix []uint8
// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect image.Rectangle
// SubsampleRatio is the subsample ratio of the original YCbCr image.
SubsampleRatio image.YCbCrSubsampleRatio
}
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *ycc) PixOffset(x, y int) int {
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*3
}
func (p *ycc) Bounds() image.Rectangle {
return p.Rect
}
func (p *ycc) ColorModel() color.Model {
return color.YCbCrModel
}
func (p *ycc) At(x, y int) color.Color {
if !(image.Point{x, y}.In(p.Rect)) {
return color.YCbCr{}
}
i := p.PixOffset(x, y)
return color.YCbCr{
p.Pix[i+0],
p.Pix[i+1],
p.Pix[i+2],
}
}
func (p *ycc) Opaque() bool {
return true
}
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *ycc) SubImage(r image.Rectangle) image.Image {
r = r.Intersect(p.Rect)
if r.Empty() {
return &ycc{SubsampleRatio: p.SubsampleRatio}
}
i := p.PixOffset(r.Min.X, r.Min.Y)
return &ycc{
Pix: p.Pix[i:],
Stride: p.Stride,
Rect: r,
SubsampleRatio: p.SubsampleRatio,
}
}
// newYCC returns a new ycc with the given bounds and subsample ratio.
func newYCC(r image.Rectangle, s image.YCbCrSubsampleRatio) *ycc {
w, h := r.Dx(), r.Dy()
buf := make([]uint8, 3*w*h)
return &ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: s}
}
// YCbCr converts ycc to a YCbCr image with the same subsample ratio
// as the YCbCr image that ycc was generated from.
func (p *ycc) YCbCr() *image.YCbCr {
ycbcr := image.NewYCbCr(p.Rect, p.SubsampleRatio)
var off int
switch ycbcr.SubsampleRatio {
case image.YCbCrSubsampleRatio422:
for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride
for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
xx := (x - ycbcr.Rect.Min.X)
yi := yy + xx
ci := cy + xx/2
ycbcr.Y[yi] = p.Pix[off+0]
ycbcr.Cb[ci] = p.Pix[off+1]
ycbcr.Cr[ci] = p.Pix[off+2]
off += 3
}
}
case image.YCbCrSubsampleRatio420:
for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride
for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
xx := (x - ycbcr.Rect.Min.X)
yi := yy + xx
ci := cy + xx/2
ycbcr.Y[yi] = p.Pix[off+0]
ycbcr.Cb[ci] = p.Pix[off+1]
ycbcr.Cr[ci] = p.Pix[off+2]
off += 3
}
}
case image.YCbCrSubsampleRatio440:
for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
cy := (y/2 - ycbcr.Rect.Min.Y/2) * ycbcr.CStride
for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
xx := (x - ycbcr.Rect.Min.X)
yi := yy + xx
ci := cy + xx
ycbcr.Y[yi] = p.Pix[off+0]
ycbcr.Cb[ci] = p.Pix[off+1]
ycbcr.Cr[ci] = p.Pix[off+2]
off += 3
}
}
default:
// Default to 4:4:4 subsampling.
for y := ycbcr.Rect.Min.Y; y < ycbcr.Rect.Max.Y; y++ {
yy := (y - ycbcr.Rect.Min.Y) * ycbcr.YStride
cy := (y - ycbcr.Rect.Min.Y) * ycbcr.CStride
for x := ycbcr.Rect.Min.X; x < ycbcr.Rect.Max.X; x++ {
xx := (x - ycbcr.Rect.Min.X)
yi := yy + xx
ci := cy + xx
ycbcr.Y[yi] = p.Pix[off+0]
ycbcr.Cb[ci] = p.Pix[off+1]
ycbcr.Cr[ci] = p.Pix[off+2]
off += 3
}
}
}
return ycbcr
}
// imageYCbCrToYCC converts a YCbCr image to a ycc image for resizing.
func imageYCbCrToYCC(in *image.YCbCr) *ycc {
w, h := in.Rect.Dx(), in.Rect.Dy()
r := image.Rect(0, 0, w, h)
buf := make([]uint8, 3*w*h)
p := ycc{Pix: buf, Stride: 3 * w, Rect: r, SubsampleRatio: in.SubsampleRatio}
var off int
switch in.SubsampleRatio {
case image.YCbCrSubsampleRatio422:
for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
yy := (y - in.Rect.Min.Y) * in.YStride
cy := (y - in.Rect.Min.Y) * in.CStride
for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
xx := (x - in.Rect.Min.X)
yi := yy + xx
ci := cy + xx/2
p.Pix[off+0] = in.Y[yi]
p.Pix[off+1] = in.Cb[ci]
p.Pix[off+2] = in.Cr[ci]
off += 3
}
}
case image.YCbCrSubsampleRatio420:
for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
yy := (y - in.Rect.Min.Y) * in.YStride
cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
xx := (x - in.Rect.Min.X)
yi := yy + xx
ci := cy + xx/2
p.Pix[off+0] = in.Y[yi]
p.Pix[off+1] = in.Cb[ci]
p.Pix[off+2] = in.Cr[ci]
off += 3
}
}
case image.YCbCrSubsampleRatio440:
for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
yy := (y - in.Rect.Min.Y) * in.YStride
cy := (y/2 - in.Rect.Min.Y/2) * in.CStride
for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
xx := (x - in.Rect.Min.X)
yi := yy + xx
ci := cy + xx
p.Pix[off+0] = in.Y[yi]
p.Pix[off+1] = in.Cb[ci]
p.Pix[off+2] = in.Cr[ci]
off += 3
}
}
default:
// Default to 4:4:4 subsampling.
for y := in.Rect.Min.Y; y < in.Rect.Max.Y; y++ {
yy := (y - in.Rect.Min.Y) * in.YStride
cy := (y - in.Rect.Min.Y) * in.CStride
for x := in.Rect.Min.X; x < in.Rect.Max.X; x++ {
xx := (x - in.Rect.Min.X)
yi := yy + xx
ci := cy + xx
p.Pix[off+0] = in.Y[yi]
p.Pix[off+1] = in.Cb[ci]
p.Pix[off+2] = in.Cr[ci]
off += 3
}
}
}
return &p
}

214
Godeps/_workspace/src/github.com/nfnt/resize/ycc_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,214 +0,0 @@
/*
Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
package resize
import (
"image"
"image/color"
"testing"
)
type Image interface {
image.Image
SubImage(image.Rectangle) image.Image
}
func TestImage(t *testing.T) {
testImage := []Image{
newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio420),
newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio422),
newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio440),
newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio444),
}
for _, m := range testImage {
if !image.Rect(0, 0, 10, 10).Eq(m.Bounds()) {
t.Errorf("%T: want bounds %v, got %v",
m, image.Rect(0, 0, 10, 10), m.Bounds())
continue
}
m = m.SubImage(image.Rect(3, 2, 9, 8)).(Image)
if !image.Rect(3, 2, 9, 8).Eq(m.Bounds()) {
t.Errorf("%T: sub-image want bounds %v, got %v",
m, image.Rect(3, 2, 9, 8), m.Bounds())
continue
}
// Test that taking an empty sub-image starting at a corner does not panic.
m.SubImage(image.Rect(0, 0, 0, 0))
m.SubImage(image.Rect(10, 0, 10, 0))
m.SubImage(image.Rect(0, 10, 0, 10))
m.SubImage(image.Rect(10, 10, 10, 10))
}
}
func TestConvertYCbCr(t *testing.T) {
testImage := []Image{
image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio420),
image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio422),
image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio440),
image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio444),
}
for _, img := range testImage {
m := img.(*image.YCbCr)
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
yi := m.YOffset(x, y)
ci := m.COffset(x, y)
m.Y[yi] = uint8(16*y + x)
m.Cb[ci] = uint8(y + 16*x)
m.Cr[ci] = uint8(y + 16*x)
}
}
// test conversion from YCbCr to ycc
yc := imageYCbCrToYCC(m)
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
ystride := 3 * (m.Rect.Max.X - m.Rect.Min.X)
xstride := 3
yi := m.YOffset(x, y)
ci := m.COffset(x, y)
si := (y * ystride) + (x * xstride)
if m.Y[yi] != yc.Pix[si] {
t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d si: %d",
m.Y[yi], yc.Pix[si], x, y, yi, si)
}
if m.Cb[ci] != yc.Pix[si+1] {
t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d si: %d",
m.Cb[ci], yc.Pix[si+1], x, y, ci, si+1)
}
if m.Cr[ci] != yc.Pix[si+2] {
t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d si: %d",
m.Cr[ci], yc.Pix[si+2], x, y, ci, si+2)
}
}
}
// test conversion from ycc back to YCbCr
ym := yc.YCbCr()
for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
yi := m.YOffset(x, y)
ci := m.COffset(x, y)
if m.Y[yi] != ym.Y[yi] {
t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d",
m.Y[yi], ym.Y[yi], x, y, yi)
}
if m.Cb[ci] != ym.Cb[ci] {
t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d",
m.Cb[ci], ym.Cb[ci], x, y, ci)
}
if m.Cr[ci] != ym.Cr[ci] {
t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d",
m.Cr[ci], ym.Cr[ci], x, y, ci)
}
}
}
}
}
func TestYCbCr(t *testing.T) {
rects := []image.Rectangle{
image.Rect(0, 0, 16, 16),
image.Rect(1, 0, 16, 16),
image.Rect(0, 1, 16, 16),
image.Rect(1, 1, 16, 16),
image.Rect(1, 1, 15, 16),
image.Rect(1, 1, 16, 15),
image.Rect(1, 1, 15, 15),
image.Rect(2, 3, 14, 15),
image.Rect(7, 0, 7, 16),
image.Rect(0, 8, 16, 8),
image.Rect(0, 0, 10, 11),
image.Rect(5, 6, 16, 16),
image.Rect(7, 7, 8, 8),
image.Rect(7, 8, 8, 9),
image.Rect(8, 7, 9, 8),
image.Rect(8, 8, 9, 9),
image.Rect(7, 7, 17, 17),
image.Rect(8, 8, 17, 17),
image.Rect(9, 9, 17, 17),
image.Rect(10, 10, 17, 17),
}
subsampleRatios := []image.YCbCrSubsampleRatio{
image.YCbCrSubsampleRatio444,
image.YCbCrSubsampleRatio422,
image.YCbCrSubsampleRatio420,
image.YCbCrSubsampleRatio440,
}
deltas := []image.Point{
image.Pt(0, 0),
image.Pt(1000, 1001),
image.Pt(5001, -400),
image.Pt(-701, -801),
}
for _, r := range rects {
for _, subsampleRatio := range subsampleRatios {
for _, delta := range deltas {
testYCbCr(t, r, subsampleRatio, delta)
}
}
if testing.Short() {
break
}
}
}
func testYCbCr(t *testing.T, r image.Rectangle, subsampleRatio image.YCbCrSubsampleRatio, delta image.Point) {
// Create a YCbCr image m, whose bounds are r translated by (delta.X, delta.Y).
r1 := r.Add(delta)
img := image.NewYCbCr(r1, subsampleRatio)
// Initialize img's pixels. For 422 and 420 subsampling, some of the Cb and Cr elements
// will be set multiple times. That's OK. We just want to avoid a uniform image.
for y := r1.Min.Y; y < r1.Max.Y; y++ {
for x := r1.Min.X; x < r1.Max.X; x++ {
yi := img.YOffset(x, y)
ci := img.COffset(x, y)
img.Y[yi] = uint8(16*y + x)
img.Cb[ci] = uint8(y + 16*x)
img.Cr[ci] = uint8(y + 16*x)
}
}
m := imageYCbCrToYCC(img)
// Make various sub-images of m.
for y0 := delta.Y + 3; y0 < delta.Y+7; y0++ {
for y1 := delta.Y + 8; y1 < delta.Y+13; y1++ {
for x0 := delta.X + 3; x0 < delta.X+7; x0++ {
for x1 := delta.X + 8; x1 < delta.X+13; x1++ {
subRect := image.Rect(x0, y0, x1, y1)
sub := m.SubImage(subRect).(*ycc)
// For each point in the sub-image's bounds, check that m.At(x, y) equals sub.At(x, y).
for y := sub.Rect.Min.Y; y < sub.Rect.Max.Y; y++ {
for x := sub.Rect.Min.X; x < sub.Rect.Max.X; x++ {
color0 := m.At(x, y).(color.YCbCr)
color1 := sub.At(x, y).(color.YCbCr)
if color0 != color1 {
t.Errorf("r=%v, subsampleRatio=%v, delta=%v, x=%d, y=%d, color0=%v, color1=%v",
r, subsampleRatio, delta, x, y, color0, color1)
return
}
}
}
}
}
}
}
}