diff options
Diffstat (limited to 'doc/articles/image_draw.html')
-rw-r--r-- | doc/articles/image_draw.html | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/doc/articles/image_draw.html b/doc/articles/image_draw.html new file mode 100644 index 000000000..848b65982 --- /dev/null +++ b/doc/articles/image_draw.html @@ -0,0 +1,222 @@ +<!--{ + "Title": "The Go image/draw package", + "Template": true +}--> + +<p> +<a href="http://golang.org/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="http://golang.org/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="http://golang.org/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="http://golang.org/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>ColorImage</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" `/CIRCLE/` `/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.ColorImage</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> + + |