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

View as plain text