记录–使用 JS 实现基本的截图功能

  • 记录–使用 JS 实现基本的截图功能已关闭评论
  • 77 次浏览
  • A+
所属分类:Web前端
摘要

在开始动手之前,分析一下整个功能的实现过程:根据图片大小创建 canvas1 画布,并将原图片直接定位在 canvas1 上;


这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--使用 JS 实现基本的截图功能

思路分析

在开始动手之前,分析一下整个功能的实现过程:

  1. 根据图片大小创建 canvas1 画布,并将原图片直接定位在 canvas1 上;

  2. 在画布上添加一个蒙层,以区分当前 canvas 图像是被裁剪的原图像;

  3. 在蒙层上方,对裁剪区域(鼠标移动形成的矩形范围)再次进行图像绘制;

  4. 获取裁剪区域的数据,并将该数据定位到另一个 canvas 画布上。

实现过程

准备工作

首先,编写所需的 HTML 结构并获取对应元素。

<body>   <!-- 上传文件 -->   <input type="file" id="imageFile" accept="image/*">   <!-- 保存被裁剪的原图像,初始样式需要设置 display: none -->   <div class="canvasContainer1">     <canvas id="canvas1"></canvas>   </div>   <!-- 保存裁剪区域的图像,初始样式需要设置 display: none -->   <div class="canvasContainer2">     <canvas id="canvas2"></canvas>   </div> </body>  <script> const imageFile = document.querySelector('#imageFile'); const canvasContainer1 = document.querySelector('.canvasContainer1'); const canvasContainer2 = document.querySelector('.canvasContainer2'); const canvas1 = document.querySelector('#canvas1'); const canvas2 = document.querySelector('#canvas2'); const ctx = canvas1.getContext('2d'); const ctx2 = canvas2.getContext('2d');  const imageBox = new Image(); // 创建一个存放图片的容器 </script>

绘制原图像

我们需要监听 input 元素的 change 事件,以获取上传图片的相关参数,这里主要是为了获取图片的宽度和高度。

我们创建一个 FileReader() 对象并监听其 load 事件。load 事件在读取操作成功后立刻执行,在这个方法中我们就可以获取图片的宽高。

function init() {   imageFile.addEventListener('change', handleFileChange, false); // 监听图片上传事件。 }  function handleFileChange(e) {   const imgFile = e.target.files[0]; // 获取上传的图片对象。    const reader = new FileReader();   reader.onload = function(e) {     const imgSrc = e.target.result; // 图片文件的 base64 编码格式。     imageBox.src = imgSrc; // 把图片放入 img 容器。      // 等图片加载完成后,获取图片的宽高。     imageBox.onload = function () {       const imgWidth = this.width, imgHeight = this.height;       console.log(imgWidth, imgHeight);     }   }   if (imgFile) {     reader.readAsDataURL(imgFile); // 读取图片文件,读取完成才能获取 result 属性。   } }  init();

记录--使用 JS 实现基本的截图功能

此时还没有图片,我们创建一个自适应图片大小的 canvas1 画布,并使用 drawImage() 方法将上传的图片直接定位到 canvas1 当中。

function handleFileChange(e) {   const imgFile = e.target.files[0]; // 获取上传的图片对象。    const reader = new FileReader();   reader.onload = function (e) {     const imgSrc = e.target.result; // 图片的 base64 编码。     imageBox.src = imgSrc; // 把上传的图像放入 img 容器。      // 图片加载完毕后执行     imageBox.onload = function () {       // 获取图片的宽高。       const imgWidth = this.width, imgHeight = this.height;       console.log(imgWidth, imgHeight);              // 创建 canvas 画布并绘制图片。       generateCanvas(canvasContainer1, canvas1, imgWidth, imgHeight);       ctx.drawImage(imageBox, 0, 0, imgWidth, imgHeight);     }   }   if (imgFile) {     reader.readAsDataURL(imgFile); // 将当前file读取成DataURL   } }  // 根据 width 和 height 创建 canvas 画布。 function generateCanvas(container, canvas, width, height) {   container.width = width + 'px';   container.height = height + 'px';   canvas.width = width;   canvas.height = height;   container.style.display = 'block'; // 显示 canvas 区域。 }

记录--使用 JS 实现基本的截图功能

可以看到原图像已经成功被绘制,接下来就可以开始动态绘制截图区域了。

绘制截图区域

在这个过程中,我们需要分别监听 imageBox 容器(原图像)上的 mousedownmousemovemouseup 事件,这些事件的作用如下:

  • mousedown 事件:记录开始截图的位置,并开始监听 mousemovemouseup 事件。
  • mousemove 事件:监听鼠标的偏移量,以计算裁剪区域的宽度和高度。
  • mouseup 事件:截图结束,注销监听 mousedownmousemove 事件,并绘制裁剪区域。
let startPosition = []; // 记录鼠标点击(开始截图)的位置。 let screenshotData = []; // 保存截取部分的相关信息。  function init() {   // 监听鼠标点击事件。   canvas1.addEventListener('mousedown', handleMouseDown, false); }  // 记录鼠标点击(开始截图)的位置,并监听相关事件。 function handleMouseDown(e) {   startPosition = [e.offsetX, e.offsetY];    canvas1.addEventListener('mousemove', handleMouseMove, false);   canvas1.addEventListener('mouseup', handleMouseUp, false); }  // 监听鼠标的偏移量,以计算裁剪区域的宽度和高度。 function handleMouseMove(e) {   // 获取裁剪区域的宽度和高度。   const { offsetX, offsetY } = e;   const [startX, startY] = startPosition;   const [rectWidth, rectHeight] = [offsetX - startX, offsetY - startY];   console.log('rect', rectWidth, rectHeight);      // 保存裁剪区域的相关信息。   screenshotData = [startX, startY, rectWidth, rectHeight]; }  // 注销监听事件等后续操作。 function handleMouseUp() {   canvas1.removeEventListener('mousemove', handleMouseMove, false);   canvas1.removeEventListener('mouseup', handleMouseUp, false); }

在 handleMouseMove 函数中,我们已经获取了裁剪区域的宽高,也就是生成截图的宽高。

接下来,我们需要在原图像上展示出我们所裁剪的区域,也就是这个效果:

记录--使用 JS 实现基本的截图功能

可以看到,原图像的上方、裁剪区域下方会覆盖一层半透明黑色蒙层,它的作用是区分原图层和裁剪部分图层。所以我们需要在绘制截图区域之前,添加一层蒙层。

注意,在已有内容的 canvas 画布上进行再次绘制之前,需要先清除整个画布的内容。 这里通过 clearRect() 方法清除 canvas1 画布上的所有内容,并添加蒙层。

我们继续来补充 handleMouseMovehandleMouseUp 函数中的逻辑:

const MASKER_OPACITY = 0.4;  function handleMouseMove(e) {   // 获取裁剪区域的宽度和高度。   const { offsetX, offsetY } = e;   const [startX, startY] = startPosition;   const [rectWidth, rectHeight] = [offsetX - startX, offsetY - startY];   console.log('rect', rectWidth, rectHeight);   // 保存裁剪区域的相关信息。   screenshotData = [startX, startY, rectWidth, rectHeight];   // 再次绘制前,清理 canvas1 画布上的内容。   const { width, height } = canvas1;   ctx.clearRect(0, 0, width, height);   // 在 canvas1 画布上绘制蒙层。   drawImageMasker(0, 0, width, height, MASKER_OPACITY);   // 绘制截图区域。   drawScreenShot(width, height, rectWidth, rectHeight); }  // ...  // 绘制图片蒙层,填充范围和颜色,以便区分原图层和裁剪部分图层。 function drawImageMasker(x, y, width, height, opacity) {   ctx.fillStyle = `rgba(0, 0, 0, ${opacity})`;   ctx.fillRect(0, 0, width, height); }  // 绘制裁剪的矩形区域。 function drawScreenShot(canWidth, canHeight, rectWidth, rectHeight) {   // 在源图像外绘制新图像,只有源图像外的目标图像部分会被显示,源图像是透明的。   ctx.globalCompositeOperation = 'destination-out';   ctx.fillStyle = '#2c2c2c';   ctx.fillRect(...startPosition, rectWidth, rectHeight);    // 在现有画布上绘制新的图形。   ctx.globalCompositeOperation = 'destination-over';   ctx.drawImage(imageBox, 0, 0, canWidth, canHeight, 0, 0, canWidth, canHeight); }

然后,当我们放开鼠标(结束截图动作)时,除了注销对 mousedownmousemove 事件的监听,还需要将所得的裁剪区域的图像放入另一个 canvas 中。

在绘制新图像的过程中,我们需要使用以下方法:

  • getImageData():读取 canvas 上的内容,返回一个 ImageData 对象,包含了每个像素的信息。
  • putImageData():将 ImagaData 对象的数据放入 canvas 中,覆盖 canvas 中的已有图像。
function handleMouseUp() {   canvas1.removeEventListener('mousemove', handleMouseMove, false);   canvas1.removeEventListener('mouseup', handleMouseUp, false);   // 开始绘制截图区域图片。   drawScreenshotImage(screenshotData);   // 如果裁剪得到新图像后,不希望保留原图像,可以设置以下属性。   // canvasContainer1.style.display = 'none'; }  // 在新容器 canvas2 上绘制新图像。 function drawScreenshotImage(screenshotData) {   // 获取 canvas1 的数据。   const data = ctx.getImageData(...screenshotData);   // 创建 canvas2 画布。   generateCanvas(canvasContainer2, canvas2, screenshotData[2], screenshotData[3]);   // 每次绘制前,都先进行清除操作。   ctx2.clearRect(...screenshotData);   // 将 canvas1 的数据放入 canvas2 中。   ctx2.putImageData(data, 0, 0); }

经过以上步骤,就可以实现我们所需的效果

记录--使用 JS 实现基本的截图功能

本文转载于:

https://juejin.cn/post/7264920437242036284

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--使用 JS 实现基本的截图功能