From: Johan Euphrosine Date: Wed, 14 Mar 2012 00:27:41 +0000 (+1100) Subject: doc: add Go image/draw package article and convert code snippets to Go1. X-Git-Tag: weekly.2012-03-22~109 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=fef92cbbac97022c094f4ff5bfb47b12852e076b;p=gostls13.git doc: add Go image/draw package article and convert code snippets to Go1. Originally published on The Go Programming Language Blog, September 29, 2011. http://blog.golang.org/2011/09/go-imagedraw-package.html Update #2547. R=golang-dev, adg, rsc CC=golang-dev https://golang.org/cl/5755057 --- diff --git a/doc/Makefile b/doc/Makefile index 60e1ef369c..b275dfe4dd 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -7,13 +7,14 @@ RAWHTML=\ articles/error_handling.rawhtml\ articles/slices_usage_and_internals.rawhtml\ articles/laws_of_reflection.rawhtml\ + articles/image_draw.rawhtml\ effective_go.rawhtml\ go1.rawhtml\ all: $(RAWHTML) %.rawhtml: %.html - godoc -url /doc/$* >$@ + godoc -url /doc/$< >$@ clean: rm -f $(RAWHTML) diff --git a/doc/articles/image-20.png b/doc/articles/image-20.png new file mode 100644 index 0000000000..063e430645 Binary files /dev/null and b/doc/articles/image-20.png differ diff --git a/doc/articles/image-2a.png b/doc/articles/image-2a.png new file mode 100644 index 0000000000..3f1c0afff8 Binary files /dev/null and b/doc/articles/image-2a.png differ diff --git a/doc/articles/image-2b.png b/doc/articles/image-2b.png new file mode 100644 index 0000000000..32b2470114 Binary files /dev/null and b/doc/articles/image-2b.png differ diff --git a/doc/articles/image-2c.png b/doc/articles/image-2c.png new file mode 100644 index 0000000000..f9abce5b52 Binary files /dev/null and b/doc/articles/image-2c.png differ diff --git a/doc/articles/image-2d.png b/doc/articles/image-2d.png new file mode 100644 index 0000000000..ed0a9f92c4 Binary files /dev/null and b/doc/articles/image-2d.png differ diff --git a/doc/articles/image-2e.png b/doc/articles/image-2e.png new file mode 100644 index 0000000000..483b208e3a Binary files /dev/null and b/doc/articles/image-2e.png differ diff --git a/doc/articles/image-2f.png b/doc/articles/image-2f.png new file mode 100644 index 0000000000..3dce02d5f4 Binary files /dev/null and b/doc/articles/image-2f.png differ diff --git a/doc/articles/image_draw.html b/doc/articles/image_draw.html new file mode 100644 index 0000000000..848b659822 --- /dev/null +++ b/doc/articles/image_draw.html @@ -0,0 +1,222 @@ + + +

+Package image/draw 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. +

+ +

+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: dst = (src IN mask) OP dst. +For a fully opaque mask, this reduces to the original Porter-Duff +formula: dst = src OP dst. In Go, a nil mask image is equivalent +to an infinitely sized, fully opaque mask image. +

+ +

+The Porter-Duff paper presented +12 different composition operators, +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 Over and Src constants. The Over 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 Src 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 Src operator is usually faster. +

+ +

Geometric Alignment

+ +

+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 sp and mp: the source rectangle is equal to r +translated so that r.Min in the destination image aligns with +sp in the source image, and similarly for mp. The effective +rectangle is also clipped to each image's bounds in their +respective co-ordinate space. +

+ +

+ +

+ +

+The DrawMask +function takes seven arguments, but an explicit mask and mask-point +are usually unnecessary, so the +Draw function takes five: +

+ +
+// 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)
+
+ +

+The destination image must be mutable, so the image/draw package +defines a draw.Image +interface which has a Set method. +

+ +{{code "../src/pkg/image/draw/draw.go" `/type Image/` `/}/`}} + +

Filling a Rectangle

+ +

+To fill a rectangle with a solid color, use an image.Uniform +source. The ColorImage type re-interprets a Color as a +practically infinite-sized Image 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 Uniform. +

+ +{{code "/doc/progs/image_draw.go" `/ZERO/` `/STOP/`}} + +

+To initialize a new image to all-blue: +

+ +{{code "/doc/progs/image_draw.go" `/BLUE/` `/STOP/`}} + +

+To reset an image to transparent (or black, if the destination +image's color model cannot represent transparency), use +image.Transparent, which is an image.Uniform: +

+ +{{code "/doc/progs/image_draw.go" `/RESET/` `/STOP/`}} + +

+ +

+ + +

Copying an Image

+ +

+To copy from a rectangle sr in the source image to a rectangle +starting at a point dp in the destination, convert the source +rectangle into the destination image's co-ordinate space: +

+ +{{code "/doc/progs/image_draw.go" `/RECT/` `/STOP/`}} + +

+Alternatively: +

+ +{{code "/doc/progs/image_draw.go" `/RECT2/` `/STOP/`}} + +

+To copy the entire source image, use sr = src.Bounds(). +

+ +

+ +

+ +

Scrolling an Image

+ +

+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: +

+ +{{code "/doc/progs/image_draw.go" `/SCROLL/` `/STOP/`}} + +

+ +

Converting an Image to RGBA

+ +

+The result of decoding an image format might not be an +image.RGBA: decoding a GIF results in an image.Paletted, +decoding a JPEG results in a ycbcr.YCbCr, and the result of +decoding a PNG depends on the image data. To convert any image to +an image.RGBA: +

+ +{{code "/doc/progs/image_draw.go" `/CONV/` `/STOP/`}} + +

+ +

+ +

Drawing Through a Mask

+ +

+To draw an image through a circular mask with center p and radius +r: +

+ +{{code "/doc/progs/image_draw.go" `/CIRCLE/` `/STOP/`}} +{{code "/doc/progs/image_draw.go" `/CIRCLE2/` `/STOP/`}} + +

+ +

+ +

Drawing Font Glyphs

+ +

+To draw a font glyph in blue starting from a point p, draw with +an image.ColorImage source and an image.Alpha mask. For +simplicity, we aren't performing any sub-pixel positioning or +rendering, or correcting for a font's height above a baseline. +

+ +{{code "/doc/progs/image_draw.go" `/GLYPH/` `/STOP/`}} + +

+ +

+ +

Performance

+ +

+The image/draw package implementation demonstrates how to provide +an image manipulation function that is both general purpose, yet +efficient for common cases. The DrawMask 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 image.RGBA image onto another, or +drawing an image.Alpha mask (such as a font glyph) onto an +image.RGBA 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 At and Set 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. +

+ + diff --git a/doc/docs.html b/doc/docs.html index 4b40bfe4b3..cc637b038a 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -117,7 +117,7 @@ Guided tours of Go programs.
  • Gobs of data - the design and use of the gob package.
  • The Laws of Reflection - the fundamentals of the reflect package.
  • The Go image package - the fundamentals of the image package.
  • -
  • The Go image/draw package - the fundamentals of the image/draw package.
  • +
  • The Go image/draw package - the fundamentals of the image/draw package.
  • Tools

    diff --git a/doc/progs/image_draw.go b/doc/progs/image_draw.go new file mode 100644 index 0000000000..f3400b601b --- /dev/null +++ b/doc/progs/image_draw.go @@ -0,0 +1,142 @@ +// Copyright 2012 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. + +// This file contains the code snippets included in "The Go image/draw package." + +package main + +import ( + "image" + "image/color" + "image/draw" +) + +func main() { + Color() + Rect() + RectAndScroll() + ConvAndCircle() + Glyph() +} + +func Color() { + c := color.RGBA{255, 0, 255, 255} + r := image.Rect(0, 0, 640, 480) + dst := image.NewRGBA(r) + + // ZERO OMIT + // image.ZP is the zero point -- the origin. + draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src) + // STOP OMIT + + // BLUE OMIT + m := image.NewRGBA(image.Rect(0, 0, 640, 480)) + blue := color.RGBA{0, 0, 255, 255} + draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src) + // STOP OMIT + + // RESET OMIT + draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src) + // STOP OMIT +} + +func Rect() { + dst := image.NewRGBA(image.Rect(0, 0, 640, 480)) + sr := image.Rect(0, 0, 200, 200) + src := image.Black + dp := image.Point{100, 100} + + // RECT OMIT + r := image.Rectangle{dp, dp.Add(sr.Size())} + draw.Draw(dst, r, src, sr.Min, draw.Src) + // STOP OMIT +} + +func RectAndScroll() { + dst := image.NewRGBA(image.Rect(0, 0, 640, 480)) + sr := image.Rect(0, 0, 200, 200) + src := image.Black + dp := image.Point{100, 100} + + // RECT2 OMIT + r := sr.Sub(sr.Min).Add(dp) + draw.Draw(dst, r, src, sr.Min, draw.Src) + // STOP OMIT + + m := dst + + // SCROLL OMIT + b := m.Bounds() + p := image.Pt(0, 20) + // Note that even though the second argument is b, + // the effective rectangle is smaller due to clipping. + draw.Draw(m, b, m, b.Min.Add(p), draw.Src) + dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y)) + // STOP OMIT + + _ = dirtyRect // noop +} + +func ConvAndCircle() { + src := image.NewRGBA(image.Rect(0, 0, 640, 480)) + dst := image.NewRGBA(image.Rect(0, 0, 640, 480)) + + // CONV OMIT + b := src.Bounds() + m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) + draw.Draw(m, m.Bounds(), src, b.Min, draw.Src) + // STOP OMIT + + p := image.Point{100, 100} + r := 50 + + // CIRCLE2 OMIT + draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over) + // STOP OMIT +} + +func theGlyphImageForAFont() image.Image { + return image.NewRGBA(image.Rect(0, 0, 640, 480)) +} + +func theBoundsFor(index int) image.Rectangle { + return image.Rect(0, 0, 32, 32) +} + +func Glyph() { + p := image.Point{100, 100} + dst := image.NewRGBA(image.Rect(0, 0, 640, 480)) + glyphIndex := 42 + + // GLYPH OMIT + src := &image.Uniform{color.RGBA{0, 0, 255, 255}} + mask := theGlyphImageForAFont() + mr := theBoundsFor(glyphIndex) + draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over) + // STOP OMIT +} + +//CIRCLE OMIT +type circle struct { + p image.Point + r int +} + +func (c *circle) ColorModel() color.Model { + return color.AlphaModel +} + +func (c *circle) Bounds() image.Rectangle { + return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r) +} + +func (c *circle) At(x, y int) color.Color { + xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r) + if xx*xx+yy*yy < rr*rr { + return color.Alpha{255} + } + return color.Alpha{0} +} + +//STOP diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go index 3b6679f7c7..bef325c0c9 100644 --- a/src/pkg/image/draw/draw.go +++ b/src/pkg/image/draw/draw.go @@ -5,7 +5,7 @@ // Package draw provides image composition functions. // // See "The Go image/draw package" for an introduction to this package: -// http://blog.golang.org/2011/09/go-imagedraw-package.html +// http://golang.org/doc/articles/image_draw.html package draw import (