JavaScript による
Lossless 画像の扱い方

準備

WebブラウザでSWF内の画像を表示したい

SWF内の画像形式は以下の通り

JPEG 系はほとんど JPEG あるいは既存のファイルフォーマットの埋め込みなので若干手を加えるだけ

Lossless をどうやって表示させるか

Lossless 基礎知識

画像フォーマットの情報的にはパレット含めて PNG と相互変換可能

PNG への変換

PNG への変換

大きく分けると以下の3つの段階に分けられる

PNGへの変換特有の処理は生成部分だけ

生データの取り出し

ZLIBの展開が出来れば何でも良いが zlib.js というライブラリで例を示す

 // deflated: ZLIB 圧縮された ByteArray or Uint8Array
var inflator = new Zlib.Inflate(deflated);
// 展開
var plain = inflator.decompress();

実際にはもう少しきちんと使う事で性能が向上する(後述)

ピクセルごとのデータ取得

基本的な仕様については省略

SWF内のColormappedとDirect画像とPNGのColourTypeの対応は以下の通り

SWF PNG
Colormapped Indexed-colour
Direct(PIX15, PIX24) TrueColour, TrueColour with alpha

PNG の生成 - 最小構成

PNG は Signature + Chunk の集まり

PNG の生成 - パレット変換

PNG の生成 - IDAT の圧縮

無圧縮にする

PNG の生成 - 無圧縮 ZLIB の作り方

JavaScript 的な話

Canvas vs PNG 生成

Webブラウザで動的に画像を描画して表示するには2種類の方法がある

Canvas vs PNG 生成


Canvas, PNG 生成実行デモ

Canvas vs PNG 生成 Direct ベンチマーク

decode lossless2 direct - jsPerf

Canvas vs PNG 生成 Colormapped ベンチマーク

decode lossless2 colormapped - jsPerf

Array vs Uint8Array

array vs typedarray - jsPerf

Typed Array を使う場合は事前に必要サイズを把握する

ensureBuffer: function DecodeStream_ensureBuffer(requested) {
  var buffer = this.buffer;
  var current = buffer ? buffer.byteLength : 0;
  if (requested < current)
    return buffer;
  var size = 512;
  while (size < requested)
    size <<= 1;
  var buffer2 = new Uint8Array(size);
  for (var i = 0; i < current; ++i)
    buffer2[i] = buffer[i];
  return (this.buffer = buffer2);
}, 

Arrayを使う場合は初期化のサイズは 64K まで (V8)

特定の環境に特化するなら気にしないで良いこともある

Lossless 形式の ZLIB 展開

Lossless 形式の ZLIB 展開時サイズ計算


zlib.js では展開に使用するバッファのサイズを指定することができる

var plain = new Zlib.Inflate(compressed, {bufferSize: size}).decompress();

PNG 生成

無圧縮 PNG のサイズ計算 - PNG 識別子、チャンク共通

無圧縮 PNG のサイズ計算 - 各チャンク個別

無圧縮 PNG のサイズ計算 - IDAT

PNG生成 - Object URL 作成

BlobBuilder / Blob Constructor / DataURL どれがいい?

環境ごとに速いものから使う

var BlobConstructorEnabled = false;
try { new Blob(); BlobConstructorEnabled = true; } catch(e) {}
if (BlobConstructorEnabled) {
  // Blob Constructor
} else if (window.BlobBuilder || window.WebKitBlobBuilder) {
  // BlobBuilder
} else {
  // Data URL
}

ByteArray から ByteString への変換

single

for (i = 0, il = testData.length; i < il; ++i) {
  tmp[i] = String.fromCharCode(testData[i]);
}

multi

for (i = 0, il = testData.length; i < il; i += size) {
  tmp[i] = String.fromCharCode.apply(null, testData.slice(i, i + size));
}

ByteArray から ByteString への変換

bytearray to bytestring - jsPerf

おわり

Adler-32

adler-32 simple vs optimized - jsPerf

おまけ - 参考になりそうなページなど