更新记录
1.1.1(2025-01-11)
下载此版本
feat: 图片上传生成水印
平台兼容性
App |
快应用 |
微信小程序 |
支付宝小程序 |
百度小程序 |
字节小程序 |
QQ小程序 |
× |
× |
√ |
× |
× |
× |
× |
钉钉小程序 |
快手小程序 |
飞书小程序 |
京东小程序 |
鸿蒙元服务 |
× |
× |
× |
× |
× |
H5-Safari |
Android Browser |
微信浏览器(Android) |
QQ浏览器(Android) |
Chrome |
IE |
Edge |
Firefox |
PC-Safari |
× |
× |
× |
× |
× |
× |
× |
× |
× |
插件使用说明
1. 按照步骤使用即可
第一步:
<u-form-item label-width="130" label="巡检照片:" prop="photoFiles">
<u-upload :action="uploadUrl" upload-text="拍照" :source-type="['camera']" :file-list="fileList"
:auto-upload="true" :before-upload="beforeUpload" @afterRead="afterRead" @on-progress=""
@on-success="onSuccess" :on-error="onError" @on-preview="onPreview" @on-remove="onRemove"
:header="headers" :name="name" :with-credentials="true" :show-upload-list="true" :multiple="true"
:accept="accept" :tip="tip" />
<view style="position: absolute;top: -999999px;">
<view>
<canvas v-if="waterMarkParams.display" canvas-id="waterMarkCanvas"
style="width: 2300px;height: 2000px;" />
</view>
</view>
</u-form-item>
第二步:
data() {
return {
waterMarkParams: {
display: false, // 控制 canvas 创建与销毁
canvasWidth: 300, // 默认宽度
canvasHeight: 225, // 默认高度
},
photoFiles: [],
uploadUrl: baseUrl + '/admin-api/infra/file/upload',
fileList: [],
headers: {
Authorization: "Bearer " + getAccessToken()
},
name: 'file',
accept: 'image/*',
tip: '支持jpg/png/gif格式,大小不超过2M',
}
}
第三步:
methods: {
// 图片上传之前 水印 渲染
beforeUpload(index, list) {
console.log("beforeUpload: " + JSON.stringify(list));
const areaName = this.checkinsOne.areaName;
const streetName = this.checkinsOne.streetName;
return new Promise((resolve, reject) => {
// 入参 图片url,区名称,街道名称
// 在这里添加水印
this.addWaterMark(list[index].url, areaName, streetName)
.then(watermarkedUrl => {
console.log('watermarkedUrl--->>>' + watermarkedUrl);
// 使用带有水印的图片 URL 替换原来的 file 对象中的 URL
list[index].url = watermarkedUrl;
resolve(list); // 继续上传
}).catch(error => {
reject(error); // 中断上传
});
});
},
(event, file, fileList) {
// 上传进度发生变化时的回调函数
console.log(": " + JSON.stringify(file));
},
// 回调图片地址
onSuccess(res, file, fileList) {
console.log('上传成功--->>>' + JSON.stringify(res.data));
this.photoFiles.push(res.data);
},
onError(err, file, fileList) {
// 上传失败时的回调函数
console.log("onError" + JSON.stringify(file));
},
onPreview(file) {
console.log("onPreview " + JSON.stringify(file));
},
onRemove(file, fileList) {
// 文件列表移除文件时的回调函数
console.log("onRemove" + JSON.stringify(file));
// 从model.photoFiles数组中移除对应的文件记录
const index = this.model.photoFiles.findIndex(p => p.name === file.name);
if (index !== -1) {
this.removeFromList(index);
}
},
removeFromList(index) {
this.model.photoFiles.splice(index, 1);
},
resultFormatter(res) {
// 返回结果的格式化函数
console.log("resultFormatter" + JSON.stringify(file));
},
// 图片水印
addWaterMark(src, areaName, streetName) {
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 = true
console.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);
// 在获取到canvas尺寸后计算偏移量
const offsetX = canvasWidth * 0.2; // 向左移动5%的宽度
const offsetY = canvasHeight * 0.05; // 向下移动5%的高度
// 防伪码的位置也根据新的偏移量调整
const fangweiY = 320 + offsetY;
// 动态设置日期和时间
const date = new Date();
// 更新文本绘制的位置
context.translate(offsetX, canvasHeight - (fangweiY + 15));
const formatDate =
`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
const formatTime = String(date.getHours()).padStart(2, '0') +
':' + String(
date.getMinutes()).padStart(2, '0');
const days = ['日', '一', '二', '三', '四', '五', '六'];
const day = days[date.getDay()];
// 水印信息文本绘制 areaName、formatTime、formatDate
fillText(context, -10, 120 + offsetY, areaName + '·' +
streetName,
'bold 45px "Microsoft YaHei"', 'white', 'center');
fillText(context, -55 + offsetX, 270 + offsetY, formatTime,
'bold 105px "Microsoft YaHei"', 'white', 'right');
fillRect(context, -40 + offsetX, 160 + offsetY, 6, 110,
'#346DFF');
fillText(context, -10 + offsetX, 210 + offsetY, formatDate,
'bold 32px "Microsoft YaHei"', 'white', 'left');
fillText(context, -10 + offsetX, 260 + offsetY, day + ' 晴 21℃',
'bold 32px "Microsoft YaHei"', 'white', 'left');
fillText(context, 120, fangweiY, `防伪:JY20240418160748XIAOMI`,
'bold 32px "Microsoft YaHei"', 'white', 'center');
// 对于marker图标的绘制也需要相应调整
fillCircle(context, -260 + offsetX, 30 + offsetY, 30,
'#346DFF');
fillCircle(context, -260 + offsetX, 30 + offsetY, 12, 'white');
fillTriangle(context, -260 + offsetX, 78 + offsetY, -235 +
offsetX, 48 + offsetY, -285 + offsetX, 48 + offsetY,
'#346DFF');
// 一定要加上一个定时器否则进入到页面第一次可能会无法正常拍照,后几次才正常
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 =
false
resolve(
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 = textAlign
context.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();
}
},
}