タイトル: HighResShotで保存した画像のファイル名を取得する方法
SEOタイトル: UE5でHighResShotの保存画像のファイル名を取得する方法
Unreal Engine 5(UE5)のHighResShotは撮影後に画像パスを戻り値として返さないため、ファイル名を確実に知る最も実用的な方法は「撮影前に自分でファイル名(パス)を指定して既知の値にしておく」ことです。デフォルトの連番/日時ファイル名のまま後から名前を特定するのは難しいので、保存先と名前をあらかじめ決め打ちし、必要ならOn Screenshot Capturedデリゲートで保存完了のタイミングを受け取る、という流れが基本になります。本記事では、その考え方と具体的な実装パターン、つまずきやすい点を整理します。
| この記事の要点 |
|---|
|
前提:HighResShotはどこに、どんな名前で保存されるか
UE5でコンソールコマンド HighResShot を実行すると、現在のビューを高解像度でキャプチャし、画像ファイルとして書き出します。ファイル名を指定しなかった場合、保存先はプロジェクトの Saved/Screenshots/ 配下で、さらにプラットフォームごとのサブフォルダ(Windowsエディタなら Windows)に分かれるのが標準的な挙動です。例えば次のようなパスになります。
<ProjectDir>/Saved/Screenshots/Windows/HighResShot_00000.png <ProjectDir>/Saved/Screenshots/Windows/HighResShot_00001.png |
ファイル名の末尾は 00000 から始まる連番で、撮影のたびに同じフォルダ内の既存ファイルを避けて番号が増えていくのが基本動作です(バージョンや設定によって命名規則が異なる場合があります)。この「連番が自動で決まる」仕様が、まさに「後からどのファイルが今撮った画像なのか分かりにくい」という問題の原因になります。連番の最大値を毎回スキャンして突き止めることも理論上は可能ですが、複数の保存処理が絡むと取りこぼしやすく、堅牢な方法とは言えません。
基本方針:ファイル名を「取得する」より「先に決める」
HighResShot コマンド自体は、保存したファイルのパスやファイル名を呼び出し側に返しません。したがって考え方としては、次の3つのアプローチに整理できます。優先度の高い順に並べると次のとおりです。
| アプローチ | 概要 | 向いている場面 |
|---|---|---|
| ① 撮影前に名前を指定 | コマンドに filename=... を渡し、保存先とファイル名を自分で決める。結果としてパスは「最初から既知」。 | 撮ったファイルを確実に後続処理(アップロード・表示等)へ渡したいとき。 |
| ② デリゲートで完了を受ける | On Screenshot Captured で保存処理の完了タイミングを受け取り、①で決めたパスとひも付ける。 | 保存が終わってからファイルを開く・読み込むなど、タイミング制御が要るとき。 |
| ③ 保存ディレクトリを列挙 | 保存先フォルダ内のファイルを列挙し、最新(最も新しい更新日時)を選ぶ。 | デフォルト連番のまま運用していて、後追いで特定したいとき(補助的)。 |
このうち実務でまず採るべきは①です。名前を自分で決めてしまえば「取得」という問題そのものが消えるためです。②は①と組み合わせて「いつ取りに行ってよいか」を知るために使い、③はデフォルト運用を変えられない場合の次善策と位置づけるのが安全です。
① Take High Res Screenshot/コマンドでファイル名を指定する
Blueprintでは Execute Console Command ノードに HighResShot 文字列を渡して実行します。HighResShot は解像度倍率や撮影範囲のほか、ファイル名を指定するパラメータを受け付けます。代表的な書式は次のとおりです(パラメータ構成はバージョンで差があり得ます)。
HighResShot filename="C:/Caps/MyShot_001.png" 3840x2160 // あるいは倍率指定: HighResShot filename="C:/Caps/MyShot_001.png" 2 |
ポイントは、filename= に渡したパスがそのまま保存先になるため、コマンドを実行する前の時点で「保存される完全パス」が分かっているということです。つまりBlueprint側で同じ文字列を変数に保持しておけば、それがそのまま「取得したファイル名」になります。撮影ごとに名前が衝突しないよう、変数を組み立てる段階で連番やタイムスタンプ(年月日・時分秒)を自分で付与しておくのが定石です。
// 疑似手順(Blueprint) FileName = "MyShot_" + 現在日時を"yyyyMMdd_HHmmss"形式で文字列化 + ".png" FullPath = <保存先ディレクトリ> + FileName Command = "HighResShot filename=\"" + FullPath + "\" 3840x2160" Execute Console Command(Command) // ← この時点でFullPathは既知 |
なお、ファイル名にスペースや日本語、相対パスが混ざると意図したパスに保存されないことがあります。原則として絶対パス・ASCII中心の名前にし、ディレクトリは事前に存在を確認しておくと安定します。デフォルトの日時命名を使いたいだけであれば、bDateTimeAsFilename 系のオプションが利用できる場合もありますが、その場合は「名前が自動で決まる=事前に確定しない」ため、後述の②や③とセットで考える必要があります。
② On Screenshot Captured で保存完了を受け取る
HighResShot による書き出しは即時に完了するとは限らず、内部的には非同期で進みます。「撮った直後にファイルを開こうとしたら、まだ存在しない/書き込み途中だった」という不具合はここに起因します。そこで、保存処理の完了通知を受け取るために On Screenshot Captured デリゲートを使います。
C++では UGameViewportClient::OnScreenshotCaptured() にコールバックをバインドします。コールバックが受け取る引数は 幅(Width)・高さ(Height)・ピクセル配列(TArray<FColor>)であり、保存先のパス文字列そのものは渡ってこない点に注意してください。つまりこのデリゲートは「いつ・どんなサイズで撮れたか」を知る手段であって、「どこに保存されたか」を教えてくれるものではありません。パスは①で自分が指定した値を保持しておき、デリゲート発火時にそれとひも付けて扱うのが正攻法です。
// C++ イメージ FString SavedPath = TEXT("C:/Caps/MyShot_001.png"); // 自分で保持 ViewportClient->OnScreenshotCaptured().AddLambda( [SavedPath](int32 W, int32 H, const TArray<FColor>& Bitmap){ // ここで SavedPath が「取得したファイル名」として使える }); |
関連して、C++から能動的に撮影を依頼する場合は FScreenshotRequest::RequestScreenshot(Filename, ...) を使う方法があり、リクエストしたファイル名は FScreenshotRequest::GetFilename() で参照できます。これも結局「自分が渡した名前を引き出す」仕組みであり、コマンドからの自動命名を逆算するものではない点は同じです。Blueprintのみで完結させたい場合は、デリゲート相当のイベントが用意されていないバージョンもあるため、①でパスを固定したうえで、保存完了の判定はファイルの存在確認やわずかな遅延フレームで代替する設計が現実的です。
保存ディレクトリの取得(Project Saved Dir など)
保存先を Saved/ 配下に揃えたい場合は、ハードコードせずにプロジェクトの保存ディレクトリを取得して組み立てます。Blueprintには Get Project Saved Dir 系のノードがあり、C++では FPaths::ProjectSavedDir() が対応します。返るのはプロジェクトの Saved/ までのパスなので、その後ろに Screenshots/ やプラットフォーム名、独自フォルダ名を連結してフルパスを作ります。
// C++ イメージ FString Dir = FPaths::ProjectSavedDir() / TEXT("Screenshots/MyCaps/"); FString Full = Dir + TEXT("MyShot_001.png"); IFileManager::Get().MakeDirectory(*Dir, true); // 事前にフォルダ作成 |
デフォルトのままデフォルトフォルダを後追いで列挙したい場合(アプローチ③)は、この保存ディレクトリ内のファイル一覧を取得し、更新日時が最も新しいものを「直近の1枚」とみなします。ただし、複数同時保存やパッケージ製品での書き込み先の違いがあると誤認しやすいため、あくまで補助的手段にとどめ、確実性が必要なら①へ寄せてください。
落とし穴
| 注意点 | 内容と対策 |
|---|---|
| 連番/上書き | デフォルトの連番は既存ファイルを避けて増えるが、filename= で固定名を指定すると同名ファイルを上書きしやすい。連番やタイムスタンプを自分で付けて衝突を防ぐ。 |
| 非同期保存のタイミング | コマンド実行直後はまだ書き込みが終わっていないことがある。撮った直後に開くのではなく、On Screenshot Captured やファイル存在確認、数フレーム待機で完了を待つ。 |
| デリゲートにパスが来ない | On Screenshot Captured の引数は幅・高さ・ピクセル配列のみ。保存パスは自分で保持して関連付ける必要がある。 |
| プラットフォーム差・書き込み先 | デフォルト保存先のプラットフォーム名サブフォルダや、エディタとパッケージ版での書き込み可能ディレクトリの違いに注意。相対パスや権限の制約も確認する。 |
| パス文字列の扱い | スペース・日本語・相対パス混在で意図しない場所に保存されることがある。絶対パスを基本とし、ディレクトリの事前作成と存在確認を行う。 |
よくある質問(FAQ)
Q1. HighResShotで撮ったファイル名を、コマンドの戻り値として直接取得できますか?
できません。HighResShot はパスやファイル名を呼び出し側へ返さない仕様です。確実に名前を知りたい場合は、コマンドに filename=... を渡してあらかじめ名前を決め、その文字列を自分で保持してください。それが事実上の「取得」になります。
Q2. デフォルトの連番ファイル名のまま、後から「今撮った1枚」を特定したいです。
保存先フォルダ(既定では Saved/Screenshots/<プラットフォーム>/)を列挙し、更新日時が最新のファイルを選ぶ方法があります。ただし非同期保存や複数同時保存があると誤判定しやすいため、可能なら撮影前に名前を指定する方式へ切り替えるのが確実です。
Q3. 撮影直後にファイルを読み込もうとすると、まだ存在しない/途中までしか書けていないことがあります。
保存が非同期で進むためです。On Screenshot Captured デリゲートで完了通知を受けてから読み込む、あるいはファイルの存在確認や数フレームの待機を挟むことで回避できます。
Q4. 各パラメータやデフォルトの命名規則は、自分のバージョンでも同じですか?
保存先や連番の付き方、利用できるオプションはエンジンのバージョンや設定で異なることがあります。重要な挙動は、お使いのUE5バージョンの公式ドキュメントや実機での書き出し結果で確認することをおすすめします。