From 9ddcf587282f26fdc60c993dbc7888968d65c345 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 2 Apr 2022 06:10:20 +0900 Subject: [PATCH] ebiten: allow passing ebiten.Image to NewImageFromImage Closes #1917 --- image.go | 11 +++++++++++ image_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/image.go b/image.go index 5c4365e1f..d875d8db3 100644 --- a/image.go +++ b/image.go @@ -808,11 +808,22 @@ func NewImage(width, height int) *Image { // Reusing the same image by Clear is much more efficient than creating a new image. // // NewImageFromImage panics if RunGame already finishes. +// +// The returned image's origin is always (0, 0). The source's bounds are not respected. func NewImageFromImage(source image.Image) *Image { if isRunGameEnded() { panic(fmt.Sprintf("ebiten: NewImage cannot be called after RunGame finishes")) } + // If the given image is an Ebiten image, use DrawImage instead of reading pixels from the source. + // This works even before the game loop runs. + if source, ok := source.(*Image); ok { + size := source.Bounds().Size() + i := NewImage(size.X, size.Y) + i.DrawImage(source, nil) + return i + } + size := source.Bounds().Size() width, height := size.X, size.Y if width <= 0 { diff --git a/image_test.go b/image_test.go index 3828fd044..e706f8a88 100644 --- a/image_test.go +++ b/image_test.go @@ -2846,3 +2846,46 @@ func TestTooManyVertices(t *testing.T) { // Confirm this doesn't freeze. dst.At(0, 0) } + +func TestImageNewImageFromEbitenImage(t *testing.T) { + const ( + w = 16 + h = 16 + ) + + pix := make([]byte, 4*w*h) + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + idx := 4 * (i + j*w) + pix[idx] = byte(i) + pix[idx+1] = byte(j) + pix[idx+2] = 0 + pix[idx+3] = 0xff + } + } + + img0 := ebiten.NewImage(w, h) + img0.ReplacePixels(pix) + img1 := ebiten.NewImageFromImage(img0) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := img1.At(i, j) + want := color.RGBA{byte(i), byte(j), 0, 0xff} + if got != want { + t.Errorf("img1.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } + + img2 := ebiten.NewImageFromImage(img0.SubImage(image.Rect(4, 4, 12, 12))) + for j := 0; j < h/2; j++ { + for i := 0; i < w/2; i++ { + got := img2.At(i, j) + want := color.RGBA{byte(i + 4), byte(j + 4), 0, 0xff} + if got != want { + t.Errorf("img1.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}