Создание фильтров изображений в стиле Instagram.

13-02-11 Html, JavaScript Canvas, jQuery 9

В этом уроке мы сделаем небольшое веб-приложение, которое позволяет перетаскивать изображения с компьютера в окно браузера и применять к нему фильтры в стиле инстаграм. Для реализации этого мы будем использовать несколько JavaScript библиотек и плагинов.

  • Caman.js — библиотека для управления элементом canvas, которая позволяет накладывать разные фильтры на изображения. Доступно 18 фильтров, которые мы будем использовать в примере (но вы можете создать больше).
  • Filereader.js — небольшая библиотека, обрабатывающая события HTML5 drag/drop и упрощающая работу с ними.
  • jQuery Mousewheel — используется для прокрутки списка фильтров.
  • также мы используем последнюю версию jQuery.

HTML разметка фильтров

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

	<title>Instagram-like Filters with jQuery | Easy-Code.ru 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>

Помимо библиотек и плагинов, перечисленных выше, мы будем использовать файл script.js (о нем мы поговорим ниже). Также в заголовке страницы мы подключаем шрифт Yanone Kaffeesatz.

JavaScript/jQuery

Для того, что бы заставить наше приложение работать, необходимо выполнить несколько шагов:

  1. Принять изображение, которое перетащили в окно браузера;
  2. Создать элемент canvas размером 500×500 (можно изменить) и сохранить его в памяти;
  3. Отслеживать клики на фильтрах. Когда какой-либо выбран:
    • Создать копию элемента canvas;
    • Удалить элементы canvas на странице;
    • Добавить копию canvas к элементу #photo;
    • Если выбран фильтр, отличный от “Normal”, применить библиотеку Caman;
    • Добавить к выбранному фильтру класс “active”.
  4. Применить фильтр “Normal”

Код assets/js/script.js

$(function() {

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

	// используем плагин fileReader для отслеживания
	// событий drag and drop элемента photo:

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

				// перетащили изображение.

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

				// удаление элементов canvas
				// удаление обработки предыдущих изображений.

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

				// если изображение успешно загружено,
				// узнаем его ширину и высоту:

				img.load(function() {

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

					// выясняем, поместится ли изображение в выделенные рамки

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

						// изображение слишком большое,
						// максимальный размер - 500x500

						if (imgWidth > imgHeight) {

							// широкое
							ratio = imgWidth / maxWidth;
							newWidth = maxWidth;
							newHeight = imgHeight / ratio;

						} else {

							// высокое или квадрат
							ratio = imgHeight / maxHeight;
							newHeight = maxHeight;
							newWidth = imgWidth / ratio;

						}

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

					// создание элемента canvas.

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

					// поместим canvas в центр

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

					// нарисовать изображение в canvas
					// с новыми размерами
					originalContext.drawImage(this, 0, 0, newWidth, newHeight);

					// больше изображение не пригодится
					img.remove();

					filterContainer.fadeIn();

					// применение фильтра "normal"
					filters.first().click();
				});

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

			beforestart: function(file){

				// Разрешить только изображения.

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

	// отслеживание кликов по фильтрам

	filters.click(function(e){

		e.preventDefault();

		var f = $(this);

		if(f.is('.active')){
			// если фильтр уже активен
			return false;
		}

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

		// копируем canvas
		var clone = originalCanvas.clone();

		// копируем изображение, хранящееся в canvas
		clone[0].getContext('2d').drawImage(originalCanvas[0],0,0);

		// добавим копию на страницу и применим
		// к ней библиотеку Caman

		photo.html(clone);

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

		Caman(clone[0], function () {

			// если фильтр существует, применим его:

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

	});

	// использование плагина mousewheel
	// для прокрутки списка фильтров

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

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

	});

});

Готово!

Данный пример будет работать в браузерах, которые поддерживают drag/drop. Некоторые фильтры требуют сложных вычислений, поэтому могут быть небольшие задержки перед отображением результата. Мы ограничили размер изображения 500 пикселями, но вы можете изменить это значение, как хотите.

Хочешь получать статьи на почту?

Подпишись на обновления!
* Ваш email не будет разглашен/продан. Вы сможете отписаться в любое время.

9 Комментариев

  1. сЕРГЕЙ says:

    Здравствуйте! Помогите разобраться с этой библиотеке. Где можно найти эту библиотеку с описаниями всех функций??

    1. root says:


      Здравствуйте. Ссылки на используемые библиотеки:
      Caman.js
      Filereader.js
      jQuery Mousewheel

  2. Александр says:

    Скажите, а как затем все это дело соханить через PHP в БД и на диск уже преобразованный файл?

    1. root says:

      Здравствуйте!
      Что бы сохранить изображение на сервере понадобится добавить js код в index.html сразу после подключения всех библиотек:

      <script type="text/javascript">
              $(document).ready(function () {
                  $("#download").click(function(e){
                      $('canvas').attr('Id', 'can');
                      var canvas = document.getElementById('can');
                      if (canvas == null) {
                          alert('You should drop your Image!');
                          return false;
                      }
                      var data = canvas.toDataURL();
                      $.post('save.php', { 'data' : data });
                  });
              });
      </script>
      

      Так же надо добавить ссылку с id=»download»:

      <a class="links" id="download" href="#save">Скачать Изображение</a>
      

      В фале save.php примерно следующее:

      $data = $_REQUEST['data'];
      file_put_contents('image.png', base64_decode(substr($data, strpos($data, 'base64') + 7)));
      
  3. Александр says:

    Все получилось, но нужно еще как-то сделать, чтобы файлы открывались не посредством дропа, а кликом например по ссылке. Это возможно? Если да, то как примерно?

    1. root says:

      Для этого можно использовать плагин Colorbox. Подключение плагина:

          <script src="assets/js/jquery.colorbox-min.js"></script>
      

      Разметка:

           <a class="links" id="view" href="#view_img">Показать изображение</a>
      
          <div style="display:none">
              <div id="view_img">
                  <img width="500" height="500" id="view_src" src="" alt=""/>
              </div>
          </div>
      

      Активация плагина:

                  $("#view").colorbox({
                      inline: true,
                      href: "#view_img",
                      fastIframe: false,
                      onLoad : function() {
                          var canvas = document.getElementById('can');
                          if (canvas == null) {
                              alert('You should drop your Image!');
                              return false;
                          }
                          var data = canvas.toDataURL();
                          document.getElementById("view_src").src = data;
                      }
                  });
      

      При нажатии на ссылку #view изображение будет показано в всплывающем окне. Я добавил эту возможность в пример этого урока, можете посмотреть как это работает.

      1. Александр says:

        Я решил попробовать сделать не так, а чтобы открывалось в новой ссылке:

        function editImage(elem, id){
        if(id == null){
        alert(‘No image’);
        return false;
        }
        /* Здесь как-то надо передать elemet (является прямой ссылкой на изображение) в canvas.toDataURL();, чтобы все прошло успешно */
        }

        Я много чего перепробовал, но ничего не выходит. Пример отправляющей функции выглядит как-то так:
        onclick=»editImage(‘image.gif’, ‘1’); return false;»
        Но вот беда, не выходит все это.
        И кстати, не подскажете, как очищать элемент canvas.toDataURL(); от изображения?

  4. ilyas says:

    А как можно сделать такое … Вот я вставил картинку , профильтровал ее. Как сделать так что бы ее отправить в PHP файл и там уже загрузить на сервер ? Мне нужно знать как это сделать в jquery

  5. Vladyslav says:

    Как сделать все это без драгндроп? Просто прописав путь к картинке? Не выходит.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *