src/pkg/image/draw/draw.go - The Go Programming Language

Golang

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	}