1
0
mirror of https://github.com/golang/go synced 2024-11-14 08:10:22 -07:00
go/doc/articles/image_draw.html

223 lines
7.6 KiB
HTML
Raw Normal View History

<!--{
"Title": "The Go image/draw package",
"Template": true
}-->
<p>
<a href="/pkg/image/draw/">Package image/draw</a> defines
only one operation: drawing a source image onto a destination
image, through an optional mask image. This one operation is
surprisingly versatile and can perform a number of common image
manipulation tasks elegantly and efficiently.
</p>
<p>
Composition is performed pixel by pixel in the style of the Plan 9
graphics library and the X Render extension. The model is based on
the classic "Compositing Digital Images" paper by Porter and Duff,
with an additional mask parameter: <code>dst = (src IN mask) OP dst</code>.
For a fully opaque mask, this reduces to the original Porter-Duff
formula: <code>dst = src OP dst</code>. In Go, a nil mask image is equivalent
to an infinitely sized, fully opaque mask image.
</p>
<p>
The Porter-Duff paper presented
<a href="http://www.w3.org/TR/SVGCompositing/examples/compop-porterduff-examples.png">12 different composition operators</a>,
but with an explicit mask, only 2 of these are needed in practice:
source-over-destination and source. In Go, these operators are
represented by the <code>Over</code> and <code>Src</code> constants. The <code>Over</code> operator
performs the natural layering of a source image over a destination
image: the change to the destination image is smaller where the
source (after masking) is more transparent (that is, has lower
alpha). The <code>Src</code> operator merely copies the source (after masking)
with no regard for the destination image's original content. For
fully opaque source and mask images, the two operators produce the
same output, but the <code>Src</code> operator is usually faster.
</p>
<p><b>Geometric Alignment</b></p>
<p>
Composition requires associating destination pixels with source and
mask pixels. Obviously, this requires destination, source and mask
images, and a composition operator, but it also requires specifying
what rectangle of each image to use. Not every drawing should write
to the entire destination: when updating an animating image, it is
more efficient to only draw the parts of the image that have
changed. Not every drawing should read from the entire source: when
using a sprite that combines many small images into one large one,
only a part of the image is needed. Not every drawing should read
from the entire mask: a mask image that collects a font's glyphs is
similar to a sprite. Thus, drawing also needs to know three
rectangles, one for each image. Since each rectangle has the same
width and height, it suffices to pass a destination rectangle `r`
and two points <code>sp</code> and <code>mp</code>: the source rectangle is equal to <code>r</code>
translated so that <code>r.Min</code> in the destination image aligns with
<code>sp</code> in the source image, and similarly for <code>mp</code>. The effective
rectangle is also clipped to each image's bounds in their
respective co-ordinate space.
</p>
<p>
<img src="image-20.png">
</p>
<p>
The <a href="/pkg/image/draw/#DrawMask"><code>DrawMask</code></a>
function takes seven arguments, but an explicit mask and mask-point
are usually unnecessary, so the
<a href="/pkg/image/draw/#Draw"><code>Draw</code></a> function takes five:
</p>
<pre>
// Draw calls DrawMask with a nil mask.
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op)
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point,
mask image.Image, mp image.Point, op Op)
</pre>
<p>
The destination image must be mutable, so the image/draw package
defines a <a href="/pkg/image/draw/#Image"><code>draw.Image</code></a>
interface which has a <code>Set</code> method.
</p>
{{code "../src/pkg/image/draw/draw.go" `/type Image/` `/}/`}}
<p><b>Filling a Rectangle</b></p>
<p>
To fill a rectangle with a solid color, use an <code>image.Uniform</code>
source. The <code>Uniform</code> type re-interprets a <code>Color</code> as a
practically infinite-sized <code>Image</code> of that color. For those
familiar with the design of Plan 9's draw library, there is no need
for an explicit "repeat bit" in Go's slice-based image types; the
concept is subsumed by <code>Uniform</code>.
</p>
{{code "/doc/progs/image_draw.go" `/ZERO/` `/STOP/`}}
<p>
To initialize a new image to all-blue:
</p>
{{code "/doc/progs/image_draw.go" `/BLUE/` `/STOP/`}}
<p>
To reset an image to transparent (or black, if the destination
image's color model cannot represent transparency), use
<code>image.Transparent</code>, which is an <code>image.Uniform</code>:
</p>
{{code "/doc/progs/image_draw.go" `/RESET/` `/STOP/`}}
<p>
<img src="image-2a.png">
</p>
<p><b>Copying an Image</b></p>
<p>
To copy from a rectangle <code>sr</code> in the source image to a rectangle
starting at a point <code>dp</code> in the destination, convert the source
rectangle into the destination image's co-ordinate space:
</p>
{{code "/doc/progs/image_draw.go" `/RECT/` `/STOP/`}}
<p>
Alternatively:
</p>
{{code "/doc/progs/image_draw.go" `/RECT2/` `/STOP/`}}
<p>
To copy the entire source image, use <code>sr = src.Bounds()</code>.
</p>
<p>
<img src="image-2b.png">
</p>
<p><b>Scrolling an Image</b></p>
<p>
Scrolling an image is just copying an image to itself, with
different destination and source rectangles. Overlapping
destination and source images are perfectly valid, just as Go's
built-in copy function can handle overlapping destination and
source slices. To scroll an image m by 20 pixels:
</p>
{{code "/doc/progs/image_draw.go" `/SCROLL/` `/STOP/`}}
<p><img src="image-2c.png"></p>
<p><b>Converting an Image to RGBA</b></p>
<p>
The result of decoding an image format might not be an
<code>image.RGBA</code>: decoding a GIF results in an <code>image.Paletted</code>,
decoding a JPEG results in a <code>ycbcr.YCbCr</code>, and the result of
decoding a PNG depends on the image data. To convert any image to
an <code>image.RGBA</code>:
</p>
{{code "/doc/progs/image_draw.go" `/CONV/` `/STOP/`}}
<p>
<img src="image-2d.png">
</p>
<p><b>Drawing Through a Mask</b></p>
<p>
To draw an image through a circular mask with center <code>p</code> and radius
<code>r</code>:
</p>
{{code "/doc/progs/image_draw.go" `/CIRCLESTRUCT/` `/STOP/`}}
{{code "/doc/progs/image_draw.go" `/CIRCLE2/` `/STOP/`}}
<p>
<img src="image-2e.png">
</p>
<p><b>Drawing Font Glyphs</b></p>
<p>
To draw a font glyph in blue starting from a point <code>p</code>, draw with
an <code>image.Uniform</code> source and an <code>image.Alpha mask</code>. For
simplicity, we aren't performing any sub-pixel positioning or
rendering, or correcting for a font's height above a baseline.
</p>
{{code "/doc/progs/image_draw.go" `/GLYPH/` `/STOP/`}}
<p>
<img src="image-2f.png">
</p>
<p><b>Performance</b></p>
<p>
The image/draw package implementation demonstrates how to provide
an image manipulation function that is both general purpose, yet
efficient for common cases. The <code>DrawMask</code> function takes arguments
of interface types, but immediately makes type assertions that its
arguments are of specific struct types, corresponding to common
operations like drawing one <code>image.RGBA</code> image onto another, or
drawing an <code>image.Alpha</code> mask (such as a font glyph) onto an
<code>image.RGBA</code> image. If a type assertion succeeds, that type
information is used to run a specialized implementation of the
general algorithm. If the assertions fail, the fallback code path
uses the generic <code>At</code> and <code>Set</code> methods. The fast-paths are purely
a performance optimization; the resultant destination image is the
same either way. In practice, only a small number of special cases
are necessary to support typical applications.
</p>