Comment mettre à l'échelle une imageData dans une toile HTML?

j'ai une toile dans ma page web; Je crée une nouvelle Image dans cette toile puis je modifie un pixel à travers myImgData.données tableau []. Maintenant, je voudrais mettre cette image à l'échelle et la rendre plus grande. J'ai essayé de mettre à l'échelle le contexte mais l'image reste petite. Est-il possible de faire cela? Merci

29
demandé sur Masiar 2010-08-10 15:21:05

5 réponses

Vous pouvez dessiner l'imageData sur une nouvelle toile, mettre à l'échelle la toile originale et ensuite dessiner la nouvelle toile sur la toile originale.

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émo fonctionnelle http://jsfiddle.net/Hm2xq/2/.

32
répondu Castrohenge 2010-08-10 13:35:45

j'avais besoin de le faire sans l'interpolation que putImageData() provoque, donc je l'ai fait en mettant à l'échelle les données d'image dans un nouvel objet ImageData redimensionné. Je ne peux pas penser à tout autre moment, j'ai pensé que l'utilisation de 5 boucles for imbriqué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 pourra copier et coller ceci dans son éditeur en murmurant, "là, mais pour la grâce de Dieu va I."

16
répondu Casey Rodarmor 2012-02-04 05:36:36

Vous pouvez dimensionner la toile en utilisant la méthode drawImage.

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

ceci aurait l'échelle de l'image pour doubler la taille et rendre la partie nord-ouest de celui-ci à la toile. La mise à l'échelle est réalisée avec les troisième et quatrième paramètres de la méthode drawImage, qui spécifient la largeur et la hauteur résultantes de l'image.

voir docs à MDN https://developer.mozilla.org/en-US/docs/DOM/CanvasRenderingContext2D#drawImage%28%29

13
répondu Sixtease 2012-12-18 16:06:48

je sais que c'est un vieux sujet, mais puisque les gens comme peuvent le trouver utile, j'ajoute mon optimisation du 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 court environ 30 fois plus vite. Par exemple, sur un zoom 100x 100*100, ce codes faut 250 ms, tandis que l'autre prend plus de 8 secondes.

13
répondu user3079576 2013-12-08 10:17:14

la réponse de@Castrohenge fonctionne, mais comme le souligne Muhammad Umer, elle perturbe les coordonnées de la souris sur la toile originale après cela. Si vous souhaitez maintenir la capacité d'effectuer des balances supplémentaires (pour la coupe, etc. ensuite, vous devez utiliser une deuxième toile (pour la mise à l'échelle), puis récupérer les données d'image de la deuxième toile et les mettre dans la toile originale. Comme ceci:

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;
}
1
répondu Chris Holmes 2016-11-23 19:41:12