2014年4月4日金曜日

【アプリ開発】アニメーションGIF画像の再生

最近データフォルダでアニメーションGIF画像の再生に対応してアップデートしました(^O^)
Googleでも画像検索で最近Gif画像の再生に対応しましたね(^^)

データフォルダでは、以前からアニメーションGIF画像の再生には対応していましたが、
ViewPagerタイプの画像表示画面では対応していなかったため、
ImageViewを拡張したGifImageViewを作成し派生させて利用しました。


アニメーションGif画像を表示する方法は2通りあるため、
ここではその2つのGifImageViewを紹介したいと思います。

Movieクラスを使用したアニメーションGIF画像の再生
GifDecoderを使用したアニメーションGIF画像の再生



Movieクラスを使用したアニメーションGIF画像の再生

public class GifImageView extends ImageView 
{
    private Movie mMovie;

    private long mMoviestart;

    public GifImageView(Context context, InputStream stream) {
        super(context);
        
        mMovie = Movie.decodeStream(stream);        
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        super.onDraw(canvas);
        final long now = SystemClock.uptimeMillis();

        if (mMoviestart == 0) { 
            mMoviestart = now;
        }

        final int relTime = (int)((now - mMoviestart) % mMovie.duration());
        mMovie.setTime(relTime);
        mMovie.draw(canvas, 10, 10);
        this.invalidate();
    }
}

まず、ImageViewを拡張したGifImageView内に
アニメーションGIF画像再生用のMovieクラスのメンバ変数を持たせ、
GIF画像をInputStreamとして渡してMovieクラスにdecodeStreamで読み込ませて再生させます。

割りと簡単に実装ができ、Movieクラスの動作はNativeであるため、軽快に動作しますが、全てのGIF画像には対応していないため、その場合にはGifDecoderを使用して動作させると良いかと
思います。




GifDecoderを使用したアニメーションGIF画像の再生

public class GifImageView extends ImageView 
{
    private boolean mIsPlayingGif = false;

    private GifDecoder mGifDecoder;

    private Bitmap mTmpBitmap;

    final Handler mHandler = new Handler();

    final Runnable mUpdateResults = new Runnable() {
        public void run() {
            if (mTmpBitmap != null && !mTmpBitmap.isRecycled()) {
                GifDecoderView.this.setImageBitmap(mTmpBitmap);
            }
        }
    };

    public GifImageView(Context context, InputStream stream) {
        super(context);
        playGif(stream);
    }

    private void playGif(InputStream stream) {
        mGifDecoder = new GifDecoder();
        mGifDecoder.read(stream);

        mIsPlayingGif = true;

        new Thread(new Runnable() {
            public void run() {
                final int n = mGifDecoder.getFrameCount();
                final int ntimes = mGifDecoder.getLoopCount();
                int repetitionCounter = 0;
                do {
                    for (int i = 0; i < n; i++) {
                        mTmpBitmap = mGifDecoder.getFrame(i);
                        int t = mGifDecoder.getDelay(i);
                        mHandler.post(mUpdateResults);
                        try {
                            Thread.sleep(t);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    if(ntimes != 0) {
                        repetitionCounter ++;
                    }
                } while (mIsPlayingGif && (repetitionCounter <= ntimes));
            }
        }).start();
    }
    
    public void stopRendering() {
        mIsPlayingGif = true;
    }
}


GifDecoderは以下のサイトのソースを使用させてもらって利用しています。
(中身は多少いじってますが(^^;))

画像解析してGIF画像を表示しているため、おそらく大抵のGIF画像の再生が可能です。
動作は少しもっさりしますが、こちらの方が色々とカスタマイズできるかと思います。




最後に

データフォルダではこの2つを組み合わせて、
Movieクラスで再生できない場合にGifDecoderを使った再生方法を実装しています。

また、GIF画像を拡大/縮小等するために、
Movieクラスで描画しているBitmapを取得して直接描画することで処理を行うようにしていますが、
そのあたりも機会があれば紹介します(*^_^*)




0 件のコメント:

コメントを投稿