前端線上圖片生成馬賽克

2023-01-03 18:27:45 來源:51CTO博客

前言

說起圖片的馬賽克,可能一般都是由后端實現然后傳遞圖片到前端,但是前端也是可以通過canvas來為圖片加上馬賽克的,下面就通過碼上掘金來進行一個簡單的實現。


(資料圖)

實現

markup

style

body {    margin: 0;    padding: 0;    width: 100vw;    height: 100vh;    display: flex;    align-items: center;    justify-content: center;}#image {    width: 200px;    height: auto;    margin-right: 30px;}

script

let canvas = document.createElement("canvas");let ctx = canvas.getContext("2d");let img = document.getElementById("image");let img1 = new Image();getBase64(document.getElementById("image").src).then((res) => {  img1.src = res;});img1.onload = function () {  let w = img1.width;  let h = img1.height;  canvas.width = w;  canvas.height = h;  ctx.drawImage(img1, 0, 0);  let pixeArr = ctx.getImageData(0, 0, w, h).data;  let sampleSize = 40;  for (let i = 0; i < h; i += sampleSize) {    for (let j = 0; j < h; j += sampleSize) {      let p = (j + i * w) * 4;      ctx.fillStyle =        "rgba(" +        pixeArr[p] +        "," +        pixeArr[p + 1] +        "," +        pixeArr[p + 2] +        "," +        pixeArr[p + 3] +        ")";      ctx.fillRect(j, i, sampleSize, sampleSize);    }  }  //   img.src = canvas.toDataURL("image/jpeg");  let img2 = new Image();  img2.src = canvas.toDataURL("image/jpeg");  img2.width = img.width;  img2.height = img.height;  document.body.appendChild(img2);};function getBase64(imgUrl) {  return new Promise(function (resolve, reject) {    window.URL = window.URL || window.webkitURL;    let xhr = new XMLHttpRequest();    xhr.open("get", imgUrl, true);    xhr.responseType = "blob";    xhr.onload = function () {      if (this.status == 200) {        let blob = this.response;        let oFileReader = new FileReader();        oFileReader.onloadend = function (e) {          let base64 = e.target.result;          resolve(base64);        };        oFileReader.readAsDataURL(blob);      }    };    xhr.send();  });}

代碼運行效果

實現過程

思路

最開始需要實現馬賽克功能是需要通過canvas提供的一個獲取到圖片每一個像素的方法,我們都知道,圖片本質上只是由像素組成的,越清晰的圖片,就有著越高的像素,而像素的本質,就只是一個個擁有顏色的小方塊而已,只要把一張圖片放大多倍,就能夠清楚的發現。

canvas實現

通過 canvas 的 getImageData 這個方法,我們就能夠拿到圖像上所有像素組成的數組,并且需要生成馬賽克,意味著我們需要把一個范圍內的色塊的顏色都改成一樣的,也就是通過canvas來重繪圖片,

let pixeArr = ctx.getImageData(0, 0, w, h).data;let sampleSize = 40;for (let i = 0; i < h; i += sampleSize) {    for (let j = 0; j < h; j += sampleSize) {      let p = (j + i * w) * 4;      ctx.fillStyle =        "rgba(" +        pixeArr[p] +        "," +        pixeArr[p + 1] +        "," +        pixeArr[p + 2] +        "," +        pixeArr[p + 3] +        ")";      ctx.fillRect(j, i, sampleSize, sampleSize);    }}復制代碼

通過雙重循環來循環圖片所有的色塊,其中的跨度就是我們設定好的色塊大小,色塊調整的越大,馬賽克后圖片更模糊,越小,圖片的模糊度就會降低。在通過 fillStyle 選取顏色,以及 fillRect 重繪 canvas 實現了將整個 canvas 的色塊都進行改變,最后在導出重繪后的圖片,無論是改變原來的圖片地址,或者是新加一張圖片作為對比,就都是可行的了。

canvas 跨域問題

在使用 getImageData 獲取圖片的時候,如果使用的是線上圖片,瀏覽器會爆出跨域的錯誤:

而上文中出現問題的圖片是存放在本地的或者線上的,本地的圖片默認是沒有域名的,線上的圖片并且是跨域的,所以瀏覽器都認為你是跨域,導致報錯。

那么對于本地圖片,我們只需要將圖片放到和html對應的文件夾下,子文件夾也是不可以的,就能夠解決,對于線上的圖片,我們可以采用先把它下載下來,再用方法來獲取數據的這種方式來進行。

function getBase64(imgUrl) {  return new Promise(function (resolve, reject) {    window.URL = window.URL || window.webkitURL;    let xhr = new XMLHttpRequest();    xhr.open("get", imgUrl, true);    xhr.responseType = "blob";    xhr.onload = function () {      if (this.status == 200) {        let blob = this.response;        let oFileReader = new FileReader();        oFileReader.onloadend = function (e) {          let base64 = e.target.result;          resolve(base64);        };        oFileReader.readAsDataURL(blob);      }    };    xhr.send();  });}復制代碼

下載圖片就不說了,通過瀏覽器提供的 API 或者其他封裝好的請求工具都是可以的,在請求成功之后,我們將圖片轉化為 base64 并且返回,這樣就能夠獲取線上圖片的數據了。

總結

本文提供了一種前端生成馬賽克圖片的方案,并且對于線上的圖片,也能夠通過先異步下載圖片在進行轉換的策略,實現了圖片添加馬賽克的功能。

完整附件:??點此下載??

標簽: 使用的是 或者其他

上一篇:世界簡訊:【網絡】udp_socket編程
下一篇:熱點聚焦:LNMP架構環境之Mariadb數據庫環境 nginx+php+mysql