ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

JavaScript GIF Encoder “GifWriter.js” 0.1.0 をリリースしました

2013 年 4 月 22 日に JavaScript の GIF Encoder ライブラリをリリースしました。 TypeScript で書いてます。

ダウンロードとデモ

次のページからダウンロードできます。 Web 上で動くデモもあります。

TypeScript で書かれたソースコードは GitHub のリポジトリに置いてます。

クラス

主要なクラスは次の 2 つです。

  • vividcode.image.GifWriter
  • vividcode.image.MedianCutColorReducer

vividcode.image.GifWriter

vividcode.image.GifWriter クラスは、インデックスカラー画像のデータをアウトプットストリームに書きだす役割を担います。

  • インデックスカラー画像のデータは vividcode.image.IIndexedColorImage インターフェイスを実装したオブジェクトで表されます。 GifWriter.js では、このインターフェイスを実装したクラスとして vividcode.image.IndexedColorImage クラスを提供していますので、基本的にはこれを使ってください。
  • アウトプットストリームは vividcode.image.IOutputStream インターフェイスを実装したオブジェクトで表されます。 writeByte メソッドと writeBytes メソッドさえ実装されていればよいので、もっとも簡単なものとしては配列をラッピングしたものになります。 後のサンプルコードに例がありますのでご覧ください。

vividcode.image.MedianCutColorReducer

vividcode.image.MedianCutColorReducer は減色処理を行うクラスです。 メディアンカットアルゴリズムを使用しています。 勢いで書いたのでコードは汚いです。

フルカラー画像を GifWriter クラスで GIF 画像のデータにして書きだしたい場合は、GifWriter クラスで処理する前に減色処理を行わなければなりません。 vividcode.image.MedianCutColorReducer を使用すると、減色処理を行うことができます。

サンプルコード

ドキュメントの整備はちゃんとしてないので、使いたい場合はソースコードを読むなりサンプルコードを見るなりして使ってください。

vividcode.image.GifWriter の使い方

Node.js 上で、vividcode.image.IndexedColorImage オブジェクトから GIF ファイルを生成する方法は以下のようになります。

// サンプルの白黒画像です
var indexedColorImage = new vividcode.image.IndexedColorImage(
    { width: 9, height: 9 },
    // 第 2 引数は画像データです: 1 要素が 1 ピクセルに相当します。
    //   値はカラーインデックスです: この例では 0 は黒 (0,0,0), 1 は白 (255,255,255)
    [
        0,0,0,1,1,1,0,0,0,
        0,0,0,1,1,1,0,0,0,
        0,0,0,1,1,1,0,0,0,
        1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,1,
        0,0,0,1,1,1,0,0,0,
        0,0,0,1,1,1,0,0,0,
        0,0,0,1,1,1,0,0,0,
    ],
    // パレットデータです: 3 要素で 1 つの色を表します (順に 赤, 緑, 青)
    [0,0,0, 255,255,255]
);

// GifWriter によって書きだされる先のアウトプットストリームを表すオブジェクト
// `writeByte` メソッドと `writeBytes` メソッドを実装すればよいです。
var outputStream = {
    buffer: [],
    writeByte: function (b: number) {
        this.buffer.push(b);
    },
    writeBytes: function (bb: number[]) {
        Array.prototype.push.apply(this.buffer, bb);
    },
};

// アウトプットストリームに書きだし
var gifWriter = new vividcode.image.GifWriter(outputStream);
gifWriter.writeHeader();
gifWriter.writeLogicalScreenInfo({
    width: indexedColorImage.width,
    height: indexedColorImage.height,
});
gifWriter.writeTableBasedImage(indexedColorImage);
gifWriter.writeTrailer();

// ファイルに書きだし
var buf = new Buffer(outputStream.buffer);
var fs = require("fs");
fs.writeFile('test.gif', buf, function (err) {
    if (err) console.log(err);
    console.log('It\'s saved!');
});

このスクリプトを実行すると、次の GIF 画像が生成されます: f:id:nobuoka:20130422015945g:plain

vividcode.image.MedianCutColorReducer の使い方

vividcode.image.MedianCutColorReducer クラスを使って、ImageData オブジェクトから vividcode.image.IndexedColorImage オブジェクトを生成する方法を示します。 (減色処理)

// imgData は HTML Standard の ImageData オブジェクトです
var imgData = canvasElem.getContext("2d").getImageData(0,0,128,128);
// 減色後の色の個数
var paletteSize = 128;

var reducer = new vividcode.image.MedianCutColorReducer(imgData, paletteSize);
var paletteData = reducer.process();
var dat = Array.prototype.slice.call(imgData.data);
var indexedColorImageData = [];
for (var idx = 0, len = dat.length; idx < len; idx += 4) {
  var d = dat.slice(idx, idx+4); // r,g,b,a
  indexedColorImageData.push(reducer.map(d[0],d[1],d[2]));
}
return new vividcode.image.IndexedColorImage({ width: imgData.width, height: imgData.height },
      indexedColorImageData, paletteData);

このように生成された vividcode.image.IndexedColorImage オブジェクトを GifWriter に渡すことで GIF データに書きだすことができます。

関連ライブラリ

JavaScript の GIF Encoder としては、id:uiureo 氏の下記記事で紹介されている jsgif というものが既に存在します。

ActionScript のコードを機械的に JS に変換してものなので JS としてはちょっと微妙な気はします。 それと、減色処理で綺麗に減色されないような気がします。 (使い方が悪いのかもしれませんが。)