使用 HTML5 Canvas 实现圆形图片裁剪并上传
前言
在Web开发中,有时候我们需要将用户上传的图片进行裁剪,特别是裁剪成圆形的头像图片。这篇博客将介绍如何使用HTML5 Canvas实现图片的圆形裁剪,并将裁剪后的图片上传到服务器。我们将详细讲解相关的代码实现过程,并提供一个完整的示例代码。
步骤概览
- 创建HTML结构,包含文件上传控件、Canvas和显示裁剪后图片的标签。
- 在
uploadFile.onchange
中创建一个Image
对象,并在onload
事件中获取图片的实际尺寸(image.width
和image.height
),我们可以计算出图片在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,我们可以灵活地处理图像,实现各种有趣的功能。