Black Lives Matter. Support the Equal Justice Initiative.

Source file src/image/draw/draw.go

Documentation: image/draw

     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  // https://golang.org/doc/articles/image_draw.html
     9  package draw
    10  
    11  import (
    12  	"image"
    13  	"image/color"
    14  	"image/internal/imageutil"
    15  )
    16  
    17  // m is the maximum color value returned by image.Color.RGBA.
    18  const m = 1<<16 - 1
    19  
    20  // Image is an image.Image with a Set method to change a single pixel.
    21  type Image interface {
    22  	image.Image
    23  	Set(x, y int, c color.Color)
    24  }
    25  
    26  // RGBA64Image extends both the Image and image.RGBA64Image interfaces with a
    27  // SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to
    28  // calling Set, but it can avoid allocations from converting concrete color
    29  // types to the color.Color interface type.
    30  type RGBA64Image interface {
    31  	image.RGBA64Image
    32  	Set(x, y int, c color.Color)
    33  	SetRGBA64(x, y int, c color.RGBA64)
    34  }
    35  
    36  // Quantizer produces a palette for an image.
    37  type Quantizer interface {
    38  	// Quantize appends up to cap(p) - len(p) colors to p and returns the
    39  	// updated palette suitable for converting m to a paletted image.
    40  	Quantize(p color.Palette, m image.Image) color.Palette
    41  }
    42  
    43  // Op is a Porter-Duff compositing operator.
    44  type Op int
    45  
    46  const (
    47  	// Over specifies ``(src in mask) over dst''.
    48  	Over Op = iota
    49  	// Src specifies ``src in mask''.
    50  	Src
    51  )
    52  
    53  // Draw implements the Drawer interface by calling the Draw function with this
    54  // Op.
    55  func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
    56  	DrawMask(dst, r, src, sp, nil, image.Point{}, op)
    57  }
    58  
    59  // Drawer contains the Draw method.
    60  type Drawer interface {
    61  	// Draw aligns r.Min in dst with sp in src and then replaces the
    62  	// rectangle r in dst with the result of drawing src on dst.
    63  	Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
    64  }
    65  
    66  // FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error
    67  // diffusion.
    68  var FloydSteinberg Drawer = floydSteinberg{}
    69  
    70  type floydSteinberg struct{}
    71  
    72  func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
    73  	clip(dst, &r, src, &sp, nil, nil)
    74  	if r.Empty() {
    75  		return
    76  	}
    77  	drawPaletted(dst, r, src, sp, true)
    78  }
    79  
    80  // clip clips r against each image's bounds (after translating into the
    81  // destination image's coordinate space) and shifts the points sp and mp by
    82  // the same amount as the change in r.Min.
    83  func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
    84  	orig := r.Min
    85  	*r = r.Intersect(dst.Bounds())
    86  	*r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
    87  	if mask != nil {
    88  		*r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
    89  	}
    90  	dx := r.Min.X - orig.X
    91  	dy := r.Min.Y - orig.Y
    92  	if dx == 0 && dy == 0 {
    93  		return
    94  	}
    95  	sp.X += dx
    96  	sp.Y += dy
    97  	if mp != nil {
    98  		mp.X += dx
    99  		mp.Y += dy
   100  	}
   101  }
   102  
   103  func processBackward(dst image.Image, r image.Rectangle, src image.Image, sp image.Point) bool {
   104  	return dst == src &&
   105  		r.Overlaps(r.Add(sp.Sub(r.Min))) &&
   106  		(sp.Y < r.Min.Y || (sp.Y == r.Min.Y && sp.X < r.Min.X))
   107  }
   108  
   109  // Draw calls DrawMask with a nil mask.
   110  func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
   111  	DrawMask(dst, r, src, sp, nil, image.Point{}, op)
   112  }
   113  
   114  // DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
   115  // in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
   116  func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
   117  	clip(dst, &r, src, &sp, mask, &mp)
   118  	if r.Empty() {
   119  		return
   120  	}
   121  
   122  	// Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
   123  	switch dst0 := dst.(type) {
   124  	case *image.RGBA:
   125  		if op == Over {
   126  			if mask == nil {
   127  				switch src0 := src.(type) {
   128  				case *image.Uniform:
   129  					sr, sg, sb, sa := src0.RGBA()
   130  					if sa == 0xffff {
   131  						drawFillSrc(dst0, r, sr, sg, sb, sa)
   132  					} else {
   133  						drawFillOver(dst0, r, sr, sg, sb, sa)
   134  					}
   135  					return
   136  				case *image.RGBA:
   137  					drawCopyOver(dst0, r, src0, sp)
   138  					return
   139  				case *image.NRGBA:
   140  					drawNRGBAOver(dst0, r, src0, sp)
   141  					return
   142  				case *image.YCbCr:
   143  					// An image.YCbCr is always fully opaque, and so if the
   144  					// mask is nil (i.e. fully opaque) then the op is
   145  					// effectively always Src. Similarly for image.Gray and
   146  					// image.CMYK.
   147  					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
   148  						return
   149  					}
   150  				case *image.Gray:
   151  					drawGray(dst0, r, src0, sp)
   152  					return
   153  				case *image.CMYK:
   154  					drawCMYK(dst0, r, src0, sp)
   155  					return
   156  				}
   157  			} else if mask0, ok := mask.(*image.Alpha); ok {
   158  				switch src0 := src.(type) {
   159  				case *image.Uniform:
   160  					drawGlyphOver(dst0, r, src0, mask0, mp)
   161  					return
   162  				}
   163  			}
   164  		} else {
   165  			if mask == nil {
   166  				switch src0 := src.(type) {
   167  				case *image.Uniform:
   168  					sr, sg, sb, sa := src0.RGBA()
   169  					drawFillSrc(dst0, r, sr, sg, sb, sa)
   170  					return
   171  				case *image.RGBA:
   172  					drawCopySrc(dst0, r, src0, sp)
   173  					return
   174  				case *image.NRGBA:
   175  					drawNRGBASrc(dst0, r, src0, sp)
   176  					return
   177  				case *image.YCbCr:
   178  					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
   179  						return
   180  					}
   181  				case *image.Gray:
   182  					drawGray(dst0, r, src0, sp)
   183  					return
   184  				case *image.CMYK:
   185  					drawCMYK(dst0, r, src0, sp)
   186  					return
   187  				}
   188  			}
   189  		}
   190  		drawRGBA(dst0, r, src, sp, mask, mp, op)
   191  		return
   192  	case *image.Paletted:
   193  		if op == Src && mask == nil {
   194  			if src0, ok := src.(*image.Uniform); ok {
   195  				colorIndex := uint8(dst0.Palette.Index(src0.C))
   196  				i0 := dst0.PixOffset(r.Min.X, r.Min.Y)
   197  				i1 := i0 + r.Dx()
   198  				for i := i0; i < i1; i++ {
   199  					dst0.Pix[i] = colorIndex
   200  				}
   201  				firstRow := dst0.Pix[i0:i1]
   202  				for y := r.Min.Y + 1; y < r.Max.Y; y++ {
   203  					i0 += dst0.Stride
   204  					i1 += dst0.Stride
   205  					copy(dst0.Pix[i0:i1], firstRow)
   206  				}
   207  				return
   208  			} else if !processBackward(dst, r, src, sp) {
   209  				drawPaletted(dst0, r, src, sp, false)
   210  				return
   211  			}
   212  		}
   213  	}
   214  
   215  	x0, x1, dx := r.Min.X, r.Max.X, 1
   216  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   217  	if processBackward(dst, r, src, sp) {
   218  		x0, x1, dx = x1-1, x0-1, -1
   219  		y0, y1, dy = y1-1, y0-1, -1
   220  	}
   221  
   222  	var out color.RGBA64
   223  	sy := sp.Y + y0 - r.Min.Y
   224  	my := mp.Y + y0 - r.Min.Y
   225  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   226  		sx := sp.X + x0 - r.Min.X
   227  		mx := mp.X + x0 - r.Min.X
   228  		for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
   229  			ma := uint32(m)
   230  			if mask != nil {
   231  				_, _, _, ma = mask.At(mx, my).RGBA()
   232  			}
   233  			switch {
   234  			case ma == 0:
   235  				if op == Over {
   236  					// No-op.
   237  				} else {
   238  					dst.Set(x, y, color.Transparent)
   239  				}
   240  			case ma == m && op == Src:
   241  				dst.Set(x, y, src.At(sx, sy))
   242  			default:
   243  				sr, sg, sb, sa := src.At(sx, sy).RGBA()
   244  				if op == Over {
   245  					dr, dg, db, da := dst.At(x, y).RGBA()
   246  					a := m - (sa * ma / m)
   247  					out.R = uint16((dr*a + sr*ma) / m)
   248  					out.G = uint16((dg*a + sg*ma) / m)
   249  					out.B = uint16((db*a + sb*ma) / m)
   250  					out.A = uint16((da*a + sa*ma) / m)
   251  				} else {
   252  					out.R = uint16(sr * ma / m)
   253  					out.G = uint16(sg * ma / m)
   254  					out.B = uint16(sb * ma / m)
   255  					out.A = uint16(sa * ma / m)
   256  				}
   257  				// The third argument is &out instead of out (and out is
   258  				// declared outside of the inner loop) to avoid the implicit
   259  				// conversion to color.Color here allocating memory in the
   260  				// inner loop if sizeof(color.RGBA64) > sizeof(uintptr).
   261  				dst.Set(x, y, &out)
   262  			}
   263  		}
   264  	}
   265  }
   266  
   267  func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
   268  	// The 0x101 is here for the same reason as in drawRGBA.
   269  	a := (m - sa) * 0x101
   270  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   271  	i1 := i0 + r.Dx()*4
   272  	for y := r.Min.Y; y != r.Max.Y; y++ {
   273  		for i := i0; i < i1; i += 4 {
   274  			dr := &dst.Pix[i+0]
   275  			dg := &dst.Pix[i+1]
   276  			db := &dst.Pix[i+2]
   277  			da := &dst.Pix[i+3]
   278  
   279  			*dr = uint8((uint32(*dr)*a/m + sr) >> 8)
   280  			*dg = uint8((uint32(*dg)*a/m + sg) >> 8)
   281  			*db = uint8((uint32(*db)*a/m + sb) >> 8)
   282  			*da = uint8((uint32(*da)*a/m + sa) >> 8)
   283  		}
   284  		i0 += dst.Stride
   285  		i1 += dst.Stride
   286  	}
   287  }
   288  
   289  func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
   290  	sr8 := uint8(sr >> 8)
   291  	sg8 := uint8(sg >> 8)
   292  	sb8 := uint8(sb >> 8)
   293  	sa8 := uint8(sa >> 8)
   294  	// The built-in copy function is faster than a straightforward for loop to fill the destination with
   295  	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
   296  	// then use the first row as the slice source for the remaining rows.
   297  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   298  	i1 := i0 + r.Dx()*4
   299  	for i := i0; i < i1; i += 4 {
   300  		dst.Pix[i+0] = sr8
   301  		dst.Pix[i+1] = sg8
   302  		dst.Pix[i+2] = sb8
   303  		dst.Pix[i+3] = sa8
   304  	}
   305  	firstRow := dst.Pix[i0:i1]
   306  	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
   307  		i0 += dst.Stride
   308  		i1 += dst.Stride
   309  		copy(dst.Pix[i0:i1], firstRow)
   310  	}
   311  }
   312  
   313  func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   314  	dx, dy := r.Dx(), r.Dy()
   315  	d0 := dst.PixOffset(r.Min.X, r.Min.Y)
   316  	s0 := src.PixOffset(sp.X, sp.Y)
   317  	var (
   318  		ddelta, sdelta int
   319  		i0, i1, idelta int
   320  	)
   321  	if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
   322  		ddelta = dst.Stride
   323  		sdelta = src.Stride
   324  		i0, i1, idelta = 0, dx*4, +4
   325  	} else {
   326  		// If the source start point is higher than the destination start point, or equal height but to the left,
   327  		// then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
   328  		d0 += (dy - 1) * dst.Stride
   329  		s0 += (dy - 1) * src.Stride
   330  		ddelta = -dst.Stride
   331  		sdelta = -src.Stride
   332  		i0, i1, idelta = (dx-1)*4, -4, -4
   333  	}
   334  	for ; dy > 0; dy-- {
   335  		dpix := dst.Pix[d0:]
   336  		spix := src.Pix[s0:]
   337  		for i := i0; i != i1; i += idelta {
   338  			s := spix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   339  			sr := uint32(s[0]) * 0x101
   340  			sg := uint32(s[1]) * 0x101
   341  			sb := uint32(s[2]) * 0x101
   342  			sa := uint32(s[3]) * 0x101
   343  
   344  			// The 0x101 is here for the same reason as in drawRGBA.
   345  			a := (m - sa) * 0x101
   346  
   347  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   348  			d[0] = uint8((uint32(d[0])*a/m + sr) >> 8)
   349  			d[1] = uint8((uint32(d[1])*a/m + sg) >> 8)
   350  			d[2] = uint8((uint32(d[2])*a/m + sb) >> 8)
   351  			d[3] = uint8((uint32(d[3])*a/m + sa) >> 8)
   352  		}
   353  		d0 += ddelta
   354  		s0 += sdelta
   355  	}
   356  }
   357  
   358  func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   359  	n, dy := 4*r.Dx(), r.Dy()
   360  	d0 := dst.PixOffset(r.Min.X, r.Min.Y)
   361  	s0 := src.PixOffset(sp.X, sp.Y)
   362  	var ddelta, sdelta int
   363  	if r.Min.Y <= sp.Y {
   364  		ddelta = dst.Stride
   365  		sdelta = src.Stride
   366  	} else {
   367  		// If the source start point is higher than the destination start
   368  		// point, then we compose the rows in bottom-up order instead of
   369  		// top-down. Unlike the drawCopyOver function, we don't have to check
   370  		// the x coordinates because the built-in copy function can handle
   371  		// overlapping slices.
   372  		d0 += (dy - 1) * dst.Stride
   373  		s0 += (dy - 1) * src.Stride
   374  		ddelta = -dst.Stride
   375  		sdelta = -src.Stride
   376  	}
   377  	for ; dy > 0; dy-- {
   378  		copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
   379  		d0 += ddelta
   380  		s0 += sdelta
   381  	}
   382  }
   383  
   384  func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
   385  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   386  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   387  	si0 := (sp.X - src.Rect.Min.X) * 4
   388  	yMax := r.Max.Y - dst.Rect.Min.Y
   389  
   390  	y := r.Min.Y - dst.Rect.Min.Y
   391  	sy := sp.Y - src.Rect.Min.Y
   392  	for ; y != yMax; y, sy = y+1, sy+1 {
   393  		dpix := dst.Pix[y*dst.Stride:]
   394  		spix := src.Pix[sy*src.Stride:]
   395  
   396  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   397  			// Convert from non-premultiplied color to pre-multiplied color.
   398  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   399  			sa := uint32(s[3]) * 0x101
   400  			sr := uint32(s[0]) * sa / 0xff
   401  			sg := uint32(s[1]) * sa / 0xff
   402  			sb := uint32(s[2]) * sa / 0xff
   403  
   404  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   405  			dr := uint32(d[0])
   406  			dg := uint32(d[1])
   407  			db := uint32(d[2])
   408  			da := uint32(d[3])
   409  
   410  			// The 0x101 is here for the same reason as in drawRGBA.
   411  			a := (m - sa) * 0x101
   412  
   413  			d[0] = uint8((dr*a/m + sr) >> 8)
   414  			d[1] = uint8((dg*a/m + sg) >> 8)
   415  			d[2] = uint8((db*a/m + sb) >> 8)
   416  			d[3] = uint8((da*a/m + sa) >> 8)
   417  		}
   418  	}
   419  }
   420  
   421  func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
   422  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   423  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   424  	si0 := (sp.X - src.Rect.Min.X) * 4
   425  	yMax := r.Max.Y - dst.Rect.Min.Y
   426  
   427  	y := r.Min.Y - dst.Rect.Min.Y
   428  	sy := sp.Y - src.Rect.Min.Y
   429  	for ; y != yMax; y, sy = y+1, sy+1 {
   430  		dpix := dst.Pix[y*dst.Stride:]
   431  		spix := src.Pix[sy*src.Stride:]
   432  
   433  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   434  			// Convert from non-premultiplied color to pre-multiplied color.
   435  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   436  			sa := uint32(s[3]) * 0x101
   437  			sr := uint32(s[0]) * sa / 0xff
   438  			sg := uint32(s[1]) * sa / 0xff
   439  			sb := uint32(s[2]) * sa / 0xff
   440  
   441  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   442  			d[0] = uint8(sr >> 8)
   443  			d[1] = uint8(sg >> 8)
   444  			d[2] = uint8(sb >> 8)
   445  			d[3] = uint8(sa >> 8)
   446  		}
   447  	}
   448  }
   449  
   450  func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
   451  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   452  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   453  	si0 := (sp.X - src.Rect.Min.X) * 1
   454  	yMax := r.Max.Y - dst.Rect.Min.Y
   455  
   456  	y := r.Min.Y - dst.Rect.Min.Y
   457  	sy := sp.Y - src.Rect.Min.Y
   458  	for ; y != yMax; y, sy = y+1, sy+1 {
   459  		dpix := dst.Pix[y*dst.Stride:]
   460  		spix := src.Pix[sy*src.Stride:]
   461  
   462  		for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
   463  			p := spix[si]
   464  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   465  			d[0] = p
   466  			d[1] = p
   467  			d[2] = p
   468  			d[3] = 255
   469  		}
   470  	}
   471  }
   472  
   473  func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
   474  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   475  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   476  	si0 := (sp.X - src.Rect.Min.X) * 4
   477  	yMax := r.Max.Y - dst.Rect.Min.Y
   478  
   479  	y := r.Min.Y - dst.Rect.Min.Y
   480  	sy := sp.Y - src.Rect.Min.Y
   481  	for ; y != yMax; y, sy = y+1, sy+1 {
   482  		dpix := dst.Pix[y*dst.Stride:]
   483  		spix := src.Pix[sy*src.Stride:]
   484  
   485  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   486  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   487  			d := dpix[i : i+4 : i+4]
   488  			d[0], d[1], d[2] = color.CMYKToRGB(s[0], s[1], s[2], s[3])
   489  			d[3] = 255
   490  		}
   491  	}
   492  }
   493  
   494  func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
   495  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   496  	i1 := i0 + r.Dx()*4
   497  	mi0 := mask.PixOffset(mp.X, mp.Y)
   498  	sr, sg, sb, sa := src.RGBA()
   499  	for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
   500  		for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
   501  			ma := uint32(mask.Pix[mi])
   502  			if ma == 0 {
   503  				continue
   504  			}
   505  			ma |= ma << 8
   506  
   507  			// The 0x101 is here for the same reason as in drawRGBA.
   508  			a := (m - (sa * ma / m)) * 0x101
   509  
   510  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   511  			d[0] = uint8((uint32(d[0])*a + sr*ma) / m >> 8)
   512  			d[1] = uint8((uint32(d[1])*a + sg*ma) / m >> 8)
   513  			d[2] = uint8((uint32(d[2])*a + sb*ma) / m >> 8)
   514  			d[3] = uint8((uint32(d[3])*a + sa*ma) / m >> 8)
   515  		}
   516  		i0 += dst.Stride
   517  		i1 += dst.Stride
   518  		mi0 += mask.Stride
   519  	}
   520  }
   521  
   522  func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
   523  	x0, x1, dx := r.Min.X, r.Max.X, 1
   524  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   525  	if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
   526  		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   527  			x0, x1, dx = x1-1, x0-1, -1
   528  			y0, y1, dy = y1-1, y0-1, -1
   529  		}
   530  	}
   531  
   532  	sy := sp.Y + y0 - r.Min.Y
   533  	my := mp.Y + y0 - r.Min.Y
   534  	sx0 := sp.X + x0 - r.Min.X
   535  	mx0 := mp.X + x0 - r.Min.X
   536  	sx1 := sx0 + (x1 - x0)
   537  	i0 := dst.PixOffset(x0, y0)
   538  	di := dx * 4
   539  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   540  		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   541  			ma := uint32(m)
   542  			if mask != nil {
   543  				_, _, _, ma = mask.At(mx, my).RGBA()
   544  			}
   545  			sr, sg, sb, sa := src.At(sx, sy).RGBA()
   546  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   547  			if op == Over {
   548  				dr := uint32(d[0])
   549  				dg := uint32(d[1])
   550  				db := uint32(d[2])
   551  				da := uint32(d[3])
   552  
   553  				// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   554  				// We work in 16-bit color, and so would normally do:
   555  				// dr |= dr << 8
   556  				// and similarly for dg, db and da, but instead we multiply a
   557  				// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   558  				// This yields the same result, but is fewer arithmetic operations.
   559  				a := (m - (sa * ma / m)) * 0x101
   560  
   561  				d[0] = uint8((dr*a + sr*ma) / m >> 8)
   562  				d[1] = uint8((dg*a + sg*ma) / m >> 8)
   563  				d[2] = uint8((db*a + sb*ma) / m >> 8)
   564  				d[3] = uint8((da*a + sa*ma) / m >> 8)
   565  
   566  			} else {
   567  				d[0] = uint8(sr * ma / m >> 8)
   568  				d[1] = uint8(sg * ma / m >> 8)
   569  				d[2] = uint8(sb * ma / m >> 8)
   570  				d[3] = uint8(sa * ma / m >> 8)
   571  			}
   572  		}
   573  		i0 += dy * dst.Stride
   574  	}
   575  }
   576  
   577  // clamp clamps i to the interval [0, 0xffff].
   578  func clamp(i int32) int32 {
   579  	if i < 0 {
   580  		return 0
   581  	}
   582  	if i > 0xffff {
   583  		return 0xffff
   584  	}
   585  	return i
   586  }
   587  
   588  // sqDiff returns the squared-difference of x and y, shifted by 2 so that
   589  // adding four of those won't overflow a uint32.
   590  //
   591  // x and y are both assumed to be in the range [0, 0xffff].
   592  func sqDiff(x, y int32) uint32 {
   593  	// This is an optimized code relying on the overflow/wrap around
   594  	// properties of unsigned integers operations guaranteed by the language
   595  	// spec. See sqDiff from the image/color package for more details.
   596  	d := uint32(x - y)
   597  	return (d * d) >> 2
   598  }
   599  
   600  func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
   601  	// TODO(nigeltao): handle the case where the dst and src overlap.
   602  	// Does it even make sense to try and do Floyd-Steinberg whilst
   603  	// walking the image backward (right-to-left bottom-to-top)?
   604  
   605  	// If dst is an *image.Paletted, we have a fast path for dst.Set and
   606  	// dst.At. The dst.Set equivalent is a batch version of the algorithm
   607  	// used by color.Palette's Index method in image/color/color.go, plus
   608  	// optional Floyd-Steinberg error diffusion.
   609  	palette, pix, stride := [][4]int32(nil), []byte(nil), 0
   610  	if p, ok := dst.(*image.Paletted); ok {
   611  		palette = make([][4]int32, len(p.Palette))
   612  		for i, col := range p.Palette {
   613  			r, g, b, a := col.RGBA()
   614  			palette[i][0] = int32(r)
   615  			palette[i][1] = int32(g)
   616  			palette[i][2] = int32(b)
   617  			palette[i][3] = int32(a)
   618  		}
   619  		pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
   620  	}
   621  
   622  	// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
   623  	// errors that have been propagated to the pixels in the current and next
   624  	// rows. The +2 simplifies calculation near the edges.
   625  	var quantErrorCurr, quantErrorNext [][4]int32
   626  	if floydSteinberg {
   627  		quantErrorCurr = make([][4]int32, r.Dx()+2)
   628  		quantErrorNext = make([][4]int32, r.Dx()+2)
   629  	}
   630  	pxRGBA := func(x, y int) (r, g, b, a uint32) { return src.At(x, y).RGBA() }
   631  	// Fast paths for special cases to avoid excessive use of the color.Color
   632  	// interface which escapes to the heap but need to be discovered for
   633  	// each pixel on r. See also https://golang.org/issues/15759.
   634  	switch src0 := src.(type) {
   635  	case *image.RGBA:
   636  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.RGBAAt(x, y).RGBA() }
   637  	case *image.NRGBA:
   638  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.NRGBAAt(x, y).RGBA() }
   639  	case *image.YCbCr:
   640  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.YCbCrAt(x, y).RGBA() }
   641  	}
   642  
   643  	// Loop over each source pixel.
   644  	out := color.RGBA64{A: 0xffff}
   645  	for y := 0; y != r.Dy(); y++ {
   646  		for x := 0; x != r.Dx(); x++ {
   647  			// er, eg and eb are the pixel's R,G,B values plus the
   648  			// optional Floyd-Steinberg error.
   649  			sr, sg, sb, sa := pxRGBA(sp.X+x, sp.Y+y)
   650  			er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
   651  			if floydSteinberg {
   652  				er = clamp(er + quantErrorCurr[x+1][0]/16)
   653  				eg = clamp(eg + quantErrorCurr[x+1][1]/16)
   654  				eb = clamp(eb + quantErrorCurr[x+1][2]/16)
   655  				ea = clamp(ea + quantErrorCurr[x+1][3]/16)
   656  			}
   657  
   658  			if palette != nil {
   659  				// Find the closest palette color in Euclidean R,G,B,A space:
   660  				// the one that minimizes sum-squared-difference.
   661  				// TODO(nigeltao): consider smarter algorithms.
   662  				bestIndex, bestSum := 0, uint32(1<<32-1)
   663  				for index, p := range palette {
   664  					sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
   665  					if sum < bestSum {
   666  						bestIndex, bestSum = index, sum
   667  						if sum == 0 {
   668  							break
   669  						}
   670  					}
   671  				}
   672  				pix[y*stride+x] = byte(bestIndex)
   673  
   674  				if !floydSteinberg {
   675  					continue
   676  				}
   677  				er -= palette[bestIndex][0]
   678  				eg -= palette[bestIndex][1]
   679  				eb -= palette[bestIndex][2]
   680  				ea -= palette[bestIndex][3]
   681  
   682  			} else {
   683  				out.R = uint16(er)
   684  				out.G = uint16(eg)
   685  				out.B = uint16(eb)
   686  				out.A = uint16(ea)
   687  				// The third argument is &out instead of out (and out is
   688  				// declared outside of the inner loop) to avoid the implicit
   689  				// conversion to color.Color here allocating memory in the
   690  				// inner loop if sizeof(color.RGBA64) > sizeof(uintptr).
   691  				dst.Set(r.Min.X+x, r.Min.Y+y, &out)
   692  
   693  				if !floydSteinberg {
   694  					continue
   695  				}
   696  				sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
   697  				er -= int32(sr)
   698  				eg -= int32(sg)
   699  				eb -= int32(sb)
   700  				ea -= int32(sa)
   701  			}
   702  
   703  			// Propagate the Floyd-Steinberg quantization error.
   704  			quantErrorNext[x+0][0] += er * 3
   705  			quantErrorNext[x+0][1] += eg * 3
   706  			quantErrorNext[x+0][2] += eb * 3
   707  			quantErrorNext[x+0][3] += ea * 3
   708  			quantErrorNext[x+1][0] += er * 5
   709  			quantErrorNext[x+1][1] += eg * 5
   710  			quantErrorNext[x+1][2] += eb * 5
   711  			quantErrorNext[x+1][3] += ea * 5
   712  			quantErrorNext[x+2][0] += er * 1
   713  			quantErrorNext[x+2][1] += eg * 1
   714  			quantErrorNext[x+2][2] += eb * 1
   715  			quantErrorNext[x+2][3] += ea * 1
   716  			quantErrorCurr[x+2][0] += er * 7
   717  			quantErrorCurr[x+2][1] += eg * 7
   718  			quantErrorCurr[x+2][2] += eb * 7
   719  			quantErrorCurr[x+2][3] += ea * 7
   720  		}
   721  
   722  		// Recycle the quantization error buffers.
   723  		if floydSteinberg {
   724  			quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
   725  			for i := range quantErrorNext {
   726  				quantErrorNext[i] = [4]int32{}
   727  			}
   728  		}
   729  	}
   730  }
   731  

View as plain text