25 The Go image/draw package go图片/描绘包:图片/描绘包的基本原理
The Go image/draw package go图片/描绘包:图片/描绘包的基本原理
29 September 2011
Introduction
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.
type Image interface {
image.Image
Set(x, y int, c color.Color)
}
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.
// image.ZP is the zero point -- the origin.
draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
To initialize a new image to all-blue:
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)
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:
draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)

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:
r := image.Rectangle{dp, dp.Add(sr.Size())}
draw.Draw(dst, r, src, sr.Min, draw.Src)
Alternatively:
r := sr.Sub(sr.Min).Add(dp)
draw.Draw(dst, r, src, sr.Min, draw.Src)
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:
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))

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:
b := src.Bounds()
m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)

Drawing Through a Mask
To draw an image through a circular mask with center p and radius r:
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}
}
draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)

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

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 Setmethods. 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.
By Nigel Tao
Related articles
- HTTP/2 Server Push
- Introducing HTTP Tracing
- Generating code
- Introducing the Go Race Detector
- Go maps in action
- go fmt your code
- Organizing Go code
- Debugging Go programs with the GNU Debugger
- The Go image package
- The Laws of Reflection
- Error handling and Go
- "First Class Functions in Go"
- Profiling Go Programs
- Spotlight on external Go libraries
- A GIF decoder: an exercise in Go interfaces
- Introducing Gofix
- Godoc: documenting Go code
- Gobs of data
- C? Go? Cgo!
- JSON and Go
- Go Slices: usage and internals
- Go Concurrency Patterns: Timing out, moving on
- Defer, Panic, and Recover
- Share Memory By Communicating
- JSON-RPC: a tale of interfaces
25 The Go image/draw package go图片/描绘包:图片/描绘包的基本原理的更多相关文章
- ios中摄像头/相册获取图片,压缩图片,上传服务器方法总结
相册 iphone的相册包含摄像头胶卷+用户计算机同步的部分照片.用户可以通过UIImagePickerController类提供的交互对话框来从相册中选择图像.但是,注意:相册中的图片机器路径无法直 ...
- Java 遍历文件下jpg图片并解析图片
package filetest; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; ...
- 【Android】获取手机中已安装apk文件信息(PackageInfo、ResolveInfo)(应用图片、应用名、包名等)
众所周知,通过PackageManager可以获取手机端已安装的apk文件的信息,具体代码如下 PackageManager packageManager = this.getPackageManag ...
- MySQL数据库写入图片并读取图片显示到JLabel上的详解
相较于Oracle,MySQL作为一个轻量级的开源的数据库,可谓是大大简化了我们的操作.这次我就来写一个关于数据库存入图片,获取图片的例子吧,也为了今后的复习使用.(我们一般采取存入路径的方式,而不是 ...
- java多图片上传--前端实现预览--图片压缩 、图片缩放,区域裁剪,水印,旋转,保持比例。
java多图片上传--前端实现预览 前端代码: https://pan.baidu.com/s/1cqKbmjBSXOhFX4HR1XGkyQ 解压后: java后台: <!--文件上传--&g ...
- java关于图片处理修改图片大小
最近做了一个关于图片浏览的内容.因为图片都是一些证件的资料的扫描件所以比较大,对系统的影响也是非常之大的,有很大可能直接把系统干死.那么我是这么处理的,给大家分享一下.如果大家有好的方案的话一定要早点 ...
- spring mvc 图片上传,图片压缩、跨域解决、 按天生成文件夹 ,删除,限制为图片代码等相关配置
spring mvc 图片上传,跨域解决 按天生成文件夹 ,删除,限制为图片代码,等相关配置 fs.root=data/ #fs.root=/home/dev/fs/ #fs.root=D:/fs/ ...
- iOS 使用AFN 进行单图和多图上传 摄像头/相册获取图片,压缩图片
图片上传时必要将图片进行压缩,不然会上传失败 首先是同系统相册选择图片和视频.iOS系统自带有UIImagePickerController,可以选择或拍摄图片视频,但是最大的问题是只支持单选,由于项 ...
- Java图片上查找图片算法
之前用按键精灵写过一些游戏辅助,里面有个函数叫FindPic,就是在屏幕范围查找给定的一张图片,返回查找到的坐标位置. 现在,Java来实现这个函数类似的功能. 算法描述: 屏幕截图,得到图A,(查找 ...
随机推荐
- [洛谷P4091][HEOI2016/TJOI2016]求和
题目大意:给你$n(n\leqslant10^5)$,求:$$\sum\limits_{i=0}^n\sum\limits_{j=0}^i\begin{Bmatrix}i\\j\end{Bmatrix ...
- jQuery map和each用法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 51nod 1483 化学变换 | 二进制 暴力
51nod 1483 化学变换 题面 给出n个整数(n <= 1e5,每个数 <= 1e5),对每个数都可以进行多次操作,操作有两种:乘二/整除以二. 问最少经过多少次操作能使所有数相等. ...
- vi写完文件保存时才发现是readonly😂
在MAC上编辑apache配置文件,老是忘记sudo…… readonly的文件保存时提示 add ! to override, 但这仅是对root来说的啊! 百毒了一下竟然还有解决方案!! :w ! ...
- 【bzoj4540】 Hnoi2016—序列
http://www.lydsy.com/JudgeOnline/problem.php?id=4540 (题目链接) 题意 给出$n$个数的序列,$m$个询问,每次询问一段区间$[l,r]$,问$[ ...
- FastDFS分布式存储
分布式存储分类 通用分布式存储:mogilefs, fastdfs, ...(无文件系统接口, 通过API访问) 专用分布式存储:即分布式文件系统, moosefs, ...(有文件系统接口) GFS ...
- netbeans工具使用xdebug断点调试php源码
对有有经验的程序员,使用echo.print_r().print_f().var_dump()等函数足以调试php代码,如果需要在IDE工具中使用断点调试,xdebug就是一个非常好的php调试工具. ...
- Android资源混淆 + 混淆忽略 .so库
安装包立减1M--微信Android资源混淆打包工具http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx ...
- 浏览器json数据格式化
在浏览器上作接口测试的时候看到json 格式的数据是密密麻麻的一片,眼睛都花了.. 如: 设置方法: chrome 的右上角选择,然后--- 更多工具--- 扩展程序 ---- JSO ...
- Java入门:基础算法之计算三角形面积
本部分介绍如何计算三角形面积. /** * @author: 理工云课堂 * @description: 程序计算三角形的面积.三角形的底和高由用户输入 */ import java.util.Sca ...