一,前端合成带水印的图片

一般来说,生成带水印的图片由后端生成,但不乏有时候需要前端来处理。当然,前端处理图片一般不建议,一方面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等转换成二进制文档流的方法,并将合成的图片上传到服务器,的更多相关文章

  1. 【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)

    web网站中常常有的功能:上传头像.上传封面等:一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传. 本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并 ...

  2. HTML5 Canvas前台压缩图片并上传到服务器

    1.前台代码: <input id="fileOne" type="file" /> <input id="btnOne" ...

  3. HTML5 本地裁剪图片并上传至服务器(转)

    很多情况下用户上传的图片都需要经过裁剪,比如头像啊什么的.但以前实现这类需求都很复杂,往往需要先把图片上传到服务器,然后返回给用户,让用户确定裁剪坐标,发送给服务器,服务器裁剪完再返回给用户,来回需要 ...

  4. HTML5裁剪图片并上传至服务器实现原理讲解

    HTML5裁剪图片并上传至服务器实现原理讲解   经常做项目需要本地上传图片裁剪并上传服务器,比如会议头像等功能,但以前实现这类需求都很复杂,往往需要先把图片上传到服务器,然后返回给用户,让用户确定裁 ...

  5. 使用ajax上传图片,支持图片即时浏览,支持js图片压缩后上传给服务器

    使用ajax上传图片,支持图片即时浏览,支持js图片压缩后上传给服务器 ajax上传主要使用了 var reader = new FileReader() 此方法 js图片压缩主要是利用canvas进 ...

  6. 前端借助dom-to-image把HTML转成图片并通过ajax上传到服务器

    之前接到了一个任务,把jsp中的table转成一个图片,保存在指定文件夹并显示在前端. 我的思路是:一.引用第三方js在前端把table转成图片 二.通过ajax把图片上传到服务器,保存在指定文件夹 ...

  7. MVC图片上传、浏览、删除 ASP.NET MVC之文件上传【一】(八) ASP.NET MVC 图片上传到服务器

    MVC图片上传.浏览.删除   1.存储配置信息 在web.config中,添加配置信息节点 <appSettings> <add key="UploadPath" ...

  8. 使用html5 FileReader获取图片,并异步上传到服务器(不使用iframe)

    使用html5 FileReader获取图片,并异步上传到服务器(不使用iframe)   原理: 1.使用FileReader 读取图片的base64编码 2.使用ajax,把图片的base64编码 ...

  9. 布局转换:文档流-&gt;绝对定位

    布局转换:文档流->绝对定位(详见妙味JS高级教程,运动课程第6课20分钟起)比如一个DIV中有三张图片并排,个数不确定的布局.需要鼠标移上去图片从中心放大,只使用float:left布局在放大 ...

随机推荐

  1. 安装Appium-windows

    安装Appium-windows JDK 安装JDK后设置 环境变量,把环境变量添加到你的系统PATH变量中. 变量: JAVA_HOME 值: C:\Program Files (x86)\Java ...

  2. 【非愚人】重要通知:04-01 贴吧继PHP资源之后又。。。

    贴吧继PHP资源之后又取消了JAVA,IOS等资源的贴,现在专注于Net,C++,Linux,平面设计.主要是为了让广大Net程序员具备全栈全平台牛人的潜力,故而取消那些干扰因素.Net的潜力和活力大 ...

  3. php的数据循环 之li的3个类判断

    这种判断必须得保证后台数据的键值为数字 ,反正要能跟数字计算的数据才行 ts2.php <?php$array = array('0'=>'a1','1'=>'b1','2'=> ...

  4. Description DisplayName Display的关系

    Description  DisplayName  Display的关系 ?

  5. python打印目录下的文件名

    打印当前目录所有文件名 import fnmatch, os def allFiles(root, patterns = '*', single_level = False, yield_folder ...

  6. 微信小程序入门——Mustache语法学习

    微信小程序中用到了大量Mustache语法,特发此文学习一下 1.简单的变量调换:{{name}} 1 var data = { "name": "Willy" ...

  7. 自定义tab吸顶效果一(原理)

    PS:问题:什么是吸顶,吸顶有什么作用,吸顶怎么使用? 在很多app商城中,介绍软件的时候就会使用吸顶效果, 吸顶有很多作用,一个最简单粗暴的作用就是,让用户知道此刻在浏览哪个模块,并可以选择另外的模 ...

  8. 学习vue容易忽视的细节

    1.对于自定义标签名(组件名称),Vue.js 不强制要求遵循 W3C 规则 (小写,并且包含一个短杠),尽管遵循这个规则比较好.HTML 特性是不区分大小写的.所以,当使用的不是字符串模板,came ...

  9. 代码: html 页面小效果 (集合,待补充)

    标签切换(下部内容区跟着切换): 2016-6-2 <script type="text/javascript" src="http://cdn.bootcss.c ...

  10. c#微信开发,使用JS-SDK自定义分享功能,分享朋友圈,分享给朋友等

    如果一个后端开发掌握了微信开发,甚至有微信开发上线项目,这在换工作的时候 还是有竞争力的. 微信开发的资料很多,但是用asp.net c#进行微信开发好像比较少,或者资料不够完整. 使用JS-SDK自 ...