Compare Revisions

使用影像

版本 274216:

Revision 274216 by happysadman on

版本 222218:

Revision 222218 by happysadman on

標題:
使用影像
使用影像
URL代稱:
Canvas_教學/使用影像
Canvas_教學/使用影像
內容:

修訂版本 274216
修訂版本 222218
t7    <p>t
8      Canvas 其中一項有趣的功能就是能夠使用影像。可用於動態的組合相片,或用作為圖形的背景等等。這也是目前唯一的新增文
>字的途徑(規格書裡並沒有任何繪製文字的函數)。只要是 <a class="internal" href="/zh_tw/Gecko 
>" title="zh tw/Gecko">Gecko</a> 支援的影像格式(如 PNG、GIF 或 JPEG 格式)就都能使用 
>。也能把同一頁面上的 canvas 元素作為影像來源。 
9    </p>
10    <h2 id="Importing_images" name="Importing_images">
11      匯入影像
12    </h2>
13    <p>
14      匯入影像基本上只需兩個步驟︰
15    </p>
16    <ul>
17      <li>首先,我們需要一個 JavaScript Image 物件的參考,或者以其他 canvas 元素作為來源。而不
>能簡單的以 URL 或路徑直接使用影像。 
18      </li>
19      <li>其次,我們使用 <code>drawImage</code> 函數把影像畫在 canvas 上。
20      </li>
21    </ul>
22    <p>
23      首先讓我們來看看第一個步驟。基本上有四個可行的選擇︰
24    </p>
25    <h4 id="Using_images_which_are_on_the_same_page" name="Using_
>images_which_are_on_the_same_page"> 
26      使用同一頁面上的影像
27    </h4>
28    <p>
29      我們可以使用各種方式存取同一頁面上的任一影像,例如 <code><a href="/en/DOM/document.i
>mages" title="en/DOM/document.images">document.images</a></code>  
>集合,<code><a href="/en/DOM/document.getElementsByTagName" title="e 
>n/DOM/document.getElementsByTagName">document.getElementsByTagNam 
>e</a></code> 方法,如果你知道特定影像的 ID 值,也可以使用 <code><a href="/en/DOM/docu 
>ment.getElementById" title="en/DOM/document.getElementById">docum 
>ent.getElementById</a></code> 方法。 
30    </p>
31    <h4 id="Using_other_canvas_elements" name="Using_other_canvas
>_elements"> 
32      使用其他的 canvas 元件
33    </h4>
34    <p>
35      如同存取頁面上的普通影像一般,我們也可以使用各種方式存取 canvas 元素,例如 <code><a href="/e
>n/DOM/document.getElementsByTagName" title="en/DOM/document.getEl 
>ementsByTagName">document.getElementsByTagName</a></code> 方法,<cod 
>e><a href="/en/DOM/document.getElementById" title="en/DOM/documen 
>t.getElementById">document.getElementById</a></code> 方法。在使用這些 Can 
>vas 之前,應先確定你已經在裡面繪製了一些東西。 
36    </p>
37    <p>
38      本方法更為實際的應用是使用第二個 canvas 元素作為另一個較大的 canvas 的縮圖。
39    </p>
40    <h4 id="Creating_an_image_from_scratch" name="Creating_an_ima
>ge_from_scratch"> 
41      從頭建立影像
42    </h4>
43    <p>
44      另一個選擇是在我們的 script 裡建立新的 <code>Image</code> 物件。這個方法主要的缺點是,如果
>我們不希望我們的 script 停在載入影像途中,便需要預先載入影像。 
45    </p>
46    <p>
47      建立新的 image 物件如下︰
48    </p>
49    <pre class="brush: js">
50var img = new Image();   // 建立新的 image 物件
51img.src = 'myImage.png'; // 設定來源路徑
52</pre>
53    <p>
54      當 script 執行時,開始載入影像。如果未能在執行 <code>drawImage</code> 之前載入完成,s
>cript 會停住,直到影像載入完成。如果你不希望這樣的話,使用 <code>onload</code> 事件處理器︰ 
55    </p>
56    <pre class="brush: js">
57var img = new Image();   // 建立新的 image 物件
58img.onload = function(){
59  // 執行 drawImage 的語句
60}
61img.src = 'myImage.png'; // 設定來源路徑
62</pre>
63    <p>
64      如果你只使用一個外部的影像,這就是個不錯的解決方法。但如果一次不只一個的話,便需要使用一些技巧。影像預讀策略已超出了本
>教學的範圍,不過你可以參考 <a class="external" href="http://www.webreference.c 
>om/programming/javascript/gr/column3/">JavaScript Image Preloader 
></a> 以取得完整的解決方法。 
65    </p>
66    <h4 id="Embedding_an_image_via_data:_url" name="Embedding_an_
>image_via_data:_url"> 
67      使用 data: url 嵌入影像
68    </h4>
69    <p>
70      另一個可行的方法是使用 <a class="external" href="http://en.wikipedia.o
>rg/wiki/Data:_URL">data: url</a> 包含影像。Data url 可讓你直接在代碼中定義影像,影像是以 
> Base64 編碼成字串。data url 的優點是影像立即可用,無須再次存取伺服器。(另一個優點是,可以把 CSS、Javas 
>cript、HTML 和影像全部裝進一個檔案之內,更具可攜性。)這個方法的缺點是,你的影像不能快取,對於大型影像來說,經過編碼的  
>url 會變的很長︰ 
71    </p>
72    <pre class="brush: js">
73var img_src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5
>BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=='; 
74</pre>
75    <p>
76      &nbsp;
77    </p>
78    <h2 id="drawImage" name="drawImage">
79      <code>drawImage</code>
80    </h2>
81    <p>
82      一旦取得作為來源的影像物件,我們就可以使用 <code>drawImage</code> 方法畫到 canvas 上。
>稍後我們將會看到經過重載(Overload)的 <code>drawImage</code> 方法的三個變體。它的最簡形式如下。 
83    </p>
84    <div style="border: 1px solid rgb(208, 221, 158); background:
> rgb(239, 248, 206) none repeat scroll 0% 0%; -moz-background-cli 
>p: -moz-initial; -moz-background-origin: -moz-initial; -moz-backg 
>round-inline-policy: -moz-initial; padding-left: 10px;"> 
85      <p>
86        <code><strong>drawImage</strong>(image, x, y)</code>
87      </p>
88    </div>
89    <p>
90      此處 <code>image</code> 即影像或 canvas 物件的參考。<code>x</code> 和 <c
>ode>y</code> 坐標即影像的擺放位置。 
91    </p>
92    <h4 id="drawImage_example_1" name="drawImage_example_1">
93      <code>drawImage</code> 範例 1
94    </h4>
95    <p>
96      <img align="right" alt="" class="internal" src="/@api/deki/
>files/58/=Canvas_backdrop.png">在接下來的範例中,我會使用一個外部的影像作為線條圖的背景。背景的使用 
>可以大幅節省 Script 內容,因為無需再繪製細緻的背景。在此我只使用一張影像,所以我使用 Image 物件的 <code>on 
>load</code> 事件處理器執行繪圖語句。<code>drawImage</code> 方法會把背景放在 (0,0) 坐標處 
> 
97    </p>
98    <p>
99      <a class="external" href="/samples/canvas-tutorial/3_1_canv
>as_drawimage.html" title="samples/canvas-tutorial/3_1_canvas_draw 
>image.html">檢視範例</a> 
100    </p>
101    <pre class="brush: js">
102  function draw() {
103    var ctx = document.getElementById('canvas').getContext('2d');
104    var img = new Image();
105    img.onload = function(){
106      ctx.drawImage(img,0,0);
107      ctx.beginPath();
108      ctx.moveTo(30,96);
109      ctx.lineTo(70,66);
110      ctx.lineTo(103,76);
111      ctx.lineTo(170,15);
112      ctx.stroke();
113    }
114    img.src = 'images/backdrop.png';
115  }
116</pre>
117    <h2 id="Scaling" name="Scaling">
118      縮放
119    </h2>
120    <p>
121      <code>drawImage</code> 方法的第二個變體多了兩個用於縮放影像的參數。
122    </p>
123    <div style="border: 1px solid rgb(208, 221, 158); background:
> rgb(239, 248, 206) none repeat scroll 0% 0%; -moz-background-cli 
>p: -moz-initial; -moz-background-origin: -moz-initial; -moz-backg 
>round-inline-policy: -moz-initial; padding-left: 10px;"> 
124      <p>
125        <code><strong>drawImage</strong>(image, x, y, width, heig
>ht)</code> 
126      </p>
127    </div>
128    <p>
129      此處的 <code>width</code> 和 <code>height</code> 是影像在 canvas 上的
>大小。 
130    </p>
131    <h4 id="drawImage_example_2" name="drawImage_example_2">
132      <code>drawImage</code> 範例 2
133    </h4>
134    <p>
135      <img align="right" alt="" class="internal" src="/@api/deki/
>files/106/=Canvas_scale_image.png"> 在這個範例中,我將使用一個影像作為 canvas 的桌布, 
>並重覆若干次。只需使用迴圈,就能輕鬆的把縮小後的影像放置在不同的位置。下面代碼的第一個 <code>for</code> 迴圈走遍 
>每一行,第二個 <code>for</code> 迴圈走遍每一列。影像縮小成原來的三分之一,像素為 50x38。後面的教學中,我們 
>還會看到如何使用自訂圖樣(pattern)達到同樣的效果。 
136    </p>
137    <p>
138      <strong>附註︰</strong>放大影像會使影像模糊,過度縮小影像則會使影像出現波紋。如果影像上已有一些文字,
>為清晰易讀起見,這時最好不要縮放影像。 
139    </p>
140    <p>
141      <a class="external" href="/samples/canvas-tutorial/3_2_canv
>as_drawimage.html" title="samples/canvas-tutorial/3_2_canvas_draw 
>image.html">檢視範例</a> <img align="right" alt="Source image" class= 
>"internal" src="/@api/deki/files/101/=Canvas_rhino.jpg"> 
142    </p>
143    <pre class="brush: js">
144  function draw() {
145    var ctx = document.getElementById('canvas').getContext('2d');
146    var img = new Image();
147    img.onload = function(){
148      for (i=0;i&lt;4;i++){
149        for (j=0;j&lt;3;j++){
150          ctx.drawImage(img,j*50,i*38,50,38);
151        }
152      }
153    }
154    img.src = 'images/rhino.jpg';
155  }
156</pre>
157    <h2 id="Slicing" name="Slicing">
158      切片
159    </h2>
160    <p>
161      <code>drawImage</code> 方法的最後一個變體有八個新的參數。我們可以使用這個方法把來源影像切一塊下
>來,並繪製在 canvas 上。 
162    </p>
163    <div style="border: 1px solid rgb(208, 221, 158); background:
> rgb(239, 248, 206) none repeat scroll 0% 0%; -moz-background-cli 
>p: -moz-initial; -moz-background-origin: -moz-initial; -moz-backg 
>round-inline-policy: -moz-initial; padding-left: 10px; margin-bot 
>tom: 10px;"> 
164      <p>
165        <code><strong>drawImage</strong>(image, sx, sy, sWidth, s
>Height, dx, dy, dWidth, dHeight)</code> 
166      </p>
167    </div>
168    <p>
169      <img align="right" alt="" class="internal" src="/@api/deki/
>files/79/=Canvas_drawimage.jpg">第一個參數 <code>image</code> 和其他變體一樣, 
>只是 Image 物件的參考,或是其他的 canvas 元素。至於剩下的八個參數,最好看看右邊的圖例。前四個參數定義了來源影像的切 
>片位置和大小。後四個參數定義了要畫在 canvas 的位置和大小。 
170    </p>
171    <p>
172      如果你想要組合一些東西,切片會是個很有用的工具。你可以把所有的元件全都放進同一影像檔裡,再使用切片方法組合畫面。舉個例
>子,如果你想要製做圖表,可以把所有所需的文字全都放進一個 PNG 影像檔裡,並根據你的數據改變圖表的比例。其優點是不再需要分別載入 
>每一個影像。 
173    </p>
174    <h4 id="drawImage_example_3" name="drawImage_example_3">
175      <code>drawImage</code> 範例 3
176    </h4>
177    <p>
178      <img align="right" alt="" class="internal" src="/@api/deki/
>files/80/=Canvas_drawimage2.jpg">在這個範例中,我會使用之前已看過的犀牛圖,不過這次我會切下頭部, 
>並把切下的圖組進畫框裡。畫框影像還附有陰影,並儲存為 32 位元的 PNG 檔案。由於 32 位元的 PNG 影像包含有完整的 8 
> 位元 Alpha 通道,有別於 GIF 和 24 位元 PNG 影像,我可以把它放在背景圖上面,而不必擔心邊緣的顏色。 
179    </p>
180    <p>
181      我改用不同的方式載入影像。我直接在 HTML 文件上放置影像,並使用 CSS 規則隱藏影像(<code>display
>:none</code>)。我給兩個影像各指定一個 <code>id</code> 屬性,以便選取。Script 本身很簡單。我先 
>在 canvas 上畫出切下並縮小過的影像(第一個 <code>drawImage</code> 語句),然後加上畫框(第二個 < 
>code>drawImage</code> 語句)。 
182    </p>
183    <p>
184      <a class="external" href="/samples/canvas-tutorial/3_3_canv
>as_drawimage.html" title="samples/canvas-tutorial/3_3_canvas_draw 
>image.html">檢視範例</a> <img align="right" alt="Source image" class= 
>"internal" src="/@api/deki/files/93/=Canvas_picture_frame.png"> 
185    </p>
186    <pre class="brush: js">
187function draw() {
188  var canvas = document.getElementById('canvas');
189  var ctx = canvas.getContext('2d');
190 
191  // 繪製切片
192  ctx.drawImage(document.getElementById('source'),
193                33,71,104,124,21,20,87,104);
194 
195  // 繪製畫框
196  ctx.drawImage(document.getElementById('frame'),0,0);
197}
198</pre>
199    <h2 id="Art_gallery_example" name="Art_gallery_example">
200      藝術圖庫範例
201    </h2>
202    <p>
203      <img align="right" alt="" class="internal" src="/@api/deki/
>files/57/=Canvas_art_gallery.jpg">在本章的最後一個範例裡,我會製作一些藝術圖庫。圖庫以包含若干圖 
>像的表格組合。當頁面載入完畢時,就在頁面上的每一個圖像之前插入加上畫框的 canvas 元素。 
204    </p>
205    <p>
206      在本例中,所有的圖像都有固定的寬和高,並在邊緣加上畫框。你可以修改 Script,使畫框配合圖像的大小。
207    </p>
208    <p>
209      以下的代碼應該很容易看懂。迴圈遍歷陣列裡的所有圖像,並為圖像加上新的 canvas 元素。對於那些不熟悉 DOM 的人
>來說,可能還有一處需要注意,那就是 <a href="/En/DOM/Node.insertBefore" title="en/D 
>OM/element.insertBefore">insertBefore</a> 方法的使用<span style="font- 
>family: monospace;">。</span><code>insertBefore</code> 是圖像元素的親節點(表 
>格)的方法,我們打算在圖像元素前面插入新的結點(canvas 元素)。 
210    </p>
211    <p>
212      <a class="external" href="/samples/canvas-tutorial/3_4_canv
>as_gallery.html" title="samples/canvas-tutorial/3_4_canvas_galler 
>y.html">檢視範例</a> 
213    </p>
214    <pre class="brush: js">
215function draw() {
216 
217  // 遍歷所有圖像的迴圈
218  for (i=0;i&lt;document.images.length;i++){
219 
220    // 無須為畫框圖像加上 canvas
221    if (document.images[i].getAttribute('id')!='frame'){
222 
223      // 建立 canvas 元素
224      canvas = document.createElement('CANVAS');
225      canvas.setAttribute('width',132);
226      canvas.setAttribute('height',150);
227 
228      // 在圖像之前插入
229      document.images[i].parentNode.insertBefore(canvas,document.
>images[i]); 
230 
231      ctx = canvas.getContext('2d');
232 
233      // 把圖像畫在 canvas 上
234      ctx.drawImage(document.images[i],15,20);
235 
236      // 加上畫框
237      ctx.drawImage(document.getElementById('frame'),0,0);
238    }
239  }
240}
241</pre>
242    <p>
243      {{ PreviousNext("Canvas 教學:繪製圖形", "Canvas 教學:套用樣式和色彩") }}
244    </p>
245    <p>
246      {{ languages( { "en": "en/Canvas_tutorial/Using_images", "f
>r": "fr/Tutoriel_canvas/Utilisation_d\'images", "ja": "ja/Canvas_ 
>tutorial/Using_images", "pl": "pl/Przewodnik_po_canvas/Zastosowan 
>ie_obrazk\u00f3w", "zh-cn": "cn/Canvas_tutorial/Using_images", "r 
>u": "ru/\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435_canvas/\ 
>u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d 
>\u0438\u0435_\u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a" }  
>) }} 
247    </p>

Back to History