javascript - Kan jeg slå av antialiasing på et HTML <canvas>-element?
Jeg leker med <canvas>-elementet, tegner linjer og slikt.
Jeg har lagt merke til at de diagonale linjene mine er antialiaset. Jeg foretrekker det hakkete utseendet for det jeg holder på med - finnes det noen måte å slå av denne funksjonen på?
Svar #1
For bilder finnes det nå context.imageSmoothingEnabled= false.
Det er imidlertid ingenting som eksplisitt kontrollerer linjetegning. Du må kanskje tegne dine egne linjer (på den vanskelige måten) ved å bruke getImageData og putImageData.
Svar #2
Tegn dine 1-piksel linjer på koordinater som ctx.lineTo(10.5, 10.5). Å tegne en én-piksel linje over punktet (10, 10) betyr at denne 1 pikselen på den posisjonen strekker seg fra 9.5 til 10.5, noe som resulterer i to linjer som blir tegnet på lerretet.
Et fint triks for å ikke alltid måtte legge til 0.5 til den faktiske koordinaten du vil tegne over hvis du har mange en-piksel linjer, er å ctx.translate(0.5, 0.5) hele lerretet ditt i begynnelsen.
Svar #3
Legger til dette:
image-rendering: pixelated; image-rendering: crisp-edges;
til stilattributtet til canvas-elementet hjalp til med å tegne skarpe piksler på canvas. Oppdaget via denne flotte artikkelen:
https://developer.mozilla.org/en-US/docs/Games/Techniques/Crisp_pixel_art_look
Svar #4
Det kan gjøres i Mozilla Firefox. Legg dette til i koden din:
contextXYZ.mozImageSmoothingEnabled = false;
I Opera er det for øyeblikket en funksjonsforespørsel, men forhåpentligvis vil det bli lagt til snart.
Svar #5
Prøv noe som canvas { image-rendering: pixelated; }.
Dette kan hende ikke fungerer hvis du prøver å bare gjøre én linje ikke antialiasert.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillRect(4, 4, 2, 2);
ctx.strokeStyle = "#11f";
/* The anti-aliasing is worse
on integer coordinates */
ctx.moveTo(0, 6.5);
ctx.lineTo(10, 7.5);
ctx.lineWidth = 1.0;
ctx.stroke();canvas {
image-rendering: pixelated;
width: 100px;
height: 100px; /* Scale 10x */
}<html>
<head></head>
<body>
<canvas width="10" height="10">Canvas unsupported</canvas>
</body>
</html>Jeg har ikke testet dette på mange nettlesere, skjønt.
Svar #6
Jeg oppdaget en bedre måte å deaktivere kantutjevning på sti-/formrendering ved hjelp av kontekstens filteregenskap:
Magien/TL;DR:
ctx = canvas.getContext('2d');
// make canvas context render without antialiasing
ctx.filter = "url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxmaWx0ZXIgaWQ9ImZpbHRlciIgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj48ZmVDb21wb25lbnRUcmFuc2Zlcj48ZmVGdW5jUiB0eXBlPSJpZGVudGl0eSIvPjxmZUZ1bmNHIHR5cGU9ImlkZW50aXR5Ii8+PGZlRnVuY0IgdHlwZT0iaWRlbnRpdHkiLz48ZmVGdW5jQSB0eXBlPSJkaXNjcmV0ZSIgdGFibGVWYWx1ZXM9IjAgMSIvPjwvZmVDb21wb25lbnRUcmFuc2Zlcj48L2ZpbHRlcj48L3N2Zz4=#filter)";
Avmystifisert:
Data-URL-en er en referanse til en SVG som inneholder et enkelt filter:
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="filter" x="0" y="0" width="100%" height="100%" color-interpolation-filters="sRGB">
<feComponentTransfer>
<feFuncR type="identity"/>
<feFuncG type="identity"/>
<feFuncB type="identity"/>
<feFuncA type="discrete" tableValues="0 1"/>
</feComponentTransfer>
</filter>
</svg>
Da, helt på slutten av URL-en er det en ID-referanse til den #filter:
"url(data:image/svg+...Zz4=#filter)";
SVG-filtret bruker en diskret transformasjon på alfa-kanalen, og velger kun helt gjennomsiktig eller helt ugjennomsiktig ved en 50 % grense når det gjengis. Dette kan justeres for å legge til noe kantutglatting tilbake hvis det er nødvendig, f.eks.:
...
<feFuncA type="discrete" tableValues="0 0 0.25 0.75 1"/>
...
Ulemper/Notater/Fallgruver
Merk, jeg har ikke testet denne metoden med bilder, men jeg kan anta at det ville påvirke semi-transparente deler av bilder. Jeg kan også gjette at det sannsynligvis ikke vil forhindre antialiasing på bilder ved forskjellige fargegrenser. Det er ikke en 'nærmeste farge'-løsning, men snarere en binær transparensløsning. Det ser ut til å fungere best med strek-/formgjengivelse siden alfa er den eneste kanalen som blir antialisert med stier.
Også er det trygt å bruke en minimum lineWidth på 1. Tynnere linjer blir sparsommelige eller kan ofte forsvinne helt.
Rediger :
Jeg har oppdaget at, i Firefox, fungerer det ikke umiddelbart/synkront å sette filter til en data-URL: data-URL-en må først 'laste'.
f.eks. Følgende vil ikke fungere i Firefox:
ctx.filter = "url(data:image/svg+xml;base64,...#filter)";
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(20,20);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.filter = "none";
Men å vente til neste JS-ramme fungerer fint:
ctx.filter = "url(data:image/svg+xml;base64,...#filter)";
setTimeout(() => {
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(20,20);
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
ctx.filter = "none";
}, 0);
Svar #7
Noe bakgrunn
Når det gis ikke-heltallige koordinater, har lerretet to alternativer:
- Antialias - mal pikslene rundt koordinaten basert på hvor langt den heltallige koordinaten er fra den ikke-heltallige (dvs. avrundingsfeilen).
- Rund - bruk en eller annen avrundingsfunksjon på den ikke-heltallige koordinaten (så 1,4 vil bli 1, for eksempel).
Den senere strategien vil fungere for statiske grafikk, selv om for små grafikk (en sirkel med radius på 2) vil kurver vise tydelige trinn i stedet for en jevn kurve.
Det virkelige problemet er når grafikken blir oversatt (flyttet) - hoppene mellom en piksel og en annen (1,6 => 2, 1,4 => 1), betyr at opprinnelsen til formen kan hoppe i forhold til den overordnede beholderen (konstant skifte 1 piksel opp/ned og til venstre/høyre).
Noen tips
Tips #1: Du kan mykne (eller forsterke) antialiasing ved å skalere lerretet (for eksempel med x) og deretter bruke den gjensidige skalaen (1/x) på geometriene selv (uten å bruke lerretet).
Sammenlign (uten skalering):
med (lerretskala: 0,75; manuell skala: 1,33):
og (lerretskala: 1,33; manuell skala: 0,75):
Tips #2: Hvis en taggete stil virkelig er det du er ute etter, prøv å tegne hver form noen ganger (uten å viske ut). Med hver tegning blir kantutjevningspikslene mørkere.
Sammenlign. Etter å ha tegnet en gang:
Etter å ha trukket tre ganger:
Svar #8
Jeg ville tegnet alt ved å bruke en tilpasset linjealgoritme som Bresenhams linjealgoritme. Sjekk ut denne JavaScript-implementasjonen: http://members.chello.at/easyfilter/canvas.html
Jeg tror dette vil definitivt løse problemene dine.




