1
0
mirror of https://github.com/golang/go synced 2024-11-24 06:10:05 -07:00

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
This commit is contained in:
Johan Euphrosine 2012-03-14 11:27:41 +11:00 committed by Andrew Gerrand
parent 5f32c8b88b
commit fef92cbbac
12 changed files with 368 additions and 3 deletions

View File

@ -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)

BIN
doc/articles/image-20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
doc/articles/image-2a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
doc/articles/image-2b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
doc/articles/image-2c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
doc/articles/image-2d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
doc/articles/image-2e.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
doc/articles/image-2f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -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>

View File

@ -117,7 +117,7 @@ Guided tours of Go programs.
<li><a href="http://blog.golang.org/2011/03/gobs-of-data.html">Gobs of data</a> - the design and use of the <a href="/pkg/encoding/gob/">gob</a> package.</li>
<li><a href="/doc/articles/laws_of_reflection.html">The Laws of Reflection</a> - the fundamentals of the <a href="/pkg/reflect/">reflect</a> package.</li>
<li><a href="http://blog.golang.org/2011/09/go-image-package.html">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</a> package.</li>
<li><a href="http://blog.golang.org/2011/09/go-imagedraw-package.html">The Go image/draw package</a> - the fundamentals of the <a href="/pkg/image/draw/">image/draw</a> package.</li>
<li><a href="/doc/articles/image_draw.html">The Go image/draw package</a> - the fundamentals of the <a href="/pkg/image/draw/">image/draw</a> package.</li>
</ul>
<h4>Tools</h4>

142
doc/progs/image_draw.go Normal file
View File

@ -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

View File

@ -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 (