Animation PNG(APNG)を作成する
前回の続きです。
APNGに必要なチャンク
必須チャンク(IHDR/IDAT/IEND)に加えて、
Chunk | 内容 |
---|---|
acTL | APNGである事を知らせる |
fcTL | フレームを知らせる |
fdAT | フレームの画像データ |
上の3つです。詳細は、Animated PNG graphicsを参照してください。
IDATとfdATの違い
IDATと違い、fdATは最初の4byteにシーケンス番号がついています。これはフレーム番号とは異なるので注意が必要です。
下のような感じになります。
chunk | フレーム番号 | シーケンス番号 |
---|---|---|
acTL(none) | (none) | |
fcTL | 0 | 0 |
IDAT | 0 | (none) |
IDAT | 0 | (none) |
IDAT | 0 | (none) |
fcTL | 1 | 1 |
fdAT | 1 | 2 |
fdAT | 1 | 3 |
fdAT | 1 | 4 |
fcTL | 2 | 5 |
fdAT | 2 | 6 |
fdAT | 2 | 7 |
fdAT | 2 | 8 |
実際のPNGファイルを除いてみるとIDATとfdATは複数に分割されていますが、これは1つのファイルをチャンクに分割しただけです。Defratorを扱う時のバッファサイズ事に出力することでメモリ消費を減らす為でしょう。
手っ取り早くアニメーションデータを持ってくる
Ank-Pixiv-Toolを使ってPixivから拾ってきます。
メタデータを一緒に取ると .zipと.jsonの2つが出てきます。
実は、.jsonファイルの中にフレームのデータが入っています。このデータが無いとタイムラインが不明になります。
jsonファイルの中身
{
"info": {
"illust": {
//省略
"path": [
{
"src": "https://i.pximg.net/img-zip-ugoira/img/xx .... xx.zip",
"frames": [
{
"f": "000000.jpg",
"d": 50
//省略
"referrer": "https://www.pixiv.net/member_illust.php?xxxxx"
}
]
}
}
info->path[0]->frames[] の下のf,dを所得すればいいわけです。
fはファイル名、dはdelay(1ms単位)です。
ただJavaには標準JSONライブラリがないので外から持ってきます。
セーブする
前回との違いはアルファチャンネル対応、APNGの出力とIDATチャンクを分割するところです。(分割サイズは64KB-12byteにしてみました。)
これは、Deflaterの使い方の違いです。前回は圧縮データがもとより大きくなるわけが無いとバッファサイズを入力サイズと同じに決め打ちしたいたものを固定バッファに切り替えてます。
Deflater encoder = new Deflater();
encoder.setInput(buffer);
encoder.finish();
int compresslength;
do {
byte[] outbuffer = new byte[buffersize];
PNGChunk data = new PNGChunk(ChunkTYPE.IDAT);
compresslength = encoder.deflate(outbuffer);
data.setBuffer(outbuffer);
data.setLength(compresslength);
if (compresslength != 0) {
list.add(data);
}
} while (compresslength != 0);
できあがった物
今回はとりあえず動かすためにファイルを決め打ちしております。