1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package draw provides image composition functions.
7 // See "The Go image/draw package" for an introduction to this package:
8 // http://blog.golang.org/2011/09/go-imagedraw-package.html
16 // m is the maximum color value returned by image.Color.RGBA.
19 // Op is a Porter-Duff compositing operator.
23 // Over specifies ``(src in mask) over dst''.
25 // Src specifies ``src in mask''.
29 var zeroColor image.Color = image.AlphaColor{0}
31 // A draw.Image is an image.Image with a Set method to change a single pixel.
32 type Image interface {
34 Set(x, y int, c image.Color)
37 // Draw calls DrawMask with a nil mask.
38 func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
39 DrawMask(dst, r, src, sp, nil, image.ZP, op)
42 // clip clips r against each image's bounds (after translating into the
43 // destination image's co-ordinate space) and shifts the points sp and mp by
44 // the same amount as the change in r.Min.
45 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
47 *r = r.Intersect(dst.Bounds())
48 *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
50 *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
52 dx := r.Min.X - orig.X
53 dy := r.Min.Y - orig.Y
54 if dx == 0 && dy == 0 {
63 // DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
64 // in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
65 func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
66 clip(dst, &r, src, &sp, mask, &mp)
71 // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
72 if dst0, ok := dst.(*image.RGBA); ok {
75 switch src0 := src.(type) {
76 case *image.ColorImage:
77 drawFillOver(dst0, r, src0)
80 drawCopyOver(dst0, r, src0, sp)
83 drawNRGBAOver(dst0, r, src0, sp)
86 drawYCbCr(dst0, r, src0, sp)
89 } else if mask0, ok := mask.(*image.Alpha); ok {
90 switch src0 := src.(type) {
91 case *image.ColorImage:
92 drawGlyphOver(dst0, r, src0, mask0, mp)
98 switch src0 := src.(type) {
99 case *image.ColorImage:
100 drawFillSrc(dst0, r, src0)
103 drawCopySrc(dst0, r, src0, sp)
106 drawNRGBASrc(dst0, r, src0, sp)
109 drawYCbCr(dst0, r, src0, sp)
114 drawRGBA(dst0, r, src, sp, mask, mp, op)
118 x0, x1, dx := r.Min.X, r.Max.X, 1
119 y0, y1, dy := r.Min.Y, r.Max.Y, 1
120 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
121 // Rectangles overlap: process backward?
122 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
123 x0, x1, dx = x1-1, x0-1, -1
124 y0, y1, dy = y1-1, y0-1, -1
128 var out *image.RGBA64Color
129 sy := sp.Y + y0 - r.Min.Y
130 my := mp.Y + y0 - r.Min.Y
131 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
132 sx := sp.X + x0 - r.Min.X
133 mx := mp.X + x0 - r.Min.X
134 for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
137 _, _, _, ma = mask.At(mx, my).RGBA()
144 dst.Set(x, y, zeroColor)
146 case ma == m && op == Src:
147 dst.Set(x, y, src.At(sx, sy))
149 sr, sg, sb, sa := src.At(sx, sy).RGBA()
151 out = new(image.RGBA64Color)
154 dr, dg, db, da := dst.At(x, y).RGBA()
155 a := m - (sa * ma / m)
156 out.R = uint16((dr*a + sr*ma) / m)
157 out.G = uint16((dg*a + sg*ma) / m)
158 out.B = uint16((db*a + sb*ma) / m)
159 out.A = uint16((da*a + sa*ma) / m)
161 out.R = uint16(sr * ma / m)
162 out.G = uint16(sg * ma / m)
163 out.B = uint16(sb * ma / m)
164 out.A = uint16(sa * ma / m)
172 func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
173 sr, sg, sb, sa := src.RGBA()
174 // The 0x101 is here for the same reason as in drawRGBA.
175 a := (m - sa) * 0x101
176 i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
178 for y := r.Min.Y; y != r.Max.Y; y++ {
179 for i := i0; i < i1; i += 4 {
180 dr := uint32(dst.Pix[i+0])
181 dg := uint32(dst.Pix[i+1])
182 db := uint32(dst.Pix[i+2])
183 da := uint32(dst.Pix[i+3])
185 dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
186 dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
187 dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
188 dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
195 func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
196 sr, sg, sb, sa := src.RGBA()
197 // The built-in copy function is faster than a straightforward for loop to fill the destination with
198 // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
199 // then use the first row as the slice source for the remaining rows.
200 i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
202 for i := i0; i < i1; i += 4 {
203 dst.Pix[i+0] = uint8(sr >> 8)
204 dst.Pix[i+1] = uint8(sg >> 8)
205 dst.Pix[i+2] = uint8(sb >> 8)
206 dst.Pix[i+3] = uint8(sa >> 8)
208 firstRow := dst.Pix[i0:i1]
209 for y := r.Min.Y + 1; y < r.Max.Y; y++ {
212 copy(dst.Pix[i0:i1], firstRow)
216 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
217 dx, dy := r.Dx(), r.Dy()
218 d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
219 s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
224 if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
227 i0, i1, idelta = 0, dx*4, +4
229 // If the source start point is higher than the destination start point, or equal height but to the left,
230 // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
231 d0 += (dy - 1) * dst.Stride
232 s0 += (dy - 1) * src.Stride
235 i0, i1, idelta = (dx-1)*4, -4, -4
240 for i := i0; i != i1; i += idelta {
241 sr := uint32(spix[i+0]) * 0x101
242 sg := uint32(spix[i+1]) * 0x101
243 sb := uint32(spix[i+2]) * 0x101
244 sa := uint32(spix[i+3]) * 0x101
246 dr := uint32(dpix[i+0])
247 dg := uint32(dpix[i+1])
248 db := uint32(dpix[i+2])
249 da := uint32(dpix[i+3])
251 // The 0x101 is here for the same reason as in drawRGBA.
252 a := (m - sa) * 0x101
254 dpix[i+0] = uint8((dr*a/m + sr) >> 8)
255 dpix[i+1] = uint8((dg*a/m + sg) >> 8)
256 dpix[i+2] = uint8((db*a/m + sb) >> 8)
257 dpix[i+3] = uint8((da*a/m + sa) >> 8)
264 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
265 n, dy := 4*r.Dx(), r.Dy()
266 d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
267 s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
268 var ddelta, sdelta int
273 // If the source start point is higher than the destination start point, then we compose the rows
274 // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
275 // check the x co-ordinates because the built-in copy function can handle overlapping slices.
276 d0 += (dy - 1) * dst.Stride
277 s0 += (dy - 1) * src.Stride
282 copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
288 func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
289 i0 := (r.Min.X - dst.Rect.Min.X) * 4
290 i1 := (r.Max.X - dst.Rect.Min.X) * 4
291 si0 := (sp.X - src.Rect.Min.X) * 4
292 yMax := r.Max.Y - dst.Rect.Min.Y
294 y := r.Min.Y - dst.Rect.Min.Y
295 sy := sp.Y - src.Rect.Min.Y
296 for ; y != yMax; y, sy = y+1, sy+1 {
297 dpix := dst.Pix[y*dst.Stride:]
298 spix := src.Pix[sy*src.Stride:]
300 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
301 // Convert from non-premultiplied color to pre-multiplied color.
302 sa := uint32(spix[si+3]) * 0x101
303 sr := uint32(spix[si+0]) * sa / 0xff
304 sg := uint32(spix[si+1]) * sa / 0xff
305 sb := uint32(spix[si+2]) * sa / 0xff
307 dr := uint32(dpix[i+0])
308 dg := uint32(dpix[i+1])
309 db := uint32(dpix[i+2])
310 da := uint32(dpix[i+3])
312 // The 0x101 is here for the same reason as in drawRGBA.
313 a := (m - sa) * 0x101
315 dpix[i+0] = uint8((dr*a/m + sr) >> 8)
316 dpix[i+1] = uint8((dg*a/m + sg) >> 8)
317 dpix[i+2] = uint8((db*a/m + sb) >> 8)
318 dpix[i+3] = uint8((da*a/m + sa) >> 8)
323 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
324 i0 := (r.Min.X - dst.Rect.Min.X) * 4
325 i1 := (r.Max.X - dst.Rect.Min.X) * 4
326 si0 := (sp.X - src.Rect.Min.X) * 4
327 yMax := r.Max.Y - dst.Rect.Min.Y
329 y := r.Min.Y - dst.Rect.Min.Y
330 sy := sp.Y - src.Rect.Min.Y
331 for ; y != yMax; y, sy = y+1, sy+1 {
332 dpix := dst.Pix[y*dst.Stride:]
333 spix := src.Pix[sy*src.Stride:]
335 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
336 // Convert from non-premultiplied color to pre-multiplied color.
337 sa := uint32(spix[si+3]) * 0x101
338 sr := uint32(spix[si+0]) * sa / 0xff
339 sg := uint32(spix[si+1]) * sa / 0xff
340 sb := uint32(spix[si+2]) * sa / 0xff
342 dpix[i+0] = uint8(sr >> 8)
343 dpix[i+1] = uint8(sg >> 8)
344 dpix[i+2] = uint8(sb >> 8)
345 dpix[i+3] = uint8(sa >> 8)
350 func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
351 // A YCbCr image is always fully opaque, and so if the mask is implicitly nil
352 // (i.e. fully opaque) then the op is effectively always Src.
356 x0 := (r.Min.X - dst.Rect.Min.X) * 4
357 x1 := (r.Max.X - dst.Rect.Min.X) * 4
358 y0 := r.Min.Y - dst.Rect.Min.Y
359 y1 := r.Max.Y - dst.Rect.Min.Y
360 switch src.SubsampleRatio {
361 case ycbcr.SubsampleRatio422:
362 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
363 dpix := dst.Pix[y*dst.Stride:]
364 for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
366 yy = src.Y[sy*src.YStride+sx]
367 cb = src.Cb[sy*src.CStride+i]
368 cr = src.Cr[sy*src.CStride+i]
369 rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
376 case ycbcr.SubsampleRatio420:
377 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
378 dpix := dst.Pix[y*dst.Stride:]
379 for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
381 yy = src.Y[sy*src.YStride+sx]
382 cb = src.Cb[j*src.CStride+i]
383 cr = src.Cr[j*src.CStride+i]
384 rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
392 // Default to 4:4:4 subsampling.
393 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
394 dpix := dst.Pix[y*dst.Stride:]
395 for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
396 yy = src.Y[sy*src.YStride+sx]
397 cb = src.Cb[sy*src.CStride+sx]
398 cr = src.Cr[sy*src.CStride+sx]
399 rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
409 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
410 i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
412 mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
413 sr, sg, sb, sa := src.RGBA()
414 for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
415 for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
416 ma := uint32(mask.Pix[mi])
422 dr := uint32(dst.Pix[i+0])
423 dg := uint32(dst.Pix[i+1])
424 db := uint32(dst.Pix[i+2])
425 da := uint32(dst.Pix[i+3])
427 // The 0x101 is here for the same reason as in drawRGBA.
428 a := (m - (sa * ma / m)) * 0x101
430 dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
431 dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
432 dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
433 dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
441 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
442 x0, x1, dx := r.Min.X, r.Max.X, 1
443 y0, y1, dy := r.Min.Y, r.Max.Y, 1
444 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
445 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
446 x0, x1, dx = x1-1, x0-1, -1
447 y0, y1, dy = y1-1, y0-1, -1
451 sy := sp.Y + y0 - r.Min.Y
452 my := mp.Y + y0 - r.Min.Y
453 sx0 := sp.X + x0 - r.Min.X
454 mx0 := mp.X + x0 - r.Min.X
455 sx1 := sx0 + (x1 - x0)
456 i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
458 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
459 for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
462 _, _, _, ma = mask.At(mx, my).RGBA()
464 sr, sg, sb, sa := src.At(sx, sy).RGBA()
466 dr := uint32(dst.Pix[i+0])
467 dg := uint32(dst.Pix[i+1])
468 db := uint32(dst.Pix[i+2])
469 da := uint32(dst.Pix[i+3])
471 // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
472 // We work in 16-bit color, and so would normally do:
474 // and similarly for dg, db and da, but instead we multiply a
475 // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
476 // This yields the same result, but is fewer arithmetic operations.
477 a := (m - (sa * ma / m)) * 0x101
479 dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
480 dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
481 dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
482 dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
485 dst.Pix[i+0] = uint8(sr * ma / m >> 8)
486 dst.Pix[i+1] = uint8(sg * ma / m >> 8)
487 dst.Pix[i+2] = uint8(sb * ma / m >> 8)
488 dst.Pix[i+3] = uint8(sa * ma / m >> 8)
491 i0 += dy * dst.Stride