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) } }) }) }) }