Exemplo n.º 1
0
// decodeP6 reads a binary pixmap
func decodeP6(r *bufio.Reader, img draw.Image, width, height uint) {
	var x, y, pix int

	mask := byte(readU(r))
	mul := 255 / mask
	data := make([]byte, width*height*3)

	space(r)

	_, err := r.Read(data)
	check(err)

	for y = 0; y < int(height); y++ {
		for x = 0; x < int(width); x++ {
			img.Set(x, y, color.RGBA{
				(data[pix] & mask) * mul,
				(data[pix+1] & mask) * mul,
				(data[pix+2] & mask) * mul,
				0xff,
			})

			pix += 3
		}
	}
}
Exemplo n.º 2
0
func line(img draw.Image, a, b image.Point, c color.Color) {
	minx, maxx := minmax(a.X, b.X)
	miny, maxy := minmax(a.Y, b.Y)

	Δx := float64(b.X - a.X)
	Δy := float64(b.Y - a.Y)

	if maxx-minx > maxy-miny {
		d := 1
		if a.X > b.X {
			d = -1
		}
		for x := 0; x != b.X-a.X+d; x += d {
			y := int(float64(x) * Δy / Δx)
			img.Set(a.X+x, a.Y+y, c)
		}
	} else {
		d := 1
		if a.Y > b.Y {
			d = -1
		}
		for y := 0; y != b.Y-a.Y+d; y += d {
			x := int(float64(y) * Δx / Δy)
			img.Set(a.X+x, a.Y+y, c)
		}
	}
}
Exemplo n.º 3
0
func warm(out, in draw.Image, opacity uint8, colors []color.Color) {
	bounds := in.Bounds()
	collen := float64(len(colors))
	wg := sync.WaitGroup{}
	wg.Add(bounds.Dx())
	for x := bounds.Min.X; x < bounds.Max.X; x++ {
		go func(x int) {
			defer wg.Done()
			for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
				col := in.At(x, y)
				_, _, _, alpha := col.RGBA()
				percent := float64(alpha) / float64(0xffff)
				var outcol color.Color
				if percent == 0 {
					outcol = color.Transparent
				} else {
					template := colors[int((collen-1)*(1.0-percent))]
					tr, tg, tb, ta := template.RGBA()
					ta /= 256
					outalpha := uint8(float64(ta) *
						(float64(opacity) / 256.0))
					outcol = color.NRGBA{
						uint8(tr / 256),
						uint8(tg / 256),
						uint8(tb / 256),
						uint8(outalpha)}
				}
				out.Set(x, y, outcol)
			}
		}(x)
	}
	wg.Wait()
}
Exemplo n.º 4
0
// http://en.wikipedia.org/wiki/Bresenham's_line_algorithm#Simplification
func line(x0, y0, x1, y1 int, c color.Color, img draw.Image) {
	var dx = abs(x1 - x0)
	var dy = abs(y1 - y0)
	var err = dx - dy
	var sx, sy = 1, 1

	if x0 > x1 {
		sx = -1
	}
	if y0 > y1 {
		sy = -1
	}

	img.Set(x0, y0, c)
	for x0 != x1 || y0 != y1 {
		var e2 = 2 * err
		if e2 > -dy {
			err -= dy
			x0 += sx
		}
		if e2 < dx {
			err += dx
			y0 += sy
		}
		img.Set(x0, y0, c)
	}

}
Exemplo n.º 5
0
// Transform applies the affine transform to src and produces dst.
func (a Affine) Transform(dst draw.Image, src image.Image, i interp.Interp) error {
	if dst == nil {
		return errors.New("graphics: dst is nil")
	}
	if src == nil {
		return errors.New("graphics: src is nil")
	}

	// RGBA fast path.
	dstRGBA, dstOk := dst.(*image.RGBA)
	srcRGBA, srcOk := src.(*image.RGBA)
	interpRGBA, interpOk := i.(interp.RGBA)
	if dstOk && srcOk && interpOk {
		return a.transformRGBA(dstRGBA, srcRGBA, interpRGBA)
	}

	srcb := src.Bounds()
	b := dst.Bounds()
	for y := b.Min.Y; y < b.Max.Y; y++ {
		for x := b.Min.X; x < b.Max.X; x++ {
			sx, sy := a.pt(x, y)
			if inBounds(srcb, sx, sy) {
				dst.Set(x, y, i.Interp(src, sx, sy))
			}
		}
	}
	return nil
}
Exemplo n.º 6
0
func warm(out, in draw.Image, opacity uint8, colors []color.Color) {
	draw.Draw(out, out.Bounds(), image.Transparent, image.ZP, draw.Src)
	bounds := in.Bounds()
	collen := float64(len(colors))
	wg := &sync.WaitGroup{}
	for x := bounds.Min.X; x < bounds.Max.X; x++ {
		wg.Add(1)
		go func(x int) {
			defer wg.Done()
			for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
				col := in.At(x, y)
				_, _, _, alpha := col.RGBA()
				if alpha > 0 {
					percent := float64(alpha) / float64(0xffff)
					template := colors[int((collen-1)*(1.0-percent))]
					tr, tg, tb, ta := template.RGBA()
					ta /= 256
					outalpha := uint8(float64(ta) *
						(float64(opacity) / 256.0))
					outcol := color.NRGBA{
						uint8(tr / 256),
						uint8(tg / 256),
						uint8(tb / 256),
						uint8(outalpha)}
					out.Set(x, y, outcol)
				}
			}
		}(x)
	}
	wg.Wait()
}
Exemplo n.º 7
0
func Bresenham(img draw.Image, color color.Color, x0, y0, x1, y1 int) {
	dx := abs(x1 - x0)
	dy := abs(y1 - y0)
	var sx, sy int
	if x0 < x1 {
		sx = 1
	} else {
		sx = -1
	}
	if y0 < y1 {
		sy = 1
	} else {
		sy = -1
	}
	err := dx - dy

	var e2 int
	for {
		img.Set(x0, y0, color)
		if x0 == x1 && y0 == y1 {
			return
		}
		e2 = 2 * err
		if e2 > -dy {
			err = err - dy
			x0 = x0 + sx
		}
		if e2 < dx {
			err = err + dx
			y0 = y0 + sy
		}
	}
}
Exemplo n.º 8
0
// 翻转函数,要求两个图像大小契合,act&1 == 0则左右翻转,否则垂直翻转。
func Overturn(dst draw.Image, src image.Image, act int) error {
	var to func(int, int) (int, int)
	sr := src.Bounds()
	dr := dst.Bounds()
	W := dr.Max.X - dr.Min.X
	H := dr.Max.Y - dr.Min.Y
	if H <= 0 || W <= 0 {
		return errors.New("target image is empty or noncanonical")
	}
	if sr.Min.X >= sr.Max.X || sr.Min.Y >= sr.Max.Y {
		return errors.New("source image is empty or noncanonical")
	}
	if sr.Max.X-sr.Min.X != W || sr.Max.Y-sr.Min.Y != H {
		return errors.New("target and source must be same size!")
	}
	if act&1 == 0 {
		to = func(x, y int) (int, int) {
			return W - 1 - x, y
		}
	} else {
		to = func(x, y int) (int, int) {
			return x, H - 1 - y
		}
	}
	for i := 0; i < W; i++ {
		for j := 0; j < H; j++ {
			x, y := to(i, j)
			dst.Set(dr.Min.X+x, dr.Min.Y+y, src.At(sr.Min.X+i, sr.Min.Y+j))
		}
	}
	return nil
}
Exemplo n.º 9
0
// decodeP4 reads a binary bitmap
func decodeP4(r *bufio.Reader, img draw.Image, width, height uint) {
	var x, y, bit int

	bytes := int(math.Ceil((float64(width) / 8)))
	bits := newBitset(uint(bytes) * height * 8)
	pad := (bytes * 8) - int(width)

	space(r)

	_, err := r.Read(bits)
	check(err)

	for y = 0; y < int(height); y++ {
		for x = 0; x < int(width); x++ {
			if bits.Test(bit) {
				img.Set(x, y, color.Alpha{0xff})
			} else {
				img.Set(x, y, color.Alpha{0x00})
			}

			bit++
		}

		bit += pad
	}
}
Exemplo n.º 10
0
func gennoise(screen draw.Image) {
	for y := 0; y < 240; y++ {
		for x := 0; x < 320; x++ {
			screen.Set(x, y, <-randcol)
		}
	}
}
Exemplo n.º 11
0
func testDrawRandom(p draw.Image) {
	bd := p.Bounds()
	for y, yEnd := bd.Min.Y, bd.Max.Y; y < yEnd; y++ {
		for x, xEnd := bd.Min.X, bd.Max.X; x < xEnd; x++ {
			p.Set(x, y, testRandomColor())
		}
	}
}
Exemplo n.º 12
0
func imageConvert(src image.Image, dest draw.Image) draw.Image {
	w, h := src.Bounds().Dx(), src.Bounds().Dy()
	for y := 0; y < h; y += 1 {
		for x := 0; x < w; x += 1 {
			dest.Set(x, y, dest.ColorModel().Convert(src.At(x, y)))
		}
	}
	return dest
}
Exemplo n.º 13
0
// Apply the given color mapping to the specified image buffers.
func Apply(from, to *Rule, src, dst draw.Image) {
	var x, y int
	var r, g, b, a uint32
	var sc color.Color
	var dc color.RGBA
	var pix pixel

	rect := src.Bounds()

	for y = 0; y < rect.Dy(); y++ {
		for x = 0; x < rect.Dx(); x++ {
			sc = src.At(x, y)

			r, g, b, a = sc.RGBA()
			pix.r = uint8(r >> 8)
			pix.g = uint8(g >> 8)
			pix.b = uint8(b >> 8)
			pix.a = uint8(a >> 8)

			// Check if the pixel matches the filter rule.
			if !(match(pix.r, from.R) && match(pix.g, from.G) && match(pix.b, from.B) && match(pix.a, from.A)) {
				dst.Set(x, y, sc)
				continue
			}

			// Compute three different types of grayscale conversion.
			// These can be applied by named references.
			pix.average = uint8(((r + g + b) / 3) >> 8)
			pix.lightness = uint8(((min(min(r, g), b) + max(max(r, g), b)) / 2) >> 8)

			// For luminosity it is necessary to apply an inverse of the gamma
			// function for the color space before calculating the inner product.
			// Then you apply the gamma function to the reduced value. Failure to
			// incorporate the gamma function can result in errors of up to 20%.
			//
			// For typical computer stuff, the color space is sRGB. The right
			// numbers for sRGB are approx. 0.21, 0.72, 0.07. Gamma for sRGB
			// is a composite function that approximates exponentiation by 1/2.2
			//
			// This is a rather expensive operation, but gives a much more accurate
			// and satisfactory result than the average and lightness versions.
			pix.luminosity = gammaSRGB(
				0.212655*invGammaSRGB(pix.r) +
					0.715158*invGammaSRGB(pix.g) +
					0.072187*invGammaSRGB(pix.b))

			// Transform color.
			dc.R = transform(&pix, pix.r, to.R)
			dc.G = transform(&pix, pix.g, to.G)
			dc.B = transform(&pix, pix.b, to.B)
			dc.A = transform(&pix, pix.a, to.A)

			// Set new pixel.
			dst.Set(x, y, dc)
		}
	}
}
Exemplo n.º 14
0
// MapColorInRectangle is a helper function for working on part of an image. It
// takes the original image, a function to use, a image to write to, and the
// bounds of the original (and therefore the final image) to act upon.
func MapColorInRectangle(img image.Image, bounds image.Rectangle, dest draw.Image,
	f Composable) {

	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			dest.Set(x, y, f(img.At(x, y)))
		}
	}
}
Exemplo n.º 15
0
// decodeP1 reads an ASCII bitmap
func decodeP1(r *bufio.Reader, img draw.Image, width, height uint) {
	var x, y int

	for y = 0; y < int(height); y++ {
		for x = 0; x < int(width); x++ {
			img.Set(x, y, color.Alpha{uint8(readU(r)) * 0xff})
		}
	}
}
Exemplo n.º 16
0
func newSetFuncDefault(p draw.Image) SetFunc {
	return func(x, y int, r, g, b, a uint32) {
		p.Set(x, y, color.RGBA64{
			R: uint16(r),
			G: uint16(g),
			B: uint16(b),
			A: uint16(a),
		})
	}
}
Exemplo n.º 17
0
// Blends src image (top layer) into dst image (bottom layer) using
// the BlendFunc provided by mode. BlendFunc is applied to each pixel
// where the src image overlaps the dst image and the result is stored
// in the original dst image, src image is unmutable.
func BlendImage(dst draw.Image, src image.Image, mode BlendFunc) {
	// Obtain the intersection of both images.
	inter := dst.Bounds().Intersect(src.Bounds())
	// Apply BlendFuc to each pixel in the intersection.
	for y := inter.Min.Y; y < inter.Max.Y; y++ {
		for x := inter.Min.X; x < inter.Max.X; x++ {
			dst.Set(x, y, mode(dst.At(x, y), src.At(x, y)))
		}
	}
}
Exemplo n.º 18
0
// DrawLinear draws a linear gradient to dst. If the gradient vector (as
// defined by x0, y0, x1, and y1) is found to be purely horizontal or purely
// vertical, the appropriate optimized functions will be called.
func DrawLinear(dst draw.Image, x0, y0, x1, y1 float64, stops []Stop) {
	if y0 == y1 && x0 != x1 {
		drawHLinear(dst, x0, x1, stops)
		return
	}

	if x0 == x1 && y0 != y1 {
		drawVLinear(dst, y0, y1, stops)
		return
	}

	if len(stops) == 0 {
		return
	}

	if y0 > y1 {
		panic(fmt.Sprintf("invalid bounds y0(%f)>y1(%f)", y0, y1))
	}
	if x0 > x1 {
		panic(fmt.Sprintf("invalid bounds x0(%f)>x1(%f)", x0, x1))
	}

	bb := dst.Bounds()
	width, height := bb.Dx(), bb.Dy()

	x0, y0 = x0*float64(width), y0*float64(height)
	x1, y1 = x1*float64(width), y1*float64(height)

	dx, dy := x1-x0, y1-y0
	px0, py0 := x0-dy, y0+dx
	mag := math.Hypot(dx, dy)

	var col color.Color
	for y := 0; y < width; y++ {
		fy := float64(y)

		for x := 0; x < width; x++ {
			fx := float64(x)
			// is the pixel before the start of the gradient?
			s0 := (px0-x0)*(fy-y0) - (py0-y0)*(fx-x0)
			if s0 > 0 {
				col = stops[0].Col
			} else {
				// calculate the distance of the pixel from the first stop line
				u := ((fx-x0)*(px0-x0) + (fy-y0)*(py0-y0)) /
					(mag * mag)
				x2, y2 := x0+u*(px0-x0), y0+u*(py0-y0)
				d := math.Hypot(fx-x2, fy-y2) / mag

				col = getColour(d, stops)
			}
			dst.Set(x+bb.Min.X, y+bb.Min.Y, col)
		}
	}
}
Exemplo n.º 19
0
func brush(img draw.Image, id int) func(x, y int) {
	colors := [][]uint8{
		{0, 0, 0xff},
		{0xff, 0, 0},
		{0xff, 0xff, 0xff},
	}
	c := colors[id%len(colors)]
	return func(x, y int) {
		img.Set(x, y, &color.NRGBA{R: c[0], G: c[1], B: c[2], A: 0xff})
	}
}
Exemplo n.º 20
0
func (burkes) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
	quantError0 := make([][3]int32, r.Dx()+4)
	quantError1 := make([][3]int32, r.Dx()+4)

	out := color.RGBA64{A: 0xffff}
	for y := 0; y != r.Dy(); y++ {
		for x := 0; x != r.Dx(); x++ {
			sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA()
			er, eg, eb := int32(sr), int32(sg), int32(sb)

			er = clamp(er + quantError0[x+2][0]/32)
			eg = clamp(eg + quantError0[x+2][1]/32)
			eb = clamp(eb + quantError0[x+2][2]/32)

			out.R = uint16(er)
			out.G = uint16(eg)
			out.B = uint16(eb)
			dst.Set(r.Min.X+x, r.Min.Y+y, &out)

			sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
			er -= int32(sr)
			eg -= int32(sg)
			eb -= int32(sb)

			quantError0[x+3][0] += er * 8
			quantError0[x+3][1] += eg * 8
			quantError0[x+3][2] += eb * 8
			quantError0[x+4][0] += er * 4
			quantError0[x+4][1] += eg * 4
			quantError0[x+4][2] += eb * 4
			quantError1[x+0][0] += er * 2
			quantError1[x+0][1] += eg * 2
			quantError1[x+0][2] += eb * 2
			quantError1[x+1][0] += er * 4
			quantError1[x+1][1] += eg * 4
			quantError1[x+1][2] += eb * 4
			quantError1[x+2][0] += er * 8
			quantError1[x+2][1] += eg * 8
			quantError1[x+2][2] += eb * 8
			quantError1[x+3][0] += er * 4
			quantError1[x+3][1] += eg * 4
			quantError1[x+3][2] += eb * 4
			quantError1[x+4][0] += er * 2
			quantError1[x+4][1] += eg * 2
			quantError1[x+4][2] += eb * 2
		}

		// Recycle the quantization error buffers.
		quantError0, quantError1 = quantError1, quantError0
		for i := range quantError1 {
			quantError1[i] = [3]int32{}
		}
	}
}
Exemplo n.º 21
0
func (hs *AutoSlicer) drawRegion(img draw.Image, r Region) {
	var (
		c    color.Color
		x, y int
	)
	c = color.RGBA{0xFF, 0, 0, 0xFF}
	for x = r.Min.X + 1; x < r.Max.X; x++ {
		for y = r.Min.Y + 1; y < r.Max.Y; y++ {
			img.Set(x, y, c)
		}
	}
}
Exemplo n.º 22
0
// decodeP2 reads an ASCII graymap
func decodeP2(r *bufio.Reader, img draw.Image, width, height uint) {
	var x, y int

	mask := readU(r)
	mul := 255 / mask

	for y = 0; y < int(height); y++ {
		for x = 0; x < int(width); x++ {
			img.Set(x, y, color.Gray{uint8((readU(r) & mask) * mul)})
		}
	}
}
Exemplo n.º 23
0
func noise(src draw.Image) {
	orig := src.Bounds()
	numToMod := (orig.Max.X * orig.Max.Y) / 2
	for i := 0; i < numToMod; i++ {
		x := rand.Intn(orig.Max.X)
		y := rand.Intn(orig.Max.Y)
		origColor := src.At(x, y).(color.RGBA)
		origColor.R += 30
		origColor.B += 30
		origColor.G += 30
		src.Set(x, y, origColor)
	}
}
Exemplo n.º 24
0
func DrawDigit(dest draw.Image, dig digitmap, sx int, sy int) {
	c := 0
	for y, h := sy, 0; h < 7; y, h = y+1, h+1 {
		for x, w := sx, 0; w < 4; x, w = x+1, w+1 {
			if dig[c] > 0 {
				dest.Set(x, y, color.White)
			} else {
				dest.Set(x, y, color.Black)
			}
			c += 1
		}
	}
}
Exemplo n.º 25
0
// 旋转,每单位1代表左旋90度。注意采用的是向右向上的直角坐标系,和图像的向右向下不同。
// 本包的函数都是采用向右向上的直角坐标系。因此在图像显示上,每单位1右旋90度。
func Rotate(dst draw.Image, src image.Image, act int) error {
	var to func(int, int) (int, int)
	sr := src.Bounds()
	dr := dst.Bounds()
	W := dr.Max.X - dr.Min.X
	H := dr.Max.Y - dr.Min.Y
	if H <= 0 || W <= 0 {
		return errors.New("target image is empty or noncanonical")
	}
	if sr.Min.X >= sr.Max.X || sr.Min.Y >= sr.Max.Y {
		return errors.New("source image is empty or noncanonical")
	}
	switch act %= 4; act {
	case 2, -2:
		if sr.Max.X-sr.Min.X != W || sr.Max.Y-sr.Min.Y != H {
			return errors.New("target and source must be same size!")
		}
		to = func(x, y int) (int, int) {
			return W - 1 - x, H - 1 - y
		}
	case 1, -3:
		if sr.Max.X-sr.Min.X != H || sr.Max.Y-sr.Min.Y != W {
			return errors.New("target and source must be same size!")
		}
		to = func(x, y int) (int, int) {
			return H - 1 - y, x
		}
	case -1, 3:
		if sr.Max.X-sr.Min.X != H || sr.Max.Y-sr.Min.Y != W {
			return errors.New("target and source must be same size!")
		}
		to = func(x, y int) (int, int) {
			return y, W - 1 - x
		}
	case 0:
		if sr.Max.X-sr.Min.X != W || sr.Max.Y-sr.Min.Y != H {
			return errors.New("target and source must be same size!")
		}
		to = func(x, y int) (int, int) {
			return x, y
		}
	}
	for i := 0; i < W; i++ {
		for j := 0; j < H; j++ {
			x, y := to(i, j)
			dst.Set(dr.Min.X+x, dr.Min.Y+y, src.At(sr.Min.X+i, sr.Min.Y+j))
		}
	}
	return nil
}
Exemplo n.º 26
0
func digit(im draw.Image, col color.Color, x, y, size, digit int) {
	n := hexdigits[digit]
	for _, s := range segments {
		if n&1 != 0 {
			xx, yy := x+s.sx*size, y+s.sy*size
			for i := 0; i <= size; i++ {
				im.Set(xx, yy, col)
				xx += s.dx
				yy += s.dy
			}
		}
		n >>= 1
	}
}
Exemplo n.º 27
0
/* Line drawing - Bresenhams algorithm in it's simplest form.*/
func DrawLine(screen draw.Image, a image.Point, b image.Point, color color.Color) {
	dx := b.X - a.X
	dy := b.Y - a.Y
	error := 0.0
	derr := math.Abs(float64(dy) / float64(dx))
	y := a.Y
	for x := a.X; x < b.X; x++ {
		screen.Set(x, y, color)
		error += derr
		if error >= 0.5 {
			y++
			error -= 1.0
		}
	}
}
Exemplo n.º 28
0
func DrawColon(dest draw.Image, sx int, sy int) {

	c := 0
	for y, h := sy, 0; h < 7; y, h = y+1, h+1 {

		for x, w := sx, 0; w < 2; x, w = x+1, w+1 {
			if colonslice[c] > 0 {
				dest.Set(x, y, color.White)
			} else {
				dest.Set(x, y, color.Black)
			}
			c += 1
		}
	}

}
Exemplo n.º 29
0
func FillArc(horizontal, vertical int, imagem draw.Image, cor color.Color) {
	var passo int

	if vertical > 0 {
		passo = 1
	} else {
		passo = -1
	}

	for indice := 0; indice != vertical; indice += passo {
		imagem.Set(horizontal, indice, cor)
		imagem.Set(indice, horizontal, cor)
	}

	imagem.Set(horizontal, vertical, cor)
	imagem.Set(vertical, horizontal, cor)
}
Exemplo n.º 30
0
func DrawImage(src image.Image, dest draw.Image, tr MatrixTransform, op draw.Op, filter ImageFilter) {
	bounds := src.Bounds()
	x0, y0, x1, y1 := float64(bounds.Min.X), float64(bounds.Min.Y), float64(bounds.Max.X), float64(bounds.Max.Y)
	tr.TransformRectangle(&x0, &y0, &x1, &y1)
	var x, y, u, v float64
	var c1, c2, cr color.Color
	var r, g, b, a, ia, r1, g1, b1, a1, r2, g2, b2, a2 uint32
	var color color.RGBA
	for x = x0; x < x1; x++ {
		for y = y0; y < y1; y++ {
			u = x
			v = y
			tr.InverseTransform(&u, &v)
			if bounds.Min.X <= int(u) && bounds.Max.X > int(u) && bounds.Min.Y <= int(v) && bounds.Max.Y > int(v) {
				c1 = dest.At(int(x), int(y))
				switch filter {
				case LinearFilter:
					c2 = src.At(int(u), int(v))
				case BilinearFilter:
					c2 = getColorBilinear(src, u, v)
				case BicubicFilter:
					c2 = getColorBicubic(src, u, v)
				}
				switch op {
				case draw.Over:
					r1, g1, b1, a1 = c1.RGBA()
					r2, g2, b2, a2 = c2.RGBA()
					ia = M - a2
					r = ((r1 * ia) / M) + r2
					g = ((g1 * ia) / M) + g2
					b = ((b1 * ia) / M) + b2
					a = ((a1 * ia) / M) + a2
					color.R = uint8(r >> 8)
					color.G = uint8(g >> 8)
					color.B = uint8(b >> 8)
					color.A = uint8(a >> 8)
					cr = color
				default:
					cr = c2
				}
				dest.Set(int(x), int(y), cr)
			}
		}
	}
}