Unityで画像をS3にアップロードしてQRコードを生成する

はじめに

ARアプリで撮影した写真をAmazon S3にアップロードして画像のURLをQRコード表示するサンプルを作ってみた。
展示会などでARアプリを体験してくれた人達に記念撮影した写真のデータを渡せるような仕組みが欲しいと思ったので作った。

github.com f:id:sotanmochi-tech:20191122092334p:plain f:id:sotanmochi-tech:20191122092327p:plain

主な実装

それぞれの実装方法は調べれば情報が出てくるけど、「スクリーンショット取得 ⇒ S3に画像アップロード ⇒ URLのQRコードを生成」という一覧の流れがまとまってるものは見つからなかった。

スクリーンショットを取得する

PhotoUploadPresenter.cs の一部抜粋

        private void TakePhoto()
        {
            StartCoroutine(TakePhotoCoroutine());
        }

        IEnumerator TakePhotoCoroutine()
        {
            _IsPreview = true;

            yield return new WaitForEndOfFrame();

            // Read pixels from screen(currently active RenderTexture) into the saved texture data.
            Texture2D preview = new Texture2D(Screen.width, Screen.height, TextureFormat.ARGB32, false, false);
            preview.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
            preview.Apply();

            _PhotoPreview.texture = preview;
            _PhotoPreviewUIRoot.SetActive(true);
        }

S3に画像データをアップロードする

PhotoUploadPresenter.cs の一部抜粋
以下のコードの「_StorageClient」は S3Storage.csインスタンス

        private async void OnClickSaveImage()
        {
            Texture2D tex2d = _PhotoPreview.texture as Texture2D;
            byte[] pngData = tex2d.EncodeToPNG();
            MemoryStream memoryStream = new MemoryStream(pngData);

            string dateTimeStr = DateTime.Now.ToString("yyyyMMddHHmmss");
            string filename = "Photo_" + dateTimeStr + ".png";

            var response = await _StorageClient.PubObjectAsync(_BucketName, filename, memoryStream, S3CannedACL.PublicRead);
            
            Debug.Log("Response: " + response.HttpStatusCode);
            if (response.HttpStatusCode == HttpStatusCode.OK)
            {
                string url = _StorageClient.GetPublicUrl(_BucketName, filename);
                _Qrcode.texture = QRCodeGenerator.GenerateQRCodeTexture(url, 256, 256);

                _PhotoPreviewUIRoot.SetActive(false);
                _QRCodeUIRoot.SetActive(true);
            }
            else
            {
                Debug.LogError("Response: " + response.HttpStatusCode);
            }
        }

QRコードを生成する

QRCodeGenerator.cs

using UnityEngine;
using ZXing;
using ZXing.QrCode;

namespace PhotoUploader
{
    public class QRCodeGenerator
    {
        public static Texture2D GenerateQRCodeTexture(string text, int width, int height)
        {
            Texture2D qrTex = new Texture2D(width, height);

            Color32[] pixels = Encode(text, width, height);
            qrTex.SetPixels32(pixels);
            qrTex.Apply();

            return qrTex;
        }

        public static Color32[] Encode(string text, int width, int height)
        {
            var writer = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options = new QrCodeEncodingOptions
                {
                    Height = height,
                    Width = width
                }
            };
            return writer.Write(text);
        }
    }    
}

サンプルを動かすまでの流れ

AWSの準備

  • S3のバケット作成
  • CognitoのIDプール作成
  • IAMのポリシー作成・設定

Unityプロジェクトの準備

Unityアプリの実行

  • UnityEditorで実行 or ビルドしてAndroid/iOS端末で実行

注意点

ポリシー作成・設定

  • 画像アップロード先のバケットに対して、オブジェクトをアップロードする操作(PubObject)とアクセス権を設定する操作(PutObjectACL)を許可するポリシーが必要

サンプル f:id:sotanmochi-tech:20191122064828p:plain

iOS向けのビルド

サンプルを動かすまでの流れ(詳細)

AWSの準備

S3のバケット作成

f:id:sotanmochi-tech:20191122070534p:plain

公開可能な設定にしておく f:id:sotanmochi-tech:20191122070549p:plain f:id:sotanmochi-tech:20191122070701p:plain

CognitoのIDプール作成

認証されていないIDにチェックを入れる
⇒ ユーザーIDとパスワードによる認証をしなくてもUnityアプリからS3を操作できるようにするため f:id:sotanmochi-tech:20191122070749p:plain

デフォルトだとロールを新規作成するので、そのままでOK f:id:sotanmochi-tech:20191122071043p:plain

IAMのポリシー作成・設定

CognitoのIDプール作成時に新しく作られたロールに対して、S3を操作するためのポリシーを作成してアタッチする

ポリシーの新規作成 f:id:sotanmochi-tech:20191122075101p:plain f:id:sotanmochi-tech:20191122075121p:plain f:id:sotanmochi-tech:20191122075137p:plain f:id:sotanmochi-tech:20191122075147p:plain

画像アップロード先のバケットに対して、オブジェクトをアップロードする操作(PubObject)とアクセス権を設定する操作(PutObjectACL)を許可するポリシーが必要なので、最終的には以下のようになった。 f:id:sotanmochi-tech:20191122075244p:plain

CognitoのIDプール作成時に新しく作られたロールにアタッチする f:id:sotanmochi-tech:20191122071223p:plain

Unityプロジェクトの準備

AWSConfigs作成

AWSConfigsというScriptableObjectで設定値を管理するようにしている。 f:id:sotanmochi-tech:20191122080035p:plain

リージョン名・IDプールのIDを設定する f:id:sotanmochi-tech:20191122080443p:plain

AWSConfigsとバケット名の設定

作成したAWSConfigsをセットする。対象のバケット名も指定する。 f:id:sotanmochi-tech:20191122080523p:plain

Unityアプリの実行

  • UnityEditorで実行 or ビルドしてAndroid/iOS端末で実行
  • 画面をマウスクリック or タッチするとスクリーンショットを取得してプレビュー画面になる

おわりに

展示会などでARアプリを体験してくれた人達に記念撮影した写真のデータを渡せるような仕組みが欲しいと思って作ったので、今後色々と活用していきたい。