149 votes

Désactiver l'Interpolation lors du Redimensionnement d'un <canvas>

REMARQUE: Cela a à voir avec la façon toile éléments sont rendus au moment de l'échelle, pas à faire avec la façon dont les lignes ou les graphiques sont rendus sur une surface de toile. En d'autres termes, cela a tout à voir avec l'interpolation de l'échelle des éléments, et rien à voir avec l'anticrénelage des graphismes dessinés sur une toile. Je ne suis pas préoccupé par la façon dont le navigateur trace des lignes; je me soucie de la façon dont le navigateur rend la toile de l'élément lui-même quand il est mis à l'échelle.


Est-il une toile de propriété ou les paramètres du navigateur, je peux la changer par programmation pour désactiver l'interpolation lors de la mise à l'échelle <canvas> éléments? Un cross-browser solution est idéale, mais pas essentiel; basé sur Webkit navigateurs sont mon objectif principal. La Performance est très important.

Cette question est très similaire, mais ne pas illustrer le problème suffisamment. Pour ce que ça vaut, j'ai essayé image-rendering: -webkit-optimize-contrast , en vain.

L'application sera une "rétro" 8-bits de style de jeu écrit en HTML5+JS pour faire comprendre ce dont j'ai besoin.


Pour illustrer, voici un exemple. (version live)

Supposons que j'ai un 21x21 sur la toile...

<canvas id='b' width='21' height='21'></canvas>

...qui a css qui rend l'élément 5 fois plus grande (105x105):

canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */

Je dessine un simple " X " sur la toile comme suit:

$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

Sur l'image de gauche est ce que le Chrome (14.0) rend. L'image de droite est ce que je veux (dessinés à la main pour des fins d'illustration).

Chrome interpolates scaled canvas elementsA non-interpolated version

146voto

namuol Points 4345

Dernière Mise À Jour: 2014-09-12

Est-il une toile de propriété ou les paramètres du navigateur, je peux la changer par programmation pour désactiver l'interpolation lors de la mise à l'échelle des éléments?

La réponse est peut-être un jour. Pour l'instant, vous devrez recourir à pirater des solutions de rechange pour obtenir ce que vous voulez.


image-rendering

Le projet de CSS3 contours d'une nouvelle propriété, image-rendering qui devrait faire ce que je veux:

L'image-rendu de la propriété fournit un indicateur de l'agent utilisateur sur les aspects d'une image sont les plus importants à conserver lorsque l'image est mise à l'échelle, à l'aide de l'agent utilisateur dans le choix d'un algorithme de mise à l'échelle.

La spécification décrit les trois valeurs acceptées: auto, crisp-edges, et pixelated.

pixélisé:

Lorsque l'échelle de l'image, le "plus proche voisin" ou similaire algorithme doit être utilisé, de sorte que l'image semble être simplement composé de très gros pixels. Lors de la mise à l'échelle vers le bas, c'est la même auto.

La norme? Croix-navigateur?

Puisque ce n'est qu'une ébauche, il n'y a aucune garantie que cela va devenir la norme. Prise en charge du navigateur est actuellement inégale, au mieux.

Le Mozilla Developer Network a un assez complète de la page consacrée à l'état actuel de l'art dont je recommande fortement la lecture.

Les développeurs de Webkit initialement choisi provisoirement mettre en œuvre ce qu' -webkit-optimize-contrast, mais Chromium/Chrome ne semble pas être à l'aide d'une version de Webkit qui la met en œuvre.

Mise à jour: 2014-09-12

Chrome 38 prend désormais en charge image-rendering: pixelated!

Firefox a un rapport de bug à ouvrir image-rendering: pixelated mis en œuvre, mais -moz-crisp-edges fonctionne pour l'instant.

La Solution?

La plupart de la croix-plate-forme, CSS seule solution à ce jour est donc:

canvas {
    image-rendering: optimizeSpeed;             // Older versions of FF
    image-rendering: -moz-crisp-edges;          // FF 6.0+
    image-rendering: -webkit-optimize-contrast; // Safari
    image-rendering: -o-crisp-edges;            // OS X & Windows Opera (12.02+)
    image-rendering: pixelated;                 // Awesome future-browsers
    -ms-interpolation-mode: nearest-neighbor;   // IE
}

Malheureusement, cela ne marchera pas sur tous les grands HTML5 plates-formes encore (Chrome, en particulier).

Bien sûr, on pourrait manuellement à l'échelle des images à l'aide du plus proche voisin d'interpolation sur haute résolution toile surfaces en javascript, ou même pré-échelle d'images côté serveur, mais dans mon cas, ce sera forbiddingly coûteux de sorte qu'il n'est pas une option viable.

ImpactJS utilise une texture de pré-mise à l'échelle technique pour obtenir autour de tout ce FUD. L'Impact du développeur, Dominic Szablewski, a écrit un très approfondie article à ce sujet (il a même fini par en citant cette question dans ses travaux de recherche).

Voir Simon réponse pour une toile à base de solution repose sur l' imageSmoothingEnabled de la propriété (non disponible dans les navigateurs plus anciens, mais plus simple qu'avant la mise à l'échelle et assez largement pris en charge).

Démonstration En Direct

Si vous souhaitez tester les propriétés CSS discuté dans le MDN article sur canvas éléments, j'ai fait ce violon qui devrait afficher quelque chose comme cela, floues ou pas, selon votre navigateur: a 4:1 (64x64 to 256x256) image of an isometric pixel-art style TV

69voto

Simon Sarris Points 33799

Nouvelle réponse 7/31/2012

C'est finalement dans la toile spec!

La spécification a récemment ajouté une propriété appelée imageSmoothingEnabled, qui par défaut est true et détermine si les images dessinées sur la non-entier coordonnées ou dessinés à l'échelle va utiliser un lisseur algorithme. Si elle est définie à l' false alors plus proche voisin est utilisé, la production d'une image moins lisse et au lieu de simplement faire de plus grands à la recherche de pixels.

Le lissage d'Image a été récemment ajouté à la toile de spécification et n'est pas pris en charge par tous les navigateurs, mais certains navigateurs ont mis en œuvre préfixé fournisseur versions de cette propriété. Sur le contexte, il existe, mozImageSmoothingEnabled dans Firefox et webkitImageSmoothingEnabled de Chrome et Safari, et la définition de ces à false va arrêter l'anti-aliasing de se produire. Malheureusement, au moment de la rédaction, IE9 et de l'Opéra n'ont pas mis en œuvre cette propriété, le vendeur préfixé ou autrement.


Aperçu: JSFiddle

Résultat:

enter image description here

11voto

Simon Sarris Points 33799

Edit 7/31/2012 - Cette fonctionnalité est maintenant dans la toile spec! Voir la réponse ici:

http://stackoverflow.com/a/11751817/154112

Vieux la réponse est ci-dessous pour la postérité.


Selon l'effet désiré, vous avez cette option:

var can = document.getElementById('b');
var ctx = can.getContext('2d');
ctx.scale(5,5);
$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

http://jsfiddle.net/wa95p/

Ce qui crée ce:

enter image description here

Probablement pas ce que vous voulez. Mais si vous êtes simplement à la recherche de zéro flou alors que serait le billet donc je vais l'offrir juste au cas où.

Plus difficile est d'utiliser la manipulation de pixels et d'écrire un algorithme pour le travail. Chaque pixel de la première image devient un 5x5 bloc de pixels sur la nouvelle image. Il ne devrait pas être trop dur à faire avec des données images.

Mais la Toile et CSS ne suffira pas à vous aider pour la mise à l'échelle de l'un à l'autre avec l'effet exact que vous désirez.

3voto

saviski Points 41

Dans google chrome, toile motifs d'image ne sont pas interpolées.

Voici un exemple de travail modifiées à partir de la namuol répondre http://jsfiddle.net/pGs4f/

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);

1voto

Timo Points 2732

Saviski du contournement expliqué ici est prometteuse, car elle fonctionne sur:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m de Windows 7
  • Chrome 18.0.1025.168 (Développeur Pour Construire 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Mais pas dans les cas suivants, mais le même effet peut être obtenu en utilisant le CSS de l'image-rendu:

  • Firefox 15.0.1 Mac OS X 10.6.8 (image-rendu:-moz-crisp-bords des œuvres dans le présent )
  • Opéra 12.02 Mac OS X 10.6.8 (image-rendu:-o-crisp-bords des œuvres dans le présent )
  • Opéra 12.02 Windows 7 (à l'image de rendu:-o-crisp-bords des œuvres dans le présent )

Les problématiques sont-elles, parce que ctx.XXXImageSmoothingEnabled n'est pas de travail et de l'image, le rendu n'est pas de travail:

  • Safari 5.1.7 Mac OS X 10.6.8. (image-rendu:-webkit-optimiser le contraste fonctionne PAS)
  • Safari 5.1.7 Windows 7 (à l'image de rendu:-webkit-optimiser le contraste fonctionne PAS)
  • IE 9 de Windows 7 (-ms-interpolation-mode:le plus proche voisin fonctionne PAS)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X