Canvas实现图像裁剪保存(含demo)

淩亂°似流年 2023-07-15 09:21 73阅读 0赞

打算用canvas实现一个简单的图片裁剪的功能 (类似于上传头像并裁剪)
先分析一下需求点:

  • 上传一张图片(图片来源会实现两种途径:1、本地上传 2、服务器获取)
  • 将上传的图片先进行预处理(进行缩放)
  • 拖动滑动条缩放图像
  • 裁剪图片并输出结果(两种途径:1、提供下载链接保存至本地 2、上传oss)
  • 项目github:https://github.com/mikoRen/picture-cropper

步骤

    • 展示
    • Start!
    • 第一部分:初始部分:设置缩放参数,图片初始位置,图像绘制
    • 第二部分:canvas位置拖动
    • 第三部分:图像缩放
    • 第四部分:预览—-绘制结果图像
    • 第五部分:导出文件
    • 第五部分:补充>获取图片途径:本地上传

展示

在这里插入图片描述

Start!

html中主要使用的元素:
第一个canvas:用于绘制,操作 原图片
第二个canvas:用于输出裁剪之后的图片
一个input type=range ,缩放时使用的滑动条
第一个button:裁剪图片
第二个button:导出图片

html:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <link href="./index.css" rel="stylesheet" type="text/css">
  8. <title>Document</title>
  9. </head>
  10. <body>
  11. <input id="img-input" type="file"/>
  12. <div class="pic-cropper">
  13. <input id="slider" type="range"/>
  14. <canvas id="image-canvas" width="300" height="300"></canvas>
  15. <button id="submit">预览</button>
  16. <canvas id="result-canvas" width="200" height="200"></canvas>
  17. <button id="export">导出</button>
  18. </div>
  19. <script src="./index.js"></script>
  20. </body>
  21. </html>

在这里插入图片描述

第一部分:初始部分:设置缩放参数,图片初始位置,图像绘制

图片来源:服务器获取(本地上传会在后面补充)
思路要点:

  • 获取一张图片,对图像尺寸进行处理之后,绘制在 源图像canvas 里 (我这里设置的源图像缩放范围是200~500,源图像初始状态:长或者宽为200)
  • 拖动滑动条进行缩放,也就是拖动滑动条的过程中修改【当前缩放值:currentFactor】
  • 滑动条的缩放范围:获取图像之后,判断图像是一个“竖长图像(width=height)”,如果是“竖长图像(width=height)”则按照height来确定缩放范围
  • 缩放和拖动过程中,要注意检测图片不要“出界”

“竖长图像”和“扁图像” 缩放参数的计算不一样
竖长图像
扁图像

使用到的变量

  1. //第一个canvas 源图像canvas
  2. var imgCanvas = document.getElementById("image-canvas"); //源图像canvas的尺寸为300*300
  3. var imgCxt = imgCanvas.getContext("2d");
  4. //第二个canvas 结果图像canvas
  5. var resultCanvas = document.getElementById("result-canvas"); //目标canvas的尺寸为200*200
  6. var resultCxt = resultCanvas.getContext("2d");
  7. var currentFactor = 1; //当前的放缩倍数
  8. var minFactor = 1; //最小放缩倍数
  9. var maxFactor = 1; //最大放缩倍数
  10. var img = new Image();
  11. img.setAttribute('crossOrigin', 'anonymous'); //解决跨域问题

确定图像的放缩范围

(里面的200是目标图的尺寸,500是放缩的最大尺寸,可以根据需求调整)

  1. // 计算初始Factor
  2. calculateFactor = function() {
  3. //竖长图片
  4. if(img.width<img.height) {
  5. minFactor = 200/img.width;//初始状态
  6. currentFactor = 200/img.width;
  7. maxFactor = 500/img.width;
  8. } else {
  9. //扁图片
  10. minFactor = 200/img.height;
  11. currentFactor = 200/img.height;
  12. maxFactor = 500/img.height;
  13. }
  14. initSlider(); //初始化滑动条的min和max
  15. }

确定图片在canvas里的初始绘制位置

  1. //计算初始画布位置
  2. canvasOriginPosition = function() {
  3. calculateFactor();
  4. var positionX;
  5. var positionY;
  6. if(img.width<img.height) {
  7. positionX = 50;
  8. positionY = 50 - (img.height*currentFactor - 200) /2;
  9. } else {
  10. positionX = 50 - (img.width*currentFactor - 200) /2;
  11. positionY = 50;
  12. }
  13. lastImgX = positionX;
  14. lastImgY = positionY;
  15. return({ "positionX":positionX,"positionY":positionY});
  16. }

画蒙版

  1. //画蒙版和截取范围
  2. drawMask = function() {
  3. imgCxt.fillStyle = "rgba(0,0,0,0.5)";
  4. imgCxt.fillRect(0,0,300,300);
  5. imgCxt.fillStyle = "rgba(0,0,0,1)";
  6. imgCxt.globalCompositeOperation = "destination-out"; //globalCompositeOperation提供canvas里图像的组合方式
  7. imgCxt.fillRect(50,50,200,200);
  8. }

获取图像绘进行初始绘制

  1. //获取图像并画出来
  2. //参数里的imgUrl是在从服务器中获取到的图像的url
  3. getImage = function(imgUrl) {
  4. img.src=imgUrl;
  5. img.onload = function() {
  6. calculateFactor(); //绘制图像前 先初始化缩放参数
  7. var originPosition = canvasOriginPosition(); //绘制图像前 获取图像的初始位置
  8. imgCxt.globalCompositeOperation = "destination-over";
  9. imgCxt.drawImage(img,originPosition.positionX,originPosition.positionY,img.width*currentFactor,img.height*currentFactor);
  10. }
  11. }

调用

  1. drawMask();//这里必须先绘制蒙版再绘制图片,原因是 设置的 globalCompositeOperation 的参数 ,可修改
  2. getImage();

到这里就可以实现一个初始的界面了
在这里插入图片描述
每次拖动,或者缩放,canvas都要重新绘制图像

pX,pY是图像的位移,没有发生位移,则参数为0

  1. redrawImg = function(pX,pY) {
  2. //每次绘图前检查position是否没有超出区域
  3. var newPosition = checkPosition(pX,pY)
  4. imgCanvas.setAttribute('height', 300);
  5. drawMask();
  6. imgCxt.globalCompositeOperation = "destination-over";
  7. imgCxt.drawImage(img,newPosition.X,newPosition.Y,img.width*currentFactor,img.height*currentFactor);
  8. }

第二部分:canvas位置拖动

思路:

  • 再canvas范围里,鼠标按下onmousedown:开始进入可拖动状态
  • 可拖动状态下,鼠标移动onmousemove:获取移动位移(pX,pY),和上次移动后的作图位置(lastImageX,lastImageY)组成新的作图位置
  • 鼠标抬起onmouseup:结束拖动状态,并取消可拖动状态
  1. //控制canvas拖动
  2. var moving = false;
  3. var lastmouseX = null;
  4. var lastmouseY = null;
  5. //上次移动结束,canvas画图的位置
  6. var lastImgX = 0;
  7. var lastImgY = 0;
  8. imgCanvas.onmousedown=function(e) {
  9. moving = true;
  10. lastmouseX = e.clientX;
  11. lastmouseY = e.clientY;
  12. }
  13. window.onmouseup = function(e) {
  14. if(moving === true) {
  15. moving = false;
  16. var newPosition = checkPosition(e.clientX - lastmouseX,e.clientY - lastmouseY)
  17. //每次移动完成都要改变一下上次图片绘制位置
  18. lastImgX = newPosition.X;
  19. lastImgY = newPosition.Y;
  20. }
  21. window.onmousemove = function(e) {
  22. if(moving) {
  23. pX=e.clientX - lastmouseX;
  24. pY=e.clientY - lastmouseY;
  25. redrawImg(pX,pY); //移动的时候要重新绘制图像
  26. }
  27. }
  28. }

第三部分:图像缩放

每次图像缩放都要重新位置图像

  1. //初始滑动条
  2. initSlider = function() {
  3. mySlider.min = minFactor;
  4. mySlider.max = maxFactor;
  5. mySlider.step = 0.01;
  6. }
  7. mySlider.oninput = function() {
  8. currentFactor = mySlider.value;
  9. //每次缩放完也都要修改图片的绘制位置,缩放不改变绘制位置,所以参数置为0
  10. redrawImg(0,0);
  11. }

第四部分:预览—绘制结果图像

按照当前的缩放系数(currentFactor),使用 五参数 drawImage()
五个参数的意义:drawImage(img,绘图位置X,绘图位置Y,缩放图像width,缩放图像height )

  1. var submitBtn = document.getElementById("submit");
  2. submitBtn.onclick = function() {
  3. resultCxt.drawImage(img,lastImgX-50,lastImgY-50,img.width*currentFactor,img.height*currentFactor)
  4. }

第五部分:导出文件

这里使用了html a 标签
canvas.toDataURL()

  1. var exportBtn = document.getElementById("export");
  2. exportBtn.onclick = function() {
  3. var url = resultCanvas.toDataURL('image/png', 0.92);
  4. var resultLink = document.createElement("a");
  5. resultLink.download = "裁剪结果";
  6. resultLink.href = url;
  7. document.body.appendChild(resultLink);
  8. resultLink.click();
  9. resultLink.remove();
  10. }

第五部分:补充>获取图片途径:本地上传

  1. var imgInput = document.getElementById("img-input");
  2. imgInput.onchange = function() {
  3. var imgUrl = URL.createObjectURL(imgInput.files[0]);
  4. imgCanvas.setAttribute('height', 300);
  5. resultCanvas.setAttribute('height',200);
  6. drawMask();
  7. getImage(imgUrl);
  8. }

发表评论

表情:
评论列表 (有 0 条评论,73人围观)

还没有评论,来说两句吧...

相关阅读

    相关 python裁剪图像

    之前以为python裁剪图像很难,后来才发现知道裁剪坐标以后(坐标根据目标检测进行坐标变换吧),就很简单了。 1.裁剪 import cv2 cut =

    相关 C#实现图像的鼠标裁剪

    C\的图像裁剪很容易操作,这里给个实现的例子 关键是需要处理鼠标的事件和一些更新 实现鼠标移动的代码.注意更新不要全部重画,只有选择矩形部分重画     C\的图像裁

    相关 canvas反向裁剪技巧

    我们都知道在canvas 可以通过clip来实现剪裁功能,其步骤一般是先设置要裁剪的区域(路径),然后通过ctx.clip()的实现裁剪,裁剪之后,后续的绘制只能在裁剪的区域显

    相关 canvas反向裁剪技巧

    我们都知道在canvas 可以通过clip来实现剪裁功能,其步骤一般是先设置要裁剪的区域(路径),然后通过ctx.clip()的实现裁剪,裁剪之后,后续的绘制只能在裁剪的区域显