2010-08-10 13 views
26

Tengo un lienzo en mi página web; Creo un nuevo dato de Imagen en este lienzo y luego modifico un poco de píxel a través de myImgData.data [] array. Ahora me gustaría escalar esta imagen y agrandarla. Intenté escalando el contexto pero la imagen sigue siendo pequeña. ¿Es posible hacer esto? Gracias¿Cómo escalar un imageData en el lienzo HTML?

Respuesta

31

Puede dibujar el imageData en un nuevo lienzo, escalar el lienzo original y luego dibujar el nuevo lienzo en el lienzo original.

Algo como esto debería funcionar:

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); 

He aquí una demostración funcionamiento http://jsfiddle.net/Hm2xq/2/.

+2

Esto funciona perfectamente. – mikechambers

+10

Me gustaría agregar que puede hacer esto sin crear otro lienzo como ctx.drawImage (ctx.canvas, 0,0); dibuja el lienzo sobre sí mismo, y puede escalar a medida que dibuja esto. – Overcode

+3

pero esa escala también altera las coordenadas 10 x es 1.5 * 10. ¿Cómo se puede compensar por eso –

13

Necesitaba hacerlo sin la interpolación que provoca putImageData(), así que lo hice escalando los datos de la imagen en un nuevo objeto ImageData con el tamaño cambiado. No puedo pensar en ningún otro momento he pensado que el uso de los bucles anidados 5 era una buena idea:

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; 
} 

espero que al menos otro programador puede copiar y pegar esto en su editor mientras murmuraba, "No hay más que por la gracia de Dios, voy yo".

+0

También es posible usar más métodos de interpolación de calidad, como bilineal o spline. –

+3

@KvanTTT es totalmente cierto, aunque a veces quieres esos píxeles gruesos. –

+1

¿A qué se refiere la variable 'c'? –

12

Puede escalar el lienzo utilizando el método drawImage.

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

Esto escalaría la imagen para duplicar el tamaño y representar la parte noroeste de la misma. El escalado se logra con los parámetros tercero y cuarto del método drawImage, que especifican el ancho y el alto resultantes de la imagen.

Ver documentos en el MDN https://developer.mozilla.org/en-US/docs/DOM/CanvasRenderingContext2D#drawImage%28%29

11

Sé que es un viejo tema, pero como la gente como les puede resultar útil, agrego mi optimización al código 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; 
} 

Este código utiliza menos gira y funciona aproximadamente 30 veces más rápido. Por ejemplo, en un zoom de 100x de un área de 100 * 100, este código toma 250 ms mientras que el otro tarda más de 8 segundos.

1

@ La respuesta de Castrohenge funciona, pero como señala Muhammad Umer, desordena las coordenadas del mouse en el lienzo original después de eso. Si desea mantener la capacidad de realizar escalas adicionales (para recortar, etc.), entonces necesita utilizar un segundo lienzo (para escalar) y luego buscar los datos de imagen del segundo lienzo y ponerlos en el lienzo original. Como lo siguiente:

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; 
} 
+0

para, 'canvas.width', y' canvas.height', ¿dónde se define la variable 'canvas'? –

Cuestiones relacionadas