前言
本文将介绍如何使用uniApp和u-upload组件封装一个自动添加水印并上传图片的功能。整个过程涵盖了图片上传、canvas画布操作、水印绘制等多个技术点。
主要技术点
- u-upload组件:用于图片的上传与展示。
- Canvas画布: 用于在图片上绘制水印信息。
- 异步操作: 用来处理图片信息的获取与水印绘制,确保操作的正确顺序。
- 图片信息的获取: 通过uni.getImageInfo()获取图片的宽高等信息。
- 地理位置的获取: 使用uni.getLocation()结合腾讯地图API获取当前位置,并显示在水印中。
实现效果
用户在选择或拍摄图片后,图片不会立即上传,而是通过Canvas在图片上绘制时间、地址、用户名称等水印信息。处理完毕后,带水印的图片将被替换原图并上传。(以下是运行到微信小程序的测试效果)
实现步骤
1. 使用u-upload组件
使用u-upload组件来处理图片选择和上传。同时准备了一个隐藏的 canvas 元素,用于绘制图片水印
<template>
<view style="width: 100%">
<u-upload
ref="uUpload"
:action="action"
:source-type="sourceType"
:file-list="defaultValue"
:auto-upload="!isWatermark"
@on-choose-complete="onChooseComplete"
/>
<!-- Canvas画布,用于添加水印 -->
<canvas
canvas-id="watermarkCanvas"
v-if="isCanvasShow"
:style="{
position: 'absolute',
top: '-9999px',
left: '-9999px',
width: canvasWidth + 'px',
height: canvasHeight + 'px',
}"
></canvas>
<!-- 模拟提示 -->
<u-toast ref="uToast" />
</view>
</template>
2. 处理选择图片后的逻辑
当用户选择图片后,触发 onChooseComplete 方法,开始处理图片水印。
由于这里是使用uView1.X版本所以在on-choose-complete事件中处理图片,如果是使用uView2.X版本,则在afterRead事件中处理图片
methods: {
// 当选择图片后触发的事件
async onChooseComplete(list, name) {
if (this.isWatermark) {
try {
const index = list.length - 1;
await this.drawWatermark(list, index); // 添加水印
} catch (error) {
console.error("水印处理失败", error);
}
}
},
// 处理水印并手动上传
async drawWatermark(list, index) {
try {
const url = list[index].url;
const size = list[index].file.size;
// 获取当前时间:年-月-日 时:分:秒 星期
this.currentTime = parseTime(new Date(), "{y}-{m}-{d} {h}:{i}:{s} {a}");
// 设置mask: true,避免水印加载过程中用户执行其他操作
uni.showLoading({ title: "加载水印中", mask: true });
await this.getCurrentAddress(); // 获取当前地址
const { width, height, path } = await this.getImageInfo(url); // 获取图片信息
// 设置画布宽高
this.canvasWidth = width;
this.canvasHeight = height;
this.isCanvasShow = true;
// 等待 canvas 元素创建
this.$nextTick(() => {
let ctx = uni.createCanvasContext("watermarkCanvas", this);
// 清除画布
ctx.clearRect(0, 0, width, height);
// 绘制图片
ctx.drawImage(path, 0, 0, width, height);
// 绘制地址水印
this.drawAddressWatermark(ctx, width, height);
// 绘制竖线水印、时间、创建人等
this.drawOtherWatermarks(ctx, width, height);
// 绘制结束后生成临时文件并上传
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: "watermarkCanvas",
quality: 0.6, // 图片质量,范围0-1,1为最高质量
width: width, // 画布宽度
height: height, // 画布高度
destWidth: width, // 输出图片宽度
destHei