Help us understand the problem. What is going on with this article?

【ゲーム用】gif画像をフレームに分解して、HTML5のcanvas上で再生してみた

More than 1 year has passed since last update.

概要

一般的にgif画像をcanvas上に貼り付けるとアニメーション機能が停止され、静止gif画像のように取り扱われます。そこで、私はgif画像をフォームから受けとり、それをフレームに分解して、HTML5のCanvas上で再生するWebアプリを作ってみました。。JavaScript上で動くゲームアプリを作るときに、gifアニメ画像をそのままゲーム素材として使えたら便利だと思います。

技術

バックエンドはJavaサーブレットを使っています。
フロントエンドは、flashの技術をJavaScriptに応用して使えると言われているadobe社のCREATEJSを使用しています。

使用するJavaのクラスのうち重要なもの

:one: org.apache.commons.fileupload.FileItem
このクラスはクライアントから受け取る multipart/form-data のPOSTリクエスト内のファイルまたはアイテムを表現したものです。利用にはApacheCommonsのjarファイルをダウンロードする必要があります。

:two: javax.imageio.stream.ImageInputStream
ImageReader で使用されるシーク可能な入力ストリームインタフェースです。InputStream や File などのさまざまな入力ソース、および将来の高速な入出力ソースを、このインタフェースの適切な実装で「ラップ」することで、イメージ入出力 API から使用可能にできます。

:three: javax.imageio.ImageReader
イメージを解析して復号化する抽象スーパークラスです。

:four: java.awt.image.BufferedImage
イメージデータのアクセス可能なバッファーを備えたImageオブジェクトを記述します。

:five: javax.imageio.metadata.IIOMetadata
イメージとストリームに関連付けられたメタデータ (イメージ以外のデータ) を表すオブジェクトにより拡張される abstract クラスです。

:six: javax.imageio.metadata.IIOMetadataNode
メタデータツリーのノードを表すクラスです。

:seven: org.w3c.dom.NodeList
順序付けられたノードのコレクションの抽象を提供します

:eight: org.w3c.dom.NamedNodeMap
名前を指定してアクセスできるノードのコレクションを表すインターフェースです。

 

手順

:one: gifファイルには、メタ情報が存在します。ファイル名、画像の高さ、幅、フレーム数、アニメ待機時間、画像データなど、画像についての情報がメタデータとして画像ファイルには付与されています。HTMLのPOSTリクエストから受け取ったgifファイルからメタデータを取得します。

//fileItem:FileItemクラスのオブジェクト
ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(readAll(fileItem)));
ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
reader.setInput(iis);
// i番目の画像データを取得する
BufferedImage bi = reader.read(i);
// i番目のフレームのメタデータを取得する
IIOMetadata meta = reader.getImageMetadata(i);

:two: メタデータツリーのノードの中から、画像記述子を探し出す。

Node tree = metadata.getAsTree("javax_imageio_gif_image_1.0");
NodeList children = tree.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
     Node nodeItem = children.item(j);
     //もし画像記述子ならば
     if (nodeItem.getNodeName().equals("ImageDescriptor")) {
     //nodeItemを使用した次の処理
     }
}

:three: 画像の位置とサイズをノードから取得して、後で、いつでも使えるようにMapに格納しておく。

//最終的にデータを格納する用のMap
Map<String, Integer> imageAttrMap = new HashMap<>();
//左位置、上位置、幅、高さを表す文字列を配列している
String[] imageAttArray = new String[] { "imageLeftPosition", "imageTopPosition", "imageWidth", "imageHeight" };
for (int k = 0; k < imageAttArray.length; k++) {
     NamedNodeMap attr = nodeItem.getAttributes();
     Node attnode = attr.getNamedItem(imageatt[k]);
     //Mapに追加
     imageAttrMap.put(imageatt[k], Integer.valueOf(attnode.getNodeValue()));
}

:four: 今まで取得した情報に基づいてイメージオブジェクトを書き出す。

BufferedImage master = new BufferedImage(imageAttr.get("imageWidth"),imageAttr.get("imageHeight"),BufferedImage.TYPE_INT_ARGB);
master.getGraphics().drawImage(bi,imageAttr.get("imageLeftPosition"),imageAttr.get("imageTopPosition"), null);

:five: イメージオブジェクトをファイルに書き出してみる。

ImageIO.write(master, "gif", new File("hoge.gif"));

ソースコード

https://github.com/fruitwater/gif-splitter

サンプルアプリ

サンプルアプリ
https://rocky-sands-26639.herokuapp.com/top

サンプルアプリを実行する際には、以下のようなサイトからgifアニメ画像をダウンロードするなどして準備してください。
http://www.civillink.net/sozai/move.html
https://studio.beatnix.co.jp/kids-it/kids-programming/scratch/free-gif-animation-site/

参考URL

以下のスタックオーバーフローの質問を参考にしています。
https://stackoverflow.com/questions/20077913/read-delay-between-frames-in-animated-gif

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした