Source file src/pkg/image/draw/draw.go
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.
4
5 // Package draw provides image composition functions.
6 //
7 // See "The Go image/draw package" for an introduction to this package:
8 // http://golang.org/doc/articles/image_draw.html
9 package draw
10
11 import (
12 "image"
13 "image/color"
14 )
15
16 // m is the maximum color value returned by image.Color.RGBA.
17 const m = 1<<16 - 1
18
19 // Op is a Porter-Duff compositing operator.
20 type Op int
21
22 const (
23 // Over specifies ``(src in mask) over dst''.
24 Over Op = iota
25 // Src specifies ``src in mask''.
26 Src
27 )
28
29 // A draw.Image is an image.Image with a Set method to change a single pixel.
30 type Image interface {
31 image.Image
32 Set(x, y int, c color.Color)
33 }
34
35 // Draw calls DrawMask with a nil mask.
36 func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
37 DrawMask(dst, r, src, sp, nil, image.ZP, op)
38 }
39
40 // clip clips r against each image's bounds (after translating into the
41 // destination image's co-ordinate space) and shifts the points sp and mp by
42 // the same amount as the change in r.Min.
43 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
44 orig := r.Min
45 *r = r.Intersect(dst.Bounds())
46 *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
47 if mask != nil {
48 *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
49 }
50 dx := r.Min.X - orig.X
51 dy := r.Min.Y - orig.Y
52 if dx == 0 && dy == 0 {
53 return
54 }
55 (*sp).X += dx
56 (*sp).Y += dy
57 (*mp).X += dx
58 (*mp).Y += dy
59 }
60
61 // DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
62 // in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
63 func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
64 clip(dst, &r, src, &sp, mask, &mp)
65 if r.Empty() {
66 return
67 }
68
69 // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
70 if dst0, ok := dst.(*image.RGBA); ok {
71 if op == Over {
72 if mask == nil {
73 switch src0 := src.(type) {
74 case *image.Uniform:
75 drawFillOver(dst0, r, src0)
76 return
77 case *image.RGBA:
78 drawCopyOver(dst0, r, src0, sp)
79 return
80 case *image.NRGBA:
81 drawNRGBAOver(dst0, r, src0, sp)
82 return
83 case *image.YCbCr:
84 drawYCbCr(dst0, r, src0, sp)
85 return
86 }
87 } else if mask0, ok := mask.(*image.Alpha); ok {
88 switch src0 := src.(type) {
89 case *image.Uniform:
90 drawGlyphOver(dst0, r, src0, mask0, mp)
91 return
92 }
93 }
94 } else {
95 if mask == nil {
96 switch src0 := src.(type) {
97 case *image.Uniform:
98 drawFillSrc(dst0, r, src0)
99 return
100 case *image.RGBA:
101 drawCopySrc(dst0, r, src0, sp)
102 return
103 case *image.NRGBA:
104 drawNRGBASrc(dst0, r, src0, sp)
105 return
106 case *image.YCbCr:
107 drawYCbCr(dst0, r, src0, sp)
108 return
109 }
110 }
111 }
112 drawRGBA(dst0, r, src, sp, mask, mp, op)
113 return
114 }
115
116 x0, x1, dx := r.Min.X, r.Max.X, 1
117 y0, y1, dy := r.Min.Y, r.Max.Y, 1
118 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
119 // Rectangles overlap: process backward?
120 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
121 x0, x1, dx = x1-1, x0-1, -1
122 y0, y1, dy = y1-1, y0-1, -1
123 }
124 }
125
126 var out *color.RGBA64
127 sy := sp.Y + y0 - r.Min.Y
128 my := mp.Y + y0 - r.Min.Y
129 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
130 sx := sp.X + x0 - r.Min.X
131 mx := mp.X + x0 - r.Min.X
132 for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
133 ma := uint32(m)
134 if mask != nil {
135 _, _, _, ma = mask.At(mx, my).RGBA()
136 }
137 switch {
138 case ma == 0:
139 if op == Over {
140 // No-op.
141 } else {
142 dst.Set(x, y, color.Transparent)
143 }
144 case ma == m && op == Src:
145 dst.Set(x, y, src.At(sx, sy))
146 default:
147 sr, sg, sb, sa := src.At(sx, sy).RGBA()
148 if out == nil {
149 out = new(color.RGBA64)
150 }
151 if op == Over {
152 dr, dg, db, da := dst.At(x, y).RGBA()
153 a := m - (sa * ma / m)
154 out.R = uint16((dr*a + sr*ma) / m)
155 out.G = uint16((dg*a + sg*ma) / m)
156 out.B = uint16((db*a + sb*ma) / m)
157 out.A = uint16((da*a + sa*ma) / m)
158 } else {
159 out.R = uint16(sr * ma / m)
160 out.G = uint16(sg * ma / m)
161 out.B = uint16(sb * ma / m)
162 out.A = uint16(sa * ma / m)
163 }
164 dst.Set(x, y, out)
165 }
166 }
167 }
168 }
169
170 func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
171 sr, sg, sb, sa := src.RGBA()
172 // The 0x101 is here for the same reason as in drawRGBA.
173 a := (m - sa) * 0x101
174 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
175 i1 := i0 + r.Dx()*4
176 for y := r.Min.Y; y != r.Max.Y; y++ {
177 for i := i0; i < i1; i += 4 {
178 dr := uint32(dst.Pix[i+0])
179 dg := uint32(dst.Pix[i+1])
180 db := uint32(dst.Pix[i+2])
181 da := uint32(dst.Pix[i+3])
182
183 dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
184 dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
185 dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
186 dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
187 }
188 i0 += dst.Stride
189 i1 += dst.Stride
190 }
191 }
192
193 func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
194 sr, sg, sb, sa := src.RGBA()
195 // The built-in copy function is faster than a straightforward for loop to fill the destination with
196 // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
197 // then use the first row as the slice source for the remaining rows.
198 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
199 i1 := i0 + r.Dx()*4
200 for i := i0; i < i1; i += 4 {
201 dst.Pix[i+0] = uint8(sr >> 8)
202 dst.Pix[i+1] = uint8(sg >> 8)
203 dst.Pix[i+2] = uint8(sb >> 8)
204 dst.Pix[i+3] = uint8(sa >> 8)
205 }
206 firstRow := dst.Pix[i0:i1]
207 for y := r.Min.Y + 1; y < r.Max.Y; y++ {
208 i0 += dst.Stride
209 i1 += dst.Stride
210 copy(dst.Pix[i0:i1], firstRow)
211 }
212 }
213
214 func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
215 dx, dy := r.Dx(), r.Dy()
216 d0 := dst.PixOffset(r.Min.X, r.Min.Y)
217 s0 := src.PixOffset(sp.X, sp.Y)
218 var (
219 ddelta, sdelta int
220 i0, i1, idelta int
221 )
222 if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
223 ddelta = dst.Stride
224 sdelta = src.Stride
225 i0, i1, idelta = 0, dx*4, +4
226 } else {
227 // If the source start point is higher than the destination start point, or equal height but to the left,
228 // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
229 d0 += (dy - 1) * dst.Stride
230 s0 += (dy - 1) * src.Stride
231 ddelta = -dst.Stride
232 sdelta = -src.Stride
233 i0, i1, idelta = (dx-1)*4, -4, -4
234 }
235 for ; dy > 0; dy-- {
236 dpix := dst.Pix[d0:]
237 spix := src.Pix[s0:]
238 for i := i0; i != i1; i += idelta {
239 sr := uint32(spix[i+0]) * 0x101
240 sg := uint32(spix[i+1]) * 0x101
241 sb := uint32(spix[i+2]) * 0x101
242 sa := uint32(spix[i+3]) * 0x101
243
244 dr := uint32(dpix[i+0])
245 dg := uint32(dpix[i+1])
246 db := uint32(dpix[i+2])
247 da := uint32(dpix[i+3])
248
249 // The 0x101 is here for the same reason as in drawRGBA.
250 a := (m - sa) * 0x101
251
252 dpix[i+0] = uint8((dr*a/m + sr) >> 8)
253 dpix[i+1] = uint8((dg*a/m + sg) >> 8)
254 dpix[i+2] = uint8((db*a/m + sb) >> 8)
255 dpix[i+3] = uint8((da*a/m + sa) >> 8)
256 }
257 d0 += ddelta
258 s0 += sdelta
259 }
260 }
261
262 func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
263 n, dy := 4*r.Dx(), r.Dy()
264 d0 := dst.PixOffset(r.Min.X, r.Min.Y)
265 s0 := src.PixOffset(sp.X, sp.Y)
266 var ddelta, sdelta int
267 if r.Min.Y <= sp.Y {
268 ddelta = dst.Stride
269 sdelta = src.Stride
270 } else {
271 // If the source start point is higher than the destination start point, then we compose the rows
272 // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
273 // check the x co-ordinates because the built-in copy function can handle overlapping slices.
274 d0 += (dy - 1) * dst.Stride
275 s0 += (dy - 1) * src.Stride
276 ddelta = -dst.Stride
277 sdelta = -src.Stride
278 }
279 for ; dy > 0; dy-- {
280 copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
281 d0 += ddelta
282 s0 += sdelta
283 }
284 }
285
286 func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
287 i0 := (r.Min.X - dst.Rect.Min.X) * 4
288 i1 := (r.Max.X - dst.Rect.Min.X) * 4
289 si0 := (sp.X - src.Rect.Min.X) * 4
290 yMax := r.Max.Y - dst.Rect.Min.Y
291
292 y := r.Min.Y - dst.Rect.Min.Y
293 sy := sp.Y - src.Rect.Min.Y
294 for ; y != yMax; y, sy = y+1, sy+1 {
295 dpix := dst.Pix[y*dst.Stride:]
296 spix := src.Pix[sy*src.Stride:]
297
298 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
299 // Convert from non-premultiplied color to pre-multiplied color.
300 sa := uint32(spix[si+3]) * 0x101
301 sr := uint32(spix[si+0]) * sa / 0xff
302 sg := uint32(spix[si+1]) * sa / 0xff
303 sb := uint32(spix[si+2]) * sa / 0xff
304
305 dr := uint32(dpix[i+0])
306 dg := uint32(dpix[i+1])
307 db := uint32(dpix[i+2])
308 da := uint32(dpix[i+3])
309
310 // The 0x101 is here for the same reason as in drawRGBA.
311 a := (m - sa) * 0x101
312
313 dpix[i+0] = uint8((dr*a/m + sr) >> 8)
314 dpix[i+1] = uint8((dg*a/m + sg) >> 8)
315 dpix[i+2] = uint8((db*a/m + sb) >> 8)
316 dpix[i+3] = uint8((da*a/m + sa) >> 8)
317 }
318 }
319 }
320
321 func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
322 i0 := (r.Min.X - dst.Rect.Min.X) * 4
323 i1 := (r.Max.X - dst.Rect.Min.X) * 4
324 si0 := (sp.X - src.Rect.Min.X) * 4
325 yMax := r.Max.Y - dst.Rect.Min.Y
326
327 y := r.Min.Y - dst.Rect.Min.Y
328 sy := sp.Y - src.Rect.Min.Y
329 for ; y != yMax; y, sy = y+1, sy+1 {
330 dpix := dst.Pix[y*dst.Stride:]
331 spix := src.Pix[sy*src.Stride:]
332
333 for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
334 // Convert from non-premultiplied color to pre-multiplied color.
335 sa := uint32(spix[si+3]) * 0x101
336 sr := uint32(spix[si+0]) * sa / 0xff
337 sg := uint32(spix[si+1]) * sa / 0xff
338 sb := uint32(spix[si+2]) * sa / 0xff
339
340 dpix[i+0] = uint8(sr >> 8)
341 dpix[i+1] = uint8(sg >> 8)
342 dpix[i+2] = uint8(sb >> 8)
343 dpix[i+3] = uint8(sa >> 8)
344 }
345 }
346 }
347
348 func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
349 // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
350 // (i.e. fully opaque) then the op is effectively always Src.
351 x0 := (r.Min.X - dst.Rect.Min.X) * 4
352 x1 := (r.Max.X - dst.Rect.Min.X) * 4
353 y0 := r.Min.Y - dst.Rect.Min.Y
354 y1 := r.Max.Y - dst.Rect.Min.Y
355 switch src.SubsampleRatio {
356 case image.YCbCrSubsampleRatio422:
357 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
358 dpix := dst.Pix[y*dst.Stride:]
359 yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
360 ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
361 for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
362 ci := ciBase + sx/2
363 rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
364 dpix[x+0] = rr
365 dpix[x+1] = gg
366 dpix[x+2] = bb
367 dpix[x+3] = 255
368 }
369 }
370 case image.YCbCrSubsampleRatio420:
371 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
372 dpix := dst.Pix[y*dst.Stride:]
373 yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
374 ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
375 for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
376 ci := ciBase + sx/2
377 rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
378 dpix[x+0] = rr
379 dpix[x+1] = gg
380 dpix[x+2] = bb
381 dpix[x+3] = 255
382 }
383 }
384 default:
385 // Default to 4:4:4 subsampling.
386 for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
387 dpix := dst.Pix[y*dst.Stride:]
388 yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
389 ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
390 for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
391 rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
392 dpix[x+0] = rr
393 dpix[x+1] = gg
394 dpix[x+2] = bb
395 dpix[x+3] = 255
396 }
397 }
398 }
399 }
400
401 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
402 i0 := dst.PixOffset(r.Min.X, r.Min.Y)
403 i1 := i0 + r.Dx()*4
404 mi0 := mask.PixOffset(mp.X, mp.Y)
405 sr, sg, sb, sa := src.RGBA()
406 for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
407 for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
408 ma := uint32(mask.Pix[mi])
409 if ma == 0 {
410 continue
411 }
412 ma |= ma << 8
413
414 dr := uint32(dst.Pix[i+0])
415 dg := uint32(dst.Pix[i+1])
416 db := uint32(dst.Pix[i+2])
417 da := uint32(dst.Pix[i+3])
418
419 // The 0x101 is here for the same reason as in drawRGBA.
420 a := (m - (sa * ma / m)) * 0x101
421
422 dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
423 dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
424 dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
425 dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
426 }
427 i0 += dst.Stride
428 i1 += dst.Stride
429 mi0 += mask.Stride
430 }
431 }
432
433 func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
434 x0, x1, dx := r.Min.X, r.Max.X, 1
435 y0, y1, dy := r.Min.Y, r.Max.Y, 1
436 if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
437 if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
438 x0, x1, dx = x1-1, x0-1, -1
439 y0, y1, dy = y1-1, y0-1, -1
440 }
441 }
442
443 sy := sp.Y + y0 - r.Min.Y
444 my := mp.Y + y0 - r.Min.Y
445 sx0 := sp.X + x0 - r.Min.X
446 mx0 := mp.X + x0 - r.Min.X
447 sx1 := sx0 + (x1 - x0)
448 i0 := dst.PixOffset(x0, y0)
449 di := dx * 4
450 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
451 for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
452 ma := uint32(m)
453 if mask != nil {
454 _, _, _, ma = mask.At(mx, my).RGBA()
455 }
456 sr, sg, sb, sa := src.At(sx, sy).RGBA()
457 if op == Over {
458 dr := uint32(dst.Pix[i+0])
459 dg := uint32(dst.Pix[i+1])
460 db := uint32(dst.Pix[i+2])
461 da := uint32(dst.Pix[i+3])
462
463 // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
464 // We work in 16-bit color, and so would normally do:
465 // dr |= dr << 8
466 // and similarly for dg, db and da, but instead we multiply a
467 // (which is a 16-bit color, ranging in [0,65535]) by 0x101.
468 // This yields the same result, but is fewer arithmetic operations.
469 a := (m - (sa * ma / m)) * 0x101
470
471 dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
472 dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
473 dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
474 dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
475
476 } else {
477 dst.Pix[i+0] = uint8(sr * ma / m >> 8)
478 dst.Pix[i+1] = uint8(sg * ma / m >> 8)
479 dst.Pix[i+2] = uint8(sb * ma / m >> 8)
480 dst.Pix[i+3] = uint8(sa * ma / m >> 8)
481 }
482 }
483 i0 += dy * dst.Stride
484 }
485 }