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
9package draw
10
11import (
12	"image"
13	"image/color"
14	"image/internal/imageutil"
15)
16
17// m is the maximum color value returned by image.Color.RGBA.
18const m = 1<<16 - 1
19
20// Image is an image.Image with a Set method to change a single pixel.
21type 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.
30type 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.
37type 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.
44type Op int
45
46const (
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].
55func (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.
60type 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.
68var FloydSteinberg Drawer = floydSteinberg{}
69
70type floydSteinberg struct{}
71
72func (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.
83func 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
103func 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.
110func 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.
116func 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
389func 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
411func 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
435func 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).
483func 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
507func 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
544func 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
573func 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
596func 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
617func 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
645func 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
695func 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
749func 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
795func 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].
934func 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].
948func 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
956func 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