问题
微信小程序加水印,需要在图片上添加文字,文字的位置需要自定义。
实现
获取和设置 canvas 上下文
<!-- 水印 -->
<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
>
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,
});
});
},
获取水印文字长度
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,所以需要对图片进行压缩。
// 压缩图片
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);
}
});
},
添加水印
// 添加水印方法 (传入图片地址)
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 绘制图片模糊,字体模糊,需要放大画布,放大画布后,图片和字体就不会模糊了。
参考代码
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;
}
微信官方解决方案
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)
})