예제 #1
0
파일: nycbcra.go 프로젝트: 2722/lantern
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *Image) SubImage(r image.Rectangle) image.Image {
	// TODO: share code with image.NewYCbCr when this type moves into the
	// standard image package.
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &Image{
			YCbCr: image.YCbCr{
				SubsampleRatio: p.SubsampleRatio,
			},
		}
	}
	yi := p.YOffset(r.Min.X, r.Min.Y)
	ci := p.COffset(r.Min.X, r.Min.Y)
	ai := p.AOffset(r.Min.X, r.Min.Y)
	return &Image{
		YCbCr: image.YCbCr{
			Y:              p.Y[yi:],
			Cb:             p.Cb[ci:],
			Cr:             p.Cr[ci:],
			SubsampleRatio: p.SubsampleRatio,
			YStride:        p.YStride,
			CStride:        p.CStride,
			Rect:           r,
		},
		A:       p.A[ai:],
		AStride: p.AStride,
	}
}
예제 #2
0
파일: xgb.go 프로젝트: Zwobot/go.wde
func (buffer Image) CopyRGBA(src *image.RGBA, r image.Rectangle) {
	// clip r against each image's bounds and move sp accordingly (see draw.clip())
	sp := image.ZP
	orig := r.Min
	r = r.Intersect(buffer.Bounds())
	r = r.Intersect(src.Bounds().Add(orig.Sub(sp)))
	dx := r.Min.X - orig.X
	dy := r.Min.Y - orig.Y
	(sp).X += dx
	(sp).Y += dy

	i0 := (r.Min.X - buffer.Rect.Min.X) * 4
	i1 := (r.Max.X - buffer.Rect.Min.X) * 4
	si0 := (sp.X - src.Rect.Min.X) * 4
	yMax := r.Max.Y - buffer.Rect.Min.Y

	y := r.Min.Y - buffer.Rect.Min.Y
	sy := sp.Y - src.Rect.Min.Y
	for ; y != yMax; y, sy = y+1, sy+1 {
		dpix := buffer.Pix[y*buffer.Stride:]
		spix := src.Pix[sy*src.Stride:]

		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
			dpix[i+0] = spix[si+2]
			dpix[i+1] = spix[si+1]
			dpix[i+2] = spix[si+0]
			dpix[i+3] = spix[si+3]
		}
	}
}
예제 #3
0
파일: average.go 프로젝트: buth/imageutil
func AverageNRGBA64(rect image.Rectangle, img *image.NRGBA64) color.NRGBA64 {

	// Only use the area of the rectangle that overlaps with the image bounds.
	rect = rect.Intersect(img.Bounds())

	// Determine whether or not there's any area over which to determine an
	// average.
	d := uint64(rect.Dx() * rect.Dy())
	if d == 0 {
		return color.NRGBA64{}
	}

	var r, g, b, a uint64
	AllPointsRP(
		func(pt image.Point) {
			c := img.NRGBA64At(pt.X, pt.Y)
			r += uint64(c.R)
			g += uint64(c.G)
			b += uint64(c.B)
			a += uint64(c.A)
		},
	)(rect)

	return color.NRGBA64{
		R: uint16(r / d),
		G: uint16(g / d),
		B: uint16(b / d),
		A: uint16(a / d),
	}
}
예제 #4
0
파일: transform.go 프로젝트: eliquious/gift
func (p *cropToSizeFilter) Bounds(srcBounds image.Rectangle) (dstBounds image.Rectangle) {
	if p.w <= 0 || p.h <= 0 {
		return image.Rect(0, 0, 0, 0)
	}
	pt := anchorPt(srcBounds, p.w, p.h, p.anchor)
	r := image.Rect(0, 0, p.w, p.h).Add(pt)
	b := srcBounds.Intersect(r)
	return b.Sub(b.Min)
}
예제 #5
0
// SliceImage returns an image which is a view onto a portion of img.
// The returned image has the specified width and height,
// but all draw operations are clipped to r.
// The origin of img is aligned with p. Where img
// overlaps with r, it will be used for drawing operations.
//
func SliceImage(width, height int, r image.Rectangle, img draw.Image, p image.Point) draw.Image {
	// TODO: detect when img is itself a SliceImage and
	// use the underlying image directly.
	i := new(imageSlice)
	i.img = img
	i.r = r.Intersect(image.Rectangle{p, p.Add(img.Bounds().Size())})
	//debugp("actual sliced rectangle %v\n", i.r)
	i.p = p
	return i
}
예제 #6
0
파일: image64.go 프로젝트: rdwilliamson/dip
// A portion of p specified by r that shares underlying pixels.
func (p *Image64) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.Rect)
	if r.Empty() {
		return &Image64{}
	}
	i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X - p.Rect.Min.X)
	return &Image64{
		Pix:    p.Pix[i:],
		Stride: p.Stride,
		Rect:   r,
	}
}
예제 #7
0
// clip clips r against each image's bounds (after translating into
// the destination image's co-ordinate space) and shifts the point
// sp by the same amount as the change in r.Min.
func clip(dst draw.Image, r *image.Rectangle, src image.Image, sp *image.Point) {
	orig := r.Min
	*r = r.Intersect(dst.Bounds())
	*r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
	dx := r.Min.X - orig.X
	dy := r.Min.Y - orig.Y
	if dx == 0 && dy == 0 {
		return
	}
	(*sp).X += dx
	(*sp).Y += dy
}
예제 #8
0
파일: rgb.go 프로젝트: kodabb/image2
func (p *RGB) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.Rect)
	if r.Empty() {
		return &RGB{}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &RGB{
		Pix:    p.Pix[i:],
		Stride: p.Stride,
		Rect:   r,
	}
}
예제 #9
0
파일: ycc.go 프로젝트: Richardphp/noms
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *ycc) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.Rect)
	if r.Empty() {
		return &ycc{SubsampleRatio: p.SubsampleRatio}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &ycc{
		Pix:            p.Pix[i:],
		Stride:         p.Stride,
		Rect:           r,
		SubsampleRatio: p.SubsampleRatio,
	}
}
예제 #10
0
파일: frame.go 프로젝트: Ostsol/console
// SubFrame returns a Frame bounded by the rectangle r, sharing the data with
// the receiver.
func (f *Frame) SubFrame(r image.Rectangle) *Frame {
	r = r.Intersect(f.Bounds)

	if r.Empty() {
		return new(Frame)
	}

	return &Frame{
		Data:   f.Data[f.CellOffset(r.Min.X, r.Min.Y):],
		Bounds: r,
		Stride: f.Stride,
	}
}
예제 #11
0
// stolen from inferno's devdraw
func (b *Background) addFlush(r image.Rectangle, drawn bool) {
	r = r.Intersect(b.r)
	if b.flushrect.Empty() {
		if drawn {
			if b.imgflush != nil {
				b.imgflush(r)
			}
		} else {
			b.flushrect = r
			b.waste = 0
		}
		return
	}

	// if the new segment doesn't overlap with the
	// old segment and it has already been drawn,
	// do nothing except possible call the external flush.
	overlaps := b.flushrect.Overlaps(r)
	if !overlaps && drawn {
		if b.imgflush != nil {
			b.imgflush(r)
		}
		return
	}
	nbb := b.flushrect.Union(r)
	ar := r.Dx() * r.Dy()
	abb := b.flushrect.Dx() * b.flushrect.Dy()
	anbb := nbb.Dx() * nbb.Dy()

	// Area of new waste is area of new bb minus area of old bb,
	// less the area of the new segment, which we assume is not waste.
	// This could be negative, but that's OK.
	b.waste += anbb - abb - ar
	if b.waste < 0 {
		b.waste = 0
	}

	//absorb if:
	//	total area is small
	//	waste is less than half total area
	// 	rectangles touch
	if anbb <= 1024 || b.waste*2 < anbb || b.flushrect.Overlaps(r) {
		b.flushrect = nbb
		return
	}
	//  emit current state
	if !b.flushrect.Empty() {
		b.flush()
	}
	b.flushrect = r
}
예제 #12
0
파일: canvas.go 프로젝트: zenoss/rog-go
func (c *Canvas) Draw(dst draw.Image, clipr image.Rectangle) {
	clipr = clipr.Intersect(c.r)
	c.img = dst
	if c.background != nil {
		draw.Draw(dst, clipr, c.background, clipr.Min, draw.Over)
	}
	clipr = clipr.Intersect(c.r)
	for e := c.items.Front(); e != nil; e = e.Next() {
		it := e.Value.(Item)
		if it.Bbox().Overlaps(clipr) {
			it.Draw(dst, clipr)
		}
	}
}
예제 #13
0
func (i *imageSlice) DrawMask(r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op draw.Op) bool {
	//debugp("imageslice draw %v; sp %v\n", r, sp)
	dr := r.Intersect(i.r)
	if dr.Empty() {
		//debugp("-> clipped empty (r %v)\n", i.r)
		return true
	}
	delta := dr.Min.Sub(r.Min) // realignment because of clipping.
	sp = sp.Add(delta)
	mp = mp.Add(delta)
	dr = dr.Sub(i.p)
	//debugp("-> draw %v; sp %v\n", dr, sp)
	draw.DrawMask(i.img, dr, src, sp, mask, mp, op)
	return true
}
예제 #14
0
파일: rgb.go 프로젝트: bradberger/webp
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *RGBImage) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.XRect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return &RGBImage{}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &RGBImage{
		XPix:    p.XPix[i:],
		XStride: p.XStride,
		XRect:   r,
	}
}
예제 #15
0
파일: canvas.go 프로젝트: zenoss/rog-go
// drawAbove draws only those items above it.
//
func (c *Canvas) drawAbove(it Item, clipr image.Rectangle) {
	clipr = clipr.Intersect(c.r)
	drawing := false
	for e := c.items.Front(); e != nil; e = e.Next() {
		if e.Value == nil {
			panic("nil value - can't happen?")
			continue
		}
		item := e.Value.(Item)
		if drawing && item.Bbox().Overlaps(clipr) {
			item.Draw(c.img, clipr)
		} else if item == it {
			drawing = true
		}
	}
}
예제 #16
0
// SubImage provides a sub image of Image without copying image data.
// N.B. The standard library defines a similar function, but returns an
// image.Image. Here, we return xgraphics.Image so that we can use the extra
// methods defined by xgraphics on it.
//
// This method is cheap to call. It should be used to update only specific
// regions of an X pixmap to avoid sending an entire image to the X server when
// only a piece of it is updated.
//
// Note that if the intersection of `r` and `im` is empty, `nil` is returned.
func (im *Image) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(im.Rect)
	if r.Empty() {
		return nil
	}

	i := im.PixOffset(r.Min.X, r.Min.Y)
	return &Image{
		X:      im.X,
		Pixmap: im.Pixmap,
		Pix:    im.Pix[i:],
		Stride: im.Stride,
		Rect:   r,
		Subimg: true,
	}
}
예제 #17
0
//Used to determine which edge the squares are touching each other at.
//the boolean is which edge(x or Y) while travelling
func boundary_move(f image.Rectangle, other image.Rectangle) (image.Point, bool) {
	point := f.Intersect(other).Size()
	if point.X >= point.Y {
		if f.Min.Y >= other.Min.Y {
			return image.Point{0, -point.Y}, false
		} else {
			return image.Point{0, point.Y}, false
		}
	} else {
		if f.Min.X >= other.Min.X {
			return image.Point{-point.X, 0}, true
		} else {
			return image.Point{point.X, 0}, true
		}
	}
}
예제 #18
0
func newBitmapRenderer(img draw.Image, bound image.Rectangle, padding int) (eanRenderer, error) {
	bound = bound.Intersect(img.Bounds())
	inner := image.Rectangle{
		Min: bound.Min.Add(image.Pt(padding, padding)),
		Max: bound.Max.Sub(image.Pt(padding, padding)),
	}.Canon()
	converter, err := newEanCoordinateConverter(inner, measureBitmapFont)
	if err != nil {
		return nil, err
	}
	return &bitmapRenderer{
		img:       img,
		bound:     bound,
		converter: converter,
	}, nil
}
예제 #19
0
파일: ppm.go 프로젝트: tburke/netpbm
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *RGBM64) SubImage(r image.Rectangle) image.Image {
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to
	// be inside either r1 or r2 if the intersection is empty. Without
	// explicitly checking for this, the Pix[i:] expression below can
	// panic.
	if r.Empty() {
		return &RGBM64{}
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &RGBM64{
		Pix:    p.Pix[i:],
		Stride: p.Stride,
		Rect:   r,
	}
}
예제 #20
0
// SubImage creates a *FloatImg for a region within the original image
// this image is backed by the data in the original image which thus can
// be manipulated by manipulating the sub image
func (p *FloatImg) SubImage(r image.Rectangle) *FloatImg {
	r = r.Intersect(p.Rect)
	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Pix[i:] expression below can panic.
	if r.Empty() {
		return NewFloatImg(r, 0)
	}
	i := p.PixOffset(r.Min.X, r.Min.Y)
	return &FloatImg{
		Pix:            p.Pix[i:],
		Stride:         p.Stride,
		Rect:           r,
		Chancnt:        p.Chancnt,
		ColorFunc:      p.ColorFunc,
		ColorModelFunc: p.ColorModelFunc}
}
예제 #21
0
파일: grid.go 프로젝트: ionous/tile
// SubImage returns an image representing the portion of the image p visible through r.
// The returned value shares pixels with the original image.
func (p *Grid) SubGrid(r image.Rectangle) *Grid {
	r = r.Intersect(p.Rect)
	// If r1 and r2 are image.Rectangles, r1.Intersect(r2) is not guaranteed to be inside
	// either r1 or r2 if the intersection is empty. Without explicitly checking for
	// this, the Cells[i:] expression below can panic.
	if r.Empty() {
		return &Grid{}
	}
	i := p.CellsOffset(r.Min.X, r.Min.Y)
	return &Grid{
		Tile:     p.Tile[i:],
		Rot:      p.Rot[i:],
		Stride:   p.Stride,
		Rect:     r,
		CellSize: p.CellSize,
	}
}
예제 #22
0
파일: window.go 프로젝트: kardianos/garage
func (w *windowImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) {
	originalSRMin := sr.Min
	sr = sr.Intersect(src.Bounds())
	if sr.Empty() {
		return
	}
	dp = dp.Add(sr.Min.Sub(originalSRMin))
	// TODO: keep a texture around for this purpose?
	t, err := w.s.NewTexture(sr.Size())
	if err != nil {
		panic(err)
	}
	t.Upload(image.Point{}, src, sr)
	w.Draw(f64.Aff3{
		1, 0, float64(dp.X),
		0, 1, float64(dp.Y),
	}, t, t.Bounds(), draw.Src, nil)
	t.Release()
}
예제 #23
0
파일: texture.go 프로젝트: kardianos/garage
func (t *textureImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) {
	buf := src.(*bufferImpl)
	buf.preUpload()

	// src2dst is added to convert from the src coordinate space to the dst
	// coordinate space. It is subtracted to convert the other way.
	src2dst := dp.Sub(sr.Min)

	// Clip to the source.
	sr = sr.Intersect(buf.Bounds())

	// Clip to the destination.
	dr := sr.Add(src2dst)
	dr = dr.Intersect(t.Bounds())
	if dr.Empty() {
		return
	}

	// Bring dr.Min in dst-space back to src-space to get the pixel buffer offset.
	pix := buf.rgba.Pix[buf.rgba.PixOffset(dr.Min.X-src2dst.X, dr.Min.Y-src2dst.Y):]

	t.w.glctxMu.Lock()
	defer t.w.glctxMu.Unlock()

	t.w.glctx.BindTexture(gl.TEXTURE_2D, t.id)

	width := dr.Dx()
	if width*4 == buf.rgba.Stride {
		t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, dr.Min.Y, width, dr.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pix)
		return
	}
	// TODO: can we use GL_UNPACK_ROW_LENGTH with glPixelStorei for stride in
	// ES 3.0, instead of uploading the pixels row-by-row?
	for y, p := dr.Min.Y, 0; y < dr.Max.Y; y++ {
		t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, y, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix[p:])
		p += buf.rgba.Stride
	}
}
예제 #24
0
파일: average.go 프로젝트: buth/imageutil
func AverageGray16(rect image.Rectangle, img Channel) color.Gray16 {

	// Only use the area of the rectangle that overlaps with the image bounds.
	rect = rect.Intersect(img.Bounds())

	// Determine whether or not there's any area over which to determine an
	// average.
	d := uint64(rect.Dx() * rect.Dy())
	if d == 0 {
		return color.Gray16{}
	}

	var y uint64
	AllPointsRP(
		func(pt image.Point) {
			y += uint64(img.Gray16At(pt.X, pt.Y).Y)
		},
	)(rect)

	return color.Gray16{
		Y: uint16(y / d),
	}
}
예제 #25
0
파일: sierra.go 프로젝트: courtf/quant
// Draw performs error diffusion dithering.
//
// This method satisfies the draw.Drawer interface, implementing a dithering
// filter attributed to Frankie Sierra.  It uses the kernel
//
//	  X 2
//	1 1
func (d Sierra24A) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	pd, ok := dst.(*image.Paletted)
	if !ok {
		// dither211 currently requires a palette
		draw.Draw(dst, r, src, sp, draw.Src)
		return
	}
	// intersect r with both dst and src bounds, fix up sp.
	ir := r.Intersect(pd.Bounds()).
		Intersect(src.Bounds().Add(r.Min.Sub(sp)))
	if ir.Empty() {
		return // no work to do.
	}
	sp = ir.Min.Sub(r.Min)
	// get subimage of src
	sr := ir.Add(sp)
	if !sr.Eq(src.Bounds()) {
		s, ok := src.(interface {
			SubImage(image.Rectangle) image.Image
		})
		if !ok {
			// dither211 currently works on whole images
			draw.Draw(dst, r, src, sp, draw.Src)
			return
		}
		src = s.SubImage(sr)
	}
	// dither211 currently returns a new image, or nil if dithering not
	// possible.
	if s := dither211(src, pd.Palette); s != nil {
		src = s
	}
	// this avoids any problem of src dst overlap but it would usually
	// work to render directly into dst.  todo.
	draw.Draw(dst, r, src, image.Point{}, draw.Src)
}
예제 #26
0
파일: draw.go 프로젝트: h8liu/golang
// clip clips r against each image's bounds (after translating into the
// destination image's co-ordinate space) and shifts the points sp and mp by
// the same amount as the change in r.Min.
func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
	orig := r.Min
	*r = r.Intersect(dst.Bounds())
	*r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
	if mask != nil {
		*r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
	}
	dx := r.Min.X - orig.X
	dy := r.Min.Y - orig.Y
	if dx == 0 && dy == 0 {
		return
	}
	(*sp).X += dx
	(*sp).Y += dy
	(*mp).X += dx
	(*mp).Y += dy
}
예제 #27
0
파일: shape.go 프로젝트: juanman2/dot-emacs
func (cp *ControlPoint) Draw(dst draw.Image, clipr image.Rectangle) {
	r := clipr.Intersect(cp.Bbox())
	draw.Draw(dst, r, cp.col, image.ZP)
}
예제 #28
0
파일: suppr.go 프로젝트: jvlmdr/go-cv
// IOU computes intersection over union.
func IOU(a, b image.Rectangle) float64 {
	inter := area(a.Intersect(b))
	union := area(a) + area(b) - inter
	return float64(inter) / float64(union)
}
예제 #29
0
파일: suppr.go 프로젝트: jvlmdr/go-cv
// Cover computes the fraction of B which is covered by A.
func Cover(a, b image.Rectangle) float64 {
	inter := area(a.Intersect(b))
	return float64(inter) / float64(area(b))
}
예제 #30
0
// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
	sb := src.Bounds()
	dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
	if mask != nil {
		mb := mask.Bounds()
		if dx > mb.Max.X-mp.X {
			dx = mb.Max.X - mp.X
		}
		if dy > mb.Max.Y-mp.Y {
			dy = mb.Max.Y - mp.Y
		}
	}
	if r.Dx() > dx {
		r.Max.X = r.Min.X + dx
	}
	if r.Dy() > dy {
		r.Max.Y = r.Min.Y + dy
	}
	r = r.Intersect(dst.Bounds())
	if r.Empty() {
		return
	}

	// Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
	if dst0, ok := dst.(*image.RGBA); ok {
		if op == Over {
			if mask == nil {
				if src0, ok := src.(*image.ColorImage); ok {
					drawFillOver(dst0, r, src0)
					return
				}
				if src0, ok := src.(*image.RGBA); ok {
					drawCopyOver(dst0, r, src0, sp)
					return
				}
			} else if mask0, ok := mask.(*image.Alpha); ok {
				if src0, ok := src.(*image.ColorImage); ok {
					drawGlyphOver(dst0, r, src0, mask0, mp)
					return
				}
			}
		} else {
			if mask == nil {
				if src0, ok := src.(*image.ColorImage); ok {
					drawFillSrc(dst0, r, src0)
					return
				}
				if src0, ok := src.(*image.RGBA); ok {
					drawCopySrc(dst0, r, src0, sp)
					return
				}
			}
		}
		drawRGBA(dst0, r, src, sp, mask, mp, op)
		return
	}

	x0, x1, dx := r.Min.X, r.Max.X, 1
	y0, y1, dy := r.Min.Y, r.Max.Y, 1
	if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
		// Rectangles overlap: process backward?
		if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X {
			x0, x1, dx = x1-1, x0-1, -1
			y0, y1, dy = y1-1, y0-1, -1
		}
	}

	var out *image.RGBA64Color
	sy := sp.Y + y0 - r.Min.Y
	my := mp.Y + y0 - r.Min.Y
	for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
		sx := sp.X + x0 - r.Min.X
		mx := mp.X + x0 - r.Min.X
		for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
			ma := uint32(m)
			if mask != nil {
				_, _, _, ma = mask.At(mx, my).RGBA()
			}
			switch {
			case ma == 0:
				if op == Over {
					// No-op.
				} else {
					dst.Set(x, y, zeroColor)
				}
			case ma == m && op == Src:
				dst.Set(x, y, src.At(sx, sy))
			default:
				sr, sg, sb, sa := src.At(sx, sy).RGBA()
				if out == nil {
					out = new(image.RGBA64Color)
				}
				if op == Over {
					dr, dg, db, da := dst.At(x, y).RGBA()
					a := m - (sa * ma / m)
					out.R = uint16((dr*a + sr*ma) / m)
					out.G = uint16((dg*a + sg*ma) / m)
					out.B = uint16((db*a + sb*ma) / m)
					out.A = uint16((da*a + sa*ma) / m)
				} else {
					out.R = uint16(sr * ma / m)
					out.G = uint16(sg * ma / m)
					out.B = uint16(sb * ma / m)
					out.A = uint16(sa * ma / m)
				}
				dst.Set(x, y, out)
			}
		}
	}
}