9

私は現在、HTML5 キャンバスに画像を描画し、アークでマスクして、画像を描画する前に clip() を呼び出して、アーク内の部分のみが表示されるようにしています。この円弧のエッジをぼかすにはどうすればよいですか? キャンバスで描いた形に「羽」を単純に適用する簡単な方法がないことをグーグルで知っています。画像のエッジが円弧に接している場合、画像のピクセル データにどのような影響がありますか? 助けてくれてありがとう。

私のコードの関連部分は次のとおりです。

ctx.arc(canvas.width/2, canvas.height/2, 250, 0, 6.28, false);//draw the circle
ctx.restore();
ctx.save();
ctx.drawImage(background, 0, 0,
              background.width * scale, background.height * scale);
ctx.clip();//call the clip method so the next render is clipped in last path
ctx.drawImage(img, 0, 0,
              img.width * scale, img.height * scale);
ctx.closePath();
ctx.restore();

アップデート

徹底的な回答と非常に役立つコード/コメント、ケンに感謝します!! 昨夜、特定のユースケースでこのソリューションを機能させるために数時間を費やしましたが、問題が発生しています。あなたが説明したセカンドキャンバステクニックで画像をクリップすると、arc()およびclip()ルーチンでできるのと同じように、変換で再描画できないようです。これは、私が達成しようとしているものの JS Fiddle です。円弧のフェザリングを除いて、2 つのレイヤー化された画像のクリック アンド ドラッグ イベントに注意してください。

http://jsfiddle.net/g3WkN/

arc() をあなたのメソッドに置き換えてみましたが、マウスイベントで発生する変換に応答するのに苦労しています。

4

1 に答える 1

24

2017年7月更新

この回答が与えられたので、新しいブラウザで利用できる新しいオプション、コンテキストのフィルタプロパティがあります。現在、すべてのブラウザがサポートしているわけではないことに注意してください。

ブラウザーの場合、次のように一時的なキャンバスを削除するだけでなく、コードを削減できます。

var ctx = demo.getContext('2d');

ctx.fillStyle = '#f90';
ctx.fillRect(0, 0, demo.width, demo.height);

clipArc(ctx, 200, 200, 150, 40);

function clipArc(ctx, x, y, r, f) {

    ctx.globalCompositeOperation = 'destination-out';

    ctx.filter = "blur(25px)";  // "feather"
    ctx.beginPath();
    ctx.arc(x, y, r, 0, 2 * Math.PI);
    ctx.fill();

    // reset comp. mode and filter
    ctx.globalCompositeOperation = 'destination-out';
    ctx.filter = "none";
}
body {background:#07c}
<canvas id="demo" width=400 height=400></canvas>

古い答え

技術

これは、次の手順を組み合わせることで実現できます。

  • オフスクリーン キャンバスを使用する
  • シャドー機能を使う(隠し味)
  • 複合モードを使用する

ぼやけた影を利用してブラウザ内部で羽を作ってもらう、というのがコンセプトです。これは、JavaScript でのぼかしよりもはるかに高速です。あらゆるオブジェクトの影を作成できるため、複雑なぼかしマスクを作成できます。

オフスクリーン キャンバスは、影だけを描画するために使用されます。これを実現するには、実際の形状をキャンバスの外に移動し、それに応じて影をオフセットします。その結果、実際の形状は「見えない」一方で、画面外のキャンバスに影が描画されます。

これでシェイプのぼかしバージョンができたので、それを合成モードのマスクとして使用できます。destination-out影が描かれる場所をクリートするかdestination-in、マスクを反転するかを選択します。

すべてのステップを実行するラッパー関数を作成しましょう

オンラインデモはこちら

function clipArc(ctx, x, y, r, f) { /// context, x, y, radius, feather size

    /// create off-screen temporary canvas where we draw in the shadow
    var temp = document.createElement('canvas'),
        tx = temp.getContext('2d');
      
    temp.width = ctx.canvas.width;
    temp.height = ctx.canvas.height;

    /// offset the context so shape itself is drawn outside canvas
    tx.translate(-temp.width, 0);

    /// offset the shadow to compensate, draws shadow only on canvas
    tx.shadowOffsetX = temp.width;    
    tx.shadowOffsetY = 0;

    /// black so alpha gets solid
    tx.shadowColor = '#000';

    /// "feather"
    tx.shadowBlur = f;
    
    /// draw the arc, only the shadow will be inside the context
    tx.beginPath();
    tx.arc(x, y, r, 0, 2 * Math.PI);
    tx.closePath();
    tx.fill();

    /// now punch a hole in main canvas with the blurred shadow
    ctx.save();
    ctx.globalCompositeOperation = 'destination-out';
    ctx.drawImage(temp, 0, 0);
    ctx.restore();
}

それだけです。

利用方法

clipArc(context, centerX, centerY, radius, featherSize);

デモの背景あり(フィドルを参照):

ctx.fillStyle = '#ffa';
ctx.fillRect(0, 0, demo.width, demo.height);

clipArc(ctx, 200, 200, 150, 40);

結果:

デモのスナップショット

センターをそのまま維持したい場合は、コンポジットモードを に置き換えてくださいdestination-in

逆フェザーマスクのデモ

デモ スナップショット反転マスク

于 2013-09-26T21:50:02.223 に答える