JavaScript實現(xiàn)為圖片添加水印的方法詳解
背景
在很多地方,我們都可以看到,上傳圖片的時候,圖片都會被加上默認的水印,水印的作用主要體現(xiàn)在以下幾個方面:
- 1.版權(quán)保護:在商業(yè)用途的照片中添加水印可以幫助保護作者的版權(quán),防止他人未經(jīng)授權(quán)使用照片。
- 2.品牌推廣:將商業(yè)品牌、商標或公司標志添加到照片中,可以幫助提高品牌知名度和曝光率。
- 3.防止盜版:添加水印可以防止盜版和未經(jīng)授權(quán)的使用,因為水印會明顯表明該照片的版權(quán)歸原作者所有。
- 4.標識來源:在社交媒體平臺上分享照片時,添加水印可以幫助其他用戶識別出照片的來源和作者。
- 5.識別真?zhèn)危簩τ谝恍┲匾恼掌蜃C件,如證書或合同等,加上水印可以幫助識別真?zhèn)?,防止偽造和篡改?/li>
因此,我們在個人網(wǎng)站進行圖片操作時,也可以給它加上自己獨特的水印,那么作為一名前端開發(fā),我們該如何實現(xiàn)給圖片加上水印呢?
實現(xiàn)
對圖片進行處理,我們的首選當然是canvas啦,使用canvas我們可以便捷地對圖片進行操作,我們需要操作的圖片主要分為以下兩種:
- 1、本地上傳的圖片
- 2、線上鏈接圖片
file 轉(zhuǎn) base64
對于本地上傳的圖片,我們需要先將其轉(zhuǎn)換成 base64 再進行后續(xù)處理:
我們可以通過FileReader來獲取圖片的 base64,F(xiàn)ileReader 是一種異步讀取文件機制。
FileReader 提供了如下方法:
- readAsArrayBuffer(file):按字節(jié)讀取文件內(nèi)容,結(jié)果用 ArrayBuffer 對象表示
- readAsBinaryString(file):按字節(jié)讀取文件內(nèi)容,結(jié)果為文件的二進制串
- 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 給圖片加水印
使用在線圖片鏈接的時候需要注意給圖片設置crossOrigin屬性(img.setAttribute("crossOrigin",'Anonymous')),不然會出現(xiàn)以下錯誤:
Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
大概意思是 canvas 無法執(zhí)行 toDataURL 方法:污染的畫布無法輸出。受限于 CORS 策略,會存在跨域問題,雖然可以使用圖像(比如 append 到頁面上)但是繪制到畫布上會污染畫布,一旦一個畫布被污染,就無法提取畫布的數(shù)據(jù),比如無法使用使用畫布 toBlob(),toDataURL(),或 getImageData()方法;當使用這些方法的時候 會拋出一個安全錯誤。
我們這里可以分為文字水印和圖片水印兩種:
文字水印
添加文字水印的大致步驟如下:
1、生成一個新的 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、繪制需要添加的水印文本并設置樣式。
我們可以使用fillText和strokeText這兩個方法來繪制文字,fillText繪制的是默認的普通實線文本,strokeText繪制的是描邊文本,這里我使用了strokeText來進行水印文本繪制。
完整代碼如下:
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:默認,文本在指定的位置開始。
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實現(xiàn)為圖片添加水印的方法詳解的詳細內(nèi)容,更多關于JavaScript圖片添加水印的資料請關注腳本之家其它相關文章!
相關文章
關于layui的下拉搜索框異步加載數(shù)據(jù)的解決方法
今天小編就為大家分享一篇關于layui的下拉搜索框異步加載數(shù)據(jù)的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09

