2015年9月14日月曜日

Animated GIF を StoreApp / UWP Appで再生する

(2016年3月追記)

2016年2月、Skodje さん作のコンポーネント GifImageSource  が公開されました。Windows 10 UWP / Windows 8.1 / Windows Phone 8.1 で使えるライブラリです。

この一か月ほど 画像掲示板ブラウザ F10 に組み込んで使っていますが、Windows10 Desktop・Mobile双方で問題なく動いており、また今までのComponentにあったようなWebブラウザ再生とのタイミングのずれ等も見られません。

お勧めです。

ソースはこちら。使い方もこちらに書いてあります(簡単!)。

GifImageSource
https://github.com/sskodje/GifImageSource

プロジェクトへの追加はNuGetで行います。

GifImageSource 1.0.5
https://www.nuget.org/packages/GifImageSource/


また、これは未確認のヨタ話なのですが…Windows10 Redstone1、API変更ログを見ると…Bitmap系に再生サポートっぽいMethodがいくつか生えているようです。ひょっとしたらOSで対応するの「かも」しれません。ヨタ話ですよ!!


…以下は2015年頃の話で、現状あまり意味は無い記述になってしまいました。


------


現在、ストアアプリ・UWP アプリでアニメGIFを再生するには幾つか方法があります。個人的に試してみたもの・実際に自分のアプリで使っているもの等を紹介しますよ、という記事です。

この記事のまとめ
  • WebView / WinRT Component / FFmpeg について説明します
  • 「動画の再現性」という観点ではWebViewを使う再生がベスト ただコード的なダサさは否めない
  • 他の方法は再現性に難がある・再生できないファイルがある等幾つか問題あり


※この記事はC#+XAML Appを扱います。なお、HTML/JS Appの場合は
特に何もしなくてもimgタグで再生できます(ガビーン)。


WebViewを使う


GIFファイルがWebサーバ上にあるか、それともローカルファイルかで方法が異なります。

Webサーバ上にある場合


そのGIF ファイルのURLをそのままWebViewに食わせることで再生可能です。


ローカルファイルを再生する場合


これは少々手間です。

1. GIFファイルをApplication Folderにコピー


基本的に、WebView はApplication Folderの外のローカルフォルダ・ファイルを扱うことができません。LocalFolderなりTempFolderなりに一度Copyする必要があります。
(Streamを使う方法もあるが、外のローカルファイルを直接扱っていないという点では同じ事なのでこの項では省略)

2. HTML ファイルの生成


Webサーバの場合と異なり、ローカルファイルのUri file:///ms-appdata/...hogehoge.gif にNavigateさせても再生されません。

理由を確認できていないのですが…おそらく、Webサーバから取得する場合はMIME情報がつくのでそこでアニメGIF再生になるのに対し、ローカルだとその情報が無いために失敗している気がします。

このため、再生用に「imgタグでローカルのGIFファイルを指定するHTMLファイル」を作成し、それをWebViewに食わせる必要があります。

うーn、ださい。でも再現度はピカイチで、普段Webブラウザで見ているのと同じクオリティでアニメGIFを再生できます。
拙作のアプリでは、PICT8 と futa8 でこの方法を使っています。コードはダサいですが、でも実際アプリに組み込んで使ってみると違和感はあまり無いです。






WinRT でGIFをデコードし、再生する


XamlAnimatedGif
https://www.nuget.org/packages/XamlAnimatedGif/

Animated GIF playback (XAML) sample
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlAnimatedGif


WinRT の 画像処理…Windows.Graphics.Imaging では、GIFの様な「複数フレームの画像が入っている」ファイルから画像を取り出すことが可能です。

BitmapDecoder class
https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmapdecoder.aspx

この機能を使ってGIFから複数フレームを取り出し順次表示させているのが、ここで紹介している二つのコンポーネントです(後者はサンプルコードですが、UserControlとして使うことができます。表示にWin2Dを使っている面白いサンプルですので一読をお勧めします)。

この方法、XAML UI内では上のWebView・下のFFmpegに比べると圧倒的に使いやすいです。
が、動画の再現性に難があります。
凝ったキャプもの、職人が命を削ってる系のアニメGIF再生では、意図したウェイト・タイミングで再生されない場合が多いです。

これ、気にならない人には気にならないかもしれません。が、週に何本もアニメをHDDレコーダに録画するような一般的な日本人には受け入れにくいのではとも思います。

(推測ですが、Win10 標準の「フォト」もおそらくこの系統です。アニメ再生のウェイトがブラウザと全然違う。)

ただ、もしあなたがアニメGIFの構造に詳しいのなら、上のコンポーネントはソースつきでもあるので自前でこの問題を解決することは可能かもしれません。


FFmpegを使う


かなりオーバーキル気味な方法ですが…太陽系内で再生できないファイルは無い気がする無敵の動画ライブラリ FFmpeg、実はアニメGIFにも対応しており、再生することができます。

また、2015年6月に「ストアアプリ・UWP アプリでFFmpegを使うためのライブラリ」をMicrosoft 自らがリリースして以降、「比較的(*1)」簡単にストアアプリ・UWPアプリで FFmpeg を使えるようになりました。

Using FFmpeg in Windows Applications
http://blogs.windows.com/buildingapps/2015/06/05/using-ffmpeg-in-windows-applications/


動作環境は Win10 / Win8.1 / Windows Phone 8.1, x86 / x64 / ARM  つまり最近のWinRT系全部。
対応言語は C#/C++/HTML/JS, これも全部。
ストアアプリ・UWP App、ほぼほぼ全部サポートではないかと。MS頑張った。

この方法では上のWinRT系コンポーネントのようなタイミング問題は無く、完璧にブラウザと同じ再生が可能です。
ただ…互換性に難があるようで、私の手持ちのアニメGIFで言うと半分ほどが再生できませんでした。
このため、アプリで「今」使うのはなかなか難しいかな、という所です。


*1) 「比較的」…FFmpegですので、ソースを取ってきて自分でビルドする必要があります。また、ビルドのための環境も準備する必要があります。詳しい手順は全てまとめられていますが、それでもそれなりに手間は掛かります。


FFmpeg サンプルアプリでGIFを再生している様子
再生はMediaElementに、FFmpegInteropで作ったMediaStreamSourceを渡す形
アニメGIFであっても完全に動画扱いです


Win10 UWP App で GetEncoding("shift-jis") を使う

Win10 UWP でGetEncoding("Shift-JIS")が使えない件、このblogの5月の記事でも触れていたのですが、Connectで質問していたところ「そういう仕様だから」という解答を得ました。


[Win10 UWP, VS2015RC] System.Text.Encoding.GetEncoding raise exception
https://connect.microsoft.com/VisualStudio/feedback/details/1496110/win10-uwp-vs2015rc-system-text-encoding-getencoding-raise-exception

UWP Appが依って立つ所の.NET CoreからShift-JIS等のEncodingProviderは外しちゃったので、必要な人は別途System.Text.Encoding.CodePages を追加すれ、との事です。

以下簡単な使い方です。

1. System.Text.Encoding.CodePagesのインストール


ツール → NuGet パッケージマネージャ → ソリューションのNuGet パッケージを管理 をクリックしてNuGet パッケージマネージャを開き、"System.Text.Encoding.CodePages"を検索してインストール。

NuGet コンソールから入れたい人はそちらで。

System.Text.Encoding.CodePages
https://www.nuget.org/packages/System.Text.Encoding.CodePages/



NuGet パッケージマネージャ

2. CodePagesEncodingProvider を登録



…上の二行、毎回要る訳ではなく…というか、アプリケーションのどこぞで一回呼べば済むようです。
自分の所では、App.xaml.csのコンストラクタで一発呼ぶと以降どこでも…参照してるライブラリでも…動いてるのでそうしています。
(このあたり良くわからない)

※今まではPortable.Text.Encoding のお世話になっていました。こちらでも困ることは全く無かったです。感謝。

Portable.Text.Encoding
https://www.nuget.org/packages/Portable.Text.Encoding/