mirror of
https://github.com/esimov/caire.git
synced 2025-09-26 20:41:14 +08:00
test: included image test cases
This commit is contained in:
228
image_test.go
Normal file
228
image_test.go
Normal file
@@ -0,0 +1,228 @@
|
||||
package caire
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/color/palette"
|
||||
"image/draw"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestImage_ShouldGetSampleImage(t *testing.T) {
|
||||
path := filepath.Join("./testdata", "sample.jpg")
|
||||
_, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("Should get the sample image")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImage_ImgToNRGBA(t *testing.T) {
|
||||
rect := image.Rect(-1, -1, 15, 15)
|
||||
colors := palette.Plan9
|
||||
testCases := []struct {
|
||||
name string
|
||||
img image.Image
|
||||
}{
|
||||
{
|
||||
name: "NRGBA",
|
||||
img: makeNRGBAImage(rect, colors),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-444",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio444),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-422",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio422),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-420",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio420),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-440",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio440),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-410",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio410),
|
||||
},
|
||||
{
|
||||
name: "YCbCr-411",
|
||||
img: makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio411),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r := tc.img.Bounds()
|
||||
for y := r.Min.Y; y < r.Max.Y; y++ {
|
||||
buf := make([]byte, r.Dx()*4)
|
||||
scan(tc.img, 0, y-r.Min.Y, r.Dx(), y+1-r.Min.Y, buf)
|
||||
wantBuf := readRow(tc.img, y)
|
||||
if !compareBytes(buf, wantBuf, 1) {
|
||||
t.Errorf("scan horizontal line (y=%d): got %v want %v", y, buf, wantBuf)
|
||||
}
|
||||
}
|
||||
for x := r.Min.X; x < r.Max.X; x++ {
|
||||
buf := make([]byte, r.Dy()*4)
|
||||
scan(tc.img, x-r.Min.X, 0, x+1-r.Min.X, r.Dy(), buf)
|
||||
wantBuf := readColumn(tc.img, x)
|
||||
if !compareBytes(buf, wantBuf, 1) {
|
||||
t.Errorf("scan vertical line (x=%d): got %v want %v", x, buf, wantBuf)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func scan(img image.Image, x1, y1, x2, y2 int, dst []uint8) {
|
||||
switch img := img.(type) {
|
||||
case *image.NRGBA:
|
||||
size := (x2 - x1) * 4
|
||||
j := 0
|
||||
i := y1*img.Stride + x1*4
|
||||
for y := y1; y < y2; y++ {
|
||||
copy(dst[j:j+size], img.Pix[i:i+size])
|
||||
j += size
|
||||
i += img.Stride
|
||||
}
|
||||
case *image.YCbCr:
|
||||
j := 0
|
||||
x1 += img.Rect.Min.X
|
||||
x2 += img.Rect.Min.X
|
||||
y1 += img.Rect.Min.Y
|
||||
y2 += img.Rect.Min.Y
|
||||
for y := y1; y < y2; y++ {
|
||||
iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X)
|
||||
for x := x1; x < x2; x++ {
|
||||
var ic int
|
||||
switch img.SubsampleRatio {
|
||||
case image.YCbCrSubsampleRatio444:
|
||||
ic = (y-img.Rect.Min.Y)*img.CStride + (x - img.Rect.Min.X)
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
ic = (y-img.Rect.Min.Y)*img.CStride + (x/2 - img.Rect.Min.X/2)
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x/2 - img.Rect.Min.X/2)
|
||||
case image.YCbCrSubsampleRatio440:
|
||||
ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x - img.Rect.Min.X)
|
||||
default:
|
||||
ic = img.COffset(x, y)
|
||||
}
|
||||
|
||||
yy := int(img.Y[iy])
|
||||
cb := int(img.Cb[ic]) - 128
|
||||
cr := int(img.Cr[ic]) - 128
|
||||
|
||||
r := (yy<<16 + 91881*cr + 1<<15) >> 16
|
||||
if r > 0xff {
|
||||
r = 0xff
|
||||
} else if r < 0 {
|
||||
r = 0
|
||||
}
|
||||
|
||||
g := (yy<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
|
||||
if g > 0xff {
|
||||
g = 0xff
|
||||
} else if g < 0 {
|
||||
g = 0
|
||||
}
|
||||
|
||||
b := (yy<<16 + 116130*cb + 1<<15) >> 16
|
||||
if b > 0xff {
|
||||
b = 0xff
|
||||
} else if b < 0 {
|
||||
b = 0
|
||||
}
|
||||
|
||||
dst[j+0] = uint8(r)
|
||||
dst[j+1] = uint8(g)
|
||||
dst[j+2] = uint8(b)
|
||||
dst[j+3] = 0xff
|
||||
|
||||
iy++
|
||||
j += 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeYCbCrImage(rect image.Rectangle, colors []color.Color, sr image.YCbCrSubsampleRatio) *image.YCbCr {
|
||||
img := image.NewYCbCr(rect, sr)
|
||||
j := 0
|
||||
for y := rect.Min.Y; y < rect.Max.Y; y++ {
|
||||
for x := rect.Min.X; x < rect.Max.X; x++ {
|
||||
iy := img.YOffset(x, y)
|
||||
ic := img.COffset(x, y)
|
||||
c := color.NRGBAModel.Convert(colors[j]).(color.NRGBA)
|
||||
img.Y[iy], img.Cb[ic], img.Cr[ic] = color.RGBToYCbCr(c.R, c.G, c.B)
|
||||
j++
|
||||
}
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
||||
func makeNRGBAImage(rect image.Rectangle, colors []color.Color) *image.NRGBA {
|
||||
img := image.NewNRGBA(rect)
|
||||
fillDrawImage(img, colors)
|
||||
return img
|
||||
}
|
||||
|
||||
func fillDrawImage(img draw.Image, colors []color.Color) {
|
||||
colorsNRGBA := make([]color.NRGBA, len(colors))
|
||||
for i, c := range colors {
|
||||
nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)
|
||||
nrgba.A = uint8(i % 256)
|
||||
colorsNRGBA[i] = nrgba
|
||||
}
|
||||
rect := img.Bounds()
|
||||
i := 0
|
||||
for y := rect.Min.Y; y < rect.Max.Y; y++ {
|
||||
for x := rect.Min.X; x < rect.Max.X; x++ {
|
||||
img.Set(x, y, colorsNRGBA[i])
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readRow(img image.Image, y int) []uint8 {
|
||||
row := make([]byte, img.Bounds().Dx()*4)
|
||||
i := 0
|
||||
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
row[i+0] = c.R
|
||||
row[i+1] = c.G
|
||||
row[i+2] = c.B
|
||||
row[i+3] = c.A
|
||||
i += 4
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
func readColumn(img image.Image, x int) []uint8 {
|
||||
column := make([]byte, img.Bounds().Dy()*4)
|
||||
i := 0
|
||||
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
column[i+0] = c.R
|
||||
column[i+1] = c.G
|
||||
column[i+2] = c.B
|
||||
column[i+3] = c.A
|
||||
i += 4
|
||||
}
|
||||
return column
|
||||
}
|
||||
|
||||
func compareBytes(a, b []uint8, delta int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(a); i++ {
|
||||
if absint(int(a[i])-int(b[i])) > delta {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user