// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package image implements a basic 2-D image library. // // The fundamental interface is called [Image]. An [Image] contains colors, which // are described in the image/color package. // // Values of the [Image] interface are created either by calling functions such // as [NewRGBA] and [NewPaletted], or by calling [Decode] on an [io.Reader] containing // image data in a format such as GIF, JPEG or PNG. Decoding any particular // image format requires the prior registration of a decoder function. // Registration is typically automatic as a side effect of initializing that // format's package so that, to decode a PNG image, it suffices to have // // import _ "image/png" // // in a program's main package. The _ means to import a package purely for its // initialization side effects. // // See "The Go image package" for more details: // https://golang.org/doc/articles/image_package.html // // # Security Considerations // // The image package can be used to parse arbitrarily large images, which can // cause resource exhaustion on machines which do not have enough memory to // store them. When operating on arbitrary images, [DecodeConfig] should be called // before [Decode], so that the program can decide whether the image, as defined // in the returned header, can be safely decoded with the available resources. A // call to [Decode] which produces an extremely large image, as defined in the // header returned by [DecodeConfig], is not considered a security issue, // regardless of whether the image is itself malformed or not. A call to // [DecodeConfig] which returns a header which does not match the image returned // by [Decode] may be considered a security issue, and should be reported per the // [Go Security Policy](https://go.dev/security/policy).
package image import ( ) // Config holds an image's color model and dimensions. type Config struct { ColorModel color.Model Width, Height int } // Image is a finite rectangular grid of [color.Color] values taken from a color // model. type Image interface { // ColorModel returns the Image's color model. ColorModel() color.Model // Bounds returns the domain for which At can return non-zero color. // The bounds do not necessarily contain the point (0, 0). Bounds() Rectangle // At returns the color of the pixel at (x, y). // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid. // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one. At(x, y int) color.Color } // RGBA64Image is an [Image] whose pixels can be converted directly to a // color.RGBA64. type RGBA64Image interface { // RGBA64At returns the RGBA64 color of the pixel at (x, y). It is // equivalent to calling At(x, y).RGBA() and converting the resulting // 32-bit return values to a color.RGBA64, but it can avoid allocations // from converting concrete color types to the color.Color interface type. RGBA64At(x, y int) color.RGBA64 Image } // PalettedImage is an image whose colors may come from a limited palette. // If m is a PalettedImage and m.ColorModel() returns a [color.Palette] p, // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's // color model is not a color.Palette, then ColorIndexAt's behavior is // undefined. type PalettedImage interface { // ColorIndexAt returns the palette index of the pixel at (x, y). ColorIndexAt(x, y int) uint8 Image } // pixelBufferLength returns the length of the []uint8 typed Pix slice field // for the NewXxx functions. Conceptually, this is just (bpp * width * height), // but this function panics if at least one of those is negative or if the // computation would overflow the int type. // // This panics instead of returning an error because of backwards // compatibility. The NewXxx functions do not return an error. func pixelBufferLength( int, Rectangle, string) int { := mul3NonNeg(, .Dx(), .Dy()) if < 0 { panic("image: New" + + " Rectangle has huge or negative dimensions") } return } // RGBA is an in-memory image whose At method returns [color.RGBA] values. type RGBA struct { // Pix holds the image's pixels, in R, G, B, A order. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *RGBA) () color.Model { return color.RGBAModel } func ( *RGBA) () Rectangle { return .Rect } func ( *RGBA) (, int) color.Color { return .RGBAAt(, ) } func ( *RGBA) (, int) color.RGBA64 { if !(Point{, }.In(.Rect)) { return color.RGBA64{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 := uint16([0]) := uint16([1]) := uint16([2]) := uint16([3]) return color.RGBA64{ ( << 8) | , ( << 8) | , ( << 8) | , ( << 8) | , } } func ( *RGBA) (, int) color.RGBA { if !(Point{, }.In(.Rect)) { return color.RGBA{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 return color.RGBA{[0], [1], [2], [3]} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *RGBA) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*4 } func ( *RGBA) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.RGBAModel.Convert().(color.RGBA) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .R [1] = .G [2] = .B [3] = .A } func ( *RGBA) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8(.R >> 8) [1] = uint8(.G >> 8) [2] = uint8(.B >> 8) [3] = uint8(.A >> 8) } func ( *RGBA) (, int, color.RGBA) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .R [1] = .G [2] = .B [3] = .A } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *RGBA) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &RGBA{} } := .PixOffset(.Min.X, .Min.Y) return &RGBA{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *RGBA) () bool { if .Rect.Empty() { return true } , := 3, .Rect.Dx()*4 for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; += 4 { if .Pix[] != 0xff { return false } } += .Stride += .Stride } return true } // NewRGBA returns a new [RGBA] image with the given bounds. func ( Rectangle) *RGBA { return &RGBA{ Pix: make([]uint8, pixelBufferLength(4, , "RGBA")), Stride: 4 * .Dx(), Rect: , } } // RGBA64 is an in-memory image whose At method returns [color.RGBA64] values. type RGBA64 struct { // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *RGBA64) () color.Model { return color.RGBA64Model } func ( *RGBA64) () Rectangle { return .Rect } func ( *RGBA64) (, int) color.Color { return .RGBA64At(, ) } func ( *RGBA64) (, int) color.RGBA64 { if !(Point{, }.In(.Rect)) { return color.RGBA64{} } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 return color.RGBA64{ uint16([0])<<8 | uint16([1]), uint16([2])<<8 | uint16([3]), uint16([4])<<8 | uint16([5]), uint16([6])<<8 | uint16([7]), } } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *RGBA64) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*8 } func ( *RGBA64) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.RGBA64Model.Convert().(color.RGBA64) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8(.R >> 8) [1] = uint8(.R) [2] = uint8(.G >> 8) [3] = uint8(.G) [4] = uint8(.B >> 8) [5] = uint8(.B) [6] = uint8(.A >> 8) [7] = uint8(.A) } func ( *RGBA64) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8(.R >> 8) [1] = uint8(.R) [2] = uint8(.G >> 8) [3] = uint8(.G) [4] = uint8(.B >> 8) [5] = uint8(.B) [6] = uint8(.A >> 8) [7] = uint8(.A) } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *RGBA64) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &RGBA64{} } := .PixOffset(.Min.X, .Min.Y) return &RGBA64{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *RGBA64) () bool { if .Rect.Empty() { return true } , := 6, .Rect.Dx()*8 for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; += 8 { if .Pix[+0] != 0xff || .Pix[+1] != 0xff { return false } } += .Stride += .Stride } return true } // NewRGBA64 returns a new [RGBA64] image with the given bounds. func ( Rectangle) *RGBA64 { return &RGBA64{ Pix: make([]uint8, pixelBufferLength(8, , "RGBA64")), Stride: 8 * .Dx(), Rect: , } } // NRGBA is an in-memory image whose At method returns [color.NRGBA] values. type NRGBA struct { // Pix holds the image's pixels, in R, G, B, A order. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *NRGBA) () color.Model { return color.NRGBAModel } func ( *NRGBA) () Rectangle { return .Rect } func ( *NRGBA) (, int) color.Color { return .NRGBAAt(, ) } func ( *NRGBA) (, int) color.RGBA64 { , , , := .NRGBAAt(, ).RGBA() return color.RGBA64{uint16(), uint16(), uint16(), uint16()} } func ( *NRGBA) (, int) color.NRGBA { if !(Point{, }.In(.Rect)) { return color.NRGBA{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 return color.NRGBA{[0], [1], [2], [3]} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *NRGBA) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*4 } func ( *NRGBA) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.NRGBAModel.Convert().(color.NRGBA) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .R [1] = .G [2] = .B [3] = .A } func ( *NRGBA) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } , , , := uint32(.R), uint32(.G), uint32(.B), uint32(.A) if ( != 0) && ( != 0xffff) { = ( * 0xffff) / = ( * 0xffff) / = ( * 0xffff) / } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8( >> 8) [1] = uint8( >> 8) [2] = uint8( >> 8) [3] = uint8( >> 8) } func ( *NRGBA) (, int, color.NRGBA) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .R [1] = .G [2] = .B [3] = .A } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *NRGBA) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &NRGBA{} } := .PixOffset(.Min.X, .Min.Y) return &NRGBA{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *NRGBA) () bool { if .Rect.Empty() { return true } , := 3, .Rect.Dx()*4 for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; += 4 { if .Pix[] != 0xff { return false } } += .Stride += .Stride } return true } // NewNRGBA returns a new [NRGBA] image with the given bounds. func ( Rectangle) *NRGBA { return &NRGBA{ Pix: make([]uint8, pixelBufferLength(4, , "NRGBA")), Stride: 4 * .Dx(), Rect: , } } // NRGBA64 is an in-memory image whose At method returns [color.NRGBA64] values. type NRGBA64 struct { // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *NRGBA64) () color.Model { return color.NRGBA64Model } func ( *NRGBA64) () Rectangle { return .Rect } func ( *NRGBA64) (, int) color.Color { return .NRGBA64At(, ) } func ( *NRGBA64) (, int) color.RGBA64 { , , , := .NRGBA64At(, ).RGBA() return color.RGBA64{uint16(), uint16(), uint16(), uint16()} } func ( *NRGBA64) (, int) color.NRGBA64 { if !(Point{, }.In(.Rect)) { return color.NRGBA64{} } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 return color.NRGBA64{ uint16([0])<<8 | uint16([1]), uint16([2])<<8 | uint16([3]), uint16([4])<<8 | uint16([5]), uint16([6])<<8 | uint16([7]), } } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *NRGBA64) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*8 } func ( *NRGBA64) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.NRGBA64Model.Convert().(color.NRGBA64) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8(.R >> 8) [1] = uint8(.R) [2] = uint8(.G >> 8) [3] = uint8(.G) [4] = uint8(.B >> 8) [5] = uint8(.B) [6] = uint8(.A >> 8) [7] = uint8(.A) } func ( *NRGBA64) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } , , , := uint32(.R), uint32(.G), uint32(.B), uint32(.A) if ( != 0) && ( != 0xffff) { = ( * 0xffff) / = ( * 0xffff) / = ( * 0xffff) / } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8( >> 8) [1] = uint8() [2] = uint8( >> 8) [3] = uint8() [4] = uint8( >> 8) [5] = uint8() [6] = uint8( >> 8) [7] = uint8() } func ( *NRGBA64) (, int, color.NRGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857 [0] = uint8(.R >> 8) [1] = uint8(.R) [2] = uint8(.G >> 8) [3] = uint8(.G) [4] = uint8(.B >> 8) [5] = uint8(.B) [6] = uint8(.A >> 8) [7] = uint8(.A) } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *NRGBA64) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &NRGBA64{} } := .PixOffset(.Min.X, .Min.Y) return &NRGBA64{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *NRGBA64) () bool { if .Rect.Empty() { return true } , := 6, .Rect.Dx()*8 for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; += 8 { if .Pix[+0] != 0xff || .Pix[+1] != 0xff { return false } } += .Stride += .Stride } return true } // NewNRGBA64 returns a new [NRGBA64] image with the given bounds. func ( Rectangle) *NRGBA64 { return &NRGBA64{ Pix: make([]uint8, pixelBufferLength(8, , "NRGBA64")), Stride: 8 * .Dx(), Rect: , } } // Alpha is an in-memory image whose At method returns [color.Alpha] values. type Alpha struct { // Pix holds the image's pixels, as alpha values. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *Alpha) () color.Model { return color.AlphaModel } func ( *Alpha) () Rectangle { return .Rect } func ( *Alpha) (, int) color.Color { return .AlphaAt(, ) } func ( *Alpha) (, int) color.RGBA64 { := uint16(.AlphaAt(, ).A) |= << 8 return color.RGBA64{, , , } } func ( *Alpha) (, int) color.Alpha { if !(Point{, }.In(.Rect)) { return color.Alpha{} } := .PixOffset(, ) return color.Alpha{.Pix[]} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *Alpha) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*1 } func ( *Alpha) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = color.AlphaModel.Convert().(color.Alpha).A } func ( *Alpha) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = uint8(.A >> 8) } func ( *Alpha) (, int, color.Alpha) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = .A } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *Alpha) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &Alpha{} } := .PixOffset(.Min.X, .Min.Y) return &Alpha{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *Alpha) () bool { if .Rect.Empty() { return true } , := 0, .Rect.Dx() for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; ++ { if .Pix[] != 0xff { return false } } += .Stride += .Stride } return true } // NewAlpha returns a new [Alpha] image with the given bounds. func ( Rectangle) *Alpha { return &Alpha{ Pix: make([]uint8, pixelBufferLength(1, , "Alpha")), Stride: 1 * .Dx(), Rect: , } } // Alpha16 is an in-memory image whose At method returns [color.Alpha16] values. type Alpha16 struct { // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *Alpha16) () color.Model { return color.Alpha16Model } func ( *Alpha16) () Rectangle { return .Rect } func ( *Alpha16) (, int) color.Color { return .Alpha16At(, ) } func ( *Alpha16) (, int) color.RGBA64 { := .Alpha16At(, ).A return color.RGBA64{, , , } } func ( *Alpha16) (, int) color.Alpha16 { if !(Point{, }.In(.Rect)) { return color.Alpha16{} } := .PixOffset(, ) return color.Alpha16{uint16(.Pix[+0])<<8 | uint16(.Pix[+1])} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *Alpha16) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*2 } func ( *Alpha16) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.Alpha16Model.Convert().(color.Alpha16) .Pix[+0] = uint8(.A >> 8) .Pix[+1] = uint8(.A) } func ( *Alpha16) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[+0] = uint8(.A >> 8) .Pix[+1] = uint8(.A) } func ( *Alpha16) (, int, color.Alpha16) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[+0] = uint8(.A >> 8) .Pix[+1] = uint8(.A) } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *Alpha16) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &Alpha16{} } := .PixOffset(.Min.X, .Min.Y) return &Alpha16{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *Alpha16) () bool { if .Rect.Empty() { return true } , := 0, .Rect.Dx()*2 for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for := ; < ; += 2 { if .Pix[+0] != 0xff || .Pix[+1] != 0xff { return false } } += .Stride += .Stride } return true } // NewAlpha16 returns a new [Alpha16] image with the given bounds. func ( Rectangle) *Alpha16 { return &Alpha16{ Pix: make([]uint8, pixelBufferLength(2, , "Alpha16")), Stride: 2 * .Dx(), Rect: , } } // Gray is an in-memory image whose At method returns [color.Gray] values. type Gray struct { // Pix holds the image's pixels, as gray values. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *Gray) () color.Model { return color.GrayModel } func ( *Gray) () Rectangle { return .Rect } func ( *Gray) (, int) color.Color { return .GrayAt(, ) } func ( *Gray) (, int) color.RGBA64 { := uint16(.GrayAt(, ).Y) |= << 8 return color.RGBA64{, , , 0xffff} } func ( *Gray) (, int) color.Gray { if !(Point{, }.In(.Rect)) { return color.Gray{} } := .PixOffset(, ) return color.Gray{.Pix[]} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *Gray) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*1 } func ( *Gray) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = color.GrayModel.Convert().(color.Gray).Y } func ( *Gray) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } // This formula is the same as in color.grayModel. := (19595*uint32(.R) + 38470*uint32(.G) + 7471*uint32(.B) + 1<<15) >> 24 := .PixOffset(, ) .Pix[] = uint8() } func ( *Gray) (, int, color.Gray) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = .Y } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *Gray) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &Gray{} } := .PixOffset(.Min.X, .Min.Y) return &Gray{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *Gray) () bool { return true } // NewGray returns a new [Gray] image with the given bounds. func ( Rectangle) *Gray { return &Gray{ Pix: make([]uint8, pixelBufferLength(1, , "Gray")), Stride: 1 * .Dx(), Rect: , } } // Gray16 is an in-memory image whose At method returns [color.Gray16] values. type Gray16 struct { // Pix holds the image's pixels, as gray values in big-endian format. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *Gray16) () color.Model { return color.Gray16Model } func ( *Gray16) () Rectangle { return .Rect } func ( *Gray16) (, int) color.Color { return .Gray16At(, ) } func ( *Gray16) (, int) color.RGBA64 { := .Gray16At(, ).Y return color.RGBA64{, , , 0xffff} } func ( *Gray16) (, int) color.Gray16 { if !(Point{, }.In(.Rect)) { return color.Gray16{} } := .PixOffset(, ) return color.Gray16{uint16(.Pix[+0])<<8 | uint16(.Pix[+1])} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *Gray16) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*2 } func ( *Gray16) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.Gray16Model.Convert().(color.Gray16) .Pix[+0] = uint8(.Y >> 8) .Pix[+1] = uint8(.Y) } func ( *Gray16) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } // This formula is the same as in color.gray16Model. := (19595*uint32(.R) + 38470*uint32(.G) + 7471*uint32(.B) + 1<<15) >> 16 := .PixOffset(, ) .Pix[+0] = uint8( >> 8) .Pix[+1] = uint8() } func ( *Gray16) (, int, color.Gray16) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[+0] = uint8(.Y >> 8) .Pix[+1] = uint8(.Y) } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *Gray16) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &Gray16{} } := .PixOffset(.Min.X, .Min.Y) return &Gray16{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *Gray16) () bool { return true } // NewGray16 returns a new [Gray16] image with the given bounds. func ( Rectangle) *Gray16 { return &Gray16{ Pix: make([]uint8, pixelBufferLength(2, , "Gray16")), Stride: 2 * .Dx(), Rect: , } } // CMYK is an in-memory image whose At method returns [color.CMYK] values. type CMYK struct { // Pix holds the image's pixels, in C, M, Y, K order. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle } func ( *CMYK) () color.Model { return color.CMYKModel } func ( *CMYK) () Rectangle { return .Rect } func ( *CMYK) (, int) color.Color { return .CMYKAt(, ) } func ( *CMYK) (, int) color.RGBA64 { , , , := .CMYKAt(, ).RGBA() return color.RGBA64{uint16(), uint16(), uint16(), uint16()} } func ( *CMYK) (, int) color.CMYK { if !(Point{, }.In(.Rect)) { return color.CMYK{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 return color.CMYK{[0], [1], [2], [3]} } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *CMYK) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*4 } func ( *CMYK) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := color.CMYKModel.Convert().(color.CMYK) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .C [1] = .M [2] = .Y [3] = .K } func ( *CMYK) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } , , , := color.RGBToCMYK(uint8(.R>>8), uint8(.G>>8), uint8(.B>>8)) := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = [1] = [2] = [3] = } func ( *CMYK) (, int, color.CMYK) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 [0] = .C [1] = .M [2] = .Y [3] = .K } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *CMYK) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &CMYK{} } := .PixOffset(.Min.X, .Min.Y) return &CMYK{ Pix: .Pix[:], Stride: .Stride, Rect: , } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *CMYK) () bool { return true } // NewCMYK returns a new CMYK image with the given bounds. func ( Rectangle) *CMYK { return &CMYK{ Pix: make([]uint8, pixelBufferLength(4, , "CMYK")), Stride: 4 * .Dx(), Rect: , } } // Paletted is an in-memory image of uint8 indices into a given palette. type Paletted struct { // Pix holds the image's pixels, as palette indices. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1]. Pix []uint8 // Stride is the Pix stride (in bytes) between vertically adjacent pixels. Stride int // Rect is the image's bounds. Rect Rectangle // Palette is the image's palette. Palette color.Palette } func ( *Paletted) () color.Model { return .Palette } func ( *Paletted) () Rectangle { return .Rect } func ( *Paletted) (, int) color.Color { if len(.Palette) == 0 { return nil } if !(Point{, }.In(.Rect)) { return .Palette[0] } := .PixOffset(, ) return .Palette[.Pix[]] } func ( *Paletted) (, int) color.RGBA64 { if len(.Palette) == 0 { return color.RGBA64{} } := color.Color(nil) if !(Point{, }.In(.Rect)) { = .Palette[0] } else { := .PixOffset(, ) = .Palette[.Pix[]] } , , , := .RGBA() return color.RGBA64{ uint16(), uint16(), uint16(), uint16(), } } // PixOffset returns the index of the first element of Pix that corresponds to // the pixel at (x, y). func ( *Paletted) (, int) int { return (-.Rect.Min.Y)*.Stride + (-.Rect.Min.X)*1 } func ( *Paletted) (, int, color.Color) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = uint8(.Palette.Index()) } func ( *Paletted) (, int, color.RGBA64) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = uint8(.Palette.Index()) } func ( *Paletted) (, int) uint8 { if !(Point{, }.In(.Rect)) { return 0 } := .PixOffset(, ) return .Pix[] } func ( *Paletted) (, int, uint8) { if !(Point{, }.In(.Rect)) { return } := .PixOffset(, ) .Pix[] = } // SubImage returns an image representing the portion of the image p visible // through r. The returned value shares pixels with the original image. func ( *Paletted) ( Rectangle) Image { = .Intersect(.Rect) // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside // either r1 or r2 if the intersection is empty. Without explicitly checking for // this, the Pix[i:] expression below can panic. if .Empty() { return &Paletted{ Palette: .Palette, } } := .PixOffset(.Min.X, .Min.Y) return &Paletted{ Pix: .Pix[:], Stride: .Stride, Rect: .Rect.Intersect(), Palette: .Palette, } } // Opaque scans the entire image and reports whether it is fully opaque. func ( *Paletted) () bool { var [256]bool , := 0, .Rect.Dx() for := .Rect.Min.Y; < .Rect.Max.Y; ++ { for , := range .Pix[:] { [] = true } += .Stride += .Stride } for , := range .Palette { if ![] { continue } , , , := .RGBA() if != 0xffff { return false } } return true } // NewPaletted returns a new [Paletted] image with the given width, height and // palette. func ( Rectangle, color.Palette) *Paletted { return &Paletted{ Pix: make([]uint8, pixelBufferLength(1, , "Paletted")), Stride: 1 * .Dx(), Rect: , Palette: , } }