在我剛學習網頁程式設計的那個年代,要在前端網頁上對圖片做除了顯示/隱藏/放大/縮小以外的處理,大都是丟到後端處理完後再丟回來,拜網頁設計技術進步所賜,生出了 Canvas 這個東西,讓我們可以利用客戶端的運算資源執行繪圖的工作,甚至要搞出一個純前端的小畫家是完全沒有問題的。
Canvas 所包含的功能非常豐富,我沒辦法在一篇文章中鉅細靡遺地介紹,我僅就用 drawImage()
方法來合併/縮放/裁切圖片當做範例,看看用 Canvas 要怎麼完成這些需求?
CanvasRenderingContext2D.drawImage() 是 Canvas 很常用的 API 之一,它可以將一個圖片來源繪製到 Canvas 上,而圖片來源的類型包括 HTMLImageElement、SVGImageElement、HTMLVideoElement、HTMLCanvasElement、ImageBitmap、OffscreenCanvas、VideoFrame,這些元素上的影像皆可以繪製到 Canvas 上。
drawImage(image, dx, dy) 合併圖片
下面的範例,我畫面上會有兩張圖片,一大一小,合併之後會繪製到 Canvas 上,預期合併的結果是小的圖片會被放在大的圖片的中間。
<p>
<img src="https://i.imgur.com/2HMwva8.jpg" crossorigin="anonymous" id="bigger" />
<img src="https://i.imgur.com/Adjd5KF.png" crossorigin="anonymous" id="smaller" />
<button id="merge">Merge</button>
<canvas id="result"></canvas>
</p>
<script>
document.querySelector("#merge").addEventListener("click", function (e) {
const bigger = document.querySelector("#bigger");
const smaller = document.querySelector("#smaller");
const canvas = document.querySelector("#result");
const canvasCtx = canvas.getContext("2d");
// Canvas 預設大小是 300×150,配合繪製圖片大小,調整 Canvas 的大小。
canvas.width = bigger.width;
canvas.height = bigger.height;
canvasCtx.drawImage(bigger, 0, 0);
canvasCtx.drawImage(smaller, (bigger.width / 2) - (smaller.width / 2), (bigger.height / 2) - (smaller.height / 2));
});
</script>
這裡我們使用 drawImage() 的第一個多載方法 drawImage(image, dx, dy)
,其中 image
指的是圖片來源,dx
及 dy
則是指要從目標畫布上的哪一個點開始畫起?
drawImage(image, dx, dy, dWidth, dHeight) 縮放圖片
drawImage() 還有兩個多載方法,第二個多載方法是 drawImage(image, dx, dy, dWidth, dHeight)
,多了 dWidth
及 dHeight
參數,這兩個參數可以讓我們將圖片來源,繪製在指定的大小之內。
如果指定的大小跟原本圖片的比例不對,會導致繪製的結果變形,這點要特別注意。
<p>
<img src="https://i.imgur.com/2HMwva8.jpg" crossorigin="anonymous" id="bigger" />
<img src="https://i.imgur.com/Adjd5KF.png" crossorigin="anonymous" id="smaller" />
<button id="merge">Merge</button>
<canvas id="result"></canvas>
</p>
<script>
document.querySelector("#merge").addEventListener("click", function (e) {
const bigger = document.querySelector("#bigger");
const smaller = document.querySelector("#smaller");
const canvas = document.querySelector("#result");
const canvasCtx = canvas.getContext("2d");
// Canvas 預設大小是 300×150,配合繪製圖片大小,調整 Canvas 的大小。
canvas.width = bigger.width;
canvas.height = bigger.height;
canvasCtx.drawImage(bigger, 0, 0, bigger.width / 2, bigger.height / 2);
canvasCtx.drawImage(smaller, (bigger.width / 2) - (smaller.width / 2), (bigger.height / 2) - (smaller.height / 2), smaller.width * 1.5, smaller.height * 1.5);
});
</script>
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) 裁切圖片
drawImage() 的第三個多載方法 drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
,多了 sx
、sy
、sWidth
、sHeight
四個參數,但是他們被定義在方法的前面,使用上要小心,這四個參數可以讓我們只擷取圖片來源的某個區塊,繪製在目標畫布上。
<p>
<img src="https://i.imgur.com/2HMwva8.jpg" crossorigin="anonymous" id="bigger" />
<img src="https://i.imgur.com/Adjd5KF.png" crossorigin="anonymous" id="smaller" />
<button id="merge">Merge</button>
<canvas id="result"></canvas>
</p>
<script>
document.querySelector("#merge").addEventListener("click", function (e) {
const bigger = document.querySelector("#bigger");
const smaller = document.querySelector("#smaller");
const canvas = document.querySelector("#result");
const canvasCtx = canvas.getContext("2d");
// Canvas 預設大小是 300×150,配合繪製圖片大小,調整 Canvas 的大小。
canvas.width = bigger.width;
canvas.height = bigger.height;
canvasCtx.drawImage(bigger, 139, 304, 286, 255, 0, 0, 286, 255);
canvasCtx.drawImage(smaller, 47, 18, 111, 82, 0, 300, 111, 82);
});
</script>
儲存圖片
同場加映,圖片處理完了,如果想儲存下來要怎麼做?我在畫面上增加一個 Save
按鈕,搭配 <a>
的一個 download 屬性來完成這件事情。
<p>
<img src="https://i.imgur.com/2HMwva8.jpg" crossorigin="anonymous" id="bigger" />
<img src="https://i.imgur.com/Adjd5KF.png" crossorigin="anonymous" id="smaller" />
<button id="merge">Merge</button>
<button id="save">Save</button>
<canvas id="result"></canvas>
</p>
<script>
document.querySelector("#merge").addEventListener("click", function (e) {
const bigger = document.querySelector("#bigger");
const smaller = document.querySelector("#smaller");
const canvas = document.querySelector("#result");
const canvasCtx = canvas.getContext("2d");
// Canvas 預設大小是 300×150,配合繪製圖片大小,調整 Canvas 的大小。
canvas.width = bigger.width;
canvas.height = bigger.height;
canvasCtx.drawImage(bigger, 139, 304, 286, 255, 0, 0, 286, 255);
canvasCtx.drawImage(smaller, 47, 18, 111, 82, 0, 300, 111, 82);
});
document.querySelector("#save").addEventListener("click", function (e) {
const canvas = document.querySelector("#result");
const anchor = document.createElement("a");
anchor.download = "image.png";
anchor.href = canvas.toDataURL();
anchor.click();
});
</script>
以上,透過幾個範例來簡單介紹 Canvas drawImage() 的使用方式,希望對有需要的朋友有一點幫助,在撰寫文章的過程中,打開我很久以前做過類似需求的程式碼,嗯,很快我就把它給關掉了,太恐怖了。