前言
在Web開發中,有時候我們需要將使用者上傳的圖片進行裁剪,特別是裁剪成圓形的頭像圖片。這篇部落格將介紹如何使用HTML5 Canvas實現圖片的圓形裁剪,並將裁剪後的圖片上傳到伺服器。我們將詳細講解相關的程式碼實現過程,並提供一個完整的示例程式碼。
步驟概覽
- 建立HTML結構,包含檔案上傳控制元件、Canvas和顯示裁剪後圖片的標籤。
- 使用FileReader讀取使用者上傳的圖片,並在Canvas上繪製圖片。
- 將Canvas的繪製區域裁剪為圓形。
- 將裁剪後的圖片轉換為Blob物件,並顯示在頁面上。
- 將Blob物件上傳到伺服器。
HTML結構
首先,我們建立一個簡單的HTML結構,包括一個檔案上傳控制元件、一個隱藏的Canvas用於繪製和裁剪圖片,以及一個用於顯示裁剪後圖片的img標籤。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { display: none; border: 1px solid red; } .upload { width: 100px; height: 20px; border: 1px solid; position: relative; } .upload-file { position: absolute; left: 0; top: 0; width: 100%; height: 100%; opacity: 0; z-index: 1; cursor: pointer; } .upload-btn { position: absolute; left: 0; top: 0; width: 100%; height: 100%; text-align: center; line-height: 1.5; font-size: 14px; color: #666; border-radius: 5px; } </style> </head> <body> <div class="upload"> <input type="file" class="upload-file"> <div class="upload-btn">圖片上傳</div> </div> <div class="upload-content"> <img src="" class="upload-img"> </div> <canvas id="canvas"></canvas> <script> </script> </body> </html>
JavaScript實現
在JavaScript中,我們將實現以下幾個關鍵步驟:
1. 讀取並繪製圖片
使用FileReader讀取使用者上傳的圖片,並在Canvas上繪製該圖片。這裡確保Canvas的寬高比與圖片一致,以避免圖片變形。
const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 300; canvas.height = 300; const uploadFile = document.querySelector('.upload-file'); const uploadImg = document.querySelector('.upload-img'); let imageBlob; uploadFile.onchange = (e) => { const fileData = e.target.files[0]; const reader = new FileReader(); const image = new Image(); reader.readAsDataURL(fileData); // 非同步讀取檔案內容,結果用data:url的字串形式表示 reader.onload = function (e) { image.src = this.result; image.onload = function () { // 清空畫布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 計算圖片繪製區域,確保圖片保持比例 const aspectRatio = image.width / image.height; let drawWidth, drawHeight; let offsetX = 0, offsetY = 0; if (aspectRatio > 1) { // 圖片更寬 drawHeight = canvas.height; drawWidth = drawHeight * aspectRatio; offsetX = (canvas.width - drawWidth) / 2; } else { // 圖片更高 drawWidth = canvas.width; drawHeight = drawWidth / aspectRatio; offsetY = (canvas.height - drawHeight) / 2; } // 將畫布剪裁為圓形區域 ctx.beginPath(); ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2); ctx.closePath(); ctx.clip(); // // 在剪裁後的圓形區域內繪製圖片 ctx.drawImage(image, offsetX, offsetY, drawWidth, drawHeight); // 將畫布內容轉換為圖片 canvas.toBlob(function (blob) { const url = URL.createObjectURL(blob); uploadImg.src = url; imageBlob = blob; }, 'image/png'); }; } }
2. 上傳圖片
實現將裁剪後的圖片上傳到伺服器。這裡我們使用FormData物件將Blob物件封裝,並透過Fetch API將其上傳到伺服器。
uploadBtn.addEventListener('click', () => { if (imageBlob) { const formData = new FormData(); formData.append('image', imageBlob, 'image.png'); fetch('/upload', { method: 'POST', body: formData, }) .then(response => response.json()) .then(data => { console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); }); } else { console.error('No image available to upload.'); } });
完整示例
將上述HTML和JavaScript程式碼結合起來,我們得到了一個完整的實現使用者上傳圖片、裁剪為圓形並上傳的示例。以下是完整的程式碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> canvas { display: none; border: 1px solid red; } .upload { width: 100px; height: 20px; border: 1px solid; position: relative; } .upload-file { position: absolute; left: 0; top: 0; width: 100%; height: 100%; opacity: 0; z-index: 1; cursor: pointer; } .upload-btn { position: absolute; left: 0; top: 0; width: 100%; height: 100%; text-align: center; line-height: 1.5; font-size: 14px; color: #666; border-radius: 5px; } </style> </head> <body> <div class="upload"> <input type="file" class="upload-file"> <div class="upload-btn">圖片上傳</div> </div> <div class="upload-content"> <img src="" class="upload-img"> </div> <canvas id="canvas"></canvas> <button id="uploadBtn">Upload Image</button> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 300; canvas.height = 300; const uploadFile = document.querySelector('.upload-file'); const uploadImg = document.querySelector('.upload-img'); let imageBlob; uploadFile.onchange = (e) => { const fileData = e.target.files[0]; const reader = new FileReader(); const image = new Image(); reader.readAsDataURL(fileData); // 非同步讀取檔案內容,結果用data:url的字串形式表示 reader.onload = function (e) { image.src = this.result; image.onload = function () { // 清空畫布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 計算圖片繪製區域,確保圖片保持比例 const aspectRatio = image.width / image.height; let drawWidth, drawHeight; let offsetX = 0, offsetY = 0; if (aspectRatio > 1) { // 圖片更寬 drawHeight = canvas.height; drawWidth = drawHeight * aspectRatio; offsetX = (canvas.width - drawWidth) / 2; } else { // 圖片更高 drawWidth = canvas.width; drawHeight = drawWidth / aspectRatio; offsetY = (canvas.height - drawHeight) / 2; } // 將畫布剪裁為圓形區域 ctx.beginPath(); ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2); ctx.closePath(); ctx.clip(); // // 在剪裁後的圓形區域內繪製圖片 ctx.drawImage(image, offsetX, offsetY, drawWidth, drawHeight); // 將畫布內容轉換為圖片 canvas.toBlob(function (blob) { const url = URL.createObjectURL(blob); uploadImg.src = url; imageBlob = blob; }, 'image/png'); }; } } uploadBtn.addEventListener('click', () => { if (imageBlob) { const formData = new FormData(); formData.append('image', imageBlob, 'image.png'); fetch('/upload', { method: 'POST', body: formData, }) .then(response => response.json()) .then(data => { console.log('Success:', data); }) .catch((error) => { console.error('Error:', error); }); } else { console.error('No image available to upload.'); } }); </script> </body> </html>
結論
透過上述步驟,我們實現了一個簡單的Web應用程式,能夠讓使用者上傳圖片,並將圖片裁剪為圓形後顯示在頁面上,並提供上傳到伺服器的功能。使用HTML5 Canvas和JavaScript,我們可以靈活地處理影像,實現各種有趣的功能。