web-dev-qa-db-fra.com

Comment faire échec d'une imagétata en toile HTML?

J'ai une toile dans ma page Web; Je crée une nouvelle image d'image dans cette toile puis je modifie un pixel via myimgdata.data [] tableau. Maintenant, je voudrais accumuler cette image et le rendre plus grand. J'ai essayé en éteignant le contexte, mais l'image reste petite. Est-il possible de faire cela? Merci

31
Masiar

Vous pouvez dessiner les ImageData sur une nouvelle toile, ce qui permet de réduire la toile d'origine puis de dessiner la nouvelle toile à la toile d'origine.

Quelque chose comme ça devrait fonctionner:

var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = $("<canvas>")
    .attr("width", imageData.width)
    .attr("height", imageData.height)[0];

newCanvas.getContext("2d").putImageData(imageData, 0, 0);

context.scale(1.5, 1.5);
context.drawImage(newCanvas, 0, 0);

Voici une démonstration fonctionnelle http://jsfiddle.net/hm2xq/2/ .

35
Castrohenge

Je sais que c'est un vieil sujet, mais comme les gens comme peuvent le trouver utiles, j'ajoute mon optimisation au code de Rodarmor:

function scaleImageData(imageData, scale) {
    var scaled = ctx.createImageData(imageData.width * scale, imageData.height * scale);
    var subLine = ctx.createImageData(scale, 1).data
    for (var row = 0; row < imageData.height; row++) {
        for (var col = 0; col < imageData.width; col++) {
            var sourcePixel = imageData.data.subarray(
                (row * imageData.width + col) * 4,
                (row * imageData.width + col) * 4 + 4
            );
            for (var x = 0; x < scale; x++) subLine.set(sourcePixel, x*4)
            for (var y = 0; y < scale; y++) {
                var destRow = row * scale + y;
                var destCol = col * scale;
                scaled.data.set(subLine, (destRow * scaled.width + destCol) * 4)
            }
        }
    }

    return scaled;
}

Ce code utilise moins de boucles et fonctionne environ 30 fois plus vite. Par exemple, sur un zoom 100X de la zone de 100 * 100, ces codes prend 250 ms tandis que l'autre prend plus de 8 secondes.

17
user3079576

J'avais besoin de le faire sans l'interpolation que Putitimagedata () provoque, donc je l'ai fait en éteignant les données d'image dans un nouvel objet imagétata redimensionné. Je ne peux pas penser à d'autres fois où j'avais pensé que l'utilisation de 5 boucles nichées était une bonne idée:

function scaleImageData(imageData, scale) {
  var scaled = c.createImageData(imageData.width * scale, imageData.height * scale);

  for(var row = 0; row < imageData.height; row++) {
    for(var col = 0; col < imageData.width; col++) {
      var sourcePixel = [
        imageData.data[(row * imageData.width + col) * 4 + 0],
        imageData.data[(row * imageData.width + col) * 4 + 1],
        imageData.data[(row * imageData.width + col) * 4 + 2],
        imageData.data[(row * imageData.width + col) * 4 + 3]
      ];
      for(var y = 0; y < scale; y++) {
        var destRow = row * scale + y;
        for(var x = 0; x < scale; x++) {
          var destCol = col * scale + x;
          for(var i = 0; i < 4; i++) {
            scaled.data[(destRow * scaled.width + destCol) * 4 + i] =
              sourcePixel[i];
          }
        }
      }
    }
  }

  return scaled;
}

J'espère qu'au moins un autre programmeur peut copier et coller cela dans leur éditeur en marmonnant, "là-bas, mais pour la grâce de Dieu, allez I."

17
Casey Rodarmor

Vous pouvez accumuler la toile à l'aide de la méthode de DrawImage.

context = canvas.getContext('2d');
context.drawImage( canvas, 0, 0, 2*canvas.width, 2*canvas.height );

Cela permettrait d'élaborer l'image pour doubler la taille et rendrait la partie nord-ouest de celle-ci à la toile. La mise à l'échelle est obtenue avec les troisième et quatrième paramètres à la méthode de cuisson, qui spécifie la largeur et la hauteur résultant de l'image.

Voir Docs à MDN https://developer.mozilla.org/en-us/docs/dom/canvasRendingContext28%29

13
Sixtease

@ La réponse de Castrohenge fonctionne, mais comme le souligne Muhammad Umer, il gâche les coordonnées de la souris sur la toile d'origine une fois cela. Si vous souhaitez maintenir la possibilité d'effectuer des échelles supplémentaires (pour le recadrage, etc.), vous devez utiliser une seconde toile (pour la mise à l'échelle), puis récupérer les données d'image de la deuxième toile et la mettre dans la toile d'origine. Ainsi:

function scaleImageData(imageData, scale){
    var newCanvas = $("<canvas>")
      .attr("width", imageData.width)
      .attr("height", imageData.height)[0];

    newCanvas.getContext("2d").putImageData(imageData, 0, 0);

    // Second canvas, for scaling
    var scaleCanvas = $("<canvas>")
      .attr("width", canvas.width)
      .attr("height", canvas.height)[0];

    var scaleCtx = scaleCanvas.getContext("2d");

    scaleCtx.scale(scale, scale);
    scaleCtx.drawImage(newCanvas, 0, 0);

    var scaledImageData =  scaleCtx.getImageData(0, 0, scaleCanvas.width, scaleCanvas.height);

    return scaledImageData;
}
2
Chris Holmes