一,前端合成带水印的图片
一般来说,生成带水印的图片由后端生成,但不乏有时候需要前端来处理。当然,前端处理图片一般不建议,一方面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
使用canvas给图片添加水印, canvas转换base64,,canvas,图片,base64等转换成二进制文档流的方法,并将合成的图片上传到服务器,
原文地址:http://www.cnblogs.com/zuoan-oopp/p/8006524.html