Использование изображений
=========================

* « Предыдущая статья
* Следующая статья »

До сих пор мы создавали наши собственные фигуры и применяли стили к ним. Одна из самых впечатляющих функций `<canvas>` это возможность использования изображений. Они могут быть использованы для динамического композитинга фото или как фоны графиков, для спрайтов в играх, и так далее. Внешние изображения могут быть использованы в любых поддерживаемых браузером форматах, таких как PNG, GIF, или JPEG. Вы можете даже использовать изображение, произведённое другими canvas элементами на той же странице как источник!

Импортирование изображений в canvas в основном состоит из 2 этапов:

1. Дав ссылку на `HTMLImageElement` объект или для другого canvas элемента как источник. Также можно использовать изображение дав ссылку на URL.
2. Для рисования изображения на canvas используется функция `drawImage()`.

Давайте посмотрим как это сделать.

Использование изображений для рисования
---------------------------------------

Canvas API может использовать все перечисленные далее типы данных как источник изображения:

`HTMLImageElement`

Эти изображения созданы, используя конструктор `Image()`, также как все`<img>` элементы.

`HTMLVideoElement`

Используя HTML `<video>` элемент как источник изображения захватывает текущий кадр из видео и использует его как изображение.

`HTMLCanvasElement`

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

Эти источники совместно именуемые по типу `CanvasImageSource` (en-US).

Есть несколько способов, чтобы получить изображения для использования на холсте.

### Использование изображений из той же страницы

Мы можем получить ссылку на изображение, на той же странице, на canvas с используя один из способов:

* `document.images` коллекция
* The `document.getElementsByTagName()` метод
* Если вы знаете id конкретного изображения, который вы хотите использовать, вы можете использовать `document.getElementById ()`, чтобы получить это конкретное изображение
### Использование изображений из других доменов

Использование `crossorigin` атрибута `<img>` элемент (отображается `HTMLImageElement.crossOrigin` (en-US) свойства), вы можете запросить разрешение на загрузку другого домена для использования в `drawImage()`. Если хостинг домен разрешает доступ к междоменному изображению, то изображение может быть использовано в вашем canvas без without tainting it;иначе он может испортить ваш canvas.

### Использование других canvas элементов

Как и с обычными изображениями, мы можем получить доступ к другим canvas элементам используя либо `document.getElementsByTagName()` либо `document.getElementById()` метод. Проверьте, что в canvas источнике уже что-то нарисовано, прежде чем использовать его в целевом изображении canvas.

Одним из удобных способов было бы использование второго элемента canvas в качестве миниатюры другого большего изображения canvas.

### Создание изображений с нуля

Другой способ это создать новые `HTMLImageElement` объекты в нашем скрипте. Чтобы это сделать, вы можете использовать удобный `Image()` конструктор:


```js
var img = new Image(); // Создаёт новый элемент изображения
img.src = "myImage.png"; // Устанавливает путь
```


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

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


```js
var img = new Image(); // Создаёт новое изображение
img.addEventListener(
  "load",
  function () {
    // здесь выполняет drawImage функцию
  },
  false,
);
img.src = "myImage.png"; // Устанавливает источник файла
```


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

### Вложение изображения с помощью данных: URL

Другой возможный способ включить изображение это через data: url (en-US). Data URLs позволяет вам полностью определить изображение как Base64 кодированную строку символов прямо в ваш код.


```js
var img = new Image(); // Создаёт новый элемент img
img.src =
  "data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==";
```


Одним из преимуществ data URLs это то что полученное изображение доступно сразу без других запросов туда-обратно на сервер. Другое потенциальное преимущество в том, что также можно инкапсулировать всё в одном файле все ваши CSS, JavaScript, HTML, и изображения, что делает его более портативным в других местах.

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

### Использование кадров из видео

Вы также можете использовать кадры из видео представленных `<video>` элементом (даже если видео не видно). Например, если у вас есть `<video>` элемент с ID "myvideo", вы можете сделать:


```js
function getMyVideo() {
  var canvas = document.getElementById("canvas");
  if (canvas.getContext) {
    var ctx = canvas.getContext("2d");

    return document.getElementById("myvideo");
  }
}
```


Эта функция вернёт `HTMLVideoElement` объект для этого видео, который, как мы упоминали ранее, является одним из объектов, который можно использовать как `CanvasImageSource`.

Рисование изображений
---------------------

Как только мы получили ссылку на источник объекта изображения, мы можем использовать метод `drawImage()` для включения его в canvas. Как мы увидим далее, метод `drawImage()` перегружен и у него есть несколько вариантов. В базовом варианте он выглядит как:

`drawImage(image, x, y)`

Рисует изображение, указанное в `CanvasImageSource` в координатах (`x`, `y`).


**Примечание:** SVG изображения должны указывать ширину и высоту корневого <svg> элемента.

### Пример: Простой линейный график

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

<html>
  <body onload="draw();">
    <canvas id="canvas" width="180" height="150"></canvas>
  </body>
</html>
```



```js
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 = "backdrop.png";
}
```


Получившийся график выглядит так:

| Screenshot | Live sample |
| --- | --- |
|  |  |

Изменение размеров
------------------

Второй вариант метода `drawImage()` добавляет два новых параметра и позволяет разместить изображение в canvas с изменёнными размерами.

`drawImage(image, x, y, width, height)`

Это добавляет параметр ширины и высоты, которые указывают до какого размера нужно изменить изображение при рисовании его в canvas.

### Пример: Тайлинг изображения

В этом примере, мы будем использовать изображение в качестве обоев и повторим его в canvas несколько раз. Это может быть сделано просто через цикл, располагая изменённые изображения на разных позициях. В коде внизу, первый цикл `for` проходит по рядам. Второй цикл `for` проходит по колонкам. Изображение уменьшено на треть от реального размера, которое было 50x38 пикселей.

**Примечание:** Изображения могут стать размытыми, при большом увеличении или зернистыми при значительном уменьшении. Возможно, лучше всего не изменять размеры изображения, если на них есть текст, который должен остаться читаемым.
```

<html>
  <body onload="draw();">
    <canvas id="canvas" width="150" height="150"></canvas>
  </body>
</html>
```



```js
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 = "rhino.jpg";
}
```


Получившийся рисунок canvas выглядит так:

| Screenshot | Live sample |
| --- | --- |
|  |  |

Нарезка
-------

У третьего и последнего варианта метода `drawImage()` в дополнении к источнику изображения есть ещё восемь параметров . Он позволяет нам вырезать кусок из изображения, затем изменить его размер и нарисовать его в canvas.

`drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)`

В данном изображении, эта функция берёт фрагмент из изображения, в виде прямоугольника, левый верхний угол которого - (`sx`, `sy`), ширина и высота - `sWidth` и `sHeight` и рисует в canvas, располагая его в точке (`dx`, `dy`) и изменяя его размер на указанные величины в `dWidth` и `dHeight`.


![](/ru/docs/Web/API/Canvas_API/Tutorial/Using_images/canvas_drawimage.jpg)Чтобы понять что делает нарезка, можно посмотреть на изображение справа. Первые четыре параметра определяют местоположение и размер фрагмента исходного изображения. Последние четыре параметра определяют прямоугольник, в который будет вписано изображение на целевом рисунке canvas.

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

### Пример: Обрамление изображения

В этом примере, мы будем использовать того же носорога, что и в предыдущем примере, но мы отрежем его голову и включим её в рамку. Изображение рамки это 24-х битный PNG, который включает падающую тень. Так как в 24-х битные PNG изображения включается полный 8-ми битный альфа-канал, в отличие от GIF и 8-битных PNG изображений, он может быть помещён в любой фон, без беспокойства о матовом цвете.


```html
<html>
  <body onload="draw();">
    <canvas id="canvas" width="150" height="150"></canvas>
    <div style="display:none;">
      <img id="source" src="rhino.jpg" width="300" height="227" />
      <img id="frame" src="canvas\_picture\_frame.png" width="132" height="150" />
    </div>
  </body>
</html>
```



```js
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);
}
```


В этот раз мы применили другой способ загрузки изображения. Вместо загрузки методом создания новых `HTMLImageElement` объектов, мы включили их как `<img>` тэги прямо в наш HTML файл и из них выбрали изображения. Изображения скрыты с помощью CSS-свойства `display`, установленного в "none" для этих изображений.

| Screenshot | Live sample |
| --- | --- |
|  |  |

Скрипт, сам по себе, очень простой. Каждому `<img>` присвоен атрибут ID, который делает удобным их выбор с использованием `document.getElementById()`. Потом мы просто используем функцию `drawImage()`, чтобы из первого изображения вырезать фрагмент носорога и вставить его в canvas, затем рисуем рамку сверху, используя второй вызов функции `drawImage()`.

Пример галереи искусства
------------------------

В последнем примере этой главы, мы построим небольшую галерею искусств. Галерея состоит из таблицы, включающей несколько изображений. Когда страница загрузится, `<canvas>` элемент вставится в каждое изображение, а вокруг будет нарисована рамка.

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

Код ниже должен говорить сам за себя. Мы проходим циклом через `document.images` контейнер и соответственно добавляем новые элементы canvas. Возможно следует упомянуть для тех, кто не слишком хорошо знаком с DOM, что для этого используется `Node.insertBefore` метод. `insertBefore()` это метод родительского узла (ячейки таблицы) элемента (изображения) перед которым мы хотим вставить наш новый узел (элемент canvas).


```html
<html>
  <body onload="draw();">
    <table>
      <tr>
        <td><img src="gallery\_1.jpg" /></td>
        <td><img src="gallery\_2.jpg" /></td>
        <td><img src="gallery\_3.jpg" /></td>
        <td><img src="gallery\_4.jpg" /></td>
      </tr>
      <tr>
        <td><img src="gallery\_5.jpg" /></td>
        <td><img src="gallery\_6.jpg" /></td>
        <td><img src="gallery\_7.jpg" /></td>
        <td><img src="gallery\_8.jpg" /></td>
      </tr>
    </table>
    <img id="frame" src="canvas\_picture\_frame.png" width="132" height="150" />
  </body>
</html>
```


И сюда какую-нибудь CSS для украшения:


```css
body {
  background: 0 -100px repeat-x url(bg\_gallery.png) #4f191a;
  margin: 10px;
}

img {
  display: none;
}

table {
  margin: 0 auto;
}

td {
  padding: 15px;
}
```


Связывая все вместе JavaScript рисует наши изображения в рамках:


```js
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);
    }
  }
}
```

Контроль изменений размеров изображения
---------------------------------------

Как было отмечено ранее, изменение размеров изображений может привести к размытости или к шуму в процессе преобразования. Вы можете использовать контекст рисования `imageSmoothingEnabled` (en-US) свойства, чтобы контролировать использование сглаживающего алгоритма, когда изменяющиеся изображения в вашем контексте. Обычно это свойство установлено в `true`, означая, что изображения будут сглажены во время изменения размеров. Вы можете отключить это свойство так:


```js
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
```

* « Предыдущая статья
* Следующая статья »