// 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 imageimport ()// Config holds an image's color model and dimensions.typeConfigstruct { ColorModel color.Model Width, Height int}// Image is a finite rectangular grid of [color.Color] values taken from a color// model.typeImageinterface {// 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.typeRGBA64Imageinterface {// 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.RGBA64Image}// 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.typePalettedImageinterface {// ColorIndexAt returns the palette index of the pixel at (x, y).ColorIndexAt(x, y int) uint8Image}// 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.typeRGBAstruct {// 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 { returncolor.RGBAModel }func ( *RGBA) () Rectangle { return .Rect }func ( *RGBA) (, int) color.Color {return .RGBAAt(, )}func ( *RGBA) (, int) color.RGBA64 {if !(Point{, }.In(.Rect)) {returncolor.RGBA64{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857 := uint16([0]) := uint16([1]) := uint16([2]) := uint16([3])returncolor.RGBA64{ ( << 8) | , ( << 8) | , ( << 8) | , ( << 8) | , }}func ( *RGBA) (, int) color.RGBA {if !(Point{, }.In(.Rect)) {returncolor.RGBA{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857returncolor.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() {returntrue } , := 3, .Rect.Dx()*4for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; += 4 {if .Pix[] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeRGBA64struct {// 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 { returncolor.RGBA64Model }func ( *RGBA64) () Rectangle { return .Rect }func ( *RGBA64) (, int) color.Color {return .RGBA64At(, )}func ( *RGBA64) (, int) color.RGBA64 {if !(Point{, }.In(.Rect)) {returncolor.RGBA64{} } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857returncolor.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() {returntrue } , := 6, .Rect.Dx()*8for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; += 8 {if .Pix[+0] != 0xff || .Pix[+1] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeNRGBAstruct {// 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 { returncolor.NRGBAModel }func ( *NRGBA) () Rectangle { return .Rect }func ( *NRGBA) (, int) color.Color {return .NRGBAAt(, )}func ( *NRGBA) (, int) color.RGBA64 { , , , := .NRGBAAt(, ).RGBA()returncolor.RGBA64{uint16(), uint16(), uint16(), uint16()}}func ( *NRGBA) (, int) color.NRGBA {if !(Point{, }.In(.Rect)) {returncolor.NRGBA{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857returncolor.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() {returntrue } , := 3, .Rect.Dx()*4for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; += 4 {if .Pix[] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeNRGBA64struct {// 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 { returncolor.NRGBA64Model }func ( *NRGBA64) () Rectangle { return .Rect }func ( *NRGBA64) (, int) color.Color {return .NRGBA64At(, )}func ( *NRGBA64) (, int) color.RGBA64 { , , , := .NRGBA64At(, ).RGBA()returncolor.RGBA64{uint16(), uint16(), uint16(), uint16()}}func ( *NRGBA64) (, int) color.NRGBA64 {if !(Point{, }.In(.Rect)) {returncolor.NRGBA64{} } := .PixOffset(, ) := .Pix[ : +8 : +8] // Small cap improves performance, see https://golang.org/issue/27857returncolor.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() {returntrue } , := 6, .Rect.Dx()*8for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; += 8 {if .Pix[+0] != 0xff || .Pix[+1] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeAlphastruct {// 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 { returncolor.AlphaModel }func ( *Alpha) () Rectangle { return .Rect }func ( *Alpha) (, int) color.Color {return .AlphaAt(, )}func ( *Alpha) (, int) color.RGBA64 { := uint16(.AlphaAt(, ).A) |= << 8returncolor.RGBA64{, , , }}func ( *Alpha) (, int) color.Alpha {if !(Point{, }.In(.Rect)) {returncolor.Alpha{} } := .PixOffset(, )returncolor.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() {returntrue } , := 0, .Rect.Dx()for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; ++ {if .Pix[] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeAlpha16struct {// 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 { returncolor.Alpha16Model }func ( *Alpha16) () Rectangle { return .Rect }func ( *Alpha16) (, int) color.Color {return .Alpha16At(, )}func ( *Alpha16) (, int) color.RGBA64 { := .Alpha16At(, ).Areturncolor.RGBA64{, , , }}func ( *Alpha16) (, int) color.Alpha16 {if !(Point{, }.In(.Rect)) {returncolor.Alpha16{} } := .PixOffset(, )returncolor.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() {returntrue } , := 0, .Rect.Dx()*2for := .Rect.Min.Y; < .Rect.Max.Y; ++ {for := ; < ; += 2 {if .Pix[+0] != 0xff || .Pix[+1] != 0xff {returnfalse } } += .Stride += .Stride }returntrue}// 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.typeGraystruct {// 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 { returncolor.GrayModel }func ( *Gray) () Rectangle { return .Rect }func ( *Gray) (, int) color.Color {return .GrayAt(, )}func ( *Gray) (, int) color.RGBA64 { := uint16(.GrayAt(, ).Y) |= << 8returncolor.RGBA64{, , , 0xffff}}func ( *Gray) (, int) color.Gray {if !(Point{, }.In(.Rect)) {returncolor.Gray{} } := .PixOffset(, )returncolor.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 {returntrue}// 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.typeGray16struct {// 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 { returncolor.Gray16Model }func ( *Gray16) () Rectangle { return .Rect }func ( *Gray16) (, int) color.Color {return .Gray16At(, )}func ( *Gray16) (, int) color.RGBA64 { := .Gray16At(, ).Yreturncolor.RGBA64{, , , 0xffff}}func ( *Gray16) (, int) color.Gray16 {if !(Point{, }.In(.Rect)) {returncolor.Gray16{} } := .PixOffset(, )returncolor.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 {returntrue}// 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.typeCMYKstruct {// 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 { returncolor.CMYKModel }func ( *CMYK) () Rectangle { return .Rect }func ( *CMYK) (, int) color.Color {return .CMYKAt(, )}func ( *CMYK) (, int) color.RGBA64 { , , , := .CMYKAt(, ).RGBA()returncolor.RGBA64{uint16(), uint16(), uint16(), uint16()}}func ( *CMYK) (, int) color.CMYK {if !(Point{, }.In(.Rect)) {returncolor.CMYK{} } := .PixOffset(, ) := .Pix[ : +4 : +4] // Small cap improves performance, see https://golang.org/issue/27857returncolor.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 {returntrue}// 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.typePalettedstruct {// 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 {iflen(.Palette) == 0 {returnnil }if !(Point{, }.In(.Rect)) {return .Palette[0] } := .PixOffset(, )return .Palette[.Pix[]]}func ( *Paletted) (, int) color.RGBA64 {iflen(.Palette) == 0 {returncolor.RGBA64{} } := color.Color(nil)if !(Point{, }.In(.Rect)) { = .Palette[0] } else { := .PixOffset(, ) = .Palette[.Pix[]] } , , , := .RGBA()returncolor.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)) {return0 } := .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 {returnfalse } }returntrue}// 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: , }}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.