Reading binary by JavaScript

  • はなだ のぶかず (@nobkz)
  • Lisp/Rust/Haskell/Scala/Erlang/OCaml/Prolog
  • (株)Groovenauts Rockstar Engineer
  • Tech parkで子どもむけの言語やツールを開発している
  • pubgにハマル
  • ボドゲ

ネタについて

  • ネタ候補
    • jsのSPAの変遷および設計論
    • ジェスチャーの実装
    • WebGLでのGPGPU
    • Web Workerについて
    • CSSについて
    • Firefoxの実装について
    • ....
  • Liteな感じ
  • だけど、実は案外知らないかも...?
  • 知ってたらごめんね

アジェンダ

  • なぜ、JSでバイナリを書くのか?
  • バイナリ基礎
  • JSでのバイナリの取扱
  • (例)STLを読む
  • まとめ

なぜJSでバイナリを書くのか?

JSでバイナリ?

  • JSでDOM操作や通信はわりとメイン?
  • 画像、音声や動画、とかとりあえず、ブラウザに任せる?
  • 通信も大体テキストをパースする感じかもね
  • てか、大体テキストでやる
  • 馴染がないよね?
  • なんか難しいイメージがある?

JSバイナリを扱うとき

  • 画像の編集や、圧縮など
  • 3Dのバイナリデータの読み込み
  • 音声ファイルのメタデータを取得
  • 動画のエンコードやデコード
  • バイナリデータの送受信

大半はライブラリがある

  • JavaScriptはそれだけコミュニティがでかい
  • まず、最初にライブラリを探しましょう。
    • JSのスキルは大半はライブラリ検索技術かもしれない...
  • それでもバイナリのプログラミングが必要なときがある
    • 3Dデータの保存
    • 独自データ形式を利用する
    • ライブラリがクソ過ぎワロタ
    • そもそも欲しいライブラリがなかった...
    • 高速化や通信量を減らすなど

あんまり難しくない

  • プログラム自体はすごく簡単
  • 2進法の知識そこまでいらん
  • ただ、結果が見えにくいのが難しいのかな?

前提知識

バイナリの知識

  • 2進法
  • ビットとバイト
  • エンディアン

2進法

  • 0と1の並びだけでデータを表わす(符号化とか言う)
  • 数だけではなく、文字、音声、画像、動画もすべてこれ
      • 1 = L
      • 01 = I
      • 001 = S
      • 0001 = P
      • 1010010001 = LISP
  • 電気的(物理的)に扱いやすい。
    • 電圧のHighとLowで表すなど

ビットとバイト

  • ビット
    • 情報量の単位
    • でもまぁ、2進法の単位と思ってええよ。
  • バイト
    • ビットのまとまり
    • だいたい8ビット=1バイト

1

1

0

0

0

1

0

1

1

基本的にバイト単位で扱う

  • c言語では(コンパイラによる)
    • char = 1 バイトで文字や数値を扱う
    • int = 4バイトで整数を扱う
    • float = 4バイトで浮動小数点数を扱う
    • double = 8バイトで浮動小数点数扱う

エンディアン

  • 例:[1234,5678,9012,3456]のデータ列
    • [1234567890123456] = ビッグエンディアン
    • [4321876521096543] = リトルエンディアン
  • CPUによってエンディアンが異なる

JSでバイナリ取扱

ArrayBuffer

  • バイナリデータを格納するクラス
  • バイナリを直接操作することができない
  • 読み書きのためには、ビューを利用する
    • Typed Array Object
    • DataView Object
  • XMLHttpRequest、FileReaderから取得する
  • new ArrayBuffer(size);

Typed Array

  • ArrayBufferのデータ列を一定のサイズで区切った配列と見なす
  • 配列と同様に扱える
  • 種類:
    • Uint8Array : 8ビットで区切った整数の配列
    • Int32Array  : 32ビットで区切った整数の配列
    • Float64Array : 64ビットで区切った浮動小数点数の配列
    • Uint8ClampedArray : 8ビットで区切った画素配列

Typed Arrayの注意点

  • CPUのネイティブのエンディアンを利用する
  • ネットワークを通じて、複数のコンピュータでバイナリデータを利用する場合
  • 逆にCPUのエンディアンを利用するので高速
  • エンディアンが問題になるときDataViewを利用

DataView

  • 異なる、型のデータ列を利用する場合につかう
    • 例:ヘッダとボディがあるようなデータ
      • 8ビット整数と16ビットの整数というヘッダと16ビットのデータ列のボディ
  • エンディアンの指定もできる
  • XMLHttpRequest、FileReaderのinput/output APIで読み出すときに使う

TypedArray Object

  •  
  • Bullet Two
  • Bullet Three

STLを読み出す

STLとは

  • Standard Triangle Language
  • 三角形で3Dのポリゴンを表現するデータ形式
  • テキスト形式とバイナリ形式がある

STLを読みこみ3Dの

オブジェクトを表示する

  • webglを利用する
  • stlで頂点データを取り出し -> シェーダ -> 表示
  • 3Dデータの頂点データを取り出すまで

STLをロード

var xhr = new XMLHttpRequest();
xhr.open("GET", "example.stl", true);
xhr.responseType = "arraybuffer";

xhr.onload = function(event){
    var arrayBuffer = xhr.response;
    ...
}

xhr.send();

STLのフォーマット

データ サイズ
ヘッダ 8バイト文字が80個
三角形の数 4バイトの符号なし整数
三角形の情報 三角形の数 × 50バイト

三角形の数を読み出す

    let dataView = new DataView(arrayBuffer);
    let faces = dataView.getUint32( 80, true );

三角形の情報

A(0,1,0)

B(1,3,5)

C(4,1,2)

法線ベクトル(1,2,3)

三角形の情報

法線ベクトルのx座標 4バイト浮動小数点
法線ベクトルのy座標 4バイト浮動小数点
法線ベクトルのz座標 4バイト浮動小数点
Aのx座標 4バイト浮動小数点
Aのy座標 4バイト浮動小数点
Aのz座標 4バイト浮動小数点
Bのx座標 4バイト浮動小数点
Bのy座標 4バイト浮動小数点
Bのz座標 4バイト浮動小数点
Cのx座標
4バイト浮動小数点
Cのy座標
4バイト浮動小数点
Cのz座標
4バイト浮動小数点
色の指定
2バイト

三角形の頂点データ読み出し

    let offset = 84;
    let faceLength = 12 * 4 + 2;
    let polygons = [];

    for(var face = 0; face < faces; face++ ) {
        let begin = offset + face * faceLength;
        let vertex1Begin = begin + 12;
        let vertex2Begin = vertex1Begin + 12;
        let vertex3Begin = vertex2Begin + 12;

        ....
    }

三角形の頂点データ読み出し

var vertex1 = {
    x : dataView.getFloat32(vertex1Begin, true),
    y : dataView.getFloat32(vertex1Begin + 4, true),
    z : dataView.getFloat32(vertex1Begin + 8, true)
};
var vertex2 = { ... };
var vertex3 = {  ... };

polygons.push({
    vertices : [vertex1, vertex2, vertex3]
 });

まとめ

JSでのバイナリ取扱

  • この3つを覚えておくだけ
    • ArrayBuffer
    • DataView
    • TypedArray
  • 基本的にDataViewを利用すれば良い

まとめ

  • 案外難しくはない
  • 大抵はライブラリを使う
  • 覚えておくと、できることがひろがる

deck

By Nobukazu Hanada

deck

  • 685