diff options
-rw-r--r-- | doc/Makefile | 1 | ||||
-rw-r--r-- | doc/articles/image-package-01.png | bin | 0 -> 1393 bytes | |||
-rw-r--r-- | doc/articles/image-package-02.png | bin | 0 -> 1494 bytes | |||
-rw-r--r-- | doc/articles/image-package-03.png | bin | 0 -> 1477 bytes | |||
-rw-r--r-- | doc/articles/image-package-04.png | bin | 0 -> 1631 bytes | |||
-rw-r--r-- | doc/articles/image-package-05.png | bin | 0 -> 1613 bytes | |||
-rw-r--r-- | doc/articles/image_package.html | 312 | ||||
-rw-r--r-- | doc/docs.html | 2 | ||||
-rw-r--r-- | doc/progs/image_package1.go | 15 | ||||
-rw-r--r-- | doc/progs/image_package2.go | 16 | ||||
-rw-r--r-- | doc/progs/image_package3.go | 15 | ||||
-rw-r--r-- | doc/progs/image_package4.go | 16 | ||||
-rw-r--r-- | doc/progs/image_package5.go | 17 | ||||
-rw-r--r-- | doc/progs/image_package6.go | 17 | ||||
-rwxr-xr-x | doc/progs/run | 19 | ||||
-rw-r--r-- | src/pkg/image/image.go | 2 |
16 files changed, 429 insertions, 3 deletions
diff --git a/doc/Makefile b/doc/Makefile index 03f341ac9..b6e475b84 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -14,6 +14,7 @@ RAWHTML=\ articles/json_and_go.rawhtml\ articles/json_rpc_tale_of_interfaces.rawhtml\ articles/image_draw.rawhtml\ + articles/image_package.rawhtml\ effective_go.rawhtml\ go1.rawhtml\ diff --git a/doc/articles/image-package-01.png b/doc/articles/image-package-01.png Binary files differnew file mode 100644 index 000000000..aad9b1243 --- /dev/null +++ b/doc/articles/image-package-01.png diff --git a/doc/articles/image-package-02.png b/doc/articles/image-package-02.png Binary files differnew file mode 100644 index 000000000..3dd4692f3 --- /dev/null +++ b/doc/articles/image-package-02.png diff --git a/doc/articles/image-package-03.png b/doc/articles/image-package-03.png Binary files differnew file mode 100644 index 000000000..5bc0bf732 --- /dev/null +++ b/doc/articles/image-package-03.png diff --git a/doc/articles/image-package-04.png b/doc/articles/image-package-04.png Binary files differnew file mode 100644 index 000000000..393dc1207 --- /dev/null +++ b/doc/articles/image-package-04.png diff --git a/doc/articles/image-package-05.png b/doc/articles/image-package-05.png Binary files differnew file mode 100644 index 000000000..54c47b67b --- /dev/null +++ b/doc/articles/image-package-05.png diff --git a/doc/articles/image_package.html b/doc/articles/image_package.html new file mode 100644 index 000000000..a9d2f3581 --- /dev/null +++ b/doc/articles/image_package.html @@ -0,0 +1,312 @@ +<!--{ + "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<<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 <= p.X && p.X < 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 < b.Max.Y; y++ { + for x := b.Min.X; y < 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> diff --git a/doc/docs.html b/doc/docs.html index 577166e15..f88e930fb 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -116,7 +116,7 @@ Guided tours of Go programs. <li><a href="/doc/articles/json_and_go.html">JSON and Go</a> - using the <a href="/pkg/encoding/json/">json</a> package.</li> <li><a href="/doc/articles/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="/doc/articles/image_package.html">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</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> diff --git a/doc/progs/image_package1.go b/doc/progs/image_package1.go new file mode 100644 index 000000000..c4c401e72 --- /dev/null +++ b/doc/progs/image_package1.go @@ -0,0 +1,15 @@ +// 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. + +package main + +import ( + "fmt" + "image" +) + +func main() { + p := image.Point{2, 1} + fmt.Println("X is", p.X, "Y is", p.Y) +} diff --git a/doc/progs/image_package2.go b/doc/progs/image_package2.go new file mode 100644 index 000000000..fcb5d9fd0 --- /dev/null +++ b/doc/progs/image_package2.go @@ -0,0 +1,16 @@ +// 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. + +package main + +import ( + "fmt" + "image" +) + +func main() { + r := image.Rect(2, 1, 5, 5) + // Dx and Dy return a rectangle's width and height. + fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 false +} diff --git a/doc/progs/image_package3.go b/doc/progs/image_package3.go new file mode 100644 index 000000000..13d0f0807 --- /dev/null +++ b/doc/progs/image_package3.go @@ -0,0 +1,15 @@ +// 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. + +package main + +import ( + "fmt" + "image" +) + +func main() { + r := image.Rect(2, 1, 5, 5).Add(image.Pt(-4, -2)) + fmt.Println(r.Dx(), r.Dy(), image.Pt(0, 0).In(r)) // prints 3 4 true +} diff --git a/doc/progs/image_package4.go b/doc/progs/image_package4.go new file mode 100644 index 000000000..c46fddf07 --- /dev/null +++ b/doc/progs/image_package4.go @@ -0,0 +1,16 @@ +// 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. + +package main + +import ( + "fmt" + "image" +) + +func main() { + r := image.Rect(0, 0, 4, 3).Intersect(image.Rect(2, 2, 5, 5)) + // Size returns a rectangle's width and height, as a Point. + fmt.Printf("%#v\n", r.Size()) // prints image.Point{X:2, Y:1} +} diff --git a/doc/progs/image_package5.go b/doc/progs/image_package5.go new file mode 100644 index 000000000..0bb5c7608 --- /dev/null +++ b/doc/progs/image_package5.go @@ -0,0 +1,17 @@ +// 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. + +package main + +import ( + "fmt" + "image" + "image/color" +) + +func main() { + m := image.NewRGBA(image.Rect(0, 0, 640, 480)) + m.Set(5, 5, color.RGBA{255, 0, 0, 255}) + fmt.Println(m.At(5, 5)) +} diff --git a/doc/progs/image_package6.go b/doc/progs/image_package6.go new file mode 100644 index 000000000..62eeecdb9 --- /dev/null +++ b/doc/progs/image_package6.go @@ -0,0 +1,17 @@ +// 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. + +package main + +import ( + "fmt" + "image" +) + +func main() { + m0 := image.NewRGBA(image.Rect(0, 0, 8, 5)) + m1 := m0.SubImage(image.Rect(1, 2, 5, 5)).(*image.RGBA) + fmt.Println(m0.Bounds().Dx(), m1.Bounds().Dx()) // prints 8, 4 + fmt.Println(m0.Stride == m1.Stride) // prints true +} diff --git a/doc/progs/run b/doc/progs/run index 8348a33e5..92c8da5cd 100755 --- a/doc/progs/run +++ b/doc/progs/run @@ -59,7 +59,16 @@ json=" json5 " -all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json slices go1) +image_package=" + image_package1 + image_package2 + image_package3 + image_package4 + image_package5 + image_package6 +" + +all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json $image_package slices go1) for i in $all; do go build $i.go @@ -87,9 +96,17 @@ testit eff_sequence '^\[-1 2 6 16 44\]$' testit go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$' testit interface2 "^type: float64$" + testit json1 "^$" testit json2 "the reciprocal of i is" testit json3 "Age is int 6" testit json4 "^$" +testit image_package1 "^X is 2 Y is 1$" +testit image_package2 "^3 4 false$" +testit image_package3 "^3 4 true$" +testit image_package4 "^image.Point{X:2, Y:1}$" +testit image_package5 "^{255 0 0 255}$" +testit image_package6 "^8 4 true$" + rm -f $all "$TMPFILE" diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go index 63bfb7d59..03ac60606 100644 --- a/src/pkg/image/image.go +++ b/src/pkg/image/image.go @@ -18,7 +18,7 @@ // initialization side effects. // // See "The Go image package" for more details: -// http://blog.golang.org/2011/09/go-image-package.html +// http://golang.org/doc/articles/image_package.html package image import ( |