0%

JS 微信小程序添加水印

问题

微信小程序加水印,需要在图片上添加文字,文字的位置需要自定义。

实现

获取和设置 canvas 上下文

1
2
3
4
5
6
7
8
<!-- 水印 -->
<canvas style="{{canvasStyle}}" type="2d" id="Canvas"></canvas>
<!-- 获取水印文字长度 -->
<view
style="position:fixed;top:0;left:-1000%;font-size:32px;white-space:nowrap;"
id="CanvasText"
>{{CanvasText}}</view
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
canvasInit() {
const query = wx.createSelectorQuery();
query
.select('#Canvas')
.fields({
node: true,
size: true,
})
.exec((res) => {
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
this.setData({
canvas,
ctx,
});
});
},

获取水印文字长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
getCanvasTextLength(CanvasText) {
return new Promise(async (resolve, reject) => {
this.setData({
CanvasText,
});
setTimeout(() => {
const query = wx.createSelectorQuery();
query
.select('#CanvasText')
.fields({
node: true,
size: true,
})
.exec((res) => {
const data = res[0];
const {
width
} = data;
resolve(width);
});
}, 100);
});
},

图片压缩

因为微信小程序的 canvas 画布大小有限制,为4096,所以需要对图片进行压缩。

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
// 压缩图片
compressImage(path) {
return new Promise(async (resolve, reject) => {
// 获取图片数据
const imgInfo = await wx.getImageInfo({
src: path,
});
// 图片宽度
const imageWidth = imgInfo.width;
// 图片高度
const imageHeight = imgInfo.height;

// 获取设备像素比,为了保险起见,加1
const dpr = wx.getSystemInfoSync().pixelRatio + 1;

// 微信小程序canvas绘制图片,图片过大,canvas 会绘制不出来
const maxCanvasSize = 4000;
const widthScaled = imgInfo.width * dpr;
const heightScaled = imgInfo.height * dpr;

if (widthScaled > maxCanvasSize || heightScaled > maxCanvasSize) {
const scaleFactor = Math.min(
maxCanvasSize / widthScaled,
maxCanvasSize / heightScaled
);

// 在高清屏幕上,图片会模糊,需要放大图片,所以提前压缩图片
const newWidth = imgInfo.width * dpr * scaleFactor;
const newHeight = imgInfo.height * dpr * scaleFactor;
const compressedWidth = newWidth / dpr;
const compressHeight = newHeight / dpr;

// 压缩图片
wx.compressImage({
src: path,
quality: 80,
compressedWidth,
compressHeight,
success: (res) => {
resolve(res.tempFilePath);
},
fail: (err) => {
reject(err);
},
});
} else {
// 传原图
resolve(path);
}
});
},

添加水印

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 添加水印方法 (传入图片地址)
addWatermark(tempFilePath) {
return new Promise(async (resolve, reject) => {
try {
// 压缩图片
const compressedFilePath = await this.compressImage(tempFilePath);

// 获取图片信息
const imgInfo = await wx.getImageInfo({
src: compressedFilePath,
});

// 获取设备像素比,为了保险起见,加1
const dpr = wx.getSystemInfoSync().pixelRatio + 1;
const widthScaled = imgInfo.width * dpr;
const heightScaled = imgInfo.height * dpr;

// 设置 canvas 大小,放大画布
this.data.canvas.width = widthScaled;
this.data.canvas.height = heightScaled;

// 设置 canvas 样式,防止Canvas遮挡页面元素
const canvasStyle = `position:fixed;top: 0;width:${imgInfo.width}px;height:${imgInfo.height}px;left:-${imgInfo.width + 100}px;`;

this.setData({
canvasStyle,
});

// 创建一个图片对象
const image = this.data.canvas.createImage();
image.src = compressedFilePath;
image.onload = async () => {
// 将图片绘制到canvas上
this.data.ctx.drawImage(
image,
0,
0,
imgInfo.width,
imgInfo.height,
0,
0,
widthScaled,
heightScaled
);
// 字体大小
const fontSize = 32;
// 设置文字字号及字体
this.data.ctx.font = fontSize + 'px sans-serif';
// 设置画笔颜色
this.data.ctx.fillStyle = 'rgba(0,0,0,0.3)';
// 绘制矩形
// this.data.ctx.fillRect(0, imgInfo.height - 40, 420, 40)
// 设置画笔颜色
this.data.ctx.fillStyle = 'red';
// 设置文字
const nameText = `用户:${this.data.userName}`;
// 获取文字长度
const nameTextLength = await this.getCanvasTextLength(nameText);
// 填入文字
this.data.ctx.fillText(
nameText,
widthScaled - nameTextLength - 10,
fontSize
);

// 将canvas转为为图片
wx.canvasToTempFilePath({
destWidth: widthScaled,
destHeight: heightScaled,
canvas: this.data.canvas,
fileType: 'jpg',
success: async (res) => {
const imgInfo = await wx.getImageInfo({
src: tempFilePath,
});
resolve(res.tempFilePath);
// 清除画布,重置Canvas宽高
this.data.ctx.clearRect(0, 0, widthScaled, heightScaled);
},
});
};
} catch (error) {
console.log('addWatermark Error', error);
resolve(tempFilePath);
}
});
},

微信小程序 Canvas 画布大小限制

微信小程序的 canvas 画布大小有限制,为4096,所以需要对图片进行压缩。

微信小程序 Canvas 绘制图片模糊,字体模糊

微信小程序 Canvas 绘制图片模糊,字体模糊,需要放大画布,放大画布后,图片和字体就不会模糊了。

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
function createHiPPICanvas(width, height) {
const ratio = window.devicePixelRatio;
const canvas = document.createElement("canvas");

canvas.width = width * ratio;
canvas.height = height * ratio;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
canvas.getContext("2d").scale(ratio, ratio);

return canvas;
}

微信官方解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const query = wx.createSelectorQuery()
query.select('#myCanvas')
.fields({ node: true, size: true })
.exec((res) => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')

const dpr = wx.getSystemInfoSync().pixelRatio
//宽高乘像素比
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
//再缩放
ctx.scale(dpr, dpr)
ctx.fillRect(0, 0, 100, 100)
})

参考文章