はじめに
今回はmgGif
というライブラリを紹介したいと思います。
A unity library to parse a GIF file and extracts the images, just for fun
// DeepL翻訳
GIF ファイルを解析し、画像を抽出するための Unity ライブラリです。
また今回実験として利用させていただいたGif
画像は以下から借りてきたものです。
http://katus-gifani.sakura.ne.jp/sozai01.html
使い方
最初に言っておくと、この使い方がよく分からなくても後述のAnimatedTexture.cs
もしくはAnimatedImage.cs
のコードをコピペすれば大丈夫ではあります。
private void Start() { // Assets/StreamingAssets以下の相対パスを指定し、gifのデータを読み込む // 以下のコードだと、「Assets/StreamingAssets/sample.gif」 byte[] data = File.ReadAllBytes(Path.Combine(Application.streamingAssetsPath, "sample.gif")); // dataからRGBのデータと間隔を抜き出す // NOTE : unsafeを有効にしている場合はDispose必須、有効にしていない場合(デフォルト)ではしなくても大丈夫ではある using( var decoder = new MG.GIF.Decoder( data ) ) { // 次の画像の情報を抜き出す var img = decoder.NextImage(); while( img != null ) { // 画像データ Texture2D tex = img.CreateTexture(); // 間隔 int delay = img.Delay; // 次の画像の情報を抜き出す img = decoder.NextImage(); } } }
コンポーネントとして利用できるようにする
公式のサンプルとしてAnimatedTexture.cs
があるので、まずはこれを使ってみます。
github.com
Quad
にAnimatedTexture.cs
をアタッチするとgif
表示することができます。
またFileName
はAssets/StreamingAssets
以下からの相対パスを記載してください。
Imageに適応する
ただImage
にGif
を貼り付けたい場面の方が多いかなと個人的には思うので、コードを書いてみました。
using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.UI; [RequireComponent(typeof(Image))] public class AnimatedImage : MonoBehaviour { [SerializeField, Header("Relative path from StreamingAssets folder")] private string filePath; private Image _image; private readonly List<Sprite> _frames = new List<Sprite>(); private readonly List<float> _frameDelay = new List<float>(); private int _currentFrame = 0; private float _time = 0.0f; private void Start() { if (string.IsNullOrWhiteSpace(filePath)) return; _image = GetComponent<Image>(); var path = Path.Combine(Application.streamingAssetsPath, filePath); using( var decoder = new MG.GIF.Decoder( File.ReadAllBytes( path ))) { var img = decoder.NextImage(); while( img != null ) { _frames.Add( Texture2DtoSprite(img.CreateTexture())); _frameDelay.Add(img.Delay/1000.0f); img = decoder.NextImage(); } } _image.sprite = _frames[0]; } private void Update() { if (_frames == null) return; _time += Time.deltaTime; if( _time >= _frameDelay[ _currentFrame ] ) { _currentFrame = ( _currentFrame + 1 ) % _frames.Count; _time = 0.0f; _image.sprite = _frames[_currentFrame]; } } private static Sprite Texture2DtoSprite(Texture2D tex) => Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero); }
パフォーマンスアップ
mgGif
の冒頭にある#define mgGIF_UNSAFE
のコメントアウト削除し、プロジェクトでunsafe
を利用できるようにすると(ProjectSettings/Player/OtherSettings/ScriptCompilation/Allow 'unsafe' Code
を有効化 or .asmdef
のAllow unsafe Code
の有効化)、マネージドヒープを利用しないようになりGC.Alloc
を削減することができるようです。
#define mgGIF_UNSAFE
またパフォーマンス(処理速度?)自体も上がるっぽい?
For an additional performance improvement, uncomment mgGIF_UNSAFE at the top of the file and allow unsafe code compilation in the assembly.
https://github.com/gwaredd/mgGif
ただしDispose
をし忘れるとメモリリークを起こすので要注意です。
var path = Path.Combine( Application.streamingAssetsPath, "sample.gif" ); var decoder = new MG.GIF.Decoder(File.ReadAllBytes(path)); // ---色々利用--- // 利用し終わったらDisposeを必ず呼ぶ decoder.Dispose();