web-dev-qa-db-fra.com

Puis-je désactiver l'antialiasing sur un élément HTML <canvas>?

Je joue avec l'élément <canvas> , en traçant des lignes, etc.

J'ai remarqué que mes lignes diagonales sont antialiasées. Pour ma part, je préférerais que mon look soit irrégulier - y at-il un moyen de désactiver cette fonctionnalité?

74
Blorgbeard

Pour les images, il y a maintenant context.imageSmoothingEnabled= false.

Cependant, rien ne permet de contrôler explicitement le dessin au trait. Vous devrez peut-être tracer vos propres traits ( à la dure ) en utilisant getImageData et putImageData.

46
Kornel

Tracez vos lignes 1-pixel sur des coordonnées telles que ctx.lineTo(10.5, 10.5). Tracer une ligne d'un pixel sur le point (10, 10) signifie que ce pixel 1 situé à cette position va de 9.5 à 10.5, ce qui donne deux lignes dessinées sur le canevas. 

Une astuce intéressante pour ne pas toujours avoir besoin d'ajouter le 0.5 à la coordonnée sur laquelle vous voulez dessiner si vous avez beaucoup de lignes d'un pixel, est de ctx.translate(0.5, 0.5) votre toile entière au début.

58
allan

Cela peut être fait dans Mozilla Firefox. Ajoutez ceci à votre code:

contextXYZ.mozImageSmoothingEnabled = false;

Dans Opera, c'est actuellement une demande de fonctionnalité, mais j'espère qu'elle sera bientôt ajoutée.

24
francholi

Il doit antialias graphiques vectoriels

L'anticrénelage est requis pour un traçage correct des graphiques vectoriels impliquant des coordonnées non entières (0.4, 0.4), ce que tous, mais très peu de clients, feront.

Lorsqu'on lui donne des coordonnées non entières, le canevas a deux options:

  • Antialias - Peint les pixels autour de la coordonnée en fonction de la distance entre la coordonnée entière et la valeur non-entière (erreur d'arrondi).
  • Round - applique une fonction d'arrondi à la coordonnée non entière (donc 1.4 deviendra 1, par exemple).

La dernière stratégie fonctionnera pour les graphiques statiques, bien que pour les petits graphiques (un cercle de rayon 2), les courbes montrent des marches claires plutôt que des courbes lisses.

Le vrai problème est lorsque les graphiques sont traduits (déplacés) - les sauts entre pixels (1,6 => 2, 1,4 => 1) signifient que l’origine de la forme peut sauter par rapport au conteneur parent (décalage constant). 1 pixel vers le haut/bas et gauche/droite).

Quelques conseils

Astuce n ° 1: vous pouvez atténuer (ou renforcer) l'antialiasing en redimensionnant le canevas (par exemple, par x), puis appliquez vous-même l'échelle réciproque (1/x) aux géométries (sans utiliser le canevas).

Comparer (pas de mise à l'échelle):

 A few rectangles

avec (échelle de la toile: 0,75; échelle manuelle: 1,33):

 Same rectangles with softer edges

et (échelle de la toile: 1,33; échelle manuelle: 0,75):

 Same rectangles with darker edges

Astuce n ° 2: Si vous recherchez vraiment un look irrégulier, essayez de dessiner chaque forme plusieurs fois (sans l’effacer). A chaque tirage, les pixels anti-crénelage deviennent plus sombres.

Comparer. Après avoir dessiné une fois:

 A few paths

Après avoir dessiné trois fois:

 Same paths but darker and no visible antialiasing.

11
Izhaki

Je dessinerais tout en utilisant un algorithme de ligne personnalisé tel que l'algorithme de ligne de Bresenham. Découvrez cette implémentation JavaScript: http://members.chello.at/easyfilter/canvas.html

Je pense que cela va certainement résoudre vos problèmes.

8
raRaRa

Je veux ajouter que j'ai eu du mal à réduire la taille d'une image et à dessiner sur une toile, elle utilisait toujours le lissage, même si elle ne l'était pas lors de la conversion.

J'ai résolu en utilisant ceci:

function setpixelated(context){
    context['imageSmoothingEnabled'] = false;       /* standard */
    context['mozImageSmoothingEnabled'] = false;    /* Firefox */
    context['oImageSmoothingEnabled'] = false;      /* Opera */
    context['webkitImageSmoothingEnabled'] = false; /* Safari */
    context['msImageSmoothingEnabled'] = false;     /* IE */
}

Vous pouvez utiliser cette fonction comme ceci:

var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))

Peut-être que cela est utile pour quelqu'un.

6
eri0o
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;

Avec ce combo, je peux dessiner de belles lignes fines de 1px.

5
retepaskab

Remarquez un truc très limité. Si vous souhaitez créer une image à 2 couleurs, vous pouvez dessiner la forme de votre choix avec la couleur # 010101 sur un arrière-plan de couleur # 000000. Une fois que cela est fait, vous pouvez tester chaque pixel dans le fichier imageData.data [] et définir sur 0xFF quelle que soit la valeur qui n’est pas 0x00:

imageData = context2d.getImageData (0, 0, g.width, g.height);
for (i = 0; i != imageData.data.length; i ++) {
    if (imageData.data[i] != 0x00)
        imageData.data[i] = 0xFF;
}
context2d.putImageData (imageData, 0, 0);

Le résultat sera une image en noir et blanc non antialiasée. Ce ne sera pas parfait, car un antialiasing aura lieu, mais cet antialiasing sera très limité, la couleur de la forme ressemblant beaucoup à celle du fond.

4
StashOfCode

Juste deux notes sur la réponse de StashOfCode:

  1. Cela ne fonctionne que pour une toile opaque en niveaux de gris (fillRect avec blanc puis dessin avec noir, ou vice versa)
  2. Il peut échouer lorsque les lignes sont fines (~ 1px line width)

Il vaut mieux le faire à la place:

Contournez et remplissez avec #FFFFFF, puis procédez comme suit:

imageData.data[i] = (imageData.data[i] >> 7) * 0xFF

Cela le résout pour les lignes d'une largeur de 1px.

En dehors de cela, la solution de StashOfCode est parfaite car elle ne nécessite pas d'écrire vos propres fonctions de rastérisation (pensez non seulement aux lignes, mais à Béziers, aux arcs de cercle, aux polygones remplis avec des trous, etc.).

0
Matías Moreno