Black Lives Matter. Support the Equal Justice Initiative.

Source file src/image/image.go

Documentation: image

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

View as plain text