2012-03-02 10 views
29

Używam funkcji clip() na kanwie.Jak obcinać krawędzie klipów() w kanwie html5 w przeglądarce Chrome?

Wyniki: using canvas clip in various browsers

Jak widać wersja chrom ma straszne schodków/aliasing wzdłuż krawędzi. Jak to naprawić?

Kod odtworzenia:

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> 
+0

Wpadłem również na ten problem. To, co zrobiłem, to narysować koło w tym samym miejscu co obraz, za nim, o promieniu większym o 1 lub 2 piksele. Zachowaj kolor podobny i tam, "anty aliasowany" klip obrazu. – Automatico

Odpowiedz

2

z odpowiedziami na Can I turn off antialiasing on an HTML <canvas> element? wydaje się, że jest to przeglądarka specyficzny. Jest to nawet aktywny bug report w projekcie chromu google. Przepraszam, ale wygląda na to, że na razie nie masz szczęścia.

+1

Teraz błąd jest w stanie rozwoju w [chrome dashboard] (https://www.chromestatus.com/features/4871530282483712). Jak napisano w [Problemy] (https://code.google.com/p/chromium/issues/detail?id=422984), inne przeglądarki (IE, Firefox, Safari) 'clip()' są antyaliasowane. – sapics

-1

Użyj klipu svg. Działa jak urok, ale nie jest tak wygodny w użyciu.

5

Natrafiłem na ten sam problem z Chrome i klipsem().

W moich okolicznościach uzyskałem lepszą kompatybilność przeglądarki, ustawiając canvas globalCompositeOperation.

context.globalCompositeOperation = 'source-atop'; 

Narysuj swój kształt, koło w tym przypadku. Następnie przełącz na "source-atop" i narysuj swój kotek.

Uwaga: jest to szybka poprawka dla podstawowego rysunku i zakłada puste płótno. Poprzedni rysunek na płótnie wpłynie na twój klip.

+0

To rozwiązanie działa bardzo dobrze, dziękuję. Jeden łuk dla klipu i jeden łuk dla uderzenia. Prosty. Wierzę, że rozwiązanie z płótna drapania jest zbyt skomplikowane i wolne dla tego problemu, chyba że masz problem z brakiem obrysu. – mattdlockyer

+0

Udało mi się zastosować to, plus technikę "płótna wstecznego", aby zmniejszyć nieprzyjemną poszarpaną krawędź, gdy kręciłem wideo przez płótno: http://codepen.io/paceaux/pen/egLOeR Dziękuję za dzielenie się. – paceaux

12

Moja poprawka polega na narysowaniu cienkiego (2px) białego obrysu o tym samym promieniu po rysowaniu obrazu. Bardzo dobrze pokrywa się z aliasingiem i wygląda dobrze w różnych przeglądarkach.

+0

Taki świetny pomysł! Dzięki!! – Keith

+0

Walczyłem z tym dzisiaj przez ponad godzinę, takie proste i niesamowite rozwiązanie :) – trueicecold

+0

TAK, TO, CLEVER, <3! –

22

Jeśli wykonujesz złożony, warstwowy rysunek, możesz użyć funkcji globalCompositeOperation do emulowania przycinania w drugim, roboczym obszarze roboczym. Następnie można użyć drawImage, aby skopiować płótno rysunkowe z powrotem na oryginalne płótno. Nie mogę zagwarantować wydajności tego podejścia, ale jest to jedyny sposób, jaki znam, aby uzyskać to, czego chcesz.

//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, ...); 

Powodem, dla którego robimy to na płótnie do rysowania, jest to, że miejsce docelowe jest bardzo destrukcyjną operacją. Jeśli już narysowałeś pewne rzeczy do głównego płótna (możesz umieścić ładny gradient w tle), a następnie chciałeś narysować przycięty obraz, kółko obcinania wycina również wszystko, co już narysowałeś. Oczywiście, jeśli twoja szczególna sytuacja jest prostsza (może WSZYSTKO, co chcesz narysować, jest obciętym obrazem), możesz zrezygnować z płótna do rysowania.

Można odtwarzać różne tryby przycinania pod numerem my demo page. Dolny rząd (z gradientami) nie jest dla ciebie zbyt przydatny, ale górny rząd (z okręgiem i kwadratem) jest dużo bardziej istotny.

edit

Ups, przypadkowo forked your JSFiddle zademonstrować technikę.

+0

Szanowny Panie, uratowałeś mój dzień! – enyce12

+0

dzięki! To działa!!! –

Powiązane problemy