资讯专栏INFORMATION COLUMN

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

MAX_zuo / 1986人阅读

摘要:利用实现图片裁剪效果图实现思路打开图片并将图片绘制到中利用的函数来裁剪图片将转化为即可。巨坑转化为图片确认截图确认截图参考文章我是,年轻的前端攻城狮一枚,爱专研,爱技术,爱分享。文章有任何问题欢迎大家指出,也欢迎大家一起交流前端各种问题

利用Canvas实现图片裁剪 效果图

实现思路

打开图片并将图片绘制到canvas中;

利用canvas的drawImage()函数来裁剪图片;

将canvas转化为Image即可。

HTML代码:
CSS代码

CSS代码基本通过javaScript添加

重点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 = "
" + "
" + "
" + "
" + "
" + "
" + "
" + "
" + "
" + "
" + "
" + "" + "" + "" + ""; 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,年轻的前端攻城狮一枚,爱专研,爱技术,爱分享。 
个人笔记,整理不易,感谢阅读、点赞和收藏。
文章有任何问题欢迎大家指出,也欢迎大家一起交流前端各种问题!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105121.html

相关文章

  • 画布、拖放事件、音视频

    摘要:立即对当前矩形进行填充清除矩形语法解释清除某个矩形内的绘制的内容,相当于橡皮擦绘制圆形概述方法创建弧曲线用于创建圆或部分圆语法解释圆心坐标,半径大小,绘制开始的角度。 一、拖放事件 1.1 设置拖拽 给标签设置一个draggable设置为true, 标签就可以拖拽了 1.2 拖拽事件 1.2.1拖拽元素事件 (事件对象为被拖拽元素) ondragstart 拖拽前触发 ondra...

    Nosee 评论0 收藏0
  • 画布、拖放事件、音视频

    摘要:立即对当前矩形进行填充清除矩形语法解释清除某个矩形内的绘制的内容,相当于橡皮擦绘制圆形概述方法创建弧曲线用于创建圆或部分圆语法解释圆心坐标,半径大小,绘制开始的角度。 一、拖放事件 1.1 设置拖拽 给标签设置一个draggable设置为true, 标签就可以拖拽了 1.2 拖拽事件 1.2.1拖拽元素事件 (事件对象为被拖拽元素) ondragstart 拖拽前触发 ondra...

    dailybird 评论0 收藏0
  • 画布、拖放事件、音视频

    摘要:立即对当前矩形进行填充清除矩形语法解释清除某个矩形内的绘制的内容,相当于橡皮擦绘制圆形概述方法创建弧曲线用于创建圆或部分圆语法解释圆心坐标,半径大小,绘制开始的角度。 一、拖放事件 1.1 设置拖拽 给标签设置一个draggable设置为true, 标签就可以拖拽了 1.2 拖拽事件 1.2.1拖拽元素事件 (事件对象为被拖拽元素) ondragstart 拖拽前触发 ondra...

    atinosun 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<