Skip to content

Commit

Permalink
Add decoding/encoding tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
harukasan committed Nov 11, 2016
1 parent 6003d49 commit 8c0364f
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 0 deletions.
38 changes: 38 additions & 0 deletions jpeg/jpeg_test.go
Expand Up @@ -381,3 +381,41 @@ func TestEncodeFailsWithEmptyImage(t *testing.T) {
t.Errorf("got no error with empty image")
}
}

func newRGBA() *image.RGBA {
rgba := image.NewRGBA(image.Rect(0, 0, 4, 8))
for i := 0; i < 4; i++ {
for j := 0; j < 4; j++ {
rgba.SetRGBA(i, j, color.RGBA{255, 0, 0, 255})
}
for j := 4; j < 8; j++ {
rgba.SetRGBA(i, j, color.RGBA{0, 0, 255, 255})
}
}
return rgba
}

func TestEncodeRGBA(t *testing.T) {
rgba := newRGBA()
w := bytes.NewBuffer(nil)

err := jpeg.Encode(w, rgba, &jpeg.EncoderOptions{
Quality: 100,
})
if err != nil {
t.Fatalf("failed to encode: %v", err)
}

decoded, err := jpeg.Decode(w, &jpeg.DecoderOptions{})
if err != nil {
t.Fatalf("failed to decode: %v", err)
}

diff, err := util.MatchImage(rgba, decoded, 1)
if err != nil {
t.Errorf("match image: %v", err)
util.WritePNG(rgba, "TestEncodeRGBA.want.png")
util.WritePNG(decoded, "TestEncodeRGBA.got.png")
util.WritePNG(diff, "TestEncodeRGBA.diff.png")
}
}
93 changes: 93 additions & 0 deletions test/util/matchcolor.go
@@ -0,0 +1,93 @@
package util

import (
"fmt"
"image"
"image/color"
)

func delta(a, b uint8) int {
d := int(a) - int(b)
if d < 0 {
return -d
}
return d
}

// MatchColor returns whteher the difference between two colors is smaller than
// the given tolerance. If the two colors a and b assume to the same, it returns
// true.
func MatchColor(a, b color.Color, tolerance int) (matched bool) {
switch ca := a.(type) {
case color.CMYK:
if cb, ok := b.(color.CMYK); ok {
dC, dM, dY, dK := delta(ca.C, cb.C), delta(ca.M, cb.M), delta(ca.Y, cb.Y), delta(ca.K, cb.K)
if dC > tolerance || dM > tolerance || dY > tolerance || dK > tolerance {
return false
}
return true
}
case color.YCbCr:
if cb, ok := b.(color.YCbCr); ok {
dY, dCb, dCr := delta(ca.Y, cb.Y), delta(ca.Cb, cb.Cb), delta(ca.Cr, cb.Cr)
if dY > tolerance || dCb > tolerance || dCr > tolerance {
return false
}
return true
}
case color.NRGBA:
if cb, ok := b.(color.NRGBA); ok {
dR, dG, dB, dA := delta(ca.R, cb.R), delta(ca.G, cb.G), delta(ca.B, cb.B), delta(ca.A, cb.A)
if ca.A == 0 && cb.A == 0 {
return true
}
if dR > tolerance || dG > tolerance || dB > tolerance || dA > tolerance {
return false
}
return true
}
}

ar, ag, ab, aa := a.RGBA()
br, bg, bb, ba := b.RGBA()
dr := delta(uint8(ar>>8), uint8(br>>8))
dg := delta(uint8(ag>>8), uint8(bg>>8))
db := delta(uint8(ab>>8), uint8(bb>>8))
da := delta(uint8(aa>>8), uint8(ba>>8))
if dr > tolerance || dg > tolerance || db > tolerance || da > tolerance {
return false
}
return true
}

// MatchImage matches by pixel-by-pixel. If any one of pixel does not matched,
// it returns an error with image difference (a - b).
func MatchImage(a, b image.Image, tolerance int) (diff image.Image, err error) {
if a == nil {
return nil, fmt.Errorf("first image is nil")
} else if b == nil {
return nil, fmt.Errorf("second image is nil")
}
if a.Bounds().Dx() != b.Bounds().Dx() || a.Bounds().Dy() != b.Bounds().Dy() {
return nil, fmt.Errorf("unmatched bounds: %v != %v\n", a.Bounds(), b.Bounds())
}
rgba := image.NewRGBA(a.Bounds())
dp := 0
for x := 0; x < a.Bounds().Dx(); x++ {
for y := 0; y < a.Bounds().Dy(); y++ {
aC := a.At(a.Bounds().Min.X+x, a.Bounds().Min.Y+y)
bC := b.At(b.Bounds().Min.X+x, b.Bounds().Min.Y+y)
if !MatchColor(aC, bC, tolerance) {
dp++
aR, aG, aB, _ := aC.RGBA()
bR, bG, bB, _ := bC.RGBA()
dR, dG, dB := delta(uint8(aR>>8), uint8(bR>>8)), delta(uint8(aG>>8), uint8(bG>>8)), delta(uint8(aB>>8), uint8(bB>>8))
rgba.SetRGBA(x, y, color.RGBA{uint8(dR), uint8(dG), uint8(dB), 255})
}
}
}
if dp > 0 {
return rgba, fmt.Errorf("image unmatched")
}
return
}
137 changes: 137 additions & 0 deletions test/util/matchcolor_test.go
@@ -0,0 +1,137 @@
package util

import (
"image"
"image/color"
"testing"
)

var colorMatches = []struct {
a, b color.Color
tolerance int
match bool
}{
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{0, 0, 0, 0},
0,
true,
},
{
color.NRGBA{1, 1, 1, 1},
color.NRGBA{1, 1, 1, 1},
0,
true,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{0, 0, 0, 1},
0,
false,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{1, 0, 0, 0},
0,
true,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{1, 0, 0, 1},
0,
false,
},
{
color.NRGBA{0, 1, 0, 1},
color.NRGBA{1, 0, 0, 1},
0,
false,
},
{
color.NRGBA{0, 0, 0, 1},
color.NRGBA{1, 0, 0, 1},
0,
false,
},
{
color.NRGBA{1, 0, 0, 2},
color.NRGBA{2, 0, 0, 1},
0,
false,
},
{
color.NRGBA{0, 0, 0, 127},
color.NRGBA{2, 0, 0, 127},
0,
false,
},
{
color.NRGBA{126, 0, 0, 127},
color.NRGBA{127, 0, 0, 126},
0,
false,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{0, 0, 0, 1},
1,
true,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{1, 0, 0, 0},
1,
true,
},
{
color.NRGBA{0, 0, 0, 0},
color.NRGBA{1, 0, 0, 1},
1,
true,
},
{
color.NRGBA{0, 0, 0, 255},
color.NRGBA{0, 0, 0, 255},
0,
true,
},
{
color.NRGBA{127, 0, 0, 255},
color.NRGBA{126, 0, 0, 255},
1,
true,
},
{
color.NRGBA{127, 0, 0, 126},
color.NRGBA{126, 0, 0, 127},
1,
true,
},
{
color.YCbCr{76, 85, 255},
color.NRGBA{255, 0, 0, 255},
1,
true,
},
}

func TestMatchImage(t *testing.T) {
for _, x := range colorMatches {
a := image.NewNRGBA(image.Rect(0, 0, 1, 1))
b := image.NewNRGBA(image.Rect(0, 0, 1, 1))
a.Set(0, 0, x.a)
b.Set(0, 0, x.b)

if _, err := MatchImage(a, b, x.tolerance); (err == nil) != x.match {
t.Errorf("MatchImage(a:%v b:%v, tolerance: %v) err:%v but want:%v", x.a, x.b, x.tolerance, err, x.match)
}
}
}

func TestMatchColor(t *testing.T) {
for _, x := range colorMatches {
if got := MatchColor(x.a, x.b, x.tolerance); x.match != got {
t.Errorf("MatchColor(a:%v b:%v, tolerance: %v) got:%v but want:%v", x.a, x.b, x.tolerance, got, x.match)
}
}
}

0 comments on commit 8c0364f

Please sign in to comment.