1. 程式人生 > 實用技巧 >Canvas基本圖片操作與處理

Canvas基本圖片操作與處理

前言

Canvas是H5中新增的技術,主要運用在圖片的處理和動畫的繪製上,隨著Canvas的使用場景越來越多,瞭解Canvas對平時開發大有裨益,這篇文章將介紹Canvas基本圖片操作與處理

圖片上傳與繪製

將圖片上傳並繪製到Canva中是最常見的Canvas的圖片處理,這個上傳與繪製的過程是怎麼實現的呢?下面舉個例子:

<canvas id="myCanvas"></canvas>
<input type="file" id="file">
let upload = document.getElementById('file')
upload.onchange = (event) => {
  let file = event.target.files[0]
  let fileReader = new FileReader()
  fileReader.onload = (e) => {
    let img = new Image()
    img.src = e.target.result
    img.onload = () => {
      let canvas = document.getElementById('myCanvas')
      canvas.width = img.width
      canvas.height = img.height
      let context = canvas.getContext('2d')
      context.drawImage(img, 0, 0)
    }
  }
  fileReader.readAsDataURL(file)
}

這個上傳與繪製的過程可以總結為兩步:

  • 通過FileReader物件將input上傳的file物件轉化為base64格式的圖片
  • 建立Image物件,將物件繪製在canvas上

這裡為什麼要將base64格式的地址複製給Image物件,然後再將Image物件繪製到Canvas上而不是直接繪製呢?
這是因為Canvas上繪製時並不支援url作為圖片源,Canvas只支援下面幾種圖片源:

  • Image()函式構造的或者任何<img>元素
  • <video>元素作為圖片源,可以抓取當前幀作為影象
  • 另一個<canvas>元素作為源
  • 高效能點陣圖作為圖片源

Canvas在繪圖時還有一個需要注意的點就是:Canvas在繪製不同域名下的圖片會出現跨域的錯誤,如圖:


被汙染的Canvas,其實就是因為圖片跨域的問題的,這時需要兩步走:

  • 圖片伺服器響應頭新增Access-Control-Allow-Origin為*或者指定域名
  • 設定Image的crossOrigin屬性img.setAttribute("crossOrigin",'Anonymous')

簡單示例程式碼:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
  let canvas = document.getElementById('myCanvas')
  canvas.width = img.width
  canvas.height = img.height
  let context = canvas.getContext('2d')
  context.drawImage(img, 0, 0)
  console.log(canvas.toDataURL('image/png', 1.0))
} 

更多跨域相關內容可以看這裡

圖片變換

圖片縮放

Canvas中圖片縮放的實際上是通過畫布的縮放來達到的,因此預設的縮放中心是在畫布原點(0, 0),但是一般情況下我們做縮放時都希望圖片中心是縮放中心,這裡有兩種辦法能達到圖片中心作為縮放中心的縮放效果,接下來分別來看這兩種辦法的示例:
第一種:

let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.translate(img.width / 2, img.height / 2)
context.scale(0.5, 0.5)
context.translate(-img.width / 2, -img.height / 2)
context.drawImage(img, 0, 0, img.width, img.height)

第一種方法就是畫布平移,先將畫布原點移到影象中心,然後再做畫布縮放,再將畫布平移還原,最後繪製圖片,此時繪製的圖片就是以圖片中心做的縮放

第二種:

let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
let paintWidth = img.width / 2
let paintHight = img.height / 2
let originX = 0 // 原圖片X座標
let originY = 0 // 原圖片Y座標
let paintX = originX + (img.width - paintWidth) / 2 // 縮放後的圖片X座標
let paintY = originY + (img.height - paintHight) / 2 // 縮放後的圖片Y座標
context.drawImage(img, paintX, paintY, paintWidth, paintHight)

第二種就是最直接的計算當圖片以左上角作為縮放中心,縮放後的圖片位置產生的位置偏移,將位置偏移加上在進行圖片繪製

圖片旋轉

Canvas的圖片旋轉和圖片縮放一樣,預設的旋轉中心也是畫布的原點(0, 0),此時也需要平移畫布來實現圖片的中心旋轉,舉個例子

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
let canvas = document.getElementById('myCanvas')
  canvas.width = img.width
  canvas.height = img.height
  let context = canvas.getContext('2d')
  context.translate(img.width / 2, img.height / 2)
  context.rotate(30 * Math.PI / 180)
  context.translate(-img.width / 2, -img.height / 2)
  context.drawImage(img, 0, 0, img.width, img.height)
}

映象變換

映象變換可以以圖片垂直中線為對稱軸,左右映象的變換叫水平映象,或者水平中線為對稱軸,上下映象的變換叫垂直映象,一般水平映象用的比較多,這裡就來看一個水平映象的例子:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
  let canvas = document.getElementById('myCanvas')
  canvas.width = img.width
  canvas.height = img.height
  let context = canvas.getContext('2d')
  context.translate(img.width / 2, img.height / 2)
  context.scale(-1 , 1)
  context.translate(-img.width / 2, -img.height / 2)
  context.drawImage(img, 0, 0, img.width, img.height)
}

原圖:

水平映象:

映象操作的原理其實很簡單:就是將scale設定為負值,當x軸的縮放為負值時,就是水平映象,當y軸的縮放為負值時就是垂直映象

對稱軸翻轉

對稱軸翻轉指的是圖片沿著左上角至右下角的對角線翻轉,來看用程式碼Canvas是怎麼實現的:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
  let canvas = document.getElementById('myCanvas')
  canvas.width = img.width
  canvas.height = img.height
  let context = canvas.getContext('2d')
  context.translate(img.width / 2, img.height / 2)
  context.scale(-1 , 1)
  context.rotate(90 * Math.PI / 180)
  context.translate(-img.width / 2, -img.height / 2)
  context.drawImage(img, 0, 0, img.width, img.height)
}

翻轉圖:

實現原理:先做水平映象,然後順時針旋轉90度,由於先做的水平映象,座標軸會被水平翻轉,順時針旋轉90度實際是逆時針旋轉90度

廣州vi設計公司 http://www.maiqicn.com 我的007辦公資源網 https://www.wode007.com

圖片灰度

圖片的灰度效果是Canvas非常常見的一個圖片處理效果,先來看實現灰度效果的程式碼:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
  let canvas = document.getElementById('myCanvas')
  canvas.width = img.width
  canvas.height = img.height
  let context = canvas.getContext('2d')
  context.drawImage(img, 0, 0, img.width, img.height)
  let imageData = context.getImageData(0, 0, img.width, img.height)
  let data = imageData.data
  for (let i = 0; i < data.length; i += 4) {
    let average = (data[i] + data[i + 1] + data[i + 2]) / 3
    data[i] = average
    data[i + 1] = average
    data[i + 2] = average
  }
  context.putImageData(imageData, 0, 0)
}

灰度效果圖:


實現思路:

  • 先將圖片繪製在canvas上
  • 利用getImageData方法獲取每個畫素點的rgb值
  • 求出每個畫素點的rgb平均值,然後重新賦值
  • 利用putImageData將重新計算的imageData物件繪製到圖片上

這裡可能會有人對getImageData和putImageData這兩個api不是很熟悉,想要了解這個兩個api的可以點getImageDataputImageData