1. 程式人生 > 實用技巧 >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>

廣州品牌設計公司https://www.houdianzi.com

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" + cropH + 'px; width:' + cropW + 'px; position:absolute; left:' +
      posX + 'px; top:' + posY + 'px; border:1px solid black;">' +
      '<div id="zxxDragBg"></div>' +
      '<div id="dragLeftTop"></div>' +
      '<div id="dragLeftBot"></div>' +
      '<div id="dragRightTop"></div>' +
      '<div id="dragRightBot"></div>' +
      '<div id="dragTopCenter"></div>' +
      '<div id="dragBotCenter"></div>' +
      '<div id="dragRightCenter"></div> ' +
      '<div id="dragLeftCenter"></div>' +
      '</div>' +
      '<input type="text" id="cropPosX" value="' + posX / scaleX + '"/>' +
      '<input type="text" id="cropPosY" value="' + posY / scaleY + '"/>' +
      '<input type="text" id="cropImageWidth" value="' + cropW / scaleX + '"/>' +
      '<input type="text" id="cropImageHeight" value="' + cropH / scaleY + '"/>';

    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);
  });