HTML5 Canvas - вставка изображений и текста

143

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

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

Вставка в Canvas изображений

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

Холст поддерживает работу с обычными изображениями посредством метода текста рисования drawImage(). Чтобы вставить изображение в холст, методу drawImage() в параметрах передается объект изображения и координаты холста, по которым это изображение следует вставить:

// Определение контекста рисования
canvas = document.getElementById("drawingCanvas");
context = canvas.getContext("2d");

context.drawImage(img, 10, 10);

Но чтобы передать объект изображения, его сначала нужно получить. В HTML5 есть три разных способа получения объекта изображения. Первый подход — создать его самостоятельно попиксельно с помощью метода createImageData(). Но этот подход очень трудоемкий и медленный.

Второй подход — использовать уже имеющийся в разметке элемент <img>. Например, если у нас есть следующая разметка:

<img id="photo" src="face.jpg">

тогда изображение можно вставить в холст с помощью этого кода:

var img = document.getElementById("photo");
context.drawImage(img, 10, 10);

Наконец, можно создать объект изображения и загрузить изображение из отдельного файла. Недостаток этого подхода состоит в том, что изображение нельзя использовать с методом drawImage() до тех пор, пока оно полностью не загрузится. Во избежание проблем нужно подождать, пока не выполнится событие загрузки изображения onLoad, прежде чем пытаться выполнять какие-либо операции с ним.

Чтобы разобраться в этом процессе, рассмотрим пример. Допустим, нам нужно отобразить на холсте изображение face.jpg. Теоретически, это можно сделать такой последовательностью операций:

// Создаем объект изображения
var img = new Image();

// Загружаем файл изображения
img.src = "face.jpg";

// Прорисовываем изображение. (Этот шаг может не выполниться,
// т.к. изображение, может быть, еще не загрузилось.)
context.drawImage(img, 10, 10);

Здесь проблема состоит в том, что установка атрибута src начинает загрузку изображения, но код продолжает исполняться дальше, не ожидая завершения загрузки. Правильно будет использовать следующий код:

// Создаем объект изображения
var img = new Image();

// Привязываем функцию к событию onload
// Это указывает браузеру, что делать, когда изображение загружено
img.onload = function() {
	context.drawImage(img, 10, 10);
};

// Загружаем файл изображения
img.src = "face.jpg";

Этот подход может показаться нелогичным, т.к. порядок указания операций в коде не совпадает с порядком их исполнения. В данном примере вызов метода context.drawImage() происходит в последнюю очередь, вскоре после установки свойства img.src.

Изображения имеют широкий диапазон применений. Их можно использовать, чтобы приукрасить штриховые рисунки или как альтернативу рисованию изображений самому. Изображения можно использовать для разных объектов и персонажей, разместив их соответствующим образом на холсте. Изображения можно также применять для заполнения линий, чтобы придать им текстурированный вид.

Искажение рисунков в элементе Canvas

Если обнаружится, что ваше изображение по непонятной причине растянуто, сжато или искажено каким-либо другим образом, наиболее вероятной причиной этому будет установка размера холста посредством правила таблицы стилей. Правильно устанавливать размер холста надо через указание его высоты и ширины в атрибутах height и width элемента <canvas> в разметке страницы. Может показаться, что эти значения не обязательно задавать в разметке, используя такую форму тега:

<canvas id="drawingCanvas"></canvas>

а установить их в правиле таблицы стилей следующим образом:

canvas { 
   width:500px;
   height:300px;
}

Но этот подход не будет работать. Проблема состоит в том, что свойства height и width CSS отличаются от одноименных свойств элемента <canvas>. Если не указать размеры холста в разметке, будет установлен размер холста по умолчанию 300x150 пикселов. Потом таблица стилей будет растягивать или сжимать холст, чтобы подогнать его к указанным в ней размерам, изменяя соответствующим образом размеры всего содержимого холста. В результате размещенные на холсте изображения будут искажены, что, несомненно, не сделает их привлекательными.

Во избежание этой проблемы всегда нужно указывать размер холста в разметке посредством атрибутов height и width элемента <canvas>. А если нужно изменить размер холста на основе каких-либо других критериев, значения этих атрибутов изменяются в разметке с помощью JavaScript.

Обрезка, разрезка и изменение размеров изображения

Функция drawImage() принимает несколько необязательных параметров, которые позволяют манипулировать изображением на холсте. Например, размер изображения можно изменить, указав параметры width и height следующим образом:

// JS
context.drawImage(img, 10, 10, 80, 150);

В данном случае метод размещает изображение в рамке размером 80x150 пикселов, левый верхний угол которой находится в точке холста с координатами (10,10). Если первоначальный размер изображения был 160x300 пикселов, то эта операция уменьшает его размеры наполовину в обоих направлениях, в результате чего общий размер конечного изображения будет лишь в четверть размера исходного.

Если нужно вставить в холст только часть изображения, методу drawImage() необходимо передать четыре параметра в начале списка параметра. Эти параметры определяют позицию и размер части изображения, которую нужно вырезать:

context.drawImage(img, source_x, source_y, source_width, source_height,
      x, y, width, height);

Последние четыре параметра в этом коде те же, что и в предыдущем примере - они определяют позицию и размер изображения на холсте. Допустим, что мы хотим вставить в холст только верхнюю половину изображения с исходным размером 225x300 пикселов. Для этого с левого верхнего угла изображения (точка (0,0)) отрезаем часть изображения шириной в 225 и высотой в 150 пикселов, которую потом вставляем в холст в начальной точке с координатами (50,25). Все это делается в одной строчке кода:

context.drawImage(img, 0, 0, 225, 150, 50, 25, 225, 150);
Обрезание изображений на Canvas

Возможностей метода drawImage() недостаточно, если вставляемое в холст изображение нужно повернуть или скосить на определенный угол. Но эти и другие манипуляции с изображением на холсте можно выполнить с помощью трансформаций.

Видеокадр

В первом параметре метода drawImage() указывается изображение, которое нужно вставить в холст. Как мы только что увидели, таким изображением может быть созданный объект изображения или элемент <img>, расположенный где-то в другом месте разметки.

Но это не все, что можно вставить в холст посредством этого метода. Вместо изображения можно указать элемент <canvas> (но не тот, на котором выполняется настоящее рисование). Таким же образом можно вставить и элемент <video>, в котором воспроизводится видео:

var video = document.getElementById("videoPlayer");
context.drawImage(video, 0, 0, video.clientWidth, video.clientWidth);

При исполнении этого кода выполняется захват одного кадра видео, воспроизводимого в момент выполнения кода, который потом вставляется в холст.

Эта возможность открывает дверь для создания некоторых интересных эффектов. Например, с помощью таймера можно последовательно выполнять захват кадров воспроизводимого видео и вставлять их в холст. Если делать это достаточно быстро, то вставляемая в холст последовательность кадров будет создавать эффект проигрывающегося видео.

Но чтобы это не был просто другой видеопроигрыватель, захваченные кадры можно модифицировать перед тем, как вставлять их в холст. Например, вставляемый кадр можно увеличить или уменьшить или наложить какой-либо эффект в стиле Photoshop, модифицировав его на уровне пикселов. Один из примеров такой манипуляции смотрите на странице "video + canvas = magic". В нем показано, как сделать цветное видео черно-белым, преобразуя каждый цветной пиксел захваченного кадра в оттенок серого.

Вставка в холст текста

Другим типом данных, который нам вряд ли бы хотелось составлять из отдельных прямых и кривых, является текст. К счастью, разработчики HTML5 позаботились и об этом для нас и предоставляют два метода контекста рисования для работы с текстом.

Но прежде чем вставлять в холст какой-либо текст, нужно указать шрифт для него, установив значение свойства контекста font. Это значение указывается посредством строки с таким же синтаксисом, как и для универсального свойства font CSS. Как минимум, нужно указать размер шрифта в пикселах и его название. В случае неуверенности в поддержке определенного шрифта браузерами, можно указать список шрифтов:

// JS
context.font = "20px Verdana, sans-serif";

Также можно установить жирный шрифт или курсив, указав соответствующие параметры в начале строки:

// JS
context.font = "bold 20px Verdana, sans-serif";

Самое главное, благодаря CSS3 можно использовать вычурные встроенные шрифты. Для этого нужно лишь сначала зарегистрировать название шрифта в таблице стилей. После установки шрифта текст в холсте вводится с помощью метода fillText(). Например, следующий код вводит в холст строку текста, левый верхний угол которого находится в точке (10,10):

// JS
context.textBaseline = "top";
context.font = "bold 20px Arial";
context.fillStyle = "black";
context.fillText("Кто рано встает, тот точно не я.", 10, 10);

Текст можно вставлять в любое место на холсте, но только по одной строке за раз. Чтобы вставить несколько строк, нужно делать соответствующее число вызовов метода fillText().

Вместо метода fillText() можно использовать другой метод для ввода текста - strokeText(). Этот метод вводит контуры букв текста; цвет и толщина контуров определяются значениями свойств контекста strokeStyle и lineWidth. Далее показано использование этого метода:

// JS
context.font = "bold 40px Verdana,sans-serif";
context.lineWidth = 1;
context.strokeStyle = "red";
context.strokeText("Народная мудрость", 20, 50);
Ввод текста Canvas

Как уже отмечалось, метод strokeText() вводит только очертания букв. Если требуется создать текст одного цвета, а его обводку — другого, можно использовать сначала метод fillText(), а после него метод strokeText().

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

Пройди тесты
Лучший чат для C# программистов