github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/blog/content/go-image-package.article (about)

     1  The Go image package
     2  21 Sep 2011
     3  Tags: image, libraries, technical
     4  
     5  Nigel Tao
     6  
     7  * Introduction
     8  
     9  The [[http://golang.org/pkg/image/][image]] and [[http://golang.org/pkg/image/color/][image/color]] packages define a number of types: `color.Color` and `color.Model` describe colors, `image.Point` and `image.Rectangle` describe basic 2-D geometry, and `image.Image` brings the two concepts together to represent a rectangular grid of colors. A [[http://golang.org/doc/articles/image_draw.html][separate article]] covers image composition with the [[http://golang.org/pkg/image/draw/][image/draw]] package.
    10  
    11  * Colors and Color Models
    12  
    13  [[http://golang.org/pkg/image/color/#Color][Color]] is an interface that defines the minimal method set of any type that can be considered a color: one that can be converted to red, green, blue and alpha values. The conversion may be lossy, such as converting from CMYK or YCbCr color spaces.
    14  
    15  	type Color interface {
    16  	    // RGBA returns the alpha-premultiplied red, green, blue and alpha values
    17  	    // for the color. Each value ranges within [0, 0xFFFF], but is represented
    18  	    // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
    19  	    // overflow.
    20  	    RGBA() (r, g, b, a uint32)
    21  	}
    22  
    23  There are three important subtleties about the return values. First, the red, green and blue are alpha-premultiplied: a fully saturated red that is also 25% transparent is represented by RGBA returning a 75% r. Second, the channels have a 16-bit effective range: 100% red is represented by RGBA returning an r of 65535, not 255, so that converting from CMYK or YCbCr is not as lossy. Third, the type returned is `uint32`, even though the maximum value is 65535, to guarantee that multiplying two values together won't overflow. Such multiplications occur when blending two colors according to an alpha mask from a third color, in the style of [[https://en.wikipedia.org/wiki/Alpha_compositing][Porter and Duff's]] classic algebra:
    24  
    25  	dstr, dstg, dstb, dsta := dst.RGBA()
    26  	srcr, srcg, srcb, srca := src.RGBA()
    27  	_, _, _, m := mask.RGBA()
    28  	const M = 1<<16 - 1
    29  	// The resultant red value is a blend of dstr and srcr, and ranges in [0, M].
    30  	// The calculation for green, blue and alpha is similar.
    31  	dstr = (dstr*(M-m) + srcr*m) / M
    32  
    33  The last line of that code snippet would have been more complicated if we worked with non-alpha-premultiplied colors, which is why `Color` uses alpha-premultiplied values.
    34  
    35  The image/color package also defines a number of concrete types that implement the `Color` interface. For example, [[http://golang.org/pkg/image/color/#RGBA][`RGBA`]] is a struct that represents the classic "8 bits per channel" color.
    36  
    37  	type RGBA struct {
    38  	    R, G, B, A uint8
    39  	}
    40  
    41  Note that the `R` field of an `RGBA` is an 8-bit alpha-premultiplied color in the range [0, 255]. `RGBA` satisfies the `Color` interface by multiplying that value by 0x101 to generate a 16-bit alpha-premultiplied color in the range [0, 65535]. Similarly, the [[http://golang.org/pkg/image/color/#NRGBA][`NRGBA`]] struct type represents an 8-bit non-alpha-premultiplied color, as used by the PNG image format. When manipulating an `NRGBA`'s fields directly, the values are non-alpha-premultiplied, but when calling the `RGBA` method, the return values are alpha-premultiplied.
    42  
    43  A [[http://golang.org/pkg/image/color/#Model][`Model`]] is simply something that can convert `Color`s to other `Color`s, possibly lossily. For example, the `GrayModel` can convert any `Color` to a desaturated [[http://golang.org/pkg/image/color/#Gray][`Gray`]]. A `Palette` can convert any `Color` to one from a limited palette.
    44  
    45  	type Model interface {
    46  	    Convert(c Color) Color
    47  	}
    48  
    49  	type Palette []Color
    50  
    51  * Points and Rectangles
    52  
    53  A [[http://golang.org/pkg/image/#Point][`Point`]] is an (x, y) co-ordinate on the integer grid, with axes increasing right and down. It is neither a pixel nor a grid square. A `Point` has no intrinsic width, height or color, but the visualizations below use a small colored square.
    54  
    55  	type Point struct {
    56  	    X, Y int
    57  	}
    58  
    59  .image go-image-package_image-package-01.png
    60  
    61  	    p := image.Point{2, 1}
    62  
    63  A [[http://golang.org/pkg/image/#Rectangle][`Rectangle`]] is an axis-aligned rectangle on the integer grid, defined by its top-left and bottom-right `Point`.  A `Rectangle` also has no intrinsic color, but the visualizations below outline rectangles with a thin colored line, and call out their `Min` and `Max` `Point`s.
    64  
    65  	type Rectangle struct {
    66  	    Min, Max Point
    67  	}
    68  
    69  For convenience, `image.Rect(x0,`y0,`x1,`y1)` is equivalent to `image.Rectangle{image.Point{x0,`y0},`image.Point{x1,`y1}}`, but is much easier to type.
    70  
    71  A `Rectangle` is inclusive at the top-left and exclusive at the bottom-right. For a `Point`p` and a `Rectangle`r`, `p.In(r)` if and only if `r.Min.X`<=`p.X`&&`p.X`<`r.Max.X`, and similarly for `Y`. This is analagous to how a slice `s[i0:i1]` is inclusive at the low end and exclusive at the high end. (Unlike arrays and slices, a `Rectangle` often has a non-zero origin.)
    72  
    73  .image go-image-package_image-package-02.png
    74  
    75  	    r := image.Rect(2, 1, 5, 5)
    76  	    // Dx and Dy return a rectangle's width and height.
    77  	    fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 false
    78  
    79  Adding a `Point` to a `Rectangle` translates the `Rectangle`. Points and Rectangles are not restricted to be in the bottom-right quadrant.
    80  
    81  .image go-image-package_image-package-03.png
    82  
    83  	    r := image.Rect(2, 1, 5, 5).Add(image.Pt(-4, -2))
    84  	    fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 true
    85  
    86  Intersecting two Rectangles yields another Rectangle, which may be empty.
    87  
    88  .image go-image-package_image-package-04.png
    89  
    90  	    r := image.Rect(0, 0, 4, 3).Intersect(image.Rect(2, 2, 5, 5))
    91  	    // Size returns a rectangle's width and height, as a Point.
    92  	    fmt.Printf("%#v\n", r.Size()) // prints image.Point{X:2, Y:1}
    93  
    94  Points and Rectangles are passed and returned by value. A function that takes a `Rectangle` argument will be as efficient as a function that takes two `Point` arguments, or four `int` arguments.
    95  
    96  * Images
    97  
    98  An [[http://golang.org/pkg/image/#Image][Image]] maps every grid square in a `Rectangle` to a `Color` from a `Model`. "The pixel at (x, y)" refers to the color of the grid square defined by the points (x, y), (x+1, y), (x+1, y+1) and (x, y+1).
    99  
   100  	type Image interface {
   101  	    // ColorModel returns the Image's color model.
   102  	    ColorModel() color.Model
   103  	    // Bounds returns the domain for which At can return non-zero color.
   104  	    // The bounds do not necessarily contain the point (0, 0).
   105  	    Bounds() Rectangle
   106  	    // At returns the color of the pixel at (x, y).
   107  	    // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
   108  	    // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
   109  	    At(x, y int) color.Color
   110  	}
   111  
   112  A common mistake is assuming that an `Image`'s bounds start at (0, 0). For example, an animated GIF contains a sequence of Images, and each `Image` after the first typically only holds pixel data for the area that changed, and that area doesn't necessarily start at (0, 0). The correct way to iterate over an `Image` m's pixels looks like:
   113  
   114  	b := m.Bounds()
   115  	for y := b.Min.Y; y < b.Max.Y; y++ {
   116  	 for x := b.Min.X; x < b.Max.X; x++ {
   117  	  doStuffWith(m.At(x, y))
   118  	 }
   119  	}
   120  
   121  `Image` implementations do not have to be based on an in-memory slice of pixel data. For example, a [[http://golang.org/pkg/image/#Uniform][`Uniform`]] is an `Image` of enormous bounds and uniform color, whose in-memory representation is simply that color.
   122  
   123  	type Uniform struct {
   124  	    C color.Color
   125  	}
   126  
   127  Typically, though, programs will want an image based on a slice. Struct types like [[http://golang.org/pkg/image/#RGBA][`RGBA`]] and [[http://golang.org/pkg/image/#Gray][`Gray`]] (which other packages refer to as `image.RGBA` and `image.Gray`) hold slices of pixel data and implement the `Image` interface.
   128  
   129  	type RGBA struct {
   130  	    // Pix holds the image's pixels, in R, G, B, A order. The pixel at
   131  	    // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
   132  	    Pix []uint8
   133  	    // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
   134  	    Stride int
   135  	    // Rect is the image's bounds.
   136  	    Rect Rectangle
   137  	}
   138  
   139  These types also provide a `Set(x,`y`int,`c`color.Color)` method that allows modifying the image one pixel at a time.
   140  
   141  	    m := image.NewRGBA(image.Rect(0, 0, 640, 480))
   142  	    m.Set(5, 5, color.RGBA{255, 0, 0, 255})
   143  
   144  If you're reading or writing a lot of pixel data, it can be more efficient, but more complicated, to access these struct type's `Pix` field directly.
   145  
   146  The slice-based `Image` implementations also provide a `SubImage` method, which returns an `Image` backed by the same array. Modifying the pixels of a sub-image will affect the pixels of the original image, analagous to how modifying the contents of a sub-slice `s[i0:i1]` will affect the contents of the original slice `s`.
   147  
   148  .image go-image-package_image-package-05.png
   149  
   150  	    m0 := image.NewRGBA(image.Rect(0, 0, 8, 5))
   151  	    m1 := m0.SubImage(image.Rect(1, 2, 5, 5)).(*image.RGBA)
   152  	    fmt.Println(m0.Bounds().Dx(), m1.Bounds().Dx()) // prints 8, 4
   153  	    fmt.Println(m0.Stride == m1.Stride)             // prints true
   154  
   155  For low-level code that works on an image's `Pix` field, be aware that ranging over `Pix` can affect pixels outside an image's bounds. In the example above, the pixels covered by `m1.Pix` are shaded in blue. Higher-level code, such as the `At` and `Set` methods or the [[http://golang.org/pkg/image/draw/][image/draw package]], will clip their operations to the image's bounds.
   156  
   157  * Image Formats
   158  
   159  The standard package library supports a number of common image formats, such as GIF, JPEG and PNG. If you know the format of a source image file, you can decode from an [[http://golang.org/pkg/io/#Reader][`io.Reader`]] directly.
   160  
   161  	import (
   162  	 "image/jpeg"
   163  	 "image/png"
   164  	 "io"
   165  	)
   166  
   167  	// convertJPEGToPNG converts from JPEG to PNG.
   168  	func convertJPEGToPNG(w io.Writer, r io.Reader) error {
   169  	 img, err := jpeg.Decode(r)
   170  	 if err != nil {
   171  	  return err
   172  	 }
   173  	 return png.Encode(w, img)
   174  	}
   175  
   176  If you have image data of unknown format, the [[http://golang.org/pkg/image/#Decode][`image.Decode`]] function can detect the format. The set of recognized formats is constructed at run time and is not limited to those in the standard package library. An image format package typically registers its format in an init function, and the main package will "underscore import" such a package solely for the side effect of format registration.
   177  
   178  	import (
   179  	 "image"
   180  	 "image/png"
   181  	 "io"
   182  
   183  	 _ "code.google.com/p/vp8-go/webp"
   184  	 _ "image/jpeg"
   185  	)
   186  
   187  	// convertToPNG converts from any recognized format to PNG.
   188  	func convertToPNG(w io.Writer, r io.Reader) error {
   189  	 img, _, err := image.Decode(r)
   190  	 if err != nil {
   191  	  return err
   192  	 }
   193  	 return png.Encode(w, img)
   194  	}