2014/01/24

[JavaScript]canvasで画像のマスキングを実現するclip()でハマった

PixelArtsという個人的なプロジェクトでcanvasをガンガン使っているんですが、canvasとその周辺技術についてTipsをまとめたいと思います。canvasにはclip()という、画像処理でいうマスクのような機能が存在します。しかし、このclip()を同じcanvasで連続して使うには、少しばかりのコツが必要でした。




clip()を有効に使う

canvas 2D contextに実装されているclip()は、canvas上の指定した範囲の画像データをクリップして他のcanvasに貼り付けたりできる強力なメソッドですが、ループ中で何回も使う場合は注意が必要です。
一度clip()したら次にclip()を実行しても指定した範囲は上書きされません。かといってcanvasを破棄するのはコストに見合わないので、save()とrestore()をうまく使う必要があります。
save()とrestore()を利用しない場合は以下のようになります。右のcanvasから左のcanvasへコピーし、左のcanvasでclip()を設定してみます。




save()とrestore()を利用すると、クリップ領域を再定義できます。




意図したとおりに動く方のコードを晒しておきます。
function test2(){
    var canvas1 = document.getElementById('test2');
    var ctx1 = canvas1.getContext('2d');
    var canvas2 = document.getElementById('test21');
    var ctx2 = canvas2.getContext('2d');
    // canvas 2D contextが使える前提

    canvas1.width = 300;
    canvas1.height = 300;
    canvas2.width = 300;
    canvas2.height = 300;

    draw();
    function draw(){
        ctx2.beginPath();
        ctx2.fillStyle = '#ff0000';
        ctx2.arc(100, 100, 20, 0, Math.PI * 2, false);
        ctx2.fill();

        ctx1.save();    // clip()する前の状態を保存
        ctx1.rect(132, 132, 36, 36);
        ctx1.clip();
        ctx1.drawImage(canvas2, 80, 80, 40, 40, 130, 130, 40, 40);
        ctx1.restore();    // clip()する前の状態へ戻す

        ctx2.beginPath();
        ctx2.fillStyle = '#00ff00';
        ctx2.arc(200, 200, 20, 0, Math.PI * 2, false);
        ctx2.fill();

        ctx1.save();    // clip()する前の状態を保存
        ctx1.rect(195, 195, 30, 30);
        ctx1.clip();
        ctx1.drawImage(canvas2, 180, 180, 40, 40, 200, 200, 40, 40);
        ctx1.restore();    // clip()する前の状態へ戻す
    };
};

バッファリング処理などでclip()を利用する事もできるので、clip()、というよりsave()をrestore()をうまく利用するとコード量がグッと減らせ、見通しがよくなります。

PixelArtsはMath.random()を使ってプログラマーが芸術に挑戦するというものです。
PixelArtsの方もよろしくお願いします。

PixelArts


0 件のコメント:

コメントを投稿