martes, 29 de octubre de 2013

Rotar una imagen

A partir de lo que hemos aprendido en los dos posts anteriores: Transformaciones en el canvas y Guardar y restaurar el contexto del canvas vamos a escribir una función con la que rotar fácilmente una imagen.

  • drawImageR(context, image, x, y, angle)
La hemos llamado drawImageR para diferenciarla de drawImage y para dar una pista de que sirve para rotar imágenes. Los argumentos son el contexto del canvas en el que dibujar, la imagen, las coordenadas x, y en las cuales dibujar la imagen y el angulo de rotación en radianes (respecto al centro de la imagen).
La forma de usarla difiere de la función drawImage porque drawImage es un método del contexto del canvas, mientras que drawImageR no, por lo tanto, sea ctx el contexto del canvas, haremos:
ctx.drawImage(...)
o
drawImageR(ctx, ...)

La función se puede modificar y ampliar para cubrir otras necesidades específicas, como por ejemplo rotar la imagen respecto a otro punto distinto del centro o dibujar un trozo específico de la imagen, como permiten las versiones con más parametros de drawImage.

La definición de drawImageR es la siguiente:
  function drawImageR(context, image, x, y, angle){
 var w_half = image.width/2;
 var h_half = image.height/2;

 context.save();
 context.translate(x + w_half, y + h_half);
 context.rotate(angle);
 context.drawImage(image, -w_half, -h_half);
 context.restore(); 
  }

Ejemplo

Un ejemplo sencillo, suponiendo que en la carpeta /images tenemos la imagen 1.jpg (un cuadrado con la mitad izquierda roja y la mitad derecha verde) usaremos la función ya conocida loadImages para cargarla y después dibujaremos una copia rotada y otra sin rotar, en la misma posición.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
 <canvas id="my_canvas" width="300px" height="200px"
 style="border:1px solid #000000;"></canvas> 
 <script type="text/javascript">
  var canvas = document.getElementById('my_canvas');
  var ctx = canvas.getContext('2d');
  var images = loadImages('./images/1.jpg', load_done);
  var cuadrado = images[0];
      
  function drawImageR(context, image, x, y, angle){
 var w_half = image.width/2;
 var h_half = image.height/2;

 context.save();
 context.translate(x + w_half, y + h_half);
 context.rotate(angle);
 context.drawImage(image, -w_half, -h_half);
 context.restore(); 
  }
  
  function loadImages() { //images and callback
 var n = arguments.length - 1;
 var callback = arguments[n]
 var images = new Array();
 var count = 0;
 
 for (i = 0; i < n; i++) {
  images[i] = new Image();
  images[i].onload = function(){
   count++;
   if (count == n){
    callback ();
   };
  };
  images[i].src = loadImages.arguments[i];
 };
 return images;  
}

 function load_done() {
  drawImageR(ctx, cuadrado, 20, 50, 45*Math.PI/180);
  ctx.drawImage(cuadrado, 20, 50);
 }
 
 </script> 
</body>
</html>

martes, 1 de octubre de 2013

Guardar y restaurar el contexto del canvas

Esta entrada continua la entrada anterior: Transformaciones en el canvas.
El contexto del canvas tiene una pila de estados. El estado del contexto del canvas contiene los valores actuales de distintos parámetros que se han fijado para el canvas:
  • Las transformaciones: traslación, rotación, escalado
  • La región de dibujo (clipping region)
  • Los valores actuales de los atributos: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline. 
¿Cómo recuperamos el estado del canvas después de haber hecho una serie de modificaciones? Para ello el estado del contexto se puede almacenar en una pila LIFO (Last In First Out). Lo que haremos para recuperar el estado que teníamos antes de hacer modificaciones será lo siguiente:
  1. guardar el estado
  2. hacer las modificaciones
  3. dibujar lo que queramos con los nuevos ajustes
  4. recuperar el estado
Para ello el contexto del canvas dispone de dos funciones:
  • context.save(): guarda el estado actual en la parte superior de la pila
  • context.restore(): saca (y aplica al contexto) el estado de la parte superior de la pila

Ejemplo

<!DOCTYPE html>
<html>
<head>
</head>
<body>
 <canvas id="my_canvas" width="300px" height="200px"
 style="border:1px solid #000000;"></canvas> 
 <script type="text/javascript">
  var canvas = document.getElementById('my_canvas');
  var ctx = canvas.getContext('2d');
      
  var x = 10;
  var y = 10;
  var w = 50;
  var h = 50;
  

  // estado original: 0
  ctx.fillRect(x, y, w, h);
  ctx.save();
 
  // estado 1 
  ctx.fillStyle = "#ff0000"; // rojo
  ctx.fillRect(x+w, y, w, h);
  ctx.save();
  
  // estado 2
  ctx.fillStyle = "#00ff00"; // verde
  ctx.fillRect(x+2*w, y, w, h);
  
  // recuperamos el estado 1
  ctx.restore();
  ctx.fillRect(x+3*w, y, w, h);
  
  // recuperamos el estado 0
  ctx.restore();
  ctx.fillRect(x+4*w, y, w, h);
 
 </script> 
</body>
</html>
 


En este ejemplo únicamente hemos modificado el color de relleno, pero el mismo principio se aplica a cualquiera de los parametros contenidos en el contexto.

Esta entrada continua la entrada anterior: Transformaciones en el canvas.