Canvas裁剪图片(截选框可拖拽)

栏目: Html5 · 发布时间: 6年前

内容简介:CSS代码基本通过javaScript添加可伸缩截图框实现思路:

利用Canvas实现图片裁剪

效果图

Canvas裁剪图片(截选框可拖拽)

实现思路

  1. 打开图片并将图片绘制到canvas中;
  2. 利用canvas的drawImage()函数来裁剪图片;
  3. 将canvas转化为Image即可。

HTML代码:

<div id="container">
  <div id="btnDiv">
    <button id="btn1">截图</button>
    <button id="btn2">确认截图</button>
    <button id="btn3">打开</button>
  </div>
  <div id="imgDiv"></div>
  <div id="clipImgDiv"></div>
</div>

CSS代码

CSS代码基本通过javaScript添加

<style>
    body {
      background-color: black;
    }
  </style>

重点JavaScript代码

变量定义、添加各事件按钮、容器等:

let originWidth; // 图片原始宽度
  let originHeight; // 图片原始高度
  let container = document.getElementById('container');
  let imgDiv = document.getElementById('imgDiv');    // 存放mycanvas
  let btnDiv = document.getElementById('btnDiv');
  let clipImgDiv = document.getElementById('clipImgDiv');    // 显示裁剪所获的图片
  let btn1 = document.getElementById('btn1');    // 截图按钮
  let btn2 = document.getElementById('btn2');    // 确认截图按钮
  let btn3 = document.getElementById('btn3');    // 打开文件按钮
  var oRelDiv = document.createElement("div"); // 截图框
  var scaleX = 1;// 图片宽度缩放比例(当前实际/原始)
  var scaleY = 1;  // 图片高度缩放比例(当前实际/原始)
  //拖拽与拉伸方法
  //拖拽拉伸所需参数
  let params = {
    left: 0,
    top: 0,
    width: 0,
    height: 0,
    currentX: 0,
    currentY: 0,
    flag: false,
    kind: "drag"
  };
  
// CSS样式修改
  container.style.display = 'flex';
  container.style.flexDirection = 'column';
  btnDiv.style.marginBottom = '20px';
  btnDiv.style.height = '30px';
  imgDiv.style.marginBottom = '20px';

  // 创建canvas,用于显示被裁剪图片
  var myCanvas = document.createElement('canvas');
  myCanvas.setAttribute('id', 'myCanvas');
  myCanvas.style.display = 'block';
  /*myCanvas.style.position = 'absolute';*/
  myCanvas.width = 600;
  myCanvas.height = 600;
  myCanvas.style.border = "1px solid #d3d3d3";
  myCanvas.innerText = '您的浏览器不支持 HTML5 canvas 标签。';
  myCanvas.style.zIndex = 'auto';

  var ctx = myCanvas.getContext('2d');

  // 被裁剪图片
  var img = new Image();
  img.src = './images/IMG_1550.jpg';
  img.setAttribute('id', 'img');
  img.width = 600;
  img.height = 600;
  img.onload = function () {
    console.log('onload()执行...');
    ctx.drawImage(img, 0, 0, 600, 600);
    originWidth = img.naturalWidth;
    originHeight = img.naturalHeight;
    console.log('图片原始宽度=', originWidth);
    console.log('图片原始高度=', originHeight);
  };

  // 裁剪得到的图片
  let clipImg = new Image();
  clipImg.src = '';
  clipImg.style.height = '100px';
  clipImg.style.width = '100px';
  clipImg.alt = '裁剪获得图片...';

  // input用于打开文件
  let fileInput = document.createElement('input');
  fileInput.setAttribute('multiple', 'multiple');
  fileInput.setAttribute('type', 'file');
  fileInput.setAttribute('id', 'fileInput');

  /*btnDiv.appendChild(fileInput);*/
  imgDiv.appendChild(myCanvas);
  /*clipImgDiv.appendChild(clipImg);*/

一些简单的功能函数

// 生成本地图片URL地址
let getObjectURL = function (file) {
    let url = null;
    if (window.createObjectURL !== undefined) { // basic
      url = window.createObjectURL(file);
    } else if (window.webkitURL !== undefined) { // webkit or chrome
      url = window.webkitURL.createObjectURL(file);
    } else if (window.URL !== undefined) { // mozilla(firefox)
      url = window.URL.createObjectURL(file);
    }
    return url;
  };

  // 获取指定元素DOM
  const ID = function (id) {
    return document.getElementById(id);
  };

  //获取相关CSS属性方法
  let getCss = function (o, key) {
    return o.currentStyle ? o.currentStyle[key] : document.defaultView.getComputedStyle(o, false)[key];
  };

打开本地图片

可伸缩截图框实现思路:

截图框由8各控制截图框大小、位置小div组成,鼠标在选中截图框后在拖动鼠标的过程中会根据鼠标位置对截图框进行实时绘制

// 打开本地图片
fileInput.addEventListener('change', function () {
    console.log('change()执行...');
    img.src = getObjectURL(this.files[0]);
  });
btn3.addEventListener("click", function () {
    fileInput.click();
  });

截图选框的绘制、拖动、大小调整

btn1.addEventListener("click", function () {
    var clickFlag = false;
    // 获取canvas中图片实际大小
    var iCurWidth = img.width;
    var iCurHeight = img.height;
    console.log('图片当前实际宽度=', iCurWidth);
    console.log('图片当前实际高度=', iCurHeight);

    // 可调整截图框
    oRelDiv.innerHTML = '';
    oRelDiv.style.position = "absolute";
    oRelDiv.style.width = iCurWidth + "px";
    oRelDiv.style.height = iCurHeight + "px";
    oRelDiv.style.top = myCanvas.offsetTop + 'px';
    console.log('oRelDiv.style.top = ', oRelDiv.style.top);
    oRelDiv.id = "cropContainer";

    var iOrigWidth = originWidth;
    var iOrigHeight = originHeight;
    scaleX = iCurWidth / iOrigWidth; // 图片宽度缩放比例(当前实际/原始)
    scaleY = iCurHeight / iOrigHeight;  // 图片高度缩放比例(当前实际/原始)
    console.log('图片横向(宽度)缩放比=', scaleX);
    console.log('图片纵向(高度)缩放比=', scaleY);

    // 将oRelDiv插入到myCanvas前
    myCanvas.parentNode.insertBefore(oRelDiv, myCanvas);

    //初始化坐标与剪裁高宽
    var cropW = 80; //截图框默认宽度
    var cropH = 80; //截图框默认高度
    /*console.log('myCanvas.offsetLeft=', myCanvas.offsetLeft);
    console.log('myCanvas.offsetTop=', myCanvas.offsetTop);*/
    var posX = myCanvas.width / 2 - cropW / 2;  // 截图框左上角x坐标
    var posY = myCanvas.height / 2 - cropH / 2;    // 截图框左上角y坐标
    /*console.log('posX=',posX);
    console.log('posY=',posY);*/

    oRelDiv.innerHTML = '<div id="zxxCropBox" style="height:' + cropH + 'px; width:' + cropW + 'px; position:absolute; left:' +
      posX + 'px; top:' + posY + 'px; border:1px solid black;">' +
      '<div id="zxxDragBg" style="height:100%; background:white; opacity:0.3; filter:alpha(opacity=30); cursor:move"></div>' +
      '<div id="dragLeftTop" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; top:-3px; cursor:nw-resize;"></div>' +
      '<div id="dragLeftBot" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; bottom:-3px; cursor:sw-resize;"></div>' +
      '<div id="dragRightTop" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; top:-3px; cursor:ne-resize;"></div>' +
      '<div id="dragRightBot" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; bottom:-3px; cursor:se-resize;"></div>' +
      '<div id="dragTopCenter" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; top:-3px; left:50%; margin-left:-3px; cursor:n-resize;"></div>' +
      '<div id="dragBotCenter" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; bottom:-3px; left:50%; margin-left:-3px; cursor:s-resize;"></div>' +
      '<div id="dragRightCenter" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; right:-3px; top:50%; margin-top:-3px; cursor:e-resize;"></div> ' +
      '<div id="dragLeftCenter" style="position:absolute; width:4px; height:4px; border:1px solid #000; background:white; overflow:hidden; left:-3px; top:50%; margin-top:-3px; cursor:w-resize;"></div>' +
      '</div>' +
      '<input type="text" id="cropPosX" value="' + posX / scaleX + '" style="position:relative; top: -26px; width: 30px"/>' +
      '<input type="text" id="cropPosY" value="' + posY / scaleY + '" style="position:relative; top: -26px; width: 30px"/>' +
      '<input type="text" id="cropImageWidth" value="' + cropW / scaleX + '" style="position:relative; top: -26px; width: 30px"/>' +
      '<input type="text" id="cropImageHeight" value="' + cropH / scaleY + '" style="position:relative; top: -26px; width: 30px"/>';

    var startDrag = function (point, target, kind) {
      //point是拉伸点,target是被拉伸的目标,其高度及位置会发生改变
      //此处的target与上面拖拽的target是同一目标,故其params.left,params.top可以共用,也必须共用
      //初始化宽高
      params.width = getCss(target, "width");
      params.height = getCss(target, "height");
      //初始化坐标
      if (getCss(target, "left") !== "auto") {
        params.left = getCss(target, "left");
      }
      if (getCss(target, "top") !== "auto") {
        params.top = getCss(target, "top");
      }
      //target是移动对象
      point.onmousedown = function (event) {
        params.kind = kind;
        params.flag = true;
        clickFlag = true;
        if (!event) {
          event = window.event;
        }
        var e = event;
        params.currentX = e.clientX;  //鼠标按下时坐标x轴
        params.currentY = e.clientY;  //鼠标按下时坐标y轴
        /*console.log('params.currentX=', params.currentX);
        console.log('params.currentY=', params.currentY);*/
        //防止IE文字选中,有助于拖拽平滑
        point.onselectstart = function () {
          return false;
        };

        document.onmousemove = function (event) {
          let e = event ? event : window.event;
          clickFlag = false;
          if (params.flag) {
            var nowX = e.clientX; // 鼠标移动时x坐标
            var nowY = e.clientY;   // 鼠标移动时y坐标
            var disX = nowX - params.currentX;  // 鼠标x方向移动距离
            var disY = nowY - params.currentY;  // 鼠标y方向移动距离
            if (params.kind === "n") {
              //上拉伸
              //高度增加或减小,位置上下移动
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
            } else if (params.kind === "w") { //左拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
            } else if (params.kind === "e") { //右拉伸
              target.style.width = parseInt(params.width) + disX + "px";
            } else if (params.kind === "s") { //下拉伸
              target.style.height = parseInt(params.height) + disY + "px";
            } else if (params.kind === "nw") { //左上拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
            } else if (params.kind === "ne") { //右上拉伸
              target.style.top = parseInt(params.top) + disY + "px";
              target.style.height = parseInt(params.height) - disY + "px";
              target.style.width = parseInt(params.width) + disX + "px";
            } else if (params.kind === "sw") { //左下拉伸
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.width = parseInt(params.width) - disX + "px";
              target.style.height = parseInt(params.height) + disY + "px";
            } else if (params.kind === "se") { //右下拉伸
              target.style.width = parseInt(params.width) + disX + "px";
              target.style.height = parseInt(params.height) + disY + "px";
            } else { //移动
              target.style.left = parseInt(params.left) + disX + "px";
              target.style.top = parseInt(params.top) + disY + "px";
            }
          }

          document.onmouseup = function () {

            params.flag = false;
            if (getCss(target, "left") !== "auto") {
              params.left = getCss(target, "left");
            }
            if (getCss(target, "top") !== "auto") {
              params.top = getCss(target, "top");
            }
            params.width = getCss(target, "width");
            params.height = getCss(target, "height");
            /*console.log('params.width=', params.width);
            console.log('params.height', params.width);*/

            //给隐藏文本框赋值
            posX = parseInt(target.style.left);
            posY = parseInt(target.style.top);
            cropW = parseInt(target.style.width);
            cropH = parseInt(target.style.height);
            if (posX < 0) {
              posX = 0;
            }
            if (posY < 0) {
              posY = 0;
            }
            if ((posX + cropW) > iCurWidth) {
              cropW = iCurWidth - posX;
            }
            if ((posY + cropH) > iCurHeight) {
              cropH = iCurHeight - posY;
            }
            //赋值
            ID("cropPosX").value = posX;
            ID("cropPosY").value = posY;
            ID("cropImageWidth").value = parseInt(ID("zxxCropBox").style.width);
            ID("cropImageHeight").value = parseInt(ID("zxxCropBox").style.height);

            /*console.log('posX=',posX);
            console.log('posY=',posY);*/
          };
        }
      };
    };

    //绑定拖拽
    startDrag(ID("zxxDragBg"), ID("zxxCropBox"), "drag");
    //绑定拉伸
    startDrag(ID("dragLeftTop"), ID("zxxCropBox"), "nw");
    startDrag(ID("dragLeftBot"), ID("zxxCropBox"), "sw");
    startDrag(ID("dragRightTop"), ID("zxxCropBox"), "ne");
    startDrag(ID("dragRightBot"), ID("zxxCropBox"), "se");
    startDrag(ID("dragTopCenter"), ID("zxxCropBox"), "n");
    startDrag(ID("dragBotCenter"), ID("zxxCropBox"), "s");
    startDrag(ID("dragRightCenter"), ID("zxxCropBox"), "e");
    startDrag(ID("dragLeftCenter"), ID("zxxCropBox"), "w");


    //图片不能被选中,目的在于使拖拽顺滑
    ID("myCanvas").onselectstart = function () {
      return false;
    };
    img.onselectstart = function () {
      return false;
    };
  });

所获截图绘制

function cropImage(img, cropPosX, cropPosY, width, height) {
    /*var cropContainer = ID("cropContainer");
    cropContainer.parentNode.removeChild(cropContainer);*/
    /*ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);*/
    //sx,sy 是相对于图片的坐标。巨坑
    var newCanvas = document.createElement('canvas');
    newCanvas.setAttribute('id', 'newCanvas');
    newCanvas.width = width * scaleX;
    newCanvas.height = height * scaleY;
    newCanvas.style.border = "1px solid #d3d3d3";
    var newCtx = newCanvas.getContext('2d');
    clipImgDiv.appendChild(newCanvas);
    newCtx.drawImage(img, cropPosX, cropPosY, width, height, 0, 0, width * scaleX, height * scaleY);

    // canvas转化为图片
    var newImage = new Image();
    newImage.src = newCanvas.toDataURL("image/png");
    newImage.style.marginLeft = '5px';
    clipImgDiv.appendChild(newImage);

    oRelDiv.innerHTML = '';
  }

确认截图

// 确认截图
  btn2.addEventListener("click", function () {
    console.log("clipend......");

    var x = document.getElementById("cropPosX").value;
    var y = document.getElementById("cropPosY").value;
    var w = document.getElementById("cropImageWidth").value;
    var h = document.getElementById("cropImageHeight").value;
    console.log('cropImage(img,', x, ',', y, ',', parseInt(w), ',', parseInt(h), ')');
    cropImage(img, x / scaleX, y / scaleY, parseInt(w) / scaleX, parseInt(h) / scaleY);
  });

参考文章: https://blog.csdn.net/qq_3870...

我是Cloudy,年轻的前端攻城狮一枚,爱专研,爱技术,爱分享。

个人笔记,整理不易,感谢阅读、点赞和收藏。

文章有任何问题欢迎大家指出,也欢迎大家一起交流前端各种问题!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入解析Spring MVC与Web Flow

深入解析Spring MVC与Web Flow

Seth Ladd、Darren Davison、Steven Devijver、Colin Yates / 徐哲、沈艳 / 人民邮电出版社 / 2008-11 / 49.00元

《深入解析Spring MVCgn Web Flow》是Spring MVC 和Web Flow 两个框架的权威指南,书中包括的技巧和提示可以让你从这个灵活的框架中汲取尽可能多的信息。书中包含了一些开发良好设计和解耦的Web 应用程序的最佳实践,介绍了Spring 框架中的Spring MVC 和Spring Web Flow,以及着重介绍利用Spring 框架和Spring MVC 编写Web ......一起来看看 《深入解析Spring MVC与Web Flow》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具