JS原生使用Canvas截取图片并下载_Dilomen的博客-程序员宝宝

技术标签: canvas  原生JS  JS文件处理  html  File  

HTML部分 

<body> 
  <div
      class="wrap"
      onmousedown="handleMouseDown(event)"
      onmousemove="handleMouseMove(event)"
      onmouseup="handleMouseUp(event)"
    >
      <img id="image" src="" alt="" />
      <canvas
        style="left: 30px;top: 40px;"
        width="300"
        height="200"
        id="canvas"
      ></canvas>
    </div>
    <input type="file" onchange="handleInput(event)" />
    <button onclick="handleCut()">截取</button>
    <button onclick="handleDownload()">下载</button>
</body> 

CSS部分

   .wrap {
      width: 600px;
      height: 400px;
      position: relative;
      border: 1px solid #333;
      box-sizing: border-box;
    }
    #image {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
    }
    #canvas {
      position: absolute;
      border: 1px solid rgb(136, 219, 119);
      background: rgba(156, 156, 156, 0.3);
      display: none;
      z-index: 100;
      box-sizing: border-box;
    }
    button {
      width: 80px;
      height: 30px;
    }

JS部分

    let imageFile = null;
    let isMouseDown = false;
    let wrap = document.getElementsByClassName("wrap")[0];
    let ctx = document.getElementById("canvas");
    let img = document.getElementById("image");
    let content = ctx.getContext("2d");
    let wrapWidth = wrap.offsetWidth;
    let wrapHeight = wrap.offsetHeight;
    let ctxWidth, ctxHeight;
    function handleInput(e) {
      imageFile = e.target.files[0];
      let fileReader = new FileReader();
      fileReader.onload = function(e) {
        img.src = e.target.result;
        canvas.style.display = "block";
        ctxWidth = ctx.offsetWidth;
        ctxHeight = ctx.offsetHeight;
      };   
      // 将文件转化为base64编码
      fileReader.readAsDataURL(imageFile);
    }

    function handleMouseDown(event) {
      if (!img.getAttribute("src")) return;
      // 一旦移动位置,就清空画布
      ctx.height = ctx.height;
      isMouseDown = true;
      updateSite(event.pageX, event.pageY);
    }
    function handleMouseMove(event) {
      if (!isMouseDown) return;
      updateSite(event.pageX, event.pageY);
    }
    function handleMouseUp(event) {
      isMouseDown = false;
    }
    // 移动canvas位置
    function updateSite(X, Y) {
      let currentTop, currentLeft;
      if (Y + ctxHeight / 2 >= wrapHeight) {
        currentTop = wrapHeight - ctxHeight;
      } else if (Y - ctxHeight / 2 <= 0) {
        currentTop = 0;
      } else {
        currentTop = Y - ctxHeight / 2;
        console.log("currentTop", currentTop, Y - ctxHeight / 2, ctxHeight);
      }
      if (X + ctxWidth / 2 >= wrapWidth) {
        currentLeft = wrapWidth - ctxWidth;
      } else if (X - ctxWidth / 2 <= 0) {
        currentLeft = 0;
      } else {
        currentLeft = X - ctxWidth / 2;
        console.log("currentLeft", currentLeft, X - ctxWidth / 2, ctxWidth);
      }
      ctx.style.top = currentTop + "px";
      ctx.style.left = currentLeft + "px";
    }

    // 截取
    function handleCut(type = "image/png") {
      if (!img.getAttribute("src")) {
        alert("请导入图片");
        return;
      }
      let cutImg = document.createElement("img");
      content.drawImage(
        img,
        -parseInt(ctx.style.left),
        -parseInt(ctx.style.top),
        wrap.scrollWidth,
        wrap.scrollHeight
      );
      cutImg.src = ctx.toDataURL(type);
      document.body.append(cutImg);
    }
    function handleDownload() {
      if (!img.getAttribute("src")) {
        alert("请导入图片");
        return;
      }
      loadFile(DataURLToFile(ctx.toDataURL()));
    }
    function DataURLToFile(dataUrl, filename = "file", type) {
      let arr = dataUrl.split(",");
      let bstr = atob(arr[1]);
      !type && (type = arr[0].replace("data:", "").replace(";base64", ""));

      let n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, { type });
    }
    // 下载文件
    function loadFile(content, filename = "file") {
      var aLink = document.createElement("a");
      aLink.download = filename;
      aLink.href = URL.createObjectURL(content);
      aLink.click();
      URL.revokeObjectURL(content);
    }

效果如下,截取框内的图片,并可通过下载按钮下载

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Dilomen/article/details/104151313

智能推荐

计算机科学与技术syc,数学与非线性科学 - 声振论坛 - 振动,动力学,声学,信号处理,故障诊断 - Powered by Discuz!..._weixin_39685697的博客-程序员宝宝

续上...========================================================================多物理多尺度数值模拟第四届国际研讨会将在北京举办Date: Fri, 10 Nov 2006 11:16:10 -0500From: Shuyu Sun Simulation of Multiphysics Multiscale Systems4...

dirsearch中文使用手册_dirsearch 参数_Yuhao~的博客-程序员宝宝

dirsearch当前版本:v0.3.9(2019.11.26)Overviewdirsearch是一种高级的命令行工具,旨在对web服务器中的目录和文件进行暴力破解。git clone https://github.com/maurosoria/dirsearch.gitcd dirsearchpython3 dirsearch.py -u &lt;URL&gt; -e &lt;EXTENSION&gt;也可以使用此别名直接发送到代理python3 /path/to/dirsearch/d

TO_CHAR(DATE,FORMAT)_whxhz80的博客-程序员宝宝

SYSDATE2009-6-16 15:25:10 TRUNC(SYSDATE)2009-6-16 TO_CHAR(SYSDATE,'YYYYMMDD')20090616到日TO_CHAR(SYSDATE,'YYYYMMDD HH24:MI:SS')20090616 15:25:10到秒TO_CHAR(SYSTIMESTAMP...

初级程序员容易犯的错误_cym492224103的博客-程序员宝宝

作为一名合格的程序员,良好的编程习惯是必不可少的,无论你是前端还是后端或者移动端,都应该时刻注意自己的编码习惯。只有不断的注意细节力争完美,才会更快速的变成高级程序员。今天就说一说一些初...

【leetcode】字符串的常见算法问题总结(LIS、LCS、LCP、LPS、ED、KMP)_字符串lcp_哈哈村长的博客-程序员宝宝

字符串有很多比较经典的算法问题,例如:LIS(最长递增子序列)、LCS(最长公共子序列、最长公共子串)、LCP(最长公共前缀)、LPS(最长回文子序列、最长回文子串)、ED(最小编辑距离,也叫 “Levenshtein 距离”)、 KMP(一种字符串匹配的高效算法)。上面列举的经典问题,在 Leetcode 中都有对应题型,这些也是笔试面试经常会遇到的基本题型。上面列举的三个经典匹配算法中,KM...

关于KMPlayer播放器不显示字幕的解决方法_kmplayer 不显示字幕_卷雷的博客-程序员宝宝

今天用KMPlayer看时,我的srt字幕文件总是不显示,后来参考了网上的答案,把问题解决了。解决方法:打开KMP播放器,右键-视频(高级)-视频渲染器-VMR7未渲染(HQ字幕)参考答案:脑小胖的回答...

随便推点

MATLAB图库中的小女孩是谁,蚁人2中的小女孩是谁 在漫画中小女孩的身份又是什么..._邢哲wanderer的博客-程序员宝宝

电影《蚁人2》这部电影和其他的英雄电影不一样的是,这部电影中的英雄不再是去拯救世界,而是拯救家庭,并且其中也没有太大的反派也没有人想要毁灭世界,这部电影可谓是充满了温馨感和愉悦感。另外这部电影中蚁人和初代黄蜂女的感情也是非常令人羡慕,《蚁人2》中的小女孩也是引起了很多观众的好奇心。《蚁人2》剧照其实《蚁人2》这部电影整体还是算不错的,但是也有人说该电影作为漫威系列的单人电影剧情还是有些过于简单,在...

YUV 420 422 444 8bit, 每个像素占几个字节_yuv422 8bit_高山飞鹰2000的博客-程序员宝宝

YUV 4:4:4采样,每一个Y对应一组UV分量。YUV 4:2:2采样,每两个Y共用一组UV分量。YUV 4:2:0采样,每四个Y共用一组UV分量。Y占一个字节,U占一个字节,V占一个字节。YUV 4:4:4采样,每一个Y对应一组UV分量,也就是说1个像素点占1个Y和一组UV,也就是3个字节。经上分析可以得出以下结论:YUV 420(NV12 NV21)每个像素:1.5个字...

Ubuntu 18.10 cosmic换源_songpeng26的博客-程序员宝宝

前情提要:今天突然ubuntu apt update 无法用了,通过调查才知道ubuntu产品售后是有期限的。过了期限的版本,会被切换到old release的源。尝试切换到中科大源:##中科大源deb https://mirrors.ustc.edu.cn/ubuntu/ cosmic main restricted universe multiversedeb-src https:/...

TCHAR ,UNICODE,CHAR,wchar_t 之间的关系_易时能的博客-程序员宝宝

1、TCHAR ,UNICODE,CHAR,wchar_t 之间的关系经常发现有的人爱用strcpy等标准ANSI函数,有的人爱用_tXXXX函数,这个问题曾经搞的很混乱。为了统一,有必要搞清楚它们之间的关系。 为了搞清这些函数,就必须理请几种字符类型的写法。char就不用说了,先说一些wchar_t。wchar_t是Unicode字符的数据类型,它实际定义在里: typedef un

C++学习笔记十-关联容器_anhuang5101的博客-程序员宝宝

一、概述:关联容器和顺序容器的本质差别在于:关联容器通过键(key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。 1.关联容器(Associative containers)支持通过键来高效地查找和读取元素。两个基本的关联容器类型是 map set。map 的元素以键-值(key-value)对的形式组织:键用作元素在 map 中的索引,...

推荐文章

热门文章

相关标签