image.mx raw

   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 []byte) int {
  94  	totalLength := mul3NonNeg(bytesPerPixel, r.Dx(), r.Dy())
  95  	if totalLength < 0 {
  96  		panic(string(append(append([]byte("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:    []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:    []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:    []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:    []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:    []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:    []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:    []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:    []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:    []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:     []uint8{:pixelBufferLength(1, r, "Paletted")},
1283  		Stride:  1 * r.Dx(),
1284  		Rect:    r,
1285  		Palette: p,
1286  	}
1287  }
1288