Beispiel #1
0
// New allocates and initializes a new DockApp.  NewDockApp does not initialize
// the window contents and does not map the window to the display screen.  The
// window is mapped to the screen when the Main method is called on the
// returned DockApp.
func New(x *xgbutil.XUtil, rect image.Rectangle) (*DockApp, error) {
	win, err := xwindow.Generate(x)
	if err != nil {
		log.Fatalf("generate window: %v", err)
	}
	win.Create(x.RootWin(), 0, 0, rect.Size().X, rect.Size().Y, 0)

	// Set WM hints so that Openbox puts the window into the dock.
	hints := &icccm.Hints{
		Flags:        icccm.HintState | icccm.HintIconWindow,
		InitialState: icccm.StateWithdrawn,
		IconWindow:   win.Id,
		WindowGroup:  win.Id,
	}
	err = icccm.WmHintsSet(x, win.Id, hints)
	if err != nil {
		win.Destroy()
		return nil, fmt.Errorf("wm hints: %v", err)
	}
	img := xgraphics.New(x, rect)
	err = img.XSurfaceSet(win.Id)
	if err != nil {
		img.Destroy()
		win.Destroy()
		return nil, fmt.Errorf("xsurface set: %v", err)
	}
	app := &DockApp{
		x:   x,
		img: img,
		win: win,
	}
	return app, nil
}
Beispiel #2
0
func imfilter(filter [][]float32, rect image.Rectangle, rgbFunc func(xpos, ypos int) (r0, g0, b0, a0 uint8), mergFunc func(a, b float32) float32) *image.RGBA {
	wg := sync.WaitGroup{}
	size := rect.Size()
	imgGrey := image.NewRGBA(rect)
	fX := len(filter)
	fY := len(filter[0])
	xoffset := fX / 2
	yoffset := fY / 2
	threadCount := (fX + fY) / 2
	sizeoffset := (size.X - fX) / threadCount

	timeStart := time.Now()

	wg.Add(threadCount)
	for i := 0; i < threadCount; i++ {
		go func(i int) {
			for x := xoffset + i*sizeoffset; x < xoffset+(i+1)*sizeoffset; x++ {
				for y := yoffset; y < size.Y-yoffset; y++ {
					newColor := imfilterMerg(filter, fX, fY, x, y, xoffset, yoffset, rgbFunc, mergFunc)
					imgGrey.SetRGBA(x, y, newColor)
				}
			}
			wg.Done()
		}(i)
	}
	wg.Wait()
	fmt.Println("Filt Time", time.Now().Sub(timeStart))
	return imgGrey
}
Beispiel #3
0
func (v *platformView) drawScene(r image.Rectangle) {
	//log.Printf("platformView.drawScene %v\n", r)
	x, y, w, h := r.Min.X, r.Min.Y, r.Size().X, r.Size().Y
	v.area.QueueDrawArea(v.parent.ScaleCoord(x, false), v.parent.ScaleCoord(y, false),
		v.parent.ScaleCoord(w, true)+1, v.parent.ScaleCoord(h, true)+1)
	return
}
Beispiel #4
0
//
//		Private functions
//
func ContainerFit(outer, inner image.Rectangle) image.Rectangle {
	borderTop := image.Point{-18, -30}
	borderBottom := image.Point{18, 18}
	test := image.Rectangle{inner.Min.Add(borderTop), inner.Max.Add(borderBottom)}
	if outer.Size().X == 0 {
		return test
	}
	return outer.Union(test)
}
Beispiel #5
0
func crop(src image.Image, r image.Rectangle) draw.Image {
	target := image.Rectangle{image.Point{0, 0}, r.Size()}

	cropped := image.NewRGBA(target)

	draw.Draw(cropped, target, src, r.Min, draw.Over)

	return cropped
}
Beispiel #6
0
// initLayout constructs two masks for drawing the battery and the remaining
// energy as well as sets the pixel bounds for drawing energy capacity.  the
// masks allow for simplified space-fills and reduced chance of pixel gaps.
func (app *App) initLayout() {
	var zeropt image.Point

	rectOutTop := image.Rectangle{Min: app.Layout.battRect.Min, Max: app.Layout.battRect.Min.Add(image.Point{2, 2})}
	rectOutBottom := rectOutTop.Add(image.Point{Y: app.Layout.battRect.Size().Y - rectOutTop.Size().Y})
	capRect := image.Rectangle{
		Min: image.Point{X: rectOutTop.Min.X, Y: rectOutTop.Max.Y},
		Max: image.Point{X: rectOutBottom.Max.X, Y: rectOutBottom.Min.Y},
	}
	bodyRect := app.Layout.battRect
	bodyRect.Min.X = capRect.Max.X

	// energy will be drawn under the battery shell.  The only place where it
	// is not safe to draw energy is outside the battery on the positive end.
	energyMask := image.NewAlpha(app.Layout.battRect)
	draw.Draw(energyMask, app.Layout.battRect, opaque, zeropt, draw.Over)
	draw.Draw(energyMask, rectOutTop, transparent, zeropt, draw.Src)
	draw.Draw(energyMask, rectOutBottom, transparent, zeropt, draw.Src)
	app.maskEnergy = energyMask

	// the body uses the same mask as the energy with additional transparency
	// inside the battery's shell.  the mask construction is complex because
	// area inside the cap may be exposed.
	bodyMask := image.NewAlpha(app.Layout.battRect)
	draw.Draw(bodyMask, app.Layout.battRect, energyMask, app.Layout.battRect.Min, draw.Over)
	bodyMaskRect := shrinkRect(bodyRect, app.Layout.thickness)
	draw.Draw(bodyMask, bodyMaskRect, transparent, zeropt, draw.Src)
	capMaskRect := shrinkRect(capRect, app.Layout.thickness)
	capMaskRect.Max.X += 2 * app.Layout.thickness
	draw.Draw(bodyMask, capMaskRect, transparent, zeropt, draw.Src)
	app.maskBattery = bodyMask

	// create a freetype.Context to render text.  each time the context is used
	// it must have its SetDst method called.
	app.tt = freetype.NewContext()
	app.tt.SetSrc(black)
	app.tt.SetClip(app.Layout.textRect)
	app.tt.SetDPI(app.Layout.DPI)
	app.tt.SetFont(app.Layout.font)
	app.tt.SetFontSize(app.Layout.fontSize)
	ttopt := &truetype.Options{
		Size: app.Layout.fontSize,
		DPI:  app.Layout.DPI,
	}
	ttface := truetype.NewFace(app.Layout.font, ttopt)
	app.font = &font.Drawer{
		Src:  black,
		Face: ttface,
	}

	// the rectangle in which energy is drawn needs to account for thickness to
	// make the visible percentage more accurate.  after adjustment reduce the
	// energy rect to account for the account of energy drained.  the energy
	// mask makes computing Y bounds largely irrelevant.
	app.minEnergy = capMaskRect.Min.X
	app.maxEnergy = bodyMaskRect.Max.X
}
Beispiel #7
0
func (w *windowImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle, sender screen.Sender) {
	// TODO: adjust if dp is outside dst bounds, or sr is outside src bounds.
	// TODO: keep a texture around for this purpose?
	t, err := w.s.NewTexture(sr.Size())
	if err != nil {
		panic(err)
	}
	t.Upload(dp, src, sr, sender)
	w.Draw(f64.Aff3{1, 0, 0, 0, 1, 0}, t, sr, draw.Src, nil)
	t.Release()
}
Beispiel #8
0
// LinearCollider is O(N) collision checker. Inefficient but simple and accurate.
func LinearCollider(bounds image.Rectangle) Collider {
	size := bounds.Size()

	collider := &linearCollider{
		bounds: Boundary{float32(bounds.Min.X), float32(bounds.Min.Y), float32(bounds.Max.X), float32(bounds.Max.Y)},
		width:  size.X,
		height: size.Y,
	}
	collider.Reset()
	return collider
}
Beispiel #9
0
func GridCollider(bounds image.Rectangle) Collider {
	size := bounds.Size()

	grid := &gridCollider{
		bounds: Boundary{float32(bounds.Min.X), float32(bounds.Min.Y), float32(bounds.Max.X), float32(bounds.Max.Y)},
		width:  size.X,
		height: size.Y,
	}
	grid.Reset()
	return grid
}
Beispiel #10
0
func Rect(src image.Image, r image.Rectangle, at At) image.Image {
	dst := image.NewRGBA64(image.Rectangle{image.ZP, r.Size()})
	b := dst.Bounds()
	for x := r.Min.X; x < r.Max.X; x++ {
		for y := r.Min.Y; y < r.Max.Y; y++ {
			p := image.Pt(x, y).Sub(r.Min).Add(b.Min)
			dst.Set(p.X, p.Y, at(src, image.Pt(x, y)))
		}
	}
	return dst
}
Beispiel #11
0
func (w *windowImpl) vertexAff3(r image.Rectangle) f64.Aff3 {
	w.mu.Lock()
	sz := w.sz
	w.mu.Unlock()

	size := r.Size()
	tx, ty := float64(size.X), float64(size.Y)
	wx, wy := float64(sz.WidthPx), float64(sz.HeightPx)
	rx, ry := tx/wx, ty/wy

	// We are drawing the texture src onto the window's framebuffer.
	// The texture is (0,0)-(tx,ty). The window is (0,0)-(wx,wy), which
	// in vertex shader space is
	//
	//	(-1, +1) (+1, +1)
	//	(-1, -1) (+1, -1)
	//
	// A src2dst unit affine transform
	//
	// 	1 0 0
	// 	0 1 0
	// 	0 0 1
	//
	// should result in a (tx,ty) texture appearing in the upper-left
	// (tx, ty) pixels of the window.
	//
	// Setting w.s.texture.mvp to a unit affine transform results in
	// mapping the 2-unit square (-1,+1)-(+1,-1) given by quadXYCoords
	// in texture.go to the same coordinates in vertex shader space.
	// Thus, it results in the whole texture ((tx, ty) in texture
	// space) occupying the whole window ((wx, wy) in window space).
	//
	// A scaling affine transform
	//
	//	rx  0  0
	//	 0 ry  0
	//	 0  0  1
	//
	// results in a (tx, ty) texture occupying (tx, ty) pixels in the
	// center of the window.
	//
	// For upper-left alignment, we want to translate by
	// (-(1-rx), 1-ry), which is the affine transform
	//
	//	1    0   -1+rx
	//	0    1   +1-ry
	//	0    0       1
	//
	// These multiply to give:
	return f64.Aff3{
		rx, 0, -1 + rx,
		0, ry, +1 - ry,
	}
}
Beispiel #12
0
func NewCamera(rect image.Rectangle) Camera {
	sz := rect.Size()
	r := image.Rect(0, 0, sz.X, sz.Y)

	c := Camera{
		Pos:      image.ZP,
		SizeRect: r,
		Rect:     r,
	}

	return c
}
Beispiel #13
0
func imfilterMid(filter [][]float32, rect image.Rectangle, rgbFunc func(xpos, ypos int) (r0, g0, b0, a0 uint8)) *image.RGBA {
	size := rect.Size()
	imgGrey := image.NewRGBA(rect)
	fX := len(filter)
	fY := len(filter[0])
	for x := fX / 2; x < size.X-fX/2; x++ {
		for y := fY / 2; y < size.Y-fY/2; y++ {
			_, _, _, a := rgbFunc(x, y)
			newColor := color.RGBA{R: 0, G: 0, B: 0, A: a}
			imgGrey.SetRGBA(x, y, newColor)
		}
	}
	return imgGrey
}
Beispiel #14
0
//Returns the aspect ratio of a rectangle.
func aspectRatio(r image.Rectangle) float64 {
	size := r.Size()
	var min, max int

	if size.X < size.Y {
		min = size.X
		max = size.Y
	} else {
		min = size.Y
		max = size.X
	}

	return float64(max) / float64(min)
}
Beispiel #15
0
func cropImage(i image.Image, d image.Rectangle) (image.Image, error) {
	bounds := i.Bounds()
	if bounds.Min.X > d.Min.X || bounds.Min.Y > d.Min.Y || bounds.Max.X < d.Max.X || bounds.Max.Y < d.Max.Y {
		return nil, errors.New("Bounds invalid for crop")
	}

	dims := d.Size()
	outIm := image.NewRGBA(image.Rect(0, 0, dims.X, dims.Y))
	for x := 0; x < dims.X; x++ {
		for y := 0; y < dims.Y; y++ {
			outIm.Set(x, y, i.At(d.Min.X+x, d.Min.Y+y))
		}
	}
	return outIm, nil
}
// 返回sub BinaryImage
func (bi BinaryImage) SubBinaryImage(rect image.Rectangle) BinaryImage {
	binimg := BinaryImage(bi)
	h, w := rect.Size().Y+1, rect.Size().X+1

	// init
	newbi := make([][]int, h, h)
	for y := 0; y < h; y++ {
		newbi[y] = make([]int, w, w)
	}

	// copy
	for y := 0; y < h; y++ {
		copy(newbi[y], binimg[rect.Min.Y+y][rect.Min.X:rect.Max.X+1])
	}
	return BinaryImage(newbi)
}
Beispiel #17
0
func TestHOG_boundary(t *testing.T) {
	const (
		sbin  = 4
		frac  = 3
		fname = "000084.jpg"
	)
	// Load image.
	file, err := os.Open(fname)
	if err != nil {
		t.Fatal(err)
	}
	im, _, err := image.Decode(file)

	// Take top-left part which is divisible by sbin and frac.
	im = ensureDivis(im, sbin*frac)
	// Make a rectangle of the top-left part of the image.
	// Not the most top-left window but the second-most.
	size := im.Bounds().Size()
	rect := image.Rectangle{size.Div(frac), size.Div(frac).Mul(2)}

	// Sub-sample image
	subim := image.NewRGBA(image.Rectangle{image.ZP, rect.Size()})
	draw.Draw(subim, subim.Bounds(), im, rect.Min, draw.Src)

	// Convert to real values.
	f := HOG(rimg64.FromColor(im), FGMRConfig(sbin))
	g := HOG(rimg64.FromColor(subim), FGMRConfig(sbin))

	// Take rectangle in f of same size as g.
	min := rect.Min.Div(sbin)
	subf := f.SubImage(image.Rectangle{min, min.Add(g.Size())})

	const prec = 1e-9
	// Skip last element because of a slight difference.
	// (Not using cell outside image.)
	for x := 0; x < g.Width; x++ {
		for y := 0; y < g.Height; y++ {
			for d := 0; d < g.Channels; d++ {
				want := g.At(x, y, d)
				got := subf.At(x, y, d)
				if math.Abs(want-got) > prec {
					t.Errorf("wrong value: at %d, %d, %d: want %g, got %g", x, y, d, want, got)
				}
			}
		}
	}
}
Beispiel #18
0
func (w *windowImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle, sender screen.Sender) {
	// TODO: adjust if dp is outside dst bounds, or sr is outside src bounds.
	// TODO: keep a texture around for this purpose?
	t, err := w.s.NewTexture(sr.Size())
	if err != nil {
		panic(err)
	}
	t.(*textureImpl).upload(dp, src, sr)
	if sender != nil {
		sender.Send(screen.UploadedEvent{Buffer: src, Uploader: w})
	}
	w.Draw(f64.Aff3{
		1, 0, float64(dp.X),
		0, 1, float64(dp.Y),
	}, t, sr, draw.Src, nil)
	t.Release()
}
Beispiel #19
0
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()
}
Beispiel #20
0
func CountColor(reader io.Reader) int {
	var count = map[string]int{}

	decodedPng, error := png.Decode(reader)
	if error == nil {
		var rect image.Rectangle = decodedPng.Bounds()
		for i := 0; i < rect.Size().X; i++ {
			for j := 0; j < rect.Size().Y; j++ {
				var pixel image.Color = decodedPng.At(i, j)
				var r, g, b, _ uint32 = pixel.RGBA()
				var key uint = (uint)((r << 16) + (g << 8) + (b))

				if _, ok := count[strconv.Uitoa(key)]; ok {
					count[strconv.Uitoa(key)]++
				} else {
					count[strconv.Uitoa(key)] = 1
				}
			}
		}
	}
	return len(count)
}
Beispiel #21
0
func imenhance(enhanceDegress float32, enhanceOffset float32, enhanceChannel [3]bool, withFunc bool, rect image.Rectangle, rgbFunc func(xpos, ypos int) (r0, g0, b0, a0 uint8)) *image.RGBA {
	timeOld := time.Now()
	wg := sync.WaitGroup{}
	newImage := image.NewRGBA(rect)
	size := rect.Size()
	fX := size.X
	fY := size.Y

	threadCount := 8
	sizeoffset := fX / threadCount
	wg.Add(threadCount)
	for i := 0; i < threadCount; i++ {
		go func(i int) {
			for x := sizeoffset * i; x < sizeoffset*(i+1); x++ {
				for y := 0; y < fY; y++ {
					r, g, b, a := rgbFunc(x, y)
					if !withFunc {
						if enhanceChannel[0] {
							r = oneColorCorrect(float32(r)*enhanceDegress + enhanceOffset)
						}
						if enhanceChannel[1] {
							g = oneColorCorrect(float32(g)*enhanceDegress + enhanceOffset)
						}
						if enhanceChannel[2] {
							b = oneColorCorrect(float32(b)*enhanceDegress + enhanceOffset)
						}
					}
					newColor := color.RGBA{R: r, G: g, B: b, A: a}
					newImage.SetRGBA(x, y, newColor)
				}
			}
			wg.Done()
		}(i)
	}
	wg.Wait()
	fmt.Println("Enhance Time:", time.Now().Sub(timeOld))
	return newImage
}
Beispiel #22
0
func Rotate(s image.Image, deg int) (image.Image, error) {
	src := toRGBA(s)
	var d image.Rectangle
	switch deg {
	default:
		return nil, errors.New("Unsupported angle (90, 180, 270).")
	case 90, 270:
		d = image.Rect(0, 0, src.Bounds().Size().Y, src.Bounds().Size().X)
	case 180:
		d = image.Rect(0, 0, src.Bounds().Size().X, src.Bounds().Size().Y)
	}
	rv := image.NewRGBA(d)
	b := src.Bounds()
	/* switch outside of loops for performance reasons */
	switch deg {
	case 270:
		for y := 0; y < b.Size().Y; y++ {
			for x := 0; x < b.Size().X; x++ {
				s := x*rv.Stride + 4*(d.Size().X-y-1)
				p := y*src.Stride + x*4
				copy(rv.Pix[s:s+4], src.Pix[p:p+4])
			}
		}
	case 180:
		for y := 0; y < b.Size().Y; y++ {
			for x := 0; x < b.Size().X; x++ {
				s := (d.Size().Y-y-1)*rv.Stride + 4*d.Size().X - (x+1)*4
				p := y*src.Stride + x*4
				copy(rv.Pix[s:s+4], src.Pix[p:p+4])
			}
		}
	case 90:
		for y := 0; y < b.Size().Y; y++ {
			for x := 0; x < b.Size().X; x++ {
				s := (d.Size().Y-x-1)*rv.Stride + y*4
				p := y*src.Stride + x*4
				copy(rv.Pix[s:s+4], src.Pix[p:p+4])
			}
		}
	}
	return rv, nil
}
Beispiel #23
0
func nonMaxSupp(scoreImgs []cv.RealImage, scales imgpyr.GeoSeq, size image.Point, maxRelOverlap float64) []PyrPos {
	// Put every window into a list.
	all := allDetections(scoreImgs, scales)
	// Sort this list by score.
	sort.Sort(sort.Reverse(byScore{scoreImgs, all}))

	// List of remaining detections.
	remain := list.New()
	// Look-up of list elements by position.
	elems := make([][][]*list.Element, len(scoreImgs))
	for k, img := range scoreImgs {
		elems[k] = make([][]*list.Element, img.Width)
		for x := 0; x < img.Width; x++ {
			elems[k][x] = make([]*list.Element, img.Height)
		}
	}
	// Populate both.
	for _, det := range all {
		elems[det.Level][det.Pos.X][det.Pos.Y] = remain.PushBack(det)
	}

	// Select best detection, remove those which overlap with it.
	var dets []PyrPos
	for remain.Len() > 0 {
		// Remove from remaining and add to detections.
		e := remain.Front()
		det, ok := e.Value.(PyrPos)
		if !ok {
			panic("unexpected type in list")
		}
		remain.Remove(e)
		dets = append(dets, det)

		// Get bounds of detection in its scale.
		r := image.Rectangle{det.Pos, det.Pos.Add(size)}
		// Scale back into frame of original (feature) image.
		r = scaleRect(1/scales.At(det.Level), r)

		for k, img := range scoreImgs {
			// Scale top-left corner into current level.
			p := scalePoint(scales.At(k), r.Min)
			// Calculate bounds on range (exclusive).
			a := p.Sub(size)
			b := p.Add(size)
			ax, bx := max(a.X+1, 0), min(b.X, img.Width)
			ay, by := max(a.Y+1, 0), min(b.Y, img.Height)

			for x := ax; x < bx; x++ {
				for y := ay; y < by; y++ {
					if elems[k][x][y] == nil {
						// Element already removed.
						continue
					}

					// Candidate rectangle in its scale.
					p := image.Pt(x, y)
					q := image.Rectangle{p, p.Add(size)}
					// Scale back into frame of original (feature) image.
					q = scaleRect(1/scales.At(k), q)

					// Compute overlap.
					overlap := q.Intersect(r)
					relR := float64(area(overlap.Size())) / float64(area(r.Size()))
					relQ := float64(area(overlap.Size())) / float64(area(q.Size()))
					if relR <= maxRelOverlap && relQ <= maxRelOverlap {
						// Maximum relative overlap is not exceeded.
						continue
					}
					// Remove from the list.
					remain.Remove(elems[k][x][y])
					elems[k][x][y] = nil
				}
			}
		}
	}
	return dets
}
Beispiel #24
0
func RotateRect(r image.Rectangle) image.Rectangle {
	s := r.Size()
	return image.Rectangle{r.Min, image.Point{s.Y, s.X}}
}
Beispiel #25
0
// Returns a blocking channel of Step.
//
// Once Step.Done() is true, the calculation has finished and the channel is closed.
// You can use this to abort calculating larger image resamples or to show percentage
// done indicators.
//
// The filter F is the resampling function used. See the provided samplers for examples.
// Additionally X- and YWrap functions are used to define how image boundaries are
// treated. See the provided Clamp function for examples.
func ResizeToChannelWithFilter(dst image.Image, dstRect image.Rectangle,
	src image.Image, srcRect image.Rectangle,
	F Filter, XWrap, YWrap WrapFunc) (<-chan Step, chan<- bool, error) {
	if src == nil {
		return nil, nil, ErrSourceImageIsInvalid
	}
	if F.Apply == nil || F.Support <= 0 {
		return nil, nil, ErrMissingFilter
	}
	if XWrap == nil || YWrap == nil {
		return nil, nil, ErrMissingWrapFunc
	}

	var dstBounds image.Rectangle
	if dst == nil {
		dstBounds.Max = srcRect.Size()
	} else {
		dstBounds = dst.Bounds()
	}

	newSize := dstRect.Size()

	if newSize.X < 0 || newSize.Y < 0 {
		return nil, nil, ErrTargetSizeIsInvalid
	}

	resultChannel := make(chan Step)
	doneChannel := make(chan bool)
	// Code for the KeepAlive closure used to
	// break the calulculation into blocks.
	// Sends on the channel only happen every opIncrement
	// operations. For now this is hardcoded to a reasonable value.
	var opCount, totalOps, lastOps, opIncrement int
	opIncrement = 200 * 1000
	keepAlive := func(ops int) bool {
		opCount += ops
		if opCount >= lastOps {
			select {
			case <-doneChannel:
				return false
			case resultChannel <- step{image: nil, total: totalOps, done: opCount}:
				lastOps += opIncrement
				return true
			}
		}
		return true

	}
	sendImage := func(img image.Image) {
		select {
		case resultChannel <- step{image: img, total: totalOps, done: opCount}:
		case <-doneChannel:
		}
	}

	if newSize.X == 0 || newSize.Y == 0 {
		go sendImage(image.NewNRGBA64(image.Rect(0, 0, newSize.X, newSize.Y)))
		return resultChannel, doneChannel, nil
	}

	go func() {
		// Send first empty step before we do any real work.
		keepAlive(0)

		xFilter, xOps := makeDiscreteFilter(F, XWrap, dstRect.Dx(), srcRect.Dx())
		yFilter, yOps := makeDiscreteFilter(F, YWrap, dstRect.Dy(), srcRect.Dy())

		if dst == nil {
			dst = image.NewNRGBA64(dstRect)
		}
		dst := dst.(*image.NRGBA64)

		xy_ops := yOps*srcRect.Dx() + xOps*dstRect.Dy()
		yx_ops := xOps*srcRect.Dy() + yOps*dstRect.Dx()

		if xy_ops < yx_ops {
			totalOps = xy_ops
			tmpBounds := image.Rect(0, 0, srcRect.Dx(), dstRect.Dy())
			var tmp *image.NRGBA64
			if tmpBounds.Dx() < dstRect.Dx() {
				tmp = image.NewNRGBA64(tmpBounds)
			} else {
				tmp = dst
			}
			resampleAxisNRGBA64(yAxis, keepAlive, tmp, tmpBounds, src, srcRect, yFilter)
			resampleAxisNRGBA64(xAxis, keepAlive, dst, dstRect, tmp, tmpBounds, xFilter)
		} else {
			totalOps = yx_ops
			tmpBounds := image.Rect(0, 0, dstRect.Dx(), srcRect.Dy())
			var tmp *image.NRGBA64
			if tmpBounds.Dy() < dstRect.Dy() {
				tmp = image.NewNRGBA64(tmpBounds)
			} else {
				tmp = dst
			}
			resampleAxisNRGBA64(xAxis, keepAlive, tmp, tmpBounds, src, srcRect, xFilter)
			resampleAxisNRGBA64(yAxis, keepAlive, dst, dstRect, tmp, tmpBounds, yFilter)
		}
		//log.Printf("Resize %v -> %v %d kOps (xy =%d,yx =%d)",src.Bounds().Max, newSize,opCount/1000, xy_ops/1000, yx_ops/1000)
		sendImage(dst)
	}()
	return resultChannel, doneChannel, nil
}
Beispiel #26
0
// CropTo returns a copy of this image that has been cropped
// to the given dimensions
func (self Image) CropTo(bounds image.Rectangle) Image {
	dst := image.NewRGBA(bounds.Sub(bounds.Min))
	r := image.Rectangle{dst.Rect.Min, dst.Rect.Min.Add(bounds.Size())}
	draw.Draw(dst, r, self.Img, bounds.Min, draw.Src)
	return Image{Img: dst, Format: self.Format}
}
Beispiel #27
0
func (v *mappingView) drawScene(r image.Rectangle) {
	x, y, w, h := r.Min.X, r.Min.Y, r.Size().X, r.Size().Y
	v.area.QueueDrawArea(v.parent.ScaleCoord(x, false), v.parent.ScaleCoord(y, false),
		v.parent.ScaleCoord(w, true)+1, v.parent.ScaleCoord(h, true)+1)
	return
}
Beispiel #28
0
// CenterOrigin returns the screen coordinates where a game tile that shows up
// at the center of the rectangle should be drawn.
func CenterOrigin(screenArea image.Rectangle) (screenPos image.Point) {
	return screenArea.Min.Add(screenArea.Size().Div(2)).Sub(image.Pt(TileW/2, TileH/2))
}