一,前端合成帶水印的圖片
一般來說,生成帶水印的圖片由后端生成,但不乏有時候需要前端來處理。當然,前端處理圖片一般不建議,一方面js的處理圖片的方法不全,二是有些老版本的瀏覽器對canvas的支持度不夠。
下面我們就說說,利用canvas 生成帶水印的圖片。
1、我們要實現一下效果

2、創建一個canvas
var canvas = document.createElement('canvas'); var time = new Date(); var logoCanvas =time+' '+'http://www.cnblogs.com/zuoan-oopp'; // 水印 var context = canvas.getContext('2d');
3,繪制圖片
var imgUpload = new Image(); imgUpload.src =src; imgUpload.onload = function () { context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,imgWidth,imgHeight); }
4,按照1024*768的比例壓縮圖片
var width = imgUpload.width; var height= imgUpload.height; var scale,imgWidth,imgHeight; // 縮放比 ,按照1024*768縮放 if(width>height){ // 橫着拍 if(width>1024){ //寬大於1024 scale = 1024/width; imgWidth =1024; imgHeight = height*scale; // 算出按照寬1024,的等比壓縮后的高 if(imgHeight>768){ // 若高>768,算出等比768縮放的寬 scale = 768/imgHeight; imgHeight = 768; imgWidth = imgWidth*scale; } }else{ imgWidth = width; imgHeight = height } }else{ // 縱着拍的或者正方形 if(height>1024){ // 高大於1024 scale = 1024/height; imgHeight =1024; imgWidth = width*scale; // 算出按照寬1024,的等比壓縮后的高 if(imgWidth>768){ // 若高>768,算出等比768縮放的寬 scale = 768/imgWidth; imgWidth = 768; imgHeight = imgHeight*scale; } }else{ imgWidth = width; imgHeight = height } }
5,給canvas添加背景和水印
canvas.height = imgHeight+60; // 給canvas 賦值高度 context.save(); context.fillStyle = "green"; context.fillRect(0,0,imgWidth,imgHeight+60); // 繪制圖片的背景 context.restore(); context.save(); context.font="100px PingFangSC-Regular microsoft yahei"; context.fillStyle = "#000"; context.restore();
6,如果水印文字太長要換行,代碼如下:
for(let i=0;i<logoCanvas.length;i++){ // 字數換行 lineWidth+=context.measureText(logoCanvas[i]).width; if(lineWidth>canvas.width-20){ context.fillText(logoCanvas.substring(lastSubStrIndex,i),10,initHeight);//繪制截取部分 initHeight+=20;//20為字體的高度 height+=20; lineWidth=0; lastSubStrIndex=i; } if(i==logoCanvas.length-1){//繪制剩余部分 context.fillText(logoCanvas.substring(lastSubStrIndex,i+1),10,initHeight); } }
7,canvas轉換成base64位,以圖片的形式展示
var url=canvas.toDataURL("image/jpg", 0.8); // canvas轉換成base64位 var newImg = new Image(); newImg.src = url; newImg.onload = function() { document.getElementById('imgUpload').append(newImg); };
注意:toDataURL函數可能會出現跨域的問題,請在同一個服務器下操作
二,圖片上傳
1,圖片上傳到服務器要轉換成文檔流(二進制blob)的形式。所以無論上傳canvas,還是img,要先轉換成文檔流
2、canvas 轉換成文檔流,利用toBlob方法轉換
canvas.toBlob(function(blob) { //創建forme var form = new FormData(); form.append('file', blob); $.POST(url, { data:formData, processData: false, contentType: false, }).done(function(data) { console.log('回調函數') }).fail((data,textStatus)=>{ console.log('失敗函數') }) });
注意:次方法兼容性不太好,,低版本的chrome不支持,安卓4.4.2版本都不支持(只測了這一個版本),各瀏覽器的兼容性如下:

3,canvas 直接轉換成文檔流兼容性不太好,但是這個功能又必須做,怎么辦,,,那么我們就換種方式,,使用base64位上傳。
4,除了base64位上傳,還想使用blob二進制文檔流上傳,怎么辦。。。我們可以使用window對象提供的atob函數
5、WindowOrWorkerGlobalScope.atob()函數用來解碼一個已經被base-64編碼過的數據。你可以使用 window.btoa() 方法來編碼一個可能在傳輸過程中出現問題的數據,並且在接受數據之后,使用 window.atob() 方法來將數據解碼。
6,將base64位轉換成blob,這樣就可以避免低版本的chrome不支持了。
url = url.replace("data:image/png;base64,", "");
var blob = b64toBlob(src);
var formData = new FormData();
formData.append("file",blob);
$.POST(url, {
data:formData,
processData: false,
contentType: false,
}).done(function(data) {
console.log('回調函數')
}).fail((data,textStatus)=>{
console.log('失敗函數')
})
// 將base64位轉換成blob
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
ablob兼容性如下:

三,源代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>合成水印</title>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<style type="text/css">
*{margin:0;padding:0;}
.content{
display:block;
margin: 30px;
}
.content:after{
content: "";
display:block;
clear:both;
}
.content li{
float: left;
margin-left:30px;
list-style: none;
}
.img-wrap{
display:-webkit-box;
-webkit-box-align:center;
-webkit-box-pack: center;
width:500px;
height:400px;
}
.img-wrap img{
max-width: 100%;
max-height:100%;
}
.img-wrap canvas{
max-width: 100%;
max-height:100%;
}
</style>
</head>
<body>
<ul class="content">
<li>
<p>原圖</p>
<div class="img-wrap">
<img src="2.jpg"/>
</div>
</li>
<li>
<p>加水印的canvas</p>
<div id="imgContent" class="img-wrap"></div>
</li>
<li>
<p>加水印的img</p>
<div id="imgUpload" class="img-wrap"></div>
</li>
</ul>
<script type="text/javascript">
var src = $('img').attr('src');
var canvas = document.createElement('canvas');
var time = new Date();
var logoCanvas =time+' '+'http://www.cnblogs.com/zuoan-oopp'; // 水印
var context = canvas.getContext('2d');
// 這是上傳圖像
var imgUpload = new Image();
imgUpload.src =src;
imgUpload.onload = function () {
// 繪制
var width = imgUpload.width;
var height= imgUpload.height;
var scale,imgWidth,imgHeight; // 縮放比 ,按照1024*768縮放
if(width>height){ // 橫着拍
if(width>1024){ //寬大於1024
scale = 1024/width;
imgWidth =1024;
imgHeight = height*scale; // 算出按照寬1024,的等比壓縮后的高
if(imgHeight>768){ // 若高>768,算出等比768縮放的寬
scale = 768/imgHeight;
imgHeight = 768;
imgWidth = imgWidth*scale;
}
}else{
imgWidth = width;
imgHeight = height
}
}else{ // 縱着拍的或者正方形
if(height>1024){ // 高大於1024
scale = 1024/height;
imgHeight =1024;
imgWidth = width*scale; // 算出按照寬1024,的等比壓縮后的高
if(imgWidth>768){ // 若高>768,算出等比768縮放的寬
scale = 768/imgWidth;
imgWidth = 768;
imgHeight = imgHeight*scale;
}
}else{
imgWidth = width;
imgHeight = height
}
}
canvas.width = imgWidth; // geicanvas賦值寬度
canvas.height = imgHeight+60; // 給canvas 賦值高度
context.save();
context.fillStyle = "green";
context.fillRect(0,0,imgWidth,imgHeight+60); // 繪制圖片的背景
context.restore();
context.save();
context.font="100px PingFangSC-Regular microsoft yahei";
context.fillStyle = "#000";
context.restore();
context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,imgWidth,imgHeight);
var lineWidth = 0
var initHeight=imgHeight+30;//繪制字體距離canvas頂部初始的高度
var lastSubStrIndex= 0; //每次開始截取的字符串的索引
for(let i=0;i<logoCanvas.length;i++){ // 字數換行
lineWidth+=context.measureText(logoCanvas[i]).width;
if(lineWidth>canvas.width-20){
context.fillText(logoCanvas.substring(lastSubStrIndex,i),10,initHeight);//繪制截取部分
initHeight+=20;//20為字體的高度
height+=20;
lineWidth=0;
lastSubStrIndex=i;
}
if(i==logoCanvas.length-1){//繪制剩余部分
context.fillText(logoCanvas.substring(lastSubStrIndex,i+1),10,initHeight);
}
}
var url=canvas.toDataURL("image/jpg", 0.8); // canvas轉換成base64位
var newImg = new Image();
newImg.src = url;
newImg.onload = function() {
document.getElementById('imgUpload').append(newImg);
};
document.getElementById('imgContent').append(canvas); // 將canvas繪制的圖片存放在imgContent里
};
canvas.toBlob(function(blob) {
//創建forme
var form = new FormData();
form.append('file', blob);
$.POST(url, {
data:formData,
processData: false,
contentType: false,
}).done(function(data) {
console.log('回調函數')
}).fail((data,textStatus)=>{
console.log('失敗函數')
})
});
url = url.replace("data:image/png;base64,", "");
var blob = b64toBlob(src);
var formData = new FormData();
formData.append("file",blob);
$.POST(url, {
data:formData,
processData: false,
contentType: false,
}).done(function(data) {
console.log('回調函數')
}).fail((data,textStatus)=>{
console.log('失敗函數')
})
// 將base64位轉換成blob
function b64toBlob(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
</script>
</body>
</html>
四,參考文檔
1、https://developer.mozilla.org/zh-CN/docs/Web/API/WindowBase64/atob
2、https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob
