Cómo hacer una aplicación web con filtros parecidos a los de Instagram

En este tutorial, vamos a crear una simple aplicación web que te permita arrastrar una foto de tu ordenador a la ventana del navegador, y aplicarle filtros parecidos a los de la aplicación Instagram. Para ello vamos a utilizar una serie de librerías y plugins de JavaScript:

  • Caman.js - Es una potente librería para la manioulación de canvas que te permite aplicar diferentes efectos y filtros en una imagen. Viene con 18 filtros predefinidos que vamos a utilizar en este ejemplo (puedes crear más si lo deseas)
  • Filereader.js - Es un wrapper ligero que hace que sea mucho más sencillo trabajar con eventos de arrastrar y soltar de HTML5.
  • jQuery Mousewheel - Utilizo este plugin para desplazar el contenedor del filtro;
  • Además, para este tutorial hemos utilizado la última versión de jQuery a la hora de escribir.

El HTML

El primer paso es escribir el código HTML:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />

	<title>Instagram-like Filters with jQuery | Tutorialzine Demo</title>
	<link href="assets/css/style.css" rel="stylesheet" />

	<!-- Include the Yanone Kaffeesatz font -->
	<link href="http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,200" rel="stylesheet" />

</head>
<body>

	<h1>Instagram <b>Filters</b></h1>
	<div id="photo"></div>

	<div id="filterContainer">
		<ul id="filters">
			<li> <a href="#" id="normal">Normal</a> </li>
			<li> <a href="#" id="vintage">Vintage</a> </li>
			<li> <a href="#" id="lomo">Lomo</a> </li>
			<li> <a href="#" id="clarity">Clarity</a> </li>
			<li> <a href="#" id="sinCity">Sin City</a> </li>
			<!-- 14 More filters go here -->
		</ul>
	</div>

	<!-- Libraries -->
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
	<script src="assets/js/filereader.min.js"></script>
	<script src="assets/js/caman.full.js"></script>
	<script src="assets/js/jquery.mousewheel.min.js"></script>
	<script src="assets/js/script.js"></script>

</body>
</html>

Además de las bibliotecas mencionadas en la introducción, también incluyo el archivo script.js que alberga el código el cual te mostraremos a continuación. En el head, incluyo la fuente Yanone Kaffeesatz desde Google Web Fonts.

El JavaScript / jQuery

Para llevar a cabo la aplicación, vamos a hacer lo siguiente:

  • Aceptar la imagen del drag & drop
  • Crear un nuevo elemento canvas (original), con un máximo de 500x500px de tamaño (personalizable) y mantenerlo en la memoria
  • Escuchar los clics de los filtros. Cuando se selecciona uno: Crear un clon del canvas original. Eliminar cualquier elemento de canvas que haya en la página. Anexar el clon al div #photo. Si el filtro seleccionado es diferente de "Normal", llama a la librería Caman. De lo contrario no hacer nada. Marca el filtro seleccionado con la clase "activo".
  • Ejecutar el filtro "Normal".

Ahora que sabemos lo que hay que hacer, vamos a empezar a programar

assets/js/script.js

$(function() {

	var	maxWidth = 500,
		maxHeight = 500,
		photo = $('#photo'),
		originalCanvas = null,
		filters = $('#filters li a'),
		filterContainer = $('#filterContainer');

	// Use the fileReader plugin to listen for
	// file drag and drop on the photo div:

	photo.fileReaderJS({
		on:{
			load: function(e, file){

				// An image has been dropped.

				var img = $('<img>').appendTo(photo),
					imgWidth, newWidth,
					imgHeight, newHeight,
					ratio;

				// Remove canvas elements left on the page
				// from previous image drag/drops.

				photo.find('canvas').remove();
				filters.removeClass('active');

				// When the image is loaded successfully,
				// we can find out its width/height:

				img.load(function() {

					imgWidth  = this.width;
					imgHeight = this.height;

					// Calculate the new image dimensions, so they fit
					// inside the maxWidth x maxHeight bounding box

					if (imgWidth >= maxWidth || imgHeight >= maxHeight) {

						// The image is too large,
						// resize it to fit a 500x500 square!

						if (imgWidth > imgHeight) {

							// Wide
							ratio = imgWidth / maxWidth;
							newWidth = maxWidth;
							newHeight = imgHeight / ratio;

						} else {

							// Tall or square
							ratio = imgHeight / maxHeight;
							newHeight = maxHeight;
							newWidth = imgWidth / ratio;

						}

					} else {
						newHeight = imgHeight;
						newWidth = imgWidth;
					}

					// Create the original canvas.

					originalCanvas = $('<canvas>');
					var originalContext = originalCanvas[0].getContext('2d');

					// Set the attributes for centering the canvas

					originalCanvas.attr({
						width: newWidth,
						height: newHeight
					}).css({
						marginTop: -newHeight/2,
						marginLeft: -newWidth/2
					});

					// Draw the dropped image to the canvas
					// with the new dimensions
					originalContext.drawImage(this, 0, 0, newWidth, newHeight);

					// We don't need this any more
					img.remove();

					filterContainer.fadeIn();

					// Trigger the default "normal" filter
					filters.first().click();
				});

				// Set the src of the img, which will
				// trigger the load event when done:

				img.attr('src', e.target.result);
			},

			beforestart: function(file){

				// Accept only images.
				// Returning false will reject the file.

				return /^image/.test(file.type);
			}
		}
	});

	// Listen for clicks on the filters

	filters.click(function(e){

		e.preventDefault();

		var f = $(this);

		if(f.is('.active')){
			// Apply filters only once
			return false;
		}

		filters.removeClass('active');
		f.addClass('active');

		// Clone the canvas
		var clone = originalCanvas.clone();

		// Clone the image stored in the canvas as well
		clone[0].getContext('2d').drawImage(originalCanvas[0],0,0);

		// Add the clone to the page and trigger
		// the Caman library on it

		photo.html(clone);

		var effect = $.trim(f[0].id);

		Caman(clone[0], function () {

			// If such an effect exists, use it:

			if( effect in this){
				this[effect]();
				this.render();
			}
		});

	});

	// Use the mousewheel plugin to scroll
	// scroll the div more intuitively

	filterContainer.find('ul').on('mousewheel',function(e, delta){

		this.scrollLeft -= (delta * 50);
		e.preventDefault();

	});

});

Este ejemplo funciona en todos los navegadores que soportan drag&drop. Algunos de los filtros son intensivos computacionalmente, por lo que tendrás un poco de retraso antes de que los resultados se muestren por pantalla. He limitado el ancho y la altura máxima de la imagen a 500px con el fin de acelerar un poco las cosas, pero puedes cambiar estos valores a tu gusto.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
SIGUIENTE ARTÍCULO