遇到了很多问题,也记录一下。
客户需求:网站上的图片容易被截图或者保存发到别的地方,所以需要页面铺满水印,能显示当前登录用户ID
主要是用js实现。
初始准备:
1)通过修改主题文件page.php
,或者自行制作别的模板page文件。js代码可以直接加入其中。
2)通过制作插件。需要php传参到js,代码如下(注释掉的部分是给前台传请求头的方法)。
function add_watermark() {
wp_enqueue_script( 'watermark-script',
plugins_url( 'watermark.js', __FILE__ ),
array('jquery')
);
global $current_user;
get_currentuserinfo();
$current_user_name = $current_user -> user_login;
wp_localize_script( 'watermark-script', 'current_user_name', array(
'current_user_name' => $current_user_name
));
}
add_action( 'wp_enqueue_scripts', 'add_watermark' );
/*
function add_http_headers() {
// 判断用户是否登陆,并且是在非后台(前台)页面
if(is_user_logged_in() && !is_admin()) {
header("Access-Control-Allow-Origin: *");
}
}
add_action( 'send_headers', 'add_http_headers' );
*/
- Round 1 -
使用canvas制作水印,设置为body背景
结果:图片在背景上层,无法被水印覆盖
- Round 2 -
添加div遮罩,显示在页面最顶层,将canvas水印图转换为div背景
小坑:css定位获取数值总是不准确。父元素relative
,本元素absolute
,top=0
即可
结果:全页均可显示水印,但是移动浏览器长按图片就可以查看到无水印原图
- Round 3 -
页面水印回归方法1,设置为body背景
另添加图片水印。加载图片后,新建canvas尺寸设置为图片元素大小,将图片画入canvas再添加水印,最后设置为图片路径
隐患:扒图插件依旧可以抓取到原图
结果:某些图片设置了srcset,随页面像素变化,产生大小变化。这时设置的src就失效了。
- Round 4 -
当图片存在srcset属性时,直接设置成canvas地址
结果:遇到部分图片加载完后被缩图
- Round 5 -
canvas的属性分为width
&height
和style.width
&style.height
,一个是画布尺寸,一个是元素尺寸。
获取图片的naturalWidth
&naturalHeight
,放大画布,可以保证画图时每个像素都不漏掉。img的width
&height
很多时候和图片实际尺寸是不一样的。
这同样也能解决某些被塞进不符合尺寸的img元素的图片,经canvas重新绘制后被拉伸的问题。
结果:目前主要问题:现在的实现方式势必会有加载中时的原图显示,当图片过大、页面图片过多时,等待所有图片onload的过程是完全不受水印保护的。
- Round 6 -
之前加水印的步骤,如果放在img.onload
,会发生重复现象,不知道原因,于是就改成了window.onload
。现在终于想通了原因。如果给img绑定onload事件,那我在onload事件中加水印改src,就导致图片重新load,就会重复运行onload事件。
解决方法就是,用jQuery(document).ready(function () { 代码段 });
来替代window.onload
,然后在img的onload事件中添加判断。我这里用了src地址判断,因为canvas转化后的地址总是data开头。
大幅提升了图片显示水印的速度。
结果:刷新后图片水印消失
- Round 7 -
原因是进入了缓存,再次刷新时直接从缓存获取,没有调用img.onload的过程。
尝试在php代码中加入header('Cache-Control: no-store, no-cache, must-revalidate, no-transform, no-siteapp');
禁止图片缓存,但是没有效果。
尝试在canvas造出的地址后添加随机数,直接图片裂了,行不通。
最后加了一个img.complete
的判断,如果为真,直接执行加水印方法。否则添加onload事件。
补丁:这里还是无论如何添加onload为佳,之后再判断是否已经complete,不然有些场合还是会漏掉部分图片。
- Round 8 -
遇到了跨域问题,无法执行toDataUrl
Tainted canvases may not be exported
查了很多资料,网上给到的解决方法:
1)添加跨域,需要图片添加属性("crossOrigin",'anonymous')
、请求头添加header('Access-Control-Allow-Origin:*');
停止报错了,但是图片全部变成黑色,连原本无需跨域的图片也变成了黑色。
2)使用Blob转码,无效,获取不到图片
3)使用Promise预加载,无效,原本方法就是在onload后执行的
最终解决方案:把地址给改了。这个站子的图片跨域是在url前多了i0.wp.com
,去掉也不影响图片读取,就直接去掉了。这里要注意的是代码顺序。
判断是否需要跨域-》换地址-》设置跨域(对,依旧需要设置跨域)-》重新绑定onload事件,不然亲测新地址的图片成