¿Qué es el Canvas?, uso básico del API Canvas en HTML y tutoriales

- 👤 Andrés Cruz

¿Qué es el Canvas?, uso básico del API Canvas en HTML y tutoriales

El Canvas es una de las tecnologías más potentes que podemos emplear en el ámbito web, el canvas no es más que un lienzo que permite la creación de gráficos, los cuales (los gráficos) están compuestos de figuras simples, las primitivas de siempre, líneas, círculos/esferas, cuadrados/rectángulos como veremos en esta misma entrada un poco más adelante en los cuales vamos a profundizar en el uso del Canvas, además de tutoriales que les dejaremos para que vean posibles usos sobre el Canvas.

Una vez aclarado que es el canvas, lo siguiente que tenemos que conocer es sobre su compatibilidad; muchos navegadores tienen soporte hoy en día para trabajar con la API de Canvas; los navegadores principales como Google Chrome y Firefox e incluso los navegadores de Microsoft soportan esta potente tecnología que nos permite dibujar gráficas tanto sencillas como simples, nos permite realizar composiciones de imágenes o fotografías como vimos en otras entradas:

Y también el renderizado de vídeo en tiempo real; así que el Canvas es básicamente eso, un lienzo en donde podemos realizar dibujos.

Todo comienza a través de la etiqueta <canvas> que se habilita un área o mejor dicho lienzo en donde es posible dibujar, escribir o incluso renderizar imágenes a través de scripts realizados con JavaScript que es el lenguaje de programación seleccionado para trabajar con esta tecnología:

<canvas id="myCanvas" width="500" height="500" >
<p>Su navegador no soporta canvas :(</p>
</canvas>

Con el canvas es posible crear todo tipo de gráficos simples o complejos a partir de primitivas básicas como círculos, óvalos, rectángulos líneas y polígonos además de fácilmente animables con el método requestAnimationFrame e inclusive el canvas es extendible hasta con los eventos de teclado y ratón, además de otras muchísimas otras características no explicadas en esta entrada que de otra forma (con CSS) serían prácticamente imposibles (o muy difíciles) de realizar como vimos antes.

Soporte del canvas en los navegadores

Los navegadores modernos desde hace un buen tiempo cuenta con soporte nativo para la etiqueta canvas; sin embargo, es recomendable verificar el soporte; como muchas otras etiquetas, podemos verificar el soporte desde la misma etiqueta; es decir cualquier cosa que se encuentre entre las etiquetas de apertura y cierre de canvas será interpretado por navegadores que no soportan la etiqueta:

  <canvas>
    Su navegador no soporta Canvas
  </canvas>

A nivel de JavaScript, podemos realizar la siguiente validación para verificar si está soportada el API de Canvas en los navegadores:

function isCanvasSupported(){ 
  var elem = document.createElement('canvas'); 
  return !!(elem.getContext && elem.getContext('2d')); 
}

A lo que nos lleva a que el canvas debe tener tres atributos aunque uno de ellos los puedes definir también por el CSS; el primero es el ID que es la forma en la que lo accedemos, y los otros son el ancho y el alto definidos por el width y el height respectivamente.

Algunas ventajas de usar el canvas en nuestras aplicaciones

  • Animable. Cada objeto que dibujamos en el canvas puede ser animado.
  • Interactivo. El Canvas es 100% interactivo y responde a todas las acciones de teclados y ratones.
  • Flexible. Podemos dibujar cualquier cosa en el Canvas, imágenes, líneas, figuras geométricas, polígonos, etc y animar cada uno de esos objetos.
  • Soporte de los navegadores. La mayoría de los navegadores modernos desde hace mucho que soportan el canvas.
  • El canvas es un estándar. Como no lo son otras tecnologías como el moribundo Flash y Silverlight, Canvas forma parte del HTML5 y cualquier navegador que se respete debe darle soporte.
Cualquier cosa que escribamos dentro de las etiquetas canvas solamente será interpretado (mostrado) en navegadores que no soportan la etiqueta <canvas>.

Ejemplos y Tutoriales sobre el Canvas: ¿Cómo funciona la etiqueta canvas?

Finalmente, vayamos a la parte interesante de todo esto del canvas y empecemos a realizar nuestro primer ejemplo.

Con tres sencillos pasos podemos comenzar a trabajar con esta etiqueta:

1. Referenciando el canvas del DOM del HTML con nuestro JavaScript

Lo primero es obtener una referencia al canvas con el cual deseamos trabajar; en este caso, la etiqueta <canvas> tiene el identificador myCanvas:

var myCanvas = document.getElementById("myCanvas")

2. Obteniendo el contexto del canvas vía JavaScript

Para realizar cualquier operación con el canvas , entiéndase dibujar gráficos y/o imágenes debemos obtener el contexto del elemento canvas y de una vez acceder a la API:

El acceso al contexto del canvas proporciona todos los métodos y propiedades para poder dibujar en el mismo.

var ctx=c.getContext("2d");

3. Dibujando primitivas

 Ahora si, podemos empezar a dibujar sobre nuestro canvas; veamos una serie de ejemplos que ejemplifican el uso del canvas.

3.1 Dibujando una línea con canvas

 El ejemplo o experimento más sencillo que podemos hacer consiste en dibujar una simple línea; el Hola Mundo en el mundo del Canvas: para ello necesitamos los siguientes métodos:

  • moveTo(x,y) punto de comienzo de la línea.
  • lineTo(x,y) punto final de la línea.
  • stroke() dibuja la línea.

 

 

 3.2 Dibujando un círculo con canvas

 Para dibujar un círculo en el canvas se debe usar los siguientes métodos: 

  • Un Path es un conjunto de dibujos que realizamos dentro de un canvas; para eso debemos de utilizar el método beginPath() de esta forma damos por terminado un Path cuando volquemos su contenido con el método closePath(); nada en el path será dibujado hasta que se indique al contexto que dibuje el trazado stroke().
  • arc(x,y,r,inicio,final) dibuja un círculo en el canvas.
    • 'x' y 'y' nos indican el centro del círculo.
    • 'r' radio del círculo.
    • 'inicio' y 'final' ángulo de comienzo y final respectivamente.
  • lineTo(x,y) punto final de la línea.
  • stroke() dibuja la línea.

 3.3 Dibujando un texto con canvas

 Para dibujar existen dos métodos texto con algún formato dentro del canvas.

  • font permite definir la fuente del texto.
  • fillText(texto,x,y) el texto a dibujar en el canvas y su posición dentro del canvas.
  • strokeText(texto,x,y) permite dibujar un texto sin relleno en el canvas dado la posición "x" y "y".
  • stroke() dibuja la línea.

 

 

 3.4 Dibujando una imagen con canvas

Es posible que te preguntes cuál es el objetivo de dibujar una imagen en un canvas aparte de poder mezclarla con otras primitivas y/o imágenes, además de esto podemos alterar cada uno de los píxeles que componen a la imagen y aplicar algún Procesamiento Digital de Imágenes; eso entre otros experimentos que ya señalamos en otros tutoriales relacionados.

Dibujar una Línea en Loop (ciclo) con HTML5 Canvas

Dibujar una Línea en Loop (ciclo) con HTML5 Canvas

Ver demo Descargar Fuente

En este artículo veremos cómo dibujar una línea en un Loop o ciclo en HTML5; específicamente, con la API de Canvas; aunque ya la API de Canvas ofrece primitivas para dibujar una línea (lineTo()), en este ejercicio pintaremos una línea a partir de cuadrados; de tamaños variables, los cuales serán los "pixeles" que conforman a nuestra línea; para dibujar un cuadrado emplearemos la siguiente función:

ctx.fillRect(X,Y,Width,Height);
  • X: La coordenada X de la esquina superior izquierda del rectángulo.
  • Y: La coordenada Y de la esquina superior izquierda del rectángulo.
  • Width: Ancho del rectángulo en pixeles.
  • Height: Largo del rectángulo en pixeles.

Dibujando la línea con la API de Canvas

Definimos el tamaño del Canvas en pixeles; el Canvas va a ser un cuadrado:

var tamCanvas = 360;

Lo siguiente es definir de cuantos "pixeles" va a constar la línea y el tamaño de los mismos:

var numCuadrados = 10;
var tam = 100;

Ahora falta definir el espaciado entre las "píxeles"; el cual será menor a medida de que aumentemos el número de rectángulos:

var espaciado = (tamCanvas-tam)/(numCuadrados-1);

Ahora realizamos un ciclo en donde dibujaremos los "pixeles" que conformarán la línea:

for(var i=0; i <numCuadrados; i++){
    ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; 
    ctx.fillRect(i*espaciado, i*espaciado, tam, tam);
}

Ver demo Descargar Fuente

Ejemplo interactivo

Si te han quedado dudas del funcionamiento de los parámetros anteriores, en este ejemplo podrás variar el valor de cada parámetro:

 

Recortes de imágenes (crop) con HTML5, Canvas y jQuery

Ver demo Descargar Fuente

Recortes de imágenes (crop) con HTML5, Canvas y jQuery

Ver demo Descargar Fuente

Poder cortar imágenes cuya operación también es conocida como crop puede ser muy útil en determinados casos, poder subdividir imágenes en trozos es una operación muy común hoy en día en cualquier ambiente y puede haber muchos casos en la que quieras que una aplicación web deba aplicar el recorte sobre una imagen y luego poder descargarla.

En este artículo veremos cómo recortar imágenes y guardarlas en nuestra computadora o dispositivo móvil con HTML5 y jQuery; en específico usaremos las siguientes tecnologías:

  • Canvas y su API en JavaScript para cortar, cargar y guardar la imagen.
  • JQuery: para el manejo de los eventos y llamadas a algunas funciones para darnos algo de soporte.

Funcionamiento del experimento de recorte de imágenes

El funcionamiento es sencillo y la podemos explicar de la siguiente manera:

  • El usuario realiza un primer clic sobre el canvas; capturamos las coordenadas del clic.
  • El usuario arrastra el ratón (sin tener el clic presionado) hasta localizarse en el punto de interés; a medida que se desplaza sobre el Canvas se mostrará un hover que representa el área de interés del corte ubicado desde el primer clic.
  • El usuario realiza un segundo clic sobre el canvas; capturamos las coordenadas del clic.
  • Es generada la imagen a partir del canvas.

Sigue el mismo procedimiento que los procesadores de imágenes como GIMP o Photoshop.

El método drawImage()

El método drawImage() permite dibujar una imagen, Canvas o video dentro de un Canvas (más información clic aquí); recibe como parámetros obligatorios:

  • Elemento: Imagen, video o canvas a usar.
  • X: Coordenada X que indica a partir de qué punto de la imagen se dibujó en el canvas.
  • Y: Coordenada Y que indica a partir de qué punto de la imagen se dibujó en el canvas.

El modo de la función varía según la cantidad de parámetros que le pasemos:

  • drawImage(img,x,y): Se pinta la imagen en el Canvas a partir de las coordenadas X y Y.
  • drawImage(img,x,y,width,height): Es copiada la imagen a partir de los puntos definidos por "x" y "y" con la anchura y altura definida por width y height.
  • drawImage(img,sx,sy,swidth,sheight,x,y,width,height): Es cortada la imagen a partir de los puntos sx y sy con la anchura y altura definida por swidth y sheight, luego es copiada la imagen al Canvas a partir de los puntos definidos por "x" y "y" con la anchura y altura definida por width y height.

1. Variables globales e inicialización

En esta parte definiremos las variables utilizadas para la elaboración de este ejemplo; pasaré por alto su explicación ya que la funciones de las mismas son explicadas en los comentarios del código mostrado a continuación:

//*** variables globales
// canvas y su contexto
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// imagen en donde se colocará la imagen cortada
var canvasImg = document.getElementById('canvasImg');
// ruta a una imagen fuente
var imgSource = "image.jpg";
// punto X y Y del primer clic sobre el canvas
var iniX;
var iniY;
// punto X y Y del segundo clic sobre el canvas
var endX;
var endY;
// anchura y altura calculada a partir del primer y segundo clic
var imgW;
var imgH;
// hover que se surperpondran sobre el canvas segun la seleccion del usuario
var hover = document.getElementById('hoverCut');
// inicializo los componentes para el recorte de la imagen
function init() {
	// primer clic del usuario que indica la zona que voy a recortar
	iniX = -1;
	iniY = -1;
	// primer clic del usuario que indica la zona que voy a recortar
	endX = -1;
	endY = -1;
	// anchura de la imagen recortada
	imgW = -1;
	imgH = -1;
	// indica si coloco el hover
	hoverBol = false;
	// div hover
	$(hover).css("width", 0);
	$(hover).css("height", 0);
}

El método init() permite inicializar las variables y deshabilitar el hover (estableciendo su anchura y altura en cero); se realizará una llamada a este método por cada recorte que realice el usuario sobre el Canvas.

2. Dibujando una imagen en el Canvas

Ahora es definido un método que permita cargar una imagen fuente a un Canvas para poder manipularlo:

// cargo el contenido del canvas hacia un tag img
function loadImageToCanvas() {
    // creo un objeto de tipo Image y se le asigna una imagen fuente
    newImg = new Image();
    newImg.src = imgSource;
    // pinto la imagen en el canvas solo si se ha terminado de cargar 
    newImg.onload = function() {
        //reescalo el canvas al tamano de la imagen
        canvas.width = newImg.width;
        canvas.height = newImg.height;
        ctx.drawImage(newImg, 0, 0);
    };
}
  • En las líneas 4 y 5 creamos un objeto de tipo Image y le asignamos una imagen fuente.
  • En las líneas 10, 11, 12; luego de que este cargada la imagen es escalado el Canvas a las dimensiones de la imagen y se pinta la imagen en el Canvas.

3. Retornando el Contenido del Canvas hacia una Tag img (imagen)

Antes pasamos el contenido de una imagen hacia el Canvas; ahora haremos lo contrario; el método permitirá cargar el contenido del Canvas hacia una imagen; también se copiará el contenido de una imagen en un Tag a para poder descargar la imagen cortada (la final o generada por la operación de corte del usuario).

    // cargo la imagen hacia el canvas
    // guardo el canvas en una imagen 
    function saveCanvasToImage() { 
        var dataURL = canvas.toDataURL(); 
        canvasImg.src = dataURL; 
        document.getElementById("downloadImage").href = dataURL;
    }

4. Evento clic en el Canvas

El siguiente paso consiste en capturar dos clic del usuario sobre el Canvas; los mismo permitirán calcular el área rectangular para recortar la imagen:

  // clic sobre el canvas
    $(canvas).click(function(e) {
        var offset = $(this).offset();
        auxX = e.clientX - offset.left + $("body").scrollLeft();
        auxY = e.clientY - offset.top + $("body").scrollTop();
        // primer clic
        if (iniX < 0) {
            // primer punto
            iniX = auxX;
            iniY = auxY;
            $(hover).css("left", e.clientX + $("body").scrollLeft());
            $(hover).css("top", e.clientY + $("body").scrollTop());
            // segundo clic
        } else {
            // segundo punto
            endX = auxX;
            endY = auxY;
            // dimenciones de la nueva imagen
            imgW = endX - iniX;
            imgH = endY - iniY;
            // guardo la imagen en un tag img
            newImg = new Image();
            newImg.src = imgSource;
	    // cuando terminde de cargar la imagen
            newImg.onload = function() {
                // limpio el canvas (para que el corte sea limpio)
                ctx.clearRect(0, 0, newImg.width, newImg.height);
                // reescalo el canvas para que quede solo la img y ningun espacio en blanco
                canvas.width = imgW;
                canvas.height = imgH;
                // corto la imagen
                ctx.drawImage(this, iniX, iniY, imgW, imgH, 0, 0, imgW, imgH);
                // guardo el corte en una imagen
                saveCanvasToImage();
                // cargo de nuevo la imagen en el canvas
                loadImageToCanvas();
		// limpio la seleccion y los clic
                init();
            };
        }
    });

Analizando la función anterior...

Si nos fijamos, el cuerpo de la función manejada por el evento clic sobre el Canvas esta dividida en dos bloques; usamos la variable iniX como bandera para saber si se trata del primer clic (primer bloque encerrado por el if()) o el segundo (segundo bloque encerrado por el if()):

  • Si la misma es menor a cero significa que es el primer clic del usuario sobre el Canvas.
  • Si la misma es distinta de -1 significa que es el segundo clic del usuario sobre el Canvas.

El punto primordial de esta función es la de capturar la posición de los clic del usuario; de eso se encargan este par de líneas para el eje X y Y:

auxX = e.clientX - offset.left + $("body").scrollLeft();
auxY = e.clientY - offset.top + $("body").scrollTop();
  • Capturamos las coordenadas del clic del usuario sobre la ventana del navegador con e.clientX y e.clientY.
  • El método offset() permite obtener las coordenadas X y Y relativas a un elemento.
  • El método scrollLeft() y scrollTop() permite obtener la posición de la barra de desplazamiento de un elemento; en este caso del body.

También ubicamos al hover sobre el primer clic del usuario; al tener un atributo position:absolute no es necesario emplear el método offset() ya que no posee una posición relativa, sino absoluta.

5. El hover sobre el Canvas

Ahora colocaremos un hover semi-transparente desde el primer clic del usuario hasta donde se mueva el mismo en el Canvas; para eso cambiamos repetidamente la altura y anchura del hover según el usuario se mueva por el canvas; la explicación es similar al punto 4:

    // pinto un div sobre el canvas desde el primer clic del usuario 
    // hasta donde el usuario mueva el raton
    $(canvas).mousemove(function(e) {
        // si hubo un primer clic por el usuario
        if (iniX >= 0) {
            var offset = $(this).offset();
            endX = e.clientX - offset.left + $("body").scrollLeft();
            endY = e.clientY - offset.top + $("body").scrollTop();
            imgW = endX - iniX;
            imgH = endY - iniY;
           $(hover).css("width", imgW - 3);
            $(hover).css("height", imgH - 3);
        }
    });

Resultado Final:

 

Ver demo Descargar Fuente

Existe otra forma en la que podemos aplicar recortes sobre las imágenes, aunque por supuesto no puedes generar una imagen a partir de la misma, es mediante los márgenes negativos, que simplemente es especificar márgenes negativos aunque solo puedes recortar desde los bordes y no en el medio de la imagen; la otra forma que tenemos es empleando la propiedad clip que vimos en esta entrada:

La propiedad clip-path en CSS para seleccionar regiones a mostrar en elementos

Detectando los eventos de teclado con Canvas

Detectando los eventos de teclado con Canvas

Ver ejemplo

Hasta ahora hemos vistos varios experimentos empleando Canvas y JavaScript en los cuales realizamos animaciones variadas, pero estas no dependen de ningún otro agente para variar su comportamiento:

En esta entrada veremos un pequeño experimento en donde interactuamos con el Canvas mediante los eventos de teclados específicamente emplearemos las flechas de direcciones del teclado.

Realizar animaciones con JavaScript y Canvas las cuales dependen de agentes externos como teclado o ratón son muy sencillas.

Como podrás imaginar al introducir el concepto de animación se está insinuando el uso de la función requestAnimationFrame() que permite realizar animaciones con el Canvas de una manera eficiente; aunque debes de tener en consideración la compatibilidad con los antiguos navegadores al formar parte de la API de HTML5; puedes obtener más información en: EL SECRETO DE LAS ANIMACIONES EN JAVASCRIPT.

Empezando con el experimento con Canvas, animaciones y eventos de teclado (JavaScript)

El experimento consiste en mover un pequeño círculo por todo el Canvas dejando una leve estela a su paso mediante las flechas de direcciones del teclado.

Inicializando el evento de teclado

Asociaremos el evento al document aunque puedes asociarlo también al Canvas si lo prefieres:

document.addEventListener('keydown', function(e) {    }, false);

En el escuchador 'keydown' asociaremos el código de las teclas con las cuales nos interesa que interactúe el Canvas y actualizaremos variables que son tomadas al momento de redibujar el círculo mediante la función requestAnimationFrame().

Puedes buscar los códigos asociados al pulsar de las teclas de direcciones o simplemente coloca un alert o console.log y consulta el código al momento de presionar el teclado.

Una vez que nos hagamos con los códigos podemos formar los siguientes condicionales para aumentar/decrementar una serie de variables:

    document.addEventListener('keydown', function (e) {
        lastDownTarget = event.target;
        if (e.keyCode === 37) {
            x-=v;
        }
        if (e.keyCode === 38) {
            y-=v;
        }
        if (e.keyCode === 39) {
            x+=v;
        }
        if (e.keyCode === 40) {
            y+=v;
        }
    }, false);
  • Las variables x y y son globales y representa la posición del círculo en un momento dado; por defecto, ambas se encuentran inicializadas en cero.
  • La variable v es un valor global y constante que expresa la velocidad del círculo al desplazarse.

x representa la posición del círculo en el eje de las X y y representa la posición del círculo en el eje de las Y.

Pintando en el Canvas

Hasta el momento hemos visto cómo actualizar un par de variables mediante los eventos de teclado; dichas variables serán empleadas para dibujar el círculo en una posición determinada, ahora veremos cómo dibujar el círculo empleando las posiciones:

    function draw() {
        $.fillStyle = 'hsla(' + (x*y)/100 + ',100%, 50%, 1)';
        $.beginPath();
        $.arc(x, y, 8, 0, dosPi);
        $.fill();
    }

Muy sencillo, simplemente consultamos las variables globales x y y que actualizamos en otra función.

En otras palabras; al actualizar las variables mediante los eventos de teclado, también deben ser actualizadas al momento de repintar el Canvas mediante la función requestAnimationFrame():

    function go() {
     $.fillStyle = 'hsla(0,0%,0%,.08)';
     $.fillRect(0, 0, w, h);
     if (x <= 0)
         x = 0;
     if (y <= 0)
         y = 0;
     if (x >= w)
         x = w;
     if (y >= h)
         y = h;
     draw();
     window.requestAnimationFrame(go);
 }

El código completo del experimento Canvas:

    var c = document.getElementById('canv');
    var w = c.width = window.innerWidth;
    var h = c.height = window.innerHeight;
    var $ = c.getContext('2d');
    var x = w/2;
    var y = h/2;
    var dosPi = Math.PI * 2;
    var v = 5;
    window.addEventListener('resize', function () {
        c.width = window.innerWidth;
        c.height = window.innerHeight;
    }, false);
    function draw() {
        $.fillStyle = 'hsla(' + (x*y)/100 + ',100%, 50%, 1)';
        $.beginPath();
        $.arc(x, y, 8, 0, dosPi);
        $.fill();
    }
    function go() {
        $.fillStyle = 'hsla(0,0%,0%,.08)';
        $.fillRect(0, 0, w, h);
        if (x <= 0)
            x = 0;
        if (y <= 0)
            y = 0;
        if (x >= w)
            x = w;
        if (y >= h)
            y = h;
        draw();
        window.requestAnimationFrame(go);
    }
    go();
    document.addEventListener('keydown', function (e) {
        lastDownTarget = event.target;
        if (e.keyCode === 37) {
            x-=v;
        }
        if (e.keyCode === 38) {
            y-=v;
        }
        if (e.keyCode === 39) {
            x+=v;
        }
        if (e.keyCode === 40) {
            y+=v;
        }
    }, false);

Y para no hacer extremadamente larga esta entrada, lo dejaremos hasta aquí; en posteriores entradas veremos como interactuar un poco más con el Canvas mediante los eventos de teclado.

Puedes probar el experimento en el siguiente enlace:

Ver ejemplo

Escalado y recortando imágenes con Canvas

Siguiendo con los tutoriales de canvas, hoy veremos cómo aplicar recortes de ciertas secciones de las imágenes que es conocido como una operación crop de las imágenes que queramos establecer; como ya sabes con el canvas es posible escalar e incluso recortar imágenes dibujadas en el lienzo (en nuestro canvas) todo con sólo una función llamada drawImage(); como veremos en este artículo, según la cantidad de parámetros presentes en la misma, varía su modo o uso; veamos:

Parámetros de la función drawImage() para dibujar en el canvas

Según los parámetros que se definen en la w3schools: HTML canvas drawImage() estos son los parámetros del método drawImage():

ParámetroDescripción
Elemento:Imagen, video o canvas a usar; en nuestro caso será el lienzo canvas.
sx:Opcional. La coordenada x en donde empieza el recorte dentro del elemento.
sy:Opcional. La coordenada y en donde empieza el recorte dentro del elemento.
swidth:Opcional. El ancho del área de recorte.
sheightOpcional. El largo del área de recorte.
x:La coordenada x en donde se empezará a pintar en el canvas.
y:La coordenada y en donde se empezará a pintar en el canvas.
width:Opcional. El ancho a usar; la misma permite escalar la imagen a lo ancho.
height:Opcional. El largo a usar; la misma permite escalar la imagen a lo largo.

Dibujando una imagen al Canvas

Lo primero que debemos hacer es una vez que tengamos nuestra imagen que queramos emplear, la especificamos en nuestra imagen:

Simplemente tomamos una imágen fuente de la cual queremos aplicar el recortado mediante JavaScript:

<img src="/public/images/example/paisaje/paisaje.jpg" alt="paisaje" title="paisaje" id="paisaje">

Y nos queda en nuestro experimento algo así:

paisaje

Y se procede a pintar la imagen anterior en el Canvas:

var img = document.getElementById('paisaje');
drawImage(img, x, y);

Es copiada la imagen (img) al Canvas a partir de los puntos definidos por x y y; si se desea copiar la imagen completa, las coordenadas x y y deben de ser cero.

En el siguiente ejemplo podemos apreciar que a medida que aumentan x y y el área mostrada de la fotografía es menor:

 

Escalando una imagen

drawImage(image, x, y, width, height);

Es copiada la imagen (img) al Canvas a partir de los puntos definidos por x y y con la anchura y altura definida por width y height.

En el siguiente ejemplo es fácil apreciar que a medida que aumenta el height o alto del canvas, la imagen dibujada en el canvas es escalada.

Recortando y Escalando una imagen con JavaScript

Este es el modo más complicado; ya que básicamente hay que indicar los datos para poder recortar y luego escalar la imagen; noten que aquí emplearemos todos los parámetros:

drawImage(image, sx, sy, swidth, sheight, x, y, width, height);

Es copiada la imagen (img) y la cortamos a partir de los puntos sx y sy con la anchura y altura definida por swidth y sheight.

A este punto tendríamos la selección lista; en los editores de imágenes como GIMP sería conceptualmente como si hubiese hecho la selección con la herramienta de recorte (sólo la selección).

Se escala la imagen; de esto se encargar los últimos cuatro parámetros, el sexto y séptimo parámetro x y y posiciona en el eje X y Y el lugar donde se desea dibujar la imagen en el canvas, se indica el ancho y largo que se desea que tenga la imagen con width y height, si no se quiere escalar la imagen los dos últimos parámetros deben ser iguales a swidth y sheight, de esta forma sólo se recortará la imagen más no se escalará como podemos apreciar en el siguiente ejemplo.

¿Cómo obtener por separado el canal RGB de una imagen con HTML5 y la API Canvas?

El procesamiento digital de imágenes es una labor que tenemos que realizar en nuestras aplicaciones día a día, desde cambiar el tamaño de imágenes para así optimizarlas a nuestras aplicaciones, como recortes como inclusive alterarse el color, brillo, saturación, e inclusive obtener por separado el canal RGB de una imagen empleando el Canvas como veremos en esta entrada.

En este artículo veremos un tutorial de como obtener los tres canales RGB de una imagen y operarlos por separados, es decir, que los tendremos los canales RGB individualmente como vemos en la imagen promocional de esta entrada; al igual que los en los artículos pasados, usaremos HTML5 y javaScript nativo para lograr el objetivo; el cuerpo del documento no difiere mucho de los otros ejercicios que hicimos antes.

Definiendo el HTML

El HTML es realmente simple, al igual que hemos empleado en entradas anteriores consisten en un tag Canvas el cual emplearemos para dibujar la imagen base, es decir, la imagen con sus tres canales que es como está por defecto:

<canvas id="canvas">
        <p>Tu navegador no soporta Canvas.</p>
</canvas>

Y tres imágenes en donde serán colocados los tres canales RGB mediante un JavaScript que mostraremos en la siguiente sección de este tutorial:

<img id="r"/>
<img id="g"/>
<img id="b"/>

Definiendo el JavaScript para obtener los canales RGB de la imagen

Definiendo el JavaScript para obtener los canales RGB de la imagen

Lo primero que hacemos es definir las variables globales de siempre para obtener el canvas y su contexto, luego obtenemos acceso a las imágenes que por defecto esta vacías (el atributo src que es el que define la imagen no tiene nada) y lo llenaremos un poco más adelante con el procesamiento que haremos mediante la API Canvas para obtener el canal RGB:

var canvas = document.getElementById('canvas');// canvas
var ctx = canvas.getContext('2d'); // contexto
var imgR = document.getElementById('r');// imagen que representa el canal R
var imgG = document.getElementById('g');// imagen que representa el canal G
var imgB = document.getElementById('b');// imagen que representa el canal B
var srcImg = "image.png";// imagen fuente

Creamos un objeto de tipo Image y le asignamos una imagen fuente que es la que especificamos anteriormente:

    img = new Image();
    img.src = srcImg;

Una vez que la imagen fuera cargada, vamos a redimensionar el Canvas a el tamaño original de la imagen; dibujamos la imagen en el Canvas y colocamos los canales RGB por separados en la imagen invocando al método getRGB(); son esos los 3 pasos fundamentales que puedes detallar en el siguiente código:

// cargo la imagen
img.onload = function() {
    // reescalamos el canvas a las dimenciones de la imagen
    canvas.width = img.width;
    canvas.height = img.height;
    // dibujamos la imagen en el Canvas
    ctx.drawImage(this, 0, 0);
    getRGB();
};

La siguiente función permite separar los tres canales RGB de una imagen (que en nuestro caso es la que cargamos anteriormente) y la guardamos en variables individuales, como vemos obtenemos es la imageData que es un string o un texto muy largo con el contenido de la imagen (algo similar a lo que ocurre cuando abres una imagen con un bloc de notas u otro procesador de texto sencillo).

El siguiente paso que hacemos es volcar el contenido de la imageData de cada uno de los canales que ya tenemos separados desde el paso anterior en el source o fuente de cada una de nuestras imágenes HTML que definimos anteriormente en nuestro HTML y que referenciamos anteriormente también:

// pinta una imagen por canal
function getRGB() {
    // obtenemos el ImageData
    var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para R
    var imgdR = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para G
    var imgdG = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // obtenemos el ImageData para B
    var imgdB = ctx.getImageData(0, 0, canvas.width, canvas.height);
    // cada una de estos array va a tener un solo canal
    var pixR = imgdR.data;
    var pixG = imgdG.data;
    var pixB = imgdB.data;
    // va a tener los 3 canales; la usaremos 
    //para reestablecer los colores originales en el canvas
    var pix = imgd.data;
    // cambiamos el contraste
    for (var i = 0, n = pixR.length; i < n; i += 4) {
        //Mantengo el canal R
        pixR[i + 1] = 0;//G
        pixR[i + 2] = 0;//B
        //Mantengo el canal G
        pixG[i] = 0;//R
        pixG[i + 2] = 0;//B
        //Mantengo el canal B
        pixB[i] = 0;//R
        pixB[i + 1] = 0;//B
    }
    // retornamos la data modificada al Canvas; canal R
    ctx.putImageData(imgdR, 0, 0);
    dataURL = canvas.toDataURL();
    imgR.src = dataURL;
    // retornamos la data modificada al Canvas; canal G
    ctx.putImageData(imgdG, 0, 0);
    dataURL = canvas.toDataURL();
    imgG.src = dataURL;
    // retornamos la data modificada al Canvas; canal B
    ctx.putImageData(imgdB, 0, 0);
    dataURL = canvas.toDataURL();
    imgB.src = dataURL;
    // retornamos la data original al Canvas; canal RGB
    ctx.putImageData(imgd, 0, 0);
}

Para colocar cada uno de los canales RGB en imágenes individuales tenemos que procesar la data de la imagen que obtuvimos en un array en donde solo prevalece uno de los canales, los otros dos son establecidos con el valor de cero.

Analizando la función anterior para obtener procesar los canales RGBs de las imágenes

Obtenemos la ImageData o data sobre toda la imagen dibujada en el Canvas, la cual nos permitirá operar la data que compone a la imagen a nivel de píxel en su escala RGB; puedes ver más sobre el ImageData en el siguiente enlace:

// obtenemos el ImageData
var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para R
var imgdR = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para G
var imgdG = ctx.getImageData(0, 0, canvas.width, canvas.height);
// obtenemos el ImageData para B
var imgdB = ctx.getImageData(0, 0, canvas.width, canvas.height);

El siguiente paso consiste en obtener todos los píxeles que componen a la imagen; esta información viene almacenado en un Array:

// cada una de estos array va a tener un solo canal
var pixR = imgdR.data;
var pixG = imgdG.data;
var pixB = imgdB.data;
// va a tener los 3 canales; la usaremos 
// para reestablecer los colores originales en el canvas
var pix = imgd.data;

Esta sección de código representa el corazón del ejercicio; se obtiene un canal por vez, estableciendo los restantes en cero:

// cambiamos el contraste
for (var i = 0, n = pixR.length; i < n; i += 4) {
    //Mantengo el canal R
    pixR[i + 1] = 0;//G
    pixR[i + 2] = 0;//B
    //Mantengo el canal G
    pixG[i] = 0;//R
    pixG[i + 2] = 0;//B
    //Mantengo el canal B
    pixB[i] = 0;//R
    pixB[i + 1] = 0;//B
}

Luego de que tengamos divididos los canales; el siguiente paso consiste en guardar los tres canales RGB en imágenes separadas:

// retornamos la data modificada al Canvas; canal R
ctx.putImageData(imgdR, 0, 0);
dataURL = canvas.toDataURL();
imgR.src = dataURL;
// retornamos la data modificada al Canvas; canal G
ctx.putImageData(imgdG, 0, 0);
dataURL = canvas.toDataURL();
imgG.src = dataURL;
// retornamos la data modificada al Canvas; canal B
ctx.putImageData(imgdB, 0, 0);
dataURL = canvas.toDataURL();
imgB.src = dataURL;
// retornamos la data original al Canvas; canal RGB
ctx.putImageData(imgd, 0, 0);

Resultado Final

Por último puedes ver el resultado de nuestro experimento en la siguiente sección y descargar el código fuente:

Ver demo Descargar Fuente

Como podemos apreciar, con HTML podemos hacer prácticamente todo: juegos, procesadores de texto, de imágenes en donde la imaginación es el límite.

¿Cómo obtener imágenes en blanco y negro o en escala de grises con solo HTML5?

¿Cómo obtener imágenes en blanco y negro o en escala de grises con solo HTML5?

HTML5 nos abre la puerta a innumerables posibilidad para personalizar o realizar software específico para nuestras aplicaciones webs de todo tipo como ya hemos visto en multitudes de entradas en las cuales trabajamos las distintas APIs, elementos y componentes en general de HTML, JavaScript y por supuesto CSS; entre estas características que venimos hablando se encuentra el procesamiento digital de imágenes, como hemos visto en posteriores entregas es realmente posible con HTML5 y Canvas.

Específicamente empleamos el API de Canvas para hacer estos ejercicios; En esta nueva entrega veremos cómo obtener imágenes en Escala de Grises o en Blanco y Negro con HTML5.

Definiendo el HTML para el procesamiento en escala de grises

Como ya explicamos en la introducción al Canvas, el tag Canvas nos permite emplear toda la API del Canvas que nos provee JavaScript, y en específico para este tutorial el de acceder a una imagen a nivel de pixeles para su procesamiento que es lo que vamos a hacer próximamente:

<canvas id="canvas">
        <p>Tu navegador no soporta Canvas.</p>
</canvas>

También necesitamos tener definido un imagen fuente con la posibilidad de descargarla que es la que vamos a referenciar en nuestro canvas para posteriormente dibuja en el mismo.

<img id="resul"/>

Esto es todo el código HTML que emplearemos en nuestro experimento para que podamos dibujar una imagen en blanco y negro sobre nuestro Canvas.

El JavaScript para referenciar el Canvas

Ahora entramos en la parte más interesante de este tutorial, vamos a definir algunas variables globales como vemos a continuación:

var canvas = document.getElementById('canvas');
canvas.getContext('2d'); 
document.getElementById('resul');
srcImg = "image.png";

Las mismas nos permitirán:

  • Acceso al Canvas.
  • Acceso al contexto del Canvas; nos permitirá dibujar o acceder al contenido del Canvas como tal.
  • Acceso a la imagen final; en donde colocaremos la imagen en Escala de Grises o en Blanco y Negro.
  • La ruta a la imagen fuente, la cual utilizaremos para obtener a partir de ella una imagen en Escala de Grises o en Blanco y Negro.

Creamos un objeto de tipo Image y le asignamos la imagen fuente; esta imagen será nuestra imagen final; es decir la imagen en Escala de Grises o en Blanco y Negro.

img = new Image();
img.src = srcImg;

Realizamos la carga de la imagen y aprovechamos para redimensionar el Canvas al tamaño de la misma; luego de eso, invocamos a la función que se encargará de llevar la imagen a en Escala de Grises o en Blanco y Negro:

// cargo la imagen fuente img.onload = function() { // reescalamos el
canvas a las dimenciones de la imagen canvas.width = img.width;
canvas.height = img.height; // dibujamos la imagen en el Canvas
ctx.drawImage(this, 0, 0); getGrayScale(); };

Pasaremos por alto la explicación en detalle de la función; si nos fijamos bien parte del cuerpo ha sido utilizado en varios artículos anteriores.

El punto de interés aquí es el JavaScript que nos permite tener la imagen en Escala de Grises o en Blanco y Negro.

Luego de que obtenemos la ImageData o data que compone a la imagen:

var imgData = img.data;

Iteramos la ImageData en un for; en cada iteración del for podemos acceder a nivel de pixeles a la ImageData y a si descomponer el pixel en el canal RGB (como esta formado el pixel) que es el que nos interesa operar.

Ahora podemos obtener un promedio con los valores de cada canal RGB por separado:

gris = parseInt((imgData[i] + imgData[i + 1] + imgData[i + 2]) / 3);

Sustituimos el valor original del canal RGB para obtener el efecto deseado; una imagen en la Escala de Grises o en Blanco y Negro.

imgData[i] = gris;
imgData[i + 1] = gris;
imgData[i + 2] = gris;

Tuviéramos un efecto similar si igualamos todos los canales R, G y B entre sí; es decir:

imgData[i + 1] = imgData[i];
imgData[i + 2] = imgData[i];

o

imgData[i] = imgData[i];
imgData[i + 2] = imgData[i];

o

imgData[i] = imgData[i + 2];
imgData[i + 1] = imgData[i + 2];

Pero se obtiene un mejor resultado al aplicar un promedio en entre los canales.

Resultado final para la escala de grises

Imágenes en blanco y negro o en escala de grises con solo CSS

Recordemos que podemos convertir imágenes a escala de grises o en blanco y negro empleando un simple selector en CSS como vimos en una anterior entrada sobre los filtros en CSS; específicamente el filtro:

img {
  -webkit-filter: grayscale(100%);
  -moz-filter: grayscale(100%);
   filter: grayscale(100%);
}
¿Cómo cambiar el contraste de una imagen con HTML5?

¿Cómo cambiar el contraste de una imagen con HTML5?

En este artículo veremos cómo aumentar o reducir el contraste de una imagen con HTML5; además hablaremos un poco de como sería el proceso para aumentar el brillo de una imagen; que es un caso similar.

Estos son algunos de los métodos, tecnologías y conceptos que van a ser utilizados para llevar a cabo el desarrollo de este ejercicio:

  • Canvas: Para utilizarlo como lienzo y dibujar una imagen.
  • getImageData(): Permite obtener data sobre la imagen dibujada en el Canvas (ImageData):
    • ImageData.width: Anchura en píxeles de la ImageData.
    • ImageData.height: Altura en píxeles de la ImageData.
    • ImageData.resolution: La densidad de píxeles que posee la imagen.
    • ImageData.data: Array de una dimensión que contiene la data en RGBA (en ese orden), con enteros entre 0-255; representa los colores que componen la imagen dibujada en el Canvas; en otras palabras; los valores de los píxeles que componen a la imagen dibujada en el Canvas.
    • img.onload: Evento que se manifiesta una vez que la imagen ha sido cargada.

La fórmula del contraste

Queda fuera del alcance de este artículo definir el contraste en toda su extensión; sin embargo podemos definir el contraste como una variación de intensidades que permite incrementar la luminosidad entre las zonas oscuras y claras de una imagen permitiendo un mejor enfoque y claridad de la imagen; la fórmula empleada a nivel de pixel será la siguiente:

valorNuevo = ( valorAnterior - 128) * tan(ángulo) + 128

En donde:

  • valorAnterior: Es el valor original de un píxel en la imagen.
  • ángulo: Calculamos el ángulo como:  Math.tan(val * Math.PI / 180.0);
    • val : El valor del campo de tipo rango manejado por el usuario.

Puedes obtener más información sobre la fórmula en el siguiente enlace: Generación de Imágenes.

Definiendo el HTML

Primero necesitaremos un Canvas; el cual utilizaremos como lienzo para pintar una imagen y poder manipularla a nivel de pixeles:

<canvas id="canvas">
	<p>Tu navegador no soporta Canvas.</p>
</canvas>

Un campo de tipo rango (type="range") para poder aumentar y decrementar el contraste fácilmente:

<input type="range" id="contrast" min="-90" max="90" step="5" value="0">

Definiendo el JavaScript

Variables globales:

	var canvas = document.getElementById('canvas');// canvas
	var ctx = canvas.getContext('2d'); // contexto
	var contrast = document.getElementById("contrast");// input de tipo rango
	var srcImg = "image.png";// imagen fuente

Primero es necesario crear un objeto de tipo image a la cual se le establece una imagen fuente que será utilizada para pintarla en el Canvas con el método drawImage():

	// nueva imagen
	img = new Image();
	img.src = srcImg;

	img.onload = function() {
	
		// reescalamos el canvas a las dimenciones de la imagen
		canvas.width = img.width;
		canvas.height = img.height;
	
		// dibujamos la imagen en el Canvas
		ctx.drawImage(this, 0, 0);
		
	};

La siguiente función permite aumentar el contraste de la imagen pintada en el Canvas:

	// aumenta el contraste
	function AddContrast(val) {

		//combino la formula para obtener el contraste con el valor obtenido del elemento ranges
		var contrast = Math.tan(val * Math.PI / 180.0);

		// reescalamos el canvas a las dimenciones de la imagen
		canvas.width = img.width;
		canvas.height = img.height;
	
		// dibujamos la imagen en el Canvas
		ctx.drawImage(img, 0, 0);
		
		// obtenemos el ImageData
		var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);
		var pix = imgd.data;
		
		// cambiamos el contraste
		for (var i = 0, n = pix.length; i < n; i += 4) {
			//incremento los valores rojo, verde y azul de cada pixel
			pix[i] = rangeColor(128 + (pix[i] - 128) * contrast);
			pix[i + 1] = rangeColor(128 + (pix[i + 1] - 128) * contrast);
			pix[i + 2] = rangeColor(128 + (pix[i + 2] - 128) * contrast);
		}
		
		// retornamos la data modificada al Canvas
		ctx.putImageData(imgd, 0, 0);
	}

Analizando la función anterior...

Creamos un objeto de tipo Image y le asignamos una imagen fuente.

img = new Image();
img.src = srcImg;

Obtenemos el imageData del Canvas y se opera a nivel de píxeles con el ImageData.data:

// obtenemos el ImageData var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height); var pix = imgd.data;

Por último alteramos los valores de los pixeles agregando contraste a la imagen a los píxeles en su notación RGB:

        for (var i = 0, n = pix.length; i < n; i += 4) {
            //incremento los valores rojo, verde y azul de cada pixel
            pix[i] = rangeColor(128 + (pix[i] - 128) * contrast);
            pix[i + 1] = rangeColor(128 + (pix[i + 1] - 128) * contrast);
            pix[i + 2] = rangeColor(128 + (pix[i + 2] - 128) * contrast);
        }

Para asegurarnos de que el color no se salga del rango 0-255 empleamos la siguiente función:

// valida que el color este en un rango valido function rangeColor(pix) {    if (pix < 0)        pix = 0;    if (pix > 255)        pix = 255;    return pix; }

El brillo

En cuanto al brillo, el mismo consiste en sumar una constante (K) que se encuentre en el rango 0-255; así que con tan solo modificar esta sección de código:

        for (var i = 0, n = pix.length; i < n; i += 4) {
            //incremento los valores rojo, verde y azul de cada pixel
            pix[i] = rangeColor(128 + (pix[i] - 128) * contrast);
            pix[i + 1] = rangeColor(128 + (pix[i + 1] - 128) * contrast);
            pix[i + 2] = rangeColor(128 + (pix[i + 2] - 128) * contrast);
        }

Por esta otra:

        for (var i = 0, n = pix.length; i < n; i += 4) {
            //cambio los valores rojo, verde y azul de cada pixel
            pix[i] = rangeColor(pix[i] + K);
            pix[i + 1] = rangeColor(pix[i + 1] + K);
            pix[i + 2] = rangeColor(pix[i + 2] + K);
        }

Podrás cambiar fácilmente el brillo de una imagen con solo HTML5; la constante K puede ser obtenida a partir de un campo de tipo rango como en el caso del contraste:

<input type="range" id="brightness" min="0" max="255" step="1" value="0">

Enlaces de Interés

Resultado Final

Ver demo Descargar Fuente

Acepto recibir anuncios de interes sobre este Blog.

El elemento canvas nos permite especificar un área de la página en donde se puede dibujar crear todo tipo de gráficos simples o complejos a partir de primitivas básicas como círculos, óvalos, rectángulos líneas, polígonos, texto, etc, veremos ejemplos , de como recortar imágenes, loops para dibujar líneas, eventos de teclado y como obtener el canal RGB.

| 👤 Andrés Cruz