Manipular imágenes

facebook-svg gplus-svg twitter-svg

El <canvas> nos permite modificar, uno por uno, los píxeles de una imagen. Para esto tenemos a nuestra disposición tres propiedades y tres métodos() de <canvas>
Importante: si queremos experimentar manipulando imágenes en el <canvas> tenemos que hacerlo en un sitio web de verdad, como por ejemplo locahost.

  JavaScript Descripción Defecto
width imgData.width Devuelve el ancho del objeto ImageData, en píxeles  
height imgData.height Devuelve la altura del objeto ImageData, en píxeles  
data imageData.data Devuelve un objeto conteniendo todos los datos del objeto ImageData.  
createImageData() context.createImageData(ancho, alto); Crea un nuevo objeto ImageData en blanco. Toma dos argumentos: la anchura y la altura del objeto creado  
createImageData() context.createImageData(imgData); Crea un nuevo objeto ImageData con las mismas dimensiones que el objeto especificado por el argumanto imgData.  
getImageData() context.getImageData ( x, y, ancho, alto ); Devuelve un objeto ImageData que copia los datos de los píxeles del rectángulo especificado.  
putImageData() context.putImageData( imgData, x, y, [dirtyX, dirtyY, dirtyWidth, dirtyHeight] ); Pone los datos de la imagen (de un objeto ImageData especificado) de nuevo en el canvas  

Vea la chuleta con las propiedades y metodos() de canvas.

Un poco de teoría

4 bytes pixels

Los píxeles de una imagen "en crudo" tienen una "anchura" de 4 bytes, uno por cada componente R G B A. ( Red (rojo), Green (verde), Blue (azul) y Alpha (transparencia) ). Accediendo uno por uno los pixeles de una imagen podemos modificar estos componentes de color, y por tanto manipular el aspecto de las imágenes en el <canvas>.
Ojo: por razones de seguridad la imagen manipulada y el <script> que la manipula tienen que provenir de la misma página web. De otra manera el acceso al <script> será denegado y el navegador levantará una excepción de seguridad.

Un ejemplo fácil

A continuación dibujamos un cuadrado utilizando el método createImageData(). Ya lo se, sería mucho más fácil dibujarlo con fillRect(), pero es solo para demonstrar como podemos dibujar una imagen sencilla partiendo prácticamente desde cero.

  • 1. El método createImageData(anchura , altura) crea un nuevo objeto ImageData en blanco, de anchura y altura dadas.
  • 2. En el siguiente paso iremos de pixel en pixel modificando uno por uno el valor de los componentes RGBA.
    Como ya hemos visto cada pixel tiene una "anchura" de 4 bytes, donde el primer byte representa el rojo, el segundo representa el verde, el tercero el azul y el cuarto es el componente alpha o el grado de transparencia.
    Siendo bytes pueden tomar valores entre 0 y 255.
    En el siguiente ejemplo manipulamos cada pixel para que:
    • el rojo = 255; (100%)
    • el verde = 0;(ausente)
    • el azul = 0; (ausente)
    • alpha = 255; (totalmente opaco)
  • 3. Después de manipular los pixeles volvemos a colocar la imagen en el <canvas> con putImageData().
    El método putImageData() toma ( en este caso ) tres argumentos: la imagen manipulada y las coordenadas x e y de donde poner la imagen en el <canvas>
Su navegador no soporta canvas :( 

		var canvas = document.getElementById("lienzo");
				if (canvas && canvas.getContext) {
				var ctx = canvas.getContext("2d");
				if (ctx) {
					// 1. crea un objeto ImageData en blanco;
					var imgData=ctx.createImageData(100,100);
					// 2. para cada pixel modifica el valor de los componentes RGBA;
					for (var i = 0; i < imgData.data.length; i+= 4)
							{
							imgData.data[i+0]=255;	// rojo = 100%;
							imgData.data[i+1]=0;	// verde - ausente;
							imgData.data[i+2]=0;	// azul - ausente;
							imgData.data[i+3]=255;	// alpha - opaco;
							}
					// 3. coloca la nueva imagen en el canvas;		
					ctx.putImageData(imgData,75,10);
				}
		}
Su navegador no soporta canvas :(

ImageData.width e ImageData.heught

En el ejemplo anterior hemos utilizado la propiedad data del objeto ImageData  que representa un array unidimensional que contiene los datos rgba de cada pixel. La longitud de este array es igual al número de pixeles multiplicado por 4. ( Ya hemos visto que cada pixel tiene una "anchura" de 4 bytes. )

Otra manera de hacer lo mismo es utilizando las propiedades width ( anchura ) y height ( altura ) del objeto ImageData.

Si en el ejemplo anterior hemos utilizado un solo bucle for, ahora necesitamos utilizar dos bucles for anidados: uno para las coordenadas en x y otro para las coordenadas en y de cada pixel.

for (var y = 0; y < imgData.height; y ++) { //imgData.height = 250
     for (var x = 0; x < imgData.width; x ++) { //imgData.width = 250
        // aquí va el código
     }
}

La fórmula para encontrar el índex de los datos en el array ImageData.data es:

var i = (y*imgData.width + x)*4;

Todo lo demás queda igual que antes:

for (var y = 0; y < imgData.height; y ++) { //imgData.height = 250
   for (var x = 0; x < imgData.width; x ++) { //imgData.width = 250
   
    var i = (y*imgData.width + x)*4;
  
    imgData.data[i + 0] = 255; // rojo = 100%;
    imgData.data[i + 1] = 0; // verde - ausente;
    imgData.data[i + 2] = 0; // azul - ausente;
    imgData.data[i + 3] = 255; // alpha - opaco;
  }
  }

ctx.putImageData(imgData,75,75);

Vea el código en CodePen

See the Pen imgData.width, imgData.heigh* by Gabi (@enxaneta) on CodePen.