TypeScript で Alembic を読み込んでみる.
普段は C++ で仕事プログラムをしているのですが、Private の時間で JavaScript の勉強をし始めて数日. Alembic 自体の調査を兼ねて、JavaScript で読み込む処理を書いてみる. JavaScript 自体は素人なので、いろいろ時間がかかりながらも、鋭意実装中.
方針と現状
普通に JavaScript で書いてもいいけど、折角なので JavaScript を生成する別の言語を使ってみようという事でいくつか調査. CoffeeScript よりも C++ に記述が近い事から TypeScript で書くことに.
Unit Test は Jasmine+Karma+PhantomJS を使って構築. いろいろあったけど、今は元気に動いています.
Alembic
情報元
Alembic の調査. 下記が Alembic フォーマットのポータルっぽい.
http://www.alembic.io/
ここの Download リンクから飛んだ先にある GoogleCode のページから ZIP に固められた Alembic を扱う Library のソースコードなどが入手可能.
https://code.google.com/p/alembic/
ただ、GoogleCode なので ReadOnly になっていたりして大層不安. さらに検索してみたら、GitHub にもページがあり、現在のメインはこっちっぽい. ここからソースコードを取得して調査している.
https://github.com/alembic
データ
サンプルデータは、GoogleCode にあった Alembic_Octopus_Example を利用.
そのほかに、去年あたり Perfume の Event で提供していたファイルもとってきて参考にしている. 現在も取得可能で、下記の #003 から取得可能.
http://www.perfume-global.com/
データ確認用のツール
今回は Private での制作という事で、Non-Commercial 版の Houdini を利用.
http://www.sidefx.jp/index.php?option=com_content&view=article&id=1&Itemid=435
Non-Commercial 版では、Alembic の Export はできないものの Import はでき、上記の取得してきたデータは確認できた.
GitHub で提供されているコードの中にも AbcView という Viewer のコードがついており、build する事で使えそうだったんだけど、いろいろ依存しているものが多く Library や build 用のツールをインストールする必要があり、あまり Private の環境を汚したくなかったので今回は見送り. そもそも、現状では Windows support is experimental となっていたし…. こっちの方が、データの中身をいろいろ見れそうだったんだけど.
ファイルフォーマット
現状、CoreType として 2 つ定義されている.それぞれの CoreType には全く互換性はないようで、提供されている Library 内でもかなり上位のレベルで実装が分かれている.
HDF5
下記で定義されているフォーマットをベースとするファイルフォーマット.
https://www.hdfgroup.org/HDF5/
HDF5 としての Attribute として、Alembic としての定義がある. 上記で示したデータは、どれもこの CoreType だった.
Ogawa
HDF5 に比べていろいろ改善されている新しいファイルフォーマット. HDF5 などの外部のフォーマットを用いず、独自のフォーマットになっている. GitHub 内に HDF5 と同等の機能を提供していると思われるソースが lib/Alembic/Ogawa の中に入っている.
TypeScript での実装と発生した問題
2015/10/21 追記
最終的に対応した方法を下記に記載しました.
参考リンク
2015/10/18 追記
下記の問題は解決しました.
参考リンク
まずは用意できたサンプルデータが HDF5 だったので、この CoreType のファイルフォーマットの読み込み処理から実装していく. HDF5 のファイルフォーマットは、下記に詳しく書かれてる.
https://www.hdfgroup.org/HDF5/doc/H5.format.html
…が、ヘッダの読み込みで早速躓く…
最初の Format Signature が一致しない. いろいろ Debug してみたところ、XMLHttpRequest で読み込んだ時点で、ファイルの先頭部分が化けてしまっている. 読み込み処理は下記の通り.
beforeAll(function (done) {
request.open('GET', filename, true);
request.responseType = 'arraybuffer';
request.addEventListener('loadend', function () {
done();
});
request.overrideMimeType('application/octet-stream');
request.send();
})
内容の表示に利用しているのは、下記のコード.
var buffer = <ArrayBuffer>request.response;
console.log(new Uint8Array(buffer, 0, 8));
上記のドキュメントにもある通り、下記の様な 8 bytes が並んでいる事を期待している.
[0x89, 0x48, 0x44, 0x46, 0x0d, 0x0a, 0x1a, 0x0a]
実際、バイナリエディタでサンプルデータの先頭部分を見てみると、期待しているデータ通りの 8 bytes が並んでいる事が確認できる. でも、読み込むと先頭部分がおかしい.いろいろ調べた結果、最初の 1 byte の内容(もしくは、先頭の 1 bit ?)の状況によって、変なデータが挿入されてしまう事が分かった.
試しに、Alembic_Octopus_Example の Alembic ファイルをバイナリエディタで開き、先頭の 1 byte を 0x7F に書き換え、下記のコードで表示してみると期待通りの結果が得られた.
LOG: Object{0: 127, 1: 72, 2: 68, 3: 70, 4: 13, 5: 10, 6: 26, 7: 10, length: 8, byteOffset: 0, buffer: Object{byteLength: 68364627}, byteLength: 8}
対して、先頭の 1 byte を 0x80 に書き換えた時の出力は下記になった
LOG: Object{0: 239, 1: 191, 2: 189, 3: 72, 4: 68, 5: 70, 6: 13, 7: 10, length: 8, byteOffset: 0, buffer: Object{byteLength: 68364629}, byteLength: 8}
比較すると、正しく読めている時の 2 byte 目以降と、化けてしまった時の 4 byte 目以降は一致している. つまり、0x80 が 3 byte のデータに書き換わっている. これは、Karma が起動させる Browser を Chrome に変えても一緒だった.
とりあえず、4 byte 目以降は一致しているという事なので、1 byte 目を無視して、4 byte 目以降と Signature を比較してみたら一致した. が、とても気持ち悪い. 2 進数データと定義しているから、最初の bit がたっている事がトリガーかなと思うけど、ただ、データが変わるのはそういうものなの?誰も困ってないの?? 情報もとむ !!
という訳で…
つづく。
追記 (2015/10/17)
上記の、XMLHttpRequest で Binary Data を読み込んだ場合、先頭の値によって内容が化けてしまう症状を再現したコードを、下記にあげてみた. 情報もとむ !!
っていうか、全部の Browser で失敗しているって事は、原因は Karma の Web-Server の方 ?