1// generated by "go run gen.go". DO NOT EDIT.
2
3package draw
4
5import (
6	"image"
7	"image/color"
8	"math"
9
10	"golang.org/x/image/math/f64"
11)
12
13func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
14	// Try to simplify a Scale to a Copy when DstMask is not specified.
15	// If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow.
16	if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) {
17		Copy(dst, dr.Min, src, sr, op, opts)
18		return
19	}
20
21	var o Options
22	if opts != nil {
23		o = *opts
24	}
25
26	// adr is the affected destination pixels.
27	adr := dst.Bounds().Intersect(dr)
28	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
29	if adr.Empty() || sr.Empty() {
30		return
31	}
32	// Make adr relative to dr.Min.
33	adr = adr.Sub(dr.Min)
34	if op == Over && o.SrcMask == nil && opaque(src) {
35		op = Src
36	}
37
38	// sr is the source pixels. If it extends beyond the src bounds,
39	// we cannot use the type-specific fast paths, as they access
40	// the Pix fields directly without bounds checking.
41	//
42	// Similarly, the fast paths assume that the masks are nil.
43	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
44		switch op {
45		case Over:
46			z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
47		case Src:
48			z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
49		}
50	} else if _, ok := src.(*image.Uniform); ok {
51		Draw(dst, dr, src, src.Bounds().Min, op)
52	} else {
53		switch op {
54		case Over:
55			switch dst := dst.(type) {
56			case *image.RGBA:
57				switch src := src.(type) {
58				case *image.NRGBA:
59					z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
60				case *image.RGBA:
61					z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
62				default:
63					z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
64				}
65			default:
66				switch src := src.(type) {
67				default:
68					z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
69				}
70			}
71		case Src:
72			switch dst := dst.(type) {
73			case *image.RGBA:
74				switch src := src.(type) {
75				case *image.Gray:
76					z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
77				case *image.NRGBA:
78					z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
79				case *image.RGBA:
80					z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
81				case *image.YCbCr:
82					switch src.SubsampleRatio {
83					default:
84						z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
85					case image.YCbCrSubsampleRatio444:
86						z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
87					case image.YCbCrSubsampleRatio422:
88						z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
89					case image.YCbCrSubsampleRatio420:
90						z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
91					case image.YCbCrSubsampleRatio440:
92						z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
93					}
94				default:
95					z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
96				}
97			default:
98				switch src := src.(type) {
99				default:
100					z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
101				}
102			}
103		}
104	}
105}
106
107func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
108	// Try to simplify a Transform to a Copy.
109	if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
110		dx := int(s2d[2])
111		dy := int(s2d[5])
112		if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
113			Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
114			return
115		}
116	}
117
118	var o Options
119	if opts != nil {
120		o = *opts
121	}
122
123	dr := transformRect(&s2d, &sr)
124	// adr is the affected destination pixels.
125	adr := dst.Bounds().Intersect(dr)
126	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
127	if adr.Empty() || sr.Empty() {
128		return
129	}
130	if op == Over && o.SrcMask == nil && opaque(src) {
131		op = Src
132	}
133
134	d2s := invert(&s2d)
135	// bias is a translation of the mapping from dst coordinates to src
136	// coordinates such that the latter temporarily have non-negative X
137	// and Y coordinates. This allows us to write int(f) instead of
138	// int(math.Floor(f)), since "round to zero" and "round down" are
139	// equivalent when f >= 0, but the former is much cheaper. The X--
140	// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
141	// adjustment.
142	bias := transformRect(&d2s, &adr).Min
143	bias.X--
144	bias.Y--
145	d2s[2] -= float64(bias.X)
146	d2s[5] -= float64(bias.Y)
147	// Make adr relative to dr.Min.
148	adr = adr.Sub(dr.Min)
149	// sr is the source pixels. If it extends beyond the src bounds,
150	// we cannot use the type-specific fast paths, as they access
151	// the Pix fields directly without bounds checking.
152	//
153	// Similarly, the fast paths assume that the masks are nil.
154	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
155		switch op {
156		case Over:
157			z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
158		case Src:
159			z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
160		}
161	} else if u, ok := src.(*image.Uniform); ok {
162		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
163	} else {
164		switch op {
165		case Over:
166			switch dst := dst.(type) {
167			case *image.RGBA:
168				switch src := src.(type) {
169				case *image.NRGBA:
170					z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
171				case *image.RGBA:
172					z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
173				default:
174					z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
175				}
176			default:
177				switch src := src.(type) {
178				default:
179					z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
180				}
181			}
182		case Src:
183			switch dst := dst.(type) {
184			case *image.RGBA:
185				switch src := src.(type) {
186				case *image.Gray:
187					z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
188				case *image.NRGBA:
189					z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
190				case *image.RGBA:
191					z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
192				case *image.YCbCr:
193					switch src.SubsampleRatio {
194					default:
195						z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
196					case image.YCbCrSubsampleRatio444:
197						z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
198					case image.YCbCrSubsampleRatio422:
199						z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
200					case image.YCbCrSubsampleRatio420:
201						z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
202					case image.YCbCrSubsampleRatio440:
203						z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
204					}
205				default:
206					z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
207				}
208			default:
209				switch src := src.(type) {
210				default:
211					z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
212				}
213			}
214		}
215	}
216}
217
218func (nnInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
219	dw2 := uint64(dr.Dx()) * 2
220	dh2 := uint64(dr.Dy()) * 2
221	sw := uint64(sr.Dx())
222	sh := uint64(sr.Dy())
223	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
224		sy := (2*uint64(dy) + 1) * sh / dh2
225		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
226		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
227			sx := (2*uint64(dx) + 1) * sw / dw2
228			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx) - src.Rect.Min.X)
229			pr := uint32(src.Pix[pi]) * 0x101
230			out := uint8(pr >> 8)
231			dst.Pix[d+0] = out
232			dst.Pix[d+1] = out
233			dst.Pix[d+2] = out
234			dst.Pix[d+3] = 0xff
235		}
236	}
237}
238
239func (nnInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
240	dw2 := uint64(dr.Dx()) * 2
241	dh2 := uint64(dr.Dy()) * 2
242	sw := uint64(sr.Dx())
243	sh := uint64(sr.Dy())
244	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
245		sy := (2*uint64(dy) + 1) * sh / dh2
246		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
247		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
248			sx := (2*uint64(dx) + 1) * sw / dw2
249			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
250			pa := uint32(src.Pix[pi+3]) * 0x101
251			pr := uint32(src.Pix[pi+0]) * pa / 0xff
252			pg := uint32(src.Pix[pi+1]) * pa / 0xff
253			pb := uint32(src.Pix[pi+2]) * pa / 0xff
254			pa1 := (0xffff - pa) * 0x101
255			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
256			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
257			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
258			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
259		}
260	}
261}
262
263func (nnInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
264	dw2 := uint64(dr.Dx()) * 2
265	dh2 := uint64(dr.Dy()) * 2
266	sw := uint64(sr.Dx())
267	sh := uint64(sr.Dy())
268	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
269		sy := (2*uint64(dy) + 1) * sh / dh2
270		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
271		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
272			sx := (2*uint64(dx) + 1) * sw / dw2
273			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
274			pa := uint32(src.Pix[pi+3]) * 0x101
275			pr := uint32(src.Pix[pi+0]) * pa / 0xff
276			pg := uint32(src.Pix[pi+1]) * pa / 0xff
277			pb := uint32(src.Pix[pi+2]) * pa / 0xff
278			dst.Pix[d+0] = uint8(pr >> 8)
279			dst.Pix[d+1] = uint8(pg >> 8)
280			dst.Pix[d+2] = uint8(pb >> 8)
281			dst.Pix[d+3] = uint8(pa >> 8)
282		}
283	}
284}
285
286func (nnInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
287	dw2 := uint64(dr.Dx()) * 2
288	dh2 := uint64(dr.Dy()) * 2
289	sw := uint64(sr.Dx())
290	sh := uint64(sr.Dy())
291	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
292		sy := (2*uint64(dy) + 1) * sh / dh2
293		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
294		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
295			sx := (2*uint64(dx) + 1) * sw / dw2
296			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
297			pr := uint32(src.Pix[pi+0]) * 0x101
298			pg := uint32(src.Pix[pi+1]) * 0x101
299			pb := uint32(src.Pix[pi+2]) * 0x101
300			pa := uint32(src.Pix[pi+3]) * 0x101
301			pa1 := (0xffff - pa) * 0x101
302			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
303			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
304			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
305			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
306		}
307	}
308}
309
310func (nnInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
311	dw2 := uint64(dr.Dx()) * 2
312	dh2 := uint64(dr.Dy()) * 2
313	sw := uint64(sr.Dx())
314	sh := uint64(sr.Dy())
315	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
316		sy := (2*uint64(dy) + 1) * sh / dh2
317		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
318		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
319			sx := (2*uint64(dx) + 1) * sw / dw2
320			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
321			pr := uint32(src.Pix[pi+0]) * 0x101
322			pg := uint32(src.Pix[pi+1]) * 0x101
323			pb := uint32(src.Pix[pi+2]) * 0x101
324			pa := uint32(src.Pix[pi+3]) * 0x101
325			dst.Pix[d+0] = uint8(pr >> 8)
326			dst.Pix[d+1] = uint8(pg >> 8)
327			dst.Pix[d+2] = uint8(pb >> 8)
328			dst.Pix[d+3] = uint8(pa >> 8)
329		}
330	}
331}
332
333func (nnInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
334	dw2 := uint64(dr.Dx()) * 2
335	dh2 := uint64(dr.Dy()) * 2
336	sw := uint64(sr.Dx())
337	sh := uint64(sr.Dy())
338	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
339		sy := (2*uint64(dy) + 1) * sh / dh2
340		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
341		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
342			sx := (2*uint64(dx) + 1) * sw / dw2
343			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
344			pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
345
346			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
347			pyy1 := int(src.Y[pi]) * 0x10101
348			pcb1 := int(src.Cb[pj]) - 128
349			pcr1 := int(src.Cr[pj]) - 128
350			pr := (pyy1 + 91881*pcr1) >> 8
351			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
352			pb := (pyy1 + 116130*pcb1) >> 8
353			if pr < 0 {
354				pr = 0
355			} else if pr > 0xffff {
356				pr = 0xffff
357			}
358			if pg < 0 {
359				pg = 0
360			} else if pg > 0xffff {
361				pg = 0xffff
362			}
363			if pb < 0 {
364				pb = 0
365			} else if pb > 0xffff {
366				pb = 0xffff
367			}
368			dst.Pix[d+0] = uint8(pr >> 8)
369			dst.Pix[d+1] = uint8(pg >> 8)
370			dst.Pix[d+2] = uint8(pb >> 8)
371			dst.Pix[d+3] = 0xff
372		}
373	}
374}
375
376func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
377	dw2 := uint64(dr.Dx()) * 2
378	dh2 := uint64(dr.Dy()) * 2
379	sw := uint64(sr.Dx())
380	sh := uint64(sr.Dy())
381	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
382		sy := (2*uint64(dy) + 1) * sh / dh2
383		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
384		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
385			sx := (2*uint64(dx) + 1) * sw / dw2
386			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
387			pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
388
389			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
390			pyy1 := int(src.Y[pi]) * 0x10101
391			pcb1 := int(src.Cb[pj]) - 128
392			pcr1 := int(src.Cr[pj]) - 128
393			pr := (pyy1 + 91881*pcr1) >> 8
394			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
395			pb := (pyy1 + 116130*pcb1) >> 8
396			if pr < 0 {
397				pr = 0
398			} else if pr > 0xffff {
399				pr = 0xffff
400			}
401			if pg < 0 {
402				pg = 0
403			} else if pg > 0xffff {
404				pg = 0xffff
405			}
406			if pb < 0 {
407				pb = 0
408			} else if pb > 0xffff {
409				pb = 0xffff
410			}
411			dst.Pix[d+0] = uint8(pr >> 8)
412			dst.Pix[d+1] = uint8(pg >> 8)
413			dst.Pix[d+2] = uint8(pb >> 8)
414			dst.Pix[d+3] = 0xff
415		}
416	}
417}
418
419func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
420	dw2 := uint64(dr.Dx()) * 2
421	dh2 := uint64(dr.Dy()) * 2
422	sw := uint64(sr.Dx())
423	sh := uint64(sr.Dy())
424	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
425		sy := (2*uint64(dy) + 1) * sh / dh2
426		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
427		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
428			sx := (2*uint64(dx) + 1) * sw / dw2
429			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
430			pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
431
432			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
433			pyy1 := int(src.Y[pi]) * 0x10101
434			pcb1 := int(src.Cb[pj]) - 128
435			pcr1 := int(src.Cr[pj]) - 128
436			pr := (pyy1 + 91881*pcr1) >> 8
437			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
438			pb := (pyy1 + 116130*pcb1) >> 8
439			if pr < 0 {
440				pr = 0
441			} else if pr > 0xffff {
442				pr = 0xffff
443			}
444			if pg < 0 {
445				pg = 0
446			} else if pg > 0xffff {
447				pg = 0xffff
448			}
449			if pb < 0 {
450				pb = 0
451			} else if pb > 0xffff {
452				pb = 0xffff
453			}
454			dst.Pix[d+0] = uint8(pr >> 8)
455			dst.Pix[d+1] = uint8(pg >> 8)
456			dst.Pix[d+2] = uint8(pb >> 8)
457			dst.Pix[d+3] = 0xff
458		}
459	}
460}
461
462func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
463	dw2 := uint64(dr.Dx()) * 2
464	dh2 := uint64(dr.Dy()) * 2
465	sw := uint64(sr.Dx())
466	sh := uint64(sr.Dy())
467	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
468		sy := (2*uint64(dy) + 1) * sh / dh2
469		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
470		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
471			sx := (2*uint64(dx) + 1) * sw / dw2
472			pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
473			pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
474
475			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
476			pyy1 := int(src.Y[pi]) * 0x10101
477			pcb1 := int(src.Cb[pj]) - 128
478			pcr1 := int(src.Cr[pj]) - 128
479			pr := (pyy1 + 91881*pcr1) >> 8
480			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
481			pb := (pyy1 + 116130*pcb1) >> 8
482			if pr < 0 {
483				pr = 0
484			} else if pr > 0xffff {
485				pr = 0xffff
486			}
487			if pg < 0 {
488				pg = 0
489			} else if pg > 0xffff {
490				pg = 0xffff
491			}
492			if pb < 0 {
493				pb = 0
494			} else if pb > 0xffff {
495				pb = 0xffff
496			}
497			dst.Pix[d+0] = uint8(pr >> 8)
498			dst.Pix[d+1] = uint8(pg >> 8)
499			dst.Pix[d+2] = uint8(pb >> 8)
500			dst.Pix[d+3] = 0xff
501		}
502	}
503}
504
505func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
506	dw2 := uint64(dr.Dx()) * 2
507	dh2 := uint64(dr.Dy()) * 2
508	sw := uint64(sr.Dx())
509	sh := uint64(sr.Dy())
510	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
511		sy := (2*uint64(dy) + 1) * sh / dh2
512		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
513		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
514			sx := (2*uint64(dx) + 1) * sw / dw2
515			pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
516			pa1 := (0xffff - pa) * 0x101
517			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
518			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
519			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
520			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
521		}
522	}
523}
524
525func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
526	dw2 := uint64(dr.Dx()) * 2
527	dh2 := uint64(dr.Dy()) * 2
528	sw := uint64(sr.Dx())
529	sh := uint64(sr.Dy())
530	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
531		sy := (2*uint64(dy) + 1) * sh / dh2
532		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
533		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
534			sx := (2*uint64(dx) + 1) * sw / dw2
535			pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
536			dst.Pix[d+0] = uint8(pr >> 8)
537			dst.Pix[d+1] = uint8(pg >> 8)
538			dst.Pix[d+2] = uint8(pb >> 8)
539			dst.Pix[d+3] = uint8(pa >> 8)
540		}
541	}
542}
543
544func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
545	dw2 := uint64(dr.Dx()) * 2
546	dh2 := uint64(dr.Dy()) * 2
547	sw := uint64(sr.Dx())
548	sh := uint64(sr.Dy())
549	srcMask, smp := opts.SrcMask, opts.SrcMaskP
550	dstMask, dmp := opts.DstMask, opts.DstMaskP
551	dstColorRGBA64 := &color.RGBA64{}
552	dstColor := color.Color(dstColorRGBA64)
553	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
554		sy := (2*uint64(dy) + 1) * sh / dh2
555		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
556			sx := (2*uint64(dx) + 1) * sw / dw2
557			pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
558			if srcMask != nil {
559				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
560				pr = pr * ma / 0xffff
561				pg = pg * ma / 0xffff
562				pb = pb * ma / 0xffff
563				pa = pa * ma / 0xffff
564			}
565			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
566			if dstMask != nil {
567				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
568				pr = pr * ma / 0xffff
569				pg = pg * ma / 0xffff
570				pb = pb * ma / 0xffff
571				pa = pa * ma / 0xffff
572			}
573			pa1 := 0xffff - pa
574			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
575			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
576			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
577			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
578			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
579		}
580	}
581}
582
583func (nnInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
584	dw2 := uint64(dr.Dx()) * 2
585	dh2 := uint64(dr.Dy()) * 2
586	sw := uint64(sr.Dx())
587	sh := uint64(sr.Dy())
588	srcMask, smp := opts.SrcMask, opts.SrcMaskP
589	dstMask, dmp := opts.DstMask, opts.DstMaskP
590	dstColorRGBA64 := &color.RGBA64{}
591	dstColor := color.Color(dstColorRGBA64)
592	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
593		sy := (2*uint64(dy) + 1) * sh / dh2
594		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
595			sx := (2*uint64(dx) + 1) * sw / dw2
596			pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
597			if srcMask != nil {
598				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
599				pr = pr * ma / 0xffff
600				pg = pg * ma / 0xffff
601				pb = pb * ma / 0xffff
602				pa = pa * ma / 0xffff
603			}
604			if dstMask != nil {
605				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
606				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
607				pr = pr * ma / 0xffff
608				pg = pg * ma / 0xffff
609				pb = pb * ma / 0xffff
610				pa = pa * ma / 0xffff
611				pa1 := 0xffff - ma
612				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
613				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
614				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
615				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
616				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
617			} else {
618				dstColorRGBA64.R = uint16(pr)
619				dstColorRGBA64.G = uint16(pg)
620				dstColorRGBA64.B = uint16(pb)
621				dstColorRGBA64.A = uint16(pa)
622				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
623			}
624		}
625	}
626}
627
628func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
629	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
630		dyf := float64(dr.Min.Y+int(dy)) + 0.5
631		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
632		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
633			dxf := float64(dr.Min.X+int(dx)) + 0.5
634			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
635			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
636			if !(image.Point{sx0, sy0}).In(sr) {
637				continue
638			}
639			pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
640			pr := uint32(src.Pix[pi]) * 0x101
641			out := uint8(pr >> 8)
642			dst.Pix[d+0] = out
643			dst.Pix[d+1] = out
644			dst.Pix[d+2] = out
645			dst.Pix[d+3] = 0xff
646		}
647	}
648}
649
650func (nnInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
651	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
652		dyf := float64(dr.Min.Y+int(dy)) + 0.5
653		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
654		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
655			dxf := float64(dr.Min.X+int(dx)) + 0.5
656			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
657			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
658			if !(image.Point{sx0, sy0}).In(sr) {
659				continue
660			}
661			pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
662			pa := uint32(src.Pix[pi+3]) * 0x101
663			pr := uint32(src.Pix[pi+0]) * pa / 0xff
664			pg := uint32(src.Pix[pi+1]) * pa / 0xff
665			pb := uint32(src.Pix[pi+2]) * pa / 0xff
666			pa1 := (0xffff - pa) * 0x101
667			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
668			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
669			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
670			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
671		}
672	}
673}
674
675func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
676	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
677		dyf := float64(dr.Min.Y+int(dy)) + 0.5
678		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
679		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
680			dxf := float64(dr.Min.X+int(dx)) + 0.5
681			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
682			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
683			if !(image.Point{sx0, sy0}).In(sr) {
684				continue
685			}
686			pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
687			pa := uint32(src.Pix[pi+3]) * 0x101
688			pr := uint32(src.Pix[pi+0]) * pa / 0xff
689			pg := uint32(src.Pix[pi+1]) * pa / 0xff
690			pb := uint32(src.Pix[pi+2]) * pa / 0xff
691			dst.Pix[d+0] = uint8(pr >> 8)
692			dst.Pix[d+1] = uint8(pg >> 8)
693			dst.Pix[d+2] = uint8(pb >> 8)
694			dst.Pix[d+3] = uint8(pa >> 8)
695		}
696	}
697}
698
699func (nnInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
700	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
701		dyf := float64(dr.Min.Y+int(dy)) + 0.5
702		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
703		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
704			dxf := float64(dr.Min.X+int(dx)) + 0.5
705			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
706			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
707			if !(image.Point{sx0, sy0}).In(sr) {
708				continue
709			}
710			pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
711			pr := uint32(src.Pix[pi+0]) * 0x101
712			pg := uint32(src.Pix[pi+1]) * 0x101
713			pb := uint32(src.Pix[pi+2]) * 0x101
714			pa := uint32(src.Pix[pi+3]) * 0x101
715			pa1 := (0xffff - pa) * 0x101
716			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
717			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
718			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
719			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
720		}
721	}
722}
723
724func (nnInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
725	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
726		dyf := float64(dr.Min.Y+int(dy)) + 0.5
727		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
728		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
729			dxf := float64(dr.Min.X+int(dx)) + 0.5
730			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
731			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
732			if !(image.Point{sx0, sy0}).In(sr) {
733				continue
734			}
735			pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
736			pr := uint32(src.Pix[pi+0]) * 0x101
737			pg := uint32(src.Pix[pi+1]) * 0x101
738			pb := uint32(src.Pix[pi+2]) * 0x101
739			pa := uint32(src.Pix[pi+3]) * 0x101
740			dst.Pix[d+0] = uint8(pr >> 8)
741			dst.Pix[d+1] = uint8(pg >> 8)
742			dst.Pix[d+2] = uint8(pb >> 8)
743			dst.Pix[d+3] = uint8(pa >> 8)
744		}
745	}
746}
747
748func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
749	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
750		dyf := float64(dr.Min.Y+int(dy)) + 0.5
751		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
752		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
753			dxf := float64(dr.Min.X+int(dx)) + 0.5
754			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
755			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
756			if !(image.Point{sx0, sy0}).In(sr) {
757				continue
758			}
759			pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
760			pj := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
761
762			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
763			pyy1 := int(src.Y[pi]) * 0x10101
764			pcb1 := int(src.Cb[pj]) - 128
765			pcr1 := int(src.Cr[pj]) - 128
766			pr := (pyy1 + 91881*pcr1) >> 8
767			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
768			pb := (pyy1 + 116130*pcb1) >> 8
769			if pr < 0 {
770				pr = 0
771			} else if pr > 0xffff {
772				pr = 0xffff
773			}
774			if pg < 0 {
775				pg = 0
776			} else if pg > 0xffff {
777				pg = 0xffff
778			}
779			if pb < 0 {
780				pb = 0
781			} else if pb > 0xffff {
782				pb = 0xffff
783			}
784			dst.Pix[d+0] = uint8(pr >> 8)
785			dst.Pix[d+1] = uint8(pg >> 8)
786			dst.Pix[d+2] = uint8(pb >> 8)
787			dst.Pix[d+3] = 0xff
788		}
789	}
790}
791
792func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
793	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
794		dyf := float64(dr.Min.Y+int(dy)) + 0.5
795		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
796		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
797			dxf := float64(dr.Min.X+int(dx)) + 0.5
798			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
799			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
800			if !(image.Point{sx0, sy0}).In(sr) {
801				continue
802			}
803			pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
804			pj := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
805
806			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
807			pyy1 := int(src.Y[pi]) * 0x10101
808			pcb1 := int(src.Cb[pj]) - 128
809			pcr1 := int(src.Cr[pj]) - 128
810			pr := (pyy1 + 91881*pcr1) >> 8
811			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
812			pb := (pyy1 + 116130*pcb1) >> 8
813			if pr < 0 {
814				pr = 0
815			} else if pr > 0xffff {
816				pr = 0xffff
817			}
818			if pg < 0 {
819				pg = 0
820			} else if pg > 0xffff {
821				pg = 0xffff
822			}
823			if pb < 0 {
824				pb = 0
825			} else if pb > 0xffff {
826				pb = 0xffff
827			}
828			dst.Pix[d+0] = uint8(pr >> 8)
829			dst.Pix[d+1] = uint8(pg >> 8)
830			dst.Pix[d+2] = uint8(pb >> 8)
831			dst.Pix[d+3] = 0xff
832		}
833	}
834}
835
836func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
837	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
838		dyf := float64(dr.Min.Y+int(dy)) + 0.5
839		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
840		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
841			dxf := float64(dr.Min.X+int(dx)) + 0.5
842			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
843			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
844			if !(image.Point{sx0, sy0}).In(sr) {
845				continue
846			}
847			pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
848			pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
849
850			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
851			pyy1 := int(src.Y[pi]) * 0x10101
852			pcb1 := int(src.Cb[pj]) - 128
853			pcr1 := int(src.Cr[pj]) - 128
854			pr := (pyy1 + 91881*pcr1) >> 8
855			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
856			pb := (pyy1 + 116130*pcb1) >> 8
857			if pr < 0 {
858				pr = 0
859			} else if pr > 0xffff {
860				pr = 0xffff
861			}
862			if pg < 0 {
863				pg = 0
864			} else if pg > 0xffff {
865				pg = 0xffff
866			}
867			if pb < 0 {
868				pb = 0
869			} else if pb > 0xffff {
870				pb = 0xffff
871			}
872			dst.Pix[d+0] = uint8(pr >> 8)
873			dst.Pix[d+1] = uint8(pg >> 8)
874			dst.Pix[d+2] = uint8(pb >> 8)
875			dst.Pix[d+3] = 0xff
876		}
877	}
878}
879
880func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
881	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
882		dyf := float64(dr.Min.Y+int(dy)) + 0.5
883		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
884		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
885			dxf := float64(dr.Min.X+int(dx)) + 0.5
886			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
887			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
888			if !(image.Point{sx0, sy0}).In(sr) {
889				continue
890			}
891			pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
892			pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
893
894			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
895			pyy1 := int(src.Y[pi]) * 0x10101
896			pcb1 := int(src.Cb[pj]) - 128
897			pcr1 := int(src.Cr[pj]) - 128
898			pr := (pyy1 + 91881*pcr1) >> 8
899			pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
900			pb := (pyy1 + 116130*pcb1) >> 8
901			if pr < 0 {
902				pr = 0
903			} else if pr > 0xffff {
904				pr = 0xffff
905			}
906			if pg < 0 {
907				pg = 0
908			} else if pg > 0xffff {
909				pg = 0xffff
910			}
911			if pb < 0 {
912				pb = 0
913			} else if pb > 0xffff {
914				pb = 0xffff
915			}
916			dst.Pix[d+0] = uint8(pr >> 8)
917			dst.Pix[d+1] = uint8(pg >> 8)
918			dst.Pix[d+2] = uint8(pb >> 8)
919			dst.Pix[d+3] = 0xff
920		}
921	}
922}
923
924func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
925	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
926		dyf := float64(dr.Min.Y+int(dy)) + 0.5
927		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
928		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
929			dxf := float64(dr.Min.X+int(dx)) + 0.5
930			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
931			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
932			if !(image.Point{sx0, sy0}).In(sr) {
933				continue
934			}
935			pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
936			pa1 := (0xffff - pa) * 0x101
937			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
938			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
939			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
940			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
941		}
942	}
943}
944
945func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
946	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
947		dyf := float64(dr.Min.Y+int(dy)) + 0.5
948		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
949		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
950			dxf := float64(dr.Min.X+int(dx)) + 0.5
951			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
952			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
953			if !(image.Point{sx0, sy0}).In(sr) {
954				continue
955			}
956			pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
957			dst.Pix[d+0] = uint8(pr >> 8)
958			dst.Pix[d+1] = uint8(pg >> 8)
959			dst.Pix[d+2] = uint8(pb >> 8)
960			dst.Pix[d+3] = uint8(pa >> 8)
961		}
962	}
963}
964
965func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
966	srcMask, smp := opts.SrcMask, opts.SrcMaskP
967	dstMask, dmp := opts.DstMask, opts.DstMaskP
968	dstColorRGBA64 := &color.RGBA64{}
969	dstColor := color.Color(dstColorRGBA64)
970	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
971		dyf := float64(dr.Min.Y+int(dy)) + 0.5
972		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
973			dxf := float64(dr.Min.X+int(dx)) + 0.5
974			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
975			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
976			if !(image.Point{sx0, sy0}).In(sr) {
977				continue
978			}
979			pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
980			if srcMask != nil {
981				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
982				pr = pr * ma / 0xffff
983				pg = pg * ma / 0xffff
984				pb = pb * ma / 0xffff
985				pa = pa * ma / 0xffff
986			}
987			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
988			if dstMask != nil {
989				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
990				pr = pr * ma / 0xffff
991				pg = pg * ma / 0xffff
992				pb = pb * ma / 0xffff
993				pa = pa * ma / 0xffff
994			}
995			pa1 := 0xffff - pa
996			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
997			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
998			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
999			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
1000			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
1001		}
1002	}
1003}
1004
1005func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
1006	srcMask, smp := opts.SrcMask, opts.SrcMaskP
1007	dstMask, dmp := opts.DstMask, opts.DstMaskP
1008	dstColorRGBA64 := &color.RGBA64{}
1009	dstColor := color.Color(dstColorRGBA64)
1010	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1011		dyf := float64(dr.Min.Y+int(dy)) + 0.5
1012		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
1013			dxf := float64(dr.Min.X+int(dx)) + 0.5
1014			sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
1015			sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
1016			if !(image.Point{sx0, sy0}).In(sr) {
1017				continue
1018			}
1019			pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
1020			if srcMask != nil {
1021				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
1022				pr = pr * ma / 0xffff
1023				pg = pg * ma / 0xffff
1024				pb = pb * ma / 0xffff
1025				pa = pa * ma / 0xffff
1026			}
1027			if dstMask != nil {
1028				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
1029				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
1030				pr = pr * ma / 0xffff
1031				pg = pg * ma / 0xffff
1032				pb = pb * ma / 0xffff
1033				pa = pa * ma / 0xffff
1034				pa1 := 0xffff - ma
1035				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
1036				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
1037				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
1038				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
1039				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
1040			} else {
1041				dstColorRGBA64.R = uint16(pr)
1042				dstColorRGBA64.G = uint16(pg)
1043				dstColorRGBA64.B = uint16(pb)
1044				dstColorRGBA64.A = uint16(pa)
1045				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
1046			}
1047		}
1048	}
1049}
1050
1051func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
1052	// Try to simplify a Scale to a Copy when DstMask is not specified.
1053	// If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow.
1054	if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) {
1055		Copy(dst, dr.Min, src, sr, op, opts)
1056		return
1057	}
1058
1059	var o Options
1060	if opts != nil {
1061		o = *opts
1062	}
1063
1064	// adr is the affected destination pixels.
1065	adr := dst.Bounds().Intersect(dr)
1066	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
1067	if adr.Empty() || sr.Empty() {
1068		return
1069	}
1070	// Make adr relative to dr.Min.
1071	adr = adr.Sub(dr.Min)
1072	if op == Over && o.SrcMask == nil && opaque(src) {
1073		op = Src
1074	}
1075
1076	// sr is the source pixels. If it extends beyond the src bounds,
1077	// we cannot use the type-specific fast paths, as they access
1078	// the Pix fields directly without bounds checking.
1079	//
1080	// Similarly, the fast paths assume that the masks are nil.
1081	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
1082		switch op {
1083		case Over:
1084			z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
1085		case Src:
1086			z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
1087		}
1088	} else if _, ok := src.(*image.Uniform); ok {
1089		Draw(dst, dr, src, src.Bounds().Min, op)
1090	} else {
1091		switch op {
1092		case Over:
1093			switch dst := dst.(type) {
1094			case *image.RGBA:
1095				switch src := src.(type) {
1096				case *image.NRGBA:
1097					z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
1098				case *image.RGBA:
1099					z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
1100				default:
1101					z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
1102				}
1103			default:
1104				switch src := src.(type) {
1105				default:
1106					z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
1107				}
1108			}
1109		case Src:
1110			switch dst := dst.(type) {
1111			case *image.RGBA:
1112				switch src := src.(type) {
1113				case *image.Gray:
1114					z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
1115				case *image.NRGBA:
1116					z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
1117				case *image.RGBA:
1118					z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
1119				case *image.YCbCr:
1120					switch src.SubsampleRatio {
1121					default:
1122						z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
1123					case image.YCbCrSubsampleRatio444:
1124						z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
1125					case image.YCbCrSubsampleRatio422:
1126						z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
1127					case image.YCbCrSubsampleRatio420:
1128						z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
1129					case image.YCbCrSubsampleRatio440:
1130						z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
1131					}
1132				default:
1133					z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
1134				}
1135			default:
1136				switch src := src.(type) {
1137				default:
1138					z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
1139				}
1140			}
1141		}
1142	}
1143}
1144
1145func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
1146	// Try to simplify a Transform to a Copy.
1147	if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
1148		dx := int(s2d[2])
1149		dy := int(s2d[5])
1150		if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
1151			Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
1152			return
1153		}
1154	}
1155
1156	var o Options
1157	if opts != nil {
1158		o = *opts
1159	}
1160
1161	dr := transformRect(&s2d, &sr)
1162	// adr is the affected destination pixels.
1163	adr := dst.Bounds().Intersect(dr)
1164	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
1165	if adr.Empty() || sr.Empty() {
1166		return
1167	}
1168	if op == Over && o.SrcMask == nil && opaque(src) {
1169		op = Src
1170	}
1171
1172	d2s := invert(&s2d)
1173	// bias is a translation of the mapping from dst coordinates to src
1174	// coordinates such that the latter temporarily have non-negative X
1175	// and Y coordinates. This allows us to write int(f) instead of
1176	// int(math.Floor(f)), since "round to zero" and "round down" are
1177	// equivalent when f >= 0, but the former is much cheaper. The X--
1178	// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
1179	// adjustment.
1180	bias := transformRect(&d2s, &adr).Min
1181	bias.X--
1182	bias.Y--
1183	d2s[2] -= float64(bias.X)
1184	d2s[5] -= float64(bias.Y)
1185	// Make adr relative to dr.Min.
1186	adr = adr.Sub(dr.Min)
1187	// sr is the source pixels. If it extends beyond the src bounds,
1188	// we cannot use the type-specific fast paths, as they access
1189	// the Pix fields directly without bounds checking.
1190	//
1191	// Similarly, the fast paths assume that the masks are nil.
1192	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
1193		switch op {
1194		case Over:
1195			z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
1196		case Src:
1197			z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1198		}
1199	} else if u, ok := src.(*image.Uniform); ok {
1200		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
1201	} else {
1202		switch op {
1203		case Over:
1204			switch dst := dst.(type) {
1205			case *image.RGBA:
1206				switch src := src.(type) {
1207				case *image.NRGBA:
1208					z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
1209				case *image.RGBA:
1210					z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
1211				default:
1212					z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
1213				}
1214			default:
1215				switch src := src.(type) {
1216				default:
1217					z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
1218				}
1219			}
1220		case Src:
1221			switch dst := dst.(type) {
1222			case *image.RGBA:
1223				switch src := src.(type) {
1224				case *image.Gray:
1225					z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1226				case *image.NRGBA:
1227					z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1228				case *image.RGBA:
1229					z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1230				case *image.YCbCr:
1231					switch src.SubsampleRatio {
1232					default:
1233						z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1234					case image.YCbCrSubsampleRatio444:
1235						z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1236					case image.YCbCrSubsampleRatio422:
1237						z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1238					case image.YCbCrSubsampleRatio420:
1239						z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1240					case image.YCbCrSubsampleRatio440:
1241						z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1242					}
1243				default:
1244					z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1245				}
1246			default:
1247				switch src := src.(type) {
1248				default:
1249					z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
1250				}
1251			}
1252		}
1253	}
1254}
1255
1256func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
1257	sw := int32(sr.Dx())
1258	sh := int32(sr.Dy())
1259	yscale := float64(sh) / float64(dr.Dy())
1260	xscale := float64(sw) / float64(dr.Dx())
1261	swMinus1, shMinus1 := sw-1, sh-1
1262
1263	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1264		sy := (float64(dy)+0.5)*yscale - 0.5
1265		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1266		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1267		// sx, below.
1268		sy0 := int32(sy)
1269		yFrac0 := sy - float64(sy0)
1270		yFrac1 := 1 - yFrac0
1271		sy1 := sy0 + 1
1272		if sy < 0 {
1273			sy0, sy1 = 0, 0
1274			yFrac0, yFrac1 = 0, 1
1275		} else if sy1 > shMinus1 {
1276			sy0, sy1 = shMinus1, shMinus1
1277			yFrac0, yFrac1 = 1, 0
1278		}
1279		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1280
1281		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1282			sx := (float64(dx)+0.5)*xscale - 0.5
1283			sx0 := int32(sx)
1284			xFrac0 := sx - float64(sx0)
1285			xFrac1 := 1 - xFrac0
1286			sx1 := sx0 + 1
1287			if sx < 0 {
1288				sx0, sx1 = 0, 0
1289				xFrac0, xFrac1 = 0, 1
1290			} else if sx1 > swMinus1 {
1291				sx0, sx1 = swMinus1, swMinus1
1292				xFrac0, xFrac1 = 1, 0
1293			}
1294
1295			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1296			s00ru := uint32(src.Pix[s00i]) * 0x101
1297			s00r := float64(s00ru)
1298			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1299			s10ru := uint32(src.Pix[s10i]) * 0x101
1300			s10r := float64(s10ru)
1301			s10r = xFrac1*s00r + xFrac0*s10r
1302			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1303			s01ru := uint32(src.Pix[s01i]) * 0x101
1304			s01r := float64(s01ru)
1305			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1306			s11ru := uint32(src.Pix[s11i]) * 0x101
1307			s11r := float64(s11ru)
1308			s11r = xFrac1*s01r + xFrac0*s11r
1309			s11r = yFrac1*s10r + yFrac0*s11r
1310			pr := uint32(s11r)
1311			out := uint8(pr >> 8)
1312			dst.Pix[d+0] = out
1313			dst.Pix[d+1] = out
1314			dst.Pix[d+2] = out
1315			dst.Pix[d+3] = 0xff
1316		}
1317	}
1318}
1319
1320func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
1321	sw := int32(sr.Dx())
1322	sh := int32(sr.Dy())
1323	yscale := float64(sh) / float64(dr.Dy())
1324	xscale := float64(sw) / float64(dr.Dx())
1325	swMinus1, shMinus1 := sw-1, sh-1
1326
1327	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1328		sy := (float64(dy)+0.5)*yscale - 0.5
1329		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1330		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1331		// sx, below.
1332		sy0 := int32(sy)
1333		yFrac0 := sy - float64(sy0)
1334		yFrac1 := 1 - yFrac0
1335		sy1 := sy0 + 1
1336		if sy < 0 {
1337			sy0, sy1 = 0, 0
1338			yFrac0, yFrac1 = 0, 1
1339		} else if sy1 > shMinus1 {
1340			sy0, sy1 = shMinus1, shMinus1
1341			yFrac0, yFrac1 = 1, 0
1342		}
1343		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1344
1345		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1346			sx := (float64(dx)+0.5)*xscale - 0.5
1347			sx0 := int32(sx)
1348			xFrac0 := sx - float64(sx0)
1349			xFrac1 := 1 - xFrac0
1350			sx1 := sx0 + 1
1351			if sx < 0 {
1352				sx0, sx1 = 0, 0
1353				xFrac0, xFrac1 = 0, 1
1354			} else if sx1 > swMinus1 {
1355				sx0, sx1 = swMinus1, swMinus1
1356				xFrac0, xFrac1 = 1, 0
1357			}
1358
1359			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1360			s00au := uint32(src.Pix[s00i+3]) * 0x101
1361			s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
1362			s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
1363			s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
1364			s00r := float64(s00ru)
1365			s00g := float64(s00gu)
1366			s00b := float64(s00bu)
1367			s00a := float64(s00au)
1368			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1369			s10au := uint32(src.Pix[s10i+3]) * 0x101
1370			s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
1371			s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
1372			s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
1373			s10r := float64(s10ru)
1374			s10g := float64(s10gu)
1375			s10b := float64(s10bu)
1376			s10a := float64(s10au)
1377			s10r = xFrac1*s00r + xFrac0*s10r
1378			s10g = xFrac1*s00g + xFrac0*s10g
1379			s10b = xFrac1*s00b + xFrac0*s10b
1380			s10a = xFrac1*s00a + xFrac0*s10a
1381			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1382			s01au := uint32(src.Pix[s01i+3]) * 0x101
1383			s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
1384			s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
1385			s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
1386			s01r := float64(s01ru)
1387			s01g := float64(s01gu)
1388			s01b := float64(s01bu)
1389			s01a := float64(s01au)
1390			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1391			s11au := uint32(src.Pix[s11i+3]) * 0x101
1392			s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
1393			s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
1394			s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
1395			s11r := float64(s11ru)
1396			s11g := float64(s11gu)
1397			s11b := float64(s11bu)
1398			s11a := float64(s11au)
1399			s11r = xFrac1*s01r + xFrac0*s11r
1400			s11g = xFrac1*s01g + xFrac0*s11g
1401			s11b = xFrac1*s01b + xFrac0*s11b
1402			s11a = xFrac1*s01a + xFrac0*s11a
1403			s11r = yFrac1*s10r + yFrac0*s11r
1404			s11g = yFrac1*s10g + yFrac0*s11g
1405			s11b = yFrac1*s10b + yFrac0*s11b
1406			s11a = yFrac1*s10a + yFrac0*s11a
1407			pr := uint32(s11r)
1408			pg := uint32(s11g)
1409			pb := uint32(s11b)
1410			pa := uint32(s11a)
1411			pa1 := (0xffff - pa) * 0x101
1412			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
1413			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
1414			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
1415			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
1416		}
1417	}
1418}
1419
1420func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
1421	sw := int32(sr.Dx())
1422	sh := int32(sr.Dy())
1423	yscale := float64(sh) / float64(dr.Dy())
1424	xscale := float64(sw) / float64(dr.Dx())
1425	swMinus1, shMinus1 := sw-1, sh-1
1426
1427	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1428		sy := (float64(dy)+0.5)*yscale - 0.5
1429		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1430		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1431		// sx, below.
1432		sy0 := int32(sy)
1433		yFrac0 := sy - float64(sy0)
1434		yFrac1 := 1 - yFrac0
1435		sy1 := sy0 + 1
1436		if sy < 0 {
1437			sy0, sy1 = 0, 0
1438			yFrac0, yFrac1 = 0, 1
1439		} else if sy1 > shMinus1 {
1440			sy0, sy1 = shMinus1, shMinus1
1441			yFrac0, yFrac1 = 1, 0
1442		}
1443		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1444
1445		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1446			sx := (float64(dx)+0.5)*xscale - 0.5
1447			sx0 := int32(sx)
1448			xFrac0 := sx - float64(sx0)
1449			xFrac1 := 1 - xFrac0
1450			sx1 := sx0 + 1
1451			if sx < 0 {
1452				sx0, sx1 = 0, 0
1453				xFrac0, xFrac1 = 0, 1
1454			} else if sx1 > swMinus1 {
1455				sx0, sx1 = swMinus1, swMinus1
1456				xFrac0, xFrac1 = 1, 0
1457			}
1458
1459			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1460			s00au := uint32(src.Pix[s00i+3]) * 0x101
1461			s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
1462			s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
1463			s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
1464			s00r := float64(s00ru)
1465			s00g := float64(s00gu)
1466			s00b := float64(s00bu)
1467			s00a := float64(s00au)
1468			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1469			s10au := uint32(src.Pix[s10i+3]) * 0x101
1470			s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
1471			s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
1472			s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
1473			s10r := float64(s10ru)
1474			s10g := float64(s10gu)
1475			s10b := float64(s10bu)
1476			s10a := float64(s10au)
1477			s10r = xFrac1*s00r + xFrac0*s10r
1478			s10g = xFrac1*s00g + xFrac0*s10g
1479			s10b = xFrac1*s00b + xFrac0*s10b
1480			s10a = xFrac1*s00a + xFrac0*s10a
1481			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1482			s01au := uint32(src.Pix[s01i+3]) * 0x101
1483			s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
1484			s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
1485			s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
1486			s01r := float64(s01ru)
1487			s01g := float64(s01gu)
1488			s01b := float64(s01bu)
1489			s01a := float64(s01au)
1490			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1491			s11au := uint32(src.Pix[s11i+3]) * 0x101
1492			s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
1493			s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
1494			s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
1495			s11r := float64(s11ru)
1496			s11g := float64(s11gu)
1497			s11b := float64(s11bu)
1498			s11a := float64(s11au)
1499			s11r = xFrac1*s01r + xFrac0*s11r
1500			s11g = xFrac1*s01g + xFrac0*s11g
1501			s11b = xFrac1*s01b + xFrac0*s11b
1502			s11a = xFrac1*s01a + xFrac0*s11a
1503			s11r = yFrac1*s10r + yFrac0*s11r
1504			s11g = yFrac1*s10g + yFrac0*s11g
1505			s11b = yFrac1*s10b + yFrac0*s11b
1506			s11a = yFrac1*s10a + yFrac0*s11a
1507			pr := uint32(s11r)
1508			pg := uint32(s11g)
1509			pb := uint32(s11b)
1510			pa := uint32(s11a)
1511			dst.Pix[d+0] = uint8(pr >> 8)
1512			dst.Pix[d+1] = uint8(pg >> 8)
1513			dst.Pix[d+2] = uint8(pb >> 8)
1514			dst.Pix[d+3] = uint8(pa >> 8)
1515		}
1516	}
1517}
1518
1519func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
1520	sw := int32(sr.Dx())
1521	sh := int32(sr.Dy())
1522	yscale := float64(sh) / float64(dr.Dy())
1523	xscale := float64(sw) / float64(dr.Dx())
1524	swMinus1, shMinus1 := sw-1, sh-1
1525
1526	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1527		sy := (float64(dy)+0.5)*yscale - 0.5
1528		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1529		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1530		// sx, below.
1531		sy0 := int32(sy)
1532		yFrac0 := sy - float64(sy0)
1533		yFrac1 := 1 - yFrac0
1534		sy1 := sy0 + 1
1535		if sy < 0 {
1536			sy0, sy1 = 0, 0
1537			yFrac0, yFrac1 = 0, 1
1538		} else if sy1 > shMinus1 {
1539			sy0, sy1 = shMinus1, shMinus1
1540			yFrac0, yFrac1 = 1, 0
1541		}
1542		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1543
1544		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1545			sx := (float64(dx)+0.5)*xscale - 0.5
1546			sx0 := int32(sx)
1547			xFrac0 := sx - float64(sx0)
1548			xFrac1 := 1 - xFrac0
1549			sx1 := sx0 + 1
1550			if sx < 0 {
1551				sx0, sx1 = 0, 0
1552				xFrac0, xFrac1 = 0, 1
1553			} else if sx1 > swMinus1 {
1554				sx0, sx1 = swMinus1, swMinus1
1555				xFrac0, xFrac1 = 1, 0
1556			}
1557
1558			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1559			s00ru := uint32(src.Pix[s00i+0]) * 0x101
1560			s00gu := uint32(src.Pix[s00i+1]) * 0x101
1561			s00bu := uint32(src.Pix[s00i+2]) * 0x101
1562			s00au := uint32(src.Pix[s00i+3]) * 0x101
1563			s00r := float64(s00ru)
1564			s00g := float64(s00gu)
1565			s00b := float64(s00bu)
1566			s00a := float64(s00au)
1567			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1568			s10ru := uint32(src.Pix[s10i+0]) * 0x101
1569			s10gu := uint32(src.Pix[s10i+1]) * 0x101
1570			s10bu := uint32(src.Pix[s10i+2]) * 0x101
1571			s10au := uint32(src.Pix[s10i+3]) * 0x101
1572			s10r := float64(s10ru)
1573			s10g := float64(s10gu)
1574			s10b := float64(s10bu)
1575			s10a := float64(s10au)
1576			s10r = xFrac1*s00r + xFrac0*s10r
1577			s10g = xFrac1*s00g + xFrac0*s10g
1578			s10b = xFrac1*s00b + xFrac0*s10b
1579			s10a = xFrac1*s00a + xFrac0*s10a
1580			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1581			s01ru := uint32(src.Pix[s01i+0]) * 0x101
1582			s01gu := uint32(src.Pix[s01i+1]) * 0x101
1583			s01bu := uint32(src.Pix[s01i+2]) * 0x101
1584			s01au := uint32(src.Pix[s01i+3]) * 0x101
1585			s01r := float64(s01ru)
1586			s01g := float64(s01gu)
1587			s01b := float64(s01bu)
1588			s01a := float64(s01au)
1589			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1590			s11ru := uint32(src.Pix[s11i+0]) * 0x101
1591			s11gu := uint32(src.Pix[s11i+1]) * 0x101
1592			s11bu := uint32(src.Pix[s11i+2]) * 0x101
1593			s11au := uint32(src.Pix[s11i+3]) * 0x101
1594			s11r := float64(s11ru)
1595			s11g := float64(s11gu)
1596			s11b := float64(s11bu)
1597			s11a := float64(s11au)
1598			s11r = xFrac1*s01r + xFrac0*s11r
1599			s11g = xFrac1*s01g + xFrac0*s11g
1600			s11b = xFrac1*s01b + xFrac0*s11b
1601			s11a = xFrac1*s01a + xFrac0*s11a
1602			s11r = yFrac1*s10r + yFrac0*s11r
1603			s11g = yFrac1*s10g + yFrac0*s11g
1604			s11b = yFrac1*s10b + yFrac0*s11b
1605			s11a = yFrac1*s10a + yFrac0*s11a
1606			pr := uint32(s11r)
1607			pg := uint32(s11g)
1608			pb := uint32(s11b)
1609			pa := uint32(s11a)
1610			pa1 := (0xffff - pa) * 0x101
1611			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
1612			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
1613			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
1614			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
1615		}
1616	}
1617}
1618
1619func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
1620	sw := int32(sr.Dx())
1621	sh := int32(sr.Dy())
1622	yscale := float64(sh) / float64(dr.Dy())
1623	xscale := float64(sw) / float64(dr.Dx())
1624	swMinus1, shMinus1 := sw-1, sh-1
1625
1626	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1627		sy := (float64(dy)+0.5)*yscale - 0.5
1628		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1629		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1630		// sx, below.
1631		sy0 := int32(sy)
1632		yFrac0 := sy - float64(sy0)
1633		yFrac1 := 1 - yFrac0
1634		sy1 := sy0 + 1
1635		if sy < 0 {
1636			sy0, sy1 = 0, 0
1637			yFrac0, yFrac1 = 0, 1
1638		} else if sy1 > shMinus1 {
1639			sy0, sy1 = shMinus1, shMinus1
1640			yFrac0, yFrac1 = 1, 0
1641		}
1642		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1643
1644		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1645			sx := (float64(dx)+0.5)*xscale - 0.5
1646			sx0 := int32(sx)
1647			xFrac0 := sx - float64(sx0)
1648			xFrac1 := 1 - xFrac0
1649			sx1 := sx0 + 1
1650			if sx < 0 {
1651				sx0, sx1 = 0, 0
1652				xFrac0, xFrac1 = 0, 1
1653			} else if sx1 > swMinus1 {
1654				sx0, sx1 = swMinus1, swMinus1
1655				xFrac0, xFrac1 = 1, 0
1656			}
1657
1658			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1659			s00ru := uint32(src.Pix[s00i+0]) * 0x101
1660			s00gu := uint32(src.Pix[s00i+1]) * 0x101
1661			s00bu := uint32(src.Pix[s00i+2]) * 0x101
1662			s00au := uint32(src.Pix[s00i+3]) * 0x101
1663			s00r := float64(s00ru)
1664			s00g := float64(s00gu)
1665			s00b := float64(s00bu)
1666			s00a := float64(s00au)
1667			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1668			s10ru := uint32(src.Pix[s10i+0]) * 0x101
1669			s10gu := uint32(src.Pix[s10i+1]) * 0x101
1670			s10bu := uint32(src.Pix[s10i+2]) * 0x101
1671			s10au := uint32(src.Pix[s10i+3]) * 0x101
1672			s10r := float64(s10ru)
1673			s10g := float64(s10gu)
1674			s10b := float64(s10bu)
1675			s10a := float64(s10au)
1676			s10r = xFrac1*s00r + xFrac0*s10r
1677			s10g = xFrac1*s00g + xFrac0*s10g
1678			s10b = xFrac1*s00b + xFrac0*s10b
1679			s10a = xFrac1*s00a + xFrac0*s10a
1680			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
1681			s01ru := uint32(src.Pix[s01i+0]) * 0x101
1682			s01gu := uint32(src.Pix[s01i+1]) * 0x101
1683			s01bu := uint32(src.Pix[s01i+2]) * 0x101
1684			s01au := uint32(src.Pix[s01i+3]) * 0x101
1685			s01r := float64(s01ru)
1686			s01g := float64(s01gu)
1687			s01b := float64(s01bu)
1688			s01a := float64(s01au)
1689			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
1690			s11ru := uint32(src.Pix[s11i+0]) * 0x101
1691			s11gu := uint32(src.Pix[s11i+1]) * 0x101
1692			s11bu := uint32(src.Pix[s11i+2]) * 0x101
1693			s11au := uint32(src.Pix[s11i+3]) * 0x101
1694			s11r := float64(s11ru)
1695			s11g := float64(s11gu)
1696			s11b := float64(s11bu)
1697			s11a := float64(s11au)
1698			s11r = xFrac1*s01r + xFrac0*s11r
1699			s11g = xFrac1*s01g + xFrac0*s11g
1700			s11b = xFrac1*s01b + xFrac0*s11b
1701			s11a = xFrac1*s01a + xFrac0*s11a
1702			s11r = yFrac1*s10r + yFrac0*s11r
1703			s11g = yFrac1*s10g + yFrac0*s11g
1704			s11b = yFrac1*s10b + yFrac0*s11b
1705			s11a = yFrac1*s10a + yFrac0*s11a
1706			pr := uint32(s11r)
1707			pg := uint32(s11g)
1708			pb := uint32(s11b)
1709			pa := uint32(s11a)
1710			dst.Pix[d+0] = uint8(pr >> 8)
1711			dst.Pix[d+1] = uint8(pg >> 8)
1712			dst.Pix[d+2] = uint8(pb >> 8)
1713			dst.Pix[d+3] = uint8(pa >> 8)
1714		}
1715	}
1716}
1717
1718func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
1719	sw := int32(sr.Dx())
1720	sh := int32(sr.Dy())
1721	yscale := float64(sh) / float64(dr.Dy())
1722	xscale := float64(sw) / float64(dr.Dx())
1723	swMinus1, shMinus1 := sw-1, sh-1
1724
1725	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1726		sy := (float64(dy)+0.5)*yscale - 0.5
1727		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1728		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1729		// sx, below.
1730		sy0 := int32(sy)
1731		yFrac0 := sy - float64(sy0)
1732		yFrac1 := 1 - yFrac0
1733		sy1 := sy0 + 1
1734		if sy < 0 {
1735			sy0, sy1 = 0, 0
1736			yFrac0, yFrac1 = 0, 1
1737		} else if sy1 > shMinus1 {
1738			sy0, sy1 = shMinus1, shMinus1
1739			yFrac0, yFrac1 = 1, 0
1740		}
1741		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1742
1743		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1744			sx := (float64(dx)+0.5)*xscale - 0.5
1745			sx0 := int32(sx)
1746			xFrac0 := sx - float64(sx0)
1747			xFrac1 := 1 - xFrac0
1748			sx1 := sx0 + 1
1749			if sx < 0 {
1750				sx0, sx1 = 0, 0
1751				xFrac0, xFrac1 = 0, 1
1752			} else if sx1 > swMinus1 {
1753				sx0, sx1 = swMinus1, swMinus1
1754				xFrac0, xFrac1 = 1, 0
1755			}
1756
1757			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1758			s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1759
1760			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1761			s00yy1 := int(src.Y[s00i]) * 0x10101
1762			s00cb1 := int(src.Cb[s00j]) - 128
1763			s00cr1 := int(src.Cr[s00j]) - 128
1764			s00ru := (s00yy1 + 91881*s00cr1) >> 8
1765			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
1766			s00bu := (s00yy1 + 116130*s00cb1) >> 8
1767			if s00ru < 0 {
1768				s00ru = 0
1769			} else if s00ru > 0xffff {
1770				s00ru = 0xffff
1771			}
1772			if s00gu < 0 {
1773				s00gu = 0
1774			} else if s00gu > 0xffff {
1775				s00gu = 0xffff
1776			}
1777			if s00bu < 0 {
1778				s00bu = 0
1779			} else if s00bu > 0xffff {
1780				s00bu = 0xffff
1781			}
1782
1783			s00r := float64(s00ru)
1784			s00g := float64(s00gu)
1785			s00b := float64(s00bu)
1786			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1787			s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1788
1789			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1790			s10yy1 := int(src.Y[s10i]) * 0x10101
1791			s10cb1 := int(src.Cb[s10j]) - 128
1792			s10cr1 := int(src.Cr[s10j]) - 128
1793			s10ru := (s10yy1 + 91881*s10cr1) >> 8
1794			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
1795			s10bu := (s10yy1 + 116130*s10cb1) >> 8
1796			if s10ru < 0 {
1797				s10ru = 0
1798			} else if s10ru > 0xffff {
1799				s10ru = 0xffff
1800			}
1801			if s10gu < 0 {
1802				s10gu = 0
1803			} else if s10gu > 0xffff {
1804				s10gu = 0xffff
1805			}
1806			if s10bu < 0 {
1807				s10bu = 0
1808			} else if s10bu > 0xffff {
1809				s10bu = 0xffff
1810			}
1811
1812			s10r := float64(s10ru)
1813			s10g := float64(s10gu)
1814			s10b := float64(s10bu)
1815			s10r = xFrac1*s00r + xFrac0*s10r
1816			s10g = xFrac1*s00g + xFrac0*s10g
1817			s10b = xFrac1*s00b + xFrac0*s10b
1818			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1819			s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1820
1821			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1822			s01yy1 := int(src.Y[s01i]) * 0x10101
1823			s01cb1 := int(src.Cb[s01j]) - 128
1824			s01cr1 := int(src.Cr[s01j]) - 128
1825			s01ru := (s01yy1 + 91881*s01cr1) >> 8
1826			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
1827			s01bu := (s01yy1 + 116130*s01cb1) >> 8
1828			if s01ru < 0 {
1829				s01ru = 0
1830			} else if s01ru > 0xffff {
1831				s01ru = 0xffff
1832			}
1833			if s01gu < 0 {
1834				s01gu = 0
1835			} else if s01gu > 0xffff {
1836				s01gu = 0xffff
1837			}
1838			if s01bu < 0 {
1839				s01bu = 0
1840			} else if s01bu > 0xffff {
1841				s01bu = 0xffff
1842			}
1843
1844			s01r := float64(s01ru)
1845			s01g := float64(s01gu)
1846			s01b := float64(s01bu)
1847			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1848			s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1849
1850			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1851			s11yy1 := int(src.Y[s11i]) * 0x10101
1852			s11cb1 := int(src.Cb[s11j]) - 128
1853			s11cr1 := int(src.Cr[s11j]) - 128
1854			s11ru := (s11yy1 + 91881*s11cr1) >> 8
1855			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
1856			s11bu := (s11yy1 + 116130*s11cb1) >> 8
1857			if s11ru < 0 {
1858				s11ru = 0
1859			} else if s11ru > 0xffff {
1860				s11ru = 0xffff
1861			}
1862			if s11gu < 0 {
1863				s11gu = 0
1864			} else if s11gu > 0xffff {
1865				s11gu = 0xffff
1866			}
1867			if s11bu < 0 {
1868				s11bu = 0
1869			} else if s11bu > 0xffff {
1870				s11bu = 0xffff
1871			}
1872
1873			s11r := float64(s11ru)
1874			s11g := float64(s11gu)
1875			s11b := float64(s11bu)
1876			s11r = xFrac1*s01r + xFrac0*s11r
1877			s11g = xFrac1*s01g + xFrac0*s11g
1878			s11b = xFrac1*s01b + xFrac0*s11b
1879			s11r = yFrac1*s10r + yFrac0*s11r
1880			s11g = yFrac1*s10g + yFrac0*s11g
1881			s11b = yFrac1*s10b + yFrac0*s11b
1882			pr := uint32(s11r)
1883			pg := uint32(s11g)
1884			pb := uint32(s11b)
1885			dst.Pix[d+0] = uint8(pr >> 8)
1886			dst.Pix[d+1] = uint8(pg >> 8)
1887			dst.Pix[d+2] = uint8(pb >> 8)
1888			dst.Pix[d+3] = 0xff
1889		}
1890	}
1891}
1892
1893func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
1894	sw := int32(sr.Dx())
1895	sh := int32(sr.Dy())
1896	yscale := float64(sh) / float64(dr.Dy())
1897	xscale := float64(sw) / float64(dr.Dx())
1898	swMinus1, shMinus1 := sw-1, sh-1
1899
1900	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
1901		sy := (float64(dy)+0.5)*yscale - 0.5
1902		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
1903		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
1904		// sx, below.
1905		sy0 := int32(sy)
1906		yFrac0 := sy - float64(sy0)
1907		yFrac1 := 1 - yFrac0
1908		sy1 := sy0 + 1
1909		if sy < 0 {
1910			sy0, sy1 = 0, 0
1911			yFrac0, yFrac1 = 0, 1
1912		} else if sy1 > shMinus1 {
1913			sy0, sy1 = shMinus1, shMinus1
1914			yFrac0, yFrac1 = 1, 0
1915		}
1916		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
1917
1918		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
1919			sx := (float64(dx)+0.5)*xscale - 0.5
1920			sx0 := int32(sx)
1921			xFrac0 := sx - float64(sx0)
1922			xFrac1 := 1 - xFrac0
1923			sx1 := sx0 + 1
1924			if sx < 0 {
1925				sx0, sx1 = 0, 0
1926				xFrac0, xFrac1 = 0, 1
1927			} else if sx1 > swMinus1 {
1928				sx0, sx1 = swMinus1, swMinus1
1929				xFrac0, xFrac1 = 1, 0
1930			}
1931
1932			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1933			s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
1934
1935			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1936			s00yy1 := int(src.Y[s00i]) * 0x10101
1937			s00cb1 := int(src.Cb[s00j]) - 128
1938			s00cr1 := int(src.Cr[s00j]) - 128
1939			s00ru := (s00yy1 + 91881*s00cr1) >> 8
1940			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
1941			s00bu := (s00yy1 + 116130*s00cb1) >> 8
1942			if s00ru < 0 {
1943				s00ru = 0
1944			} else if s00ru > 0xffff {
1945				s00ru = 0xffff
1946			}
1947			if s00gu < 0 {
1948				s00gu = 0
1949			} else if s00gu > 0xffff {
1950				s00gu = 0xffff
1951			}
1952			if s00bu < 0 {
1953				s00bu = 0
1954			} else if s00bu > 0xffff {
1955				s00bu = 0xffff
1956			}
1957
1958			s00r := float64(s00ru)
1959			s00g := float64(s00gu)
1960			s00b := float64(s00bu)
1961			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
1962			s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
1963
1964			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1965			s10yy1 := int(src.Y[s10i]) * 0x10101
1966			s10cb1 := int(src.Cb[s10j]) - 128
1967			s10cr1 := int(src.Cr[s10j]) - 128
1968			s10ru := (s10yy1 + 91881*s10cr1) >> 8
1969			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
1970			s10bu := (s10yy1 + 116130*s10cb1) >> 8
1971			if s10ru < 0 {
1972				s10ru = 0
1973			} else if s10ru > 0xffff {
1974				s10ru = 0xffff
1975			}
1976			if s10gu < 0 {
1977				s10gu = 0
1978			} else if s10gu > 0xffff {
1979				s10gu = 0xffff
1980			}
1981			if s10bu < 0 {
1982				s10bu = 0
1983			} else if s10bu > 0xffff {
1984				s10bu = 0xffff
1985			}
1986
1987			s10r := float64(s10ru)
1988			s10g := float64(s10gu)
1989			s10b := float64(s10bu)
1990			s10r = xFrac1*s00r + xFrac0*s10r
1991			s10g = xFrac1*s00g + xFrac0*s10g
1992			s10b = xFrac1*s00b + xFrac0*s10b
1993			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
1994			s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
1995
1996			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
1997			s01yy1 := int(src.Y[s01i]) * 0x10101
1998			s01cb1 := int(src.Cb[s01j]) - 128
1999			s01cr1 := int(src.Cr[s01j]) - 128
2000			s01ru := (s01yy1 + 91881*s01cr1) >> 8
2001			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
2002			s01bu := (s01yy1 + 116130*s01cb1) >> 8
2003			if s01ru < 0 {
2004				s01ru = 0
2005			} else if s01ru > 0xffff {
2006				s01ru = 0xffff
2007			}
2008			if s01gu < 0 {
2009				s01gu = 0
2010			} else if s01gu > 0xffff {
2011				s01gu = 0xffff
2012			}
2013			if s01bu < 0 {
2014				s01bu = 0
2015			} else if s01bu > 0xffff {
2016				s01bu = 0xffff
2017			}
2018
2019			s01r := float64(s01ru)
2020			s01g := float64(s01gu)
2021			s01b := float64(s01bu)
2022			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2023			s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
2024
2025			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2026			s11yy1 := int(src.Y[s11i]) * 0x10101
2027			s11cb1 := int(src.Cb[s11j]) - 128
2028			s11cr1 := int(src.Cr[s11j]) - 128
2029			s11ru := (s11yy1 + 91881*s11cr1) >> 8
2030			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
2031			s11bu := (s11yy1 + 116130*s11cb1) >> 8
2032			if s11ru < 0 {
2033				s11ru = 0
2034			} else if s11ru > 0xffff {
2035				s11ru = 0xffff
2036			}
2037			if s11gu < 0 {
2038				s11gu = 0
2039			} else if s11gu > 0xffff {
2040				s11gu = 0xffff
2041			}
2042			if s11bu < 0 {
2043				s11bu = 0
2044			} else if s11bu > 0xffff {
2045				s11bu = 0xffff
2046			}
2047
2048			s11r := float64(s11ru)
2049			s11g := float64(s11gu)
2050			s11b := float64(s11bu)
2051			s11r = xFrac1*s01r + xFrac0*s11r
2052			s11g = xFrac1*s01g + xFrac0*s11g
2053			s11b = xFrac1*s01b + xFrac0*s11b
2054			s11r = yFrac1*s10r + yFrac0*s11r
2055			s11g = yFrac1*s10g + yFrac0*s11g
2056			s11b = yFrac1*s10b + yFrac0*s11b
2057			pr := uint32(s11r)
2058			pg := uint32(s11g)
2059			pb := uint32(s11b)
2060			dst.Pix[d+0] = uint8(pr >> 8)
2061			dst.Pix[d+1] = uint8(pg >> 8)
2062			dst.Pix[d+2] = uint8(pb >> 8)
2063			dst.Pix[d+3] = 0xff
2064		}
2065	}
2066}
2067
2068func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
2069	sw := int32(sr.Dx())
2070	sh := int32(sr.Dy())
2071	yscale := float64(sh) / float64(dr.Dy())
2072	xscale := float64(sw) / float64(dr.Dx())
2073	swMinus1, shMinus1 := sw-1, sh-1
2074
2075	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2076		sy := (float64(dy)+0.5)*yscale - 0.5
2077		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2078		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2079		// sx, below.
2080		sy0 := int32(sy)
2081		yFrac0 := sy - float64(sy0)
2082		yFrac1 := 1 - yFrac0
2083		sy1 := sy0 + 1
2084		if sy < 0 {
2085			sy0, sy1 = 0, 0
2086			yFrac0, yFrac1 = 0, 1
2087		} else if sy1 > shMinus1 {
2088			sy0, sy1 = shMinus1, shMinus1
2089			yFrac0, yFrac1 = 1, 0
2090		}
2091		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2092
2093		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2094			sx := (float64(dx)+0.5)*xscale - 0.5
2095			sx0 := int32(sx)
2096			xFrac0 := sx - float64(sx0)
2097			xFrac1 := 1 - xFrac0
2098			sx1 := sx0 + 1
2099			if sx < 0 {
2100				sx0, sx1 = 0, 0
2101				xFrac0, xFrac1 = 0, 1
2102			} else if sx1 > swMinus1 {
2103				sx0, sx1 = swMinus1, swMinus1
2104				xFrac0, xFrac1 = 1, 0
2105			}
2106
2107			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2108			s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
2109
2110			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2111			s00yy1 := int(src.Y[s00i]) * 0x10101
2112			s00cb1 := int(src.Cb[s00j]) - 128
2113			s00cr1 := int(src.Cr[s00j]) - 128
2114			s00ru := (s00yy1 + 91881*s00cr1) >> 8
2115			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
2116			s00bu := (s00yy1 + 116130*s00cb1) >> 8
2117			if s00ru < 0 {
2118				s00ru = 0
2119			} else if s00ru > 0xffff {
2120				s00ru = 0xffff
2121			}
2122			if s00gu < 0 {
2123				s00gu = 0
2124			} else if s00gu > 0xffff {
2125				s00gu = 0xffff
2126			}
2127			if s00bu < 0 {
2128				s00bu = 0
2129			} else if s00bu > 0xffff {
2130				s00bu = 0xffff
2131			}
2132
2133			s00r := float64(s00ru)
2134			s00g := float64(s00gu)
2135			s00b := float64(s00bu)
2136			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2137			s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
2138
2139			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2140			s10yy1 := int(src.Y[s10i]) * 0x10101
2141			s10cb1 := int(src.Cb[s10j]) - 128
2142			s10cr1 := int(src.Cr[s10j]) - 128
2143			s10ru := (s10yy1 + 91881*s10cr1) >> 8
2144			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
2145			s10bu := (s10yy1 + 116130*s10cb1) >> 8
2146			if s10ru < 0 {
2147				s10ru = 0
2148			} else if s10ru > 0xffff {
2149				s10ru = 0xffff
2150			}
2151			if s10gu < 0 {
2152				s10gu = 0
2153			} else if s10gu > 0xffff {
2154				s10gu = 0xffff
2155			}
2156			if s10bu < 0 {
2157				s10bu = 0
2158			} else if s10bu > 0xffff {
2159				s10bu = 0xffff
2160			}
2161
2162			s10r := float64(s10ru)
2163			s10g := float64(s10gu)
2164			s10b := float64(s10bu)
2165			s10r = xFrac1*s00r + xFrac0*s10r
2166			s10g = xFrac1*s00g + xFrac0*s10g
2167			s10b = xFrac1*s00b + xFrac0*s10b
2168			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2169			s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
2170
2171			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2172			s01yy1 := int(src.Y[s01i]) * 0x10101
2173			s01cb1 := int(src.Cb[s01j]) - 128
2174			s01cr1 := int(src.Cr[s01j]) - 128
2175			s01ru := (s01yy1 + 91881*s01cr1) >> 8
2176			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
2177			s01bu := (s01yy1 + 116130*s01cb1) >> 8
2178			if s01ru < 0 {
2179				s01ru = 0
2180			} else if s01ru > 0xffff {
2181				s01ru = 0xffff
2182			}
2183			if s01gu < 0 {
2184				s01gu = 0
2185			} else if s01gu > 0xffff {
2186				s01gu = 0xffff
2187			}
2188			if s01bu < 0 {
2189				s01bu = 0
2190			} else if s01bu > 0xffff {
2191				s01bu = 0xffff
2192			}
2193
2194			s01r := float64(s01ru)
2195			s01g := float64(s01gu)
2196			s01b := float64(s01bu)
2197			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2198			s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
2199
2200			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2201			s11yy1 := int(src.Y[s11i]) * 0x10101
2202			s11cb1 := int(src.Cb[s11j]) - 128
2203			s11cr1 := int(src.Cr[s11j]) - 128
2204			s11ru := (s11yy1 + 91881*s11cr1) >> 8
2205			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
2206			s11bu := (s11yy1 + 116130*s11cb1) >> 8
2207			if s11ru < 0 {
2208				s11ru = 0
2209			} else if s11ru > 0xffff {
2210				s11ru = 0xffff
2211			}
2212			if s11gu < 0 {
2213				s11gu = 0
2214			} else if s11gu > 0xffff {
2215				s11gu = 0xffff
2216			}
2217			if s11bu < 0 {
2218				s11bu = 0
2219			} else if s11bu > 0xffff {
2220				s11bu = 0xffff
2221			}
2222
2223			s11r := float64(s11ru)
2224			s11g := float64(s11gu)
2225			s11b := float64(s11bu)
2226			s11r = xFrac1*s01r + xFrac0*s11r
2227			s11g = xFrac1*s01g + xFrac0*s11g
2228			s11b = xFrac1*s01b + xFrac0*s11b
2229			s11r = yFrac1*s10r + yFrac0*s11r
2230			s11g = yFrac1*s10g + yFrac0*s11g
2231			s11b = yFrac1*s10b + yFrac0*s11b
2232			pr := uint32(s11r)
2233			pg := uint32(s11g)
2234			pb := uint32(s11b)
2235			dst.Pix[d+0] = uint8(pr >> 8)
2236			dst.Pix[d+1] = uint8(pg >> 8)
2237			dst.Pix[d+2] = uint8(pb >> 8)
2238			dst.Pix[d+3] = 0xff
2239		}
2240	}
2241}
2242
2243func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
2244	sw := int32(sr.Dx())
2245	sh := int32(sr.Dy())
2246	yscale := float64(sh) / float64(dr.Dy())
2247	xscale := float64(sw) / float64(dr.Dx())
2248	swMinus1, shMinus1 := sw-1, sh-1
2249
2250	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2251		sy := (float64(dy)+0.5)*yscale - 0.5
2252		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2253		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2254		// sx, below.
2255		sy0 := int32(sy)
2256		yFrac0 := sy - float64(sy0)
2257		yFrac1 := 1 - yFrac0
2258		sy1 := sy0 + 1
2259		if sy < 0 {
2260			sy0, sy1 = 0, 0
2261			yFrac0, yFrac1 = 0, 1
2262		} else if sy1 > shMinus1 {
2263			sy0, sy1 = shMinus1, shMinus1
2264			yFrac0, yFrac1 = 1, 0
2265		}
2266		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2267
2268		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2269			sx := (float64(dx)+0.5)*xscale - 0.5
2270			sx0 := int32(sx)
2271			xFrac0 := sx - float64(sx0)
2272			xFrac1 := 1 - xFrac0
2273			sx1 := sx0 + 1
2274			if sx < 0 {
2275				sx0, sx1 = 0, 0
2276				xFrac0, xFrac1 = 0, 1
2277			} else if sx1 > swMinus1 {
2278				sx0, sx1 = swMinus1, swMinus1
2279				xFrac0, xFrac1 = 1, 0
2280			}
2281
2282			s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2283			s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2284
2285			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2286			s00yy1 := int(src.Y[s00i]) * 0x10101
2287			s00cb1 := int(src.Cb[s00j]) - 128
2288			s00cr1 := int(src.Cr[s00j]) - 128
2289			s00ru := (s00yy1 + 91881*s00cr1) >> 8
2290			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
2291			s00bu := (s00yy1 + 116130*s00cb1) >> 8
2292			if s00ru < 0 {
2293				s00ru = 0
2294			} else if s00ru > 0xffff {
2295				s00ru = 0xffff
2296			}
2297			if s00gu < 0 {
2298				s00gu = 0
2299			} else if s00gu > 0xffff {
2300				s00gu = 0xffff
2301			}
2302			if s00bu < 0 {
2303				s00bu = 0
2304			} else if s00bu > 0xffff {
2305				s00bu = 0xffff
2306			}
2307
2308			s00r := float64(s00ru)
2309			s00g := float64(s00gu)
2310			s00b := float64(s00bu)
2311			s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2312			s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2313
2314			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2315			s10yy1 := int(src.Y[s10i]) * 0x10101
2316			s10cb1 := int(src.Cb[s10j]) - 128
2317			s10cr1 := int(src.Cr[s10j]) - 128
2318			s10ru := (s10yy1 + 91881*s10cr1) >> 8
2319			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
2320			s10bu := (s10yy1 + 116130*s10cb1) >> 8
2321			if s10ru < 0 {
2322				s10ru = 0
2323			} else if s10ru > 0xffff {
2324				s10ru = 0xffff
2325			}
2326			if s10gu < 0 {
2327				s10gu = 0
2328			} else if s10gu > 0xffff {
2329				s10gu = 0xffff
2330			}
2331			if s10bu < 0 {
2332				s10bu = 0
2333			} else if s10bu > 0xffff {
2334				s10bu = 0xffff
2335			}
2336
2337			s10r := float64(s10ru)
2338			s10g := float64(s10gu)
2339			s10b := float64(s10bu)
2340			s10r = xFrac1*s00r + xFrac0*s10r
2341			s10g = xFrac1*s00g + xFrac0*s10g
2342			s10b = xFrac1*s00b + xFrac0*s10b
2343			s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2344			s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
2345
2346			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2347			s01yy1 := int(src.Y[s01i]) * 0x10101
2348			s01cb1 := int(src.Cb[s01j]) - 128
2349			s01cr1 := int(src.Cr[s01j]) - 128
2350			s01ru := (s01yy1 + 91881*s01cr1) >> 8
2351			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
2352			s01bu := (s01yy1 + 116130*s01cb1) >> 8
2353			if s01ru < 0 {
2354				s01ru = 0
2355			} else if s01ru > 0xffff {
2356				s01ru = 0xffff
2357			}
2358			if s01gu < 0 {
2359				s01gu = 0
2360			} else if s01gu > 0xffff {
2361				s01gu = 0xffff
2362			}
2363			if s01bu < 0 {
2364				s01bu = 0
2365			} else if s01bu > 0xffff {
2366				s01bu = 0xffff
2367			}
2368
2369			s01r := float64(s01ru)
2370			s01g := float64(s01gu)
2371			s01b := float64(s01bu)
2372			s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2373			s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
2374
2375			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
2376			s11yy1 := int(src.Y[s11i]) * 0x10101
2377			s11cb1 := int(src.Cb[s11j]) - 128
2378			s11cr1 := int(src.Cr[s11j]) - 128
2379			s11ru := (s11yy1 + 91881*s11cr1) >> 8
2380			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
2381			s11bu := (s11yy1 + 116130*s11cb1) >> 8
2382			if s11ru < 0 {
2383				s11ru = 0
2384			} else if s11ru > 0xffff {
2385				s11ru = 0xffff
2386			}
2387			if s11gu < 0 {
2388				s11gu = 0
2389			} else if s11gu > 0xffff {
2390				s11gu = 0xffff
2391			}
2392			if s11bu < 0 {
2393				s11bu = 0
2394			} else if s11bu > 0xffff {
2395				s11bu = 0xffff
2396			}
2397
2398			s11r := float64(s11ru)
2399			s11g := float64(s11gu)
2400			s11b := float64(s11bu)
2401			s11r = xFrac1*s01r + xFrac0*s11r
2402			s11g = xFrac1*s01g + xFrac0*s11g
2403			s11b = xFrac1*s01b + xFrac0*s11b
2404			s11r = yFrac1*s10r + yFrac0*s11r
2405			s11g = yFrac1*s10g + yFrac0*s11g
2406			s11b = yFrac1*s10b + yFrac0*s11b
2407			pr := uint32(s11r)
2408			pg := uint32(s11g)
2409			pb := uint32(s11b)
2410			dst.Pix[d+0] = uint8(pr >> 8)
2411			dst.Pix[d+1] = uint8(pg >> 8)
2412			dst.Pix[d+2] = uint8(pb >> 8)
2413			dst.Pix[d+3] = 0xff
2414		}
2415	}
2416}
2417
2418func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
2419	sw := int32(sr.Dx())
2420	sh := int32(sr.Dy())
2421	yscale := float64(sh) / float64(dr.Dy())
2422	xscale := float64(sw) / float64(dr.Dx())
2423	swMinus1, shMinus1 := sw-1, sh-1
2424
2425	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2426		sy := (float64(dy)+0.5)*yscale - 0.5
2427		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2428		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2429		// sx, below.
2430		sy0 := int32(sy)
2431		yFrac0 := sy - float64(sy0)
2432		yFrac1 := 1 - yFrac0
2433		sy1 := sy0 + 1
2434		if sy < 0 {
2435			sy0, sy1 = 0, 0
2436			yFrac0, yFrac1 = 0, 1
2437		} else if sy1 > shMinus1 {
2438			sy0, sy1 = shMinus1, shMinus1
2439			yFrac0, yFrac1 = 1, 0
2440		}
2441		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2442
2443		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2444			sx := (float64(dx)+0.5)*xscale - 0.5
2445			sx0 := int32(sx)
2446			xFrac0 := sx - float64(sx0)
2447			xFrac1 := 1 - xFrac0
2448			sx1 := sx0 + 1
2449			if sx < 0 {
2450				sx0, sx1 = 0, 0
2451				xFrac0, xFrac1 = 0, 1
2452			} else if sx1 > swMinus1 {
2453				sx0, sx1 = swMinus1, swMinus1
2454				xFrac0, xFrac1 = 1, 0
2455			}
2456
2457			s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
2458			s00r := float64(s00ru)
2459			s00g := float64(s00gu)
2460			s00b := float64(s00bu)
2461			s00a := float64(s00au)
2462			s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
2463			s10r := float64(s10ru)
2464			s10g := float64(s10gu)
2465			s10b := float64(s10bu)
2466			s10a := float64(s10au)
2467			s10r = xFrac1*s00r + xFrac0*s10r
2468			s10g = xFrac1*s00g + xFrac0*s10g
2469			s10b = xFrac1*s00b + xFrac0*s10b
2470			s10a = xFrac1*s00a + xFrac0*s10a
2471			s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
2472			s01r := float64(s01ru)
2473			s01g := float64(s01gu)
2474			s01b := float64(s01bu)
2475			s01a := float64(s01au)
2476			s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
2477			s11r := float64(s11ru)
2478			s11g := float64(s11gu)
2479			s11b := float64(s11bu)
2480			s11a := float64(s11au)
2481			s11r = xFrac1*s01r + xFrac0*s11r
2482			s11g = xFrac1*s01g + xFrac0*s11g
2483			s11b = xFrac1*s01b + xFrac0*s11b
2484			s11a = xFrac1*s01a + xFrac0*s11a
2485			s11r = yFrac1*s10r + yFrac0*s11r
2486			s11g = yFrac1*s10g + yFrac0*s11g
2487			s11b = yFrac1*s10b + yFrac0*s11b
2488			s11a = yFrac1*s10a + yFrac0*s11a
2489			pr := uint32(s11r)
2490			pg := uint32(s11g)
2491			pb := uint32(s11b)
2492			pa := uint32(s11a)
2493			pa1 := (0xffff - pa) * 0x101
2494			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
2495			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
2496			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
2497			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
2498		}
2499	}
2500}
2501
2502func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
2503	sw := int32(sr.Dx())
2504	sh := int32(sr.Dy())
2505	yscale := float64(sh) / float64(dr.Dy())
2506	xscale := float64(sw) / float64(dr.Dx())
2507	swMinus1, shMinus1 := sw-1, sh-1
2508
2509	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2510		sy := (float64(dy)+0.5)*yscale - 0.5
2511		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2512		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2513		// sx, below.
2514		sy0 := int32(sy)
2515		yFrac0 := sy - float64(sy0)
2516		yFrac1 := 1 - yFrac0
2517		sy1 := sy0 + 1
2518		if sy < 0 {
2519			sy0, sy1 = 0, 0
2520			yFrac0, yFrac1 = 0, 1
2521		} else if sy1 > shMinus1 {
2522			sy0, sy1 = shMinus1, shMinus1
2523			yFrac0, yFrac1 = 1, 0
2524		}
2525		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2526
2527		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2528			sx := (float64(dx)+0.5)*xscale - 0.5
2529			sx0 := int32(sx)
2530			xFrac0 := sx - float64(sx0)
2531			xFrac1 := 1 - xFrac0
2532			sx1 := sx0 + 1
2533			if sx < 0 {
2534				sx0, sx1 = 0, 0
2535				xFrac0, xFrac1 = 0, 1
2536			} else if sx1 > swMinus1 {
2537				sx0, sx1 = swMinus1, swMinus1
2538				xFrac0, xFrac1 = 1, 0
2539			}
2540
2541			s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
2542			s00r := float64(s00ru)
2543			s00g := float64(s00gu)
2544			s00b := float64(s00bu)
2545			s00a := float64(s00au)
2546			s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
2547			s10r := float64(s10ru)
2548			s10g := float64(s10gu)
2549			s10b := float64(s10bu)
2550			s10a := float64(s10au)
2551			s10r = xFrac1*s00r + xFrac0*s10r
2552			s10g = xFrac1*s00g + xFrac0*s10g
2553			s10b = xFrac1*s00b + xFrac0*s10b
2554			s10a = xFrac1*s00a + xFrac0*s10a
2555			s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
2556			s01r := float64(s01ru)
2557			s01g := float64(s01gu)
2558			s01b := float64(s01bu)
2559			s01a := float64(s01au)
2560			s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
2561			s11r := float64(s11ru)
2562			s11g := float64(s11gu)
2563			s11b := float64(s11bu)
2564			s11a := float64(s11au)
2565			s11r = xFrac1*s01r + xFrac0*s11r
2566			s11g = xFrac1*s01g + xFrac0*s11g
2567			s11b = xFrac1*s01b + xFrac0*s11b
2568			s11a = xFrac1*s01a + xFrac0*s11a
2569			s11r = yFrac1*s10r + yFrac0*s11r
2570			s11g = yFrac1*s10g + yFrac0*s11g
2571			s11b = yFrac1*s10b + yFrac0*s11b
2572			s11a = yFrac1*s10a + yFrac0*s11a
2573			pr := uint32(s11r)
2574			pg := uint32(s11g)
2575			pb := uint32(s11b)
2576			pa := uint32(s11a)
2577			dst.Pix[d+0] = uint8(pr >> 8)
2578			dst.Pix[d+1] = uint8(pg >> 8)
2579			dst.Pix[d+2] = uint8(pb >> 8)
2580			dst.Pix[d+3] = uint8(pa >> 8)
2581		}
2582	}
2583}
2584
2585func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
2586	sw := int32(sr.Dx())
2587	sh := int32(sr.Dy())
2588	yscale := float64(sh) / float64(dr.Dy())
2589	xscale := float64(sw) / float64(dr.Dx())
2590	swMinus1, shMinus1 := sw-1, sh-1
2591	srcMask, smp := opts.SrcMask, opts.SrcMaskP
2592	dstMask, dmp := opts.DstMask, opts.DstMaskP
2593	dstColorRGBA64 := &color.RGBA64{}
2594	dstColor := color.Color(dstColorRGBA64)
2595
2596	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2597		sy := (float64(dy)+0.5)*yscale - 0.5
2598		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2599		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2600		// sx, below.
2601		sy0 := int32(sy)
2602		yFrac0 := sy - float64(sy0)
2603		yFrac1 := 1 - yFrac0
2604		sy1 := sy0 + 1
2605		if sy < 0 {
2606			sy0, sy1 = 0, 0
2607			yFrac0, yFrac1 = 0, 1
2608		} else if sy1 > shMinus1 {
2609			sy0, sy1 = shMinus1, shMinus1
2610			yFrac0, yFrac1 = 1, 0
2611		}
2612
2613		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
2614			sx := (float64(dx)+0.5)*xscale - 0.5
2615			sx0 := int32(sx)
2616			xFrac0 := sx - float64(sx0)
2617			xFrac1 := 1 - xFrac0
2618			sx1 := sx0 + 1
2619			if sx < 0 {
2620				sx0, sx1 = 0, 0
2621				xFrac0, xFrac1 = 0, 1
2622			} else if sx1 > swMinus1 {
2623				sx0, sx1 = swMinus1, swMinus1
2624				xFrac0, xFrac1 = 1, 0
2625			}
2626
2627			s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
2628			if srcMask != nil {
2629				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
2630				s00ru = s00ru * ma / 0xffff
2631				s00gu = s00gu * ma / 0xffff
2632				s00bu = s00bu * ma / 0xffff
2633				s00au = s00au * ma / 0xffff
2634			}
2635			s00r := float64(s00ru)
2636			s00g := float64(s00gu)
2637			s00b := float64(s00bu)
2638			s00a := float64(s00au)
2639			s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
2640			if srcMask != nil {
2641				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
2642				s10ru = s10ru * ma / 0xffff
2643				s10gu = s10gu * ma / 0xffff
2644				s10bu = s10bu * ma / 0xffff
2645				s10au = s10au * ma / 0xffff
2646			}
2647			s10r := float64(s10ru)
2648			s10g := float64(s10gu)
2649			s10b := float64(s10bu)
2650			s10a := float64(s10au)
2651			s10r = xFrac1*s00r + xFrac0*s10r
2652			s10g = xFrac1*s00g + xFrac0*s10g
2653			s10b = xFrac1*s00b + xFrac0*s10b
2654			s10a = xFrac1*s00a + xFrac0*s10a
2655			s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
2656			if srcMask != nil {
2657				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
2658				s01ru = s01ru * ma / 0xffff
2659				s01gu = s01gu * ma / 0xffff
2660				s01bu = s01bu * ma / 0xffff
2661				s01au = s01au * ma / 0xffff
2662			}
2663			s01r := float64(s01ru)
2664			s01g := float64(s01gu)
2665			s01b := float64(s01bu)
2666			s01a := float64(s01au)
2667			s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
2668			if srcMask != nil {
2669				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
2670				s11ru = s11ru * ma / 0xffff
2671				s11gu = s11gu * ma / 0xffff
2672				s11bu = s11bu * ma / 0xffff
2673				s11au = s11au * ma / 0xffff
2674			}
2675			s11r := float64(s11ru)
2676			s11g := float64(s11gu)
2677			s11b := float64(s11bu)
2678			s11a := float64(s11au)
2679			s11r = xFrac1*s01r + xFrac0*s11r
2680			s11g = xFrac1*s01g + xFrac0*s11g
2681			s11b = xFrac1*s01b + xFrac0*s11b
2682			s11a = xFrac1*s01a + xFrac0*s11a
2683			s11r = yFrac1*s10r + yFrac0*s11r
2684			s11g = yFrac1*s10g + yFrac0*s11g
2685			s11b = yFrac1*s10b + yFrac0*s11b
2686			s11a = yFrac1*s10a + yFrac0*s11a
2687			pr := uint32(s11r)
2688			pg := uint32(s11g)
2689			pb := uint32(s11b)
2690			pa := uint32(s11a)
2691			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
2692			if dstMask != nil {
2693				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
2694				pr = pr * ma / 0xffff
2695				pg = pg * ma / 0xffff
2696				pb = pb * ma / 0xffff
2697				pa = pa * ma / 0xffff
2698			}
2699			pa1 := 0xffff - pa
2700			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
2701			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
2702			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
2703			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
2704			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
2705		}
2706	}
2707}
2708
2709func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
2710	sw := int32(sr.Dx())
2711	sh := int32(sr.Dy())
2712	yscale := float64(sh) / float64(dr.Dy())
2713	xscale := float64(sw) / float64(dr.Dx())
2714	swMinus1, shMinus1 := sw-1, sh-1
2715	srcMask, smp := opts.SrcMask, opts.SrcMaskP
2716	dstMask, dmp := opts.DstMask, opts.DstMaskP
2717	dstColorRGBA64 := &color.RGBA64{}
2718	dstColor := color.Color(dstColorRGBA64)
2719
2720	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2721		sy := (float64(dy)+0.5)*yscale - 0.5
2722		// If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
2723		// we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
2724		// sx, below.
2725		sy0 := int32(sy)
2726		yFrac0 := sy - float64(sy0)
2727		yFrac1 := 1 - yFrac0
2728		sy1 := sy0 + 1
2729		if sy < 0 {
2730			sy0, sy1 = 0, 0
2731			yFrac0, yFrac1 = 0, 1
2732		} else if sy1 > shMinus1 {
2733			sy0, sy1 = shMinus1, shMinus1
2734			yFrac0, yFrac1 = 1, 0
2735		}
2736
2737		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
2738			sx := (float64(dx)+0.5)*xscale - 0.5
2739			sx0 := int32(sx)
2740			xFrac0 := sx - float64(sx0)
2741			xFrac1 := 1 - xFrac0
2742			sx1 := sx0 + 1
2743			if sx < 0 {
2744				sx0, sx1 = 0, 0
2745				xFrac0, xFrac1 = 0, 1
2746			} else if sx1 > swMinus1 {
2747				sx0, sx1 = swMinus1, swMinus1
2748				xFrac0, xFrac1 = 1, 0
2749			}
2750
2751			s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
2752			if srcMask != nil {
2753				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
2754				s00ru = s00ru * ma / 0xffff
2755				s00gu = s00gu * ma / 0xffff
2756				s00bu = s00bu * ma / 0xffff
2757				s00au = s00au * ma / 0xffff
2758			}
2759			s00r := float64(s00ru)
2760			s00g := float64(s00gu)
2761			s00b := float64(s00bu)
2762			s00a := float64(s00au)
2763			s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
2764			if srcMask != nil {
2765				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
2766				s10ru = s10ru * ma / 0xffff
2767				s10gu = s10gu * ma / 0xffff
2768				s10bu = s10bu * ma / 0xffff
2769				s10au = s10au * ma / 0xffff
2770			}
2771			s10r := float64(s10ru)
2772			s10g := float64(s10gu)
2773			s10b := float64(s10bu)
2774			s10a := float64(s10au)
2775			s10r = xFrac1*s00r + xFrac0*s10r
2776			s10g = xFrac1*s00g + xFrac0*s10g
2777			s10b = xFrac1*s00b + xFrac0*s10b
2778			s10a = xFrac1*s00a + xFrac0*s10a
2779			s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
2780			if srcMask != nil {
2781				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
2782				s01ru = s01ru * ma / 0xffff
2783				s01gu = s01gu * ma / 0xffff
2784				s01bu = s01bu * ma / 0xffff
2785				s01au = s01au * ma / 0xffff
2786			}
2787			s01r := float64(s01ru)
2788			s01g := float64(s01gu)
2789			s01b := float64(s01bu)
2790			s01a := float64(s01au)
2791			s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
2792			if srcMask != nil {
2793				_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
2794				s11ru = s11ru * ma / 0xffff
2795				s11gu = s11gu * ma / 0xffff
2796				s11bu = s11bu * ma / 0xffff
2797				s11au = s11au * ma / 0xffff
2798			}
2799			s11r := float64(s11ru)
2800			s11g := float64(s11gu)
2801			s11b := float64(s11bu)
2802			s11a := float64(s11au)
2803			s11r = xFrac1*s01r + xFrac0*s11r
2804			s11g = xFrac1*s01g + xFrac0*s11g
2805			s11b = xFrac1*s01b + xFrac0*s11b
2806			s11a = xFrac1*s01a + xFrac0*s11a
2807			s11r = yFrac1*s10r + yFrac0*s11r
2808			s11g = yFrac1*s10g + yFrac0*s11g
2809			s11b = yFrac1*s10b + yFrac0*s11b
2810			s11a = yFrac1*s10a + yFrac0*s11a
2811			pr := uint32(s11r)
2812			pg := uint32(s11g)
2813			pb := uint32(s11b)
2814			pa := uint32(s11a)
2815			if dstMask != nil {
2816				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
2817				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
2818				pr = pr * ma / 0xffff
2819				pg = pg * ma / 0xffff
2820				pb = pb * ma / 0xffff
2821				pa = pa * ma / 0xffff
2822				pa1 := 0xffff - ma
2823				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
2824				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
2825				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
2826				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
2827				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
2828			} else {
2829				dstColorRGBA64.R = uint16(pr)
2830				dstColorRGBA64.G = uint16(pg)
2831				dstColorRGBA64.B = uint16(pb)
2832				dstColorRGBA64.A = uint16(pa)
2833				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
2834			}
2835		}
2836	}
2837}
2838
2839func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
2840	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2841		dyf := float64(dr.Min.Y+int(dy)) + 0.5
2842		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2843		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2844			dxf := float64(dr.Min.X+int(dx)) + 0.5
2845			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
2846			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
2847			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
2848				continue
2849			}
2850
2851			sx -= 0.5
2852			sx0 := int(sx)
2853			xFrac0 := sx - float64(sx0)
2854			xFrac1 := 1 - xFrac0
2855			sx0 += bias.X
2856			sx1 := sx0 + 1
2857			if sx0 < sr.Min.X {
2858				sx0, sx1 = sr.Min.X, sr.Min.X
2859				xFrac0, xFrac1 = 0, 1
2860			} else if sx1 >= sr.Max.X {
2861				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
2862				xFrac0, xFrac1 = 1, 0
2863			}
2864
2865			sy -= 0.5
2866			sy0 := int(sy)
2867			yFrac0 := sy - float64(sy0)
2868			yFrac1 := 1 - yFrac0
2869			sy0 += bias.Y
2870			sy1 := sy0 + 1
2871			if sy0 < sr.Min.Y {
2872				sy0, sy1 = sr.Min.Y, sr.Min.Y
2873				yFrac0, yFrac1 = 0, 1
2874			} else if sy1 >= sr.Max.Y {
2875				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
2876				yFrac0, yFrac1 = 1, 0
2877			}
2878
2879			s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
2880			s00ru := uint32(src.Pix[s00i]) * 0x101
2881			s00r := float64(s00ru)
2882			s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
2883			s10ru := uint32(src.Pix[s10i]) * 0x101
2884			s10r := float64(s10ru)
2885			s10r = xFrac1*s00r + xFrac0*s10r
2886			s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
2887			s01ru := uint32(src.Pix[s01i]) * 0x101
2888			s01r := float64(s01ru)
2889			s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
2890			s11ru := uint32(src.Pix[s11i]) * 0x101
2891			s11r := float64(s11ru)
2892			s11r = xFrac1*s01r + xFrac0*s11r
2893			s11r = yFrac1*s10r + yFrac0*s11r
2894			pr := uint32(s11r)
2895			out := uint8(pr >> 8)
2896			dst.Pix[d+0] = out
2897			dst.Pix[d+1] = out
2898			dst.Pix[d+2] = out
2899			dst.Pix[d+3] = 0xff
2900		}
2901	}
2902}
2903
2904func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
2905	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
2906		dyf := float64(dr.Min.Y+int(dy)) + 0.5
2907		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
2908		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
2909			dxf := float64(dr.Min.X+int(dx)) + 0.5
2910			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
2911			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
2912			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
2913				continue
2914			}
2915
2916			sx -= 0.5
2917			sx0 := int(sx)
2918			xFrac0 := sx - float64(sx0)
2919			xFrac1 := 1 - xFrac0
2920			sx0 += bias.X
2921			sx1 := sx0 + 1
2922			if sx0 < sr.Min.X {
2923				sx0, sx1 = sr.Min.X, sr.Min.X
2924				xFrac0, xFrac1 = 0, 1
2925			} else if sx1 >= sr.Max.X {
2926				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
2927				xFrac0, xFrac1 = 1, 0
2928			}
2929
2930			sy -= 0.5
2931			sy0 := int(sy)
2932			yFrac0 := sy - float64(sy0)
2933			yFrac1 := 1 - yFrac0
2934			sy0 += bias.Y
2935			sy1 := sy0 + 1
2936			if sy0 < sr.Min.Y {
2937				sy0, sy1 = sr.Min.Y, sr.Min.Y
2938				yFrac0, yFrac1 = 0, 1
2939			} else if sy1 >= sr.Max.Y {
2940				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
2941				yFrac0, yFrac1 = 1, 0
2942			}
2943
2944			s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
2945			s00au := uint32(src.Pix[s00i+3]) * 0x101
2946			s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
2947			s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
2948			s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
2949			s00r := float64(s00ru)
2950			s00g := float64(s00gu)
2951			s00b := float64(s00bu)
2952			s00a := float64(s00au)
2953			s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
2954			s10au := uint32(src.Pix[s10i+3]) * 0x101
2955			s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
2956			s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
2957			s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
2958			s10r := float64(s10ru)
2959			s10g := float64(s10gu)
2960			s10b := float64(s10bu)
2961			s10a := float64(s10au)
2962			s10r = xFrac1*s00r + xFrac0*s10r
2963			s10g = xFrac1*s00g + xFrac0*s10g
2964			s10b = xFrac1*s00b + xFrac0*s10b
2965			s10a = xFrac1*s00a + xFrac0*s10a
2966			s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
2967			s01au := uint32(src.Pix[s01i+3]) * 0x101
2968			s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
2969			s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
2970			s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
2971			s01r := float64(s01ru)
2972			s01g := float64(s01gu)
2973			s01b := float64(s01bu)
2974			s01a := float64(s01au)
2975			s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
2976			s11au := uint32(src.Pix[s11i+3]) * 0x101
2977			s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
2978			s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
2979			s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
2980			s11r := float64(s11ru)
2981			s11g := float64(s11gu)
2982			s11b := float64(s11bu)
2983			s11a := float64(s11au)
2984			s11r = xFrac1*s01r + xFrac0*s11r
2985			s11g = xFrac1*s01g + xFrac0*s11g
2986			s11b = xFrac1*s01b + xFrac0*s11b
2987			s11a = xFrac1*s01a + xFrac0*s11a
2988			s11r = yFrac1*s10r + yFrac0*s11r
2989			s11g = yFrac1*s10g + yFrac0*s11g
2990			s11b = yFrac1*s10b + yFrac0*s11b
2991			s11a = yFrac1*s10a + yFrac0*s11a
2992			pr := uint32(s11r)
2993			pg := uint32(s11g)
2994			pb := uint32(s11b)
2995			pa := uint32(s11a)
2996			pa1 := (0xffff - pa) * 0x101
2997			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
2998			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
2999			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
3000			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
3001		}
3002	}
3003}
3004
3005func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
3006	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3007		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3008		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3009		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3010			dxf := float64(dr.Min.X+int(dx)) + 0.5
3011			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3012			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3013			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3014				continue
3015			}
3016
3017			sx -= 0.5
3018			sx0 := int(sx)
3019			xFrac0 := sx - float64(sx0)
3020			xFrac1 := 1 - xFrac0
3021			sx0 += bias.X
3022			sx1 := sx0 + 1
3023			if sx0 < sr.Min.X {
3024				sx0, sx1 = sr.Min.X, sr.Min.X
3025				xFrac0, xFrac1 = 0, 1
3026			} else if sx1 >= sr.Max.X {
3027				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3028				xFrac0, xFrac1 = 1, 0
3029			}
3030
3031			sy -= 0.5
3032			sy0 := int(sy)
3033			yFrac0 := sy - float64(sy0)
3034			yFrac1 := 1 - yFrac0
3035			sy0 += bias.Y
3036			sy1 := sy0 + 1
3037			if sy0 < sr.Min.Y {
3038				sy0, sy1 = sr.Min.Y, sr.Min.Y
3039				yFrac0, yFrac1 = 0, 1
3040			} else if sy1 >= sr.Max.Y {
3041				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3042				yFrac0, yFrac1 = 1, 0
3043			}
3044
3045			s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3046			s00au := uint32(src.Pix[s00i+3]) * 0x101
3047			s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
3048			s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
3049			s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
3050			s00r := float64(s00ru)
3051			s00g := float64(s00gu)
3052			s00b := float64(s00bu)
3053			s00a := float64(s00au)
3054			s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3055			s10au := uint32(src.Pix[s10i+3]) * 0x101
3056			s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
3057			s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
3058			s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
3059			s10r := float64(s10ru)
3060			s10g := float64(s10gu)
3061			s10b := float64(s10bu)
3062			s10a := float64(s10au)
3063			s10r = xFrac1*s00r + xFrac0*s10r
3064			s10g = xFrac1*s00g + xFrac0*s10g
3065			s10b = xFrac1*s00b + xFrac0*s10b
3066			s10a = xFrac1*s00a + xFrac0*s10a
3067			s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3068			s01au := uint32(src.Pix[s01i+3]) * 0x101
3069			s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
3070			s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
3071			s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
3072			s01r := float64(s01ru)
3073			s01g := float64(s01gu)
3074			s01b := float64(s01bu)
3075			s01a := float64(s01au)
3076			s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3077			s11au := uint32(src.Pix[s11i+3]) * 0x101
3078			s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
3079			s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
3080			s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
3081			s11r := float64(s11ru)
3082			s11g := float64(s11gu)
3083			s11b := float64(s11bu)
3084			s11a := float64(s11au)
3085			s11r = xFrac1*s01r + xFrac0*s11r
3086			s11g = xFrac1*s01g + xFrac0*s11g
3087			s11b = xFrac1*s01b + xFrac0*s11b
3088			s11a = xFrac1*s01a + xFrac0*s11a
3089			s11r = yFrac1*s10r + yFrac0*s11r
3090			s11g = yFrac1*s10g + yFrac0*s11g
3091			s11b = yFrac1*s10b + yFrac0*s11b
3092			s11a = yFrac1*s10a + yFrac0*s11a
3093			pr := uint32(s11r)
3094			pg := uint32(s11g)
3095			pb := uint32(s11b)
3096			pa := uint32(s11a)
3097			dst.Pix[d+0] = uint8(pr >> 8)
3098			dst.Pix[d+1] = uint8(pg >> 8)
3099			dst.Pix[d+2] = uint8(pb >> 8)
3100			dst.Pix[d+3] = uint8(pa >> 8)
3101		}
3102	}
3103}
3104
3105func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
3106	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3107		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3108		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3109		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3110			dxf := float64(dr.Min.X+int(dx)) + 0.5
3111			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3112			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3113			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3114				continue
3115			}
3116
3117			sx -= 0.5
3118			sx0 := int(sx)
3119			xFrac0 := sx - float64(sx0)
3120			xFrac1 := 1 - xFrac0
3121			sx0 += bias.X
3122			sx1 := sx0 + 1
3123			if sx0 < sr.Min.X {
3124				sx0, sx1 = sr.Min.X, sr.Min.X
3125				xFrac0, xFrac1 = 0, 1
3126			} else if sx1 >= sr.Max.X {
3127				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3128				xFrac0, xFrac1 = 1, 0
3129			}
3130
3131			sy -= 0.5
3132			sy0 := int(sy)
3133			yFrac0 := sy - float64(sy0)
3134			yFrac1 := 1 - yFrac0
3135			sy0 += bias.Y
3136			sy1 := sy0 + 1
3137			if sy0 < sr.Min.Y {
3138				sy0, sy1 = sr.Min.Y, sr.Min.Y
3139				yFrac0, yFrac1 = 0, 1
3140			} else if sy1 >= sr.Max.Y {
3141				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3142				yFrac0, yFrac1 = 1, 0
3143			}
3144
3145			s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3146			s00ru := uint32(src.Pix[s00i+0]) * 0x101
3147			s00gu := uint32(src.Pix[s00i+1]) * 0x101
3148			s00bu := uint32(src.Pix[s00i+2]) * 0x101
3149			s00au := uint32(src.Pix[s00i+3]) * 0x101
3150			s00r := float64(s00ru)
3151			s00g := float64(s00gu)
3152			s00b := float64(s00bu)
3153			s00a := float64(s00au)
3154			s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3155			s10ru := uint32(src.Pix[s10i+0]) * 0x101
3156			s10gu := uint32(src.Pix[s10i+1]) * 0x101
3157			s10bu := uint32(src.Pix[s10i+2]) * 0x101
3158			s10au := uint32(src.Pix[s10i+3]) * 0x101
3159			s10r := float64(s10ru)
3160			s10g := float64(s10gu)
3161			s10b := float64(s10bu)
3162			s10a := float64(s10au)
3163			s10r = xFrac1*s00r + xFrac0*s10r
3164			s10g = xFrac1*s00g + xFrac0*s10g
3165			s10b = xFrac1*s00b + xFrac0*s10b
3166			s10a = xFrac1*s00a + xFrac0*s10a
3167			s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3168			s01ru := uint32(src.Pix[s01i+0]) * 0x101
3169			s01gu := uint32(src.Pix[s01i+1]) * 0x101
3170			s01bu := uint32(src.Pix[s01i+2]) * 0x101
3171			s01au := uint32(src.Pix[s01i+3]) * 0x101
3172			s01r := float64(s01ru)
3173			s01g := float64(s01gu)
3174			s01b := float64(s01bu)
3175			s01a := float64(s01au)
3176			s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3177			s11ru := uint32(src.Pix[s11i+0]) * 0x101
3178			s11gu := uint32(src.Pix[s11i+1]) * 0x101
3179			s11bu := uint32(src.Pix[s11i+2]) * 0x101
3180			s11au := uint32(src.Pix[s11i+3]) * 0x101
3181			s11r := float64(s11ru)
3182			s11g := float64(s11gu)
3183			s11b := float64(s11bu)
3184			s11a := float64(s11au)
3185			s11r = xFrac1*s01r + xFrac0*s11r
3186			s11g = xFrac1*s01g + xFrac0*s11g
3187			s11b = xFrac1*s01b + xFrac0*s11b
3188			s11a = xFrac1*s01a + xFrac0*s11a
3189			s11r = yFrac1*s10r + yFrac0*s11r
3190			s11g = yFrac1*s10g + yFrac0*s11g
3191			s11b = yFrac1*s10b + yFrac0*s11b
3192			s11a = yFrac1*s10a + yFrac0*s11a
3193			pr := uint32(s11r)
3194			pg := uint32(s11g)
3195			pb := uint32(s11b)
3196			pa := uint32(s11a)
3197			pa1 := (0xffff - pa) * 0x101
3198			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
3199			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
3200			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
3201			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
3202		}
3203	}
3204}
3205
3206func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
3207	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3208		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3209		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3210		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3211			dxf := float64(dr.Min.X+int(dx)) + 0.5
3212			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3213			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3214			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3215				continue
3216			}
3217
3218			sx -= 0.5
3219			sx0 := int(sx)
3220			xFrac0 := sx - float64(sx0)
3221			xFrac1 := 1 - xFrac0
3222			sx0 += bias.X
3223			sx1 := sx0 + 1
3224			if sx0 < sr.Min.X {
3225				sx0, sx1 = sr.Min.X, sr.Min.X
3226				xFrac0, xFrac1 = 0, 1
3227			} else if sx1 >= sr.Max.X {
3228				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3229				xFrac0, xFrac1 = 1, 0
3230			}
3231
3232			sy -= 0.5
3233			sy0 := int(sy)
3234			yFrac0 := sy - float64(sy0)
3235			yFrac1 := 1 - yFrac0
3236			sy0 += bias.Y
3237			sy1 := sy0 + 1
3238			if sy0 < sr.Min.Y {
3239				sy0, sy1 = sr.Min.Y, sr.Min.Y
3240				yFrac0, yFrac1 = 0, 1
3241			} else if sy1 >= sr.Max.Y {
3242				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3243				yFrac0, yFrac1 = 1, 0
3244			}
3245
3246			s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3247			s00ru := uint32(src.Pix[s00i+0]) * 0x101
3248			s00gu := uint32(src.Pix[s00i+1]) * 0x101
3249			s00bu := uint32(src.Pix[s00i+2]) * 0x101
3250			s00au := uint32(src.Pix[s00i+3]) * 0x101
3251			s00r := float64(s00ru)
3252			s00g := float64(s00gu)
3253			s00b := float64(s00bu)
3254			s00a := float64(s00au)
3255			s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3256			s10ru := uint32(src.Pix[s10i+0]) * 0x101
3257			s10gu := uint32(src.Pix[s10i+1]) * 0x101
3258			s10bu := uint32(src.Pix[s10i+2]) * 0x101
3259			s10au := uint32(src.Pix[s10i+3]) * 0x101
3260			s10r := float64(s10ru)
3261			s10g := float64(s10gu)
3262			s10b := float64(s10bu)
3263			s10a := float64(s10au)
3264			s10r = xFrac1*s00r + xFrac0*s10r
3265			s10g = xFrac1*s00g + xFrac0*s10g
3266			s10b = xFrac1*s00b + xFrac0*s10b
3267			s10a = xFrac1*s00a + xFrac0*s10a
3268			s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
3269			s01ru := uint32(src.Pix[s01i+0]) * 0x101
3270			s01gu := uint32(src.Pix[s01i+1]) * 0x101
3271			s01bu := uint32(src.Pix[s01i+2]) * 0x101
3272			s01au := uint32(src.Pix[s01i+3]) * 0x101
3273			s01r := float64(s01ru)
3274			s01g := float64(s01gu)
3275			s01b := float64(s01bu)
3276			s01a := float64(s01au)
3277			s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
3278			s11ru := uint32(src.Pix[s11i+0]) * 0x101
3279			s11gu := uint32(src.Pix[s11i+1]) * 0x101
3280			s11bu := uint32(src.Pix[s11i+2]) * 0x101
3281			s11au := uint32(src.Pix[s11i+3]) * 0x101
3282			s11r := float64(s11ru)
3283			s11g := float64(s11gu)
3284			s11b := float64(s11bu)
3285			s11a := float64(s11au)
3286			s11r = xFrac1*s01r + xFrac0*s11r
3287			s11g = xFrac1*s01g + xFrac0*s11g
3288			s11b = xFrac1*s01b + xFrac0*s11b
3289			s11a = xFrac1*s01a + xFrac0*s11a
3290			s11r = yFrac1*s10r + yFrac0*s11r
3291			s11g = yFrac1*s10g + yFrac0*s11g
3292			s11b = yFrac1*s10b + yFrac0*s11b
3293			s11a = yFrac1*s10a + yFrac0*s11a
3294			pr := uint32(s11r)
3295			pg := uint32(s11g)
3296			pb := uint32(s11b)
3297			pa := uint32(s11a)
3298			dst.Pix[d+0] = uint8(pr >> 8)
3299			dst.Pix[d+1] = uint8(pg >> 8)
3300			dst.Pix[d+2] = uint8(pb >> 8)
3301			dst.Pix[d+3] = uint8(pa >> 8)
3302		}
3303	}
3304}
3305
3306func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
3307	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3308		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3309		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3310		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3311			dxf := float64(dr.Min.X+int(dx)) + 0.5
3312			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3313			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3314			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3315				continue
3316			}
3317
3318			sx -= 0.5
3319			sx0 := int(sx)
3320			xFrac0 := sx - float64(sx0)
3321			xFrac1 := 1 - xFrac0
3322			sx0 += bias.X
3323			sx1 := sx0 + 1
3324			if sx0 < sr.Min.X {
3325				sx0, sx1 = sr.Min.X, sr.Min.X
3326				xFrac0, xFrac1 = 0, 1
3327			} else if sx1 >= sr.Max.X {
3328				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3329				xFrac0, xFrac1 = 1, 0
3330			}
3331
3332			sy -= 0.5
3333			sy0 := int(sy)
3334			yFrac0 := sy - float64(sy0)
3335			yFrac1 := 1 - yFrac0
3336			sy0 += bias.Y
3337			sy1 := sy0 + 1
3338			if sy0 < sr.Min.Y {
3339				sy0, sy1 = sr.Min.Y, sr.Min.Y
3340				yFrac0, yFrac1 = 0, 1
3341			} else if sy1 >= sr.Max.Y {
3342				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3343				yFrac0, yFrac1 = 1, 0
3344			}
3345
3346			s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3347			s00j := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
3348
3349			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3350			s00yy1 := int(src.Y[s00i]) * 0x10101
3351			s00cb1 := int(src.Cb[s00j]) - 128
3352			s00cr1 := int(src.Cr[s00j]) - 128
3353			s00ru := (s00yy1 + 91881*s00cr1) >> 8
3354			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
3355			s00bu := (s00yy1 + 116130*s00cb1) >> 8
3356			if s00ru < 0 {
3357				s00ru = 0
3358			} else if s00ru > 0xffff {
3359				s00ru = 0xffff
3360			}
3361			if s00gu < 0 {
3362				s00gu = 0
3363			} else if s00gu > 0xffff {
3364				s00gu = 0xffff
3365			}
3366			if s00bu < 0 {
3367				s00bu = 0
3368			} else if s00bu > 0xffff {
3369				s00bu = 0xffff
3370			}
3371
3372			s00r := float64(s00ru)
3373			s00g := float64(s00gu)
3374			s00b := float64(s00bu)
3375			s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3376			s10j := (sy0-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
3377
3378			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3379			s10yy1 := int(src.Y[s10i]) * 0x10101
3380			s10cb1 := int(src.Cb[s10j]) - 128
3381			s10cr1 := int(src.Cr[s10j]) - 128
3382			s10ru := (s10yy1 + 91881*s10cr1) >> 8
3383			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
3384			s10bu := (s10yy1 + 116130*s10cb1) >> 8
3385			if s10ru < 0 {
3386				s10ru = 0
3387			} else if s10ru > 0xffff {
3388				s10ru = 0xffff
3389			}
3390			if s10gu < 0 {
3391				s10gu = 0
3392			} else if s10gu > 0xffff {
3393				s10gu = 0xffff
3394			}
3395			if s10bu < 0 {
3396				s10bu = 0
3397			} else if s10bu > 0xffff {
3398				s10bu = 0xffff
3399			}
3400
3401			s10r := float64(s10ru)
3402			s10g := float64(s10gu)
3403			s10b := float64(s10bu)
3404			s10r = xFrac1*s00r + xFrac0*s10r
3405			s10g = xFrac1*s00g + xFrac0*s10g
3406			s10b = xFrac1*s00b + xFrac0*s10b
3407			s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3408			s01j := (sy1-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
3409
3410			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3411			s01yy1 := int(src.Y[s01i]) * 0x10101
3412			s01cb1 := int(src.Cb[s01j]) - 128
3413			s01cr1 := int(src.Cr[s01j]) - 128
3414			s01ru := (s01yy1 + 91881*s01cr1) >> 8
3415			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
3416			s01bu := (s01yy1 + 116130*s01cb1) >> 8
3417			if s01ru < 0 {
3418				s01ru = 0
3419			} else if s01ru > 0xffff {
3420				s01ru = 0xffff
3421			}
3422			if s01gu < 0 {
3423				s01gu = 0
3424			} else if s01gu > 0xffff {
3425				s01gu = 0xffff
3426			}
3427			if s01bu < 0 {
3428				s01bu = 0
3429			} else if s01bu > 0xffff {
3430				s01bu = 0xffff
3431			}
3432
3433			s01r := float64(s01ru)
3434			s01g := float64(s01gu)
3435			s01b := float64(s01bu)
3436			s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3437			s11j := (sy1-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
3438
3439			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3440			s11yy1 := int(src.Y[s11i]) * 0x10101
3441			s11cb1 := int(src.Cb[s11j]) - 128
3442			s11cr1 := int(src.Cr[s11j]) - 128
3443			s11ru := (s11yy1 + 91881*s11cr1) >> 8
3444			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
3445			s11bu := (s11yy1 + 116130*s11cb1) >> 8
3446			if s11ru < 0 {
3447				s11ru = 0
3448			} else if s11ru > 0xffff {
3449				s11ru = 0xffff
3450			}
3451			if s11gu < 0 {
3452				s11gu = 0
3453			} else if s11gu > 0xffff {
3454				s11gu = 0xffff
3455			}
3456			if s11bu < 0 {
3457				s11bu = 0
3458			} else if s11bu > 0xffff {
3459				s11bu = 0xffff
3460			}
3461
3462			s11r := float64(s11ru)
3463			s11g := float64(s11gu)
3464			s11b := float64(s11bu)
3465			s11r = xFrac1*s01r + xFrac0*s11r
3466			s11g = xFrac1*s01g + xFrac0*s11g
3467			s11b = xFrac1*s01b + xFrac0*s11b
3468			s11r = yFrac1*s10r + yFrac0*s11r
3469			s11g = yFrac1*s10g + yFrac0*s11g
3470			s11b = yFrac1*s10b + yFrac0*s11b
3471			pr := uint32(s11r)
3472			pg := uint32(s11g)
3473			pb := uint32(s11b)
3474			dst.Pix[d+0] = uint8(pr >> 8)
3475			dst.Pix[d+1] = uint8(pg >> 8)
3476			dst.Pix[d+2] = uint8(pb >> 8)
3477			dst.Pix[d+3] = 0xff
3478		}
3479	}
3480}
3481
3482func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
3483	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3484		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3485		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3486		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3487			dxf := float64(dr.Min.X+int(dx)) + 0.5
3488			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3489			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3490			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3491				continue
3492			}
3493
3494			sx -= 0.5
3495			sx0 := int(sx)
3496			xFrac0 := sx - float64(sx0)
3497			xFrac1 := 1 - xFrac0
3498			sx0 += bias.X
3499			sx1 := sx0 + 1
3500			if sx0 < sr.Min.X {
3501				sx0, sx1 = sr.Min.X, sr.Min.X
3502				xFrac0, xFrac1 = 0, 1
3503			} else if sx1 >= sr.Max.X {
3504				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3505				xFrac0, xFrac1 = 1, 0
3506			}
3507
3508			sy -= 0.5
3509			sy0 := int(sy)
3510			yFrac0 := sy - float64(sy0)
3511			yFrac1 := 1 - yFrac0
3512			sy0 += bias.Y
3513			sy1 := sy0 + 1
3514			if sy0 < sr.Min.Y {
3515				sy0, sy1 = sr.Min.Y, sr.Min.Y
3516				yFrac0, yFrac1 = 0, 1
3517			} else if sy1 >= sr.Max.Y {
3518				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3519				yFrac0, yFrac1 = 1, 0
3520			}
3521
3522			s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3523			s00j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
3524
3525			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3526			s00yy1 := int(src.Y[s00i]) * 0x10101
3527			s00cb1 := int(src.Cb[s00j]) - 128
3528			s00cr1 := int(src.Cr[s00j]) - 128
3529			s00ru := (s00yy1 + 91881*s00cr1) >> 8
3530			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
3531			s00bu := (s00yy1 + 116130*s00cb1) >> 8
3532			if s00ru < 0 {
3533				s00ru = 0
3534			} else if s00ru > 0xffff {
3535				s00ru = 0xffff
3536			}
3537			if s00gu < 0 {
3538				s00gu = 0
3539			} else if s00gu > 0xffff {
3540				s00gu = 0xffff
3541			}
3542			if s00bu < 0 {
3543				s00bu = 0
3544			} else if s00bu > 0xffff {
3545				s00bu = 0xffff
3546			}
3547
3548			s00r := float64(s00ru)
3549			s00g := float64(s00gu)
3550			s00b := float64(s00bu)
3551			s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3552			s10j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
3553
3554			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3555			s10yy1 := int(src.Y[s10i]) * 0x10101
3556			s10cb1 := int(src.Cb[s10j]) - 128
3557			s10cr1 := int(src.Cr[s10j]) - 128
3558			s10ru := (s10yy1 + 91881*s10cr1) >> 8
3559			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
3560			s10bu := (s10yy1 + 116130*s10cb1) >> 8
3561			if s10ru < 0 {
3562				s10ru = 0
3563			} else if s10ru > 0xffff {
3564				s10ru = 0xffff
3565			}
3566			if s10gu < 0 {
3567				s10gu = 0
3568			} else if s10gu > 0xffff {
3569				s10gu = 0xffff
3570			}
3571			if s10bu < 0 {
3572				s10bu = 0
3573			} else if s10bu > 0xffff {
3574				s10bu = 0xffff
3575			}
3576
3577			s10r := float64(s10ru)
3578			s10g := float64(s10gu)
3579			s10b := float64(s10bu)
3580			s10r = xFrac1*s00r + xFrac0*s10r
3581			s10g = xFrac1*s00g + xFrac0*s10g
3582			s10b = xFrac1*s00b + xFrac0*s10b
3583			s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3584			s01j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
3585
3586			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3587			s01yy1 := int(src.Y[s01i]) * 0x10101
3588			s01cb1 := int(src.Cb[s01j]) - 128
3589			s01cr1 := int(src.Cr[s01j]) - 128
3590			s01ru := (s01yy1 + 91881*s01cr1) >> 8
3591			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
3592			s01bu := (s01yy1 + 116130*s01cb1) >> 8
3593			if s01ru < 0 {
3594				s01ru = 0
3595			} else if s01ru > 0xffff {
3596				s01ru = 0xffff
3597			}
3598			if s01gu < 0 {
3599				s01gu = 0
3600			} else if s01gu > 0xffff {
3601				s01gu = 0xffff
3602			}
3603			if s01bu < 0 {
3604				s01bu = 0
3605			} else if s01bu > 0xffff {
3606				s01bu = 0xffff
3607			}
3608
3609			s01r := float64(s01ru)
3610			s01g := float64(s01gu)
3611			s01b := float64(s01bu)
3612			s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3613			s11j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
3614
3615			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3616			s11yy1 := int(src.Y[s11i]) * 0x10101
3617			s11cb1 := int(src.Cb[s11j]) - 128
3618			s11cr1 := int(src.Cr[s11j]) - 128
3619			s11ru := (s11yy1 + 91881*s11cr1) >> 8
3620			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
3621			s11bu := (s11yy1 + 116130*s11cb1) >> 8
3622			if s11ru < 0 {
3623				s11ru = 0
3624			} else if s11ru > 0xffff {
3625				s11ru = 0xffff
3626			}
3627			if s11gu < 0 {
3628				s11gu = 0
3629			} else if s11gu > 0xffff {
3630				s11gu = 0xffff
3631			}
3632			if s11bu < 0 {
3633				s11bu = 0
3634			} else if s11bu > 0xffff {
3635				s11bu = 0xffff
3636			}
3637
3638			s11r := float64(s11ru)
3639			s11g := float64(s11gu)
3640			s11b := float64(s11bu)
3641			s11r = xFrac1*s01r + xFrac0*s11r
3642			s11g = xFrac1*s01g + xFrac0*s11g
3643			s11b = xFrac1*s01b + xFrac0*s11b
3644			s11r = yFrac1*s10r + yFrac0*s11r
3645			s11g = yFrac1*s10g + yFrac0*s11g
3646			s11b = yFrac1*s10b + yFrac0*s11b
3647			pr := uint32(s11r)
3648			pg := uint32(s11g)
3649			pb := uint32(s11b)
3650			dst.Pix[d+0] = uint8(pr >> 8)
3651			dst.Pix[d+1] = uint8(pg >> 8)
3652			dst.Pix[d+2] = uint8(pb >> 8)
3653			dst.Pix[d+3] = 0xff
3654		}
3655	}
3656}
3657
3658func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
3659	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3660		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3661		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3662		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3663			dxf := float64(dr.Min.X+int(dx)) + 0.5
3664			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3665			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3666			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3667				continue
3668			}
3669
3670			sx -= 0.5
3671			sx0 := int(sx)
3672			xFrac0 := sx - float64(sx0)
3673			xFrac1 := 1 - xFrac0
3674			sx0 += bias.X
3675			sx1 := sx0 + 1
3676			if sx0 < sr.Min.X {
3677				sx0, sx1 = sr.Min.X, sr.Min.X
3678				xFrac0, xFrac1 = 0, 1
3679			} else if sx1 >= sr.Max.X {
3680				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3681				xFrac0, xFrac1 = 1, 0
3682			}
3683
3684			sy -= 0.5
3685			sy0 := int(sy)
3686			yFrac0 := sy - float64(sy0)
3687			yFrac1 := 1 - yFrac0
3688			sy0 += bias.Y
3689			sy1 := sy0 + 1
3690			if sy0 < sr.Min.Y {
3691				sy0, sy1 = sr.Min.Y, sr.Min.Y
3692				yFrac0, yFrac1 = 0, 1
3693			} else if sy1 >= sr.Max.Y {
3694				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3695				yFrac0, yFrac1 = 1, 0
3696			}
3697
3698			s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3699			s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
3700
3701			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3702			s00yy1 := int(src.Y[s00i]) * 0x10101
3703			s00cb1 := int(src.Cb[s00j]) - 128
3704			s00cr1 := int(src.Cr[s00j]) - 128
3705			s00ru := (s00yy1 + 91881*s00cr1) >> 8
3706			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
3707			s00bu := (s00yy1 + 116130*s00cb1) >> 8
3708			if s00ru < 0 {
3709				s00ru = 0
3710			} else if s00ru > 0xffff {
3711				s00ru = 0xffff
3712			}
3713			if s00gu < 0 {
3714				s00gu = 0
3715			} else if s00gu > 0xffff {
3716				s00gu = 0xffff
3717			}
3718			if s00bu < 0 {
3719				s00bu = 0
3720			} else if s00bu > 0xffff {
3721				s00bu = 0xffff
3722			}
3723
3724			s00r := float64(s00ru)
3725			s00g := float64(s00gu)
3726			s00b := float64(s00bu)
3727			s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3728			s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
3729
3730			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3731			s10yy1 := int(src.Y[s10i]) * 0x10101
3732			s10cb1 := int(src.Cb[s10j]) - 128
3733			s10cr1 := int(src.Cr[s10j]) - 128
3734			s10ru := (s10yy1 + 91881*s10cr1) >> 8
3735			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
3736			s10bu := (s10yy1 + 116130*s10cb1) >> 8
3737			if s10ru < 0 {
3738				s10ru = 0
3739			} else if s10ru > 0xffff {
3740				s10ru = 0xffff
3741			}
3742			if s10gu < 0 {
3743				s10gu = 0
3744			} else if s10gu > 0xffff {
3745				s10gu = 0xffff
3746			}
3747			if s10bu < 0 {
3748				s10bu = 0
3749			} else if s10bu > 0xffff {
3750				s10bu = 0xffff
3751			}
3752
3753			s10r := float64(s10ru)
3754			s10g := float64(s10gu)
3755			s10b := float64(s10bu)
3756			s10r = xFrac1*s00r + xFrac0*s10r
3757			s10g = xFrac1*s00g + xFrac0*s10g
3758			s10b = xFrac1*s00b + xFrac0*s10b
3759			s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3760			s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
3761
3762			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3763			s01yy1 := int(src.Y[s01i]) * 0x10101
3764			s01cb1 := int(src.Cb[s01j]) - 128
3765			s01cr1 := int(src.Cr[s01j]) - 128
3766			s01ru := (s01yy1 + 91881*s01cr1) >> 8
3767			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
3768			s01bu := (s01yy1 + 116130*s01cb1) >> 8
3769			if s01ru < 0 {
3770				s01ru = 0
3771			} else if s01ru > 0xffff {
3772				s01ru = 0xffff
3773			}
3774			if s01gu < 0 {
3775				s01gu = 0
3776			} else if s01gu > 0xffff {
3777				s01gu = 0xffff
3778			}
3779			if s01bu < 0 {
3780				s01bu = 0
3781			} else if s01bu > 0xffff {
3782				s01bu = 0xffff
3783			}
3784
3785			s01r := float64(s01ru)
3786			s01g := float64(s01gu)
3787			s01b := float64(s01bu)
3788			s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3789			s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
3790
3791			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3792			s11yy1 := int(src.Y[s11i]) * 0x10101
3793			s11cb1 := int(src.Cb[s11j]) - 128
3794			s11cr1 := int(src.Cr[s11j]) - 128
3795			s11ru := (s11yy1 + 91881*s11cr1) >> 8
3796			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
3797			s11bu := (s11yy1 + 116130*s11cb1) >> 8
3798			if s11ru < 0 {
3799				s11ru = 0
3800			} else if s11ru > 0xffff {
3801				s11ru = 0xffff
3802			}
3803			if s11gu < 0 {
3804				s11gu = 0
3805			} else if s11gu > 0xffff {
3806				s11gu = 0xffff
3807			}
3808			if s11bu < 0 {
3809				s11bu = 0
3810			} else if s11bu > 0xffff {
3811				s11bu = 0xffff
3812			}
3813
3814			s11r := float64(s11ru)
3815			s11g := float64(s11gu)
3816			s11b := float64(s11bu)
3817			s11r = xFrac1*s01r + xFrac0*s11r
3818			s11g = xFrac1*s01g + xFrac0*s11g
3819			s11b = xFrac1*s01b + xFrac0*s11b
3820			s11r = yFrac1*s10r + yFrac0*s11r
3821			s11g = yFrac1*s10g + yFrac0*s11g
3822			s11b = yFrac1*s10b + yFrac0*s11b
3823			pr := uint32(s11r)
3824			pg := uint32(s11g)
3825			pb := uint32(s11b)
3826			dst.Pix[d+0] = uint8(pr >> 8)
3827			dst.Pix[d+1] = uint8(pg >> 8)
3828			dst.Pix[d+2] = uint8(pb >> 8)
3829			dst.Pix[d+3] = 0xff
3830		}
3831	}
3832}
3833
3834func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
3835	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
3836		dyf := float64(dr.Min.Y+int(dy)) + 0.5
3837		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
3838		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
3839			dxf := float64(dr.Min.X+int(dx)) + 0.5
3840			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
3841			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
3842			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
3843				continue
3844			}
3845
3846			sx -= 0.5
3847			sx0 := int(sx)
3848			xFrac0 := sx - float64(sx0)
3849			xFrac1 := 1 - xFrac0
3850			sx0 += bias.X
3851			sx1 := sx0 + 1
3852			if sx0 < sr.Min.X {
3853				sx0, sx1 = sr.Min.X, sr.Min.X
3854				xFrac0, xFrac1 = 0, 1
3855			} else if sx1 >= sr.Max.X {
3856				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
3857				xFrac0, xFrac1 = 1, 0
3858			}
3859
3860			sy -= 0.5
3861			sy0 := int(sy)
3862			yFrac0 := sy - float64(sy0)
3863			yFrac1 := 1 - yFrac0
3864			sy0 += bias.Y
3865			sy1 := sy0 + 1
3866			if sy0 < sr.Min.Y {
3867				sy0, sy1 = sr.Min.Y, sr.Min.Y
3868				yFrac0, yFrac1 = 0, 1
3869			} else if sy1 >= sr.Max.Y {
3870				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
3871				yFrac0, yFrac1 = 1, 0
3872			}
3873
3874			s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3875			s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
3876
3877			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3878			s00yy1 := int(src.Y[s00i]) * 0x10101
3879			s00cb1 := int(src.Cb[s00j]) - 128
3880			s00cr1 := int(src.Cr[s00j]) - 128
3881			s00ru := (s00yy1 + 91881*s00cr1) >> 8
3882			s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
3883			s00bu := (s00yy1 + 116130*s00cb1) >> 8
3884			if s00ru < 0 {
3885				s00ru = 0
3886			} else if s00ru > 0xffff {
3887				s00ru = 0xffff
3888			}
3889			if s00gu < 0 {
3890				s00gu = 0
3891			} else if s00gu > 0xffff {
3892				s00gu = 0xffff
3893			}
3894			if s00bu < 0 {
3895				s00bu = 0
3896			} else if s00bu > 0xffff {
3897				s00bu = 0xffff
3898			}
3899
3900			s00r := float64(s00ru)
3901			s00g := float64(s00gu)
3902			s00b := float64(s00bu)
3903			s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3904			s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
3905
3906			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3907			s10yy1 := int(src.Y[s10i]) * 0x10101
3908			s10cb1 := int(src.Cb[s10j]) - 128
3909			s10cr1 := int(src.Cr[s10j]) - 128
3910			s10ru := (s10yy1 + 91881*s10cr1) >> 8
3911			s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
3912			s10bu := (s10yy1 + 116130*s10cb1) >> 8
3913			if s10ru < 0 {
3914				s10ru = 0
3915			} else if s10ru > 0xffff {
3916				s10ru = 0xffff
3917			}
3918			if s10gu < 0 {
3919				s10gu = 0
3920			} else if s10gu > 0xffff {
3921				s10gu = 0xffff
3922			}
3923			if s10bu < 0 {
3924				s10bu = 0
3925			} else if s10bu > 0xffff {
3926				s10bu = 0xffff
3927			}
3928
3929			s10r := float64(s10ru)
3930			s10g := float64(s10gu)
3931			s10b := float64(s10bu)
3932			s10r = xFrac1*s00r + xFrac0*s10r
3933			s10g = xFrac1*s00g + xFrac0*s10g
3934			s10b = xFrac1*s00b + xFrac0*s10b
3935			s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
3936			s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
3937
3938			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3939			s01yy1 := int(src.Y[s01i]) * 0x10101
3940			s01cb1 := int(src.Cb[s01j]) - 128
3941			s01cr1 := int(src.Cr[s01j]) - 128
3942			s01ru := (s01yy1 + 91881*s01cr1) >> 8
3943			s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
3944			s01bu := (s01yy1 + 116130*s01cb1) >> 8
3945			if s01ru < 0 {
3946				s01ru = 0
3947			} else if s01ru > 0xffff {
3948				s01ru = 0xffff
3949			}
3950			if s01gu < 0 {
3951				s01gu = 0
3952			} else if s01gu > 0xffff {
3953				s01gu = 0xffff
3954			}
3955			if s01bu < 0 {
3956				s01bu = 0
3957			} else if s01bu > 0xffff {
3958				s01bu = 0xffff
3959			}
3960
3961			s01r := float64(s01ru)
3962			s01g := float64(s01gu)
3963			s01b := float64(s01bu)
3964			s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
3965			s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
3966
3967			// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
3968			s11yy1 := int(src.Y[s11i]) * 0x10101
3969			s11cb1 := int(src.Cb[s11j]) - 128
3970			s11cr1 := int(src.Cr[s11j]) - 128
3971			s11ru := (s11yy1 + 91881*s11cr1) >> 8
3972			s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
3973			s11bu := (s11yy1 + 116130*s11cb1) >> 8
3974			if s11ru < 0 {
3975				s11ru = 0
3976			} else if s11ru > 0xffff {
3977				s11ru = 0xffff
3978			}
3979			if s11gu < 0 {
3980				s11gu = 0
3981			} else if s11gu > 0xffff {
3982				s11gu = 0xffff
3983			}
3984			if s11bu < 0 {
3985				s11bu = 0
3986			} else if s11bu > 0xffff {
3987				s11bu = 0xffff
3988			}
3989
3990			s11r := float64(s11ru)
3991			s11g := float64(s11gu)
3992			s11b := float64(s11bu)
3993			s11r = xFrac1*s01r + xFrac0*s11r
3994			s11g = xFrac1*s01g + xFrac0*s11g
3995			s11b = xFrac1*s01b + xFrac0*s11b
3996			s11r = yFrac1*s10r + yFrac0*s11r
3997			s11g = yFrac1*s10g + yFrac0*s11g
3998			s11b = yFrac1*s10b + yFrac0*s11b
3999			pr := uint32(s11r)
4000			pg := uint32(s11g)
4001			pb := uint32(s11b)
4002			dst.Pix[d+0] = uint8(pr >> 8)
4003			dst.Pix[d+1] = uint8(pg >> 8)
4004			dst.Pix[d+2] = uint8(pb >> 8)
4005			dst.Pix[d+3] = 0xff
4006		}
4007	}
4008}
4009
4010func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
4011	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
4012		dyf := float64(dr.Min.Y+int(dy)) + 0.5
4013		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
4014		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
4015			dxf := float64(dr.Min.X+int(dx)) + 0.5
4016			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
4017			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
4018			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
4019				continue
4020			}
4021
4022			sx -= 0.5
4023			sx0 := int(sx)
4024			xFrac0 := sx - float64(sx0)
4025			xFrac1 := 1 - xFrac0
4026			sx0 += bias.X
4027			sx1 := sx0 + 1
4028			if sx0 < sr.Min.X {
4029				sx0, sx1 = sr.Min.X, sr.Min.X
4030				xFrac0, xFrac1 = 0, 1
4031			} else if sx1 >= sr.Max.X {
4032				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
4033				xFrac0, xFrac1 = 1, 0
4034			}
4035
4036			sy -= 0.5
4037			sy0 := int(sy)
4038			yFrac0 := sy - float64(sy0)
4039			yFrac1 := 1 - yFrac0
4040			sy0 += bias.Y
4041			sy1 := sy0 + 1
4042			if sy0 < sr.Min.Y {
4043				sy0, sy1 = sr.Min.Y, sr.Min.Y
4044				yFrac0, yFrac1 = 0, 1
4045			} else if sy1 >= sr.Max.Y {
4046				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
4047				yFrac0, yFrac1 = 1, 0
4048			}
4049
4050			s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
4051			s00r := float64(s00ru)
4052			s00g := float64(s00gu)
4053			s00b := float64(s00bu)
4054			s00a := float64(s00au)
4055			s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
4056			s10r := float64(s10ru)
4057			s10g := float64(s10gu)
4058			s10b := float64(s10bu)
4059			s10a := float64(s10au)
4060			s10r = xFrac1*s00r + xFrac0*s10r
4061			s10g = xFrac1*s00g + xFrac0*s10g
4062			s10b = xFrac1*s00b + xFrac0*s10b
4063			s10a = xFrac1*s00a + xFrac0*s10a
4064			s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
4065			s01r := float64(s01ru)
4066			s01g := float64(s01gu)
4067			s01b := float64(s01bu)
4068			s01a := float64(s01au)
4069			s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
4070			s11r := float64(s11ru)
4071			s11g := float64(s11gu)
4072			s11b := float64(s11bu)
4073			s11a := float64(s11au)
4074			s11r = xFrac1*s01r + xFrac0*s11r
4075			s11g = xFrac1*s01g + xFrac0*s11g
4076			s11b = xFrac1*s01b + xFrac0*s11b
4077			s11a = xFrac1*s01a + xFrac0*s11a
4078			s11r = yFrac1*s10r + yFrac0*s11r
4079			s11g = yFrac1*s10g + yFrac0*s11g
4080			s11b = yFrac1*s10b + yFrac0*s11b
4081			s11a = yFrac1*s10a + yFrac0*s11a
4082			pr := uint32(s11r)
4083			pg := uint32(s11g)
4084			pb := uint32(s11b)
4085			pa := uint32(s11a)
4086			pa1 := (0xffff - pa) * 0x101
4087			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
4088			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
4089			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
4090			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
4091		}
4092	}
4093}
4094
4095func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
4096	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
4097		dyf := float64(dr.Min.Y+int(dy)) + 0.5
4098		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
4099		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
4100			dxf := float64(dr.Min.X+int(dx)) + 0.5
4101			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
4102			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
4103			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
4104				continue
4105			}
4106
4107			sx -= 0.5
4108			sx0 := int(sx)
4109			xFrac0 := sx - float64(sx0)
4110			xFrac1 := 1 - xFrac0
4111			sx0 += bias.X
4112			sx1 := sx0 + 1
4113			if sx0 < sr.Min.X {
4114				sx0, sx1 = sr.Min.X, sr.Min.X
4115				xFrac0, xFrac1 = 0, 1
4116			} else if sx1 >= sr.Max.X {
4117				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
4118				xFrac0, xFrac1 = 1, 0
4119			}
4120
4121			sy -= 0.5
4122			sy0 := int(sy)
4123			yFrac0 := sy - float64(sy0)
4124			yFrac1 := 1 - yFrac0
4125			sy0 += bias.Y
4126			sy1 := sy0 + 1
4127			if sy0 < sr.Min.Y {
4128				sy0, sy1 = sr.Min.Y, sr.Min.Y
4129				yFrac0, yFrac1 = 0, 1
4130			} else if sy1 >= sr.Max.Y {
4131				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
4132				yFrac0, yFrac1 = 1, 0
4133			}
4134
4135			s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
4136			s00r := float64(s00ru)
4137			s00g := float64(s00gu)
4138			s00b := float64(s00bu)
4139			s00a := float64(s00au)
4140			s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
4141			s10r := float64(s10ru)
4142			s10g := float64(s10gu)
4143			s10b := float64(s10bu)
4144			s10a := float64(s10au)
4145			s10r = xFrac1*s00r + xFrac0*s10r
4146			s10g = xFrac1*s00g + xFrac0*s10g
4147			s10b = xFrac1*s00b + xFrac0*s10b
4148			s10a = xFrac1*s00a + xFrac0*s10a
4149			s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
4150			s01r := float64(s01ru)
4151			s01g := float64(s01gu)
4152			s01b := float64(s01bu)
4153			s01a := float64(s01au)
4154			s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
4155			s11r := float64(s11ru)
4156			s11g := float64(s11gu)
4157			s11b := float64(s11bu)
4158			s11a := float64(s11au)
4159			s11r = xFrac1*s01r + xFrac0*s11r
4160			s11g = xFrac1*s01g + xFrac0*s11g
4161			s11b = xFrac1*s01b + xFrac0*s11b
4162			s11a = xFrac1*s01a + xFrac0*s11a
4163			s11r = yFrac1*s10r + yFrac0*s11r
4164			s11g = yFrac1*s10g + yFrac0*s11g
4165			s11b = yFrac1*s10b + yFrac0*s11b
4166			s11a = yFrac1*s10a + yFrac0*s11a
4167			pr := uint32(s11r)
4168			pg := uint32(s11g)
4169			pb := uint32(s11b)
4170			pa := uint32(s11a)
4171			dst.Pix[d+0] = uint8(pr >> 8)
4172			dst.Pix[d+1] = uint8(pg >> 8)
4173			dst.Pix[d+2] = uint8(pb >> 8)
4174			dst.Pix[d+3] = uint8(pa >> 8)
4175		}
4176	}
4177}
4178
4179func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
4180	srcMask, smp := opts.SrcMask, opts.SrcMaskP
4181	dstMask, dmp := opts.DstMask, opts.DstMaskP
4182	dstColorRGBA64 := &color.RGBA64{}
4183	dstColor := color.Color(dstColorRGBA64)
4184	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
4185		dyf := float64(dr.Min.Y+int(dy)) + 0.5
4186		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
4187			dxf := float64(dr.Min.X+int(dx)) + 0.5
4188			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
4189			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
4190			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
4191				continue
4192			}
4193
4194			sx -= 0.5
4195			sx0 := int(sx)
4196			xFrac0 := sx - float64(sx0)
4197			xFrac1 := 1 - xFrac0
4198			sx0 += bias.X
4199			sx1 := sx0 + 1
4200			if sx0 < sr.Min.X {
4201				sx0, sx1 = sr.Min.X, sr.Min.X
4202				xFrac0, xFrac1 = 0, 1
4203			} else if sx1 >= sr.Max.X {
4204				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
4205				xFrac0, xFrac1 = 1, 0
4206			}
4207
4208			sy -= 0.5
4209			sy0 := int(sy)
4210			yFrac0 := sy - float64(sy0)
4211			yFrac1 := 1 - yFrac0
4212			sy0 += bias.Y
4213			sy1 := sy0 + 1
4214			if sy0 < sr.Min.Y {
4215				sy0, sy1 = sr.Min.Y, sr.Min.Y
4216				yFrac0, yFrac1 = 0, 1
4217			} else if sy1 >= sr.Max.Y {
4218				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
4219				yFrac0, yFrac1 = 1, 0
4220			}
4221
4222			s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
4223			if srcMask != nil {
4224				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
4225				s00ru = s00ru * ma / 0xffff
4226				s00gu = s00gu * ma / 0xffff
4227				s00bu = s00bu * ma / 0xffff
4228				s00au = s00au * ma / 0xffff
4229			}
4230			s00r := float64(s00ru)
4231			s00g := float64(s00gu)
4232			s00b := float64(s00bu)
4233			s00a := float64(s00au)
4234			s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
4235			if srcMask != nil {
4236				_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
4237				s10ru = s10ru * ma / 0xffff
4238				s10gu = s10gu * ma / 0xffff
4239				s10bu = s10bu * ma / 0xffff
4240				s10au = s10au * ma / 0xffff
4241			}
4242			s10r := float64(s10ru)
4243			s10g := float64(s10gu)
4244			s10b := float64(s10bu)
4245			s10a := float64(s10au)
4246			s10r = xFrac1*s00r + xFrac0*s10r
4247			s10g = xFrac1*s00g + xFrac0*s10g
4248			s10b = xFrac1*s00b + xFrac0*s10b
4249			s10a = xFrac1*s00a + xFrac0*s10a
4250			s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
4251			if srcMask != nil {
4252				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
4253				s01ru = s01ru * ma / 0xffff
4254				s01gu = s01gu * ma / 0xffff
4255				s01bu = s01bu * ma / 0xffff
4256				s01au = s01au * ma / 0xffff
4257			}
4258			s01r := float64(s01ru)
4259			s01g := float64(s01gu)
4260			s01b := float64(s01bu)
4261			s01a := float64(s01au)
4262			s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
4263			if srcMask != nil {
4264				_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
4265				s11ru = s11ru * ma / 0xffff
4266				s11gu = s11gu * ma / 0xffff
4267				s11bu = s11bu * ma / 0xffff
4268				s11au = s11au * ma / 0xffff
4269			}
4270			s11r := float64(s11ru)
4271			s11g := float64(s11gu)
4272			s11b := float64(s11bu)
4273			s11a := float64(s11au)
4274			s11r = xFrac1*s01r + xFrac0*s11r
4275			s11g = xFrac1*s01g + xFrac0*s11g
4276			s11b = xFrac1*s01b + xFrac0*s11b
4277			s11a = xFrac1*s01a + xFrac0*s11a
4278			s11r = yFrac1*s10r + yFrac0*s11r
4279			s11g = yFrac1*s10g + yFrac0*s11g
4280			s11b = yFrac1*s10b + yFrac0*s11b
4281			s11a = yFrac1*s10a + yFrac0*s11a
4282			pr := uint32(s11r)
4283			pg := uint32(s11g)
4284			pb := uint32(s11b)
4285			pa := uint32(s11a)
4286			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
4287			if dstMask != nil {
4288				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
4289				pr = pr * ma / 0xffff
4290				pg = pg * ma / 0xffff
4291				pb = pb * ma / 0xffff
4292				pa = pa * ma / 0xffff
4293			}
4294			pa1 := 0xffff - pa
4295			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
4296			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
4297			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
4298			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
4299			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
4300		}
4301	}
4302}
4303
4304func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
4305	srcMask, smp := opts.SrcMask, opts.SrcMaskP
4306	dstMask, dmp := opts.DstMask, opts.DstMaskP
4307	dstColorRGBA64 := &color.RGBA64{}
4308	dstColor := color.Color(dstColorRGBA64)
4309	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
4310		dyf := float64(dr.Min.Y+int(dy)) + 0.5
4311		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
4312			dxf := float64(dr.Min.X+int(dx)) + 0.5
4313			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
4314			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
4315			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
4316				continue
4317			}
4318
4319			sx -= 0.5
4320			sx0 := int(sx)
4321			xFrac0 := sx - float64(sx0)
4322			xFrac1 := 1 - xFrac0
4323			sx0 += bias.X
4324			sx1 := sx0 + 1
4325			if sx0 < sr.Min.X {
4326				sx0, sx1 = sr.Min.X, sr.Min.X
4327				xFrac0, xFrac1 = 0, 1
4328			} else if sx1 >= sr.Max.X {
4329				sx0, sx1 = sr.Max.X-1, sr.Max.X-1
4330				xFrac0, xFrac1 = 1, 0
4331			}
4332
4333			sy -= 0.5
4334			sy0 := int(sy)
4335			yFrac0 := sy - float64(sy0)
4336			yFrac1 := 1 - yFrac0
4337			sy0 += bias.Y
4338			sy1 := sy0 + 1
4339			if sy0 < sr.Min.Y {
4340				sy0, sy1 = sr.Min.Y, sr.Min.Y
4341				yFrac0, yFrac1 = 0, 1
4342			} else if sy1 >= sr.Max.Y {
4343				sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
4344				yFrac0, yFrac1 = 1, 0
4345			}
4346
4347			s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
4348			if srcMask != nil {
4349				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
4350				s00ru = s00ru * ma / 0xffff
4351				s00gu = s00gu * ma / 0xffff
4352				s00bu = s00bu * ma / 0xffff
4353				s00au = s00au * ma / 0xffff
4354			}
4355			s00r := float64(s00ru)
4356			s00g := float64(s00gu)
4357			s00b := float64(s00bu)
4358			s00a := float64(s00au)
4359			s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
4360			if srcMask != nil {
4361				_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
4362				s10ru = s10ru * ma / 0xffff
4363				s10gu = s10gu * ma / 0xffff
4364				s10bu = s10bu * ma / 0xffff
4365				s10au = s10au * ma / 0xffff
4366			}
4367			s10r := float64(s10ru)
4368			s10g := float64(s10gu)
4369			s10b := float64(s10bu)
4370			s10a := float64(s10au)
4371			s10r = xFrac1*s00r + xFrac0*s10r
4372			s10g = xFrac1*s00g + xFrac0*s10g
4373			s10b = xFrac1*s00b + xFrac0*s10b
4374			s10a = xFrac1*s00a + xFrac0*s10a
4375			s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
4376			if srcMask != nil {
4377				_, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
4378				s01ru = s01ru * ma / 0xffff
4379				s01gu = s01gu * ma / 0xffff
4380				s01bu = s01bu * ma / 0xffff
4381				s01au = s01au * ma / 0xffff
4382			}
4383			s01r := float64(s01ru)
4384			s01g := float64(s01gu)
4385			s01b := float64(s01bu)
4386			s01a := float64(s01au)
4387			s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
4388			if srcMask != nil {
4389				_, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
4390				s11ru = s11ru * ma / 0xffff
4391				s11gu = s11gu * ma / 0xffff
4392				s11bu = s11bu * ma / 0xffff
4393				s11au = s11au * ma / 0xffff
4394			}
4395			s11r := float64(s11ru)
4396			s11g := float64(s11gu)
4397			s11b := float64(s11bu)
4398			s11a := float64(s11au)
4399			s11r = xFrac1*s01r + xFrac0*s11r
4400			s11g = xFrac1*s01g + xFrac0*s11g
4401			s11b = xFrac1*s01b + xFrac0*s11b
4402			s11a = xFrac1*s01a + xFrac0*s11a
4403			s11r = yFrac1*s10r + yFrac0*s11r
4404			s11g = yFrac1*s10g + yFrac0*s11g
4405			s11b = yFrac1*s10b + yFrac0*s11b
4406			s11a = yFrac1*s10a + yFrac0*s11a
4407			pr := uint32(s11r)
4408			pg := uint32(s11g)
4409			pb := uint32(s11b)
4410			pa := uint32(s11a)
4411			if dstMask != nil {
4412				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
4413				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
4414				pr = pr * ma / 0xffff
4415				pg = pg * ma / 0xffff
4416				pb = pb * ma / 0xffff
4417				pa = pa * ma / 0xffff
4418				pa1 := 0xffff - ma
4419				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
4420				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
4421				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
4422				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
4423				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
4424			} else {
4425				dstColorRGBA64.R = uint16(pr)
4426				dstColorRGBA64.G = uint16(pg)
4427				dstColorRGBA64.B = uint16(pb)
4428				dstColorRGBA64.A = uint16(pa)
4429				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
4430			}
4431		}
4432	}
4433}
4434
4435func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
4436	if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
4437		z.kernel.Scale(dst, dr, src, sr, op, opts)
4438		return
4439	}
4440
4441	var o Options
4442	if opts != nil {
4443		o = *opts
4444	}
4445
4446	// adr is the affected destination pixels.
4447	adr := dst.Bounds().Intersect(dr)
4448	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
4449	if adr.Empty() || sr.Empty() {
4450		return
4451	}
4452	// Make adr relative to dr.Min.
4453	adr = adr.Sub(dr.Min)
4454	if op == Over && o.SrcMask == nil && opaque(src) {
4455		op = Src
4456	}
4457
4458	if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
4459		Draw(dst, dr, src, src.Bounds().Min, op)
4460		return
4461	}
4462
4463	// Create a temporary buffer:
4464	// scaleX distributes the source image's columns over the temporary image.
4465	// scaleY distributes the temporary image's rows over the destination image.
4466	var tmp [][4]float64
4467	if z.pool.New != nil {
4468		tmpp := z.pool.Get().(*[][4]float64)
4469		defer z.pool.Put(tmpp)
4470		tmp = *tmpp
4471	} else {
4472		tmp = z.makeTmpBuf()
4473	}
4474
4475	// sr is the source pixels. If it extends beyond the src bounds,
4476	// we cannot use the type-specific fast paths, as they access
4477	// the Pix fields directly without bounds checking.
4478	//
4479	// Similarly, the fast paths assume that the masks are nil.
4480	if o.SrcMask != nil || !sr.In(src.Bounds()) {
4481		z.scaleX_Image(tmp, src, sr, &o)
4482	} else {
4483		switch src := src.(type) {
4484		case *image.Gray:
4485			z.scaleX_Gray(tmp, src, sr, &o)
4486		case *image.NRGBA:
4487			z.scaleX_NRGBA(tmp, src, sr, &o)
4488		case *image.RGBA:
4489			z.scaleX_RGBA(tmp, src, sr, &o)
4490		case *image.YCbCr:
4491			switch src.SubsampleRatio {
4492			default:
4493				z.scaleX_Image(tmp, src, sr, &o)
4494			case image.YCbCrSubsampleRatio444:
4495				z.scaleX_YCbCr444(tmp, src, sr, &o)
4496			case image.YCbCrSubsampleRatio422:
4497				z.scaleX_YCbCr422(tmp, src, sr, &o)
4498			case image.YCbCrSubsampleRatio420:
4499				z.scaleX_YCbCr420(tmp, src, sr, &o)
4500			case image.YCbCrSubsampleRatio440:
4501				z.scaleX_YCbCr440(tmp, src, sr, &o)
4502			}
4503		default:
4504			z.scaleX_Image(tmp, src, sr, &o)
4505		}
4506	}
4507
4508	if o.DstMask != nil {
4509		switch op {
4510		case Over:
4511			z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
4512		case Src:
4513			z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
4514		}
4515	} else {
4516		switch op {
4517		case Over:
4518			switch dst := dst.(type) {
4519			case *image.RGBA:
4520				z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o)
4521			default:
4522				z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
4523			}
4524		case Src:
4525			switch dst := dst.(type) {
4526			case *image.RGBA:
4527				z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o)
4528			default:
4529				z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
4530			}
4531		}
4532	}
4533}
4534
4535func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
4536	var o Options
4537	if opts != nil {
4538		o = *opts
4539	}
4540
4541	dr := transformRect(&s2d, &sr)
4542	// adr is the affected destination pixels.
4543	adr := dst.Bounds().Intersect(dr)
4544	adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
4545	if adr.Empty() || sr.Empty() {
4546		return
4547	}
4548	if op == Over && o.SrcMask == nil && opaque(src) {
4549		op = Src
4550	}
4551	d2s := invert(&s2d)
4552	// bias is a translation of the mapping from dst coordinates to src
4553	// coordinates such that the latter temporarily have non-negative X
4554	// and Y coordinates. This allows us to write int(f) instead of
4555	// int(math.Floor(f)), since "round to zero" and "round down" are
4556	// equivalent when f >= 0, but the former is much cheaper. The X--
4557	// and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
4558	// adjustment.
4559	bias := transformRect(&d2s, &adr).Min
4560	bias.X--
4561	bias.Y--
4562	d2s[2] -= float64(bias.X)
4563	d2s[5] -= float64(bias.Y)
4564	// Make adr relative to dr.Min.
4565	adr = adr.Sub(dr.Min)
4566
4567	if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
4568		transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
4569		return
4570	}
4571
4572	xscale := abs(d2s[0])
4573	if s := abs(d2s[1]); xscale < s {
4574		xscale = s
4575	}
4576	yscale := abs(d2s[3])
4577	if s := abs(d2s[4]); yscale < s {
4578		yscale = s
4579	}
4580
4581	// sr is the source pixels. If it extends beyond the src bounds,
4582	// we cannot use the type-specific fast paths, as they access
4583	// the Pix fields directly without bounds checking.
4584	//
4585	// Similarly, the fast paths assume that the masks are nil.
4586	if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
4587		switch op {
4588		case Over:
4589			q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4590		case Src:
4591			q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4592		}
4593	} else {
4594		switch op {
4595		case Over:
4596			switch dst := dst.(type) {
4597			case *image.RGBA:
4598				switch src := src.(type) {
4599				case *image.NRGBA:
4600					q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4601				case *image.RGBA:
4602					q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4603				default:
4604					q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4605				}
4606			default:
4607				switch src := src.(type) {
4608				default:
4609					q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4610				}
4611			}
4612		case Src:
4613			switch dst := dst.(type) {
4614			case *image.RGBA:
4615				switch src := src.(type) {
4616				case *image.Gray:
4617					q.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4618				case *image.NRGBA:
4619					q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4620				case *image.RGBA:
4621					q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4622				case *image.YCbCr:
4623					switch src.SubsampleRatio {
4624					default:
4625						q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4626					case image.YCbCrSubsampleRatio444:
4627						q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4628					case image.YCbCrSubsampleRatio422:
4629						q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4630					case image.YCbCrSubsampleRatio420:
4631						q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4632					case image.YCbCrSubsampleRatio440:
4633						q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4634					}
4635				default:
4636					q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4637				}
4638			default:
4639				switch src := src.(type) {
4640				default:
4641					q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
4642				}
4643			}
4644		}
4645	}
4646}
4647
4648func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle, opts *Options) {
4649	t := 0
4650	for y := int32(0); y < z.sh; y++ {
4651		for _, s := range z.horizontal.sources {
4652			var pr float64
4653			for _, c := range z.horizontal.contribs[s.i:s.j] {
4654				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4655				pru := uint32(src.Pix[pi]) * 0x101
4656				pr += float64(pru) * c.weight
4657			}
4658			pr *= s.invTotalWeightFFFF
4659			tmp[t] = [4]float64{
4660				pr,
4661				pr,
4662				pr,
4663				1,
4664			}
4665			t++
4666		}
4667	}
4668}
4669
4670func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, sr image.Rectangle, opts *Options) {
4671	t := 0
4672	for y := int32(0); y < z.sh; y++ {
4673		for _, s := range z.horizontal.sources {
4674			var pr, pg, pb, pa float64
4675			for _, c := range z.horizontal.contribs[s.i:s.j] {
4676				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
4677				pau := uint32(src.Pix[pi+3]) * 0x101
4678				pru := uint32(src.Pix[pi+0]) * pau / 0xff
4679				pgu := uint32(src.Pix[pi+1]) * pau / 0xff
4680				pbu := uint32(src.Pix[pi+2]) * pau / 0xff
4681				pr += float64(pru) * c.weight
4682				pg += float64(pgu) * c.weight
4683				pb += float64(pbu) * c.weight
4684				pa += float64(pau) * c.weight
4685			}
4686			tmp[t] = [4]float64{
4687				pr * s.invTotalWeightFFFF,
4688				pg * s.invTotalWeightFFFF,
4689				pb * s.invTotalWeightFFFF,
4690				pa * s.invTotalWeightFFFF,
4691			}
4692			t++
4693		}
4694	}
4695}
4696
4697func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.Rectangle, opts *Options) {
4698	t := 0
4699	for y := int32(0); y < z.sh; y++ {
4700		for _, s := range z.horizontal.sources {
4701			var pr, pg, pb, pa float64
4702			for _, c := range z.horizontal.contribs[s.i:s.j] {
4703				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
4704				pru := uint32(src.Pix[pi+0]) * 0x101
4705				pgu := uint32(src.Pix[pi+1]) * 0x101
4706				pbu := uint32(src.Pix[pi+2]) * 0x101
4707				pau := uint32(src.Pix[pi+3]) * 0x101
4708				pr += float64(pru) * c.weight
4709				pg += float64(pgu) * c.weight
4710				pb += float64(pbu) * c.weight
4711				pa += float64(pau) * c.weight
4712			}
4713			tmp[t] = [4]float64{
4714				pr * s.invTotalWeightFFFF,
4715				pg * s.invTotalWeightFFFF,
4716				pb * s.invTotalWeightFFFF,
4717				pa * s.invTotalWeightFFFF,
4718			}
4719			t++
4720		}
4721	}
4722}
4723
4724func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
4725	t := 0
4726	for y := int32(0); y < z.sh; y++ {
4727		for _, s := range z.horizontal.sources {
4728			var pr, pg, pb float64
4729			for _, c := range z.horizontal.contribs[s.i:s.j] {
4730				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4731				pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4732
4733				// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
4734				pyy1 := int(src.Y[pi]) * 0x10101
4735				pcb1 := int(src.Cb[pj]) - 128
4736				pcr1 := int(src.Cr[pj]) - 128
4737				pru := (pyy1 + 91881*pcr1) >> 8
4738				pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
4739				pbu := (pyy1 + 116130*pcb1) >> 8
4740				if pru < 0 {
4741					pru = 0
4742				} else if pru > 0xffff {
4743					pru = 0xffff
4744				}
4745				if pgu < 0 {
4746					pgu = 0
4747				} else if pgu > 0xffff {
4748					pgu = 0xffff
4749				}
4750				if pbu < 0 {
4751					pbu = 0
4752				} else if pbu > 0xffff {
4753					pbu = 0xffff
4754				}
4755
4756				pr += float64(pru) * c.weight
4757				pg += float64(pgu) * c.weight
4758				pb += float64(pbu) * c.weight
4759			}
4760			tmp[t] = [4]float64{
4761				pr * s.invTotalWeightFFFF,
4762				pg * s.invTotalWeightFFFF,
4763				pb * s.invTotalWeightFFFF,
4764				1,
4765			}
4766			t++
4767		}
4768	}
4769}
4770
4771func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
4772	t := 0
4773	for y := int32(0); y < z.sh; y++ {
4774		for _, s := range z.horizontal.sources {
4775			var pr, pg, pb float64
4776			for _, c := range z.horizontal.contribs[s.i:s.j] {
4777				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4778				pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
4779
4780				// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
4781				pyy1 := int(src.Y[pi]) * 0x10101
4782				pcb1 := int(src.Cb[pj]) - 128
4783				pcr1 := int(src.Cr[pj]) - 128
4784				pru := (pyy1 + 91881*pcr1) >> 8
4785				pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
4786				pbu := (pyy1 + 116130*pcb1) >> 8
4787				if pru < 0 {
4788					pru = 0
4789				} else if pru > 0xffff {
4790					pru = 0xffff
4791				}
4792				if pgu < 0 {
4793					pgu = 0
4794				} else if pgu > 0xffff {
4795					pgu = 0xffff
4796				}
4797				if pbu < 0 {
4798					pbu = 0
4799				} else if pbu > 0xffff {
4800					pbu = 0xffff
4801				}
4802
4803				pr += float64(pru) * c.weight
4804				pg += float64(pgu) * c.weight
4805				pb += float64(pbu) * c.weight
4806			}
4807			tmp[t] = [4]float64{
4808				pr * s.invTotalWeightFFFF,
4809				pg * s.invTotalWeightFFFF,
4810				pb * s.invTotalWeightFFFF,
4811				1,
4812			}
4813			t++
4814		}
4815	}
4816}
4817
4818func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
4819	t := 0
4820	for y := int32(0); y < z.sh; y++ {
4821		for _, s := range z.horizontal.sources {
4822			var pr, pg, pb float64
4823			for _, c := range z.horizontal.contribs[s.i:s.j] {
4824				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4825				pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
4826
4827				// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
4828				pyy1 := int(src.Y[pi]) * 0x10101
4829				pcb1 := int(src.Cb[pj]) - 128
4830				pcr1 := int(src.Cr[pj]) - 128
4831				pru := (pyy1 + 91881*pcr1) >> 8
4832				pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
4833				pbu := (pyy1 + 116130*pcb1) >> 8
4834				if pru < 0 {
4835					pru = 0
4836				} else if pru > 0xffff {
4837					pru = 0xffff
4838				}
4839				if pgu < 0 {
4840					pgu = 0
4841				} else if pgu > 0xffff {
4842					pgu = 0xffff
4843				}
4844				if pbu < 0 {
4845					pbu = 0
4846				} else if pbu > 0xffff {
4847					pbu = 0xffff
4848				}
4849
4850				pr += float64(pru) * c.weight
4851				pg += float64(pgu) * c.weight
4852				pb += float64(pbu) * c.weight
4853			}
4854			tmp[t] = [4]float64{
4855				pr * s.invTotalWeightFFFF,
4856				pg * s.invTotalWeightFFFF,
4857				pb * s.invTotalWeightFFFF,
4858				1,
4859			}
4860			t++
4861		}
4862	}
4863}
4864
4865func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
4866	t := 0
4867	for y := int32(0); y < z.sh; y++ {
4868		for _, s := range z.horizontal.sources {
4869			var pr, pg, pb float64
4870			for _, c := range z.horizontal.contribs[s.i:s.j] {
4871				pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4872				pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
4873
4874				// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
4875				pyy1 := int(src.Y[pi]) * 0x10101
4876				pcb1 := int(src.Cb[pj]) - 128
4877				pcr1 := int(src.Cr[pj]) - 128
4878				pru := (pyy1 + 91881*pcr1) >> 8
4879				pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
4880				pbu := (pyy1 + 116130*pcb1) >> 8
4881				if pru < 0 {
4882					pru = 0
4883				} else if pru > 0xffff {
4884					pru = 0xffff
4885				}
4886				if pgu < 0 {
4887					pgu = 0
4888				} else if pgu > 0xffff {
4889					pgu = 0xffff
4890				}
4891				if pbu < 0 {
4892					pbu = 0
4893				} else if pbu > 0xffff {
4894					pbu = 0xffff
4895				}
4896
4897				pr += float64(pru) * c.weight
4898				pg += float64(pgu) * c.weight
4899				pb += float64(pbu) * c.weight
4900			}
4901			tmp[t] = [4]float64{
4902				pr * s.invTotalWeightFFFF,
4903				pg * s.invTotalWeightFFFF,
4904				pb * s.invTotalWeightFFFF,
4905				1,
4906			}
4907			t++
4908		}
4909	}
4910}
4911
4912func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) {
4913	t := 0
4914	srcMask, smp := opts.SrcMask, opts.SrcMaskP
4915	for y := int32(0); y < z.sh; y++ {
4916		for _, s := range z.horizontal.sources {
4917			var pr, pg, pb, pa float64
4918			for _, c := range z.horizontal.contribs[s.i:s.j] {
4919				pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
4920				if srcMask != nil {
4921					_, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA()
4922					pru = pru * ma / 0xffff
4923					pgu = pgu * ma / 0xffff
4924					pbu = pbu * ma / 0xffff
4925					pau = pau * ma / 0xffff
4926				}
4927				pr += float64(pru) * c.weight
4928				pg += float64(pgu) * c.weight
4929				pb += float64(pbu) * c.weight
4930				pa += float64(pau) * c.weight
4931			}
4932			tmp[t] = [4]float64{
4933				pr * s.invTotalWeightFFFF,
4934				pg * s.invTotalWeightFFFF,
4935				pb * s.invTotalWeightFFFF,
4936				pa * s.invTotalWeightFFFF,
4937			}
4938			t++
4939		}
4940	}
4941}
4942
4943func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
4944	for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
4945		d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
4946		for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
4947			var pr, pg, pb, pa float64
4948			for _, c := range z.vertical.contribs[s.i:s.j] {
4949				p := &tmp[c.coord*z.dw+dx]
4950				pr += p[0] * c.weight
4951				pg += p[1] * c.weight
4952				pb += p[2] * c.weight
4953				pa += p[3] * c.weight
4954			}
4955
4956			if pr > pa {
4957				pr = pa
4958			}
4959			if pg > pa {
4960				pg = pa
4961			}
4962			if pb > pa {
4963				pb = pa
4964			}
4965
4966			pr0 := uint32(ftou(pr * s.invTotalWeight))
4967			pg0 := uint32(ftou(pg * s.invTotalWeight))
4968			pb0 := uint32(ftou(pb * s.invTotalWeight))
4969			pa0 := uint32(ftou(pa * s.invTotalWeight))
4970			pa1 := (0xffff - uint32(pa0)) * 0x101
4971			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
4972			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
4973			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
4974			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
4975			d += dst.Stride
4976		}
4977	}
4978}
4979
4980func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
4981	for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
4982		d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
4983		for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
4984			var pr, pg, pb, pa float64
4985			for _, c := range z.vertical.contribs[s.i:s.j] {
4986				p := &tmp[c.coord*z.dw+dx]
4987				pr += p[0] * c.weight
4988				pg += p[1] * c.weight
4989				pb += p[2] * c.weight
4990				pa += p[3] * c.weight
4991			}
4992
4993			if pr > pa {
4994				pr = pa
4995			}
4996			if pg > pa {
4997				pg = pa
4998			}
4999			if pb > pa {
5000				pb = pa
5001			}
5002
5003			dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8)
5004			dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8)
5005			dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8)
5006			dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8)
5007			d += dst.Stride
5008		}
5009	}
5010}
5011
5012func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
5013	dstMask, dmp := opts.DstMask, opts.DstMaskP
5014	dstColorRGBA64 := &color.RGBA64{}
5015	dstColor := color.Color(dstColorRGBA64)
5016	for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
5017		for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
5018			var pr, pg, pb, pa float64
5019			for _, c := range z.vertical.contribs[s.i:s.j] {
5020				p := &tmp[c.coord*z.dw+dx]
5021				pr += p[0] * c.weight
5022				pg += p[1] * c.weight
5023				pb += p[2] * c.weight
5024				pa += p[3] * c.weight
5025			}
5026
5027			if pr > pa {
5028				pr = pa
5029			}
5030			if pg > pa {
5031				pg = pa
5032			}
5033			if pb > pa {
5034				pb = pa
5035			}
5036
5037			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
5038			pr0 := uint32(ftou(pr * s.invTotalWeight))
5039			pg0 := uint32(ftou(pg * s.invTotalWeight))
5040			pb0 := uint32(ftou(pb * s.invTotalWeight))
5041			pa0 := uint32(ftou(pa * s.invTotalWeight))
5042			if dstMask != nil {
5043				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
5044				pr0 = pr0 * ma / 0xffff
5045				pg0 = pg0 * ma / 0xffff
5046				pb0 = pb0 * ma / 0xffff
5047				pa0 = pa0 * ma / 0xffff
5048			}
5049			pa1 := 0xffff - pa0
5050			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
5051			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
5052			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
5053			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
5054			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
5055		}
5056	}
5057}
5058
5059func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
5060	dstMask, dmp := opts.DstMask, opts.DstMaskP
5061	dstColorRGBA64 := &color.RGBA64{}
5062	dstColor := color.Color(dstColorRGBA64)
5063	for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
5064		for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
5065			var pr, pg, pb, pa float64
5066			for _, c := range z.vertical.contribs[s.i:s.j] {
5067				p := &tmp[c.coord*z.dw+dx]
5068				pr += p[0] * c.weight
5069				pg += p[1] * c.weight
5070				pb += p[2] * c.weight
5071				pa += p[3] * c.weight
5072			}
5073
5074			if pr > pa {
5075				pr = pa
5076			}
5077			if pg > pa {
5078				pg = pa
5079			}
5080			if pb > pa {
5081				pb = pa
5082			}
5083
5084			if dstMask != nil {
5085				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
5086				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
5087				pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff
5088				pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff
5089				pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff
5090				pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff
5091				pa1 := 0xffff - ma
5092				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
5093				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
5094				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
5095				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
5096				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
5097			} else {
5098				dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
5099				dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
5100				dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
5101				dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
5102				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
5103			}
5104		}
5105	}
5106}
5107
5108func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5109	// When shrinking, broaden the effective kernel support so that we still
5110	// visit every source pixel.
5111	xHalfWidth, xKernelArgScale := q.Support, 1.0
5112	if xscale > 1 {
5113		xHalfWidth *= xscale
5114		xKernelArgScale = 1 / xscale
5115	}
5116	yHalfWidth, yKernelArgScale := q.Support, 1.0
5117	if yscale > 1 {
5118		yHalfWidth *= yscale
5119		yKernelArgScale = 1 / yscale
5120	}
5121
5122	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5123	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5124
5125	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5126		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5127		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5128		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5129			dxf := float64(dr.Min.X+int(dx)) + 0.5
5130			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5131			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5132			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5133				continue
5134			}
5135
5136			// TODO: adjust the bias so that we can use int(f) instead
5137			// of math.Floor(f) and math.Ceil(f).
5138			sx += float64(bias.X)
5139			sx -= 0.5
5140			ix := int(math.Floor(sx - xHalfWidth))
5141			if ix < sr.Min.X {
5142				ix = sr.Min.X
5143			}
5144			jx := int(math.Ceil(sx + xHalfWidth))
5145			if jx > sr.Max.X {
5146				jx = sr.Max.X
5147			}
5148
5149			totalXWeight := 0.0
5150			for kx := ix; kx < jx; kx++ {
5151				xWeight := 0.0
5152				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5153					xWeight = q.At(t)
5154				}
5155				xWeights[kx-ix] = xWeight
5156				totalXWeight += xWeight
5157			}
5158			for x := range xWeights[:jx-ix] {
5159				xWeights[x] /= totalXWeight
5160			}
5161
5162			sy += float64(bias.Y)
5163			sy -= 0.5
5164			iy := int(math.Floor(sy - yHalfWidth))
5165			if iy < sr.Min.Y {
5166				iy = sr.Min.Y
5167			}
5168			jy := int(math.Ceil(sy + yHalfWidth))
5169			if jy > sr.Max.Y {
5170				jy = sr.Max.Y
5171			}
5172
5173			totalYWeight := 0.0
5174			for ky := iy; ky < jy; ky++ {
5175				yWeight := 0.0
5176				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5177					yWeight = q.At(t)
5178				}
5179				yWeights[ky-iy] = yWeight
5180				totalYWeight += yWeight
5181			}
5182			for y := range yWeights[:jy-iy] {
5183				yWeights[y] /= totalYWeight
5184			}
5185
5186			var pr float64
5187			for ky := iy; ky < jy; ky++ {
5188				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5189					for kx := ix; kx < jx; kx++ {
5190						if w := xWeights[kx-ix] * yWeight; w != 0 {
5191							pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X)
5192							pru := uint32(src.Pix[pi]) * 0x101
5193							pr += float64(pru) * w
5194						}
5195					}
5196				}
5197			}
5198			out := uint8(fffftou(pr) >> 8)
5199			dst.Pix[d+0] = out
5200			dst.Pix[d+1] = out
5201			dst.Pix[d+2] = out
5202			dst.Pix[d+3] = 0xff
5203		}
5204	}
5205}
5206
5207func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5208	// When shrinking, broaden the effective kernel support so that we still
5209	// visit every source pixel.
5210	xHalfWidth, xKernelArgScale := q.Support, 1.0
5211	if xscale > 1 {
5212		xHalfWidth *= xscale
5213		xKernelArgScale = 1 / xscale
5214	}
5215	yHalfWidth, yKernelArgScale := q.Support, 1.0
5216	if yscale > 1 {
5217		yHalfWidth *= yscale
5218		yKernelArgScale = 1 / yscale
5219	}
5220
5221	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5222	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5223
5224	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5225		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5226		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5227		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5228			dxf := float64(dr.Min.X+int(dx)) + 0.5
5229			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5230			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5231			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5232				continue
5233			}
5234
5235			// TODO: adjust the bias so that we can use int(f) instead
5236			// of math.Floor(f) and math.Ceil(f).
5237			sx += float64(bias.X)
5238			sx -= 0.5
5239			ix := int(math.Floor(sx - xHalfWidth))
5240			if ix < sr.Min.X {
5241				ix = sr.Min.X
5242			}
5243			jx := int(math.Ceil(sx + xHalfWidth))
5244			if jx > sr.Max.X {
5245				jx = sr.Max.X
5246			}
5247
5248			totalXWeight := 0.0
5249			for kx := ix; kx < jx; kx++ {
5250				xWeight := 0.0
5251				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5252					xWeight = q.At(t)
5253				}
5254				xWeights[kx-ix] = xWeight
5255				totalXWeight += xWeight
5256			}
5257			for x := range xWeights[:jx-ix] {
5258				xWeights[x] /= totalXWeight
5259			}
5260
5261			sy += float64(bias.Y)
5262			sy -= 0.5
5263			iy := int(math.Floor(sy - yHalfWidth))
5264			if iy < sr.Min.Y {
5265				iy = sr.Min.Y
5266			}
5267			jy := int(math.Ceil(sy + yHalfWidth))
5268			if jy > sr.Max.Y {
5269				jy = sr.Max.Y
5270			}
5271
5272			totalYWeight := 0.0
5273			for ky := iy; ky < jy; ky++ {
5274				yWeight := 0.0
5275				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5276					yWeight = q.At(t)
5277				}
5278				yWeights[ky-iy] = yWeight
5279				totalYWeight += yWeight
5280			}
5281			for y := range yWeights[:jy-iy] {
5282				yWeights[y] /= totalYWeight
5283			}
5284
5285			var pr, pg, pb, pa float64
5286			for ky := iy; ky < jy; ky++ {
5287				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5288					for kx := ix; kx < jx; kx++ {
5289						if w := xWeights[kx-ix] * yWeight; w != 0 {
5290							pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
5291							pau := uint32(src.Pix[pi+3]) * 0x101
5292							pru := uint32(src.Pix[pi+0]) * pau / 0xff
5293							pgu := uint32(src.Pix[pi+1]) * pau / 0xff
5294							pbu := uint32(src.Pix[pi+2]) * pau / 0xff
5295							pr += float64(pru) * w
5296							pg += float64(pgu) * w
5297							pb += float64(pbu) * w
5298							pa += float64(pau) * w
5299						}
5300					}
5301				}
5302			}
5303
5304			if pr > pa {
5305				pr = pa
5306			}
5307			if pg > pa {
5308				pg = pa
5309			}
5310			if pb > pa {
5311				pb = pa
5312			}
5313
5314			pr0 := uint32(fffftou(pr))
5315			pg0 := uint32(fffftou(pg))
5316			pb0 := uint32(fffftou(pb))
5317			pa0 := uint32(fffftou(pa))
5318			pa1 := (0xffff - uint32(pa0)) * 0x101
5319			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
5320			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
5321			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
5322			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
5323		}
5324	}
5325}
5326
5327func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5328	// When shrinking, broaden the effective kernel support so that we still
5329	// visit every source pixel.
5330	xHalfWidth, xKernelArgScale := q.Support, 1.0
5331	if xscale > 1 {
5332		xHalfWidth *= xscale
5333		xKernelArgScale = 1 / xscale
5334	}
5335	yHalfWidth, yKernelArgScale := q.Support, 1.0
5336	if yscale > 1 {
5337		yHalfWidth *= yscale
5338		yKernelArgScale = 1 / yscale
5339	}
5340
5341	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5342	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5343
5344	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5345		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5346		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5347		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5348			dxf := float64(dr.Min.X+int(dx)) + 0.5
5349			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5350			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5351			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5352				continue
5353			}
5354
5355			// TODO: adjust the bias so that we can use int(f) instead
5356			// of math.Floor(f) and math.Ceil(f).
5357			sx += float64(bias.X)
5358			sx -= 0.5
5359			ix := int(math.Floor(sx - xHalfWidth))
5360			if ix < sr.Min.X {
5361				ix = sr.Min.X
5362			}
5363			jx := int(math.Ceil(sx + xHalfWidth))
5364			if jx > sr.Max.X {
5365				jx = sr.Max.X
5366			}
5367
5368			totalXWeight := 0.0
5369			for kx := ix; kx < jx; kx++ {
5370				xWeight := 0.0
5371				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5372					xWeight = q.At(t)
5373				}
5374				xWeights[kx-ix] = xWeight
5375				totalXWeight += xWeight
5376			}
5377			for x := range xWeights[:jx-ix] {
5378				xWeights[x] /= totalXWeight
5379			}
5380
5381			sy += float64(bias.Y)
5382			sy -= 0.5
5383			iy := int(math.Floor(sy - yHalfWidth))
5384			if iy < sr.Min.Y {
5385				iy = sr.Min.Y
5386			}
5387			jy := int(math.Ceil(sy + yHalfWidth))
5388			if jy > sr.Max.Y {
5389				jy = sr.Max.Y
5390			}
5391
5392			totalYWeight := 0.0
5393			for ky := iy; ky < jy; ky++ {
5394				yWeight := 0.0
5395				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5396					yWeight = q.At(t)
5397				}
5398				yWeights[ky-iy] = yWeight
5399				totalYWeight += yWeight
5400			}
5401			for y := range yWeights[:jy-iy] {
5402				yWeights[y] /= totalYWeight
5403			}
5404
5405			var pr, pg, pb, pa float64
5406			for ky := iy; ky < jy; ky++ {
5407				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5408					for kx := ix; kx < jx; kx++ {
5409						if w := xWeights[kx-ix] * yWeight; w != 0 {
5410							pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
5411							pau := uint32(src.Pix[pi+3]) * 0x101
5412							pru := uint32(src.Pix[pi+0]) * pau / 0xff
5413							pgu := uint32(src.Pix[pi+1]) * pau / 0xff
5414							pbu := uint32(src.Pix[pi+2]) * pau / 0xff
5415							pr += float64(pru) * w
5416							pg += float64(pgu) * w
5417							pb += float64(pbu) * w
5418							pa += float64(pau) * w
5419						}
5420					}
5421				}
5422			}
5423
5424			if pr > pa {
5425				pr = pa
5426			}
5427			if pg > pa {
5428				pg = pa
5429			}
5430			if pb > pa {
5431				pb = pa
5432			}
5433
5434			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
5435			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
5436			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
5437			dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
5438		}
5439	}
5440}
5441
5442func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5443	// When shrinking, broaden the effective kernel support so that we still
5444	// visit every source pixel.
5445	xHalfWidth, xKernelArgScale := q.Support, 1.0
5446	if xscale > 1 {
5447		xHalfWidth *= xscale
5448		xKernelArgScale = 1 / xscale
5449	}
5450	yHalfWidth, yKernelArgScale := q.Support, 1.0
5451	if yscale > 1 {
5452		yHalfWidth *= yscale
5453		yKernelArgScale = 1 / yscale
5454	}
5455
5456	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5457	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5458
5459	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5460		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5461		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5462		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5463			dxf := float64(dr.Min.X+int(dx)) + 0.5
5464			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5465			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5466			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5467				continue
5468			}
5469
5470			// TODO: adjust the bias so that we can use int(f) instead
5471			// of math.Floor(f) and math.Ceil(f).
5472			sx += float64(bias.X)
5473			sx -= 0.5
5474			ix := int(math.Floor(sx - xHalfWidth))
5475			if ix < sr.Min.X {
5476				ix = sr.Min.X
5477			}
5478			jx := int(math.Ceil(sx + xHalfWidth))
5479			if jx > sr.Max.X {
5480				jx = sr.Max.X
5481			}
5482
5483			totalXWeight := 0.0
5484			for kx := ix; kx < jx; kx++ {
5485				xWeight := 0.0
5486				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5487					xWeight = q.At(t)
5488				}
5489				xWeights[kx-ix] = xWeight
5490				totalXWeight += xWeight
5491			}
5492			for x := range xWeights[:jx-ix] {
5493				xWeights[x] /= totalXWeight
5494			}
5495
5496			sy += float64(bias.Y)
5497			sy -= 0.5
5498			iy := int(math.Floor(sy - yHalfWidth))
5499			if iy < sr.Min.Y {
5500				iy = sr.Min.Y
5501			}
5502			jy := int(math.Ceil(sy + yHalfWidth))
5503			if jy > sr.Max.Y {
5504				jy = sr.Max.Y
5505			}
5506
5507			totalYWeight := 0.0
5508			for ky := iy; ky < jy; ky++ {
5509				yWeight := 0.0
5510				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5511					yWeight = q.At(t)
5512				}
5513				yWeights[ky-iy] = yWeight
5514				totalYWeight += yWeight
5515			}
5516			for y := range yWeights[:jy-iy] {
5517				yWeights[y] /= totalYWeight
5518			}
5519
5520			var pr, pg, pb, pa float64
5521			for ky := iy; ky < jy; ky++ {
5522				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5523					for kx := ix; kx < jx; kx++ {
5524						if w := xWeights[kx-ix] * yWeight; w != 0 {
5525							pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
5526							pru := uint32(src.Pix[pi+0]) * 0x101
5527							pgu := uint32(src.Pix[pi+1]) * 0x101
5528							pbu := uint32(src.Pix[pi+2]) * 0x101
5529							pau := uint32(src.Pix[pi+3]) * 0x101
5530							pr += float64(pru) * w
5531							pg += float64(pgu) * w
5532							pb += float64(pbu) * w
5533							pa += float64(pau) * w
5534						}
5535					}
5536				}
5537			}
5538
5539			if pr > pa {
5540				pr = pa
5541			}
5542			if pg > pa {
5543				pg = pa
5544			}
5545			if pb > pa {
5546				pb = pa
5547			}
5548
5549			pr0 := uint32(fffftou(pr))
5550			pg0 := uint32(fffftou(pg))
5551			pb0 := uint32(fffftou(pb))
5552			pa0 := uint32(fffftou(pa))
5553			pa1 := (0xffff - uint32(pa0)) * 0x101
5554			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
5555			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
5556			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
5557			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
5558		}
5559	}
5560}
5561
5562func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5563	// When shrinking, broaden the effective kernel support so that we still
5564	// visit every source pixel.
5565	xHalfWidth, xKernelArgScale := q.Support, 1.0
5566	if xscale > 1 {
5567		xHalfWidth *= xscale
5568		xKernelArgScale = 1 / xscale
5569	}
5570	yHalfWidth, yKernelArgScale := q.Support, 1.0
5571	if yscale > 1 {
5572		yHalfWidth *= yscale
5573		yKernelArgScale = 1 / yscale
5574	}
5575
5576	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5577	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5578
5579	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5580		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5581		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5582		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5583			dxf := float64(dr.Min.X+int(dx)) + 0.5
5584			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5585			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5586			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5587				continue
5588			}
5589
5590			// TODO: adjust the bias so that we can use int(f) instead
5591			// of math.Floor(f) and math.Ceil(f).
5592			sx += float64(bias.X)
5593			sx -= 0.5
5594			ix := int(math.Floor(sx - xHalfWidth))
5595			if ix < sr.Min.X {
5596				ix = sr.Min.X
5597			}
5598			jx := int(math.Ceil(sx + xHalfWidth))
5599			if jx > sr.Max.X {
5600				jx = sr.Max.X
5601			}
5602
5603			totalXWeight := 0.0
5604			for kx := ix; kx < jx; kx++ {
5605				xWeight := 0.0
5606				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5607					xWeight = q.At(t)
5608				}
5609				xWeights[kx-ix] = xWeight
5610				totalXWeight += xWeight
5611			}
5612			for x := range xWeights[:jx-ix] {
5613				xWeights[x] /= totalXWeight
5614			}
5615
5616			sy += float64(bias.Y)
5617			sy -= 0.5
5618			iy := int(math.Floor(sy - yHalfWidth))
5619			if iy < sr.Min.Y {
5620				iy = sr.Min.Y
5621			}
5622			jy := int(math.Ceil(sy + yHalfWidth))
5623			if jy > sr.Max.Y {
5624				jy = sr.Max.Y
5625			}
5626
5627			totalYWeight := 0.0
5628			for ky := iy; ky < jy; ky++ {
5629				yWeight := 0.0
5630				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5631					yWeight = q.At(t)
5632				}
5633				yWeights[ky-iy] = yWeight
5634				totalYWeight += yWeight
5635			}
5636			for y := range yWeights[:jy-iy] {
5637				yWeights[y] /= totalYWeight
5638			}
5639
5640			var pr, pg, pb, pa float64
5641			for ky := iy; ky < jy; ky++ {
5642				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5643					for kx := ix; kx < jx; kx++ {
5644						if w := xWeights[kx-ix] * yWeight; w != 0 {
5645							pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
5646							pru := uint32(src.Pix[pi+0]) * 0x101
5647							pgu := uint32(src.Pix[pi+1]) * 0x101
5648							pbu := uint32(src.Pix[pi+2]) * 0x101
5649							pau := uint32(src.Pix[pi+3]) * 0x101
5650							pr += float64(pru) * w
5651							pg += float64(pgu) * w
5652							pb += float64(pbu) * w
5653							pa += float64(pau) * w
5654						}
5655					}
5656				}
5657			}
5658
5659			if pr > pa {
5660				pr = pa
5661			}
5662			if pg > pa {
5663				pg = pa
5664			}
5665			if pb > pa {
5666				pb = pa
5667			}
5668
5669			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
5670			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
5671			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
5672			dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
5673		}
5674	}
5675}
5676
5677func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5678	// When shrinking, broaden the effective kernel support so that we still
5679	// visit every source pixel.
5680	xHalfWidth, xKernelArgScale := q.Support, 1.0
5681	if xscale > 1 {
5682		xHalfWidth *= xscale
5683		xKernelArgScale = 1 / xscale
5684	}
5685	yHalfWidth, yKernelArgScale := q.Support, 1.0
5686	if yscale > 1 {
5687		yHalfWidth *= yscale
5688		yKernelArgScale = 1 / yscale
5689	}
5690
5691	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5692	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5693
5694	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5695		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5696		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5697		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5698			dxf := float64(dr.Min.X+int(dx)) + 0.5
5699			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5700			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5701			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5702				continue
5703			}
5704
5705			// TODO: adjust the bias so that we can use int(f) instead
5706			// of math.Floor(f) and math.Ceil(f).
5707			sx += float64(bias.X)
5708			sx -= 0.5
5709			ix := int(math.Floor(sx - xHalfWidth))
5710			if ix < sr.Min.X {
5711				ix = sr.Min.X
5712			}
5713			jx := int(math.Ceil(sx + xHalfWidth))
5714			if jx > sr.Max.X {
5715				jx = sr.Max.X
5716			}
5717
5718			totalXWeight := 0.0
5719			for kx := ix; kx < jx; kx++ {
5720				xWeight := 0.0
5721				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5722					xWeight = q.At(t)
5723				}
5724				xWeights[kx-ix] = xWeight
5725				totalXWeight += xWeight
5726			}
5727			for x := range xWeights[:jx-ix] {
5728				xWeights[x] /= totalXWeight
5729			}
5730
5731			sy += float64(bias.Y)
5732			sy -= 0.5
5733			iy := int(math.Floor(sy - yHalfWidth))
5734			if iy < sr.Min.Y {
5735				iy = sr.Min.Y
5736			}
5737			jy := int(math.Ceil(sy + yHalfWidth))
5738			if jy > sr.Max.Y {
5739				jy = sr.Max.Y
5740			}
5741
5742			totalYWeight := 0.0
5743			for ky := iy; ky < jy; ky++ {
5744				yWeight := 0.0
5745				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5746					yWeight = q.At(t)
5747				}
5748				yWeights[ky-iy] = yWeight
5749				totalYWeight += yWeight
5750			}
5751			for y := range yWeights[:jy-iy] {
5752				yWeights[y] /= totalYWeight
5753			}
5754
5755			var pr, pg, pb float64
5756			for ky := iy; ky < jy; ky++ {
5757				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5758					for kx := ix; kx < jx; kx++ {
5759						if w := xWeights[kx-ix] * yWeight; w != 0 {
5760							pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
5761							pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X)
5762
5763							// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
5764							pyy1 := int(src.Y[pi]) * 0x10101
5765							pcb1 := int(src.Cb[pj]) - 128
5766							pcr1 := int(src.Cr[pj]) - 128
5767							pru := (pyy1 + 91881*pcr1) >> 8
5768							pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
5769							pbu := (pyy1 + 116130*pcb1) >> 8
5770							if pru < 0 {
5771								pru = 0
5772							} else if pru > 0xffff {
5773								pru = 0xffff
5774							}
5775							if pgu < 0 {
5776								pgu = 0
5777							} else if pgu > 0xffff {
5778								pgu = 0xffff
5779							}
5780							if pbu < 0 {
5781								pbu = 0
5782							} else if pbu > 0xffff {
5783								pbu = 0xffff
5784							}
5785
5786							pr += float64(pru) * w
5787							pg += float64(pgu) * w
5788							pb += float64(pbu) * w
5789						}
5790					}
5791				}
5792			}
5793			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
5794			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
5795			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
5796			dst.Pix[d+3] = 0xff
5797		}
5798	}
5799}
5800
5801func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5802	// When shrinking, broaden the effective kernel support so that we still
5803	// visit every source pixel.
5804	xHalfWidth, xKernelArgScale := q.Support, 1.0
5805	if xscale > 1 {
5806		xHalfWidth *= xscale
5807		xKernelArgScale = 1 / xscale
5808	}
5809	yHalfWidth, yKernelArgScale := q.Support, 1.0
5810	if yscale > 1 {
5811		yHalfWidth *= yscale
5812		yKernelArgScale = 1 / yscale
5813	}
5814
5815	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5816	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5817
5818	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5819		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5820		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5821		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5822			dxf := float64(dr.Min.X+int(dx)) + 0.5
5823			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5824			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5825			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5826				continue
5827			}
5828
5829			// TODO: adjust the bias so that we can use int(f) instead
5830			// of math.Floor(f) and math.Ceil(f).
5831			sx += float64(bias.X)
5832			sx -= 0.5
5833			ix := int(math.Floor(sx - xHalfWidth))
5834			if ix < sr.Min.X {
5835				ix = sr.Min.X
5836			}
5837			jx := int(math.Ceil(sx + xHalfWidth))
5838			if jx > sr.Max.X {
5839				jx = sr.Max.X
5840			}
5841
5842			totalXWeight := 0.0
5843			for kx := ix; kx < jx; kx++ {
5844				xWeight := 0.0
5845				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5846					xWeight = q.At(t)
5847				}
5848				xWeights[kx-ix] = xWeight
5849				totalXWeight += xWeight
5850			}
5851			for x := range xWeights[:jx-ix] {
5852				xWeights[x] /= totalXWeight
5853			}
5854
5855			sy += float64(bias.Y)
5856			sy -= 0.5
5857			iy := int(math.Floor(sy - yHalfWidth))
5858			if iy < sr.Min.Y {
5859				iy = sr.Min.Y
5860			}
5861			jy := int(math.Ceil(sy + yHalfWidth))
5862			if jy > sr.Max.Y {
5863				jy = sr.Max.Y
5864			}
5865
5866			totalYWeight := 0.0
5867			for ky := iy; ky < jy; ky++ {
5868				yWeight := 0.0
5869				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5870					yWeight = q.At(t)
5871				}
5872				yWeights[ky-iy] = yWeight
5873				totalYWeight += yWeight
5874			}
5875			for y := range yWeights[:jy-iy] {
5876				yWeights[y] /= totalYWeight
5877			}
5878
5879			var pr, pg, pb float64
5880			for ky := iy; ky < jy; ky++ {
5881				if yWeight := yWeights[ky-iy]; yWeight != 0 {
5882					for kx := ix; kx < jx; kx++ {
5883						if w := xWeights[kx-ix] * yWeight; w != 0 {
5884							pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
5885							pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
5886
5887							// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
5888							pyy1 := int(src.Y[pi]) * 0x10101
5889							pcb1 := int(src.Cb[pj]) - 128
5890							pcr1 := int(src.Cr[pj]) - 128
5891							pru := (pyy1 + 91881*pcr1) >> 8
5892							pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
5893							pbu := (pyy1 + 116130*pcb1) >> 8
5894							if pru < 0 {
5895								pru = 0
5896							} else if pru > 0xffff {
5897								pru = 0xffff
5898							}
5899							if pgu < 0 {
5900								pgu = 0
5901							} else if pgu > 0xffff {
5902								pgu = 0xffff
5903							}
5904							if pbu < 0 {
5905								pbu = 0
5906							} else if pbu > 0xffff {
5907								pbu = 0xffff
5908							}
5909
5910							pr += float64(pru) * w
5911							pg += float64(pgu) * w
5912							pb += float64(pbu) * w
5913						}
5914					}
5915				}
5916			}
5917			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
5918			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
5919			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
5920			dst.Pix[d+3] = 0xff
5921		}
5922	}
5923}
5924
5925func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
5926	// When shrinking, broaden the effective kernel support so that we still
5927	// visit every source pixel.
5928	xHalfWidth, xKernelArgScale := q.Support, 1.0
5929	if xscale > 1 {
5930		xHalfWidth *= xscale
5931		xKernelArgScale = 1 / xscale
5932	}
5933	yHalfWidth, yKernelArgScale := q.Support, 1.0
5934	if yscale > 1 {
5935		yHalfWidth *= yscale
5936		yKernelArgScale = 1 / yscale
5937	}
5938
5939	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
5940	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
5941
5942	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
5943		dyf := float64(dr.Min.Y+int(dy)) + 0.5
5944		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
5945		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
5946			dxf := float64(dr.Min.X+int(dx)) + 0.5
5947			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
5948			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
5949			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
5950				continue
5951			}
5952
5953			// TODO: adjust the bias so that we can use int(f) instead
5954			// of math.Floor(f) and math.Ceil(f).
5955			sx += float64(bias.X)
5956			sx -= 0.5
5957			ix := int(math.Floor(sx - xHalfWidth))
5958			if ix < sr.Min.X {
5959				ix = sr.Min.X
5960			}
5961			jx := int(math.Ceil(sx + xHalfWidth))
5962			if jx > sr.Max.X {
5963				jx = sr.Max.X
5964			}
5965
5966			totalXWeight := 0.0
5967			for kx := ix; kx < jx; kx++ {
5968				xWeight := 0.0
5969				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
5970					xWeight = q.At(t)
5971				}
5972				xWeights[kx-ix] = xWeight
5973				totalXWeight += xWeight
5974			}
5975			for x := range xWeights[:jx-ix] {
5976				xWeights[x] /= totalXWeight
5977			}
5978
5979			sy += float64(bias.Y)
5980			sy -= 0.5
5981			iy := int(math.Floor(sy - yHalfWidth))
5982			if iy < sr.Min.Y {
5983				iy = sr.Min.Y
5984			}
5985			jy := int(math.Ceil(sy + yHalfWidth))
5986			if jy > sr.Max.Y {
5987				jy = sr.Max.Y
5988			}
5989
5990			totalYWeight := 0.0
5991			for ky := iy; ky < jy; ky++ {
5992				yWeight := 0.0
5993				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
5994					yWeight = q.At(t)
5995				}
5996				yWeights[ky-iy] = yWeight
5997				totalYWeight += yWeight
5998			}
5999			for y := range yWeights[:jy-iy] {
6000				yWeights[y] /= totalYWeight
6001			}
6002
6003			var pr, pg, pb float64
6004			for ky := iy; ky < jy; ky++ {
6005				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6006					for kx := ix; kx < jx; kx++ {
6007						if w := xWeights[kx-ix] * yWeight; w != 0 {
6008							pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
6009							pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
6010
6011							// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
6012							pyy1 := int(src.Y[pi]) * 0x10101
6013							pcb1 := int(src.Cb[pj]) - 128
6014							pcr1 := int(src.Cr[pj]) - 128
6015							pru := (pyy1 + 91881*pcr1) >> 8
6016							pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
6017							pbu := (pyy1 + 116130*pcb1) >> 8
6018							if pru < 0 {
6019								pru = 0
6020							} else if pru > 0xffff {
6021								pru = 0xffff
6022							}
6023							if pgu < 0 {
6024								pgu = 0
6025							} else if pgu > 0xffff {
6026								pgu = 0xffff
6027							}
6028							if pbu < 0 {
6029								pbu = 0
6030							} else if pbu > 0xffff {
6031								pbu = 0xffff
6032							}
6033
6034							pr += float64(pru) * w
6035							pg += float64(pgu) * w
6036							pb += float64(pbu) * w
6037						}
6038					}
6039				}
6040			}
6041			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
6042			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
6043			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
6044			dst.Pix[d+3] = 0xff
6045		}
6046	}
6047}
6048
6049func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
6050	// When shrinking, broaden the effective kernel support so that we still
6051	// visit every source pixel.
6052	xHalfWidth, xKernelArgScale := q.Support, 1.0
6053	if xscale > 1 {
6054		xHalfWidth *= xscale
6055		xKernelArgScale = 1 / xscale
6056	}
6057	yHalfWidth, yKernelArgScale := q.Support, 1.0
6058	if yscale > 1 {
6059		yHalfWidth *= yscale
6060		yKernelArgScale = 1 / yscale
6061	}
6062
6063	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
6064	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
6065
6066	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
6067		dyf := float64(dr.Min.Y+int(dy)) + 0.5
6068		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
6069		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
6070			dxf := float64(dr.Min.X+int(dx)) + 0.5
6071			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
6072			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
6073			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
6074				continue
6075			}
6076
6077			// TODO: adjust the bias so that we can use int(f) instead
6078			// of math.Floor(f) and math.Ceil(f).
6079			sx += float64(bias.X)
6080			sx -= 0.5
6081			ix := int(math.Floor(sx - xHalfWidth))
6082			if ix < sr.Min.X {
6083				ix = sr.Min.X
6084			}
6085			jx := int(math.Ceil(sx + xHalfWidth))
6086			if jx > sr.Max.X {
6087				jx = sr.Max.X
6088			}
6089
6090			totalXWeight := 0.0
6091			for kx := ix; kx < jx; kx++ {
6092				xWeight := 0.0
6093				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
6094					xWeight = q.At(t)
6095				}
6096				xWeights[kx-ix] = xWeight
6097				totalXWeight += xWeight
6098			}
6099			for x := range xWeights[:jx-ix] {
6100				xWeights[x] /= totalXWeight
6101			}
6102
6103			sy += float64(bias.Y)
6104			sy -= 0.5
6105			iy := int(math.Floor(sy - yHalfWidth))
6106			if iy < sr.Min.Y {
6107				iy = sr.Min.Y
6108			}
6109			jy := int(math.Ceil(sy + yHalfWidth))
6110			if jy > sr.Max.Y {
6111				jy = sr.Max.Y
6112			}
6113
6114			totalYWeight := 0.0
6115			for ky := iy; ky < jy; ky++ {
6116				yWeight := 0.0
6117				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
6118					yWeight = q.At(t)
6119				}
6120				yWeights[ky-iy] = yWeight
6121				totalYWeight += yWeight
6122			}
6123			for y := range yWeights[:jy-iy] {
6124				yWeights[y] /= totalYWeight
6125			}
6126
6127			var pr, pg, pb float64
6128			for ky := iy; ky < jy; ky++ {
6129				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6130					for kx := ix; kx < jx; kx++ {
6131						if w := xWeights[kx-ix] * yWeight; w != 0 {
6132							pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
6133							pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X)
6134
6135							// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
6136							pyy1 := int(src.Y[pi]) * 0x10101
6137							pcb1 := int(src.Cb[pj]) - 128
6138							pcr1 := int(src.Cr[pj]) - 128
6139							pru := (pyy1 + 91881*pcr1) >> 8
6140							pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
6141							pbu := (pyy1 + 116130*pcb1) >> 8
6142							if pru < 0 {
6143								pru = 0
6144							} else if pru > 0xffff {
6145								pru = 0xffff
6146							}
6147							if pgu < 0 {
6148								pgu = 0
6149							} else if pgu > 0xffff {
6150								pgu = 0xffff
6151							}
6152							if pbu < 0 {
6153								pbu = 0
6154							} else if pbu > 0xffff {
6155								pbu = 0xffff
6156							}
6157
6158							pr += float64(pru) * w
6159							pg += float64(pgu) * w
6160							pb += float64(pbu) * w
6161						}
6162					}
6163				}
6164			}
6165			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
6166			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
6167			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
6168			dst.Pix[d+3] = 0xff
6169		}
6170	}
6171}
6172
6173func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
6174	// When shrinking, broaden the effective kernel support so that we still
6175	// visit every source pixel.
6176	xHalfWidth, xKernelArgScale := q.Support, 1.0
6177	if xscale > 1 {
6178		xHalfWidth *= xscale
6179		xKernelArgScale = 1 / xscale
6180	}
6181	yHalfWidth, yKernelArgScale := q.Support, 1.0
6182	if yscale > 1 {
6183		yHalfWidth *= yscale
6184		yKernelArgScale = 1 / yscale
6185	}
6186
6187	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
6188	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
6189
6190	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
6191		dyf := float64(dr.Min.Y+int(dy)) + 0.5
6192		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
6193		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
6194			dxf := float64(dr.Min.X+int(dx)) + 0.5
6195			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
6196			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
6197			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
6198				continue
6199			}
6200
6201			// TODO: adjust the bias so that we can use int(f) instead
6202			// of math.Floor(f) and math.Ceil(f).
6203			sx += float64(bias.X)
6204			sx -= 0.5
6205			ix := int(math.Floor(sx - xHalfWidth))
6206			if ix < sr.Min.X {
6207				ix = sr.Min.X
6208			}
6209			jx := int(math.Ceil(sx + xHalfWidth))
6210			if jx > sr.Max.X {
6211				jx = sr.Max.X
6212			}
6213
6214			totalXWeight := 0.0
6215			for kx := ix; kx < jx; kx++ {
6216				xWeight := 0.0
6217				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
6218					xWeight = q.At(t)
6219				}
6220				xWeights[kx-ix] = xWeight
6221				totalXWeight += xWeight
6222			}
6223			for x := range xWeights[:jx-ix] {
6224				xWeights[x] /= totalXWeight
6225			}
6226
6227			sy += float64(bias.Y)
6228			sy -= 0.5
6229			iy := int(math.Floor(sy - yHalfWidth))
6230			if iy < sr.Min.Y {
6231				iy = sr.Min.Y
6232			}
6233			jy := int(math.Ceil(sy + yHalfWidth))
6234			if jy > sr.Max.Y {
6235				jy = sr.Max.Y
6236			}
6237
6238			totalYWeight := 0.0
6239			for ky := iy; ky < jy; ky++ {
6240				yWeight := 0.0
6241				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
6242					yWeight = q.At(t)
6243				}
6244				yWeights[ky-iy] = yWeight
6245				totalYWeight += yWeight
6246			}
6247			for y := range yWeights[:jy-iy] {
6248				yWeights[y] /= totalYWeight
6249			}
6250
6251			var pr, pg, pb, pa float64
6252			for ky := iy; ky < jy; ky++ {
6253				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6254					for kx := ix; kx < jx; kx++ {
6255						if w := xWeights[kx-ix] * yWeight; w != 0 {
6256							pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
6257							pr += float64(pru) * w
6258							pg += float64(pgu) * w
6259							pb += float64(pbu) * w
6260							pa += float64(pau) * w
6261						}
6262					}
6263				}
6264			}
6265
6266			if pr > pa {
6267				pr = pa
6268			}
6269			if pg > pa {
6270				pg = pa
6271			}
6272			if pb > pa {
6273				pb = pa
6274			}
6275
6276			pr0 := uint32(fffftou(pr))
6277			pg0 := uint32(fffftou(pg))
6278			pb0 := uint32(fffftou(pb))
6279			pa0 := uint32(fffftou(pa))
6280			pa1 := (0xffff - uint32(pa0)) * 0x101
6281			dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
6282			dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
6283			dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
6284			dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
6285		}
6286	}
6287}
6288
6289func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
6290	// When shrinking, broaden the effective kernel support so that we still
6291	// visit every source pixel.
6292	xHalfWidth, xKernelArgScale := q.Support, 1.0
6293	if xscale > 1 {
6294		xHalfWidth *= xscale
6295		xKernelArgScale = 1 / xscale
6296	}
6297	yHalfWidth, yKernelArgScale := q.Support, 1.0
6298	if yscale > 1 {
6299		yHalfWidth *= yscale
6300		yKernelArgScale = 1 / yscale
6301	}
6302
6303	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
6304	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
6305
6306	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
6307		dyf := float64(dr.Min.Y+int(dy)) + 0.5
6308		d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
6309		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
6310			dxf := float64(dr.Min.X+int(dx)) + 0.5
6311			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
6312			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
6313			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
6314				continue
6315			}
6316
6317			// TODO: adjust the bias so that we can use int(f) instead
6318			// of math.Floor(f) and math.Ceil(f).
6319			sx += float64(bias.X)
6320			sx -= 0.5
6321			ix := int(math.Floor(sx - xHalfWidth))
6322			if ix < sr.Min.X {
6323				ix = sr.Min.X
6324			}
6325			jx := int(math.Ceil(sx + xHalfWidth))
6326			if jx > sr.Max.X {
6327				jx = sr.Max.X
6328			}
6329
6330			totalXWeight := 0.0
6331			for kx := ix; kx < jx; kx++ {
6332				xWeight := 0.0
6333				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
6334					xWeight = q.At(t)
6335				}
6336				xWeights[kx-ix] = xWeight
6337				totalXWeight += xWeight
6338			}
6339			for x := range xWeights[:jx-ix] {
6340				xWeights[x] /= totalXWeight
6341			}
6342
6343			sy += float64(bias.Y)
6344			sy -= 0.5
6345			iy := int(math.Floor(sy - yHalfWidth))
6346			if iy < sr.Min.Y {
6347				iy = sr.Min.Y
6348			}
6349			jy := int(math.Ceil(sy + yHalfWidth))
6350			if jy > sr.Max.Y {
6351				jy = sr.Max.Y
6352			}
6353
6354			totalYWeight := 0.0
6355			for ky := iy; ky < jy; ky++ {
6356				yWeight := 0.0
6357				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
6358					yWeight = q.At(t)
6359				}
6360				yWeights[ky-iy] = yWeight
6361				totalYWeight += yWeight
6362			}
6363			for y := range yWeights[:jy-iy] {
6364				yWeights[y] /= totalYWeight
6365			}
6366
6367			var pr, pg, pb, pa float64
6368			for ky := iy; ky < jy; ky++ {
6369				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6370					for kx := ix; kx < jx; kx++ {
6371						if w := xWeights[kx-ix] * yWeight; w != 0 {
6372							pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
6373							pr += float64(pru) * w
6374							pg += float64(pgu) * w
6375							pb += float64(pbu) * w
6376							pa += float64(pau) * w
6377						}
6378					}
6379				}
6380			}
6381
6382			if pr > pa {
6383				pr = pa
6384			}
6385			if pg > pa {
6386				pg = pa
6387			}
6388			if pb > pa {
6389				pb = pa
6390			}
6391
6392			dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
6393			dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
6394			dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
6395			dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
6396		}
6397	}
6398}
6399
6400func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
6401	// When shrinking, broaden the effective kernel support so that we still
6402	// visit every source pixel.
6403	xHalfWidth, xKernelArgScale := q.Support, 1.0
6404	if xscale > 1 {
6405		xHalfWidth *= xscale
6406		xKernelArgScale = 1 / xscale
6407	}
6408	yHalfWidth, yKernelArgScale := q.Support, 1.0
6409	if yscale > 1 {
6410		yHalfWidth *= yscale
6411		yKernelArgScale = 1 / yscale
6412	}
6413
6414	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
6415	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
6416
6417	srcMask, smp := opts.SrcMask, opts.SrcMaskP
6418	dstMask, dmp := opts.DstMask, opts.DstMaskP
6419	dstColorRGBA64 := &color.RGBA64{}
6420	dstColor := color.Color(dstColorRGBA64)
6421	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
6422		dyf := float64(dr.Min.Y+int(dy)) + 0.5
6423		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
6424			dxf := float64(dr.Min.X+int(dx)) + 0.5
6425			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
6426			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
6427			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
6428				continue
6429			}
6430
6431			// TODO: adjust the bias so that we can use int(f) instead
6432			// of math.Floor(f) and math.Ceil(f).
6433			sx += float64(bias.X)
6434			sx -= 0.5
6435			ix := int(math.Floor(sx - xHalfWidth))
6436			if ix < sr.Min.X {
6437				ix = sr.Min.X
6438			}
6439			jx := int(math.Ceil(sx + xHalfWidth))
6440			if jx > sr.Max.X {
6441				jx = sr.Max.X
6442			}
6443
6444			totalXWeight := 0.0
6445			for kx := ix; kx < jx; kx++ {
6446				xWeight := 0.0
6447				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
6448					xWeight = q.At(t)
6449				}
6450				xWeights[kx-ix] = xWeight
6451				totalXWeight += xWeight
6452			}
6453			for x := range xWeights[:jx-ix] {
6454				xWeights[x] /= totalXWeight
6455			}
6456
6457			sy += float64(bias.Y)
6458			sy -= 0.5
6459			iy := int(math.Floor(sy - yHalfWidth))
6460			if iy < sr.Min.Y {
6461				iy = sr.Min.Y
6462			}
6463			jy := int(math.Ceil(sy + yHalfWidth))
6464			if jy > sr.Max.Y {
6465				jy = sr.Max.Y
6466			}
6467
6468			totalYWeight := 0.0
6469			for ky := iy; ky < jy; ky++ {
6470				yWeight := 0.0
6471				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
6472					yWeight = q.At(t)
6473				}
6474				yWeights[ky-iy] = yWeight
6475				totalYWeight += yWeight
6476			}
6477			for y := range yWeights[:jy-iy] {
6478				yWeights[y] /= totalYWeight
6479			}
6480
6481			var pr, pg, pb, pa float64
6482			for ky := iy; ky < jy; ky++ {
6483				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6484					for kx := ix; kx < jx; kx++ {
6485						if w := xWeights[kx-ix] * yWeight; w != 0 {
6486							pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
6487							if srcMask != nil {
6488								_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
6489								pru = pru * ma / 0xffff
6490								pgu = pgu * ma / 0xffff
6491								pbu = pbu * ma / 0xffff
6492								pau = pau * ma / 0xffff
6493							}
6494							pr += float64(pru) * w
6495							pg += float64(pgu) * w
6496							pb += float64(pbu) * w
6497							pa += float64(pau) * w
6498						}
6499					}
6500				}
6501			}
6502
6503			if pr > pa {
6504				pr = pa
6505			}
6506			if pg > pa {
6507				pg = pa
6508			}
6509			if pb > pa {
6510				pb = pa
6511			}
6512
6513			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
6514			pr0 := uint32(fffftou(pr))
6515			pg0 := uint32(fffftou(pg))
6516			pb0 := uint32(fffftou(pb))
6517			pa0 := uint32(fffftou(pa))
6518			if dstMask != nil {
6519				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
6520				pr0 = pr0 * ma / 0xffff
6521				pg0 = pg0 * ma / 0xffff
6522				pb0 = pb0 * ma / 0xffff
6523				pa0 = pa0 * ma / 0xffff
6524			}
6525			pa1 := 0xffff - pa0
6526			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
6527			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
6528			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
6529			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
6530			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
6531		}
6532	}
6533}
6534
6535func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
6536	// When shrinking, broaden the effective kernel support so that we still
6537	// visit every source pixel.
6538	xHalfWidth, xKernelArgScale := q.Support, 1.0
6539	if xscale > 1 {
6540		xHalfWidth *= xscale
6541		xKernelArgScale = 1 / xscale
6542	}
6543	yHalfWidth, yKernelArgScale := q.Support, 1.0
6544	if yscale > 1 {
6545		yHalfWidth *= yscale
6546		yKernelArgScale = 1 / yscale
6547	}
6548
6549	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
6550	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
6551
6552	srcMask, smp := opts.SrcMask, opts.SrcMaskP
6553	dstMask, dmp := opts.DstMask, opts.DstMaskP
6554	dstColorRGBA64 := &color.RGBA64{}
6555	dstColor := color.Color(dstColorRGBA64)
6556	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
6557		dyf := float64(dr.Min.Y+int(dy)) + 0.5
6558		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
6559			dxf := float64(dr.Min.X+int(dx)) + 0.5
6560			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
6561			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
6562			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
6563				continue
6564			}
6565
6566			// TODO: adjust the bias so that we can use int(f) instead
6567			// of math.Floor(f) and math.Ceil(f).
6568			sx += float64(bias.X)
6569			sx -= 0.5
6570			ix := int(math.Floor(sx - xHalfWidth))
6571			if ix < sr.Min.X {
6572				ix = sr.Min.X
6573			}
6574			jx := int(math.Ceil(sx + xHalfWidth))
6575			if jx > sr.Max.X {
6576				jx = sr.Max.X
6577			}
6578
6579			totalXWeight := 0.0
6580			for kx := ix; kx < jx; kx++ {
6581				xWeight := 0.0
6582				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
6583					xWeight = q.At(t)
6584				}
6585				xWeights[kx-ix] = xWeight
6586				totalXWeight += xWeight
6587			}
6588			for x := range xWeights[:jx-ix] {
6589				xWeights[x] /= totalXWeight
6590			}
6591
6592			sy += float64(bias.Y)
6593			sy -= 0.5
6594			iy := int(math.Floor(sy - yHalfWidth))
6595			if iy < sr.Min.Y {
6596				iy = sr.Min.Y
6597			}
6598			jy := int(math.Ceil(sy + yHalfWidth))
6599			if jy > sr.Max.Y {
6600				jy = sr.Max.Y
6601			}
6602
6603			totalYWeight := 0.0
6604			for ky := iy; ky < jy; ky++ {
6605				yWeight := 0.0
6606				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
6607					yWeight = q.At(t)
6608				}
6609				yWeights[ky-iy] = yWeight
6610				totalYWeight += yWeight
6611			}
6612			for y := range yWeights[:jy-iy] {
6613				yWeights[y] /= totalYWeight
6614			}
6615
6616			var pr, pg, pb, pa float64
6617			for ky := iy; ky < jy; ky++ {
6618				if yWeight := yWeights[ky-iy]; yWeight != 0 {
6619					for kx := ix; kx < jx; kx++ {
6620						if w := xWeights[kx-ix] * yWeight; w != 0 {
6621							pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
6622							if srcMask != nil {
6623								_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
6624								pru = pru * ma / 0xffff
6625								pgu = pgu * ma / 0xffff
6626								pbu = pbu * ma / 0xffff
6627								pau = pau * ma / 0xffff
6628							}
6629							pr += float64(pru) * w
6630							pg += float64(pgu) * w
6631							pb += float64(pbu) * w
6632							pa += float64(pau) * w
6633						}
6634					}
6635				}
6636			}
6637
6638			if pr > pa {
6639				pr = pa
6640			}
6641			if pg > pa {
6642				pg = pa
6643			}
6644			if pb > pa {
6645				pb = pa
6646			}
6647
6648			if dstMask != nil {
6649				qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
6650				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
6651				pr := uint32(fffftou(pr)) * ma / 0xffff
6652				pg := uint32(fffftou(pg)) * ma / 0xffff
6653				pb := uint32(fffftou(pb)) * ma / 0xffff
6654				pa := uint32(fffftou(pa)) * ma / 0xffff
6655				pa1 := 0xffff - ma
6656				dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
6657				dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
6658				dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
6659				dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
6660				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
6661			} else {
6662				dstColorRGBA64.R = fffftou(pr)
6663				dstColorRGBA64.G = fffftou(pg)
6664				dstColorRGBA64.B = fffftou(pb)
6665				dstColorRGBA64.A = fffftou(pa)
6666				dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
6667			}
6668		}
6669	}
6670}
6671