DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> HTML基礎知識 >> HTML5教程 >> 從web圖片裁剪出發:了解H5中的canvas
從web圖片裁剪出發:了解H5中的canvas
編輯:HTML5教程     

  本篇內容不針對canvas文檔對每個api進行逐個的詳解!

  本篇內容不針對canvas文檔對每個api進行逐個的詳解!

  本篇內容不針對canvas文檔對每個api進行逐個的詳解!

  重說三,好了,現在進入正文。上一回我們解釋了圖片在浏覽器中以怎樣的形式留存,並且在最後一個example中演示了選擇圖片、預覽最後提交的過程。然而這個預覽並沒有起到什麼卵用,因為只能預覽不能處理,原圖片還是原圖片,預覽變得可有可無。這一篇我們就在預覽這一步裡做點手腳,加入處理圖片的功能。

  我們先修改之前的example,既然要處理圖片,肯定要引入canvas,所以我們把原來img這個標簽去掉,取而代之的是canvas,並在js中加入對應的修改。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <form name='test'>
    <input type="file" name='file'>
    <input type="submit" value="提交">
  </form>
  <canvas width="0" height="0"></canvas>
  <script>
    var canvas = document.querySelector('canvas'),
        ctx = canvas.getContext('2d'),
        preview = new Image();
    document.test.file.addEventListener('change', function() {
      var fr = new FileReader();
      fr.onload = function() {
        preview.src = this.result;
        canvas.width = preview.width;
        canvas.height = preview.height;
        drawImage();
      };
      fr.readAsDataURL(this.files[0]);
    })
    function drawImage() {
      ctx.drawImage(preview, 0, 0); //把圖片繪制到canvas上
    }
    document.test.addEventListener('submit', function(e) {
      e.preventDefault();
      var formData = new FormData(),
          xhr = new XMLHttpRequest(),
          mime = 'image/jpeg',
          dataUrl = canvas.toDataURL(mime, 0.8),  //取出base64
          data = atob(dataUrl.split(',')[1]),
          n = data.length,
          uInt8 = new Uint8Array(n),
          blob;
      while(n--) {
        uInt8[n] = data.charCodeAt(n);
      }
      blob = new Blob([uInt8.buffer], {type: mime});
      formData.append('file', blob, 'test.jpg');
      xhr.open('post', '/upload');
      xhr.send(formData);
    })
  </script>
</body>
</html>

  之前example的canvas版實現了,現在我們加入處理圖片的功能。首先我們加入裁剪的功能,裁剪的引入必須先引入橡皮筋功能,就是一個選取框。一般我們見過的選取框是這樣的。

預覽的樣子

選取一部分的樣子

  我們來分析下實現這樣一個功能需要做什麼。首先選取框有個開始點和結束點,在鼠標按下去的時候確定開始點,在松開的時候確定結束點,在移動的時候還要不停的繪制。那麼繪制一個有選取框的內容分幾步呢?第一步是繪制底圖,第二步是繪制陰影,第三部還是繪制底圖,但是只作用於選取框內部。最後想取消選取框怎麼辦,我們還要有個方法重置開始點和結束點,並且只繪制底圖。

  我們一步一步來,首先確定開始點和結束點。

var sPoint = {},
        ePoint = {};
    canvas.addEventListener('mousedown', function(e) {
      if(e.button === 0) {
        sPoint.x = e.offsetX;
        sPoint.y = e.offsetY;
        sPoint.drag = true;
      }
    });

  然後我們確定繪制陰影的的方法,並且在鼠標按下去移動的時候不停的繪制。

function drawCover() {
      ctx.save();
      ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.restore();
    }
    canvas.addEventListener('mousemove', function(e) {
      if(e.button === 0 && sPoint.drag) {var nPoint = {
          x: e.offsetX,
          y: e.offsetY
        };
        ctx.save();    //clip要通過restore回復
        ctx.clearRect(0, 0, canvas.width, canvas.height);    //畫布全清
        drawImage();    //繪制底圖
        drawCover();    //繪制陰影
        ctx.beginPath();    //開始路徑
        ctx.rect(sPoint.x, sPoint.y, nPoint.x - sPoint.x, nPoint.y - sPoint.y);    //設置路徑為選取框
        ctx.clip();    //截取路徑內為新的作用區域
        drawImage();    //在選取框內繪制底圖
        ctx.restore();    //恢復clip截取的作用范圍
      }
    });

  最後我們添加松開鼠標的事件監聽,松開左鍵為拖動結束,松開右鍵為復原

canvas.addEventListener('mouseup', function(e) {
      if(e.button === 0) {
        sPoint.drag = false;
        ePoint.x = e.offsetX;
        ePoint.y = e.offsetY;
      }else if(e.button === 2) {
        restore();
      }
    });
    function restore() {
      sPoint = {};
      ePoint = {};
      drawImage();
    }

  由於右鍵會出現惡心的浏覽器自帶菜單欄,影響體驗,我們屏蔽它。

document.addEventListener('contextmenu', function(e) {
      e.preventDefault();
      e.stopPropagation();
    });

  現在選取框有了,我們要開始截取了。新添加一個按鈕,然後添加點擊監聽。

html代碼

<form name='test'>
    <input type="file" name='file'>
    <button id="clip">裁剪</button>
    <input type="submit" value="提交">
  </form>

js代碼

var clip = document.querySelector('#clip');
    clip.addEventListener('click', function(e) {
  e.preventDefault();    //阻止默認事件,不然會觸發form的submit
      if(sPoint.x !== undefined && ePoint.x !== undefined) {
        var imgData = ctx.getImageData(sPoint.x, sPoint.y, ePoint.x - sPoint.x, ePoint.y - sPoint.y);    //把裁剪區域的圖片信息提取出來
        ctx.clearRect(0, 0, canvas.width, canvas.height);    //清空畫布
        canvas.width = Math.abs(ePoint.x - sPoint.x);    //重置canvas的大小為新圖的大小
        canvas.height = Math.abs(ePoint.y - sPoint.y);
        ctx.putImageData(imgData, 0, 0);    //把提取出來的圖片信息放進canvas中
        preview.src = canvas.toDataURL();    //裁剪後我們用新圖替換底圖,方便繼續處理
      }else {
        alert('沒有選擇區域');
      }
    });

 

  現在我們裁剪後選擇提交,會發現服務器生成的是裁剪後的圖片

  裁剪的功能完成了,我們在來實現第二個功能:灰度。如果說裁剪的功能在於clip的用法,那麼灰度的實現是基於getImageData返回的對象的認識。這個對象中有一個屬性叫data,這是一個數組,以4個為一組,分別存儲了一個像素red、green、blue、opacity四個數據。也就是當你的canvas尺寸為1*1時,它的ImageData.data元素為4個。

   廢話不多說,直接給出實現的代碼。

html代碼

<form name='test'>
    <input type="file" name='file'>
    <button id="clip">裁剪</button>
    <button id="grey">灰度</button>
    <input type="submit" value="提交">
  </form>

js代碼

var grey = document.querySelector('#grey');
    grey.addEventListener('click', function(e) {
  e.preventDefault();
      var startX = 0, startY = 0, width = canvas.width, height = canvas.height;
      ctx.clearRect(0, 0, canvas.width, canvas.height);    //一如既往的先清空畫布,不然會處理含有選取框的圖片內容
      drawImage();    //繪制底圖
      var imgData = ctx.getImageData(startX, startY, width, height);   //把整個底圖的圖片內容取出來 
      for(var i = 0; i < imgData.data.length;) {
        var red = imgData.data[i],
            green = imgData.data[i+1],
            blue = imgData.data[i+2],
            opacity = imgData.data[i+3],    //不處理,可以省去這一行,占位說明這一位是透明度
            average = (red + green + blue) / 3;    //所謂灰度其實是取三種顏色的平均值
        imgData.data[i] = imgData.data[i+1] = imgData.data[i+2] = average;    //三個顏色設為一樣即是對應的灰色
        i += 4;
      }
      ctx.putImageData(imgData, startX, startY, 0, 0, width, height);    //把處理過的imagedata放回canvas中
      preview.src = canvas.toDataURL();    //保存圖片信息方便再進行處理
    });

 

  選擇灰度並提交,我們看服務器上生成的圖片

  最後我們結合裁剪和灰度,一起處理一張圖片再提交。

 

  好了,簡單的兩個圖片處理的方式就介紹到這,至於復雜的,你可以拿到每一個像素的信息,還擔心實現不了其他的功能麼。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved