Unity でスクリーンショットを撮る Application.CaptureScreenshot について調べてみたこと。

概要

  • Application.CaptureScreenshot でスクリーンショットが撮れる
  • filename にはパスを渡すことができる
  • 保存は非同期で行われる
  • デフォルトは端末の画面サイズになる

環境

  • Unity 5.3.1p3
  • Android 6.0.1

基本的なこと

Application.CaptureScreenshot | Unity Scripting API に書いてあること。

  • filename でスクリーンショットの保存ファイル名を指定する
  • superSize で解像度を増やすことができる
    • 縦横それぞれ n 倍になるので、画像の大きさは n^2 倍になる
    • デフォルトは 0 (・・・だと!?)
  • Web Player では使えない(なにも起こらない)
  • モバイル端末では、persistent data path 以下に保存される

以下、モバイル端末(iOS/Android)を前提とする。

調べたこと

filename にはパスを渡すことができる

Application.CaptureScreenshot("images/screenshot.png");

スクリーンショットは <アプリのデータディレクトリ>/images/screenshot.png に保存される。

このとき、images ディレクトリが無いとスクリーンショットを保存できない。 なお、その場合 Exception が投げられることはなく、コンソールに Failed to store screen shot というログが出るだけ。

System.IO を使ってディレクトリを作っておく。

Directory.CreateDirectory(Path.Combine(Application.persistentDataPath, "images"));
Application.CaptureScreenshot("images/screenshot.png");

保存は非同期で行われる

保存には 1 フレーム以上の時間がかかる。何フレームかかるかは、端末の性能に依る。

IEnumerator CaptureScreenshot(string fileName)
{
    Application.CaptureScreenshot(fileName);

    // ここでは、まだ保存できていない

    yield return null;

    // ここなら、性能が良い端末なら保存できているかも
}

撮ったスクリーンショットを SNS に投稿したい場合などは、System.IO.File.Exists でファイルが存在することを確認する必要があるだろう。

雑に書くと以下の様な感じ。

IEnumerator CaptureScreenshot(string fileName)
{
    Application.CaptureScreenshot(fileName);

    var filePath = Path.Combine(Application.persistentDataPath, fileName);
    while (!File.Exists(fullPath))
    {
        yield return null;
    }

    // 保存できている
}

ちゃんと書くとしたら、少なくとも以下の点ぐらいはなんとかしておきたい。

  • Application.CaptureScreenshot する前に、既に同名のファイルが存在する場合に対応する
  • 保存にタイムアウトを設ける(無限ループさせないようにする)

デフォルトは端末の画面サイズになる

superSize = 0 では、端末の画面サイズのスクリーンショットが撮られる。

1 以下の値を指定しても、同様の結果になる。

まとめ・感想

  • filename にはパスを渡せば、persistentDataPath 内の好きなディレクトリに保存できる
  • 保存は非同期で行われるので、System.IO.File.Exists などで保存できたことをチェックする
  • デフォルトは端末の画面サイズになり、superSize に 1 以下の値を設定しても同様の結果になる

手軽にスクリーンショットを撮ることができるが、保存が非同期で行われるのにコールバックの仕組みが無いので、 撮ったスクリーンショットをどうこうしたい場合はちょっと面倒だと思う。 多分 Camera から texture が取得できると思う(要出典)ので、そちらを使うほうが良さそう。

一方で、自動テストの際に、画面見たまんまを撮影するのには便利そう。

追記

ちゃんと書くとしたら、少なくとも以下の点ぐらいはなんとかしておきたい。

  • Application.CaptureScreenshot する前に、既に同名のファイルが存在する場合に対応する
  • 保存にタイムアウトを設ける(無限ループさせないようにする)

というのを Unity で独自のコルーチンを定義する | KAKELOG でやってみた。