--- title: Использование изображений slug: Web/API/Canvas_API/Tutorial/Using_images tags: - Графика translation_of: Web/API/Canvas_API/Tutorial/Using_images original_slug: Web/API/Canvas_API/Tutorial/Использование_изображений ---
До сих пор мы создавали наши собственные фигуры и применяли стили к ним. Одна из самых впечатляющих функций {{HTMLElement("canvas")}} это возможность использования изображений. Они могут быть использованы для динамического композитинга фото или как фоны графиков, для спрайтов в играх, и так далее. Внешние изображения могут быть использованы в любых поддерживаемых браузером форматах, таких как PNG, GIF, или JPEG. Вы можете даже использовать изображение, произведённое другими canvas элементами на той же странице как источник!
Импортирование изображений в canvas в основном состоит из 2 этапов:
drawImage()
.Давайте посмотрим как это сделать.
Canvas API может использовать все перечисленные далее типы данных как источник изображения:
Image()
, также как все{{HTMLElement("img")}} элементы.Эти источники совместно именуемые по типу {{domxref("CanvasImageSource")}}.
Есть несколько способов, чтобы получить изображения для использования на холсте.
Мы можем получить ссылку на изображение, на той же странице, на canvas с используя один из способов:
Использование {{htmlattrxref("crossorigin", "img")}} атрибута {{HTMLElement("img")}} элемент (отображается {{domxref("HTMLImageElement.crossOrigin")}} свойства), вы можете запросить разрешение на загрузку другого домена для использования в drawImage()
. Если хостинг домен разрешает доступ к междоменному изображению, то изображение может быть использовано в вашем canvas без without tainting it;иначе он может испортить ваш canvas.
Как и с обычными изображениями, мы можем получить доступ к другим canvas элементам используя либо {{domxref("document.getElementsByTagName()")}} либо {{domxref("document.getElementById()")}} метод. Проверьте, что в canvas источнике уже что-то нарисовано, прежде чем использовать его в целевом изображении canvas.
Одним из удобных способов было бы использование второго элемента canvas в качестве миниатюры другого большего изображения canvas.
Другой способ это создать новые {{domxref("HTMLImageElement")}} объекты в нашем скрипте. Чтобы это сделать, вы можете использовать удобный Image()
конструктор:
var img = new Image(); // Создаёт новый элемент изображения img.src = 'myImage.png'; // Устанавливает путь
Когда этот скрипт выполнится, изображение начнёт загружаться.
Если вы попытаетесь вызвать функцию drawImage()
перед тем как изображение загрузится, то скрипт ничего не сделает (или, в старых браузерах, может даже выдать исключение). Поэтому вам необходимо использовать событие load, чтобы вы не пытались сделать это прежде, чем изображение загрузится:
var img = new Image(); // Создаёт новое изображение img.addEventListener("load", function() { // здесь выполняет drawImage функцию }, false); img.src = 'myImage.png'; // Устанавливает источник файла
Если вы используете только одно стороннее изображение, то этот метод может быть хорошим примером, но если нужно следить за несколькими изображениями, то необходимо придумать что-то более умное. Хотя поиски тактики проверки загрузки изображений выходят за пределы этого обучающего курса, вы должны об этом помнить.
Другой возможный способ включить изображение это через data: url. Data URLs позволяет вам полностью определить изображение как Base64 кодированную строку символов прямо в ваш код.
var img = new Image(); // Создаёт новый элемент img img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
Одним из преимуществ data URLs это то что полученное изображение доступно сразу без других запросов туда-обратно на сервер. Другое потенциальное преимущество в том, что также можно инкапсулировать всё в одном файле все ваши CSS, JavaScript, HTML, и изображения, что делает его более портативным в других местах.
Некоторые недостатки этого метода в том что ваше изображение не кешировано, и для изображений с большим размером кодирование url может стать очень долгим процессом.
Вы также можете использовать кадры из видео представленных {{HTMLElement("video")}} элементом (даже если видео не видно). Например, если у вас есть {{HTMLElement("video")}} элемент с ID "myvideo", вы можете сделать:
function getMyVideo() { var canvas = document.getElementById('canvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); return document.getElementById('myvideo'); } }
Эта функция вернёт {{domxref("HTMLVideoElement")}} объект для этого видео, который, как мы упоминали ранее, является одним из объектов, который можно использовать как CanvasImageSource
.
Как только мы получили ссылку на источник объекта изображения, мы можем использовать метод drawImage()
для включения его в canvas. Как мы увидим далее, метод drawImage()
перегружен и у него есть несколько вариантов. В базовом варианте он выглядит как:
CanvasImageSource
в координатах (x
, y
).SVG изображения должны указывать ширину и высоту корневого <svg> элемента.
В следующем примере, мы будем использовать внешнее изображение в качестве фона для небольшого линейного графика. Использование фонов может сделать ваш скрипт значительно меньше, потому что мы можем избежать необходимости писать код для создания фона. В этом примере мы используем только один образ, поэтому я использую обработчик событий изображения объекта загрузки для выполнения операторов рисования. drawImage()
метод определяющий место фона с координатами (0, 0), которые привязаны к верхнему левому углу canvas.
<html> <body onload="draw();"> <canvas id="canvas" width="180" height="150"></canvas> </body> </html>
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ ctx.drawImage(img,0,0); ctx.beginPath(); ctx.moveTo(30,96); ctx.lineTo(70,66); ctx.lineTo(103,76); ctx.lineTo(170,15); ctx.stroke(); }; img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png'; }
Получившийся график выглядит так:
{{EmbedLiveSample("Пример_Простой_линейный_график", 220, 160, "https://mdn.mozillademos.org/files/206/Canvas_backdrop.png")}}
Второй вариант метода drawImage()
добавляет два новых параметра и позволяет разместить изображение в canvas с изменёнными размерами.
В этом примере, мы будем использовать изображение в качестве обоев и повторим его в canvas несколько раз. Это может быть сделано просто через цикл, располагая изменённые изображения на разных позициях. В коде внизу, первый цикл for
проходит по рядам. Второй цикл for
проходит по колонкам. Изображение уменьшено на треть от реального размера, которое было 50x38 пикселей.
Обратите внимание: Изображения могут стать размытыми, при большом увеличении или зернистыми при значительном уменьшении. Возможно, лучше всего не изменять размеры изображения, если на них есть текст, который должен остаться читаемым.
<html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> </body> </html>
function draw() { var ctx = document.getElementById('canvas').getContext('2d'); var img = new Image(); img.onload = function(){ for (var i=0;i<4;i++){ for (var j=0;j<3;j++){ ctx.drawImage(img,j*50,i*38,50,38); } } }; img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg'; }
Получившийся рисунок canvas выглядит так:
{{EmbedLiveSample("Пример_Тайлинг_изображения", 160, 160, "https://mdn.mozillademos.org/files/251/Canvas_scale_image.png")}}
У третьего и последнего варианта метода drawImage()
в дополнении к источнику изображения есть ещё восемь параметров . Он позволяет нам вырезать кусок из изображения, затем изменить его размер и нарисовать его в canvas.
sx
, sy
), ширина и высота - sWidth
и sHeight
и рисует в canvas, располагая его в точке (dx
, dy
) и изменяя его размер на указанные величины в dWidth
и dHeight
.Чтобы понять что делает нарезка, можно посмотреть на изображение справа. Первые четыре параметра определяют местоположение и размер фрагмента исходного изображения. Последние четыре параметра определяют прямоугольник, в который будет вписано изображение на целевом рисунке canvas.
Нарезка может быть полезным инструментом, когда вы захотите сделать композицию. Вы могли бы собрать все элементы в одном файле изображения и использовать этот метод для создания композиции. Например, если вы захотите сделать график, вы могли бы сделать PNG изображение, содержащее все необходимые тексты в одном файле и в зависимости от ваших данных, могли бы достаточно просто изменять график. Другим преимуществом является то, что нет необходимости загружать каждое изображение по отдельности, получив возможность увеличить скорость загрузки.
В этом примере, мы будем использовать того же носорога, что и в предыдущем примере, но мы отрежем его голову и включим её в рамку. Изображение рамки это 24-х битный PNG, который включает падающую тень. Так как в 24-х битные PNG изображения включается полный 8-ми битный альфа-канал, в отличие от GIF и 8-битных PNG изображений, он может быть помещён в любой фон, без беспокойства о матовом цвете.
<html> <body onload="draw();"> <canvas id="canvas" width="150" height="150"></canvas> <div style="display:none;"> <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227"> <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> </div> </body> </html>
function draw() { var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); // Рисуем фрагмент ctx.drawImage(document.getElementById('source'), 33, 71, 104, 124, 21, 20, 87, 104); // Рисуем рамку ctx.drawImage(document.getElementById('frame'),0,0); }
В этот раз мы применили другой способ загрузки изображения. Вместо загрузки методом создания новых {{domxref("HTMLImageElement")}} объектов, мы включили их как {{HTMLElement("img")}} тэги прямо в наш HTML файл и из них выбрали изображения. Изображения скрыты с помощью CSS-свойства {{cssxref("display")}}, установленного в "none" для этих изображений.
{{EmbedLiveSample("Пример_Обрамление_изображения", 160, 160, "https://mdn.mozillademos.org/files/226/Canvas_drawimage2.jpg")}}
Скрипт, сам по себе, очень простой. Каждому {{HTMLElement("img")}} присвоен атрибут ID, который делает удобным их выбор с использованием {{domxref("document.getElementById()")}}. Потом мы просто используем функцию drawImage()
, чтобы из первого изображения вырезать фрагмент носорога и вставить его в canvas, затем рисуем рамку сверху, используя второй вызов функции drawImage()
.
В последнем примере этой главы, мы построим небольшую галерею искусств. Галерея состоит из таблицы, включающей несколько изображений. Когда страница загрузится, {{HTMLElement("canvas")}} элемент вставится в каждое изображение, а вокруг будет нарисована рамка.
В этом случае, у каждого изображения фиксированная ширина и высота, такая же, как и у рамки нарисованной вокруг них. Вы могли бы усовершенствовать этот скрипт так, чтобы он использовал ширину и высоту изображения, чтобы рамка идеально его окружила.
Код ниже должен говорить сам за себя. Мы проходим циклом через {{domxref("document.images")}} контейнер и соответственно добавляем новые элементы canvas. Возможно следует упомянуть для тех, кто не слишком хорошо знаком с DOM, что для этого используется {{domxref("Node.insertBefore")}} метод. insertBefore()
это метод родительского узла (ячейки таблицы) элемента (изображения) перед которым мы хотим вставить наш новый узел (элемент canvas).
<html> <body onload="draw();"> <table> <tr> <td><img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"></td> </tr> <tr> <td><img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"></td> <td><img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"></td> </tr> </table> <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> </body> </html>
И сюда какую-нибудь CSS для украшения:
body { background: 0 -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; margin: 10px; } img { display: none; } table { margin: 0 auto; } td { padding: 15px; }
Связывая все вместе JavaScript рисует наши изображения в рамках:
function draw() { // Цикл по всем изображениям for (var i=0;i<document.images.length;i++){ // Не добавляет canvas для изображения рамки if (document.images[i].getAttribute('id')!='frame'){ // Создаёт элемент canvas var canvas = document.createElement('canvas'); canvas.setAttribute('width',132); canvas.setAttribute('height',150); // Вставляет перед изображением document.images[i].parentNode.insertBefore(canvas,document.images[i]); var ctx = canvas.getContext('2d'); // Рисует изображение в canvas ctx.drawImage(document.images[i],15,20); // Добавляет рамку ctx.drawImage(document.getElementById('frame'),0,0); } } }
{{EmbedLiveSample("Пример_галереи_искусства", 725, 400)}}
Как было отмечено ранее, изменение размеров изображений может привести к размытости или к шуму в процессе преобразования. Вы можете использовать контекст рисования {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}} свойства, чтобы контролировать использование сглаживающего алгоритма, когда изменяющиеся изображения в вашем контексте. Обычно это свойство установлено в true
, означая, что изображения будут сглажены во время изменения размеров. Вы можете отключить это свойство так:
ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false;
{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations")}}