246 lines
5.5 KiB
Go
246 lines
5.5 KiB
Go
package oklab
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"image/draw"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewImage(t *testing.T) {
|
|
r := image.Rect(13, 21, 34, 55)
|
|
img := NewImage(r)
|
|
|
|
if img.Rect != r {
|
|
t.Errorf("img.Rect = %v, want %v", img.Rect, r)
|
|
}
|
|
|
|
if got := img.Bounds(); got != r {
|
|
t.Errorf("img.Bounds() = %v, want %v", got, r)
|
|
}
|
|
|
|
if got := img.ColorModel(); got != Model {
|
|
t.Errorf("img.ColorModel() = %v, want %v", got, Model)
|
|
}
|
|
|
|
if got, want := img.Stride, r.Dx()*bytesPerPixel; got != want {
|
|
t.Errorf("img.Stride = %v, want %v", got, want)
|
|
}
|
|
|
|
if got, want := len(img.Pix), (r.Dy()-1)*img.Stride+r.Dx()*bytesPerPixel; got != want {
|
|
t.Errorf("len(img.Pix) = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func testColor(x, y int) Color {
|
|
return Color{
|
|
float64(x),
|
|
float64(y),
|
|
float64(x + y),
|
|
float64(x ^ y),
|
|
}
|
|
}
|
|
|
|
func mod(a int, m int) int {
|
|
a = a % m
|
|
if a < 0 {
|
|
// fucking intel.
|
|
a += m
|
|
}
|
|
return a
|
|
}
|
|
|
|
func testRGBA64Color(x, y int) color.RGBA64 {
|
|
a := mod(x^y, 0xffff)
|
|
|
|
return color.RGBA64{
|
|
uint16(mod(x, a+1)),
|
|
uint16(mod(y, a+1)),
|
|
uint16(mod(x+y, a+1)),
|
|
uint16(a),
|
|
}
|
|
}
|
|
|
|
func TestImage_Set(t *testing.T) {
|
|
r := image.Rect(13, 21, 34, 55)
|
|
img := NewImage(r)
|
|
|
|
// intentionally invoking SetOkLab beyond the boundaries of the image, here.
|
|
for y := r.Min.Y - 1; y <= r.Max.Y; y++ {
|
|
for x := r.Min.X - 1; x <= r.Max.X; x++ {
|
|
img.Set(x, y, testColor(x, y))
|
|
}
|
|
}
|
|
|
|
for y := r.Min.Y - 1; y <= r.Max.Y; y++ {
|
|
for x := r.Min.X - 1; x <= r.Max.X; x++ {
|
|
want := Color{}
|
|
|
|
if image.Pt(x, y).In(r) {
|
|
want = testColor(x, y)
|
|
}
|
|
|
|
got := img.At(x, y).(Color)
|
|
|
|
if got != want {
|
|
t.Errorf("img.At(%d, %d) = %v, want %v", x, y, got, want)
|
|
// stop at the first error, please.
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestImage_SetRGBA64(t *testing.T) {
|
|
r := image.Rect(13, 21, 34, 55)
|
|
img := NewImage(r)
|
|
|
|
// intentionally invoking SetOkLab beyond the boundaries of the image, here.
|
|
for y := r.Min.Y - 1; y <= r.Max.Y; y++ {
|
|
for x := r.Min.X - 1; x <= r.Max.X; x++ {
|
|
img.SetRGBA64(x, y, testRGBA64Color(x, y))
|
|
}
|
|
}
|
|
|
|
for y := r.Min.Y - 1; y <= r.Max.Y; y++ {
|
|
for x := r.Min.X - 1; x <= r.Max.X; x++ {
|
|
want := color.RGBA64{}
|
|
|
|
if image.Pt(x, y).In(r) {
|
|
want = testRGBA64Color(x, y)
|
|
}
|
|
|
|
got := img.RGBA64At(x, y)
|
|
|
|
if got != want {
|
|
t.Errorf("img.RGBA64At(%d, %d) = %v, want %v", x, y, got, want)
|
|
// stop at the first error, please.
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func setPixels(img *Image) {
|
|
for y := img.Rect.Min.Y - 1; y <= img.Rect.Max.Y; y++ {
|
|
for x := img.Rect.Min.X - 1; x <= img.Rect.Max.X; x++ {
|
|
img.SetOkLab(x, y, testColor(x, y))
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkPixels(t *testing.T, img *Image) {
|
|
for y := img.Rect.Min.Y - 1; y <= img.Rect.Max.Y; y++ {
|
|
for x := img.Rect.Min.X - 1; x <= img.Rect.Max.X; x++ {
|
|
want := Color{}
|
|
|
|
if image.Pt(x, y).In(img.Rect) {
|
|
want = testColor(x, y)
|
|
}
|
|
|
|
got := img.OkLabAt(x, y)
|
|
|
|
if got != want {
|
|
t.Errorf("checkPixels: img.OkLabAt(%d, %d) = %v, want %v", x, y, got, want)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestImage_SetOkLab(t *testing.T) {
|
|
r := image.Rect(13, 21, 34, 55)
|
|
img := NewImage(r)
|
|
|
|
setPixels(img)
|
|
checkPixels(t, img)
|
|
}
|
|
|
|
func TestImage_SubImage(t *testing.T) {
|
|
r := image.Rect(13, 21, 34, 55)
|
|
img := NewImage(r)
|
|
|
|
setPixels(img)
|
|
|
|
for _, tt := range []struct {
|
|
name string
|
|
r image.Rectangle
|
|
}{
|
|
{"identity", r},
|
|
{"inset", r.Inset(1)},
|
|
{"outset", r.Inset(-1)},
|
|
{"left", r.Add(image.Pt(-1, 0))},
|
|
{"right", r.Add(image.Pt(1, 0))},
|
|
{"up", r.Add(image.Pt(0, -1))},
|
|
{"down", r.Add(image.Pt(0, 1))},
|
|
{"outside", image.Rect(-100, -100, 1, 1)},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
subImage := img.SubImage(tt.r)
|
|
|
|
if got, want := subImage.Rect, img.Rect.Intersect(tt.r); got != want {
|
|
t.Errorf("subImage.Rect = %v, want %v", got, want)
|
|
return
|
|
}
|
|
|
|
if got, want := subImage.Stride, subImage.Rect.Dx()*bytesPerPixel; got < want {
|
|
t.Errorf("subImage.Stride = %v, want >= %v", got, want)
|
|
}
|
|
|
|
if got, want := len(subImage.Pix), (subImage.Rect.Dy()-1)*subImage.Stride+subImage.Rect.Dx()*bytesPerPixel; got != want {
|
|
t.Errorf("len(img.Pix) = %v, want %v", got, want)
|
|
}
|
|
|
|
checkPixels(t, subImage)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestImage_Opaque(t *testing.T) {
|
|
t.Run("empty", func(t *testing.T) {
|
|
// an empty image is opaque by virtue of not containing any pixels, opaque or otherwise.
|
|
got, want := NewImage(image.Rect(0, 0, 0, 0)).Opaque(), true
|
|
if got != want {
|
|
t.Errorf("Opaque() = %v, want %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("non-empty", func(t *testing.T) {
|
|
img := NewImage(image.Rect(13, 21, 34, 55))
|
|
|
|
// the pixels of a non-empty image will have an alpha value of zero,
|
|
// make it completely transparent.
|
|
got, want := img.Opaque(), false
|
|
if got != want {
|
|
t.Errorf("img.Opaque() = %v, want %v", got, want)
|
|
}
|
|
|
|
t.Run("explicitly transparent", func(t *testing.T) {
|
|
// if we explicitly set every pixel to be transparent, the result should be the same.
|
|
draw.Draw(img, img.Rect, image.Transparent, image.Point{}, draw.Src)
|
|
got, want := img.Opaque(), false
|
|
|
|
if got != want {
|
|
t.Errorf("img.Opaque() = %v, want %v", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("opaque", func(t *testing.T) {
|
|
// make every pixel opaque.
|
|
draw.Draw(img, img.Rect, image.Opaque, image.Point{}, draw.Src)
|
|
got, want := img.Opaque(), true
|
|
if got != want {
|
|
t.Errorf("img.Opaque() = %v, want %v", got, want)
|
|
}
|
|
|
|
t.Run("except for a single transparent pixel", func(t *testing.T) {
|
|
img.Set(14, 23, color.Transparent)
|
|
got, want := img.Opaque(), false
|
|
if got != want {
|
|
t.Errorf("img.Opaque() = %v, want %v", got, want)
|
|
}
|
|
})
|
|
})
|
|
})
|
|
}
|