domingo, 24 de abril de 2016

Procesando video en el lienzo - HTML, CSS y JAVASCRIPT



Al igual que para animaciones, no hay ningún método especial para mostrar video en el elemento <canvas>. La única manera de hacerlo es tomando cada cuadro del video desde el elemento <video> y dibujarlo como una imagen en el lienzo usando drawImage(). Así que básicamente, el procesamiento de video en el lienzo es hecho con la combinación de técnicas ya estudiadas.
Construyamos una nueva plantilla y los códigos para ver de qué estamos hablando.

Código 7-28. Plantilla para reproducir video en el lienzo.

<!DOCTYPE html>
<html lang="es">
<head>
<title>Video en el Lienzo</title>
<style>
.cajas{
display: inline-block;
margin: 10px;
padding: 5px;
border: 1px solid #999999;
}
</style>
<script src="canvasvideo.js"></script>
</head>
<body>
<section class="cajas">
<video id="medio" width="483" height="272">
<source src="http://www.minkbooks.com/content/trailer2.mp4">
<source src="http://www.minkbooks.com/content/trailer2.ogg">
</video>
</section>
<section class="cajas">
<canvas id="lienzo" width="483" height="272">
Su navegador no soporta el elemento canvas
</canvas>
</section>
</body>
</html>

La plantilla en el código 7-28 incluye dos componentes específicos: el elemento <video> y el elemento <canvas>. Con la combinación de ambos vamos a procesar y mostrar video en el lienzo.
La plantilla también incluye estilos CSS embebidos para las cajas y un archivo Javascript llamado canvasvideo.js para el siguiente código:


Código 7-29. Video color convertido en blanco y negro.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
video=document.getElementById('medio');
video.addEventListener('click', presionar, false);
}
function presionar(){
if(!video.paused && !video.ended){
video.pause();
window.clearInterval(bucle);
}else{
video.play();
bucle=setInterval(procesarCuadros, 33);
}
}
function procesarCuadros(){
lienzo.drawImage(video,0,0);
var info=lienzo.getImageData(0,0,483,272);
var pos;
var gris;
for(x=0;x<=483;x++){
for(y=0;y<=272;y++){
pos=(info.width*4*y)+(x*4);
gris=parseInt(info.data[pos]*0.2989 +
info.data[pos+1]*0.5870 + info.data[pos+2]*0.1140);
info.data[pos]=gris;
info.data[pos+1]=gris;
info.data[pos+2]=gris;
}
}
lienzo.putImageData(info,0,0);
}
window.addEventListener("load", iniciar, false);

Hágalo usted mismo: Cree un nuevo archivo HTML con el código 7-28 y un archivo Javascript llamado canvasvideo.js con el código 7-29.
Para comenzar a reproducir el video, haga clic en la caja izquierda en la pantalla.
IMPORTANTE: Este ejemplo usa los métodos getImageData() y putImageData() para procesar datos de imagen. Como explicamos anteriormente, estos métodos extraen información del lienzo. Debido a restricciones de seguridad, la extracción de información desde el lienzo es desactivada luego de que el elemento recibe contenido desde un origen que no es el origen del documento que lo creó (el documento pertenece a un dominio y el video a otro). Por lo tanto, para probar este ejemplo, deberá descargar el video desde nuestro sitio web (o usar el suyo propio) y luego subir cada uno de los archivos a su servidor. 

Estudiemos por un momento el código 7-29. Como dijimos previamente, para procesar video en el lienzo, simplemente debemos recurrir a códigos y técnicas ya vistas. En este código estamos usando la función presionar() tomada del Capítulo 5 para comenzar y detener la reproducción del video haciendo clic sobre el mismo. También creamos una función llamada procesarCuadros() que está usando el mismo código 7-25 de este capítulo, excepto que esta vez en lugar de invertir la imagen estamos usando una fórmula para transformar todos los colores de cada cuadro del video en el correspondiente gris. Esto convertirá nuestro video color en un video blanco y negro. La función presionar() cumple con dos propósitos: comenzar o detener la reproducción del video e iniciar un intervalo que ejecutará la función procesarCuadros() cada 33 milisegundos. Esta función toma un cuadro del elemento <video> y lo dibuja en el lienzo con la instrucción drawImage(video,0,0). 
Luego los datos son extraídos del lienzo con el método getImageData() y cada pixel de ese cuadro es procesado por medio de dos bucles for (como lo hicimos en un ejemplo anterior). 
El proceso utilizado para convertir cada uno de los colores que integran cada pixel en su correspondiente gris es uno de los más populares y fáciles de encontrar en Internet. La fórmula es la siguiente: rojo × 0.2989 + verde × 0.5870 + azul × 0.1140. 
Luego de que la fórmula es calculada, el resultado debe ser asignado a cada color del pixel (rojo, verde y azul), como lo hicimos en el ejemplo usando la variable gris. 
El proceso termina cuando dibujamos nuevamente el cuadro modificado en el lienzo usando el método putImageData().
IMPORTANTE: Este ejemplo es con propósitos didácticos. Procesar video en
tiempo real del modo en que lo hicimos no es una práctica recomendada.
Dependiendo de la configuración de su ordenador y el navegador que use para correr la aplicación, probablemente note algunas demoras en el proceso. Para crear aplicaciones Javascript útiles, siempre debe considerar su rendimiento.


Referencia rápida

La API Canvas es probablemente la más compleja y extensa de todas las APIs incluidas dentro de la especificación HTML5. Provee varios métodos y propiedades para crear aplicaciones gráficas sobre el elemento <canvas>.

Métodos

Estos métodos son específicos de la API Canvas:
  • getContext(contexto) Este método crea el contexto para el lienzo. Puede tomar dos valores: 2d y 3d para gráficos en 2 y 3 dimensiones.
  • fillRect(x, y, ancho, alto) Este método dibujará un rectángulo sólido directamente en el lienzo en la posición indicada por x,y y el tamaño ancho,alto.
  • strokeRect(x, y, ancho, alto) Este método dibujará un rectángulo vacío (solo el contorno) directamente en el lienzo en la posición indicada por x,y y el tamaño ancho,alto.
  • clearRect(x, y, ancho, alto) Este método borra un área en el lienzo usando una figura rectangular declarada por los valores de sus atributos.
  • createLinearGradient(x1, y1, x2, y2) Este método crea un gradiente lineal para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. Sus atributos solo especifican las posiciones de comienzo y final del gradiente (relativas al lienzo). Para declarar los colores involucrados en el gradiente, este método debe ser usado en combinación con addColorStop().
  • createRadialGradient(x1, y1, r1, x2, y2, r2) Este método crea un gradiente radial para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. El gradiente es construido por medio de dos círculos. Los atributos solo especifican la posición y radio de los círculos (relativos al lienzo). Para declarar los colores involucrados en el gradiente, este método debe ser usado en combinación con addColorStop().
  • addColorStop(posición, color) Este método es usado para declarar los colores para el gradiente. El atributo posición es un valor entre 0.0 y 1.0, usado para determinar dónde el color comenzará la degradación.
  • beginPath() Este método es requerido para comenzar un nuevo trazado.
  • closePath() Este método puede ser usado al final de un trazado para cerrarlo. Generará una línea recta desde la última posición del lápiz hasta el punto donde el trazado comenzó. No es necesario usar este método cuando el trazado debe permanecer abierto o es dibujado en el lienzo usando fill().
  • stroke() Este método es usado para dibujar un trazado como una figura vacía (solo el contorno).
  • fill() Este método es usado para dibujar un trazado como una figura sólida.
  • clip() Este método es usado para crear una máscara a partir de un trazado. Todo lo que sea enviado al lienzo luego de que este método es declarado será dibujado sólo si cae dentro de la máscara.
  • moveTo(x, y) Este método mueve el lápiz virtual a una nueva posición para continuar el trazado desde ese punto.
  • lineTo(x, y) Este método agrega líneas rectas al trazado desde la posición actual del lápiz hasta el punto indicado por los atributos x e y.
  • rect(x, y, ancho, alto) Este método agrega un rectángulo al trazado en la posición x,y y con un tamaño determinado por ancho,alto.
  • arc(x, y, radio, ángulo inicio, ángulo final, dirección) Este método agrega un arco al trazado. El centro del arco es determinado por x e y, los ángulos son definidos en radianes, y la dirección es un valor booleano para determinar si el arco será dibujado en el mismo sentido o el opuesto a las agujas del reloj. Para convertir grados en radianes, use la fórmula: Math.PI/180×grados.
  • quadraticCurveTo(cpx, cpy, x, y) Este método agrega una curva Bézier cuadrática al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cpx y cpy especifican la posición del punto de control que dará forma a la curva.
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) Este método agrega una curva Bézier cúbica al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cp1x, cp1y, cp2x, y cp2y especifican la posición de los dos puntos de control que darán forma a la curva.
  • strokeText(texto, x, y, máximo) Este método dibuja un texto vacío (solo el contorno) directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en pixeles.
  • fillText(texto, x, y, máximo) Este método dibuja un texto sólido directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en pixeles. 
  • measureText(texto) Este método calcula el tamaño del área que un texto ocupará en el lienzo usando los estilos vigentes. La propiedad width es usada para retornar el valor.
  • translate(x, y) Este método mueve el origen del lienzo al punto x,y. La posición inicial del origen (0,0) es la esquina superior izquierda del área generada por el elemento <canvas>.
  • rotate(angle) Este método es usado para rotar el lienzo alrededor del origen. El ángulo debe ser declarado en radianes. Para convertir grados en radianes, use la fórmula: Math.PI/180×grados.
  • scale(x, y) Este método cambia la escala del lienzo. Los valores por defecto son (1.0, 1.0). Los valores provistos pueden ser negativos.
  • transform(m1, m2, m3, m4, dx, dy) Este método modifica la matriz de transformación del lienzo. La nueva matriz es calculada sobre la anterior.
  • setTransform(m1, m2, m3, m4, dx, dy) Este método modifica la matriz de transformación del lienzo. Reinicia los valores anteriores y declara los nuevos.
  • save() Este método graba el estado del lienzo, incluyendo la matriz de transformación, propiedades de estilo y la máscara.
  • restore() Este método restaura el último estado del lienzo grabado, incluyendo la matriz de transformación, propiedades de estilo y la máscara.
  • drawImage() Esta método dibujará una imagen en el lienzo. Existen tres sintaxis posibles.  La sintaxis drawImage(imagen,x,y) dibuja la imagen en la posición x,y. 
  • La sintaxis drawImage(imagen,x,y,ancho,alto) dibuja la imagen en la posición x,y con un nuevo tamaño declarado por ancho,alto. Y la sintaxis drawImage(imagen, x1, y1, ancho1, alto1, x2, y2, ancho2, alto2) toma una porción de la imagen original determinada por x1,y1,ancho1,alto1 y la dibuja en el lienzo en la posición x2,y2 y el nuevo tamaño ancho2,alto2. 
  • getImageData(x, y, ancho, alto) Este método toma una porción del lienzo y la graba como datos en un objeto. Los valores del objeto son accesibles a través de las propiedades width, height y data. Las primeras dos propiedades retornan el tamaño de la porción de la imagen tomada, y data retorna la información como un array con valores representando los colores de cada pixel. Este valor puede ser accedido usando la fórmula (ancho×4×y)+(x×4).
  • putImageData(datosImagen, x, y) Este método dibuja en el lienzo la imagen representada por la información en datosImagen.
  • createImageData(ancho, alto) Este método crea una nueva imagen en formato de datos. Todos los pixeles son inicializados en color negro transparente. Puede tomar datos de imagen como atributo en lugar de ancho y alto. En este caso la nueva imagen tendrá el tamaño determinado por los datos provistos.
  • createPattern(imagen, tipo) Este método crea un patrón desde una imagen que luego podrá ser asignado a una figura usando la propiedad fillStyle. Los valores posibles para el atributo tipo son repeat, repeat-x, repeat-y y no-repeat.


Propiedades

La siguiente lista de propiedades es específica para la API Canvas:
  • strokeStyle Esta propiedad declara el color para las líneas de las figuras. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba().
  • fillStyle Esta propiedad declara el color para el interior de figuras sólidas. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba(). Es también usada para asignar gradientes y patrones a figuras (estos estilos son primero asignados a una variable y luego esa variable es declarada como el valor de esta propiedad).
  • globalAlpha Esta propiedad es usada para determinar el nivel de transparencia de las figuras. Recibe valores entre 0.0 (completamente opaco) y 1.0 (completamente transparente).
  • lineWidth Esta propiedad especifica el grosor de la línea. Por defecto el valor es 1.0.
  • lineCap - Esta propiedad determina la forma de la terminación de las líneas. Se pueden utilizar tres valores: butt (terminación normal), round (termina la línea con un semicírculo) y square (termina la línea con un cuadrado).
  • lineJoin Esta propiedad determina la forma de la conexión entre líneas. Se pueden utilizar tres valores: round (la unión es redondeada), bevel (la unión es cortada) y miter (la unión es extendida hasta que ambas líneas alcanzan un punto en común).
  • miterLimit Esta propiedad determina cuánto se extenderán las líneas cuando la propiedad lineJoin es declarada como miter.
  • font Esta propiedad es similar a la propiedad font de CSS y utiliza la misma sintaxis para declarar los estilos del texto. 
  • textAlign Esta propiedad determina cómo el texto será alineado. Los posibles valores son start, end, left, right y center.
  • textBaseline Esta propiedad determina el alineamiento vertical para el texto. Los posibles valores son: top, hanging, middle, alphabetic, ideographic y bottom.
  • shadowColor Esta propiedad establece el color para la sombra. Utiliza valores CSS.
  • shadowOffsetX Esta propiedad declara la distancia horizontal entre la sombra y el objeto.
  • shadowOffsetY Esta propiedad declara la distancia vertical entre la sombra y el objeto.
  • shadowBlur Esta propiedad recibe un valor numérico para generar un efecto de difuminación para la sombra.
  • globalCompositeOperation Esta propiedad determina cómo las nuevas figuras serán dibujadas en el lienzo considerando las figuras ya existentes. Puede recibir varios valores: source-over, source-in, source-out, source-atop, lighter, xor,destination-over, destination-in, destination-out, destination-atop,darker y copy. El valor por defecto es source-over, lo que significa que las nuevas formas son dibujadas sobre las anteriores.


Espero haber ayudado en algo. Hasta la próxima oportunidad!











  

No hay comentarios:

Publicar un comentario en la entrada