mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 23:55:39 +00:00
gpu/headless: make Screenshot take an input image to tranfer into
When extracting headless.Window's content via screenshots, it can be useful to keep reusing the same image for output, as well as specify which area of the Window is to be extracted. The updated Screenshot method does this by using the supplied image. API change: users must pass an existing image to Window.Screenshot. Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
+4
-7
@@ -10,6 +10,7 @@ import (
|
||||
"hash/maphash"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
@@ -648,17 +649,13 @@ func (g *compute) frame(target RenderTarget) error {
|
||||
|
||||
func (g *compute) dumpAtlases() {
|
||||
for i, a := range g.atlases {
|
||||
dump, err := driver.DownloadImage(g.ctx, a.image, image.Rectangle{Max: a.size})
|
||||
dump := image.NewRGBA(image.Rectangle{Max: a.size})
|
||||
err := driver.DownloadImage(g.ctx, a.image, dump)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
nrgba := image.NewNRGBA(dump.Bounds())
|
||||
bnd := dump.Bounds()
|
||||
for x := bnd.Min.X; x < bnd.Max.X; x++ {
|
||||
for y := bnd.Min.Y; y < bnd.Max.Y; y++ {
|
||||
nrgba.SetNRGBA(x, y, f32color.RGBAToNRGBA(dump.RGBAAt(x, y)))
|
||||
}
|
||||
}
|
||||
draw.Draw(nrgba, image.Rectangle{}, dump, image.Point{}, draw.Src)
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, nrgba); err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -185,7 +185,8 @@ func newDriver(t *testing.T) driver.Device {
|
||||
}
|
||||
|
||||
func screenshot(t *testing.T, d driver.Device, fbo driver.Texture, size image.Point) *image.RGBA {
|
||||
img, err := driver.DownloadImage(d, fbo, image.Rectangle{Max: size})
|
||||
img := image.NewRGBA(image.Rectangle{Max: size})
|
||||
err := driver.DownloadImage(d, fbo, img)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+10
-12
@@ -122,7 +122,12 @@ func (w *Window) Release() {
|
||||
}
|
||||
}
|
||||
|
||||
// Frame replace the window content and state with the
|
||||
// Size returns the window size.
|
||||
func (w *Window) Size() image.Point {
|
||||
return w.size
|
||||
}
|
||||
|
||||
// Frame replaces the window content and state with the
|
||||
// operation list.
|
||||
func (w *Window) Frame(frame *op.Ops) error {
|
||||
return contextDo(w.ctx, func() error {
|
||||
@@ -131,18 +136,11 @@ func (w *Window) Frame(frame *op.Ops) error {
|
||||
})
|
||||
}
|
||||
|
||||
// Screenshot returns an image with the content of the window.
|
||||
func (w *Window) Screenshot() (*image.RGBA, error) {
|
||||
var img *image.RGBA
|
||||
err := contextDo(w.ctx, func() error {
|
||||
var err error
|
||||
img, err = driver.DownloadImage(w.dev, w.fboTex, image.Rectangle{Max: w.size})
|
||||
return err
|
||||
// Screenshot transfers the Window content at origin img.Rect.Min to img.
|
||||
func (w *Window) Screenshot(img *image.RGBA) error {
|
||||
return contextDo(w.ctx, func() error {
|
||||
return driver.DownloadImage(w.dev, w.fboTex, img)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
func contextDo(ctx context, f func() error) error {
|
||||
|
||||
@@ -28,7 +28,8 @@ func TestHeadless(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
img, err := w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: w.Size()})
|
||||
err := w.Screenshot(img)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -69,7 +70,8 @@ func TestClipping(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
img, err := w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: w.Size()})
|
||||
err := w.Screenshot(img)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -108,7 +110,8 @@ func TestDepth(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
img, err := w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: w.Size()})
|
||||
err := w.Screenshot(img)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -199,17 +199,17 @@ func (f Features) Has(feats Features) bool {
|
||||
return f&feats == feats
|
||||
}
|
||||
|
||||
func DownloadImage(d Device, t Texture, r image.Rectangle) (*image.RGBA, error) {
|
||||
img := image.NewRGBA(r)
|
||||
func DownloadImage(d Device, t Texture, img *image.RGBA) error {
|
||||
r := img.Bounds()
|
||||
if err := t.ReadPixels(r, img.Pix, img.Stride); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if d.Caps().BottomLeftOrigin {
|
||||
// OpenGL origin is in the lower-left corner. Flip the image to
|
||||
// match.
|
||||
flipImageY(r.Dx()*4, r.Dy(), img.Pix)
|
||||
}
|
||||
return img, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func flipImageY(stride, height int, pixels []byte) {
|
||||
|
||||
@@ -47,7 +47,8 @@ func resetOps(gtx layout.Context) {
|
||||
func finishBenchmark(b *testing.B, w *headless.Window) {
|
||||
b.StopTimer()
|
||||
if *dumpImages {
|
||||
img, err := w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: w.Size()})
|
||||
err := w.Screenshot(img)
|
||||
w.Release()
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
|
||||
@@ -59,7 +59,7 @@ func buildSquares(size int) paint.ImageOp {
|
||||
return paint.NewImageOp(im)
|
||||
}
|
||||
|
||||
func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (im *image.RGBA, err error) {
|
||||
func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (*image.RGBA, error) {
|
||||
sz := image.Point{X: size, Y: size}
|
||||
w := newWindow(t, sz.X, sz.Y)
|
||||
defer w.Release()
|
||||
@@ -67,7 +67,9 @@ func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (im *i
|
||||
if err := w.Frame(ops); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: sz})
|
||||
err := w.Screenshot(img)
|
||||
return img, err
|
||||
}
|
||||
|
||||
func run(t *testing.T, f func(o *op.Ops), c func(r result)) {
|
||||
@@ -106,7 +108,6 @@ type frameT struct {
|
||||
func multiRun(t *testing.T, frames ...frameT) {
|
||||
// draw a few times and check that it is correct each time, to
|
||||
// ensure any caching effects still generate the correct images.
|
||||
var img *image.RGBA
|
||||
var err error
|
||||
sz := image.Point{X: 128, Y: 128}
|
||||
w := newWindow(t, sz.X, sz.Y)
|
||||
@@ -119,7 +120,8 @@ func multiRun(t *testing.T, frames ...frameT) {
|
||||
t.Errorf("rendering failed: %v", err)
|
||||
continue
|
||||
}
|
||||
img, err = w.Screenshot()
|
||||
img := image.NewRGBA(image.Rectangle{Max: sz})
|
||||
err = w.Screenshot(img)
|
||||
if err != nil {
|
||||
t.Errorf("screenshot failed: %v", err)
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user