JavaでアニメーションGIF
Java SE6.0
(Mustang)がリリースされ、GIFの書き出しが標準機能で実装できるようになりました。以前からJAI
、JAI ImageIO Tools
、Gif-plugin
などの選択肢はありましたが、今後は追加パッケージ無しで実装可能になります。
GIFImageWriterの取得
GIFの書き出しはこれまでjpegやpngなどの書き出しと同様に ImageWriter を取得して行います。以下は例です(エラー処理は省略)。
1 2 3
| Iterator it = ImageIO.getImageWritersByFormatName("gif");
ImageWriter iw = it.hasNext()?
(ImageWriter)it.next() : null;
|
シーケンスの書き出し
各フレームのイメージは writeToSequence を使って書き出します。以下は例です。
1 2 3 4 5 6 7 8 9 10 11 12
| BufferedImage bi1;
BufferedImage bi2;
iw.prepareWriteSequence(null);
iw.writeToSequence(new IIOImage(bi1, null, null), null);
iw.writeToSequence(new IIOImage(bi2, null, null), null);
iw.endWriteSequence();
|
各シーケンスのディレイタイム
シーケンスのディレイタイムはイメージメタデータの GraphicControlExtension に指定する必要があります。このメタデータには他にも 前画像の消去方法(disposalMethod)などの指定が可能です。以下は指定の例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ImageWriteParam iwp = iw.getDefaultWriteParam();
IIOMetadata meta = iw.getDefaultImageMetadata(
new ImageTypeSpecifier(bi1), iwp);
String metaFormat = meta.getNativeMetadataFormatName();
IIOMetadataNode root = (IIOMetadataNode)meta.getAsTree(metaFormat);
IIOMetadataNode child = new IIOMetadataNode("GraphicControlExtension");
child.setAttribute("disposalMethod", "none");
child.setAttribute("userInputFlag", "FALSE");
child.setAttribute("transparentColorFlag", "FALSE");
child.setAttribute("transparentColorIndex", "0");
child.setAttribute("delayTime", "100");
root.appendChild(child);
meta.setFromTree(metaFormat, root);
iw.writeToSequence(new IIOImage(bi1, null, meta), iwp);
|
delayTimeは 1/100秒単位の指定になります。上記例ではdelayTimeを1秒に指定します。disposeMethodには none, doNotDispose, restoreToBackgroundColorなどが指定可能です。詳細はGIFメタデータ仕様
をご覧ください。
ループカウントの指定
デフォルトではアニメーションは1回のみ実行されます。繰り返し実行したり回数を指定する場合にも(Stream)メタデータで指定する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int loop = 3;
IIOMetadataNode child = new IIOMetadataNode(
"ApplicationExtensions");
IIOMetadataNode child2 = new IIOMetadataNode(
"ApplicationExtension");
child2.setAttribute("applicationID", "NETSCAPE");
child2.setAttribute("authenticationCode", "2.0");
byte high = (byte)((loop >> 8) & 0xff);
byte low = (byte)(loop & 0xff);
child2.setUserObject(new byte[]{ 0x1, low, high });
child.appendChild(child2);
root.appendChild(child);
|
"NETSCAPE"となっているのは繰り返し回数の指定がNetscapeによる拡張仕様であったためです。回数は setUserObject を使って指定します。1バイト目の 0x1は固定です。2-3バイトに low, highバイトの順に指定します。繰り返し回数に0を指定するとアニメーションが永久に繰り返されます。1を指定すると合計で2回実行されることになります。