func()

in draw/impl.go [6400:6533]


func (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) {
	// When shrinking, broaden the effective kernel support so that we still
	// visit every source pixel.
	xHalfWidth, xKernelArgScale := q.Support, 1.0
	if xscale > 1 {
		xHalfWidth *= xscale
		xKernelArgScale = 1 / xscale
	}
	yHalfWidth, yKernelArgScale := q.Support, 1.0
	if yscale > 1 {
		yHalfWidth *= yscale
		yKernelArgScale = 1 / yscale
	}

	xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
	yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))

	srcMask, smp := opts.SrcMask, opts.SrcMaskP
	dstMask, dmp := opts.DstMask, opts.DstMaskP
	dstColorRGBA64 := &color.RGBA64{}
	dstColor := color.Color(dstColorRGBA64)
	for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
		dyf := float64(dr.Min.Y+int(dy)) + 0.5
		for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
			dxf := float64(dr.Min.X+int(dx)) + 0.5
			sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
			sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
			if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
				continue
			}

			// TODO: adjust the bias so that we can use int(f) instead
			// of math.Floor(f) and math.Ceil(f).
			sx += float64(bias.X)
			sx -= 0.5
			ix := int(math.Floor(sx - xHalfWidth))
			if ix < sr.Min.X {
				ix = sr.Min.X
			}
			jx := int(math.Ceil(sx + xHalfWidth))
			if jx > sr.Max.X {
				jx = sr.Max.X
			}

			totalXWeight := 0.0
			for kx := ix; kx < jx; kx++ {
				xWeight := 0.0
				if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
					xWeight = q.At(t)
				}
				xWeights[kx-ix] = xWeight
				totalXWeight += xWeight
			}
			for x := range xWeights[:jx-ix] {
				xWeights[x] /= totalXWeight
			}

			sy += float64(bias.Y)
			sy -= 0.5
			iy := int(math.Floor(sy - yHalfWidth))
			if iy < sr.Min.Y {
				iy = sr.Min.Y
			}
			jy := int(math.Ceil(sy + yHalfWidth))
			if jy > sr.Max.Y {
				jy = sr.Max.Y
			}

			totalYWeight := 0.0
			for ky := iy; ky < jy; ky++ {
				yWeight := 0.0
				if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
					yWeight = q.At(t)
				}
				yWeights[ky-iy] = yWeight
				totalYWeight += yWeight
			}
			for y := range yWeights[:jy-iy] {
				yWeights[y] /= totalYWeight
			}

			var pr, pg, pb, pa float64
			for ky := iy; ky < jy; ky++ {
				if yWeight := yWeights[ky-iy]; yWeight != 0 {
					for kx := ix; kx < jx; kx++ {
						if w := xWeights[kx-ix] * yWeight; w != 0 {
							pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
							if srcMask != nil {
								_, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
								pru = pru * ma / 0xffff
								pgu = pgu * ma / 0xffff
								pbu = pbu * ma / 0xffff
								pau = pau * ma / 0xffff
							}
							pr += float64(pru) * w
							pg += float64(pgu) * w
							pb += float64(pbu) * w
							pa += float64(pau) * w
						}
					}
				}
			}

			if pr > pa {
				pr = pa
			}
			if pg > pa {
				pg = pa
			}
			if pb > pa {
				pb = pa
			}

			qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
			pr0 := uint32(fffftou(pr))
			pg0 := uint32(fffftou(pg))
			pb0 := uint32(fffftou(pb))
			pa0 := uint32(fffftou(pa))
			if dstMask != nil {
				_, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
				pr0 = pr0 * ma / 0xffff
				pg0 = pg0 * ma / 0xffff
				pb0 = pb0 * ma / 0xffff
				pa0 = pa0 * ma / 0xffff
			}
			pa1 := 0xffff - pa0
			dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
			dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
			dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
			dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
			dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
		}
	}
}