web-dev-qa-db-ja.com

Chrome Windowsの下でhtml5キャンバスのclip()エッジをアンチエイリアスする方法は?

キャンバスでclip()関数を使用しています。

結果: using canvas clip in various browsers

ご覧のとおり、chromeバージョンには、エッジに沿ってひどいジャギー/エイリアシングがあります。これを修正するにはどうすればよいですか?

再現するコード:

http://jsfiddle.net/ZRA76/

<canvas id="test" width="300" height="300"></canvas>​

<script type="text/javascript">
    cv = document.getElementById("test");
    ctx = cv.getContext("2d");

    var im = new Image();
    im.onload = function () {
        ctx.beginPath();
        ctx.arc(110, 110, 100, 0, 2*Math.PI, true);
        ctx.clip();
        ctx.drawImage(im, 0, 0);
    }
    im.src = "http://placekitten.com/300/300";
</script>
31
Simon Epskamp

複雑な階層化された描画を行う場合は、globalCompositeOperationを使用して、2番目のスクラッチキャンバスでクリッピングをエミュレートできます。次に、drawImageを使用して、スクラッチキャンバスを元のキャンバスにコピーして戻すことができます。このアプローチのパフォーマンスを保証することはできませんが、それがあなたが望むものを手に入れるために私が知っている唯一の方法です。

//set-up - probably only needs to be done once
var scratchCanvas = document.createElement('canvas');
scratchCanvas.width = 100;
scratchCanvas.height = 100;
var scratchCtx = scratchCanvas.getContext('2d');


//drawing code
scratchCtx.clearRect(0, 0, scratchCanvas.width, scratchCanvas.height);

scratchCtx.globalCompositeOperation = 'source-over'; //default

//Do whatever drawing you want. In your case, draw your image.
scratchCtx.drawImage(imageToCrop, ...);


//As long as we can represent our clipping region as a single path, 
//we can perform our clipping by using a non-default composite operation.
//You can think of destination-in as "write alpha". It will not touch
//the color channel of the canvas, but will replace the alpha channel.
//(Actually, it will multiply the already drawn alpha with the alpha
//currently being drawn - meaning that things look good where two anti-
//aliased pixels overlap.)
//
//If you can't represent the clipping region as a single path, you can
//always draw your clip shape into yet another scratch canvas.

scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
scratchCtx.globalCompositeOperation = 'destination-in';
scratchCtx.beginPath();
scratchCtx.arc(50, 50, 50, 0, 2 * Math.PI, true);
scratchCtx.closePath();
scratchCtx.fill();


//Now that we have a Nice, cropped image, we can draw it in our
//actual canvas. We can even draw it over top existing pixels, and
//everything will look great!

ctx.drawImage(scratchCanvas, ...);

スクラッチキャンバスでこれを行う理由は、destination-inがかなり破壊的な操作であるためです。メインキャンバスにすでにいくつかのものを描画していて(おそらく背景にニースグラデーションを配置した場合)、クリップされた画像を描画したい場合、クリッピングサークルはすでに描画したものすべてをクリップします。もちろん、特定の状況がより単純な場合(おそらく、描画したいのはクリップされた画像だけです)、スクラッチキャンバスを使用しないでください。

私のデモページ でさまざまなクリッピングモードを試してみることができます。下の行(グラデーション付き)はあまり役に立ちませんが、上の行(円と正方形付き)の方がはるかに関連性があります。

編集

おっと、私は誤って あなたのJSFiddleをフォークしました テクニックを示すために。

24

これに対する私の修正は、画像を描画した後、同じ半径で細い(2px)白いストロークを描画することです。エイリアシングをうまくカバーし、ブラウザ間で問題なく表示されます。

12
cacheflowe

Chromeとclip()で同じ問題に遭遇しました。

私の状況では、キャンバスのglobalCompositeOperationを設定することで、ブラウザーの互換性を向上させました。

context.globalCompositeOperation = 'source-atop';

だからあなたの形、この場合は円を描きなさい。次に、「source-atop」に切り替えて、子猫の画像を描画します。

これは基本的な描画の簡単な修正であり、空白のキャンバスを想定していることに注意してください。以前のキャンバスの描画はクリップに影響します。

5
Edward

HTMLの<canvas>要素でアンチエイリアスをオフにできますか? ブラウザ固有のようです。それはグーグルコードクロムプロジェクトでさえアクティブです バグレポート 。申し訳ありませんが、今のところ運が悪いようです。

2
Scott M.