示例#1
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) {
	clip(dst, &r, src, &sp, mask, &mp)
	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 {
				switch src0 := src.(type) {
				case *image.ColorImage:
					drawFillOver(dst0, r, src0)
					return
				case *image.RGBA:
					drawCopyOver(dst0, r, src0, sp)
					return
				case *image.NRGBA:
					drawNRGBAOver(dst0, r, src0, sp)
					return
				case *ycbcr.YCbCr:
					drawYCbCr(dst0, r, src0, sp)
					return
				}
			} else if mask0, ok := mask.(*image.Alpha); ok {
				switch src0 := src.(type) {
				case *image.ColorImage:
					drawGlyphOver(dst0, r, src0, mask0, mp)
					return
				}
			}
		} else {
			if mask == nil {
				switch src0 := src.(type) {
				case *image.ColorImage:
					drawFillSrc(dst0, r, src0)
					return
				case *image.RGBA:
					drawCopySrc(dst0, r, src0, sp)
					return
				case *image.NRGBA:
					drawNRGBASrc(dst0, r, src0, sp)
					return
				case *ycbcr.YCbCr:
					drawYCbCr(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)
			}
		}
	}
}
示例#2
0
func bilinear(im image.Image, scalex float32, scaley float32) (imageng, os.Error) {
	if scalex >= 1.0 && scaley >= 1.0 {
		ws := im.Bounds().Dx()
		hs := im.Bounds().Dy()
		wd := int(scalex * float32(ws))
		hd := int(scaley * float32(hs))

		scaled := imgType(im, wd, hd)

		var c00, c01, c10, c11 image.RGBA64Color
		var x0, x1, xs, ys, y0, y1 uint32
		var r, g, b, a uint32
		var r00, r11, r10, r01, g00, g11, g10, g01, b00, b11, b10, b01, a00, a11, a10, a01 uint32
		var i, j uint32
		ys = 1
		for y := 1; y < hs; y++ {
			x0 = 0
			x1 = 0 // not so sure
			xs = 1
			y0 = y1
			y1 = uint32(float32(ys) * scaley)
			c00 = image.RGBA64ColorModel.Convert(im.At(0, int(ys-1))).(image.RGBA64Color)
			c01 = image.RGBA64ColorModel.Convert(im.At(0, int(ys))).(image.RGBA64Color)
			c10 = image.RGBA64ColorModel.Convert(im.At(1, int(ys-1))).(image.RGBA64Color)
			c11 = image.RGBA64ColorModel.Convert(im.At(1, int(ys))).(image.RGBA64Color)
			for x := 1; x < ws; x++ {
				x0 = x1
				x1 = uint32(float32(xs) * scalex)
				c00 = c10
				c01 = c11
				c10 = image.RGBA64ColorModel.Convert(im.At(int(xs), int(ys-1))).(image.RGBA64Color)
				c11 = image.RGBA64ColorModel.Convert(im.At(int(xs), int(ys))).(image.RGBA64Color)
				for j = y0; j < y1; j++ {
					for i = x0; i < x1; i++ {
						r00, g00, b00, a00 = c00.RGBA()
						r01, g01, b01, a01 = c01.RGBA()
						r10, g10, b10, a10 = c10.RGBA()
						r11, g11, b11, a11 = c11.RGBA()
						//						print(r00, ", ", r01, ", ", r10, ", ", r11, "\n")
						r = ((r00*(x1-i)+r10*(i-x0))*(y1-j) +
							(r01*(x1-i)+r11*(i-x0))*(j-y0)) /
							((x1 - x0) * (y1 - y0))
						g = ((g00*(x1-i)+g10*(i-x0))*(y1-j) +
							(g01*(x1-i)+g11*(i-x0))*(j-y0)) /
							((x1 - x0) * (y1 - y0))
						b = ((b00*(x1-i)+b10*(i-x0))*(y1-j) +
							(b01*(x1-i)+b11*(i-x0))*(j-y0)) /
							((x1 - x0) * (y1 - y0))
						a = ((a00*(x1-i)+a10*(i-x0))*(y1-j) +
							(a01*(x1-i)+a11*(i-x0))*(j-y0)) /
							((x1 - x0) * (y1 - y0))
						scaled.Set(int(i), int(j),
							convertColor(im, image.RGBA64Color{uint16(r), uint16(g), uint16(b), uint16(a)}))
					}
				}
				xs++
			}
			ys++
		}
		return scaled, nil
	}
	return nil, os.NewError("no scaling down")
}
示例#3
0
文件: draw.go 项目: 8l/go-learn
// Draw aligns r.Min in dst with pt in src and mask
// and then replaces the rectangle r in dst with the
// result of the Porter-Duff compositing operation
// ``(src in mask) over dst.''  If mask is nil, the operation
// simplifies to ``src over dst.''
// The implementation is simple and slow.
func Draw(dst Image, r Rectangle, src, mask image.Image, pt Point) {
	// Plenty of room for optimizations here.

	dx, dy := src.Width(), src.Height()
	if mask != nil {
		if dx > mask.Width() {
			dx = mask.Width()
		}
		if dy > mask.Width() {
			dy = mask.Width()
		}
	}
	dx -= pt.X
	dy -= pt.Y
	if r.Dx() > dx {
		r.Max.X = r.Min.X + dx
	}
	if r.Dy() > dy {
		r.Max.Y = r.Min.Y + dy
	}

	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(pt.Sub(r.Min))) {
		// Rectangles overlap: process backward?
		if pt.Y < r.Min.Y || pt.Y == r.Min.Y && pt.X < r.Min.X {
			x0, x1, dx = x1-1, x0-1, -1
			y0, y1, dy = y1-1, y0-1, -1
		}
	}

	var out *image.RGBA64Color
	for y := y0; y != y1; y += dy {
		for x := x0; x != x1; x += dx {
			sx := pt.X + x - r.Min.X
			sy := pt.Y + y - r.Min.Y
			if mask == nil {
				dst.Set(x, y, src.At(sx, sy))
				continue
			}
			_, _, _, ma := mask.At(sx, sy).RGBA()
			switch ma {
			case 0:
				continue
			case 0xFFFFFFFF:
				dst.Set(x, y, src.At(sx, sy))
			default:
				dr, dg, db, da := dst.At(x, y).RGBA()
				dr >>= 16
				dg >>= 16
				db >>= 16
				da >>= 16
				sr, sg, sb, sa := src.At(sx, sy).RGBA()
				sr >>= 16
				sg >>= 16
				sb >>= 16
				sa >>= 16
				ma >>= 16
				const M = 1<<16 - 1
				a := sa * ma / M
				dr = (dr*(M-a) + sr*ma) / M
				dg = (dg*(M-a) + sg*ma) / M
				db = (db*(M-a) + sb*ma) / M
				da = (da*(M-a) + sa*ma) / M
				if out == nil {
					out = new(image.RGBA64Color)
				}
				out.R = uint16(dr)
				out.G = uint16(dg)
				out.B = uint16(db)
				out.A = uint16(da)
				dst.Set(x, y, out)
			}
		}
	}
}
示例#4
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.
// The implementation is simple and slow.
// TODO(nigeltao): Optimize this.
func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Image, mp Point, op Op) {
	dx, dy := src.Width()-sp.X, src.Height()-sp.Y
	if mask != nil {
		if dx > mask.Width()-mp.X {
			dx = mask.Width() - mp.X
		}
		if dy > mask.Height()-mp.Y {
			dy = mask.Height() - mp.Y
		}
	}
	if r.Dx() > dx {
		r.Max.X = r.Min.X + dx
	}
	if r.Dy() > dy {
		r.Max.Y = r.Min.Y + dy
	}

	// TODO(nigeltao): Clip r to dst's bounding box, and handle the case when sp or mp has negative X or Y.
	// TODO(nigeltao): Ensure that r is well formed, i.e. r.Max.X >= r.Min.X and likewise for Y.

	// 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 {
			// TODO(nigeltao): Implement a fast path for font glyphs (i.e. when mask is an image.Alpha).
		} else {
			if mask == nil {
				if src0, ok := src.(image.ColorImage); ok {
					drawFill(dst0, r, src0)
					return
				}
				if src0, ok := src.(*image.RGBA); ok {
					if dst0 == src0 && r.Overlaps(r.Add(sp.Sub(r.Min))) {
						// TODO(nigeltao): Implement a fast path for the overlapping case.
					} else {
						drawCopy(dst0, r, src0, sp)
						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 {
			// A nil mask is equivalent to a fully opaque, infinitely large mask.
			// We work in 16-bit color, so that multiplying two values does not overflow a uint32.
			const M = 1<<16 - 1
			ma := uint32(M)
			if mask != nil {
				_, _, _, ma = mask.At(mx, my).RGBA()
				ma >>= 16
			}
			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()
				sr >>= 16
				sg >>= 16
				sb >>= 16
				sa >>= 16
				if out == nil {
					out = new(image.RGBA64Color)
				}
				if op == Over {
					dr, dg, db, da := dst.At(x, y).RGBA()
					dr >>= 16
					dg >>= 16
					db >>= 16
					da >>= 16
					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)
			}
		}
	}
}