前置内容
uni-app为图片添加自定义水印(解决生成图片不全问题)
UI
升级
现在水印样式变成这样了:
代码
<template><canvas v-if="waterMarkParams.display" canvas-id="waterMarkCanvas" :style="canvasStyle"/>
</template><script>export default {data() {return {waterMarkParams: {display: false, // 控制 canvas 创建与销毁canvasWidth: 300, // 默认宽度canvasHeight: 225, // 默认高度}}},computed: {canvasStyle() {return {position: 'fixed', // 移除到屏幕外left: '9999px',width: this.waterMarkParams.canvasWidth + 'px',height: this.waterMarkParams.canvasHeight + 'px'}}},methods: {chooseImage() {uni.chooseImage({sourceType: ['all'],success: async ({ tempFilePaths, tempFiles }) => {// 这里就得到了带水印的图片路径列表const imgFileArr = await this.callAddWaterMark(tempFilePaths)}})},// 因为有可能在相册中选择多个图片,所以这里要依次生成水印async callAddWaterMark(imgPathArr) {let results = []if(imgPathArr.length > 0) {let addIndex = 0while(addIndex < imgPathArr.length) {const tempFilePath = await this.addWaterMark(imgPathArr[addIndex])results.push(tempFilePath)addIndex = addIndex + 1}}return results},addWaterMark(src) {return new Promise((resolve, reject) => {// 获取图片信息,配置 canvas 尺寸uni.getImageInfo({src,success: res => {// 修复部分手机(如红米9)手机屏幕比较窄拍摄出来的图片水印压缩着覆盖的问题this.waterMarkParams.canvasWidth = Math.max(res.width, 886);this.waterMarkParams.canvasHeight = res.height;this.waterMarkParams.display = trueconsole.log('当前图片信息waterMarkParams:', this.waterMarkParams);// 等待 canvas 元素创建this.$nextTick(() => {let context = uni.createCanvasContext("waterMarkCanvas", this);/* 绘制 */const { canvasWidth, canvasHeight } = this.waterMarkParams// 绘制前清空画布context.clearRect(0, 0, canvasWidth, canvasHeight);// 将图片src放到cancas内,宽高必须为图片大小context.drawImage(src, 0, 0, canvasWidth, canvasHeight, canvasWidth, canvasHeight);// 防伪码的位置const fangweiY = 320;// 保证水印能完整显示出来const [x, y] = [canvasWidth / 2, canvasHeight - (fangweiY + 100)];context.translate(x, y);// 标记一下坐标系,更容易理解/* context.beginPath();context.lineWidth = 2;context.strokeStyle = 'white';context.moveTo(- x, 0);context.lineTo(x, 0);context.moveTo(0, -y);context.lineTo(0, canvasHeight - y);context.stroke();context.closePath(); */fillText(context, 0, 70, '上海市·金山区', 'bold 56px "Microsoft YaHei"', 'white', 'center');fillText(context, -20, 220, '16:08', 'bold 150px "Microsoft YaHei"', 'white', 'right');fillRect(context, -4, 100, 8, 120, '#346DFF');fillText(context, 20, 140, '2024.04.18', 'bold 40px "Microsoft YaHei"', 'white', 'left');fillText(context, 20, 210, '星期四 晴 21℃', 'bold 40px "Microsoft YaHei"', 'white', 'left');fillText(context, 0, fangweiY, `防伪:JY20240418160748XIAOMI`, 'bold 40px "Microsoft YaHei"', 'white', 'center');/* 绘制marker图标 */// 蓝色外圆fillCircle(context, -260, 30, 30, '#346DFF');// 白色内圆fillCircle(context, -260, 30, 12, 'white');// 蓝色三角fillTriangle(context, -260, 78, -235, 48, -285, 48, '#346DFF');// 坐标原点移动到画布右上角context.translate(canvasWidth / 2, -y);const [rectWidth, rectHeight, rectX, rectY, lineWidth, lineHeight] = [200, 90, -550, 60, 300, 6];// 右上角矩形fillRect(context, rectX, 60, rectWidth, rectHeight, '#346DFF');// 右上角下划线fillRect(context, rectX + rectWidth, rectY + rectHeight - lineHeight, lineWidth, lineHeight, '#346DFF');// 右上角姓名fillText(context, rectX + rectWidth / 2, 120, '鹏北海', 'bold 40px "Microsoft YaHei"', 'white', 'center');// 右上角手机号码fillText(context, rectX + rectWidth + lineWidth / 2, 120, '15888888888', 'bold 34px "Microsoft YaHei"', 'white', 'center');// 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常setTimeout(() => {// 本次绘画完重开开始绘画,并且在绘画完毕之后再保存图片,不然页面可能会出现白屏等情况context.draw(false, () => {console.log('!!!!!开始绘画', canvasWidth, canvasHeight);uni.canvasToTempFilePath({canvasId: "waterMarkCanvas",fileType: "jpg",width: canvasWidth,height: canvasHeight,destWidth: canvasWidth,destHeight: canvasHeight,success: ({ tempFilePath }) => {console.log('绘制成功', tempFilePath);this.waterMarkParams.display = falseresolve(tempFilePath)},fail: err => {reject(err)console.log(err);}}, this)})}, 1000);})}})})// 绘制文字function fillText(context, x, y, content, font, fontStyle, textAlign) {// 保存当前绘图状态context.save();// 设置字体样式context.font = font// 设置文字颜色为白色context.fillStyle = fontStyle// 设置文字水平居中对齐context.textAlign = textAligncontext.fillText(content, x, y)// 恢复到之前保存的绘图状态,清除样式设置context.restore();}// 绘制圆function fillCircle(context, x, y, r, fillStyle) {// 保存当前绘图状态context.save();context.beginPath();context.arc(x, y, r, 0, 2 * Math.PI);context.fillStyle = fillStyle;context.fill();context.closePath();// 恢复到之前保存的绘图状态,清除样式设置context.restore();}// 绘制三角形function fillTriangle(context, x1, y1, x2, y2, x3, y3, fillStyle) {// 保存当前绘图状态context.save();context.beginPath();context.moveTo(x1, y1);context.lineTo(x2, y2);context.lineTo(x3, y3);context.fillStyle = fillStyle;context.fill();context.closePath();// 恢复到之前保存的绘图状态,清除样式设置context.restore();}// 绘制矩形function fillRect(context, x, y, width, height, fillStyle) {// 保存当前绘图状态context.save();context.fillStyle = fillStyle;context.fillRect(x, y, width, height);// 恢复到之前保存的绘图状态,清除样式设置context.restore();}},}}
</script>