Создайте инструмент для обрезки изображений с использованием HTML5

JavaScriptJavaScriptBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом проекте вас проведет по процессу создания простого инструмента для обрезки изображений. В конце вы получите интерактивное приложение, которое позволяет пользователям загружать, отображать и обрезать изображения.

👀 Предпросмотр

Демонстрация инструмента для обрезки изображений

🎯 Задачи

В этом проекте вы научитесь:

  • Как создать HTML-структуру для инструмента обрезки изображений
  • Как стилизовать веб-страницу с использованием CSS, чтобы сделать ее визуально привлекательной
  • Как инициализировать переменные и обработчики событий с использованием JavaScript для обработки взаимодействий пользователя
  • Как обрабатывать загрузку и отображение изображений с использованием API FileReader в JavaScript
  • Как реализовать механизм обрезки с использованием API Canvas в JavaScript
  • Как сохранять обрезанное изображение и отображать результат

🏆 Достижения

После завершения этого проекта вы сможете:

  • Разбираться в HTML-тегах и структуре
  • Эффективно применять свойства и селекторы CSS
  • Использовать синтаксис, переменные и обработчики событий JavaScript
  • Использовать API FileReader в JavaScript для обработки загрузки файлов
  • Реализовать обработку изображений с использованием API Canvas в JavaScript

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL javascript(("JavaScript")) -.-> javascript/BasicConceptsGroup(["Basic Concepts"]) javascript(("JavaScript")) -.-> javascript/DOMManipulationGroup(["DOM Manipulation"]) javascript/BasicConceptsGroup -.-> javascript/variables("Variables") javascript/DOMManipulationGroup -.-> javascript/dom_select("DOM Selection") javascript/DOMManipulationGroup -.-> javascript/dom_manip("DOM Manipulation") javascript/DOMManipulationGroup -.-> javascript/event_handle("Event Handling") subgraph Lab Skills javascript/variables -.-> lab-445698{{"Создайте инструмент для обрезки изображений с использованием HTML5"}} javascript/dom_select -.-> lab-445698{{"Создайте инструмент для обрезки изображений с использованием HTML5"}} javascript/dom_manip -.-> lab-445698{{"Создайте инструмент для обрезки изображений с использованием HTML5"}} javascript/event_handle -.-> lab-445698{{"Создайте инструмент для обрезки изображений с использованием HTML5"}} end

Разместите HTML-структуру

Требования:

  • Знание HTML-тегов и структуры.

Функциональность:

  • Создайте интерфейс, который позволяет пользователям загружать изображение и запускать процесс обрезки.

Вставьте HTML-код в файл index.html.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HTML5 Crop Image</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <input type="file" name="file" id="post_file" />

    <button id="save_button">СОХРАНИТЬ</button>
    <div id="label">
      <canvas id="get_image"></canvas>
      <p>
        <canvas id="cover_box"></canvas>
        <canvas id="edit_pic"></canvas>
      </p>
    </div>
    <p>
      <span id="show_edit"></span>
      <span id="show_pic"><img src="" /></span>
    </p>
    <script type="text/javascript" src="main.js"></script>
  </body>
</html>

Три тега <canvas>, упомянутые выше, используются для обработки содержимого, связанного с изображениями. Подробная обработка будет представлена в последующем коде на js (JavaScript). Элементы с идентификаторами show_edit и show_pic предназначены для предварительного просмотра изображения и просмотра результата генерации конечного изображения.

✨ Проверить решение и практиковаться

Стилизуйте веб-страницу

Требования:

  • Знание CSS-свойств и селекторов.

Функциональность:

  • Стилизуйте HTML-элементы, чтобы интерфейс был удобным для пользователя и визуально привлекательным.

Вставьте CSS в файл style.css.

body {
  background-color: #f6f6f6;
  margin: 0;
  padding: 20px;
  text-align: center;
}

#label {
  border: 1px solid #ccc;
  background-color: #fff;
  text-align: center;
  height: 300px;
  width: 300px;
  margin: 20px auto;
  position: relative;
}

#get_image {
  position: absolute;
}

#edit_pic {
  position: absolute;
  display: none;
  background: #000;
}

#cover_box {
  position: absolute;
  z-index: 9999;
  display: none;
  top: 0px;
  left: 0px;
}

#show_edit {
  margin: 0 auto;
  display: inline-block;
}

#show_pic {
  height: 100px;
  width: 100px;
  border: 2px solid #000;
  overflow: hidden;
  margin: 0 auto;
  display: inline-block;
}

canvas {
  position: absolute;
  top: 0;
  left: 0;
}

#save_button {
  padding: 8px 16px;
  background-color: #3498db;
  color: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.2s;
}

#save_button:hover {
  background-color: #2980b9;
}

input[type="file"] {
  margin-bottom: 20px;
}
✨ Проверить решение и практиковаться

Инициализируйте переменные и обработчики событий

Требования:

  • Основное понимание синтаксиса JavaScript, переменных и обработчиков событий.

Функциональность:

  • Инициализируйте свойства и настройки для инструмента обрезки. Добавьте обработчик событий для обработки загруженного изображения.

В файле main.js напишите код для инициализации свойств инструмента обрезки и настройки обработчиков событий.

var postFile = {
  init: function () {
    var t = this;
    t.regional = document.getElementById("label");
    t.getImage = document.getElementById("get_image");
    t.editPic = document.getElementById("edit_pic");
    t.editBox = document.getElementById("cover_box");
    t.px = 0; //координата x фонового изображения
    t.py = 0; //координата y фонового изображения
    t.sx = 15; //координата x области обрезки
    t.sy = 15; //координата y области обрезки
    t.sHeight = 150; //высота области обрезки
    t.sWidth = 150; //ширина области обрезки
    document
      .getElementById("post_file")
      .addEventListener("change", t.handleFiles, false);
  }
};

Все наши функции и переменные封装рованы внутри объекта postFile. Функция init, упомянутая выше, в основном устанавливает некоторые начальные значения.

t.px = 0;
t.py = 0;
t.sx = 15;
t.sy = 15;
t.sHeight = 100;
t.sWidth = 100;

Переменные t.px и t.py представляют координаты фонового изображения в области предварительного просмотра в режиме реального времени; t.sx, t.sy, t.sHeight и t.sWidth представляют координаты x, y изображения и его ширину, высоту соответственно.

Мы также получаем несколько элементов, с которыми мы будем работать позже, с помощью document.getElementById.

document
  .getElementById("post_file")
  .addEventListener("change", t.handleFiles, false);

Мы слушаем событие change формы input с id post_file для обработки файлов, загруженных пользователем. Здесь мы делегируем это функции handleFiles. Поэтому, далее мы реализуем функцию handleFiles.

✨ Проверить решение и практиковаться

Обработайте загрузку и отображение изображений

Требования:

  • Основное знание API FileReader в JavaScript.

Функциональность:

  • Убедитесь, что когда пользователи загружают изображение, оно корректно обрабатывается, читается и отображается на экране.

Расширьте файл main.js функциями для обработки и отображения загруженного изображения.

  1. Для реализации функции handleFiles

    Здесь мы используем HTML5 File API. Во - первых, вызывая new FileReader(), мы создаем экземпляр объекта FileReader под названием oFReader. Затем мы вызываем его метод readAsDataURL() для чтения содержимого файла и преобразования его в формат, закодированный в base64.

    Наконец, когда файл полностью прочитан и загружен, мы обрабатываем прочитанное изображение с использованием postFile.paintImage(oFREvent.target.result). Простыми словами, мы перерисовываем данные изображения, которые мы прочитали, на браузере.

handleFiles: function () {
        var fileList = this.files[0];
        var oFReader = new FileReader();
        oFReader.readAsDataURL(fileList);
        oFReader.onload = function (oFREvent) {
            postFile.paintImage(oFREvent.target.result);
        };
},
  1. Для реализации функции paintImage

    Самый важный шаг здесь - это нарисовать изображение в соответствии с размером контейнера с использованием canvas. В предыдущем шаге, используя FileReader из File API, мы уже получили URL изображения, которое мы хотим загрузить (значение oFREvent.target.result). Следующим шагом является использование canvas для рисования этого изображения. Во - первых, мы используем getImage.getContext для получения 2d - содержимого <canvas id="get_image"></canvas>, что можно упрощенно понять, как содержимое изображения. Затем мы используем new Image() для создания элемента <img> и задаем значение его атрибута src.

paintImage: function (url) {
        var t = this;
        var createCanvas = t.getImage.getContext("2d");
        var img = new Image();
        img.src = url;
        img.onload = function () {
            if (
                img.width < t.regional.offsetWidth &&
                img.height < t.regional.offsetHeight
            ) {
                t.imgWidth = img.width;
                t.imgHeight = img.height;
            } else {
                var pWidth = img.width / (img.height / t.regional.offsetHeight);
                var pHeight = img.height / (img.width / t.regional.offsetWidth);
                t.imgWidth = img.width > img.height? t.regional.offsetWidth : pWidth;
                t.imgHeight =
                    img.height > img.width? t.regional.offsetHeight : pHeight;
            }
            t.px = (t.regional.offsetWidth - t.imgWidth) / 2 + "px";
            t.py = (t.regional.offsetHeight - t.imgHeight) / 2 + "px";

            t.getImage.height = t.imgHeight;
            t.getImage.width = t.imgWidth;
            t.getImage.style.left = t.px;
            t.getImage.style.top = t.py;

            createCanvas.drawImage(img, 0, 0, t.imgWidth, t.imgHeight);
            t.imgUrl = t.getImage.toDataURL();
            t.cutImage();
            t.drag();
        };
},

Внутри функции img.onload наша главная цель - перерисовать изображение в исходном размере, сохраняя при этом его пропорции, поэтому мы имеем условие if. В конце мы используем строку кода createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight); для фактического отображения изображения.

✨ Проверить решение и практиковаться

Реализуйте механизм обрезки

Требования:

  • Знание API Canvas в JavaScript для рисования и манипуляций с изображениями.

Функциональность:

  • Добавьте область обрезки на отображенном изображении и сделайте эту область перетаскиваемой. Это дает пользователям возможность выбирать желаемую область для обрезки.

Добавьте соответствующие методы в main.js.

  1. Создайте метод cutImage

    Метод cutImage в основном отвечает за две задачи: одна - создать маску, а вторая - использовать CSS - свойство background для предоставления实时-предпросмотра выбранной области обрезки.

cutImage: function () {
        var t = this;

        t.editBox.height = t.imgHeight;
        t.editBox.width = t.imgWidth;
        t.editBox.style.display = "block";
        t.editBox.style.left = t.px;
        t.editBox.style.top = t.py;

        var cover = t.editBox.getContext("2d");
        cover.fillStyle = "rgba(0, 0, 0, 0.5)";
        cover.fillRect(0, 0, t.imgWidth, t.imgHeight);
        cover.clearRect(t.sx, t.sy, t.sHeight, t.sWidth);

        document.getElementById("show_edit").style.background =
            "url(" + t.imgUrl + ")" + -t.sx + "px " + -t.sy + "px no-repeat";
        document.getElementById("show_edit").style.height = t.sHeight + "px";
        document.getElementById("show_edit").style.width = t.sWidth + "px";
},
  1. Создайте метод drag
drag: function () {
        var t = this;
        var draging = false;
        var startX = 0;
        var startY = 0;

        document.getElementById("cover_box").onmousemove = function (e) {
            var pageX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
            var pageY = e.pageY - (t.regional.offsetTop + this.offsetTop);

            if (
                pageX > t.sx &&
                pageX < t.sx + t.sWidth &&
                pageY > t.sy &&
                pageY < t.sy + t.sHeight
            ) {
                this.style.cursor = "move";

                this.onmousedown = function () {
                    draging = true;

                    t.ex = t.sx;
                    t.ey = t.sy;

                    startX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
                    startY = e.pageY - (t.regional.offsetTop + this.offsetTop);
                };
                window.onmouseup = function () {
                    draging = false;
                };

                if (draging) {
                    if (t.ex + (pageX - startX) < 0) {
                        t.sx = 0;
                    } else if (t.ex + (pageX - startX) + t.sWidth > t.imgWidth) {
                        t.sx = t.imgWidth - t.sWidth;
                    } else {
                        t.sx = t.ex + (pageX - startX);
                    }

                    if (t.ey + (pageY - startY) < 0) {
                        t.sy = 0;
                    } else if (t.ey + (pageY - startY) + t.sHeight > t.imgHeight) {
                        t.sy = t.imgHeight - t.sHeight;
                    } else {
                        t.sy = t.ey + (pageY - startY);
                    }

                    t.cutImage();
                }
            } else {
                this.style.cursor = "auto";
            }
        };
},

Для понимания этого метода вам нужно понять следующие ключевые моменты:

var pageX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
var pageY = e.pageY - (t.regional.offsetTop + this.offsetTop);

С помощью двух строк кода выше мы получаем расстояние между мышью и фоновым изображением. e.pageX представляет расстояние от мыши до левого края браузера, а t.regional.offsetLeft + this.offsetLeft вычисляет расстояние от изображения до левого края браузера. Аналогично можно вывести расстояние сверху.

 if ( pageX > t.sx && pageX < t.sx + t.sWidth && pageY > t.sy && pageY < t.sy + t.sHeight )

После того, как вы поняли расстояние между мышью и фоновым изображением, это должно быть легко понять: оно определяет, находится ли мышь внутри области изображения.

t.ex = t.sx;
t.ey = t.sy;

startX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
startY = e.pageY - (t.regional.offsetTop + this.offsetTop);

Эти два фрагмента кода заслуживают особого внимания. Первые две строки записывают координаты из последнего скриншота (или если предыдущего не было, то начальные координаты); следующие две строки записывают координаты, когда кнопка мыши нажата. Вы можете проверить эти значения отдельно с помощью console.log().

if (draging) {
  if (t.ex + (pageX - startX) < 0) {
    t.sx = 0;
  } else if (t.ex + (pageX - startX) + t.sWidth > t.imgWidth) {
    t.sx = t.imgWidth - t.sWidth;
  } else {
    t.sx = t.ex + (pageX - startX);
  }

  if (t.ey + (pageY - startY) < 0) {
    t.sy = 0;
  } else if (t.ey + (pageY - startY) + t.sHeight > t.imgHeight) {
    t.sy = t.imgHeight - t.sHeight;
  } else {
    t.sy = t.ey + (pageY - startY);
  }

  t.cutImage();
}

Вышеописанный код по существу говорит: если мы в процессе перетаскивания, то нужно обновлять значения t.sx и t.sy в реальном времени в зависимости от изменения координат и вызывать метод cutImage для предоставления实时-предпросмотра.

Координаты области обрезки при движении = последняя записанная позиция + (текущая позиция мыши - позиция, когда кнопка мыши была нажата)

✨ Проверить решение и практиковаться

Сохраните обрезанное изображение

Требования:

  • Знание использования canvas для извлечения и отображения данных изображения.

Функциональность:

  • После обрезания желаемой области изображения позволяет пользователям сохранить эту обрезанную область, отображая результат на экране.

Расширьте функцию инициализации в main.js для обработки сохранения обрезанного изображения.

var postFile = {
  init: function () {
    //...
    document.getElementById("save_button").onclick = function () {
      t.editPic.height = t.sHeight;
      t.editPic.width = t.sWidth;
      var ctx = t.editPic.getContext("2d");
      var images = new Image();
      images.src = t.imgUrl;

      images.onload = function () {
        ctx.drawImage(
          images,
          t.sx,
          t.sy,
          t.sHeight,
          t.sWidth,
          0,
          0,
          t.sHeight,
          t.sWidth
        );
        document.getElementById("show_pic").getElementsByTagName("img")[0].src =
          t.editPic.toDataURL();
      };
    };
  }
};
postFile.init();

Похоже на реализацию метода paintImage, мы сначала слушаем событие нажатия на кнопку сохранения. Затем мы используем метод drawImage для отображения выбранной области изображения. Наконец, мы используем метод toDataURL для преобразования изображения в формат, закодированный в base64. Это значение затем присваивается атрибуту src элемента img внутри show_pic. Таким образом, обрезание и сохранение изображения завершаются.

✨ Проверить решение и практиковаться

Протестируйте инструмент

  • Откройте index.html в веб - браузере.
    open web
  • Загрузите изображение и протестируйте функциональность обрезки.
  • Эффект страницы выглядит так:
    image cropping tool demo
✨ Проверить решение и практиковаться

Резюме

Поздравляем! Вы построили базовый инструмент для обрезки изображений с использованием HTML5 и JavaScript. На этом фундаменте можно строить более продвинутые функциональности или выполнять другие задачи по манипуляция с изображениями. Практикуйтесь, улучшая инструмент или исследуя другие проекты веб - разработки!