前言

  前段时间在写houdini学习之路的博文,这个过程中引用了大量的图片,我担心图片被人盗取,所以想要给所有的博客图片添加水印,这篇博文就应运而生了。

  这次研究还延伸除了博客瘦身的方法,详情可以了解另一篇博文——博客瘦身方法。

  最开始我是直接搜索js给图片添加水印的方法,有通过给图片添加div生成水印的,但是这种方案只是在网页上实现水印,用户下载图片水印就消失了,这样的方案指标不治本,所以我需要将水印合成到图片当中,获取合成后的图片地址。这之中有利用canvas和直接生成的链接方案。当然网上也有封装好的插件。

  最开始我并不打算使用插件来完成的,但是canvas的方案实在让我头疼,不得已我只好去寻求插件来解决。

  canvas的最大问题在于我无法将img标签替换为canvas,我在这地方卡壳了,所以就放弃了canvas方案。

利用插件生成图片水印

pa7/watermark.js

  最开始在网上找到了watermark.js,看名字就知道这个东西铁定和水印有关的,但是这个脚本是很久没有更新了。官方给出的使用方法看得我不明不白,而且有些代码错误,而且实现不了效果。

相关链接

brianium/watermarkjs

  后面我就去github上面找watermark,找个星星多的,就找到了另一个watermark.js脚本,然而这个也不好弄,官方的doc介绍不明不白的(bootstrap的脚本路径还是错误的),用得我很是不爽,还是实现不了效果。

相关链接

Img2Blob.js

  这个工具也是在网上找的,感觉实现还算友好,单独的图片好像是可以的,但是博客上还是不行。

相关链接

lelinhtinh/watermark

  终于在使用这个工具的时候,我发现博客之所以不行是因为要等待图片加载,需要加入setTimeout进行操作。后面这个插件就实现了效果。

相关链接

1
<script src="/js/jquery.watermark.min.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
setTimeout(function(){
$('.fancy-ctn').each(function(){//最开始我是只遍历img的,但是这会导致头像之类的img也被误操作,所以最后是遍历img的父对象
$(this).children('img').watermark({
text: 'FXTD-odyssey',
textSize:50,
textWidth: 300,
// gravity: 'w',
opacity: 0,
margin: 10,
done:function(imgURL){
this.src=imgURL;//修改图片的链接地址
$(this).parent().attr('href',imgURL);//fancybox打开的时候链接的就是自带水印的图了
}
});

})
},500)

总结

  这是通过生成合成了水印的图片链接,将图片的src地址替换掉,从而实现效果,这样就不用去用canvas去替换img标签那么麻烦了。

  效果虽然实现了,但是有个致命的问题。

  如果博文的图片少还不是很明显,我Houdini系列中,有些博文一篇就有30多张图,打开之后要卡顿很久很久才能将水印生成出来,为此回想起canvas的快速实现效果,于是乎我重新去研究canvas的实现方案。

canvas生成图片水印

  因为最开始我一直在寻找img替换为canvas的方法,但是并没有好的实现方案,网上的那些转换,在博客当中都不起作用。

  所以经过水印插件的研究,我认为替换图片路径会是更好的方案,问题是图片地址要怎么生成出来。

  经过不懈的努力,我找到了这篇博文

  但是他实现的效果和我的大相径庭,我将它的代码复制了下来进行了魔改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

setTimeout(function(){
$('.fancy-ctn').each(function(){
var scope = this;
Img_waterMark($(this).children().attr('src'),function(url){
$(scope).children('img').attr('src',url);//这里也被坑了好久才发现为什么this不起作用
$(scope).attr('href',url);
});
})
},500)

function Img_waterMark(imgPath,setImg){
var src = imgPath;
var canvas = document.createElement('canvas');
var logoText ='FXTD-odyssey'; // 水印
var context = canvas.getContext('2d');

var imgUpload = new Image();
imgUpload.src =src;
imgUpload.onload = function () {
var width = imgUpload.width;
var height= imgUpload.height;

canvas.width = width; // 给canvas赋值宽度
canvas.height = height; // 给canvas 赋值高度

context.font="50px 微软雅黑";
context.fillStyle = "#fff";

context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,width,height);

context.fillText(logoText,10,50);

let url=canvas.toDataURL("image/jpg"); // canvas转换成base64位

setImg(url);
}
}

图片加载完成才添加水印

  使用setTimeout其实并不好,延迟的时间很难定夺,图片太多的话500毫秒可能也是不够的。

  为了解决这个问题,我找了这篇博文

  这样就实现了图片都加载完才去添加水印。

  最后的代码汇总

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*canvas 方案*/
var t_img; // 定时器
var isLoad = true; // 控制变量

// 判断图片加载状况,加载完成后回调
isImgLoad(function(){
// 加载完成
$('.fancy-ctn').each(function(){
var scope = this;
console.log("test");
Img_waterMark($(this).children().attr('src'),function(url){
$(scope).children('img').attr('src',url);
$(scope).attr('href',url);
});
})
});

/*https://www.cnblogs.com/ymy124/p/4538695.html*/
// 判断图片加载的函数
function isImgLoad(callback){
// 注意我的图片类名都是cover,因为我只需要处理cover。其它图片可以不管。
// 查找所有封面图,迭代处理
$('img').each(function(){
// 找到为0就将isLoad设为false,并退出each
if(this.height === 0){
isLoad = false;
return false;
}
});
// 为true,没有发现为0的。加载完毕
if(isLoad){
clearTimeout(t_img); // 清除定时器
// 回调函数
callback();
// 为false,因为找到了没有加载完成的图,将调用定时器递归
}else{
isLoad = true;
t_img = setTimeout(function(){
isImgLoad(callback); // 递归扫描
},500); // 我这里设置的是500毫秒就扫描一次,可以自己调整
}
}

/*https://www.cnblogs.com/zuoan-oopp/p/8006524.html*/
function Img_waterMark(imgPath,setImg){
var src = imgPath;
var canvas = document.createElement('canvas');
var logoText ='FXTD-odyssey'; // 水印
var context = canvas.getContext('2d');

var imgUpload = new Image();
imgUpload.src =src;
imgUpload.onload = function () {
var width = imgUpload.width;
var height= imgUpload.height;

canvas.width = width; // 给canvas赋值宽度
canvas.height = height; // 给canvas 赋值高度

context.font="50px 微软雅黑";
context.fillStyle = "#fff";

context.drawImage(imgUpload, 0, 0,imgUpload.width,imgUpload.height,0,0,width,height);

context.fillText(logoText,10,50);

let url=canvas.toDataURL("image/jpg"); // canvas转换成base64位

setImg(url);
}
}

总结

  其实canvas的方案和插件的实现效率相差无几,而且在加载的过程中原图会暴露,不仅起不到保护作用,也让网页加载巨慢无比,因此,我最后不得不放弃这些js的实现方案,采用图床来添加水印。