diff --git a/doc/Makefile b/doc/Makefile index 03f341ac9ab..b6e475b84e9 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 new file mode 100644 index 00000000000..aad9b124340 Binary files /dev/null and b/doc/articles/image-package-01.png differ diff --git a/doc/articles/image-package-02.png b/doc/articles/image-package-02.png new file mode 100644 index 00000000000..3dd4692f3eb Binary files /dev/null and b/doc/articles/image-package-02.png differ diff --git a/doc/articles/image-package-03.png b/doc/articles/image-package-03.png new file mode 100644 index 00000000000..5bc0bf732d6 Binary files /dev/null and b/doc/articles/image-package-03.png differ diff --git a/doc/articles/image-package-04.png b/doc/articles/image-package-04.png new file mode 100644 index 00000000000..393dc1207ec Binary files /dev/null and b/doc/articles/image-package-04.png differ diff --git a/doc/articles/image-package-05.png b/doc/articles/image-package-05.png new file mode 100644 index 00000000000..54c47b67bf4 Binary files /dev/null and b/doc/articles/image-package-05.png differ diff --git a/doc/articles/image_package.html b/doc/articles/image_package.html new file mode 100644 index 00000000000..a9d2f3581d0 --- /dev/null +++ b/doc/articles/image_package.html @@ -0,0 +1,312 @@ + + +

+The image and +image/color packages define a number of types: +color.Color and color.Model describe colors, +image.Point and image.Rectangle describe basic 2-D +geometry, and image.Image brings the two concepts together to +represent a rectangular grid of colors. A +separate article covers image +composition with the image/draw package. +

+ +

+Colors and Color Models +

+ +

+Color 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. +

+ +{{code "/src/pkg/image/color/color.go" `/type Color interface/` `/^}/`}} + +

+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 uint32, 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 +Porter and Duff's +classic algebra: +

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

+The last line of that code snippet would have been more complicated if we worked +with non-alpha-premultiplied colors, which is why Color uses +alpha-premultiplied values. +

+ +

+The image/color package also defines a number of concrete types that implement +the Color interface. For example, +RGBA is a struct that represents +the classic "8 bits per channel" color. +

+ +{{code "/src/pkg/image/color/color.go" `/type RGBA struct/` `/^}/`}} + +

+Note that the R field of an RGBA is an 8-bit +alpha-premultiplied color in the range [0, 255]. RGBA satisfies the +Color interface by multiplying that value by 0x101 to generate a +16-bit alpha-premultiplied color in the range [0, 65535]. Similarly, the +NRGBA struct type represents +an 8-bit non-alpha-premultiplied color, as used by the PNG image format. When +manipulating an NRGBA's fields directly, the values are +non-alpha-premultiplied, but when calling the RGBA method, the +return values are alpha-premultiplied. +

+ +

+A Model is simply +something that can convert Colors to other Colors, possibly lossily. For +example, the GrayModel can convert any Color to a +desaturated Gray. A +Palette can convert any Color to one from a +limited palette. +

+ +{{code "/src/pkg/image/color/color.go" `/type Model interface/` `/^}/`}} + +{{code "/src/pkg/image/color/color.go" `/type Palette \[\]Color/`}} + +

+Points and Rectangles +

+ +

+A Point 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 Point has no intrinsic width, height or +color, but the visualizations below use a small colored square. +

+ +{{code "/src/pkg/image/geom.go" `/type Point struct/` `/^}/`}} + +

+ +

+ +{{code "/doc/progs/image_package1.go" `/p := image.Point/`}} + +

+A Rectangle is an axis-aligned +rectangle on the integer grid, defined by its top-left and bottom-right +Point. A Rectangle also has no intrinsic color, but +the visualizations below outline rectangles with a thin colored line, and call +out their Min and Max Points. +

+ +{{code "/src/pkg/image/geom.go" `/type Rectangle struct/` `/^}/`}} + +

+For convenience, image.Rect(x0, y0, x1, y1) is equivalent to +image.Rectangle{image.Point{x0, y0}, image.Point{x1, y1}}, but is +much easier to type. +

+ +

+A Rectangle is inclusive at the top-left and exclusive at the +bottom-right. For a Point p and a Rectangle r, +p.In(r) if and only if +r.Min.X <= p.X && p.X < r.Max.X, and similarly for Y. This is analagous to how +a slice s[i0:i1] is inclusive at the low end and exclusive at the +high end. (Unlike arrays and slices, a Rectangle often has a +non-zero origin.) +

+ +

+ +

+ +{{code "/doc/progs/image_package2.go" `/r := image.Rect/` `/fmt.Println/`}} + +

+Adding a Point to a Rectangle translates the +Rectangle. Points and Rectangles are not restricted to be in the +bottom-right quadrant. +

+ +

+ +

+ +{{code "/doc/progs/image_package3.go" `/r := image.Rect/` `/fmt.Println/`}} + +

+Intersecting two Rectangles yields another Rectangle, which may be empty. +

+ +

+ +

+ +{{code "/doc/progs/image_package4.go" `/r := image.Rect/` `/fmt.Printf/`}} + +

+Points and Rectangles are passed and returned by value. A function that takes a +Rectangle argument will be as efficient as a function that takes +two Point arguments, or four int arguments. +

+ +

+Images +

+ +

+An Image maps every grid square in a +Rectangle to a Color from a Model. +"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). +

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

+A common mistake is assuming that an Image's bounds start at (0, +0). For example, an animated GIF contains a sequence of Images, and each +Image 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 Image m's pixels looks like: +

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

+Image implementations do not have to be based on an in-memory +slice of pixel data. For example, a +Uniform is an +Image of enormous bounds and uniform color, whose in-memory +representation is simply that color. +

+ +{{code "/src/pkg/image/names.go" `/type Uniform struct/` `/^}/`}} + +

+Typically, though, programs will want an image based on a slice. Struct types +like RGBA and +Gray (which other packages refer +to as image.RGBA and image.Gray) hold slices of pixel +data and implement the Image interface. +

+ +{{code "/src/pkg/image/image.go" `/type RGBA struct/` `/^}/`}} + +

+These types also provide a Set(x, y int, c color.Color) method +that allows modifying the image one pixel at a time. +

+ +{{code "/doc/progs/image_package5.go" `/m := image.New/` `/m.Set/`}} + +

+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 Pix field directly. +

+ +

+The slice-based Image implementations also provide a +SubImage method, which returns an Image 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 +s[i0:i1] will affect the contents of the original slice +s. +

+ + + +{{code "/doc/progs/image_package6.go" `/m0 := image.New/` `/fmt.Println\(m0.Stride/`}} + +

+For low-level code that works on an image's Pix field, be aware +that ranging over Pix can affect pixels outside an image's bounds. +In the example above, the pixels covered by m1.Pix are shaded in +blue. Higher-level code, such as the At and Set +methods or the image/draw package, will clip +their operations to the image's bounds. +

+ +

+Image Formats +

+ +

+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 io.Reader directly. +

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

+If you have image data of unknown format, the +image.Decode 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. +

+ +
+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)
+}
+
diff --git a/doc/docs.html b/doc/docs.html index 577166e15ca..f88e930fba2 100644 --- a/doc/docs.html +++ b/doc/docs.html @@ -116,7 +116,7 @@ Guided tours of Go programs.
  • JSON and Go - using the json package.
  • 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 package - the fundamentals of the image package.
  • The Go image/draw package - the fundamentals of the image/draw package.
  • diff --git a/doc/progs/image_package1.go b/doc/progs/image_package1.go new file mode 100644 index 00000000000..c4c401e729e --- /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 00000000000..fcb5d9fd039 --- /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 00000000000..13d0f08079c --- /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 00000000000..c46fddf07a1 --- /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 00000000000..0bb5c7608e1 --- /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 00000000000..62eeecdb923 --- /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 8348a33e56e..92c8da5cdcd 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 63bfb7d59e4..03ac6060671 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 (