最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript實(shí)現(xiàn)為圖片添加水印的方法詳解

 更新時(shí)間:2023年05月24日 09:24:02   作者:JYeontu  
在很多地方,我們都可以看到,上傳圖片的時(shí)候,圖片都會被加上默認(rèn)的水印,因此,我們在個(gè)人網(wǎng)站進(jìn)行圖片操作時(shí),也可以給它加上自己獨(dú)特的水印,本文就為大家整理了JS添加圖片合文字水印的方法,需要的可以參考一下

背景

在很多地方,我們都可以看到,上傳圖片的時(shí)候,圖片都會被加上默認(rèn)的水印,水印的作用主要體現(xiàn)在以下幾個(gè)方面:

  • 1.版權(quán)保護(hù):在商業(yè)用途的照片中添加水印可以幫助保護(hù)作者的版權(quán),防止他人未經(jīng)授權(quán)使用照片。
  • 2.品牌推廣:將商業(yè)品牌、商標(biāo)或公司標(biāo)志添加到照片中,可以幫助提高品牌知名度和曝光率。
  • 3.防止盜版:添加水印可以防止盜版和未經(jīng)授權(quán)的使用,因?yàn)樗黠@表明該照片的版權(quán)歸原作者所有。
  • 4.標(biāo)識來源:在社交媒體平臺上分享照片時(shí),添加水印可以幫助其他用戶識別出照片的來源和作者。
  • 5.識別真?zhèn)危簩τ谝恍┲匾恼掌蜃C件,如證書或合同等,加上水印可以幫助識別真?zhèn)?,防止偽造和篡改?/li>

因此,我們在個(gè)人網(wǎng)站進(jìn)行圖片操作時(shí),也可以給它加上自己獨(dú)特的水印,那么作為一名前端開發(fā),我們該如何實(shí)現(xiàn)給圖片加上水印呢?

實(shí)現(xiàn)

對圖片進(jìn)行處理,我們的首選當(dāng)然是canvas啦,使用canvas我們可以便捷地對圖片進(jìn)行操作,我們需要操作的圖片主要分為以下兩種:

  • 1、本地上傳的圖片
  • 2、線上鏈接圖片

file 轉(zhuǎn) base64

對于本地上傳的圖片,我們需要先將其轉(zhuǎn)換成 base64 再進(jìn)行后續(xù)處理:

我們可以通過FileReader來獲取圖片的 base64,F(xiàn)ileReader 是一種異步讀取文件機(jī)制。

FileReader 提供了如下方法:

  • readAsArrayBuffer(file):按字節(jié)讀取文件內(nèi)容,結(jié)果用 ArrayBuffer 對象表示
  • readAsBinaryString(file):按字節(jié)讀取文件內(nèi)容,結(jié)果為文件的二進(jìn)制串
  • readAsDataURL(file):讀取文件內(nèi)容,結(jié)果用 data:url 的字符串形式表示
  • readAsText(file,encoding):按字符讀取文件內(nèi)容,結(jié)果用字符串形式表示
  • abort():終止文件讀取操作

readAsDataURL 方法會讀取指定的 Blob 或 File 對象。并生成 data URl(base64 編碼)。這里我們可以使用readAsDataURL來獲取上傳圖片的 base64 編碼:

function fileToBase64Async(file) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
      resolve(e.target.result);
    };
  });
}

使用 canvas 給圖片加水印

使用在線圖片鏈接的時(shí)候需要注意給圖片設(shè)置crossOrigin屬性(img.setAttribute("crossOrigin",'Anonymous')),不然會出現(xiàn)以下錯(cuò)誤:

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

大概意思是 canvas 無法執(zhí)行 toDataURL 方法:污染的畫布無法輸出。受限于 CORS 策略,會存在跨域問題,雖然可以使用圖像(比如 append 到頁面上)但是繪制到畫布上會污染畫布,一旦一個(gè)畫布被污染,就無法提取畫布的數(shù)據(jù),比如無法使用使用畫布 toBlob(),toDataURL(),或 getImageData()方法;當(dāng)使用這些方法的時(shí)候 會拋出一個(gè)安全錯(cuò)誤。

我們這里可以分為文字水印和圖片水印兩種:

文字水印

添加文字水印的大致步驟如下:

1、生成一個(gè)新的 canvas 畫布;

const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;

2、將現(xiàn)有需要添加水印的圖片繪制到畫布上;

const ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

3、繪制需要添加的水印文本并設(shè)置樣式。

我們可以使用fillText和strokeText這兩個(gè)方法來繪制文字,fillText繪制的是默認(rèn)的普通實(shí)線文本,strokeText繪制的是描邊文本,這里我使用了strokeText來進(jìn)行水印文本繪制。

完整代碼如下:

const remFontSize = canvas.width / 35;
ctx.font = "bolder " + remFontSize + "px Verdana";
ctx.textAlign = "center";
ctx.strokeStyle = "#fff";
const name = "@JYeontu";
const spaceH = remFontSize * 0.3;
ctx.strokeText(name, canvas.width / 2, canvas.height - remFontSize - spaceH);
function fillTextToImg(base64) {
  const img = new Image();
  img.src = base64;
  img.setAttribute("crossOrigin", "Anonymous");
  return new Promise((resolve, reject) => {
    img.onload = () => {
      const canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;
      const ctx = canvas.getContext("2d");
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      const remFontSize = canvas.width / 35;
      ctx.font = "bolder " + remFontSize + "px Verdana";
      ctx.textAlign = "center";
      /**
        ctx.textAlign = "center|end|left|right|start";
        start:默認(rèn),文本在指定的位置開始。
        end:文本在指定的位置結(jié)束。
        center:文本的中心在指定的位置。
        left:文本左對齊。
        right:文本右對齊。
        **/
      ctx.strokeStyle = "#fff";
      const name = "@JYeontu";
      const spaceH = remFontSize * 0.3;
      ctx.strokeText(
        name,
        canvas.width / 2,
        canvas.height - remFontSize - spaceH
      );
      resolve(canvas.toDataURL("image/jpeg"));
    };
  });
}

效果如下圖,左邊為原圖,右邊為加了文字水印的圖片:

圖片水印

//圖片轉(zhuǎn)為base64
async function getImgBase64(base64, width = 50) {
  const img = new Image();
  img.src = base64;
  img.setAttribute("crossOrigin", "Anonymous");
  return new Promise((resolve, reject) => {
    img.onload = () => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      canvas.width = width;
      canvas.height = (img.height * width) / img.width;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      resolve(canvas.toDataURL("image/jpeg"));
    };
  });
}
function fillImgToImg(base64, waterMark = imgLink) {
  waterMark =
    "https://img2.baidu.com/it/u=2243573419,589412055&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1684861200&t=7bf0a17ca21ae8ec8aa77b0f98cb4c7e";
  const img = new Image();
  img.src = base64;
  img.setAttribute("crossOrigin", "Anonymous");
  return new Promise((resolve, reject) => {
    img.onload = async () => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      const waterMarkSrc = await getImgBase64(waterMark, 100);
      const waterMarkImg = new Image();
      waterMarkImg.src = waterMarkSrc;
      waterMarkImg.setAttribute("crossOrigin", "Anonymous");
      waterMarkImg.onload = () => {
        ctx.drawImage(
          waterMarkImg,
          canvas.width / 2 - waterMarkImg.width / 2,
          canvas.height - waterMarkImg.height - 10,
          waterMarkImg.width,
          waterMarkImg.height
        );
        resolve(canvas.toDataURL("image/jpeg"));
      };
    };
  });
}

效果如下圖,左邊為原圖,右邊為加了圖片水印的圖片: 

完整代碼

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      img {
        width: 500px;
      }
    </style>
  </head>
  <body>
    <input type="file" id="fileUplodBox" />
    <img alt="原圖" id="originPic" />
    <img alt="水印圖" id="waterMark" />
  </body>
  <script>
    const imgLink =
      "https://img2.baidu.com/it/u=2048195462,703560066&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1684861200&t=a0c977f68632303e7dac2196e8ad2866";
    document.getElementById("originPic").setAttribute("src", imgLink);
    const fileUplodBox = document.getElementById("fileUplodBox");
    fileUplodBox.addEventListener("change", (e) => {
      const file = e.target.files[0];
      dealFile(file);
    });
    test();
    async function test() {
      const img = await fillImgToImg(imgLink);
      document.getElementById("waterMark").setAttribute("src", img);
    }
    async function dealFile(file) {
      const base64 = await fileToBase64Async(file);
      document.getElementById("originPic").setAttribute("src", base64);
      const img = await fillTextToImg(base64);
      document.getElementById("waterMark").setAttribute("src", img);
    }
    function fileToBase64Async(file) {
      return new Promise((resolve, reject) => {
        let reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = (e) => {
          resolve(e.target.result);
        };
      });
    }
    // 給圖片加文字水印
    function fillTextToImg(base64) {
      const img = new Image();
      img.src = base64;
      img.setAttribute("crossOrigin", "Anonymous");
      return new Promise((resolve, reject) => {
        img.onload = () => {
          const canvas = document.createElement("canvas");
          const ctx = canvas.getContext("2d");
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
          const remFontSize = canvas.width / 35;
          ctx.font = "bolder " + remFontSize + "px Verdana";
          ctx.textAlign = "center";
          ctx.strokeStyle = "#fff";
          const uploadTime = new Date();
          const name = "@JYeontu";
          const spaceH = remFontSize * 0.3;
          ctx.strokeText(
            name,
            canvas.width / 2,
            canvas.height - remFontSize - spaceH
          );
          resolve(canvas.toDataURL("image/jpeg"));
        };
      });
    }
    async function getImgBase64(base64, width = 50) {
      const img = new Image();
      img.src = base64;
      img.setAttribute("crossOrigin", "Anonymous");
      return new Promise((resolve, reject) => {
        img.onload = () => {
          const canvas = document.createElement("canvas");
          const ctx = canvas.getContext("2d");
          canvas.width = width;
          canvas.height = (img.height * width) / img.width;
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
          resolve(canvas.toDataURL("image/jpeg"));
        };
      });
    }
    // 給圖片加圖片水印
    function fillImgToImg(base64, waterMark = imgLink) {
      waterMark =
        "https://img2.baidu.com/it/u=2243573419,589412055&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1684861200&t=7bf0a17ca21ae8ec8aa77b0f98cb4c7e";
      const img = new Image();
      img.src = base64;
      img.setAttribute("crossOrigin", "Anonymous");
      return new Promise((resolve, reject) => {
        img.onload = async () => {
          const canvas = document.createElement("canvas");
          const ctx = canvas.getContext("2d");
          canvas.width = img.width;
          canvas.height = img.height;
          ctx.fillRect(0, 0, canvas.width, canvas.height);
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
          const waterMarkSrc = await getImgBase64(waterMark, 100);
          const waterMarkImg = new Image();
          waterMarkImg.src = waterMarkSrc;
          waterMarkImg.setAttribute("crossOrigin", "Anonymous");
          waterMarkImg.onload = () => {
            ctx.drawImage(
              waterMarkImg,
              canvas.width / 2 - waterMarkImg.width / 2,
              canvas.height - waterMarkImg.height - 10,
              waterMarkImg.width,
              waterMarkImg.height
            );
            resolve(canvas.toDataURL("image/jpeg"));
          };
        };
      });
    }
  </script>
</html>

以上就是JavaScript實(shí)現(xiàn)為圖片添加水印的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript圖片添加水印的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JavaScript?編寫枚舉的最有效方法分享

    JavaScript?編寫枚舉的最有效方法分享

    這篇文章主要介紹了JavaScript?編寫枚舉的最有效方法分享,JavaScript語言本身不支持枚舉。如果我們想模擬枚舉,我們可以使用一個(gè)對象。更多相關(guān)內(nèi)容感興趣的小伙伴可以參考一下
    2022-06-06
  • 關(guān)于layui的下拉搜索框異步加載數(shù)據(jù)的解決方法

    關(guān)于layui的下拉搜索框異步加載數(shù)據(jù)的解決方法

    今天小編就為大家分享一篇關(guān)于layui的下拉搜索框異步加載數(shù)據(jù)的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • Javascript排序算法之計(jì)數(shù)排序的實(shí)例

    Javascript排序算法之計(jì)數(shù)排序的實(shí)例

    計(jì)數(shù)排序是一種高效的線性排序,它通過計(jì)算一個(gè)集合中元素楚翔的次數(shù)來確定集合如何排列,計(jì)數(shù)排序不需要進(jìn)行數(shù)據(jù)的比較,所有他的運(yùn)行效率前面介紹的都高
    2014-04-04
  • JS實(shí)現(xiàn)右側(cè)懸浮框效果

    JS實(shí)現(xiàn)右側(cè)懸浮框效果

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)右側(cè)懸浮框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 淺析Bootstrap組件之面板組件

    淺析Bootstrap組件之面板組件

    這篇文章主要介紹了淺析Bootstrap組件之面板組件 的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • 用js判斷是否為360瀏覽器的實(shí)現(xiàn)代碼

    用js判斷是否為360瀏覽器的實(shí)現(xiàn)代碼

    這篇文章主要介紹了用js判斷是否為360瀏覽器的實(shí)現(xiàn)代碼,有時(shí)候我們需要判斷是否為360瀏覽器,包括百度聯(lián)盟后臺就有這樣的提示需要的朋友可以參考下
    2015-01-01
  • JS實(shí)現(xiàn)點(diǎn)擊圖片放大縮小及拖拽功能

    JS實(shí)現(xiàn)點(diǎn)擊圖片放大縮小及拖拽功能

    本文使用 vue創(chuàng)建一個(gè)可拖拽和縮放的圖片查看器組件,該組件不僅可以展示圖片,還支持用戶通過鼠標(biāo)拖動和縮放來查看細(xì)節(jié),本文將介紹如何封裝一個(gè)簡單的圖片拖拽與縮放組件,感興趣的小伙伴跟著小編一起來看看吧
    2025-02-02
  • javascript靜態(tài)的url如何傳遞

    javascript靜態(tài)的url如何傳遞

    javascript靜態(tài)的url如何傳遞...
    2007-05-05
  • 小程序分享模塊超級詳解(推薦)

    小程序分享模塊超級詳解(推薦)

    這篇文章主要介紹了小程序分享模塊超級詳解(推薦),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 微信小程序點(diǎn)擊頂部導(dǎo)航欄切換樣式代碼實(shí)例

    微信小程序點(diǎn)擊頂部導(dǎo)航欄切換樣式代碼實(shí)例

    這篇文章主要介紹了微信小程序點(diǎn)擊頂部導(dǎo)航欄切換樣式代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評論

丰镇市| 潮州市| 通化市| 东安县| 卓尼县| 砀山县| 成武县| 永靖县| 米易县| 自贡市| 菏泽市| 抚远县| 静海县| 辽阳县| 哈巴河县| 孝义市| 玛沁县| 砚山县| 称多县| 小金县| 沾化县| 通州区| 南丹县| 内黄县| 浑源县| 宾阳县| 宜春市| 阿坝| 大理市| 普格县| 阜新市| 江永县| 沧州市| 株洲县| 临江市| 陆川县| 曲麻莱县| 泰和县| 巫山县| 城步| 贵阳市|