canvas簡單實現純色背景圖片摳圖

最近在研究html5 canvas的過程當中,發現,canvas爲前端對圖像的處理開闢了一條新的道路,canvas能夠作到不少事情,甚至能夠作個相似於PhotoShop的東西,曾經本人在一家軟件工做就作相似的工做,能夠看一下我以前開發的軟件:
v2-70afa0ac99829ba42adde3b969596693_b.jpghtml

這個就是canvas實現的相似於Adobe Photoshop,足以見得canvas的強大之處!前端

本文就是抽出其中一個小的功能點,來簡單聊聊canvas強大之處:咱們來一步步實現一個簡單的智能摳圖功能:(具體的代碼見個人github:monkeyWangs/Matting)html5

1.環境準備node

本人採用ES6語法做爲開發環境,選用webpack做爲構建工具,因而乎,咱們有了webpack.config.jswebpack

/**
 * @author monkeyWang
 *
 */

/* 引入操做路徑模塊和webpack */
var path = require('path');
var webpack = require('webpack');

module.exports = {
  /* 輸入文件 */
  entry: './src/index.js',
  output: {
    /* 輸出目錄,沒有則新建 */
    path: path.resolve(__dirname, './dist'),
    /* 靜態目錄,能夠直接從這裏取文件 */
    publicPath: '/dist/',
    /* 文件名 */
    filename: 'matting.js'
  },
  module: {
    rules: [
      /* 用babel來解析js文件並把es6的語法轉換成瀏覽器認識的語法 */
      {
        test: /\.js$/,
        loader: 'babel-loader',
        /* 排除模塊安裝目錄的文件 */
        exclude: /node_modules/
      }
    ]
  }
}

這樣變準備好了開發用的基本環境,接下來咱們來實現具體的核心代碼,爲了方便起見,個人代碼全寫在了inde.jsgit

2.代碼實現es6

首選咱們須要新建一個對象:github

/**
 * @author monkeywang
 * Date: 17/3/30
 */
class Matting {

}

而後咱們須要接受用戶上傳的圖片文件:web

class Matting {
/**
   * 構造函數
   * @param file
   */
  constructor(file) {
    this.file = file
  }
}

再接着把圖片文件轉成base64格式,因此咱們在類中建了一個createStream方法:算法

createStream() {
let reader = new FileReader()
let ext = this.file.name.substring(this.file.name.lastIndexOf(".") + 1).toLowerCase()
if (ext != 'png' && ext != 'jpg' && ext != 'jpeg') {
alert("圖片的格式必須爲png或者jpg或者jpeg格式!")
return
  }
reader.onload = (e) => {
let src = e.target.result
    let img = new Image()
img.src = src
    let w = img.width
    let h = img.height
    this.fitch(w, h, img)
  }
reader.readAsDataURL(this.file)
}

而後,開始咱們的摳圖邏輯代碼以前,先描述一下個人思想:顏色屬性實際上是由RGBA四個元素組成的,RGB,表明三基色,A表明透明度,當A的值爲0,則表示這個顏色是純透明的,因此咱們的主要邏輯就是把背景色設置爲透明就行了。

建立一個canvas畫布,而後把圖片放到這個畫布中,接着取這個圖片上下左右四個點的像素,接下來要扣除這個圖片的背景,那麼,就須要去對整個圖片的像素點顏色和背景色以前的區別,若是顏色相同,則把這個顏色的透明度設置成0

fitch(width, height, img) {
    let dataUrl
    let c = document.createElement("canvas")
    c.width = width
    c.height = height
    let ctx = c.getContext("2d")
    ctx.drawImage(img, 0, 0)
    /**
     * 取圖片四個腳邊的像素點rgba
     * @type {*}
     */
    let tl = Array.prototype.slice.call(ctx.getImageData(0, 0, 1, 1).data).join(',')
    let tr = Array.prototype.slice.call(ctx.getImageData(width - 1, 0, 1, 1).data).join(',')
    let br = Array.prototype.slice.call(ctx.getImageData(width - 1, height - 1, 1, 1).data).join(',')
    let bl = Array.prototype.slice.call(ctx.getImageData(0, height - 1, 1, 1).data).join(',')
    let imgdata = [tl, tr, bl, br] // 四個取色點
    let selfImageData = [] // 當前rgba
    imgdata.sort()
    // 目前只支持純色背景摳圖,簡單的判斷是否爲純色
    let deferNum = this.unique(imgdata).length
    if (deferNum <= 1) {
      {
        selfImageData = imgdata[1].split(",") // 設置要扣除的主題色
        let isPNG = true // 判斷是否已經扣過
        let imgDataUrl = ctx.getImageData(0, 0, width, height) //獲取像素點
        let data = imgDataUrl.data
        for (let i = 0; i < data.length; i += 4) {
          // 獲得 RGBA 通道的值
          let r = data[i]
          let g = data[i + 1]
          let b = data[i + 2]

          /**
           * function 判斷顏色是否是屬於背景色
           * @param numerical
           * @param index
           * @returns {boolean}
           */
          let isIn = (numerical, index) => {
            if (selfImageData[3] == 0) {
              isPNG = false
              return false
            }
            return numerical > parseInt(selfImageData[index]) && numerical < parseInt(selfImageData[index])// 去掉邊緣色
          }

          if ([r, g, b].every(isIn)) {
            data[i + 3] = 0 // 設置背景透明
          }
        }
        // 將修改後的代碼複製回畫布中
        ctx.putImageData(imgDataUrl, 0, 0)
        dataUrl = c.toDataURL("image/png")
        if (isPNG) {
          /**
           * 建立下載連接 進行圖片下載
           * @type {Element}
           */
          let a = document.createElement('a')
          a.href = dataUrl //下載圖片
          a.download = '未命名.png'
          a.click()
        }
        else {
          alert('背景已摳除!')
        }
      }
    }
    else {
      alert('只支持純色背景摳圖!')
    }

  }

而後咱們測試一下效果:建立index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
 <input type="file" id="file">
 <button onclick="matting()">開始摳圖</button>
</body>
<script src="./dist/matting.js"></script>
<script>
  function matting() {
    var file = document.getElementById('file').files[0];
    var mat = new Matting(file);
    mat.createStream();
  }
</script>
</html>

而後咱們選擇一個純色背景圖
圖片描述

摳圖後,咱們看看:

圖片描述

確實完成了摳圖。

固然實現算法還不是很完善,主要是爲了給你們展現canvas的無限可能,固然我也在逐步優化算法中,使得圖片摳圖更加完美,更加智能,也歡迎你們的star, pullrequest

相關文章
相關標籤/搜索