この記事ではスクリーンショットをPNG画像に保存する方法について解説します。
目次
スクリーンショットをPNG画像に保存する方法
Image.save_png() を使う
PNG画像へ保存するには Image.save_png() を使います。この関数の引数に保存するパスを指定することで、その画像がPNGとして保存されます。
ViewportTexture から Image を取り出す
スクリーンショットをPNGとして保存するには、Viewport から Image を取得します。
具体的に記述方法を確認するためにテスト用のプロジェクトを作ってみます。以下はたこ焼きが動き回るだけのプロジェクトです。

Main.gd はすでに用意されているので、そのまま編集していきます。
extends Node2D
func _process(delta: float) -> void:
if Input.is_action_just_pressed("click"):
_save_png()
## PNG保存処理.
func _save_png() -> void:
# ビューポートを取得.
var vp = get_viewport()
# ビューポートテクスチャを取得.
var vp_tex = vp.get_texture()
# Imageを取得.
var image = vp_tex.get_image()
# PNGとして保存.(res://に保存)
image.save_png("res://screenshot1.png")
# PNGとして保存.(user://に保存)
image.save_png("user://screenshot2.png")
print("Save PNG.")
まず get_viewport() で現在のシーンのビューポートを取得します。次に ViewportTexture を取得し、Image を取り出して save_png() で保存します。
保存先としては、”res://” または “user://” に保存します。これは用途によって使い分けが必要です。
ただスクリーンショットの保存という用途であれば、通常は “user://” に保存します。
理由として、”res://” はアクセス権限がない可能性があるためで、詳しくは以下の記事に書いています。(また “res://” に保存するとプロジェクトに含まれてしまうという問題もあります)。

ひとまず先程のスクリプトを実行すると、”screenshot1.png” は プロジェクト内に保存されます。

“user://” のフォルダは少し厄介な場所にあります。
- Windows:
%APPDATA%\Godot\
- macOS:
~/Library/Application Support/Godot/
上記フォルダの「TestSavePNG」フォルダに “screenshot2.png” は保存されています。

保存したフォルダを自動で開くようにする
“user://” のフォルダを開くのは面倒なので、自動で開くようにすることもできます。
ProjectSettings.globalize_path() でパスを取得し、OS.shell_open() でフォルダを開きます。
## PNG保存処理.
func _save_png() -> void:
# ビューポートを取得.
var vp = get_viewport()
# ビューポートテクスチャを取得.
var vp_tex = vp.get_texture()
# Imageを取得.
var image = vp_tex.get_image()
# PNGとして保存.(user://に保存)
image.save_png("user://screenshot2.png")
# 保存したフォルダをシェルで開く.
var path = str("file://", ProjectSettings.globalize_path("user://"))
OS.shell_open(path)
print("Save PNG.")
_save_png() をこのように修正すると、自動でフォルダが開くようになります。
透過を有効にする
シーンのビューポートをそのまま使うと、クリアカラーで背景が塗られた画像となってしまいます。そのため出力したPNG画像を素材画像として使用する…ということができません。
また画面全体がキャプチャされるため、一部分を切り出して保存することもできません。

そこでキャプチャしたい部分に “SubViewport” を適用することで、該当の部分を切り出したり、背景を透過することができます。
SubViewport を使うには、まずは「SubViewportContainer」ノードを追加します。

そして SubViewportContainer を右クリックして「子ノードを追加」を選びます。

「SubViewport」を追加。

このような構成となりました。

次に「SubViewportContainer」を選んで、”Stretch” の項目をオンにします。

そうしたら、「SubViewportContainer」のサイズを Viewport と同じサイズ (ウィンドウと同じサイズ) にします。

「SubViewport」を選んで、インスペクタを見ると サイズが「1152 x 648」となっています。これは SubViewportContainer の “Stretch” を有効にしたためで、自動で拡張されました。
それと すぐ上にある SubViewport のプレビュー表示 (オレンジの枠) に注目します。まだ描画物がなにもないので、グレーのままとなっています。

そこで SubViewport の下にたこ焼き(Tako) オブジェクトをすべて移動すると、たこ焼きが表示されます。

SubViewport のインスペクタにもたこ焼きが表示されています。

Main.gd の _save_png() を以下のように修正します。
## PNG保存処理.
func _save_png() -> void:
# ビューポートを取得.
#var vp = get_viewport()
var vp = $SubViewportContainer/SubViewport # SubViewport を取得.
# ビューポートテクスチャを取得.
var vp_tex = vp.get_texture()
# Imageを取得.
var image = vp_tex.get_image()
# PNGとして保存.(user://に保存)
image.save_png("user://screenshot2.png")
# 保存したフォルダをシェルで開く.
var path = str("file://", ProjectSettings.globalize_path("user://"))
OS.shell_open(path)
print("Save PNG.")
シーンのビューポートの代わりに SubViewport を使うようにしました。
では実行して確認しますが、背景が透過されていません…。理由として、ビューポートはデフォルトで背景をクリアカラーで消去してしまうためです。
これを修正するには SubViewport のインスペクタから、”TransparentBG” の項目をオンにします。

これで実行して確認すると、背景が透過しました。

さらに SubViewportContainer のサイズを変えると切り取り位置も変化します。

完成プロジェクト
今回作成したプロジェクトファイルを添付しておきます。