swf2jsでswfを直接分解してcanvasに出力する

  • 40
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

swfのバイナリをJavaScriptで読み込んでバイナリ分解してcanvasに出力したい。

完成品

ienaga/swf2js

SWF仕様書

SWFの仕様書が公開されているので仕様書を見ながら分解する。

SWF File Format Specification

SWF Investigator

分解された状態を確認できる。便利。

Adobe SWF Investigator

swfを読み込む

var xmlHttpRequest = new XMLHttpRequest();

xmlHttpRequest.open('GET', url);

// XMLHttpRequest2が使えるなら使う
isXHR2 = typeof xmlHttpRequest.responseType != 'undefined';

if (isXHR2) {
    xmlHttpRequest.responseType = 'arraybuffer';
} else {
    xmlHttpRequest.overrideMimeType(
        'text/plain; charset=x-user-defined'
    );
}

xmlHttpRequest.send(null);

xmlHttpRequest.onreadystatechange = function()
{

    var readyState = xmlHttpRequest.readyState;

    if (readyState == 4) {

        var status = xmlHttpRequest.status;

        switch (status) {

            case 200:

                // 分解の実装
                parse(isXHR2 ? xmlHttpRequest.response : xmlHttpRequest.responseText, player.parent);
                ...省略
                break;

            case 404:
                alert('Swf Data Not Found');
                break;

            case 500:
                alert('Internal Server Error');
                break;

        }
    }
}

バイナリの分解

取得できたバイナリを分解・・・

いやいや、こんなの無知な状態から勉強開始しても全然意味不明すぎる・・・

って事で、バイナリの達人yoyaさんの「swfpl」の「bitio.js」を使って勉強させて頂きます!

yoya/swfpl

XMLHttpRequest2に対応していなければバイナリのデータを0から255の数値に変換する
型付き配列(Typed Array)に対応している端末ならTyped Arrayを使用する。

bitio.js
    /**
     * BitIO
     * @constructor
     */
    var BitIO = function()
    {
        this.data = null;
        this.bit_offset = 0;
        this.byte_offset = 0;
        this.bit_buffer = null;
    };

    /**
     * init
     * @param binary
     */
    BitIO.prototype.init = function(binary)
    {
        var _this = this;
        var length = binary.length;
        var array = _this.createArray(length);
        var key = 0;
        for (; length--;) {
            array[key] = binary.charCodeAt(key++) & 0xff;
        }
        this.data = array;
    };

    /**
     * createArray
     * @param length
     * @returns {Array}
     */
    BitIO.prototype.createArray = function(length)
    {
        return (window.ArrayBuffer) ? new Uint8Array(length) : [];
    };

    ...省略

分からない所は使いながらコネコネしながらひたすら学ぶしかない。。。

SwfTag

バイナリの勉強を進めながら、SWF仕様書に書いてある通りに分解していく。

tagの分解はSWF Investigatorのソースがとても参考になりました。

sourceforge/SWFInvestigator

ベクターの分解と描画

個人的に一番の苦労したのは、ベクターの分解と描画。

SWFのベクターの描画は一回の描画で二色塗るという実装がされている。

image01.png

参考資料

canvasだとそんなの無理じゃないかな・・・orz

なので、一回描画のデータを2つに分解して描画の座標を結合する事にした。

image02.png

※ s=開始点、e=終点

次にぶつかった問題は中抜きの描画

image03.png

でも・・・

image04.png

はて???

non-zero rule

いろいろ調べた結果、中抜きするにはnon-zero ruleを使用するしかない。

参考ページ

ようするに0の部分は描画しないらしい。

前提として、時計回りの描画を+1
反時計回りを-1とする。

時計回り(+1)のデータが重なる部分は2となり、描画される。

image05.png

時計回り(+1)の描画と反時計回り(-1)の描画が重なる分は0となり描画されない

image06.png

個人的にはこの部分にハマって何回も作るのを断念しそうになった。。。

Action Script

[2015/08/10-追記]
http://qiita.com/ienaga/items/fc5b25df3b3f2b2f191d

タイムラインのMovieClipの作られた順にアクションを実行していく。

実行中のアクションでフレームの移動があれば移動先のアクションを予約。

移動先の描画前にアクションを実行

これを繰り返えす。

概ねSWF仕様書の通りでActionScriptは実行できている。

が、きっと例外的な挙動もあると思うので、その際は是非コメントください。

WebGL

まだまだ勉強中・・・

そのうち対応する予定・・・

flash lite 2.x

現在、地道に実装中☆彡

目標としてバージョン8には対応したい。

※現在はバージョン5か6までなら対応出来てるはず・・・

デモサイトはこちらから

https://swf2js.wordpress.com/demos/