AndroidでGif動画をこのように扱いたい
- GIF動画をフレームに分割
- それぞれを画像として保存する
ここでのGIFとはアニメGIFのことです。
アニメGIFはパラパラ漫画のコマとして分割し、
その各フレームをPNG画像として保存したかったです。
その方法がようやくわかったので、
AndroidでGIFを画像保存するKotlinコード例を紹介!
このページの目次
1.GifDrawableというライブラリを導入する
Android標準でGIFを扱えるAPIはありません。
だから優秀な外部ライブラリに頼ることにします。
その名も android-gif-drawable というライブラリ
次のGitHubページで公開されています。
▼ Github : koral--/android-gif-drawable
▼ Android Studio : build.gradleに以下を追加
1 2 |
/// Gif drawable implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.24' |
最新バージョンは1.2.24の模様。
ライセンスもMITライセンスだから安心です。
2.GIF動画を外部ピッカーから選択してもらう
ここから具体的なコード部分です。
まずGIF動画をアプリ側で選択させる処理を書きます。
▼ ちょうどこのようなコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
val openVideoLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK && result.data != null) { val uri: Uri? = result.data?.data /// GIFをフレーム毎に画像保存する処理 /// 後述するのでスルーしてOK splitGifToImages(uri) } } val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) intent.type = "image/gif" val title = "Select animated GIF" val chooser = Intent.createChooser(intent, title) openVideoLauncher.launch(chooser) |
ここでは ACTION_OPEN_DOCUMENT を使ってます。
▼ ACTION_OPEN_DOCUMENTの扱いについて
そしてIntentから外部のファイルピッカーを起動し、その結果を registerForActivityResult() からURIとして取得しています。
もちろん Activity#onActivityForResult() を実装してもいいのですが、Kotlinでは registerForActivityResult() を使って結果を受け取るのがベストな方法みたいです。
3.GIF動画を分割して全フレームを画像保存
最後にGIF動画を分割します。
そして全フレームをPNG画像で保存してみます。
▼ そのために定義したメソッドコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
private fun splitGifToImages(uri: Uri?){ /// GIF動画URIをGifDrawableに変換 val gif = GifDrawable(contentResolver, uri!!) /// GIF動画の最終フレームインデックス取得 val lastFrameIndex = gif.numberOfFrames-1 /// ひたすら各フレームを画像保存していく for(i in 0..lastFrameIndex){ val thread = Thread { /// i番目のフレームをBitmapで取得 val bitmap = gif.seekToFrameAndGet(i) /// アプリの外部ディレクトリに保存 val f = File( getExternalFilesDir( Environment.DIRECTORY_MOVIES ), "frame${i}.png" ) if (!f.exists()) f.createNewFile() /// 実際にファイルに画像データを書き込み val byteArrayOutputStream = ByteArrayOutputStream() bitmap!!.compress(Bitmap.CompressFormat.PNG, 50, byteArrayOutputStream) val byteArray: ByteArray = byteArrayOutputStream.toByteArray() f.writeBytes(byteArray) } thread.start() } } |
何をしているかはコメント参照。
先ほど導入したGifDrawableを使ってURIからGifDrawableに変換、そのあと1枚1枚のフレームをPNG画像として保存しているだけです。
4.実際にGIF動画をフレーム分割保存してみた
ひとまず適当なGIF動画を用意してみました。
▼ URL : http://tsukikoya.com/sample-gif-image/
これを先ほどのコードでフレーム分割。
各フレームをPNG画像として保存を試しました。
▼ 問題なくフレーム分割&保存ができた!
▼ 当環境では次のディレクトリに保存された
1 |
/storage/emulated/0/Android/data/[アプリパッケージ名]/files/Movies/frame0.png |
保存先はアプリの外部ディレクトリです。
しっかり全フレーム漏らさず画像保存できてました。