web-dev-qa-db-fra.com

HTML5 - Canvas, drawImage () dessine une image floue

J'essaie de dessiner l'image suivante sur une toile mais elle semble floue malgré la définition de la taille de la toile. Comme vous pouvez le voir ci-dessous, l'image est nette et claire alors que sur la toile, elle est floue et pixélisée.

enter image description here

et voici à quoi cela ressemble (celui de gauche étant l'original et celui de droite étant la toile dessinée et floue.)

enter image description here

Qu'est-ce que je fais mal?

console.log('Hello world')

var c = document.getElementById('canvas')
var ctx = c.getContext('2d')
var playerImg = new Image()

// http://i.imgur.com/ruZv0dl.png sees a CLEAR, CRISP image
playerImg.src = 'http://i.imgur.com/ruZv0dl.png'
playerImg.width = 32
playerImg.height = 32

playerImg.onload = function() {
  ctx.drawImage(playerImg, 0, 0, 32, 32);
};
#canvas {
  background: #ABABAB;
  position: relative;
  height: 352px;
  width: 512px;
  z-index: 1;
}
<canvas id="canvas" height="352" width="521"></canvas>
14
Zeng Cheng

La raison pour laquelle cela se produit est à cause de l'anticrénelage. Définissez simplement imageSmoothingEnabled sur false comme

context.imageSmoothingEnabled = false;

Voici un verson jsFiddle

jsFiddle: https://jsfiddle.net/mt8sk9cb/

var c = document.getElementById('canvas')
var ctx = c.getContext('2d')
var playerImg = new Image()

// http://i.imgur.com/ruZv0dl.png sees a CLEAR, CRISP image
playerImg.src = 'http://i.imgur.com/ruZv0dl.png'

playerImg.onload = function() {
  ctx.imageSmoothingEnabled = false;
  ctx.drawImage(playerImg, 0, 0, 256, 256);
};
22
Canvas

Votre problème est que vos contraintes css de canvas{width:512}vs la propriété canvas width=521fera votre navigateur rééchantillonner l'ensemble du canevas.

Pour l'éviter, supprimez ces déclarations CSS.

var c = document.getElementById('canvas')
var ctx = c.getContext('2d')
var playerImg = new Image()

// http://i.imgur.com/ruZv0dl.png sees a CLEAR, CRISP image
playerImg.src = 'http://i.imgur.com/ruZv0dl.png'
playerImg.width = 32
playerImg.height = 32

playerImg.onload = function() {
  ctx.drawImage(playerImg, 0, 0, 32, 32);
};
#canvas {
  background: #ABABAB;
  position: relative;
  z-index: 1;
}
<canvas id="canvas" height="352" width="521"></canvas>

De plus, si vous rééchantillonniez l'image (de 32x32 à une autre taille), la solution de @canvas aurait été la voie à suivre.

12
Kaiido

Alors que je rencontrais cet ancien article pour certains de mes problèmes, voici encore plus d'informations sur les images floues à superposer à la solution 'imageSmoothingEnabled'.

C'est plus spécifiquement pour le cas d'utilisation du rendu spécifique au moniteur et seules certaines personnes auront rencontré ce problème si elles ont essayé de restituer des graphiques de qualité rétine dans leur toile avec des résultats décevants.

Essentiellement, les moniteurs haute densité signifient que votre toile doit s'adapter à cette densité supplémentaire de pixels. Si vous ne faites rien, le canevas ne rendra que suffisamment d'informations sur les pixels dans son contexte pour représenter un rapport de pixels de 1.

Ainsi, pour de nombreux moniteurs modernes qui ont des ratios> 1, vous devez modifier le contexte de votre canevas pour tenir compte de ces informations supplémentaires, mais conserver la largeur et la hauteur normales de votre canevas.

Pour ce faire, il vous suffit de définir la largeur et la hauteur du contexte de rendu sur: largeur et hauteur cible * window.devicePixelRatio.

canvas.width = target width * window.devicePixelRatio;
canvas.height = target height * window.devicePixelRatio;

Ensuite, vous définissez le style du canevas pour dimensionner le canevas dans des dimensions normales:

canvas.style.width = `${target width}px`;
canvas.style.height = `${target height}px`;

Enfin, vous rendez l'image à la taille de contexte maximale autorisée par l'image. Dans certains cas (comme le rendu d'images svg), vous pouvez toujours obtenir une meilleure qualité d'image en rendant l'image aux dimensions de pixelRatio:

ctx.drawImage(
    img, 0, 0, 
    img.width * window.devicePixelRatio, 
    img.height * window.devicePixelRatio
  );

Alors pour montrer ce phénomène, j'ai fait un violon. Vous ne verrez PAS de différence dans la qualité du canevas si vous êtes sur un moniteur pixelRatio proche de 1.

https://jsfiddle.net/ufjm50p9/2/

1
Diniden

En plus de la réponse @canvas.

context.imageSmoothingEnabled = false;

Fonctionne parfaitement. Mais dans mon cas, changer la taille du canevas réinitialiser cette propriété à true.

window.addEventListener('resize', function(e){
    context.imageSmoothingEnabled = false;
}, false)
1
aleha

Le code suivant fonctionne pour moi:

img.onload = function () {
  canvas.width = img.width;
  canvas.height = img.height;
  context.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
};
img.src = e.target.result;  // your src
1
Jeff Tian