diff --git a/imagedumper_notmobile.go b/imagedumper_notmobile.go index 25d57b5ec..2310b7771 100644 --- a/imagedumper_notmobile.go +++ b/imagedumper_notmobile.go @@ -18,64 +18,39 @@ package ebiten import ( - "errors" "fmt" "os" - "syscall" "time" "github.com/hajimehoshi/ebiten/v2/internal/debug" "github.com/hajimehoshi/ebiten/v2/internal/ui" ) -// availableFilename returns a filename that is valid as a new file or directory. -func availableFilename(prefix, postfix string) (string, error) { +func datetimeForFilename() string { const datetimeFormat = "20060102030405" - now := time.Now() - name := fmt.Sprintf("%s%s%s", prefix, now.Format(datetimeFormat), postfix) - for i := 1; ; i++ { - if _, err := os.Stat(name); err != nil { - if os.IsNotExist(err) || errors.Is(err, syscall.ENOSYS) { - break - } - if !os.IsNotExist(err) { - return "", err - } - } - name = fmt.Sprintf("%s%s_%d%s", prefix, now.Format(datetimeFormat), i, postfix) - } - return name, nil + return now.Format(datetimeFormat) } func takeScreenshot(screen *Image) error { - newname, err := availableFilename("screenshot_", ".png") + name := "screenshot_" + datetimeForFilename() + ".png" + blackbg := !IsScreenTransparent() + dumpedName, err := screen.image.DumpScreenshot(name, blackbg) if err != nil { return err } - - blackbg := !IsScreenTransparent() - if err := screen.image.DumpScreenshot(newname, blackbg); err != nil { - return err - } - - if _, err := fmt.Fprintf(os.Stderr, "Saved screenshot: %s\n", newname); err != nil { + if _, err := fmt.Fprintf(os.Stderr, "Saved screenshot: %s\n", dumpedName); err != nil { return err } return nil } func dumpInternalImages() error { - dir, err := availableFilename("internalimages_", "") + dumpedDir, err := ui.DumpImages("internalimages_" + datetimeForFilename()) if err != nil { return err } - - if err := ui.DumpImages(dir); err != nil { - return err - } - - if _, err := fmt.Fprintf(os.Stderr, "Dumped the internal images at: %s\n", dir); err != nil { + if _, err := fmt.Fprintf(os.Stderr, "Dumped the internal images at: %s\n", dumpedDir); err != nil { return err } return nil diff --git a/internal/atlas/image.go b/internal/atlas/image.go index beccb29b9..e0f82f37f 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -733,7 +733,7 @@ func (i *Image) allocate(putOnAtlas bool) { i.node = n } -func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool) error { +func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool) (string, error) { backendsM.Lock() defer backendsM.Unlock() @@ -786,7 +786,7 @@ func BeginFrame(graphicsDriver graphicsdriver.Graphics) error { return nil } -func DumpImages(graphicsDriver graphicsdriver.Graphics, dir string) error { +func DumpImages(graphicsDriver graphicsdriver.Graphics, dir string) (string, error) { backendsM.Lock() defer backendsM.Unlock() return restorable.DumpImages(graphicsDriver, dir) diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 0fbcb82c4..b7b8dcf7c 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -113,7 +113,7 @@ func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte return nil } -func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) error { +func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) (string, error) { checkDelayedCommandsFlushed("Dump") return i.img.DumpScreenshot(graphicsDriver, name, blackbg) } diff --git a/internal/graphicscommand/image_js.go b/internal/graphicscommand/image_js.go index 210e12357..b4f63ffac 100644 --- a/internal/graphicscommand/image_js.go +++ b/internal/graphicscommand/image_js.go @@ -39,26 +39,26 @@ func download(buf *bytes.Buffer, mime string, path string) { a.Call("click") } -func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) error { +func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) (string, error) { // Screen image cannot be dumped. if i.screen { - return nil + return "", nil } buf := &bytes.Buffer{} if err := i.dumpTo(buf, graphicsDriver, blackbg, rect); err != nil { - return err + return "", err } download(buf, "image/png", i.dumpName(path)) - return nil + return path, nil } // DumpImages dumps all the specified images to the specified directory. // // This is for testing usage. -func DumpImages(images []*Image, graphicsDriver graphicsdriver.Graphics, dir string) error { +func DumpImages(images []*Image, graphicsDriver graphicsdriver.Graphics, dir string) (string, error) { buf := &bytes.Buffer{} zw := zip.NewWriter(buf) @@ -70,17 +70,18 @@ func DumpImages(images []*Image, graphicsDriver graphicsdriver.Graphics, dir str f, err := zw.Create(img.dumpName("*.png")) if err != nil { - return err + return "", err } if err := img.dumpTo(f, graphicsDriver, false, image.Rect(0, 0, img.width, img.height)); err != nil { - return err + return "", err } } zw.Close() - download(buf, "archive/zip", dir+".zip") + zip := dir + ".zip" + download(buf, "archive/zip", zip) - return nil + return zip, nil } diff --git a/internal/graphicscommand/image_notjs.go b/internal/graphicscommand/image_notjs.go index d805f418e..4ff2fda34 100644 --- a/internal/graphicscommand/image_notjs.go +++ b/internal/graphicscommand/image_notjs.go @@ -18,6 +18,8 @@ package graphicscommand import ( + "errors" + "fmt" "image" "os" "path/filepath" @@ -25,38 +27,74 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" ) -func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) error { - // Screen image cannot be dumped. - if i.screen { - return nil +func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) (string, error) { + p, err := availableFilename(path) + if err != nil { + return "", err } + path = p path = i.dumpName(path) f, err := os.Create(path) if err != nil { - return err + return "", err } defer f.Close() if err := i.dumpTo(f, graphicsDriver, blackbg, rect); err != nil { - return err + return "", err } - return nil + return path, nil } // DumpImages dumps all the current images to the specified directory. // // This is for testing usage. -func DumpImages(images []*Image, graphicsDriver graphicsdriver.Graphics, dir string) error { +func DumpImages(images []*Image, graphicsDriver graphicsdriver.Graphics, dir string) (string, error) { + d, err := availableFilename(dir) + if err != nil { + return "", err + } + dir = d + if err := os.Mkdir(dir, 0755); err != nil { - return err + return "", err } for _, img := range images { - if err := img.Dump(graphicsDriver, filepath.Join(dir, "*.png"), false, image.Rect(0, 0, img.width, img.height)); err != nil { - return err + // Screen image cannot be dumped. + if img.screen { + continue + } + + f, err := os.Create(filepath.Join(dir, img.dumpName("*.png"))) + if err != nil { + return "", err + } + defer f.Close() + + if err := img.dumpTo(f, graphicsDriver, false, image.Rect(0, 0, img.width, img.height)); err != nil { + return "", err } } - return nil + + return dir, nil +} + +// availableFilename returns a filename that is valid as a new file or directory. +func availableFilename(name string) (string, error) { + ext := filepath.Ext(name) + base := name[:len(name)-len(ext)] + + for i := 1; ; i++ { + if _, err := os.Stat(name); err != nil { + if errors.Is(err, os.ErrNotExist) { + break + } + return "", err + } + name = fmt.Sprintf("%s_%d%s", base, i, ext) + } + return name, nil } diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index 45b7f9c0a..5dc581b8e 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -45,7 +45,7 @@ func New(width, height int, imageType atlas.ImageType) *Mipmap { } } -func (m *Mipmap) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) error { +func (m *Mipmap) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) (string, error) { return m.orig.DumpScreenshot(graphicsDriver, name, blackbg) } diff --git a/internal/restorable/image.go b/internal/restorable/image.go index e227c304b..572547638 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -668,7 +668,7 @@ func (i *Image) isInvalidated(graphicsDriver graphicsdriver.Graphics) (bool, err return i.image.IsInvalidated(), nil } -func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) error { +func (i *Image) Dump(graphicsDriver graphicsdriver.Graphics, path string, blackbg bool, rect image.Rectangle) (string, error) { return i.image.Dump(graphicsDriver, path, blackbg, rect) } diff --git a/internal/restorable/images.go b/internal/restorable/images.go index d9f424903..03f89a778 100644 --- a/internal/restorable/images.go +++ b/internal/restorable/images.go @@ -122,7 +122,7 @@ func RestoreIfNeeded(graphicsDriver graphicsdriver.Graphics) error { // DumpImages dumps all the current images to the specified directory. // // This is for testing usage. -func DumpImages(graphicsDriver graphicsdriver.Graphics, dir string) error { +func DumpImages(graphicsDriver graphicsdriver.Graphics, dir string) (string, error) { images := make([]*graphicscommand.Image, 0, len(theImages.images)) for img := range theImages.images { images = append(images, img.image) diff --git a/internal/ui/image.go b/internal/ui/image.go index e3e9703f2..819e2c927 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -89,11 +89,11 @@ func (i *Image) ReadPixels(pixels []byte, x, y, width, height int) { } } -func (i *Image) DumpScreenshot(name string, blackbg bool) error { +func (i *Image) DumpScreenshot(name string, blackbg bool) (string, error) { return theUI.dumpScreenshot(i.mipmap, name, blackbg) } -func DumpImages(dir string) error { +func DumpImages(dir string) (string, error) { return theUI.dumpImages(dir) } diff --git a/internal/ui/ui.go b/internal/ui/ui.go index 57411f81e..bf9aed937 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -95,10 +95,10 @@ func (u *UserInterface) readPixels(mipmap *mipmap.Mipmap, pixels []byte, x, y, w return mipmap.ReadPixels(u.graphicsDriver, pixels, x, y, width, height) } -func (u *UserInterface) dumpScreenshot(mipmap *mipmap.Mipmap, name string, blackbg bool) error { +func (u *UserInterface) dumpScreenshot(mipmap *mipmap.Mipmap, name string, blackbg bool) (string, error) { return mipmap.DumpScreenshot(u.graphicsDriver, name, blackbg) } -func (u *UserInterface) dumpImages(dir string) error { +func (u *UserInterface) dumpImages(dir string) (string, error) { return atlas.DumpImages(u.graphicsDriver, dir) }