JS+Canvas实现上传图片截图功能
作者:yinuo
在我们平时开发图片上传时,有时需要实现图片的裁剪功能,这篇文章主要为大家介绍了如何使用Canvas实现上传图片截图功能,希望对大家有所帮助
1. 前言
在我们平时开发图片上传时,有时需要实现图片的裁剪功能。通常我们使用Vue-cropper来实现图片的裁剪功能。
如何实现呢?本文介绍下图片裁剪的功能的实现过程。
2. 实现思路
- 使用
input
元素让用户选择图片文件,然后使用FileReader
API 读取图片文件的内容,并将其设置为img
元素的src
属性。 - 创建一个
canvas
元素并获取其 2D 渲染上下文,然后使用drawImage
方法将图片绘制到 canvas 上。 - 监听鼠标的
mousedown
、mousemove
和mouseup
事件,用于创建和调整裁剪框。当用户点击鼠标并移动时,记录鼠标的位置并在 canvas 上绘制一个矩形作为裁剪框。 - 当用户释放鼠标按钮时,使用
getImageData
方法获取裁剪框内的像素数据,然后创建一个新的 canvas 并使用putImageData
方法将这些像素数据放入新的 canvas 中。这样就得到了裁剪后的图片。 - 最后,使用
toDataURL
方法将裁剪后的图片转换为 Base64 格式的字符串,或者使用toBlob
方法将其转换为 Blob 对象,然后可以将其下载到用户的计算机上,或者上传到服务器。
3. 实现步骤
使用原生js进行实现,使用两个canvas,一个是原图展示,一个是截图后的。
HTML部分:
<!-- 文件上传 --> <input type="file" id="inputFile" accept="image/*" /> <!-- 展示读取的图片的canvas --> <div class="clipContainer"> <canvas id="clip"></canvas> </div> <!-- 截图后的图片的canvas --> <div class="drawContainer"> <canvas id="draw"></canvas> </div>
JS公共部分:
const inputNode = document.querySelector("#inputFile"); const clipCanvas = document.querySelector("#clip"); const drawCanvas = document.querySelector("#draw"); const clipContainer = document.querySelector( ".clipContainer" ); const drawContainer = document.querySelector( ".drawContainer" ); const clipCanvasCtx = clipCanvas.getContext("2d"); const drawCanvasCtx = drawCanvas.getContext("2d"); const imageNode = document.createElement('img'); const drawImageNode = document.createElement('img');//用于最终展示图片 let resultFile = null;//最终生成的File对象图片文件
3.1 选择文件进行预览
使用FileReader
读取文件的url和宽高,进行cavas绘制。
// 1. 选择图片 读取图片 inputNode.addEventListener( "change", function (e) { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = function (e) { imageNode.src = e.target.result; imageNode.onload = function () { // 获取真实的图片宽高 canvas绘制图片 generateCanvas(clipContainer, clipCanvas, this.width, this.height); clipCanvasCtx.drawImage(imageNode, 0, 0, this.width, this.height); }; }; file && reader.readAsDataURL(file); }, false ); // 2. canvas绘制图片 function generateCanvas(canvasContainer, canvas, width, height) { // 2.1 外部容器的宽高 canvasContainer.style.width = width + 'px'; canvasContainer.style.height = height + 'px'; // 2.2 canvas的宽高 canvas.width = width; canvas.height = height; }
结果如下:
3.2 监听mousedown事件
监听mousedown
记录起点坐标,使用startPositon进行记录起始位置。
// 记录点击开始结束位置 let startPosition = [] clipCanvas.addEventListener('mousedown', function (e) { // 3.1 记录开始截图的位置 startPosition = [e.offsetX, e.offsetY] // 3.2 开始监听 mousemove 和 mouseup 事件 clipCanvas.addEventListener('mousemove', mousemoveHandler, false) clipCanvas.addEventListener('mouseup', mouseupHandler, false) })
3.3 监听mousemove事件
记录鼠标移动坐标,计算出截图大小,绘制截图蒙层区域
// 记录截图的偏移x,y和截图的宽高w,h let screenShotData = [] function mousemoveHandler(e) { // 1. 计算裁剪区域的宽度和高度 const { offsetX, offsetY } = e const [startX, startY] = startPosition // 偏移位置-起始位置 = 真实宽高 const [rectWidth, rectHeight] = [offsetX - startX, offsetY - startY] // 2. 保存裁剪区域的相关信息 screenShotData = [startX, startY, rectWidth, rectHeight] // 3. 重新绘制 fill(clipCanvasCtx, clipCanvas, screenShotData) } function fill(ctx, canvas, sizeData) { const { width, height } = canvas const [x, y, w, h] = sizeData // 1. 再次绘制前,清理canvas1画布上的内容 ctx.clearRect(0, 0, width, height) // 2. 画布上绘制蒙层 ctx.fillStyle = `rgba(0,0,0,0.6)` ctx.fillRect(0, 0, width, height) // 3. 绘制裁剪区域 // 在源图像外绘制新图像,只有源图像外的目标图像部分会被显示,源图像是透明的 ctx.globalCompositeOperation = 'destination-out' ctx.fillStyle = '#2c2c2c' ctx.fillRect(...sizeData) // 设置在现有画布上绘制新的图形 ctx.globalCompositeOperation = 'destination-over' // 剪切图像,并在画布上定位被剪切的部分 ctx.drawImage(imageNode, 0, 0, width, height, 0, 0, width, height); }
结果如下:
3.4 监听mouseup事件
注销事件监听,将裁剪区域放入另一个canvas中进行处理,并读取File对象
function mouseupHandler(e) { // 1. 注销监听 mousedown 和 mousemove 事件 clipCanvas.removeEventListener('mousemove', mousemoveHandler, false) clipCanvas.removeEventListener('mouseup', mouseupHandler, false) // 2. 开始绘制截图区域图片 const data = clipCanvasCtx.getImageData(...screenShotData) // 3. 使用新画布 const [x, y, w, h] = screenShotData generateCanvas(drawCanvas, drawContainer, w, h) // 每次绘制前,都先进行清除操作 drawCanvasCtx.clearRect(...screenShotData); // 将 clipCanvas 裁剪区域的数据放入 drawCanvas 中 drawCanvasCtx.putImageData(data, 0, 0); drawCanvas.style.display = 'none' // 4. 展示图片 const imageUrl = drawCanvas.toDataURL('image/png') drawImageNode.src = imageUrl; document.body.appendChild(drawImageNode) // 5. 生成File对象 drawCanvas.toBlob(blob => { resultFile = new File([blob], 'test.png', { type: 'image/png' }) }, 'image.png') }
4. 总结
最后总结一下如图:
到此这篇关于JS+Canvas实现上传图片截图功能的文章就介绍到这了,更多相关JS Canvas图片截图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!