From 18f1a71dc282689f29eeb51e248e6f79a970965b Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Wed, 28 Mar 2012 14:20:51 +1100 Subject: [PATCH] doc: added The Go image package article Orignally published on The Go Programming Language, September 21, 2011. http://blog.golang.org/2011/09/go-image-package.html Update #2547 R=adg, nigeltao CC=golang-dev https://golang.org/cl/5933049 --- doc/Makefile | 1 + doc/articles/image-package-01.png | Bin 0 -> 1393 bytes doc/articles/image-package-02.png | Bin 0 -> 1494 bytes doc/articles/image-package-03.png | Bin 0 -> 1477 bytes doc/articles/image-package-04.png | Bin 0 -> 1631 bytes doc/articles/image-package-05.png | Bin 0 -> 1613 bytes doc/articles/image_package.html | 312 ++++++++++++++++++++++++++++++ doc/docs.html | 2 +- doc/progs/image_package1.go | 15 ++ doc/progs/image_package2.go | 16 ++ doc/progs/image_package3.go | 15 ++ doc/progs/image_package4.go | 16 ++ doc/progs/image_package5.go | 17 ++ doc/progs/image_package6.go | 17 ++ doc/progs/run | 19 +- src/pkg/image/image.go | 2 +- 16 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 doc/articles/image-package-01.png create mode 100644 doc/articles/image-package-02.png create mode 100644 doc/articles/image-package-03.png create mode 100644 doc/articles/image-package-04.png create mode 100644 doc/articles/image-package-05.png create mode 100644 doc/articles/image_package.html create mode 100644 doc/progs/image_package1.go create mode 100644 doc/progs/image_package2.go create mode 100644 doc/progs/image_package3.go create mode 100644 doc/progs/image_package4.go create mode 100644 doc/progs/image_package5.go create mode 100644 doc/progs/image_package6.go 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 0000000000000000000000000000000000000000..aad9b124340435a35f30bfe50cf378d7633fef24 GIT binary patch literal 1393 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKNIvh+uk)*3dQyCaoEj(QuLn`LHxqh+t_Aw^6 zhuY4qJ=V$Ux4EomzjO)rY*65@;&@SU(z!;S=Wvz8ALq)#4SzmbrJSpL^Wfn^AtPhC{2)xQFYHDle*0ML$KQBEo=ktw&-T8Yz z|ILjq|I3$q^H*(j9A_g5L5|lZyb<`g@*C@qvvU34;~&58Uw=K*yfOZnxsJkP!{;`? z`NTK9|Gh0Y{r;oj}BH`(*e0SkvF% zpFg|wdUeLM$awSD$Nw`Zv2dRd&{1&S(7;cj=tI z8O^Z&`;6y54{S6%wy{}!{?^@3OJ}BDvrVg1VIkI!L2NWZ((-KqU^(?&1L0#*X^(UtNbwczVzji)339@ z&i=9Z_uapLyi9%n-8skmqm53{jOOC}I=go9U$*ZairPG@v@6KzDSY$bX!_fj>$8uU z$6YT!2TF=j1Dg(O_Wk@R6Zhi#j`r{m$O*DIHviMTiuVZY{|Nk>N WlCMXYiR}h*7(8A5T-G@yGywoK>N=VL literal 0 HcmV?d00001 diff --git a/doc/articles/image-package-03.png b/doc/articles/image-package-03.png new file mode 100644 index 0000000000000000000000000000000000000000..5bc0bf732d6ca2262480664394e50fa849a49004 GIT binary patch literal 1477 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKNIvh+uk)*3dQyCaodpunnLn`LHxsls-+e5_R zqDF<{r*m5-zgwD-zG`m89F}LyhZa8{pnRO!~XJ_ z&nu7LkVwA&VD|f6)=!^rI=!y=%_kKW(u^h2c64Purwkp11wJ1M`wxCwzbU?Zea=_Dhn~xBzulId_iJ1Jhr;BZ%6a`aOZ86_3R=FDy_I_Xb6KSj z6J6W}^|sILZEq!JufM)A`@`9_uXpL3Hr#!#s{Mn_^vZePec#E|T#v;dC z)ZW%aeA zU;p>(=i8;WCDISf?<6uxu7Cgjz5DwQBKPWl{(Ic^df~Cf>^1$7@ALDm`JNB7Tx=3Zua4S zQ9GT&`LfM9fJLH6GI_i0hrOF=Q;W4Nzs=Hv9eK9^4~Ia{a>Zr`H?@ zJCrW*zusN{K(nv?{+{3U^RGQNYqWpH$9-bPvr4Yis1=w{RXf{B!Z|o3-~u-c+bF^*;vMLwwG`kyh{;@c8Qs)`ZC~=j&fP zESBj1ZbL&)=Dg>N%PW)~7g<)dvRnR?Jz=EZFITv;=jX@ZAMcly-u)C9H!Zd2{p<1L<;V2$L)j8@o=y}1x_#C=bL-c~CqFpOy^oXB zl7Jll0QJCpu>JPis=ac1k6zy$bIeBHJ^$h}DZA$DhR50tPfNX7_F(e)UBz+rC(<9E zpZitn-%p+X7CICoz~uU|>I>6{H_Kki>tFkNAargC zuVeKdzYsl_Ja78q@E`l)j!Q`MMNdn;-RN)k`rVZ0rT-o;s9hbFnGH9xvXV2B6+ literal 0 HcmV?d00001 diff --git a/doc/articles/image-package-05.png b/doc/articles/image-package-05.png new file mode 100644 index 0000000000000000000000000000000000000000..54c47b67bf41a294adef10cbb9931fe5595406b6 GIT binary patch literal 1613 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKNIvh+uk)*3dQyCc8L_A#_Ln`LHxpA@Zv74Af zV4_!}iE(7=A|I1;E;B7e6ol7l+`2da=3T7=Dg_UVPffFsUvWK0Oz+~a!r0V#&r8MS zYOWnWe*ALU+*1CtMz0Gu*X?0&;Sigk7~#;Cz$n?onnEPU=d;cGy=}}t|NN<`ufJa{ zdSLzDKEtq>Z91oSar4`~KCO9wdSu$%dW^(@Xy=;pK=g*)2{{8#j zaK=BkUP~k&O+CG7&F&8mHt(DBsdi@SHOn+hAtn<1ip3%#1MAr9d)yX1nZJI0{QUa= z{kq+MKUdu?H9eqTafr!iS$}{3-s=S%_V4+_4k-VztNIKKc2|Hi-nX05yay6g0`RLSHV$(l2f`j@|K%5n~~cr7<8^;-SbpZ|(f zSZMDmpoe>|?-l>xZ{qv?{^NhItM2BiUU_&RipMI1s+S%jY|3L6r z<;`l&+}rQh0|VJ%6C{w6&+VFfO|IVQ_h*kE?f2{JzZ{run78}K2gCd4tX{u;D>?tl z-N^4B;`5{5ua~dC9>gGbR{m~z!T-LQ%bwRJAGQQVBF%#y!PQQCBch*x6 z4q~%3`N#f(RzTQ_}zc*rcCon@HLc8+TnwLk-OD}zW zy*PPxYHr!G*Q?Sur$!!=czopr E0A;jtxBvhE literal 0 HcmV?d00001 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 (