美文网首页功能点
JS实现截屏和编辑图片(隐藏,高亮,裁剪)

JS实现截屏和编辑图片(隐藏,高亮,裁剪)

作者: avery1 | 来源:发表于2023-03-23 15:18 被阅读0次

产品要求添加的功能,本来功能是用户上传图片,添加新需求是可以点击button截屏然后编辑(隐藏敏感信息,高亮和裁剪)。参考的是google的截屏. gif没显示的是选择截屏的选项, 已添加截图

google take screenshot select what to capture

中间遇到了很多问题,记录下。

1, 截图

canvas

第一个问题就是截图,最开始考虑的是htmlcanvas来截图

https://hackernoon.com/how-to-take-screenshots-in-the-browser-using-javascript-l92k3xq7

https://www.cnblogs.com/chunying/p/17022025.html

https://blog.csdn.net/m0_56976301/article/details/127776427

但是canvas只截取当前网页。需要引入第三方库。上代码

html2canvas(document.body, {

                ignoreElements: (el) => {

                    if (el.classList.contains('upload')) {

                        if (el.tagName==="DIV") {

                            return true;

                        }

                    }

                }

            }).then(canvas => {

                    this.img.nativeElement.setAttribute('src', canvas.toDataURL());

            });

MediaDevices.getDisplayMedia()

https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getDisplayMedia

这个是web API,不需要引入库,而且可以选择当前电脑的屏幕,tab等,现代浏览器也基本支持。所以选择了这个。代码

async capture() {

        const canvas = document.createElement("canvas");

        const context = canvas.getContext("2d");

        const video: any = document.createElement("video");

        const gdmOptions = {

            video: true,

            preferCurrentTab:true

        }

        try {

          const mediaDevices : any = navigator.mediaDevices;

          const captureStream = await mediaDevices.getDisplayMedia(gdmOptions);

          video.srcObject = captureStream;

          console.dir(video);

          console.dir(captureStream);

          await video.play();

          canvas.width = video.videoWidth;

          canvas.height = video.videoHeight;

          context.drawImage(video, 0, 0, canvas.width, canvas.height);

          let size = canvas.toDataURL().length*3/4;

        //   let s = size > 1048576 ? (size/1048576).toFixed(2) + 'MB' : (size/1024).toFixed(1) + 'KB';

          this.editImage = true;

          setTimeout(() => {

            // console.log(this.can);

            this.can.nativeElement.setAttribute('src', canvas.toDataURL());

          }, 50);

          captureStream.getTracks().forEach(track => track.stop());

        } catch (err) {

          console.error("Error: " + err);

        }

      };

编辑

重要的就是编辑的逻辑

肯定要用canvas画图

https://baijiahao.baidu.com/s?id=1733267341500955304&wfr=spider&for=pc

布局

图片层,然后在图片层之上画布层,画图在画布层做,保存在合并

 <div style="display: inline-block; position: relative;">

      <img id="can" (dragstart)="stopDrag()" #can/>

      <canvas style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;" id="canvas" #canvas></canvas>

      <div id="drawState" #drawState style="width: 100%; height: 100%; position: absolute;left: 0;top: 0;" (mousedown)="canvasStart($event)" (mousemove)="canvasDraw($event)" (mouseup)="canvasDone($event)" (mouseleave)="canvasDone($event)"></div>

    </div>

hide就是画矩形然后stroke黑色,

遇到的问题

画布大小

开始画的时候发现画的路径和鼠标的路径不一样,这里就有个canvas的clientWidth/clientHeight 和width/height

canvas显示的大小和画布实际大小不一样,所以一定要记得设置画布大小,如果两个尺寸不一样的话在画的时候还要进行坐标转换

InitCanvasInstance() {

        if (!this.ctx) {

            let canvas: any = this.canvas.nativeElement;

            let img:any = this.img.nativeElement;

            this.canvasRatio.width = can.naturalWidth/canvas.clientWidth;

            this.canvasRatio.height = can.naturalHeight/canvas.clientHeight 

            canvas.width = can.naturalWidth;

            canvas.height = can.naturalHeight;

            this.ctx = canvas.getContext('2d');

            this.strokeColor = "#0072a3";

        }

highlight的实现

highlight是要把图片加一个遮罩层然后高亮部分不加。这块逻辑包括遮罩还得是canvas。

canvas画一个和画布大小一样的矩形, stroke图片的遮罩颜色,需要高亮的部分clear一下就实现了,遮罩加个flag,如果有了就不再重复加了

清除path

画图开始记录开始坐标,在画图的过程中怎么清楚上一步的路径也是问题,因为我们在画的过程中要实时显示当前选中的区域,也就是在这个过程中一直在画

想了一个比较好现实也比较切合实际的办法就是在当前画布层之上再加一个画布层,每次mousemove的时候都把这个画布层全部clear,鼠标up的时候把最后这一步的path画到下面画布上,这个画布层clear

start

canvasStart (){           

          this.drawing = true; 

            let canvas: any = this.canvas.nativeElement;

            this.startCoordinate = {x: e.offsetX, y: e.offsetY};

            this.endCoordinate = {x: e.offsetX, y: e.offsetY};

            let statusCanvas = document.createElement('canvas');

            statusCanvas.width = canvas.width

            statusCanvas.height = canvas.width;

            this.statusCtx = statusCanvas.getContext('2d');

            this.drawState.nativeElement.appendChild(statusCanvas);

}

drawing

canvasDraw(e: MouseEvent) {

            let canvas: any = this.canvas.nativeElement;

            this.statusCtx.beginPath();

            this.statusCtx.clearRect(0, 0, canvas.width, canvas.height);

            this.statusCtx.strokeStyle = this.strokeColor;

            this.statusCtx.strokeRect(this.startCoordinate.x*this.canvasRatio.width, this.startCoordinate.y*this.canvasRatio.height , (e.offsetX-this.startCoordinate.x)*this.canvasRatio.width, (e.offsetY-this.startCoordinate.y)*this.canvasRatio.height);

            this.statusCtx.closePath();

    }

done

canvasDone(e: MouseEvent) {

            let canvas: any = this.canvas.nativeElement;

            this.statusCtx.beginPath();

            this.statusCtx.clearRect(0, 0, canvas.width, canvas.height);

            this.statusCtx.closePath();

            this.ctx.beginPath();

            if (this.type === 'hide') {

                this.ctx.fillStyle = this.fillColor;

                this.ctx.fillRect(this.startCoordinate.x*this.canvasRatio.width, this.startCoordinate.y*this.canvasRatio.height, (e.offsetX-this.startCoordinate.x)*this.canvasRatio.width, (e.offsetY-this.startCoordinate.y)*this.canvasRatio.height);

            }

            if (this.type === 'highlight') {

                this.ctx.strokeStyle = this.strokeColor;

                this.ctx.clearRect(this.startCoordinate.x*this.canvasRatio.width, this.startCoordinate.y*this.canvasRatio.height, (e.offsetX-this.startCoordinate.x)*this.canvasRatio.width, (e.offsetY-this.startCoordinate.y)*this.canvasRatio.height);

                this.ctx.strokeRect(this.startCoordinate.x*this.canvasRatio.width, this.startCoordinate.y*this.canvasRatio.height , (e.offsetX-this.startCoordinate.x)*this.canvasRatio.width, (e.offsetY-this.startCoordinate.y)*this.canvasRatio.height);

            }

            this.ctx.closePath();

            let statusCanvas: HTMLElement = this.drawState.nativeElement;

            for (let i = statusCanvas.childNodes.length - 1; i >= 0; i -- ) {

                statusCanvas.removeChild(statusCanvas.childNodes[i]);

            }

        this.drawing = false;

    }

保存

保存的时候在创建一个画布将图片和画布的路径层画到上面然后保存就可以了

saveScreenshot() {

            let canvas: any = this.canvas.nativeElement;

            let newCanvas = document.createElement('canvas');

            let can: any = this.can.nativeElement;

            newCanvas.width = can.naturalWidth;

            newCanvas.height = can.naturalHeight;

            let newCtx = newCanvas.getContext('2d');

            var image = new Image();

            image.src = can['src'];

            newCtx.drawImage(image, 0, 0, newCanvas.width, newCanvas.height);

            newCtx.drawImage(canvas, 0, 0, newCanvas.width, newCanvas.height);

            this.clear();   // 取消,clear,或者done的时候记得清除画布就可以了

            document.getElementById('scr').setAttribute('src', newCanvas.toDataURL())

    }

效果

相关文章

  • Quartz 2D (2)

    1、圆形图片裁剪 2、实现手机屏幕截屏功能(把控制器中View的内容截屏生成一张新的图片) 3、图片截屏 4、图片...

  • 图片水印.擦除 图片截屏.........

    画板 图片裁剪 图片擦除 方形图片生产圆形头像 手机截屏 图片水印

  • Quartz2D 第二集

    01-带有边框的图片裁剪 02-截屏 03-图片擦除 04-图片截屏 05-手势解锁 06-画板

  • #Quartz2D#

    01-带有边框的图片裁剪 02-截屏 03-图片擦除 04-图片截屏 05-手势解锁 06-画板

  • Android 截屏方式整理

    Android 实现截屏方式整理 可能的需求: 截自己的屏 截所有的屏 带导航栏截屏 不带导航栏截屏 截屏并编辑选...

  • Quartz2D <实例1>

    饼图 进度条 水印 裁剪圆形图片,带边框 截屏 (图片截屏)截取图片一部分(手指滑动截取) 橡皮擦 手势解锁 画板

  • 截屏、图片裁剪、拼接

    我们在开发中经常需要使用截屏功能或者把某个view生成一张图片的功能,还有可能需要拼接在一起组成一张大图,另外有可...

  • 截屏后图片的裁剪

    //再截屏 UIGraphicsBeginImageContextWithOptions(contentImage...

  • OneNote 插入代码 语法高亮

    问题: OneNote 粘贴代码会丢失语法高亮 解决办法 1 直接截屏 IntelliJ,代码无法编辑2 使用 W...

  • 读袁靖老师关于长城保护的政协提案有感(修订版)

    截屏图片一: 截屏图片二: 截屏图片三: 截屏图片四: 正文: 当看到袁靖老师这一政协提案时,第一印象,这...

网友评论

    本文标题:JS实现截屏和编辑图片(隐藏,高亮,裁剪)

    本文链接:https://www.haomeiwen.com/subject/pmyirdtx.html