git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/imaging/scanner_test.go (about)

     1  package imaging
     2  
     3  import (
     4  	"fmt"
     5  	"image"
     6  	"image/color"
     7  	"image/color/palette"
     8  	"image/draw"
     9  	"testing"
    10  )
    11  
    12  func TestScanner(t *testing.T) {
    13  	rect := image.Rect(-1, -1, 15, 15)
    14  	colors := palette.Plan9
    15  	testCases := []struct {
    16  		name string
    17  		img  image.Image
    18  	}{
    19  		{
    20  			name: "NRGBA",
    21  			img:  makeNRGBAImage(rect, colors),
    22  		},
    23  		{
    24  			name: "NRGBA64",
    25  			img:  makeNRGBA64Image(rect, colors),
    26  		},
    27  		{
    28  			name: "RGBA",
    29  			img:  makeRGBAImage(rect, colors),
    30  		},
    31  		{
    32  			name: "RGBA64",
    33  			img:  makeRGBA64Image(rect, colors),
    34  		},
    35  		{
    36  			name: "Gray",
    37  			img:  makeGrayImage(rect, colors),
    38  		},
    39  		{
    40  			name: "Gray16",
    41  			img:  makeGray16Image(rect, colors),
    42  		},
    43  		{
    44  			name: "YCbCr-444",
    45  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio444),
    46  		},
    47  		{
    48  			name: "YCbCr-422",
    49  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio422),
    50  		},
    51  		{
    52  			name: "YCbCr-420",
    53  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio420),
    54  		},
    55  		{
    56  			name: "YCbCr-440",
    57  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio440),
    58  		},
    59  		{
    60  			name: "YCbCr-410",
    61  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio410),
    62  		},
    63  		{
    64  			name: "YCbCr-411",
    65  			img:  makeYCbCrImage(rect, colors, image.YCbCrSubsampleRatio411),
    66  		},
    67  		{
    68  			name: "Paletted",
    69  			img:  makePalettedImage(rect, colors),
    70  		},
    71  		{
    72  			name: "Alpha",
    73  			img:  makeAlphaImage(rect, colors),
    74  		},
    75  		{
    76  			name: "Alpha16",
    77  			img:  makeAlpha16Image(rect, colors),
    78  		},
    79  		{
    80  			name: "Generic",
    81  			img:  makeGenericImage(rect, colors),
    82  		},
    83  	}
    84  
    85  	for _, tc := range testCases {
    86  		t.Run(tc.name, func(t *testing.T) {
    87  			r := tc.img.Bounds()
    88  			s := newScanner(tc.img)
    89  			for y := r.Min.Y; y < r.Max.Y; y++ {
    90  				buf := make([]byte, r.Dx()*4)
    91  				s.scan(0, y-r.Min.Y, r.Dx(), y+1-r.Min.Y, buf)
    92  				wantBuf := readRow(tc.img, y)
    93  				if !compareBytes(buf, wantBuf, 1) {
    94  					fmt.Println(tc.img)
    95  					t.Fatalf("scan horizontal line (y=%d): got %v want %v", y, buf, wantBuf)
    96  				}
    97  			}
    98  			for x := r.Min.X; x < r.Max.X; x++ {
    99  				buf := make([]byte, r.Dy()*4)
   100  				s.scan(x-r.Min.X, 0, x+1-r.Min.X, r.Dy(), buf)
   101  				wantBuf := readColumn(tc.img, x)
   102  				if !compareBytes(buf, wantBuf, 1) {
   103  					t.Fatalf("scan vertical line (x=%d): got %v want %v", x, buf, wantBuf)
   104  				}
   105  			}
   106  		})
   107  	}
   108  }
   109  
   110  func makeYCbCrImage(rect image.Rectangle, colors []color.Color, sr image.YCbCrSubsampleRatio) *image.YCbCr {
   111  	img := image.NewYCbCr(rect, sr)
   112  	j := 0
   113  	for y := rect.Min.Y; y < rect.Max.Y; y++ {
   114  		for x := rect.Min.X; x < rect.Max.X; x++ {
   115  			iy := img.YOffset(x, y)
   116  			ic := img.COffset(x, y)
   117  			c := color.NRGBAModel.Convert(colors[j]).(color.NRGBA)
   118  			img.Y[iy], img.Cb[ic], img.Cr[ic] = color.RGBToYCbCr(c.R, c.G, c.B)
   119  			j++
   120  		}
   121  	}
   122  	return img
   123  }
   124  
   125  func makeNRGBAImage(rect image.Rectangle, colors []color.Color) *image.NRGBA {
   126  	img := image.NewNRGBA(rect)
   127  	fillDrawImage(img, colors)
   128  	return img
   129  }
   130  
   131  func makeNRGBA64Image(rect image.Rectangle, colors []color.Color) *image.NRGBA64 {
   132  	img := image.NewNRGBA64(rect)
   133  	fillDrawImage(img, colors)
   134  	return img
   135  }
   136  
   137  func makeRGBAImage(rect image.Rectangle, colors []color.Color) *image.RGBA {
   138  	img := image.NewRGBA(rect)
   139  	fillDrawImage(img, colors)
   140  	return img
   141  }
   142  
   143  func makeRGBA64Image(rect image.Rectangle, colors []color.Color) *image.RGBA64 {
   144  	img := image.NewRGBA64(rect)
   145  	fillDrawImage(img, colors)
   146  	return img
   147  }
   148  
   149  func makeGrayImage(rect image.Rectangle, colors []color.Color) *image.Gray {
   150  	img := image.NewGray(rect)
   151  	fillDrawImage(img, colors)
   152  	return img
   153  }
   154  
   155  func makeGray16Image(rect image.Rectangle, colors []color.Color) *image.Gray16 {
   156  	img := image.NewGray16(rect)
   157  	fillDrawImage(img, colors)
   158  	return img
   159  }
   160  
   161  func makePalettedImage(rect image.Rectangle, colors []color.Color) *image.Paletted {
   162  	img := image.NewPaletted(rect, colors)
   163  	fillDrawImage(img, colors)
   164  	return img
   165  }
   166  
   167  func makeAlphaImage(rect image.Rectangle, colors []color.Color) *image.Alpha {
   168  	img := image.NewAlpha(rect)
   169  	fillDrawImage(img, colors)
   170  	return img
   171  }
   172  
   173  func makeAlpha16Image(rect image.Rectangle, colors []color.Color) *image.Alpha16 {
   174  	img := image.NewAlpha16(rect)
   175  	fillDrawImage(img, colors)
   176  	return img
   177  }
   178  
   179  func makeGenericImage(rect image.Rectangle, colors []color.Color) image.Image {
   180  	img := image.NewRGBA(rect)
   181  	fillDrawImage(img, colors)
   182  	type genericImage struct{ *image.RGBA }
   183  	return &genericImage{img}
   184  }
   185  
   186  func fillDrawImage(img draw.Image, colors []color.Color) {
   187  	colorsNRGBA := make([]color.NRGBA, len(colors))
   188  	for i, c := range colors {
   189  		nrgba := color.NRGBAModel.Convert(c).(color.NRGBA)
   190  		nrgba.A = uint8(i % 256)
   191  		colorsNRGBA[i] = nrgba
   192  	}
   193  	rect := img.Bounds()
   194  	i := 0
   195  	for y := rect.Min.Y; y < rect.Max.Y; y++ {
   196  		for x := rect.Min.X; x < rect.Max.X; x++ {
   197  			img.Set(x, y, colorsNRGBA[i])
   198  			i++
   199  		}
   200  	}
   201  }
   202  
   203  func readRow(img image.Image, y int) []uint8 {
   204  	row := make([]byte, img.Bounds().Dx()*4)
   205  	i := 0
   206  	for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
   207  		c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
   208  		row[i+0] = c.R
   209  		row[i+1] = c.G
   210  		row[i+2] = c.B
   211  		row[i+3] = c.A
   212  		i += 4
   213  	}
   214  	return row
   215  }
   216  
   217  func readColumn(img image.Image, x int) []uint8 {
   218  	column := make([]byte, img.Bounds().Dy()*4)
   219  	i := 0
   220  	for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
   221  		c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
   222  		column[i+0] = c.R
   223  		column[i+1] = c.G
   224  		column[i+2] = c.B
   225  		column[i+3] = c.A
   226  		i += 4
   227  	}
   228  	return column
   229  }