1
0
mirror of https://github.com/golang/go synced 2024-11-21 13:14:40 -07:00
go/doc/articles/image_package.html
2012-08-07 11:12:54 +08:00

313 lines
10 KiB
HTML

<!--{
"Title": "The Go image package",
"Template": true
}-->
<p>
The <a href="/pkg/image/">image</a> and
<a href="/pkg/image/color/">image/color</a> packages define a number of types:
<code>color.Color</code> and <code>color.Model</code> describe colors,
<code>image.Point</code> and <code>image.Rectangle</code> describe basic 2-D
geometry, and <code>image.Image</code> brings the two concepts together to
represent a rectangular grid of colors. A
<a href="/doc/articles/image_draw.html">separate article</a> covers image
composition with the <a href="/pkg/image/draw/">image/draw</a> package.
</p>
<p>
<b>Colors and Color Models</b>
</p>
<p>
<a href="/pkg/image/color/#Color">Color</a> 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.
</p>
{{code "/src/pkg/image/color/color.go" `/type Color interface/` `/^}/`}}
<p>
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 <code>uint32</code>, 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
<a href="https://en.wikipedia.org/wiki/Alpha_compositing">Porter and Duff's</a>
classic algebra:
</p>
<pre>
dstr, dstg, dstb, dsta := dst.RGBA()
srcr, srcg, srcb, srca := src.RGBA()
_, _, _, m := mask.RGBA()
const M = 1&lt;&lt;16 - 1
// The resultant red value is a blend of dstr and srcr, and ranges in [0, M].
// The calculation for green, blue and alpha is similar.
dstr = (dstr*(M-m) + srcr*m) / M
</pre>
<p>
The last line of that code snippet would have been more complicated if we worked
with non-alpha-premultiplied colors, which is why <code>Color</code> uses
alpha-premultiplied values.
</p>
<p>
The image/color package also defines a number of concrete types that implement
the <code>Color</code> interface. For example,
<a href="/pkg/image/color/#RGBA"><code>RGBA</code></a> is a struct that represents
the classic "8 bits per channel" color.
</p>
{{code "/src/pkg/image/color/color.go" `/type RGBA struct/` `/^}/`}}
<p>
Note that the <code>R</code> field of an <code>RGBA</code> is an 8-bit
alpha-premultiplied color in the range [0, 255]. <code>RGBA</code> satisfies the
<code>Color</code> interface by multiplying that value by 0x101 to generate a
16-bit alpha-premultiplied color in the range [0, 65535]. Similarly, the
<a href="/pkg/image/color/#NRGBA"><code>NRGBA</code></a> struct type represents
an 8-bit non-alpha-premultiplied color, as used by the PNG image format. When
manipulating an <code>NRGBA</code>'s fields directly, the values are
non-alpha-premultiplied, but when calling the <code>RGBA</code> method, the
return values are alpha-premultiplied.
</p>
<p>
A <a href="/pkg/image/color/#Model"><code>Model</code></a> is simply
something that can convert <code>Color</code>s to other <code>Color</code>s, possibly lossily. For
example, the <code>GrayModel</code> can convert any <code>Color</code> to a
desaturated <a href="/pkg/image/color/#Gray"><code>Gray</code></a>. A
<code>Palette</code> can convert any <code>Color</code> to one from a
limited palette.
</p>
{{code "/src/pkg/image/color/color.go" `/type Model interface/` `/^}/`}}
{{code "/src/pkg/image/color/color.go" `/type Palette \[\]Color/`}}
<p>
<b>Points and Rectangles</b>
</p>
<p>
A <a href="/pkg/image/#Point"><code>Point</code></a> 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 <code>Point</code> has no intrinsic width, height or
color, but the visualizations below use a small colored square.
</p>
{{code "/src/pkg/image/geom.go" `/type Point struct/` `/^}/`}}
<p>
<img src="image-package-01.png" width="400" height="300">
</p>
{{code "/doc/progs/image_package1.go" `/p := image.Point/`}}
<p>
A <a href="/pkg/image/#Rectangle"><code>Rectangle</code></a> is an axis-aligned
rectangle on the integer grid, defined by its top-left and bottom-right
<code>Point</code>. A <code>Rectangle</code> also has no intrinsic color, but
the visualizations below outline rectangles with a thin colored line, and call
out their <code>Min</code> and <code>Max</code> <code>Point</code>s.
</p>
{{code "/src/pkg/image/geom.go" `/type Rectangle struct/` `/^}/`}}
<p>
For convenience, <code>image.Rect(x0, y0, x1, y1)</code> is equivalent to
<code>image.Rectangle{image.Point{x0, y0}, image.Point{x1, y1}}</code>, but is
much easier to type.
</p>
<p>
A <code>Rectangle</code> is inclusive at the top-left and exclusive at the
bottom-right. For a <code>Point p</code> and a <code>Rectangle r</code>,
<code>p.In(r)</code> if and only if
<code>r.Min.X &lt;= p.X &amp;&amp; p.X &lt; r.Max.X</code>, and similarly for <code>Y</code>. This is analagous to how
a slice <code>s[i0:i1]</code> is inclusive at the low end and exclusive at the
high end. (Unlike arrays and slices, a <code>Rectangle</code> often has a
non-zero origin.)
</p>
<p>
<img src="image-package-02.png" width="400" height="300">
</p>
{{code "/doc/progs/image_package2.go" `/r := image.Rect/` `/fmt.Println/`}}
<p>
Adding a <code>Point</code> to a <code>Rectangle</code> translates the
<code>Rectangle</code>. Points and Rectangles are not restricted to be in the
bottom-right quadrant.
</p>
<p>
<img src="image-package-03.png" width="400" height="300">
</p>
{{code "/doc/progs/image_package3.go" `/r := image.Rect/` `/fmt.Println/`}}
<p>
Intersecting two Rectangles yields another Rectangle, which may be empty.
</p>
<p>
<img src="image-package-04.png" width="400" height="300">
</p>
{{code "/doc/progs/image_package4.go" `/r := image.Rect/` `/fmt.Printf/`}}
<p>
Points and Rectangles are passed and returned by value. A function that takes a
<code>Rectangle</code> argument will be as efficient as a function that takes
two <code>Point</code> arguments, or four <code>int</code> arguments.
</p>
<p>
<b>Images</b>
</p>
<p>
An <a href="/pkg/image/#Image">Image</a> maps every grid square in a
<code>Rectangle</code> to a <code>Color</code> from a <code>Model</code>.
"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).
</p>
{{code "/src/pkg/image/image.go" `/type Image interface/` `/^}/`}}
<p>
A common mistake is assuming that an <code>Image</code>'s bounds start at (0,
0). For example, an animated GIF contains a sequence of Images, and each
<code>Image</code> 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 <code>Image</code> m's pixels looks like:
</p>
<pre>
b := m.Bounds()
for y := b.Min.Y; y &lt; b.Max.Y; y++ {
for x := b.Min.X; y &lt; b.Max.X; x++ {
doStuffWith(m.At(x, y))
}
}
</pre>
<p>
<code>Image</code> implementations do not have to be based on an in-memory
slice of pixel data. For example, a
<a href="/pkg/image/#Uniform"><code>Uniform</code></a> is an
<code>Image</code> of enormous bounds and uniform color, whose in-memory
representation is simply that color.
</p>
{{code "/src/pkg/image/names.go" `/type Uniform struct/` `/^}/`}}
<p>
Typically, though, programs will want an image based on a slice. Struct types
like <a href="/pkg/image/#RGBA"><code>RGBA</code></a> and
<a href="/pkg/image/#Gray"><code>Gray</code></a> (which other packages refer
to as <code>image.RGBA</code> and <code>image.Gray</code>) hold slices of pixel
data and implement the <code>Image</code> interface.
</p>
{{code "/src/pkg/image/image.go" `/type RGBA struct/` `/^}/`}}
<p>
These types also provide a <code>Set(x, y int, c color.Color)</code> method
that allows modifying the image one pixel at a time.
</p>
{{code "/doc/progs/image_package5.go" `/m := image.New/` `/m.Set/`}}
<p>
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 <code>Pix</code> field directly.
</p>
<p>
The slice-based <code>Image</code> implementations also provide a
<code>SubImage</code> method, which returns an <code>Image</code> 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
<code>s[i0:i1]</code> will affect the contents of the original slice
<code>s</code>.
</p>
<img src="image-package-05.png" width="400" height="300">
{{code "/doc/progs/image_package6.go" `/m0 := image.New/` `/fmt.Println\(m0.Stride/`}}
<p>
For low-level code that works on an image's <code>Pix</code> field, be aware
that ranging over <code>Pix</code> can affect pixels outside an image's bounds.
In the example above, the pixels covered by <code>m1.Pix</code> are shaded in
blue. Higher-level code, such as the <code>At</code> and <code>Set</code>
methods or the <a href="/pkg/image/draw/">image/draw package</a>, will clip
their operations to the image's bounds.
</p>
<p>
<b>Image Formats</b>
</p>
<p>
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 <a href="/pkg/io/#Reader"><code>io.Reader</code></a> directly.
</p>
<pre>
import (
"image/jpeg"
"image/png"
"io"
)
// convertJPEGToPNG converts from JPEG to PNG.
func convertJPEGToPNG(w io.Writer, r io.Reader) error {
img, err := jpeg.Decode(r)
if err != nil {
return err
}
return png.Encode(w, img)
}
</pre>
<p>
If you have image data of unknown format, the
<a href="/pkg/image/#Decode"><code>image.Decode</code></a> 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.
</p>
<pre>
import (
"image"
"image/png"
"io"
_ "code.google.com/p/vp8-go/webp"
_ "image/jpeg"
)
// convertToPNG converts from any recognized format to PNG.
func convertToPNG(w io.Writer, r io.Reader) error {
img, _, err := image.Decode(r)
if err != nil {
return err
}
return png.Encode(w, img)
}
</pre>