aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/api/canvas_api/tutorial/using_images/index.html
blob: d9779506157ad8cabad11fda3ad2fdb8b6d0b2c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
---
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/Использование_изображений
---
<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Трансформации")}}</div>

<div class="summary">
<p>До сих пор мы создавали наши собственные фигуры и применяли стили к ним. Одна из самых впечатляющих функций {{HTMLElement("canvas")}} это возможность использования изображений. Они могут быть использованы для динамического композитинга фото или как фоны графиков, для спрайтов в играх, и так далее. Внешние изображения могут быть использованы в любых поддерживаемых браузером форматах, таких как PNG, GIF, или JPEG. Вы можете даже использовать изображение, произведённое другими canvas элементами на той же странице как источник!</p>
</div>

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

<ol>
 <li>Дав ссылку на {{domxref("HTMLImageElement")}} объект или для другого canvas элемента как источник. Также можно использовать изображение дав ссылку на URL.</li>
 <li>Для рисования изображения на canvas используется функция <code>drawImage()</code>.</li>
</ol>

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

<h2 id="Использование_изображений_для_рисования">Использование изображений для рисования</h2>

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

<dl>
 <dt>{{domxref("HTMLImageElement")}}</dt>
 <dd>Эти изображения созданы, используя конструктор <code>Image()</code>, также как все{{HTMLElement("img")}} элементы.</dd>
 <dt>{{domxref("HTMLVideoElement")}}</dt>
 <dd>Используя HTML {{HTMLElement("video")}} элемент как источник изображения захватывает текущий кадр из видео и использует его как изображение.</dd>
 <dt>{{domxref("HTMLCanvasElement")}}</dt>
 <dd>Вы можете использовать другой {{HTMLElement("canvas")}} элемент как источник изображения.</dd>
</dl>

<p>Эти источники совместно именуемые по типу {{domxref("CanvasImageSource")}}.</p>

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

<h3 id="Использование_изображений_из_той_же_страницы">Использование изображений из той же страницы</h3>

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

<ul>
 <li> {{domxref("document.images")}} коллекция</li>
 <li>The {{domxref("document.getElementsByTagName()")}} метод</li>
 <li>Если вы знаете id конкретного изображения, который вы хотите использовать, вы можете использовать {{domxref("document.getElementById ()")}}, чтобы получить это конкретное изображение</li>
</ul>

<h3 id="Использование_изображений_из_других_доменов">Использование изображений из других доменов</h3>

<p>Использование {{htmlattrxref("crossorigin", "img")}} атрибута {{HTMLElement("img")}} элемент (отображается  {{domxref("HTMLImageElement.crossOrigin")}} свойства), вы можете запросить разрешение на загрузку другого домена для использования в <code>drawImage()</code>. Если хостинг домен разрешает доступ к междоменному изображению, то изображение может быть использовано в вашем canvas без  without tainting it;иначе он может испортить ваш canvas.</p>

<h3 id="Использование_других_canvas_элементов">Использование других canvas элементов</h3>

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

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

<h3 id="Создание_изображений_с_нуля">Создание изображений с нуля</h3>

<p>Другой способ это создать новые {{domxref("HTMLImageElement")}} объекты в нашем скрипте.  Чтобы это сделать, вы можете использовать удобный <code>Image()</code> конструктор:</p>

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

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

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

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

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

<h3 id="Вложение_изображения_с_помощью_данных_URL">Вложение изображения с помощью данных: URL</h3>

<p>Другой возможный способ включить изображение это через <a class="external" href="/en-US/docs/Web/HTTP/data_URIs" rel="external" title="http://en.wikipedia.org/wiki/Data:_URL">data: url</a>. Data URLs позволяет вам полностью определить изображение как Base64 кодированную строку символов прямо в ваш код.</p>

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

<p>Одним из преимуществ data URLs  это то что полученное изображение доступно сразу без других запросов туда-обратно на сервер. Другое потенциальное преимущество в том, что также можно инкапсулировать всё в одном файле все ваши <a href="/en-US/docs/Web/CSS" title="/en-US/docs/Web/CSS">CSS</a>, <a href="/en-US/docs/Web/JavaScript" title="/en-US/docs/Web/JavaScript">JavaScript</a>, <a href="/en-US/docs/Web/HTML" title="/en-US/docs/Web/HTML">HTML</a>, и изображения, что делает его более портативным в других местах.</p>

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

<h3 id="Использование_кадров_из_видео">Использование кадров из видео</h3>

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

<pre class="brush: js">function getMyVideo() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    return document.getElementById('myvideo');
  }
}
</pre>

<p>Эта функция вернёт {{domxref("HTMLVideoElement")}} объект для этого видео, который, как мы упоминали ранее, является одним из объектов, который можно использовать как <code>CanvasImageSource</code>.</p>

<h2 id="Рисование_изображений">Рисование изображений</h2>

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

<dl>
 <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, x, y)")}}</dt>
 <dd>Рисует  изображение, указанное в <code>CanvasImageSource</code> в координатах  (<code>x</code>, <code>y</code>).</dd>
</dl>

<div class="note">
<p>SVG изображения должны указывать ширину и высоту корневого  &lt;svg&gt; элемента.</p>
</div>

<h3 id="Пример_Простой_линейный_график">Пример: Простой линейный график</h3>

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

<div class="hidden">
<pre class="brush: html">&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="180" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<pre class="brush: js;highlight[5]">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';
}</pre>

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

<p>{{EmbedLiveSample("Пример_Простой_линейный_график", 220, 160, "https://mdn.mozillademos.org/files/206/Canvas_backdrop.png")}}</p>

<h2 id="Изменение_размеров">Изменение размеров</h2>

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

<dl>
 <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, x, y, width, height)")}}</dt>
 <dd>Это добавляет параметр ширины и высоты, которые указывают до какого размера нужно изменить изображение при рисовании его в  canvas.</dd>
</dl>

<h3 id="Пример_Тайлинг_изображения">Пример: Тайлинг изображения</h3>

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

<div class="note">
<p><strong>Обратите внимание</strong>: Изображения могут стать размытыми, при большом увеличении или зернистыми при значительном уменьшении. Возможно, лучше всего не изменять размеры изображения, если на них есть текст, который должен остаться читаемым. </p>
</div>

<div class="hidden">
<pre class="brush: html">&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
</div>

<pre class="brush: js">function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function(){
    for (var i=0;i&lt;4;i++){
      for (var j=0;j&lt;3;j++){
        ctx.drawImage(img,j*50,i*38,50,38);
      }
    }
  };
  img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
}</pre>

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

<p>{{EmbedLiveSample("Пример_Тайлинг_изображения", 160, 160, "https://mdn.mozillademos.org/files/251/Canvas_scale_image.png")}}</p>

<h2 id="Нарезка">Нарезка</h2>

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

<dl>
 <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)")}}</dt>
 <dd>В данном изображении, эта функция берёт фрагмент из изображения, в виде прямоугольника, левый верхний угол которого -  (<code>sx</code>, <code>sy</code>), ширина и высота -  <code>sWidth</code> и <code>sHeight</code> и рисует  в  canvas, располагая его в точке  (<code>dx</code>, <code>dy</code>) и изменяя его размер на указанные величины в  <code>dWidth</code> и <code>dHeight</code>.</dd>
</dl>

<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/225/Canvas_drawimage.jpg" style="float: right; height: 290px; width: 300px;">Чтобы понять что  делает нарезка, можно посмотреть на изображение справа. Первые четыре параметра определяют местоположение и размер фрагмента исходного изображения.  Последние четыре параметра определяют прямоугольник, в который будет вписано изображение на целевом рисунке  canvas.</p>

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

<h3 id="Пример_Обрамление_изображения">Пример: Обрамление изображения</h3>

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

<pre class="brush: html">&lt;html&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
   &lt;div style="display:none;"&gt;
     &lt;img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227"&gt;
     &lt;img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"&gt;
   &lt;/div&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>

<pre class="brush: 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);
}</pre>

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

<p>{{EmbedLiveSample("Пример_Обрамление_изображения", 160, 160, "https://mdn.mozillademos.org/files/226/Canvas_drawimage2.jpg")}}</p>

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

<h2 id="Пример_галереи_искусства">Пример галереи искусства</h2>

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

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

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

<pre class="brush: html">&lt;html&gt;
 &lt;body onload="draw();"&gt;
     &lt;table&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"&gt;&lt;/td&gt;
        &lt;td&gt;&lt;img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"&gt;&lt;/td&gt;
      &lt;/tr&gt;
     &lt;/table&gt;
     &lt;img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>

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

<pre class="brush: 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;
}
</pre>

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

<pre class="brush: js">function draw() {

  // Цикл по всем изображениям
  for (var i=0;i&lt;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);
    }
  }
}</pre>

<p>{{EmbedLiveSample("Пример_галереи_искусства", 725, 400)}}</p>

<h2 id="Контроль_изменений_размеров_изображения">Контроль изменений размеров изображения</h2>

<p>Как было отмечено ранее, изменение размеров изображений может привести к размытости или к шуму в процессе преобразования. Вы можете использовать контекст рисования {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}} свойства, чтобы контролировать использование сглаживающего алгоритма, когда изменяющиеся изображения в вашем контексте. Обычно это свойство установлено в  <code>true</code>, означая, что изображения будут сглажены во время изменения размеров. Вы можете отключить это свойство так:</p>

<pre class="brush: js">ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
</pre>

<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations")}}</p>