Run Format

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						if drawYCbCr(dst0, r, src0, sp) {
    85							return
    86						}
    87					}
    88				} else if mask0, ok := mask.(*image.Alpha); ok {
    89					switch src0 := src.(type) {
    90					case *image.Uniform:
    91						drawGlyphOver(dst0, r, src0, mask0, mp)
    92						return
    93					}
    94				}
    95			} else {
    96				if mask == nil {
    97					switch src0 := src.(type) {
    98					case *image.Uniform:
    99						drawFillSrc(dst0, r, src0)
   100						return
   101					case *image.RGBA:
   102						drawCopySrc(dst0, r, src0, sp)
   103						return
   104					case *image.NRGBA:
   105						drawNRGBASrc(dst0, r, src0, sp)
   106						return
   107					case *image.YCbCr:
   108						if drawYCbCr(dst0, r, src0, sp) {
   109							return
   110						}
   111					}
   112				}
   113			}
   114			drawRGBA(dst0, r, src, sp, mask, mp, op)
   115			return
   116		}
   117	
   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
   125			}
   126		}
   127	
   128		var out *color.RGBA64
   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 {
   135				ma := uint32(m)
   136				if mask != nil {
   137					_, _, _, ma = mask.At(mx, my).RGBA()
   138				}
   139				switch {
   140				case ma == 0:
   141					if op == Over {
   142						// No-op.
   143					} else {
   144						dst.Set(x, y, color.Transparent)
   145					}
   146				case ma == m && op == Src:
   147					dst.Set(x, y, src.At(sx, sy))
   148				default:
   149					sr, sg, sb, sa := src.At(sx, sy).RGBA()
   150					if out == nil {
   151						out = new(color.RGBA64)
   152					}
   153					if op == Over {
   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)
   160					} else {
   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)
   165					}
   166					dst.Set(x, y, out)
   167				}
   168			}
   169		}
   170	}
   171	
   172	func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
   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 := dst.PixOffset(r.Min.X, r.Min.Y)
   177		i1 := i0 + r.Dx()*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])
   184	
   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)
   189			}
   190			i0 += dst.Stride
   191			i1 += dst.Stride
   192		}
   193	}
   194	
   195	func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
   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 := dst.PixOffset(r.Min.X, r.Min.Y)
   201		i1 := i0 + r.Dx()*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)
   207		}
   208		firstRow := dst.Pix[i0:i1]
   209		for y := r.Min.Y + 1; y < r.Max.Y; y++ {
   210			i0 += dst.Stride
   211			i1 += dst.Stride
   212			copy(dst.Pix[i0:i1], firstRow)
   213		}
   214	}
   215	
   216	func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   217		dx, dy := r.Dx(), r.Dy()
   218		d0 := dst.PixOffset(r.Min.X, r.Min.Y)
   219		s0 := src.PixOffset(sp.X, sp.Y)
   220		var (
   221			ddelta, sdelta int
   222			i0, i1, idelta int
   223		)
   224		if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
   225			ddelta = dst.Stride
   226			sdelta = src.Stride
   227			i0, i1, idelta = 0, dx*4, +4
   228		} else {
   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
   233			ddelta = -dst.Stride
   234			sdelta = -src.Stride
   235			i0, i1, idelta = (dx-1)*4, -4, -4
   236		}
   237		for ; dy > 0; dy-- {
   238			dpix := dst.Pix[d0:]
   239			spix := src.Pix[s0:]
   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
   245	
   246				dr := uint32(dpix[i+0])
   247				dg := uint32(dpix[i+1])
   248				db := uint32(dpix[i+2])
   249				da := uint32(dpix[i+3])
   250	
   251				// The 0x101 is here for the same reason as in drawRGBA.
   252				a := (m - sa) * 0x101
   253	
   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)
   258			}
   259			d0 += ddelta
   260			s0 += sdelta
   261		}
   262	}
   263	
   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 := dst.PixOffset(r.Min.X, r.Min.Y)
   267		s0 := src.PixOffset(sp.X, sp.Y)
   268		var ddelta, sdelta int
   269		if r.Min.Y <= sp.Y {
   270			ddelta = dst.Stride
   271			sdelta = src.Stride
   272		} else {
   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
   278			ddelta = -dst.Stride
   279			sdelta = -src.Stride
   280		}
   281		for ; dy > 0; dy-- {
   282			copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
   283			d0 += ddelta
   284			s0 += sdelta
   285		}
   286	}
   287	
   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
   293	
   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:]
   299	
   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
   306	
   307				dr := uint32(dpix[i+0])
   308				dg := uint32(dpix[i+1])
   309				db := uint32(dpix[i+2])
   310				da := uint32(dpix[i+3])
   311	
   312				// The 0x101 is here for the same reason as in drawRGBA.
   313				a := (m - sa) * 0x101
   314	
   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)
   319			}
   320		}
   321	}
   322	
   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
   328	
   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:]
   334	
   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
   341	
   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)
   346			}
   347		}
   348	}
   349	
   350	func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
   351		// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
   352		// (i.e. fully opaque) then the op is effectively always Src.
   353		x0 := (r.Min.X - dst.Rect.Min.X) * 4
   354		x1 := (r.Max.X - dst.Rect.Min.X) * 4
   355		y0 := r.Min.Y - dst.Rect.Min.Y
   356		y1 := r.Max.Y - dst.Rect.Min.Y
   357		switch src.SubsampleRatio {
   358		case image.YCbCrSubsampleRatio444:
   359			for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
   360				dpix := dst.Pix[y*dst.Stride:]
   361				yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
   362				ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
   363				for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
   364					rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
   365					dpix[x+0] = rr
   366					dpix[x+1] = gg
   367					dpix[x+2] = bb
   368					dpix[x+3] = 255
   369				}
   370			}
   371		case image.YCbCrSubsampleRatio422:
   372			for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
   373				dpix := dst.Pix[y*dst.Stride:]
   374				yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
   375				ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
   376				for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
   377					ci := ciBase + sx/2
   378					rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
   379					dpix[x+0] = rr
   380					dpix[x+1] = gg
   381					dpix[x+2] = bb
   382					dpix[x+3] = 255
   383				}
   384			}
   385		case image.YCbCrSubsampleRatio420:
   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				ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
   390				for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
   391					ci := ciBase + sx/2
   392					rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
   393					dpix[x+0] = rr
   394					dpix[x+1] = gg
   395					dpix[x+2] = bb
   396					dpix[x+3] = 255
   397				}
   398			}
   399		case image.YCbCrSubsampleRatio440:
   400			for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
   401				dpix := dst.Pix[y*dst.Stride:]
   402				yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
   403				ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
   404				for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
   405					rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
   406					dpix[x+0] = rr
   407					dpix[x+1] = gg
   408					dpix[x+2] = bb
   409					dpix[x+3] = 255
   410				}
   411			}
   412		default:
   413			return false
   414		}
   415		return true
   416	}
   417	
   418	func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
   419		i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   420		i1 := i0 + r.Dx()*4
   421		mi0 := mask.PixOffset(mp.X, mp.Y)
   422		sr, sg, sb, sa := src.RGBA()
   423		for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
   424			for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
   425				ma := uint32(mask.Pix[mi])
   426				if ma == 0 {
   427					continue
   428				}
   429				ma |= ma << 8
   430	
   431				dr := uint32(dst.Pix[i+0])
   432				dg := uint32(dst.Pix[i+1])
   433				db := uint32(dst.Pix[i+2])
   434				da := uint32(dst.Pix[i+3])
   435	
   436				// The 0x101 is here for the same reason as in drawRGBA.
   437				a := (m - (sa * ma / m)) * 0x101
   438	
   439				dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
   440				dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
   441				dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
   442				dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
   443			}
   444			i0 += dst.Stride
   445			i1 += dst.Stride
   446			mi0 += mask.Stride
   447		}
   448	}
   449	
   450	func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
   451		x0, x1, dx := r.Min.X, r.Max.X, 1
   452		y0, y1, dy := r.Min.Y, r.Max.Y, 1
   453		if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
   454			if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   455				x0, x1, dx = x1-1, x0-1, -1
   456				y0, y1, dy = y1-1, y0-1, -1
   457			}
   458		}
   459	
   460		sy := sp.Y + y0 - r.Min.Y
   461		my := mp.Y + y0 - r.Min.Y
   462		sx0 := sp.X + x0 - r.Min.X
   463		mx0 := mp.X + x0 - r.Min.X
   464		sx1 := sx0 + (x1 - x0)
   465		i0 := dst.PixOffset(x0, y0)
   466		di := dx * 4
   467		for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   468			for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   469				ma := uint32(m)
   470				if mask != nil {
   471					_, _, _, ma = mask.At(mx, my).RGBA()
   472				}
   473				sr, sg, sb, sa := src.At(sx, sy).RGBA()
   474				if op == Over {
   475					dr := uint32(dst.Pix[i+0])
   476					dg := uint32(dst.Pix[i+1])
   477					db := uint32(dst.Pix[i+2])
   478					da := uint32(dst.Pix[i+3])
   479	
   480					// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   481					// We work in 16-bit color, and so would normally do:
   482					// dr |= dr << 8
   483					// and similarly for dg, db and da, but instead we multiply a
   484					// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   485					// This yields the same result, but is fewer arithmetic operations.
   486					a := (m - (sa * ma / m)) * 0x101
   487	
   488					dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
   489					dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
   490					dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
   491					dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
   492	
   493				} else {
   494					dst.Pix[i+0] = uint8(sr * ma / m >> 8)
   495					dst.Pix[i+1] = uint8(sg * ma / m >> 8)
   496					dst.Pix[i+2] = uint8(sb * ma / m >> 8)
   497					dst.Pix[i+3] = uint8(sa * ma / m >> 8)
   498				}
   499			}
   500			i0 += dy * dst.Stride
   501		}
   502	}

View as plain text