Source file src/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  // 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
   123  	// to general but slower implementations.
   124  	//
   125  	// For NRGBA and NRGBA64 image types, the code paths aren't just faster.
   126  	// They also avoid the information loss that would otherwise occur from
   127  	// converting non-alpha-premultiplied color to and from alpha-premultiplied
   128  	// color. See TestDrawSrcNonpremultiplied.
   129  	switch dst0 := dst.(type) {
   130  	case *image.RGBA:
   131  		if op == Over {
   132  			if mask == nil {
   133  				switch src0 := src.(type) {
   134  				case *image.Uniform:
   135  					sr, sg, sb, sa := src0.RGBA()
   136  					if sa == 0xffff {
   137  						drawFillSrc(dst0, r, sr, sg, sb, sa)
   138  					} else {
   139  						drawFillOver(dst0, r, sr, sg, sb, sa)
   140  					}
   141  					return
   142  				case *image.RGBA:
   143  					drawCopyOver(dst0, r, src0, sp)
   144  					return
   145  				case *image.NRGBA:
   146  					drawNRGBAOver(dst0, r, src0, sp)
   147  					return
   148  				case *image.YCbCr:
   149  					// An image.YCbCr is always fully opaque, and so if the
   150  					// mask is nil (i.e. fully opaque) then the op is
   151  					// effectively always Src. Similarly for image.Gray and
   152  					// image.CMYK.
   153  					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
   154  						return
   155  					}
   156  				case *image.Gray:
   157  					drawGray(dst0, r, src0, sp)
   158  					return
   159  				case *image.CMYK:
   160  					drawCMYK(dst0, r, src0, sp)
   161  					return
   162  				}
   163  			} else if mask0, ok := mask.(*image.Alpha); ok {
   164  				switch src0 := src.(type) {
   165  				case *image.Uniform:
   166  					drawGlyphOver(dst0, r, src0, mask0, mp)
   167  					return
   168  				case *image.RGBA:
   169  					drawRGBAMaskOver(dst0, r, src0, sp, mask0, mp)
   170  					return
   171  				case *image.Gray:
   172  					drawGrayMaskOver(dst0, r, src0, sp, mask0, mp)
   173  					return
   174  				// Case order matters. The next case (image.RGBA64Image) is an
   175  				// interface type that the concrete types above also implement.
   176  				case image.RGBA64Image:
   177  					drawRGBA64ImageMaskOver(dst0, r, src0, sp, mask0, mp)
   178  					return
   179  				}
   180  			}
   181  		} else {
   182  			if mask == nil {
   183  				switch src0 := src.(type) {
   184  				case *image.Uniform:
   185  					sr, sg, sb, sa := src0.RGBA()
   186  					drawFillSrc(dst0, r, sr, sg, sb, sa)
   187  					return
   188  				case *image.RGBA:
   189  					d0 := dst0.PixOffset(r.Min.X, r.Min.Y)
   190  					s0 := src0.PixOffset(sp.X, sp.Y)
   191  					drawCopySrc(
   192  						dst0.Pix[d0:], dst0.Stride, r, src0.Pix[s0:], src0.Stride, sp, 4*r.Dx())
   193  					return
   194  				case *image.NRGBA:
   195  					drawNRGBASrc(dst0, r, src0, sp)
   196  					return
   197  				case *image.YCbCr:
   198  					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
   199  						return
   200  					}
   201  				case *image.Gray:
   202  					drawGray(dst0, r, src0, sp)
   203  					return
   204  				case *image.CMYK:
   205  					drawCMYK(dst0, r, src0, sp)
   206  					return
   207  				}
   208  			}
   209  		}
   210  		drawRGBA(dst0, r, src, sp, mask, mp, op)
   211  		return
   212  	case *image.Paletted:
   213  		if op == Src && mask == nil {
   214  			if src0, ok := src.(*image.Uniform); ok {
   215  				colorIndex := uint8(dst0.Palette.Index(src0.C))
   216  				i0 := dst0.PixOffset(r.Min.X, r.Min.Y)
   217  				i1 := i0 + r.Dx()
   218  				for i := i0; i < i1; i++ {
   219  					dst0.Pix[i] = colorIndex
   220  				}
   221  				firstRow := dst0.Pix[i0:i1]
   222  				for y := r.Min.Y + 1; y < r.Max.Y; y++ {
   223  					i0 += dst0.Stride
   224  					i1 += dst0.Stride
   225  					copy(dst0.Pix[i0:i1], firstRow)
   226  				}
   227  				return
   228  			} else if !processBackward(dst, r, src, sp) {
   229  				drawPaletted(dst0, r, src, sp, false)
   230  				return
   231  			}
   232  		}
   233  	case *image.NRGBA:
   234  		if op == Src && mask == nil {
   235  			if src0, ok := src.(*image.NRGBA); ok {
   236  				d0 := dst0.PixOffset(r.Min.X, r.Min.Y)
   237  				s0 := src0.PixOffset(sp.X, sp.Y)
   238  				drawCopySrc(
   239  					dst0.Pix[d0:], dst0.Stride, r, src0.Pix[s0:], src0.Stride, sp, 4*r.Dx())
   240  				return
   241  			}
   242  		}
   243  	case *image.NRGBA64:
   244  		if op == Src && mask == nil {
   245  			if src0, ok := src.(*image.NRGBA64); ok {
   246  				d0 := dst0.PixOffset(r.Min.X, r.Min.Y)
   247  				s0 := src0.PixOffset(sp.X, sp.Y)
   248  				drawCopySrc(
   249  					dst0.Pix[d0:], dst0.Stride, r, src0.Pix[s0:], src0.Stride, sp, 8*r.Dx())
   250  				return
   251  			}
   252  		}
   253  	}
   254  
   255  	x0, x1, dx := r.Min.X, r.Max.X, 1
   256  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   257  	if processBackward(dst, r, src, sp) {
   258  		x0, x1, dx = x1-1, x0-1, -1
   259  		y0, y1, dy = y1-1, y0-1, -1
   260  	}
   261  
   262  	// FALLBACK1.17
   263  	//
   264  	// Try the draw.RGBA64Image and image.RGBA64Image interfaces, part of the
   265  	// standard library since Go 1.17. These are like the draw.Image and
   266  	// image.Image interfaces but they can avoid allocations from converting
   267  	// concrete color types to the color.Color interface type.
   268  
   269  	if dst0, _ := dst.(RGBA64Image); dst0 != nil {
   270  		if src0, _ := src.(image.RGBA64Image); src0 != nil {
   271  			if mask == nil {
   272  				sy := sp.Y + y0 - r.Min.Y
   273  				my := mp.Y + y0 - r.Min.Y
   274  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   275  					sx := sp.X + x0 - r.Min.X
   276  					mx := mp.X + x0 - r.Min.X
   277  					for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
   278  						if op == Src {
   279  							dst0.SetRGBA64(x, y, src0.RGBA64At(sx, sy))
   280  						} else {
   281  							srgba := src0.RGBA64At(sx, sy)
   282  							a := m - uint32(srgba.A)
   283  							drgba := dst0.RGBA64At(x, y)
   284  							dst0.SetRGBA64(x, y, color.RGBA64{
   285  								R: uint16((uint32(drgba.R)*a)/m) + srgba.R,
   286  								G: uint16((uint32(drgba.G)*a)/m) + srgba.G,
   287  								B: uint16((uint32(drgba.B)*a)/m) + srgba.B,
   288  								A: uint16((uint32(drgba.A)*a)/m) + srgba.A,
   289  							})
   290  						}
   291  					}
   292  				}
   293  				return
   294  
   295  			} else if mask0, _ := mask.(image.RGBA64Image); mask0 != nil {
   296  				sy := sp.Y + y0 - r.Min.Y
   297  				my := mp.Y + y0 - r.Min.Y
   298  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   299  					sx := sp.X + x0 - r.Min.X
   300  					mx := mp.X + x0 - r.Min.X
   301  					for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
   302  						ma := uint32(mask0.RGBA64At(mx, my).A)
   303  						switch {
   304  						case ma == 0:
   305  							if op == Over {
   306  								// No-op.
   307  							} else {
   308  								dst0.SetRGBA64(x, y, color.RGBA64{})
   309  							}
   310  						case ma == m && op == Src:
   311  							dst0.SetRGBA64(x, y, src0.RGBA64At(sx, sy))
   312  						default:
   313  							srgba := src0.RGBA64At(sx, sy)
   314  							if op == Over {
   315  								drgba := dst0.RGBA64At(x, y)
   316  								a := m - (uint32(srgba.A) * ma / m)
   317  								dst0.SetRGBA64(x, y, color.RGBA64{
   318  									R: uint16((uint32(drgba.R)*a + uint32(srgba.R)*ma) / m),
   319  									G: uint16((uint32(drgba.G)*a + uint32(srgba.G)*ma) / m),
   320  									B: uint16((uint32(drgba.B)*a + uint32(srgba.B)*ma) / m),
   321  									A: uint16((uint32(drgba.A)*a + uint32(srgba.A)*ma) / m),
   322  								})
   323  							} else {
   324  								dst0.SetRGBA64(x, y, color.RGBA64{
   325  									R: uint16(uint32(srgba.R) * ma / m),
   326  									G: uint16(uint32(srgba.G) * ma / m),
   327  									B: uint16(uint32(srgba.B) * ma / m),
   328  									A: uint16(uint32(srgba.A) * ma / m),
   329  								})
   330  							}
   331  						}
   332  					}
   333  				}
   334  				return
   335  			}
   336  		}
   337  	}
   338  
   339  	// FALLBACK1.0
   340  	//
   341  	// If none of the faster code paths above apply, use the draw.Image and
   342  	// image.Image interfaces, part of the standard library since Go 1.0.
   343  
   344  	var out color.RGBA64
   345  	sy := sp.Y + y0 - r.Min.Y
   346  	my := mp.Y + y0 - r.Min.Y
   347  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   348  		sx := sp.X + x0 - r.Min.X
   349  		mx := mp.X + x0 - r.Min.X
   350  		for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
   351  			ma := uint32(m)
   352  			if mask != nil {
   353  				_, _, _, ma = mask.At(mx, my).RGBA()
   354  			}
   355  			switch {
   356  			case ma == 0:
   357  				if op == Over {
   358  					// No-op.
   359  				} else {
   360  					dst.Set(x, y, color.Transparent)
   361  				}
   362  			case ma == m && op == Src:
   363  				dst.Set(x, y, src.At(sx, sy))
   364  			default:
   365  				sr, sg, sb, sa := src.At(sx, sy).RGBA()
   366  				if op == Over {
   367  					dr, dg, db, da := dst.At(x, y).RGBA()
   368  					a := m - (sa * ma / m)
   369  					out.R = uint16((dr*a + sr*ma) / m)
   370  					out.G = uint16((dg*a + sg*ma) / m)
   371  					out.B = uint16((db*a + sb*ma) / m)
   372  					out.A = uint16((da*a + sa*ma) / m)
   373  				} else {
   374  					out.R = uint16(sr * ma / m)
   375  					out.G = uint16(sg * ma / m)
   376  					out.B = uint16(sb * ma / m)
   377  					out.A = uint16(sa * ma / m)
   378  				}
   379  				// The third argument is &out instead of out (and out is
   380  				// declared outside of the inner loop) to avoid the implicit
   381  				// conversion to color.Color here allocating memory in the
   382  				// inner loop if sizeof(color.RGBA64) > sizeof(uintptr).
   383  				dst.Set(x, y, &out)
   384  			}
   385  		}
   386  	}
   387  }
   388  
   389  func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
   390  	// The 0x101 is here for the same reason as in drawRGBA.
   391  	a := (m - sa) * 0x101
   392  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   393  	i1 := i0 + r.Dx()*4
   394  	for y := r.Min.Y; y != r.Max.Y; y++ {
   395  		for i := i0; i < i1; i += 4 {
   396  			dr := &dst.Pix[i+0]
   397  			dg := &dst.Pix[i+1]
   398  			db := &dst.Pix[i+2]
   399  			da := &dst.Pix[i+3]
   400  
   401  			*dr = uint8((uint32(*dr)*a/m + sr) >> 8)
   402  			*dg = uint8((uint32(*dg)*a/m + sg) >> 8)
   403  			*db = uint8((uint32(*db)*a/m + sb) >> 8)
   404  			*da = uint8((uint32(*da)*a/m + sa) >> 8)
   405  		}
   406  		i0 += dst.Stride
   407  		i1 += dst.Stride
   408  	}
   409  }
   410  
   411  func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
   412  	sr8 := uint8(sr >> 8)
   413  	sg8 := uint8(sg >> 8)
   414  	sb8 := uint8(sb >> 8)
   415  	sa8 := uint8(sa >> 8)
   416  	// The built-in copy function is faster than a straightforward for loop to fill the destination with
   417  	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
   418  	// then use the first row as the slice source for the remaining rows.
   419  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   420  	i1 := i0 + r.Dx()*4
   421  	for i := i0; i < i1; i += 4 {
   422  		dst.Pix[i+0] = sr8
   423  		dst.Pix[i+1] = sg8
   424  		dst.Pix[i+2] = sb8
   425  		dst.Pix[i+3] = sa8
   426  	}
   427  	firstRow := dst.Pix[i0:i1]
   428  	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
   429  		i0 += dst.Stride
   430  		i1 += dst.Stride
   431  		copy(dst.Pix[i0:i1], firstRow)
   432  	}
   433  }
   434  
   435  func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
   436  	dx, dy := r.Dx(), r.Dy()
   437  	d0 := dst.PixOffset(r.Min.X, r.Min.Y)
   438  	s0 := src.PixOffset(sp.X, sp.Y)
   439  	var (
   440  		ddelta, sdelta int
   441  		i0, i1, idelta int
   442  	)
   443  	if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
   444  		ddelta = dst.Stride
   445  		sdelta = src.Stride
   446  		i0, i1, idelta = 0, dx*4, +4
   447  	} else {
   448  		// If the source start point is higher than the destination start point, or equal height but to the left,
   449  		// then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
   450  		d0 += (dy - 1) * dst.Stride
   451  		s0 += (dy - 1) * src.Stride
   452  		ddelta = -dst.Stride
   453  		sdelta = -src.Stride
   454  		i0, i1, idelta = (dx-1)*4, -4, -4
   455  	}
   456  	for ; dy > 0; dy-- {
   457  		dpix := dst.Pix[d0:]
   458  		spix := src.Pix[s0:]
   459  		for i := i0; i != i1; i += idelta {
   460  			s := spix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   461  			sr := uint32(s[0]) * 0x101
   462  			sg := uint32(s[1]) * 0x101
   463  			sb := uint32(s[2]) * 0x101
   464  			sa := uint32(s[3]) * 0x101
   465  
   466  			// The 0x101 is here for the same reason as in drawRGBA.
   467  			a := (m - sa) * 0x101
   468  
   469  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   470  			d[0] = uint8((uint32(d[0])*a/m + sr) >> 8)
   471  			d[1] = uint8((uint32(d[1])*a/m + sg) >> 8)
   472  			d[2] = uint8((uint32(d[2])*a/m + sb) >> 8)
   473  			d[3] = uint8((uint32(d[3])*a/m + sa) >> 8)
   474  		}
   475  		d0 += ddelta
   476  		s0 += sdelta
   477  	}
   478  }
   479  
   480  // drawCopySrc copies bytes to dstPix from srcPix. These arguments roughly
   481  // correspond to the Pix fields of the image package's concrete image.Image
   482  // implementations, but are offset (dstPix is dst.Pix[dpOffset:] not dst.Pix).
   483  func drawCopySrc(
   484  	dstPix []byte, dstStride int, r image.Rectangle,
   485  	srcPix []byte, srcStride int, sp image.Point,
   486  	bytesPerRow int) {
   487  
   488  	d0, s0, ddelta, sdelta, dy := 0, 0, dstStride, srcStride, r.Dy()
   489  	if r.Min.Y > sp.Y {
   490  		// If the source start point is higher than the destination start
   491  		// point, then we compose the rows in bottom-up order instead of
   492  		// top-down. Unlike the drawCopyOver function, we don't have to check
   493  		// the x coordinates because the built-in copy function can handle
   494  		// overlapping slices.
   495  		d0 = (dy - 1) * dstStride
   496  		s0 = (dy - 1) * srcStride
   497  		ddelta = -dstStride
   498  		sdelta = -srcStride
   499  	}
   500  	for ; dy > 0; dy-- {
   501  		copy(dstPix[d0:d0+bytesPerRow], srcPix[s0:s0+bytesPerRow])
   502  		d0 += ddelta
   503  		s0 += sdelta
   504  	}
   505  }
   506  
   507  func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
   508  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   509  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   510  	si0 := (sp.X - src.Rect.Min.X) * 4
   511  	yMax := r.Max.Y - dst.Rect.Min.Y
   512  
   513  	y := r.Min.Y - dst.Rect.Min.Y
   514  	sy := sp.Y - src.Rect.Min.Y
   515  	for ; y != yMax; y, sy = y+1, sy+1 {
   516  		dpix := dst.Pix[y*dst.Stride:]
   517  		spix := src.Pix[sy*src.Stride:]
   518  
   519  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   520  			// Convert from non-premultiplied color to pre-multiplied color.
   521  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   522  			sa := uint32(s[3]) * 0x101
   523  			sr := uint32(s[0]) * sa / 0xff
   524  			sg := uint32(s[1]) * sa / 0xff
   525  			sb := uint32(s[2]) * sa / 0xff
   526  
   527  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   528  			dr := uint32(d[0])
   529  			dg := uint32(d[1])
   530  			db := uint32(d[2])
   531  			da := uint32(d[3])
   532  
   533  			// The 0x101 is here for the same reason as in drawRGBA.
   534  			a := (m - sa) * 0x101
   535  
   536  			d[0] = uint8((dr*a/m + sr) >> 8)
   537  			d[1] = uint8((dg*a/m + sg) >> 8)
   538  			d[2] = uint8((db*a/m + sb) >> 8)
   539  			d[3] = uint8((da*a/m + sa) >> 8)
   540  		}
   541  	}
   542  }
   543  
   544  func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
   545  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   546  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   547  	si0 := (sp.X - src.Rect.Min.X) * 4
   548  	yMax := r.Max.Y - dst.Rect.Min.Y
   549  
   550  	y := r.Min.Y - dst.Rect.Min.Y
   551  	sy := sp.Y - src.Rect.Min.Y
   552  	for ; y != yMax; y, sy = y+1, sy+1 {
   553  		dpix := dst.Pix[y*dst.Stride:]
   554  		spix := src.Pix[sy*src.Stride:]
   555  
   556  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   557  			// Convert from non-premultiplied color to pre-multiplied color.
   558  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   559  			sa := uint32(s[3]) * 0x101
   560  			sr := uint32(s[0]) * sa / 0xff
   561  			sg := uint32(s[1]) * sa / 0xff
   562  			sb := uint32(s[2]) * sa / 0xff
   563  
   564  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   565  			d[0] = uint8(sr >> 8)
   566  			d[1] = uint8(sg >> 8)
   567  			d[2] = uint8(sb >> 8)
   568  			d[3] = uint8(sa >> 8)
   569  		}
   570  	}
   571  }
   572  
   573  func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
   574  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   575  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   576  	si0 := (sp.X - src.Rect.Min.X) * 1
   577  	yMax := r.Max.Y - dst.Rect.Min.Y
   578  
   579  	y := r.Min.Y - dst.Rect.Min.Y
   580  	sy := sp.Y - src.Rect.Min.Y
   581  	for ; y != yMax; y, sy = y+1, sy+1 {
   582  		dpix := dst.Pix[y*dst.Stride:]
   583  		spix := src.Pix[sy*src.Stride:]
   584  
   585  		for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
   586  			p := spix[si]
   587  			d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   588  			d[0] = p
   589  			d[1] = p
   590  			d[2] = p
   591  			d[3] = 255
   592  		}
   593  	}
   594  }
   595  
   596  func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
   597  	i0 := (r.Min.X - dst.Rect.Min.X) * 4
   598  	i1 := (r.Max.X - dst.Rect.Min.X) * 4
   599  	si0 := (sp.X - src.Rect.Min.X) * 4
   600  	yMax := r.Max.Y - dst.Rect.Min.Y
   601  
   602  	y := r.Min.Y - dst.Rect.Min.Y
   603  	sy := sp.Y - src.Rect.Min.Y
   604  	for ; y != yMax; y, sy = y+1, sy+1 {
   605  		dpix := dst.Pix[y*dst.Stride:]
   606  		spix := src.Pix[sy*src.Stride:]
   607  
   608  		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
   609  			s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
   610  			d := dpix[i : i+4 : i+4]
   611  			d[0], d[1], d[2] = color.CMYKToRGB(s[0], s[1], s[2], s[3])
   612  			d[3] = 255
   613  		}
   614  	}
   615  }
   616  
   617  func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
   618  	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
   619  	i1 := i0 + r.Dx()*4
   620  	mi0 := mask.PixOffset(mp.X, mp.Y)
   621  	sr, sg, sb, sa := src.RGBA()
   622  	for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
   623  		for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
   624  			ma := uint32(mask.Pix[mi])
   625  			if ma == 0 {
   626  				continue
   627  			}
   628  			ma |= ma << 8
   629  
   630  			// The 0x101 is here for the same reason as in drawRGBA.
   631  			a := (m - (sa * ma / m)) * 0x101
   632  
   633  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   634  			d[0] = uint8((uint32(d[0])*a + sr*ma) / m >> 8)
   635  			d[1] = uint8((uint32(d[1])*a + sg*ma) / m >> 8)
   636  			d[2] = uint8((uint32(d[2])*a + sb*ma) / m >> 8)
   637  			d[3] = uint8((uint32(d[3])*a + sa*ma) / m >> 8)
   638  		}
   639  		i0 += dst.Stride
   640  		i1 += dst.Stride
   641  		mi0 += mask.Stride
   642  	}
   643  }
   644  
   645  func drawGrayMaskOver(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point, mask *image.Alpha, mp image.Point) {
   646  	x0, x1, dx := r.Min.X, r.Max.X, 1
   647  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   648  	if r.Overlaps(r.Add(sp.Sub(r.Min))) {
   649  		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   650  			x0, x1, dx = x1-1, x0-1, -1
   651  			y0, y1, dy = y1-1, y0-1, -1
   652  		}
   653  	}
   654  
   655  	sy := sp.Y + y0 - r.Min.Y
   656  	my := mp.Y + y0 - r.Min.Y
   657  	sx0 := sp.X + x0 - r.Min.X
   658  	mx0 := mp.X + x0 - r.Min.X
   659  	sx1 := sx0 + (x1 - x0)
   660  	i0 := dst.PixOffset(x0, y0)
   661  	di := dx * 4
   662  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   663  		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   664  			mi := mask.PixOffset(mx, my)
   665  			ma := uint32(mask.Pix[mi])
   666  			ma |= ma << 8
   667  			si := src.PixOffset(sx, sy)
   668  			sy := uint32(src.Pix[si])
   669  			sy |= sy << 8
   670  			sa := uint32(0xffff)
   671  
   672  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   673  			dr := uint32(d[0])
   674  			dg := uint32(d[1])
   675  			db := uint32(d[2])
   676  			da := uint32(d[3])
   677  
   678  			// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   679  			// We work in 16-bit color, and so would normally do:
   680  			// dr |= dr << 8
   681  			// and similarly for dg, db and da, but instead we multiply a
   682  			// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   683  			// This yields the same result, but is fewer arithmetic operations.
   684  			a := (m - (sa * ma / m)) * 0x101
   685  
   686  			d[0] = uint8((dr*a + sy*ma) / m >> 8)
   687  			d[1] = uint8((dg*a + sy*ma) / m >> 8)
   688  			d[2] = uint8((db*a + sy*ma) / m >> 8)
   689  			d[3] = uint8((da*a + sa*ma) / m >> 8)
   690  		}
   691  		i0 += dy * dst.Stride
   692  	}
   693  }
   694  
   695  func drawRGBAMaskOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point, mask *image.Alpha, mp image.Point) {
   696  	x0, x1, dx := r.Min.X, r.Max.X, 1
   697  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   698  	if dst == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
   699  		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   700  			x0, x1, dx = x1-1, x0-1, -1
   701  			y0, y1, dy = y1-1, y0-1, -1
   702  		}
   703  	}
   704  
   705  	sy := sp.Y + y0 - r.Min.Y
   706  	my := mp.Y + y0 - r.Min.Y
   707  	sx0 := sp.X + x0 - r.Min.X
   708  	mx0 := mp.X + x0 - r.Min.X
   709  	sx1 := sx0 + (x1 - x0)
   710  	i0 := dst.PixOffset(x0, y0)
   711  	di := dx * 4
   712  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   713  		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   714  			mi := mask.PixOffset(mx, my)
   715  			ma := uint32(mask.Pix[mi])
   716  			ma |= ma << 8
   717  			si := src.PixOffset(sx, sy)
   718  			sr := uint32(src.Pix[si+0])
   719  			sg := uint32(src.Pix[si+1])
   720  			sb := uint32(src.Pix[si+2])
   721  			sa := uint32(src.Pix[si+3])
   722  			sr |= sr << 8
   723  			sg |= sg << 8
   724  			sb |= sb << 8
   725  			sa |= sa << 8
   726  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   727  			dr := uint32(d[0])
   728  			dg := uint32(d[1])
   729  			db := uint32(d[2])
   730  			da := uint32(d[3])
   731  
   732  			// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   733  			// We work in 16-bit color, and so would normally do:
   734  			// dr |= dr << 8
   735  			// and similarly for dg, db and da, but instead we multiply a
   736  			// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   737  			// This yields the same result, but is fewer arithmetic operations.
   738  			a := (m - (sa * ma / m)) * 0x101
   739  
   740  			d[0] = uint8((dr*a + sr*ma) / m >> 8)
   741  			d[1] = uint8((dg*a + sg*ma) / m >> 8)
   742  			d[2] = uint8((db*a + sb*ma) / m >> 8)
   743  			d[3] = uint8((da*a + sa*ma) / m >> 8)
   744  		}
   745  		i0 += dy * dst.Stride
   746  	}
   747  }
   748  
   749  func drawRGBA64ImageMaskOver(dst *image.RGBA, r image.Rectangle, src image.RGBA64Image, sp image.Point, mask *image.Alpha, mp image.Point) {
   750  	x0, x1, dx := r.Min.X, r.Max.X, 1
   751  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   752  	if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
   753  		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   754  			x0, x1, dx = x1-1, x0-1, -1
   755  			y0, y1, dy = y1-1, y0-1, -1
   756  		}
   757  	}
   758  
   759  	sy := sp.Y + y0 - r.Min.Y
   760  	my := mp.Y + y0 - r.Min.Y
   761  	sx0 := sp.X + x0 - r.Min.X
   762  	mx0 := mp.X + x0 - r.Min.X
   763  	sx1 := sx0 + (x1 - x0)
   764  	i0 := dst.PixOffset(x0, y0)
   765  	di := dx * 4
   766  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   767  		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   768  			mi := mask.PixOffset(mx, my)
   769  			ma := uint32(mask.Pix[mi])
   770  			ma |= ma << 8
   771  			srgba := src.RGBA64At(sx, sy)
   772  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   773  			dr := uint32(d[0])
   774  			dg := uint32(d[1])
   775  			db := uint32(d[2])
   776  			da := uint32(d[3])
   777  
   778  			// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   779  			// We work in 16-bit color, and so would normally do:
   780  			// dr |= dr << 8
   781  			// and similarly for dg, db and da, but instead we multiply a
   782  			// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   783  			// This yields the same result, but is fewer arithmetic operations.
   784  			a := (m - (uint32(srgba.A) * ma / m)) * 0x101
   785  
   786  			d[0] = uint8((dr*a + uint32(srgba.R)*ma) / m >> 8)
   787  			d[1] = uint8((dg*a + uint32(srgba.G)*ma) / m >> 8)
   788  			d[2] = uint8((db*a + uint32(srgba.B)*ma) / m >> 8)
   789  			d[3] = uint8((da*a + uint32(srgba.A)*ma) / m >> 8)
   790  		}
   791  		i0 += dy * dst.Stride
   792  	}
   793  }
   794  
   795  func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
   796  	x0, x1, dx := r.Min.X, r.Max.X, 1
   797  	y0, y1, dy := r.Min.Y, r.Max.Y, 1
   798  	if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
   799  		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
   800  			x0, x1, dx = x1-1, x0-1, -1
   801  			y0, y1, dy = y1-1, y0-1, -1
   802  		}
   803  	}
   804  
   805  	sy := sp.Y + y0 - r.Min.Y
   806  	my := mp.Y + y0 - r.Min.Y
   807  	sx0 := sp.X + x0 - r.Min.X
   808  	mx0 := mp.X + x0 - r.Min.X
   809  	sx1 := sx0 + (x1 - x0)
   810  	i0 := dst.PixOffset(x0, y0)
   811  	di := dx * 4
   812  
   813  	// Try the image.RGBA64Image interface, part of the standard library since
   814  	// Go 1.17.
   815  	//
   816  	// This optimization is similar to how FALLBACK1.17 optimizes FALLBACK1.0
   817  	// in DrawMask, except here the concrete type of dst is known to be
   818  	// *image.RGBA.
   819  	if src0, _ := src.(image.RGBA64Image); src0 != nil {
   820  		if mask == nil {
   821  			if op == Over {
   822  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   823  					for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   824  						srgba := src0.RGBA64At(sx, sy)
   825  						d := dst.Pix[i : i+4 : i+4]
   826  						dr := uint32(d[0])
   827  						dg := uint32(d[1])
   828  						db := uint32(d[2])
   829  						da := uint32(d[3])
   830  						a := (m - uint32(srgba.A)) * 0x101
   831  						d[0] = uint8((dr*a/m + uint32(srgba.R)) >> 8)
   832  						d[1] = uint8((dg*a/m + uint32(srgba.G)) >> 8)
   833  						d[2] = uint8((db*a/m + uint32(srgba.B)) >> 8)
   834  						d[3] = uint8((da*a/m + uint32(srgba.A)) >> 8)
   835  					}
   836  					i0 += dy * dst.Stride
   837  				}
   838  			} else {
   839  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   840  					for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   841  						srgba := src0.RGBA64At(sx, sy)
   842  						d := dst.Pix[i : i+4 : i+4]
   843  						d[0] = uint8(srgba.R >> 8)
   844  						d[1] = uint8(srgba.G >> 8)
   845  						d[2] = uint8(srgba.B >> 8)
   846  						d[3] = uint8(srgba.A >> 8)
   847  					}
   848  					i0 += dy * dst.Stride
   849  				}
   850  			}
   851  			return
   852  
   853  		} else if mask0, _ := mask.(image.RGBA64Image); mask0 != nil {
   854  			if op == Over {
   855  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   856  					for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   857  						ma := uint32(mask0.RGBA64At(mx, my).A)
   858  						srgba := src0.RGBA64At(sx, sy)
   859  						d := dst.Pix[i : i+4 : i+4]
   860  						dr := uint32(d[0])
   861  						dg := uint32(d[1])
   862  						db := uint32(d[2])
   863  						da := uint32(d[3])
   864  						a := (m - (uint32(srgba.A) * ma / m)) * 0x101
   865  						d[0] = uint8((dr*a + uint32(srgba.R)*ma) / m >> 8)
   866  						d[1] = uint8((dg*a + uint32(srgba.G)*ma) / m >> 8)
   867  						d[2] = uint8((db*a + uint32(srgba.B)*ma) / m >> 8)
   868  						d[3] = uint8((da*a + uint32(srgba.A)*ma) / m >> 8)
   869  					}
   870  					i0 += dy * dst.Stride
   871  				}
   872  			} else {
   873  				for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   874  					for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   875  						ma := uint32(mask0.RGBA64At(mx, my).A)
   876  						srgba := src0.RGBA64At(sx, sy)
   877  						d := dst.Pix[i : i+4 : i+4]
   878  						d[0] = uint8(uint32(srgba.R) * ma / m >> 8)
   879  						d[1] = uint8(uint32(srgba.G) * ma / m >> 8)
   880  						d[2] = uint8(uint32(srgba.B) * ma / m >> 8)
   881  						d[3] = uint8(uint32(srgba.A) * ma / m >> 8)
   882  					}
   883  					i0 += dy * dst.Stride
   884  				}
   885  			}
   886  			return
   887  		}
   888  	}
   889  
   890  	// Use the image.Image interface, part of the standard library since Go
   891  	// 1.0.
   892  	//
   893  	// This is similar to FALLBACK1.0 in DrawMask, except here the concrete
   894  	// type of dst is known to be *image.RGBA.
   895  	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
   896  		for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx {
   897  			ma := uint32(m)
   898  			if mask != nil {
   899  				_, _, _, ma = mask.At(mx, my).RGBA()
   900  			}
   901  			sr, sg, sb, sa := src.At(sx, sy).RGBA()
   902  			d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
   903  			if op == Over {
   904  				dr := uint32(d[0])
   905  				dg := uint32(d[1])
   906  				db := uint32(d[2])
   907  				da := uint32(d[3])
   908  
   909  				// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
   910  				// We work in 16-bit color, and so would normally do:
   911  				// dr |= dr << 8
   912  				// and similarly for dg, db and da, but instead we multiply a
   913  				// (which is a 16-bit color, ranging in [0,65535]) by 0x101.
   914  				// This yields the same result, but is fewer arithmetic operations.
   915  				a := (m - (sa * ma / m)) * 0x101
   916  
   917  				d[0] = uint8((dr*a + sr*ma) / m >> 8)
   918  				d[1] = uint8((dg*a + sg*ma) / m >> 8)
   919  				d[2] = uint8((db*a + sb*ma) / m >> 8)
   920  				d[3] = uint8((da*a + sa*ma) / m >> 8)
   921  
   922  			} else {
   923  				d[0] = uint8(sr * ma / m >> 8)
   924  				d[1] = uint8(sg * ma / m >> 8)
   925  				d[2] = uint8(sb * ma / m >> 8)
   926  				d[3] = uint8(sa * ma / m >> 8)
   927  			}
   928  		}
   929  		i0 += dy * dst.Stride
   930  	}
   931  }
   932  
   933  // clamp clamps i to the interval [0, 0xffff].
   934  func clamp(i int32) int32 {
   935  	if i < 0 {
   936  		return 0
   937  	}
   938  	if i > 0xffff {
   939  		return 0xffff
   940  	}
   941  	return i
   942  }
   943  
   944  // sqDiff returns the squared-difference of x and y, shifted by 2 so that
   945  // adding four of those won't overflow a uint32.
   946  //
   947  // x and y are both assumed to be in the range [0, 0xffff].
   948  func sqDiff(x, y int32) uint32 {
   949  	// This is an optimized code relying on the overflow/wrap around
   950  	// properties of unsigned integers operations guaranteed by the language
   951  	// spec. See sqDiff from the image/color package for more details.
   952  	d := uint32(x - y)
   953  	return (d * d) >> 2
   954  }
   955  
   956  func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
   957  	// TODO(nigeltao): handle the case where the dst and src overlap.
   958  	// Does it even make sense to try and do Floyd-Steinberg whilst
   959  	// walking the image backward (right-to-left bottom-to-top)?
   960  
   961  	// If dst is an *image.Paletted, we have a fast path for dst.Set and
   962  	// dst.At. The dst.Set equivalent is a batch version of the algorithm
   963  	// used by color.Palette's Index method in image/color/color.go, plus
   964  	// optional Floyd-Steinberg error diffusion.
   965  	palette, pix, stride := [][4]int32(nil), []byte(nil), 0
   966  	if p, ok := dst.(*image.Paletted); ok {
   967  		palette = make([][4]int32, len(p.Palette))
   968  		for i, col := range p.Palette {
   969  			r, g, b, a := col.RGBA()
   970  			palette[i][0] = int32(r)
   971  			palette[i][1] = int32(g)
   972  			palette[i][2] = int32(b)
   973  			palette[i][3] = int32(a)
   974  		}
   975  		pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
   976  	}
   977  
   978  	// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
   979  	// errors that have been propagated to the pixels in the current and next
   980  	// rows. The +2 simplifies calculation near the edges.
   981  	var quantErrorCurr, quantErrorNext [][4]int32
   982  	if floydSteinberg {
   983  		quantErrorCurr = make([][4]int32, r.Dx()+2)
   984  		quantErrorNext = make([][4]int32, r.Dx()+2)
   985  	}
   986  	pxRGBA := func(x, y int) (r, g, b, a uint32) { return src.At(x, y).RGBA() }
   987  	// Fast paths for special cases to avoid excessive use of the color.Color
   988  	// interface which escapes to the heap but need to be discovered for
   989  	// each pixel on r. See also https://golang.org/issues/15759.
   990  	switch src0 := src.(type) {
   991  	case *image.RGBA:
   992  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.RGBAAt(x, y).RGBA() }
   993  	case *image.NRGBA:
   994  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.NRGBAAt(x, y).RGBA() }
   995  	case *image.YCbCr:
   996  		pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.YCbCrAt(x, y).RGBA() }
   997  	}
   998  
   999  	// Loop over each source pixel.
  1000  	out := color.RGBA64{A: 0xffff}
  1001  	for y := 0; y != r.Dy(); y++ {
  1002  		for x := 0; x != r.Dx(); x++ {
  1003  			// er, eg and eb are the pixel's R,G,B values plus the
  1004  			// optional Floyd-Steinberg error.
  1005  			sr, sg, sb, sa := pxRGBA(sp.X+x, sp.Y+y)
  1006  			er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
  1007  			if floydSteinberg {
  1008  				er = clamp(er + quantErrorCurr[x+1][0]/16)
  1009  				eg = clamp(eg + quantErrorCurr[x+1][1]/16)
  1010  				eb = clamp(eb + quantErrorCurr[x+1][2]/16)
  1011  				ea = clamp(ea + quantErrorCurr[x+1][3]/16)
  1012  			}
  1013  
  1014  			if palette != nil {
  1015  				// Find the closest palette color in Euclidean R,G,B,A space:
  1016  				// the one that minimizes sum-squared-difference.
  1017  				// TODO(nigeltao): consider smarter algorithms.
  1018  				bestIndex, bestSum := 0, uint32(1<<32-1)
  1019  				for index, p := range palette {
  1020  					sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
  1021  					if sum < bestSum {
  1022  						bestIndex, bestSum = index, sum
  1023  						if sum == 0 {
  1024  							break
  1025  						}
  1026  					}
  1027  				}
  1028  				pix[y*stride+x] = byte(bestIndex)
  1029  
  1030  				if !floydSteinberg {
  1031  					continue
  1032  				}
  1033  				er -= palette[bestIndex][0]
  1034  				eg -= palette[bestIndex][1]
  1035  				eb -= palette[bestIndex][2]
  1036  				ea -= palette[bestIndex][3]
  1037  
  1038  			} else {
  1039  				out.R = uint16(er)
  1040  				out.G = uint16(eg)
  1041  				out.B = uint16(eb)
  1042  				out.A = uint16(ea)
  1043  				// The third argument is &out instead of out (and out is
  1044  				// declared outside of the inner loop) to avoid the implicit
  1045  				// conversion to color.Color here allocating memory in the
  1046  				// inner loop if sizeof(color.RGBA64) > sizeof(uintptr).
  1047  				dst.Set(r.Min.X+x, r.Min.Y+y, &out)
  1048  
  1049  				if !floydSteinberg {
  1050  					continue
  1051  				}
  1052  				sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
  1053  				er -= int32(sr)
  1054  				eg -= int32(sg)
  1055  				eb -= int32(sb)
  1056  				ea -= int32(sa)
  1057  			}
  1058  
  1059  			// Propagate the Floyd-Steinberg quantization error.
  1060  			quantErrorNext[x+0][0] += er * 3
  1061  			quantErrorNext[x+0][1] += eg * 3
  1062  			quantErrorNext[x+0][2] += eb * 3
  1063  			quantErrorNext[x+0][3] += ea * 3
  1064  			quantErrorNext[x+1][0] += er * 5
  1065  			quantErrorNext[x+1][1] += eg * 5
  1066  			quantErrorNext[x+1][2] += eb * 5
  1067  			quantErrorNext[x+1][3] += ea * 5
  1068  			quantErrorNext[x+2][0] += er * 1
  1069  			quantErrorNext[x+2][1] += eg * 1
  1070  			quantErrorNext[x+2][2] += eb * 1
  1071  			quantErrorNext[x+2][3] += ea * 1
  1072  			quantErrorCurr[x+2][0] += er * 7
  1073  			quantErrorCurr[x+2][1] += eg * 7
  1074  			quantErrorCurr[x+2][2] += eb * 7
  1075  			quantErrorCurr[x+2][3] += ea * 7
  1076  		}
  1077  
  1078  		// Recycle the quantization error buffers.
  1079  		if floydSteinberg {
  1080  			quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
  1081  			clear(quantErrorNext)
  1082  		}
  1083  	}
  1084  }
  1085  

View as plain text