github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/image/draw/impl.go (about)

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