Source file src/image/image.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package image implements a basic 2-D image library.
     6  //
     7  // The fundamental interface is called [Image]. An [Image] contains colors, which
     8  // are described in the image/color package.
     9  //
    10  // Values of the [Image] interface are created either by calling functions such
    11  // as [NewRGBA] and [NewPaletted], or by calling [Decode] on an [io.Reader] containing
    12  // image data in a format such as GIF, JPEG or PNG. Decoding any particular
    13  // image format requires the prior registration of a decoder function.
    14  // Registration is typically automatic as a side effect of initializing that
    15  // format's package so that, to decode a PNG image, it suffices to have
    16  //
    17  //	import _ "image/png"
    18  //
    19  // in a program's main package. The _ means to import a package purely for its
    20  // initialization side effects.
    21  //
    22  // See "The Go image package" for more details:
    23  // https://golang.org/doc/articles/image_package.html
    24  //
    25  // # Security Considerations
    26  //
    27  // The image package can be used to parse arbitrarily large images, which can
    28  // cause resource exhaustion on machines which do not have enough memory to
    29  // store them. When operating on arbitrary images, [DecodeConfig] should be called
    30  // before [Decode], so that the program can decide whether the image, as defined
    31  // in the returned header, can be safely decoded with the available resources. A
    32  // call to [Decode] which produces an extremely large image, as defined in the
    33  // header returned by [DecodeConfig], is not considered a security issue,
    34  // regardless of whether the image is itself malformed or not. A call to
    35  // [DecodeConfig] which returns a header which does not match the image returned
    36  // by [Decode] may be considered a security issue, and should be reported per the
    37  // [Go Security Policy].
    38  //
    39  // [Go Security Policy]: https://go.dev/security/policy
    40  package image
    41  
    42  import (
    43  	"image/color"
    44  )
    45  
    46  // Config holds an image's color model and dimensions.
    47  type Config struct {
    48  	ColorModel    color.Model
    49  	Width, Height int
    50  }
    51  
    52  // Image is a finite rectangular grid of [color.Color] values taken from a color
    53  // model.
    54  type Image interface {
    55  	// ColorModel returns the Image's color model.
    56  	ColorModel() color.Model
    57  	// Bounds returns the domain for which At can return non-zero color.
    58  	// The bounds do not necessarily contain the point (0, 0).
    59  	Bounds() Rectangle
    60  	// At returns the color of the pixel at (x, y).
    61  	// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
    62  	// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
    63  	At(x, y int) color.Color
    64  }
    65  
    66  // RGBA64Image is an [Image] whose pixels can be converted directly to a
    67  // color.RGBA64.
    68  type RGBA64Image interface {
    69  	// RGBA64At returns the RGBA64 color of the pixel at (x, y). It is
    70  	// equivalent to calling At(x, y).RGBA() and converting the resulting
    71  	// 32-bit return values to a color.RGBA64, but it can avoid allocations
    72  	// from converting concrete color types to the color.Color interface type.
    73  	RGBA64At(x, y int) color.RGBA64
    74  	Image
    75  }
    76  
    77  // PalettedImage is an image whose colors may come from a limited palette.
    78  // If m is a PalettedImage and m.ColorModel() returns a [color.Palette] p,
    79  // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
    80  // color model is not a color.Palette, then ColorIndexAt's behavior is
    81  // undefined.
    82  type PalettedImage interface {
    83  	// ColorIndexAt returns the palette index of the pixel at (x, y).
    84  	ColorIndexAt(x, y int) uint8
    85  	Image
    86  }
    87  
    88  // pixelBufferLength returns the length of the []uint8 typed Pix slice field
    89  // for the NewXxx functions. Conceptually, this is just (bpp * width * height),
    90  // but this function panics if at least one of those is negative or if the
    91  // computation would overflow the int type.
    92  //
    93  // This panics instead of returning an error because of backwards
    94  // compatibility. The NewXxx functions do not return an error.
    95  func pixelBufferLength(bytesPerPixel int, r Rectangle, imageTypeName string) int {
    96  	totalLength := mul3NonNeg(bytesPerPixel, r.Dx(), r.Dy())
    97  	if totalLength < 0 {
    98  		panic("image: New" + imageTypeName + " Rectangle has huge or negative dimensions")
    99  	}
   100  	return totalLength
   101  }
   102  
   103  // RGBA is an in-memory image whose At method returns [color.RGBA] values.
   104  type RGBA struct {
   105  	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
   106  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
   107  	Pix []uint8
   108  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   109  	Stride int
   110  	// Rect is the image's bounds.
   111  	Rect Rectangle
   112  }
   113  
   114  func (p *RGBA) ColorModel() color.Model { return color.RGBAModel }
   115  
   116  func (p *RGBA) Bounds() Rectangle { return p.Rect }
   117  
   118  func (p *RGBA) At(x, y int) color.Color {
   119  	return p.RGBAAt(x, y)
   120  }
   121  
   122  func (p *RGBA) RGBA64At(x, y int) color.RGBA64 {
   123  	if !(Point{x, y}.In(p.Rect)) {
   124  		return color.RGBA64{}
   125  	}
   126  	i := p.PixOffset(x, y)
   127  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   128  	r := uint16(s[0])
   129  	g := uint16(s[1])
   130  	b := uint16(s[2])
   131  	a := uint16(s[3])
   132  	return color.RGBA64{
   133  		(r << 8) | r,
   134  		(g << 8) | g,
   135  		(b << 8) | b,
   136  		(a << 8) | a,
   137  	}
   138  }
   139  
   140  func (p *RGBA) RGBAAt(x, y int) color.RGBA {
   141  	if !(Point{x, y}.In(p.Rect)) {
   142  		return color.RGBA{}
   143  	}
   144  	i := p.PixOffset(x, y)
   145  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   146  	return color.RGBA{s[0], s[1], s[2], s[3]}
   147  }
   148  
   149  // PixOffset returns the index of the first element of Pix that corresponds to
   150  // the pixel at (x, y).
   151  func (p *RGBA) PixOffset(x, y int) int {
   152  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
   153  }
   154  
   155  func (p *RGBA) Set(x, y int, c color.Color) {
   156  	if !(Point{x, y}.In(p.Rect)) {
   157  		return
   158  	}
   159  	i := p.PixOffset(x, y)
   160  	c1 := color.RGBAModel.Convert(c).(color.RGBA)
   161  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   162  	s[0] = c1.R
   163  	s[1] = c1.G
   164  	s[2] = c1.B
   165  	s[3] = c1.A
   166  }
   167  
   168  func (p *RGBA) SetRGBA64(x, y int, c color.RGBA64) {
   169  	if !(Point{x, y}.In(p.Rect)) {
   170  		return
   171  	}
   172  	i := p.PixOffset(x, y)
   173  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   174  	s[0] = uint8(c.R >> 8)
   175  	s[1] = uint8(c.G >> 8)
   176  	s[2] = uint8(c.B >> 8)
   177  	s[3] = uint8(c.A >> 8)
   178  }
   179  
   180  func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
   181  	if !(Point{x, y}.In(p.Rect)) {
   182  		return
   183  	}
   184  	i := p.PixOffset(x, y)
   185  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   186  	s[0] = c.R
   187  	s[1] = c.G
   188  	s[2] = c.B
   189  	s[3] = c.A
   190  }
   191  
   192  // SubImage returns an image representing the portion of the image p visible
   193  // through r. The returned value shares pixels with the original image.
   194  func (p *RGBA) SubImage(r Rectangle) Image {
   195  	r = r.Intersect(p.Rect)
   196  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   197  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   198  	// this, the Pix[i:] expression below can panic.
   199  	if r.Empty() {
   200  		return &RGBA{}
   201  	}
   202  	i := p.PixOffset(r.Min.X, r.Min.Y)
   203  	return &RGBA{
   204  		Pix:    p.Pix[i:],
   205  		Stride: p.Stride,
   206  		Rect:   r,
   207  	}
   208  }
   209  
   210  // Opaque scans the entire image and reports whether it is fully opaque.
   211  func (p *RGBA) Opaque() bool {
   212  	if p.Rect.Empty() {
   213  		return true
   214  	}
   215  	i0, i1 := 3, p.Rect.Dx()*4
   216  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   217  		for i := i0; i < i1; i += 4 {
   218  			if p.Pix[i] != 0xff {
   219  				return false
   220  			}
   221  		}
   222  		i0 += p.Stride
   223  		i1 += p.Stride
   224  	}
   225  	return true
   226  }
   227  
   228  // NewRGBA returns a new [RGBA] image with the given bounds.
   229  func NewRGBA(r Rectangle) *RGBA {
   230  	return &RGBA{
   231  		Pix:    make([]uint8, pixelBufferLength(4, r, "RGBA")),
   232  		Stride: 4 * r.Dx(),
   233  		Rect:   r,
   234  	}
   235  }
   236  
   237  // RGBA64 is an in-memory image whose At method returns [color.RGBA64] values.
   238  type RGBA64 struct {
   239  	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
   240  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
   241  	Pix []uint8
   242  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   243  	Stride int
   244  	// Rect is the image's bounds.
   245  	Rect Rectangle
   246  }
   247  
   248  func (p *RGBA64) ColorModel() color.Model { return color.RGBA64Model }
   249  
   250  func (p *RGBA64) Bounds() Rectangle { return p.Rect }
   251  
   252  func (p *RGBA64) At(x, y int) color.Color {
   253  	return p.RGBA64At(x, y)
   254  }
   255  
   256  func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 {
   257  	if !(Point{x, y}.In(p.Rect)) {
   258  		return color.RGBA64{}
   259  	}
   260  	i := p.PixOffset(x, y)
   261  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   262  	return color.RGBA64{
   263  		uint16(s[0])<<8 | uint16(s[1]),
   264  		uint16(s[2])<<8 | uint16(s[3]),
   265  		uint16(s[4])<<8 | uint16(s[5]),
   266  		uint16(s[6])<<8 | uint16(s[7]),
   267  	}
   268  }
   269  
   270  // PixOffset returns the index of the first element of Pix that corresponds to
   271  // the pixel at (x, y).
   272  func (p *RGBA64) PixOffset(x, y int) int {
   273  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
   274  }
   275  
   276  func (p *RGBA64) Set(x, y int, c color.Color) {
   277  	if !(Point{x, y}.In(p.Rect)) {
   278  		return
   279  	}
   280  	i := p.PixOffset(x, y)
   281  	c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
   282  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   283  	s[0] = uint8(c1.R >> 8)
   284  	s[1] = uint8(c1.R)
   285  	s[2] = uint8(c1.G >> 8)
   286  	s[3] = uint8(c1.G)
   287  	s[4] = uint8(c1.B >> 8)
   288  	s[5] = uint8(c1.B)
   289  	s[6] = uint8(c1.A >> 8)
   290  	s[7] = uint8(c1.A)
   291  }
   292  
   293  func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
   294  	if !(Point{x, y}.In(p.Rect)) {
   295  		return
   296  	}
   297  	i := p.PixOffset(x, y)
   298  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   299  	s[0] = uint8(c.R >> 8)
   300  	s[1] = uint8(c.R)
   301  	s[2] = uint8(c.G >> 8)
   302  	s[3] = uint8(c.G)
   303  	s[4] = uint8(c.B >> 8)
   304  	s[5] = uint8(c.B)
   305  	s[6] = uint8(c.A >> 8)
   306  	s[7] = uint8(c.A)
   307  }
   308  
   309  // SubImage returns an image representing the portion of the image p visible
   310  // through r. The returned value shares pixels with the original image.
   311  func (p *RGBA64) SubImage(r Rectangle) Image {
   312  	r = r.Intersect(p.Rect)
   313  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   314  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   315  	// this, the Pix[i:] expression below can panic.
   316  	if r.Empty() {
   317  		return &RGBA64{}
   318  	}
   319  	i := p.PixOffset(r.Min.X, r.Min.Y)
   320  	return &RGBA64{
   321  		Pix:    p.Pix[i:],
   322  		Stride: p.Stride,
   323  		Rect:   r,
   324  	}
   325  }
   326  
   327  // Opaque scans the entire image and reports whether it is fully opaque.
   328  func (p *RGBA64) Opaque() bool {
   329  	if p.Rect.Empty() {
   330  		return true
   331  	}
   332  	i0, i1 := 6, p.Rect.Dx()*8
   333  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   334  		for i := i0; i < i1; i += 8 {
   335  			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
   336  				return false
   337  			}
   338  		}
   339  		i0 += p.Stride
   340  		i1 += p.Stride
   341  	}
   342  	return true
   343  }
   344  
   345  // NewRGBA64 returns a new [RGBA64] image with the given bounds.
   346  func NewRGBA64(r Rectangle) *RGBA64 {
   347  	return &RGBA64{
   348  		Pix:    make([]uint8, pixelBufferLength(8, r, "RGBA64")),
   349  		Stride: 8 * r.Dx(),
   350  		Rect:   r,
   351  	}
   352  }
   353  
   354  // NRGBA is an in-memory image whose At method returns [color.NRGBA] values.
   355  type NRGBA struct {
   356  	// Pix holds the image's pixels, in R, G, B, A order. The pixel at
   357  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
   358  	Pix []uint8
   359  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   360  	Stride int
   361  	// Rect is the image's bounds.
   362  	Rect Rectangle
   363  }
   364  
   365  func (p *NRGBA) ColorModel() color.Model { return color.NRGBAModel }
   366  
   367  func (p *NRGBA) Bounds() Rectangle { return p.Rect }
   368  
   369  func (p *NRGBA) At(x, y int) color.Color {
   370  	return p.NRGBAAt(x, y)
   371  }
   372  
   373  func (p *NRGBA) RGBA64At(x, y int) color.RGBA64 {
   374  	r, g, b, a := p.NRGBAAt(x, y).RGBA()
   375  	return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
   376  }
   377  
   378  func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
   379  	if !(Point{x, y}.In(p.Rect)) {
   380  		return color.NRGBA{}
   381  	}
   382  	i := p.PixOffset(x, y)
   383  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   384  	return color.NRGBA{s[0], s[1], s[2], s[3]}
   385  }
   386  
   387  // PixOffset returns the index of the first element of Pix that corresponds to
   388  // the pixel at (x, y).
   389  func (p *NRGBA) PixOffset(x, y int) int {
   390  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
   391  }
   392  
   393  func (p *NRGBA) Set(x, y int, c color.Color) {
   394  	if !(Point{x, y}.In(p.Rect)) {
   395  		return
   396  	}
   397  	i := p.PixOffset(x, y)
   398  	c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
   399  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   400  	s[0] = c1.R
   401  	s[1] = c1.G
   402  	s[2] = c1.B
   403  	s[3] = c1.A
   404  }
   405  
   406  func (p *NRGBA) SetRGBA64(x, y int, c color.RGBA64) {
   407  	if !(Point{x, y}.In(p.Rect)) {
   408  		return
   409  	}
   410  	r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
   411  	if (a != 0) && (a != 0xffff) {
   412  		r = (r * 0xffff) / a
   413  		g = (g * 0xffff) / a
   414  		b = (b * 0xffff) / a
   415  	}
   416  	i := p.PixOffset(x, y)
   417  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   418  	s[0] = uint8(r >> 8)
   419  	s[1] = uint8(g >> 8)
   420  	s[2] = uint8(b >> 8)
   421  	s[3] = uint8(a >> 8)
   422  }
   423  
   424  func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
   425  	if !(Point{x, y}.In(p.Rect)) {
   426  		return
   427  	}
   428  	i := p.PixOffset(x, y)
   429  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   430  	s[0] = c.R
   431  	s[1] = c.G
   432  	s[2] = c.B
   433  	s[3] = c.A
   434  }
   435  
   436  // SubImage returns an image representing the portion of the image p visible
   437  // through r. The returned value shares pixels with the original image.
   438  func (p *NRGBA) SubImage(r Rectangle) Image {
   439  	r = r.Intersect(p.Rect)
   440  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   441  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   442  	// this, the Pix[i:] expression below can panic.
   443  	if r.Empty() {
   444  		return &NRGBA{}
   445  	}
   446  	i := p.PixOffset(r.Min.X, r.Min.Y)
   447  	return &NRGBA{
   448  		Pix:    p.Pix[i:],
   449  		Stride: p.Stride,
   450  		Rect:   r,
   451  	}
   452  }
   453  
   454  // Opaque scans the entire image and reports whether it is fully opaque.
   455  func (p *NRGBA) Opaque() bool {
   456  	if p.Rect.Empty() {
   457  		return true
   458  	}
   459  	i0, i1 := 3, p.Rect.Dx()*4
   460  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   461  		for i := i0; i < i1; i += 4 {
   462  			if p.Pix[i] != 0xff {
   463  				return false
   464  			}
   465  		}
   466  		i0 += p.Stride
   467  		i1 += p.Stride
   468  	}
   469  	return true
   470  }
   471  
   472  // NewNRGBA returns a new [NRGBA] image with the given bounds.
   473  func NewNRGBA(r Rectangle) *NRGBA {
   474  	return &NRGBA{
   475  		Pix:    make([]uint8, pixelBufferLength(4, r, "NRGBA")),
   476  		Stride: 4 * r.Dx(),
   477  		Rect:   r,
   478  	}
   479  }
   480  
   481  // NRGBA64 is an in-memory image whose At method returns [color.NRGBA64] values.
   482  type NRGBA64 struct {
   483  	// Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
   484  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
   485  	Pix []uint8
   486  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   487  	Stride int
   488  	// Rect is the image's bounds.
   489  	Rect Rectangle
   490  }
   491  
   492  func (p *NRGBA64) ColorModel() color.Model { return color.NRGBA64Model }
   493  
   494  func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
   495  
   496  func (p *NRGBA64) At(x, y int) color.Color {
   497  	return p.NRGBA64At(x, y)
   498  }
   499  
   500  func (p *NRGBA64) RGBA64At(x, y int) color.RGBA64 {
   501  	r, g, b, a := p.NRGBA64At(x, y).RGBA()
   502  	return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
   503  }
   504  
   505  func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
   506  	if !(Point{x, y}.In(p.Rect)) {
   507  		return color.NRGBA64{}
   508  	}
   509  	i := p.PixOffset(x, y)
   510  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   511  	return color.NRGBA64{
   512  		uint16(s[0])<<8 | uint16(s[1]),
   513  		uint16(s[2])<<8 | uint16(s[3]),
   514  		uint16(s[4])<<8 | uint16(s[5]),
   515  		uint16(s[6])<<8 | uint16(s[7]),
   516  	}
   517  }
   518  
   519  // PixOffset returns the index of the first element of Pix that corresponds to
   520  // the pixel at (x, y).
   521  func (p *NRGBA64) PixOffset(x, y int) int {
   522  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
   523  }
   524  
   525  func (p *NRGBA64) Set(x, y int, c color.Color) {
   526  	if !(Point{x, y}.In(p.Rect)) {
   527  		return
   528  	}
   529  	i := p.PixOffset(x, y)
   530  	c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
   531  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   532  	s[0] = uint8(c1.R >> 8)
   533  	s[1] = uint8(c1.R)
   534  	s[2] = uint8(c1.G >> 8)
   535  	s[3] = uint8(c1.G)
   536  	s[4] = uint8(c1.B >> 8)
   537  	s[5] = uint8(c1.B)
   538  	s[6] = uint8(c1.A >> 8)
   539  	s[7] = uint8(c1.A)
   540  }
   541  
   542  func (p *NRGBA64) SetRGBA64(x, y int, c color.RGBA64) {
   543  	if !(Point{x, y}.In(p.Rect)) {
   544  		return
   545  	}
   546  	r, g, b, a := uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
   547  	if (a != 0) && (a != 0xffff) {
   548  		r = (r * 0xffff) / a
   549  		g = (g * 0xffff) / a
   550  		b = (b * 0xffff) / a
   551  	}
   552  	i := p.PixOffset(x, y)
   553  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   554  	s[0] = uint8(r >> 8)
   555  	s[1] = uint8(r)
   556  	s[2] = uint8(g >> 8)
   557  	s[3] = uint8(g)
   558  	s[4] = uint8(b >> 8)
   559  	s[5] = uint8(b)
   560  	s[6] = uint8(a >> 8)
   561  	s[7] = uint8(a)
   562  }
   563  
   564  func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
   565  	if !(Point{x, y}.In(p.Rect)) {
   566  		return
   567  	}
   568  	i := p.PixOffset(x, y)
   569  	s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
   570  	s[0] = uint8(c.R >> 8)
   571  	s[1] = uint8(c.R)
   572  	s[2] = uint8(c.G >> 8)
   573  	s[3] = uint8(c.G)
   574  	s[4] = uint8(c.B >> 8)
   575  	s[5] = uint8(c.B)
   576  	s[6] = uint8(c.A >> 8)
   577  	s[7] = uint8(c.A)
   578  }
   579  
   580  // SubImage returns an image representing the portion of the image p visible
   581  // through r. The returned value shares pixels with the original image.
   582  func (p *NRGBA64) SubImage(r Rectangle) Image {
   583  	r = r.Intersect(p.Rect)
   584  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   585  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   586  	// this, the Pix[i:] expression below can panic.
   587  	if r.Empty() {
   588  		return &NRGBA64{}
   589  	}
   590  	i := p.PixOffset(r.Min.X, r.Min.Y)
   591  	return &NRGBA64{
   592  		Pix:    p.Pix[i:],
   593  		Stride: p.Stride,
   594  		Rect:   r,
   595  	}
   596  }
   597  
   598  // Opaque scans the entire image and reports whether it is fully opaque.
   599  func (p *NRGBA64) Opaque() bool {
   600  	if p.Rect.Empty() {
   601  		return true
   602  	}
   603  	i0, i1 := 6, p.Rect.Dx()*8
   604  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   605  		for i := i0; i < i1; i += 8 {
   606  			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
   607  				return false
   608  			}
   609  		}
   610  		i0 += p.Stride
   611  		i1 += p.Stride
   612  	}
   613  	return true
   614  }
   615  
   616  // NewNRGBA64 returns a new [NRGBA64] image with the given bounds.
   617  func NewNRGBA64(r Rectangle) *NRGBA64 {
   618  	return &NRGBA64{
   619  		Pix:    make([]uint8, pixelBufferLength(8, r, "NRGBA64")),
   620  		Stride: 8 * r.Dx(),
   621  		Rect:   r,
   622  	}
   623  }
   624  
   625  // Alpha is an in-memory image whose At method returns [color.Alpha] values.
   626  type Alpha struct {
   627  	// Pix holds the image's pixels, as alpha values. The pixel at
   628  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
   629  	Pix []uint8
   630  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   631  	Stride int
   632  	// Rect is the image's bounds.
   633  	Rect Rectangle
   634  }
   635  
   636  func (p *Alpha) ColorModel() color.Model { return color.AlphaModel }
   637  
   638  func (p *Alpha) Bounds() Rectangle { return p.Rect }
   639  
   640  func (p *Alpha) At(x, y int) color.Color {
   641  	return p.AlphaAt(x, y)
   642  }
   643  
   644  func (p *Alpha) RGBA64At(x, y int) color.RGBA64 {
   645  	a := uint16(p.AlphaAt(x, y).A)
   646  	a |= a << 8
   647  	return color.RGBA64{a, a, a, a}
   648  }
   649  
   650  func (p *Alpha) AlphaAt(x, y int) color.Alpha {
   651  	if !(Point{x, y}.In(p.Rect)) {
   652  		return color.Alpha{}
   653  	}
   654  	i := p.PixOffset(x, y)
   655  	return color.Alpha{p.Pix[i]}
   656  }
   657  
   658  // PixOffset returns the index of the first element of Pix that corresponds to
   659  // the pixel at (x, y).
   660  func (p *Alpha) PixOffset(x, y int) int {
   661  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
   662  }
   663  
   664  func (p *Alpha) Set(x, y int, c color.Color) {
   665  	if !(Point{x, y}.In(p.Rect)) {
   666  		return
   667  	}
   668  	i := p.PixOffset(x, y)
   669  	p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A
   670  }
   671  
   672  func (p *Alpha) SetRGBA64(x, y int, c color.RGBA64) {
   673  	if !(Point{x, y}.In(p.Rect)) {
   674  		return
   675  	}
   676  	i := p.PixOffset(x, y)
   677  	p.Pix[i] = uint8(c.A >> 8)
   678  }
   679  
   680  func (p *Alpha) SetAlpha(x, y int, c color.Alpha) {
   681  	if !(Point{x, y}.In(p.Rect)) {
   682  		return
   683  	}
   684  	i := p.PixOffset(x, y)
   685  	p.Pix[i] = c.A
   686  }
   687  
   688  // SubImage returns an image representing the portion of the image p visible
   689  // through r. The returned value shares pixels with the original image.
   690  func (p *Alpha) SubImage(r Rectangle) Image {
   691  	r = r.Intersect(p.Rect)
   692  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   693  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   694  	// this, the Pix[i:] expression below can panic.
   695  	if r.Empty() {
   696  		return &Alpha{}
   697  	}
   698  	i := p.PixOffset(r.Min.X, r.Min.Y)
   699  	return &Alpha{
   700  		Pix:    p.Pix[i:],
   701  		Stride: p.Stride,
   702  		Rect:   r,
   703  	}
   704  }
   705  
   706  // Opaque scans the entire image and reports whether it is fully opaque.
   707  func (p *Alpha) Opaque() bool {
   708  	if p.Rect.Empty() {
   709  		return true
   710  	}
   711  	i0, i1 := 0, p.Rect.Dx()
   712  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   713  		for i := i0; i < i1; i++ {
   714  			if p.Pix[i] != 0xff {
   715  				return false
   716  			}
   717  		}
   718  		i0 += p.Stride
   719  		i1 += p.Stride
   720  	}
   721  	return true
   722  }
   723  
   724  // NewAlpha returns a new [Alpha] image with the given bounds.
   725  func NewAlpha(r Rectangle) *Alpha {
   726  	return &Alpha{
   727  		Pix:    make([]uint8, pixelBufferLength(1, r, "Alpha")),
   728  		Stride: 1 * r.Dx(),
   729  		Rect:   r,
   730  	}
   731  }
   732  
   733  // Alpha16 is an in-memory image whose At method returns [color.Alpha16] values.
   734  type Alpha16 struct {
   735  	// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
   736  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
   737  	Pix []uint8
   738  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   739  	Stride int
   740  	// Rect is the image's bounds.
   741  	Rect Rectangle
   742  }
   743  
   744  func (p *Alpha16) ColorModel() color.Model { return color.Alpha16Model }
   745  
   746  func (p *Alpha16) Bounds() Rectangle { return p.Rect }
   747  
   748  func (p *Alpha16) At(x, y int) color.Color {
   749  	return p.Alpha16At(x, y)
   750  }
   751  
   752  func (p *Alpha16) RGBA64At(x, y int) color.RGBA64 {
   753  	a := p.Alpha16At(x, y).A
   754  	return color.RGBA64{a, a, a, a}
   755  }
   756  
   757  func (p *Alpha16) Alpha16At(x, y int) color.Alpha16 {
   758  	if !(Point{x, y}.In(p.Rect)) {
   759  		return color.Alpha16{}
   760  	}
   761  	i := p.PixOffset(x, y)
   762  	return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
   763  }
   764  
   765  // PixOffset returns the index of the first element of Pix that corresponds to
   766  // the pixel at (x, y).
   767  func (p *Alpha16) PixOffset(x, y int) int {
   768  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
   769  }
   770  
   771  func (p *Alpha16) Set(x, y int, c color.Color) {
   772  	if !(Point{x, y}.In(p.Rect)) {
   773  		return
   774  	}
   775  	i := p.PixOffset(x, y)
   776  	c1 := color.Alpha16Model.Convert(c).(color.Alpha16)
   777  	p.Pix[i+0] = uint8(c1.A >> 8)
   778  	p.Pix[i+1] = uint8(c1.A)
   779  }
   780  
   781  func (p *Alpha16) SetRGBA64(x, y int, c color.RGBA64) {
   782  	if !(Point{x, y}.In(p.Rect)) {
   783  		return
   784  	}
   785  	i := p.PixOffset(x, y)
   786  	p.Pix[i+0] = uint8(c.A >> 8)
   787  	p.Pix[i+1] = uint8(c.A)
   788  }
   789  
   790  func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) {
   791  	if !(Point{x, y}.In(p.Rect)) {
   792  		return
   793  	}
   794  	i := p.PixOffset(x, y)
   795  	p.Pix[i+0] = uint8(c.A >> 8)
   796  	p.Pix[i+1] = uint8(c.A)
   797  }
   798  
   799  // SubImage returns an image representing the portion of the image p visible
   800  // through r. The returned value shares pixels with the original image.
   801  func (p *Alpha16) SubImage(r Rectangle) Image {
   802  	r = r.Intersect(p.Rect)
   803  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   804  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   805  	// this, the Pix[i:] expression below can panic.
   806  	if r.Empty() {
   807  		return &Alpha16{}
   808  	}
   809  	i := p.PixOffset(r.Min.X, r.Min.Y)
   810  	return &Alpha16{
   811  		Pix:    p.Pix[i:],
   812  		Stride: p.Stride,
   813  		Rect:   r,
   814  	}
   815  }
   816  
   817  // Opaque scans the entire image and reports whether it is fully opaque.
   818  func (p *Alpha16) Opaque() bool {
   819  	if p.Rect.Empty() {
   820  		return true
   821  	}
   822  	i0, i1 := 0, p.Rect.Dx()*2
   823  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
   824  		for i := i0; i < i1; i += 2 {
   825  			if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
   826  				return false
   827  			}
   828  		}
   829  		i0 += p.Stride
   830  		i1 += p.Stride
   831  	}
   832  	return true
   833  }
   834  
   835  // NewAlpha16 returns a new [Alpha16] image with the given bounds.
   836  func NewAlpha16(r Rectangle) *Alpha16 {
   837  	return &Alpha16{
   838  		Pix:    make([]uint8, pixelBufferLength(2, r, "Alpha16")),
   839  		Stride: 2 * r.Dx(),
   840  		Rect:   r,
   841  	}
   842  }
   843  
   844  // Gray is an in-memory image whose At method returns [color.Gray] values.
   845  type Gray struct {
   846  	// Pix holds the image's pixels, as gray values. The pixel at
   847  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
   848  	Pix []uint8
   849  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   850  	Stride int
   851  	// Rect is the image's bounds.
   852  	Rect Rectangle
   853  }
   854  
   855  func (p *Gray) ColorModel() color.Model { return color.GrayModel }
   856  
   857  func (p *Gray) Bounds() Rectangle { return p.Rect }
   858  
   859  func (p *Gray) At(x, y int) color.Color {
   860  	return p.GrayAt(x, y)
   861  }
   862  
   863  func (p *Gray) RGBA64At(x, y int) color.RGBA64 {
   864  	gray := uint16(p.GrayAt(x, y).Y)
   865  	gray |= gray << 8
   866  	return color.RGBA64{gray, gray, gray, 0xffff}
   867  }
   868  
   869  func (p *Gray) GrayAt(x, y int) color.Gray {
   870  	if !(Point{x, y}.In(p.Rect)) {
   871  		return color.Gray{}
   872  	}
   873  	i := p.PixOffset(x, y)
   874  	return color.Gray{p.Pix[i]}
   875  }
   876  
   877  // PixOffset returns the index of the first element of Pix that corresponds to
   878  // the pixel at (x, y).
   879  func (p *Gray) PixOffset(x, y int) int {
   880  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
   881  }
   882  
   883  func (p *Gray) Set(x, y int, c color.Color) {
   884  	if !(Point{x, y}.In(p.Rect)) {
   885  		return
   886  	}
   887  	i := p.PixOffset(x, y)
   888  	p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y
   889  }
   890  
   891  func (p *Gray) SetRGBA64(x, y int, c color.RGBA64) {
   892  	if !(Point{x, y}.In(p.Rect)) {
   893  		return
   894  	}
   895  	// This formula is the same as in color.grayModel.
   896  	gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 24
   897  	i := p.PixOffset(x, y)
   898  	p.Pix[i] = uint8(gray)
   899  }
   900  
   901  func (p *Gray) SetGray(x, y int, c color.Gray) {
   902  	if !(Point{x, y}.In(p.Rect)) {
   903  		return
   904  	}
   905  	i := p.PixOffset(x, y)
   906  	p.Pix[i] = c.Y
   907  }
   908  
   909  // SubImage returns an image representing the portion of the image p visible
   910  // through r. The returned value shares pixels with the original image.
   911  func (p *Gray) SubImage(r Rectangle) Image {
   912  	r = r.Intersect(p.Rect)
   913  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
   914  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
   915  	// this, the Pix[i:] expression below can panic.
   916  	if r.Empty() {
   917  		return &Gray{}
   918  	}
   919  	i := p.PixOffset(r.Min.X, r.Min.Y)
   920  	return &Gray{
   921  		Pix:    p.Pix[i:],
   922  		Stride: p.Stride,
   923  		Rect:   r,
   924  	}
   925  }
   926  
   927  // Opaque scans the entire image and reports whether it is fully opaque.
   928  func (p *Gray) Opaque() bool {
   929  	return true
   930  }
   931  
   932  // NewGray returns a new [Gray] image with the given bounds.
   933  func NewGray(r Rectangle) *Gray {
   934  	return &Gray{
   935  		Pix:    make([]uint8, pixelBufferLength(1, r, "Gray")),
   936  		Stride: 1 * r.Dx(),
   937  		Rect:   r,
   938  	}
   939  }
   940  
   941  // Gray16 is an in-memory image whose At method returns [color.Gray16] values.
   942  type Gray16 struct {
   943  	// Pix holds the image's pixels, as gray values in big-endian format. The pixel at
   944  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
   945  	Pix []uint8
   946  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   947  	Stride int
   948  	// Rect is the image's bounds.
   949  	Rect Rectangle
   950  }
   951  
   952  func (p *Gray16) ColorModel() color.Model { return color.Gray16Model }
   953  
   954  func (p *Gray16) Bounds() Rectangle { return p.Rect }
   955  
   956  func (p *Gray16) At(x, y int) color.Color {
   957  	return p.Gray16At(x, y)
   958  }
   959  
   960  func (p *Gray16) RGBA64At(x, y int) color.RGBA64 {
   961  	gray := p.Gray16At(x, y).Y
   962  	return color.RGBA64{gray, gray, gray, 0xffff}
   963  }
   964  
   965  func (p *Gray16) Gray16At(x, y int) color.Gray16 {
   966  	if !(Point{x, y}.In(p.Rect)) {
   967  		return color.Gray16{}
   968  	}
   969  	i := p.PixOffset(x, y)
   970  	return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
   971  }
   972  
   973  // PixOffset returns the index of the first element of Pix that corresponds to
   974  // the pixel at (x, y).
   975  func (p *Gray16) PixOffset(x, y int) int {
   976  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
   977  }
   978  
   979  func (p *Gray16) Set(x, y int, c color.Color) {
   980  	if !(Point{x, y}.In(p.Rect)) {
   981  		return
   982  	}
   983  	i := p.PixOffset(x, y)
   984  	c1 := color.Gray16Model.Convert(c).(color.Gray16)
   985  	p.Pix[i+0] = uint8(c1.Y >> 8)
   986  	p.Pix[i+1] = uint8(c1.Y)
   987  }
   988  
   989  func (p *Gray16) SetRGBA64(x, y int, c color.RGBA64) {
   990  	if !(Point{x, y}.In(p.Rect)) {
   991  		return
   992  	}
   993  	// This formula is the same as in color.gray16Model.
   994  	gray := (19595*uint32(c.R) + 38470*uint32(c.G) + 7471*uint32(c.B) + 1<<15) >> 16
   995  	i := p.PixOffset(x, y)
   996  	p.Pix[i+0] = uint8(gray >> 8)
   997  	p.Pix[i+1] = uint8(gray)
   998  }
   999  
  1000  func (p *Gray16) SetGray16(x, y int, c color.Gray16) {
  1001  	if !(Point{x, y}.In(p.Rect)) {
  1002  		return
  1003  	}
  1004  	i := p.PixOffset(x, y)
  1005  	p.Pix[i+0] = uint8(c.Y >> 8)
  1006  	p.Pix[i+1] = uint8(c.Y)
  1007  }
  1008  
  1009  // SubImage returns an image representing the portion of the image p visible
  1010  // through r. The returned value shares pixels with the original image.
  1011  func (p *Gray16) SubImage(r Rectangle) Image {
  1012  	r = r.Intersect(p.Rect)
  1013  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
  1014  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
  1015  	// this, the Pix[i:] expression below can panic.
  1016  	if r.Empty() {
  1017  		return &Gray16{}
  1018  	}
  1019  	i := p.PixOffset(r.Min.X, r.Min.Y)
  1020  	return &Gray16{
  1021  		Pix:    p.Pix[i:],
  1022  		Stride: p.Stride,
  1023  		Rect:   r,
  1024  	}
  1025  }
  1026  
  1027  // Opaque scans the entire image and reports whether it is fully opaque.
  1028  func (p *Gray16) Opaque() bool {
  1029  	return true
  1030  }
  1031  
  1032  // NewGray16 returns a new [Gray16] image with the given bounds.
  1033  func NewGray16(r Rectangle) *Gray16 {
  1034  	return &Gray16{
  1035  		Pix:    make([]uint8, pixelBufferLength(2, r, "Gray16")),
  1036  		Stride: 2 * r.Dx(),
  1037  		Rect:   r,
  1038  	}
  1039  }
  1040  
  1041  // CMYK is an in-memory image whose At method returns [color.CMYK] values.
  1042  type CMYK struct {
  1043  	// Pix holds the image's pixels, in C, M, Y, K order. The pixel at
  1044  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
  1045  	Pix []uint8
  1046  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
  1047  	Stride int
  1048  	// Rect is the image's bounds.
  1049  	Rect Rectangle
  1050  }
  1051  
  1052  func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
  1053  
  1054  func (p *CMYK) Bounds() Rectangle { return p.Rect }
  1055  
  1056  func (p *CMYK) At(x, y int) color.Color {
  1057  	return p.CMYKAt(x, y)
  1058  }
  1059  
  1060  func (p *CMYK) RGBA64At(x, y int) color.RGBA64 {
  1061  	r, g, b, a := p.CMYKAt(x, y).RGBA()
  1062  	return color.RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
  1063  }
  1064  
  1065  func (p *CMYK) CMYKAt(x, y int) color.CMYK {
  1066  	if !(Point{x, y}.In(p.Rect)) {
  1067  		return color.CMYK{}
  1068  	}
  1069  	i := p.PixOffset(x, y)
  1070  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
  1071  	return color.CMYK{s[0], s[1], s[2], s[3]}
  1072  }
  1073  
  1074  // PixOffset returns the index of the first element of Pix that corresponds to
  1075  // the pixel at (x, y).
  1076  func (p *CMYK) PixOffset(x, y int) int {
  1077  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
  1078  }
  1079  
  1080  func (p *CMYK) Set(x, y int, c color.Color) {
  1081  	if !(Point{x, y}.In(p.Rect)) {
  1082  		return
  1083  	}
  1084  	i := p.PixOffset(x, y)
  1085  	c1 := color.CMYKModel.Convert(c).(color.CMYK)
  1086  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
  1087  	s[0] = c1.C
  1088  	s[1] = c1.M
  1089  	s[2] = c1.Y
  1090  	s[3] = c1.K
  1091  }
  1092  
  1093  func (p *CMYK) SetRGBA64(x, y int, c color.RGBA64) {
  1094  	if !(Point{x, y}.In(p.Rect)) {
  1095  		return
  1096  	}
  1097  	cc, mm, yy, kk := color.RGBToCMYK(uint8(c.R>>8), uint8(c.G>>8), uint8(c.B>>8))
  1098  	i := p.PixOffset(x, y)
  1099  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
  1100  	s[0] = cc
  1101  	s[1] = mm
  1102  	s[2] = yy
  1103  	s[3] = kk
  1104  }
  1105  
  1106  func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
  1107  	if !(Point{x, y}.In(p.Rect)) {
  1108  		return
  1109  	}
  1110  	i := p.PixOffset(x, y)
  1111  	s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
  1112  	s[0] = c.C
  1113  	s[1] = c.M
  1114  	s[2] = c.Y
  1115  	s[3] = c.K
  1116  }
  1117  
  1118  // SubImage returns an image representing the portion of the image p visible
  1119  // through r. The returned value shares pixels with the original image.
  1120  func (p *CMYK) SubImage(r Rectangle) Image {
  1121  	r = r.Intersect(p.Rect)
  1122  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
  1123  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
  1124  	// this, the Pix[i:] expression below can panic.
  1125  	if r.Empty() {
  1126  		return &CMYK{}
  1127  	}
  1128  	i := p.PixOffset(r.Min.X, r.Min.Y)
  1129  	return &CMYK{
  1130  		Pix:    p.Pix[i:],
  1131  		Stride: p.Stride,
  1132  		Rect:   r,
  1133  	}
  1134  }
  1135  
  1136  // Opaque scans the entire image and reports whether it is fully opaque.
  1137  func (p *CMYK) Opaque() bool {
  1138  	return true
  1139  }
  1140  
  1141  // NewCMYK returns a new CMYK image with the given bounds.
  1142  func NewCMYK(r Rectangle) *CMYK {
  1143  	return &CMYK{
  1144  		Pix:    make([]uint8, pixelBufferLength(4, r, "CMYK")),
  1145  		Stride: 4 * r.Dx(),
  1146  		Rect:   r,
  1147  	}
  1148  }
  1149  
  1150  // Paletted is an in-memory image of uint8 indices into a given palette.
  1151  type Paletted struct {
  1152  	// Pix holds the image's pixels, as palette indices. The pixel at
  1153  	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
  1154  	Pix []uint8
  1155  	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
  1156  	Stride int
  1157  	// Rect is the image's bounds.
  1158  	Rect Rectangle
  1159  	// Palette is the image's palette.
  1160  	Palette color.Palette
  1161  }
  1162  
  1163  func (p *Paletted) ColorModel() color.Model { return p.Palette }
  1164  
  1165  func (p *Paletted) Bounds() Rectangle { return p.Rect }
  1166  
  1167  func (p *Paletted) At(x, y int) color.Color {
  1168  	if len(p.Palette) == 0 {
  1169  		return nil
  1170  	}
  1171  	if !(Point{x, y}.In(p.Rect)) {
  1172  		return p.Palette[0]
  1173  	}
  1174  	i := p.PixOffset(x, y)
  1175  	return p.Palette[p.Pix[i]]
  1176  }
  1177  
  1178  func (p *Paletted) RGBA64At(x, y int) color.RGBA64 {
  1179  	if len(p.Palette) == 0 {
  1180  		return color.RGBA64{}
  1181  	}
  1182  	c := color.Color(nil)
  1183  	if !(Point{x, y}.In(p.Rect)) {
  1184  		c = p.Palette[0]
  1185  	} else {
  1186  		i := p.PixOffset(x, y)
  1187  		c = p.Palette[p.Pix[i]]
  1188  	}
  1189  	r, g, b, a := c.RGBA()
  1190  	return color.RGBA64{
  1191  		uint16(r),
  1192  		uint16(g),
  1193  		uint16(b),
  1194  		uint16(a),
  1195  	}
  1196  }
  1197  
  1198  // PixOffset returns the index of the first element of Pix that corresponds to
  1199  // the pixel at (x, y).
  1200  func (p *Paletted) PixOffset(x, y int) int {
  1201  	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1
  1202  }
  1203  
  1204  func (p *Paletted) Set(x, y int, c color.Color) {
  1205  	if !(Point{x, y}.In(p.Rect)) {
  1206  		return
  1207  	}
  1208  	i := p.PixOffset(x, y)
  1209  	p.Pix[i] = uint8(p.Palette.Index(c))
  1210  }
  1211  
  1212  func (p *Paletted) SetRGBA64(x, y int, c color.RGBA64) {
  1213  	if !(Point{x, y}.In(p.Rect)) {
  1214  		return
  1215  	}
  1216  	i := p.PixOffset(x, y)
  1217  	p.Pix[i] = uint8(p.Palette.Index(c))
  1218  }
  1219  
  1220  func (p *Paletted) ColorIndexAt(x, y int) uint8 {
  1221  	if !(Point{x, y}.In(p.Rect)) {
  1222  		return 0
  1223  	}
  1224  	i := p.PixOffset(x, y)
  1225  	return p.Pix[i]
  1226  }
  1227  
  1228  func (p *Paletted) SetColorIndex(x, y int, index uint8) {
  1229  	if !(Point{x, y}.In(p.Rect)) {
  1230  		return
  1231  	}
  1232  	i := p.PixOffset(x, y)
  1233  	p.Pix[i] = index
  1234  }
  1235  
  1236  // SubImage returns an image representing the portion of the image p visible
  1237  // through r. The returned value shares pixels with the original image.
  1238  func (p *Paletted) SubImage(r Rectangle) Image {
  1239  	r = r.Intersect(p.Rect)
  1240  	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
  1241  	// either r1 or r2 if the intersection is empty. Without explicitly checking for
  1242  	// this, the Pix[i:] expression below can panic.
  1243  	if r.Empty() {
  1244  		return &Paletted{
  1245  			Palette: p.Palette,
  1246  		}
  1247  	}
  1248  	i := p.PixOffset(r.Min.X, r.Min.Y)
  1249  	return &Paletted{
  1250  		Pix:     p.Pix[i:],
  1251  		Stride:  p.Stride,
  1252  		Rect:    p.Rect.Intersect(r),
  1253  		Palette: p.Palette,
  1254  	}
  1255  }
  1256  
  1257  // Opaque scans the entire image and reports whether it is fully opaque.
  1258  func (p *Paletted) Opaque() bool {
  1259  	var present [256]bool
  1260  	i0, i1 := 0, p.Rect.Dx()
  1261  	for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
  1262  		for _, c := range p.Pix[i0:i1] {
  1263  			present[c] = true
  1264  		}
  1265  		i0 += p.Stride
  1266  		i1 += p.Stride
  1267  	}
  1268  	for i, c := range p.Palette {
  1269  		if !present[i] {
  1270  			continue
  1271  		}
  1272  		_, _, _, a := c.RGBA()
  1273  		if a != 0xffff {
  1274  			return false
  1275  		}
  1276  	}
  1277  	return true
  1278  }
  1279  
  1280  // NewPaletted returns a new [Paletted] image with the given width, height and
  1281  // palette.
  1282  func NewPaletted(r Rectangle, p color.Palette) *Paletted {
  1283  	return &Paletted{
  1284  		Pix:     make([]uint8, pixelBufferLength(1, r, "Paletted")),
  1285  		Stride:  1 * r.Dx(),
  1286  		Rect:    r,
  1287  		Palette: p,
  1288  	}
  1289  }
  1290  

View as plain text