React Native (expo) + Open GL で遊んでいると描画したものを保存したくなる。
需要ありそうな気がするんだけど全然情報がないので手探りでやってみます。
とりあえずAPIドキュメントを読むとSurface.capture()があります。
captureAsDataURL()
やcaptureAsBlob()
を使えれば嬉しいけど<canvas/>
のWeb APIを使っているためReact Nativeでは(そのままでは)使えない。
capture()
はNDArray
を返すため適当なフォーマットに落とし込むことは容易そうだけど自分で作るより探した方がよさそう。
gl-reactのissueでキャプチャした画像をファイルに保存したいという内容があった。
色々有益な内容がありますが結論としてSurface.glView.capture()
が非同期で画像を保存して、{width, height, uri, localUri}
を返してくれます。
jpeg形式で保存されているので、後は以前やったようにカメラロールやメディアライブラリに保存するだけです。
透過画像としてpngで保存するにはどうするか。
APIにはglView
すら載っていないのでソースの方を探そうと思いましたが対象箇所がわかりにくいので探す手順から書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
//SurfaceのRefから対象の関数を見てみる console.log(this.sRef.glView.capture); //[Function anonymous] console.log(this.sRef.glView.capture.toString()); /* function (opt) { var _assertThisInitialize = _assertThisInitialized(_this), ref = _assertThisInitialize.ref; if (!ref) return Promise.reject(new Error("glView is unmounted")); return ref.takeSnapshotAsync(opt); } */ |
関数内の変数なんかでGitHubから検索してみるとここのようです。
takeSnapshotAsync()
の定義場所は見つからなかったんですが、どっかで見たことあるなと思ったら以前同名の関数を使ってますね。
さらにこのとき使ったreact-native-view-shot
とgl-react
の製作者同じなのか。
expoでの関数は使えませんでしたが今回は動作確認もできてます。
expoのドキュメントを参考にして{ format: "png" }
を引数にしたところ、ちゃんと透過画像として保存できました。
ソースで重点をまとめるとこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 |
<Surface ... ref={r => { this.sRef = r; }} >...</Surface> onSave= async () => { let f = await this.sRef.glView.capture({ format: "png" }); someSaveFunc(f.uri); } |
こうしてみると簡単だけどここにたどり着くのは結構時間かかった。