选择图片 → 将图片绘制到 canvas 中并绘制水印 →将添加水印的图片绘制到 canvas 中 → 将 canvas 画布转换为图片地址 → 上传/展示操作
注意:微信小程序在选择照片或者唤起相机之前需要获取相应的 权限
uni.getSetting({
success: async (res) => {
// 是否有相机权限
if (!res.authSetting['scope.camera']) {
// 获取相机权限
uni.authorize({
scope: 'scope.camera',
async success() {
// 选择图片
chooseImage()
}
})
} else {
// 选择图片
chooseImage()
}
},
fail(err) {
console.log('err :>> ', err);
}
})
uni.chooseMedia({
count: 1, // 1就是最多选择一张图片
mediaType: ['image'],
sourceType: _this.sourceType, // album相册、camera相机
success: async (res) => {
const tempFilePath = res.tempFiles[0].tempFilePath
//添加水印
_this.addWaterMarking(tempFilePath)
}
})
放置 canvas 画布并将其放置到窗口外
<template>
<view class='waterMarkingCamera'>
<canvas id="myCanvas" type="2d" :style="'position:fixed;left:8888px'" />
view>
template>
利用 uni.getImageInfo 获取原图片信息
addWaterMarking(imageUrl) {
//获取原图片信息
uni.getImageInfo({
src: imageUrl,
success: async function(res) {
const imgWidth = res.width; // 图片的宽
const imgHeight = res.height; // 图片的高
}
})
}
利用 wx.createSelectorQuery 获取 canvas 对象并渲染上下文
addWaterMarking(imageUrl) {
//获取原图片信息
uni.getImageInfo({
src: imageUrl,
success: async function(res) {
const imgWidth = res.width; // 图片的宽
const imgHeight = res.height; // 图片的高
// 获取 canvas
wx.createSelectorQuery()
.in(_this)
.select('#myCanvas') //
.fields({
node: true,
size: true
})
.exec((resCanvas) => {
// canvas 对象
const canvas = resCanvas[0].node
// 初始化画布大小
canvas.width = imgWidth;
canvas.height = imgHeight;
// 渲染上下文
const ctx = canvas.getContext('2d')
}
}
})
}
创建图片对象并绘制图片和水印
addWaterMarking(imageUrl) {
//获取原图片信息
uni.getImageInfo({
src: imageUrl,
success: async function(res) {
const imgWidth = res.width; // 图片的宽
const imgHeight = res.height; // 图片的高
// 获取 canvas
wx.createSelectorQuery()
.in(_this)
.select('#myCanvas') //
.fields({
node: true,
size: true
})
.exec((resCanvas) => {
// canvas 对象
const canvas = resCanvas[0].node
// 初始化画布大小
canvas.width = imgWidth;
canvas.height = imgHeight;
// 渲染上下文
const ctx = canvas.getContext('2d')
// 图片对象
const image = canvas.createImage()
// 图片加载完成回调
image.onload = async () => {
let waterMarkingText = _this.waterMarkingText;
// 将图片绘制到 canvas 上
ctx.drawImage(image, 0, 0, imgWidth, imgHeight)
// 添加遮罩水印
if (_this.isOverlay) {
_this.addOverlay(ctx, res, waterMarkingText)
}
// 添加文字水印
if (typeDetection.call(waterMarkingText) == '[object Array]') {// 判断是否添加多条水印
for (let i = 0; i < waterMarkingText.length; i++) {
// 设置水印内容
const text = waterMarkingText[i] == 'time' ?
_this.$parseTime(new Date()) :
waterMarkingText[i] == 'address' ?
_this.address : waterMarkingText[i]
// 设置水印颜色
ctx.fillStyle = typeDetection.call(_this.fontColor) == '[object Array]' ?
_this.fontColor[i] : _this.fontColor;
// 设置水印文字大小
ctx.font = `${typeDetection.call(_this.fontSize) == '[object Array]' ?
_this.fontSize[i] : _this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(text, _this.interval[0], res.height -
(typeDetection.call(_this.fontSize) == '[object Array]' ?
_this.fontSize[i] :
_this.fontSize) - _this.interval[1] * i)
ctx.restore();
}
} else {
// 设置水印颜色
ctx.fillStyle = _this.fontColor;
// 设置水印文字大小
ctx.font = `${_this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(waterMarkingText, _this.interval[0], res.height - _this.fontSize);
ctx.restore();
}
}
image.src = imageUrl
})
}
})
}
addWaterMarking(imageUrl) {
//获取原图片信息
uni.getImageInfo({
src: imageUrl,
success: async function(res) {
const imgWidth = res.width; // 图片的宽
const imgHeight = res.height; // 图片的高
// 获取 canvas
wx.createSelectorQuery()
.in(_this)
.select('#myCanvas') //
.fields({
node: true,
size: true
})
.exec((resCanvas) => {
// canvas 对象
const canvas = resCanvas[0].node
// 初始化画布大小
canvas.width = imgWidth;
canvas.height = imgHeight;
// 渲染上下文
const ctx = canvas.getContext('2d')
// 图片对象
const image = canvas.createImage()
// 图片加载完成回调
image.onload = async () => {
let waterMarkingText = _this.waterMarkingText;
// 将图片绘制到 canvas 上
ctx.drawImage(image, 0, 0, imgWidth, imgHeight)
// 添加遮罩水印
if (_this.isOverlay) {
_this.addOverlay(ctx, res, waterMarkingText)
}
// 添加文字水印
if (typeDetection.call(waterMarkingText) == '[object Array]') {
for (let i = 0; i < waterMarkingText.length; i++) {
// 设置水印内容
const text = waterMarkingText[i] == 'time' ?
_this.$parseTime(new Date()) :
waterMarkingText[i] == 'address' ?
_this.address : waterMarkingText[i]
// 设置水印颜色
ctx.fillStyle = typeDetection.call(_this.fontColor) == '[object Array]' ?
_this.fontColor[i] : _this.fontColor;
// 设置水印文字大小
ctx.font = `${typeDetection.call(_this.fontSize) == '[object Array]' ?
_this.fontSize[i] : _this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(text, _this.interval[0], res.height -
(typeDetection.call(_this.fontSize) == '[object Array]' ?
_this.fontSize[i] :
_this.fontSize) - _this.interval[1] * i)
ctx.restore();
}
} else {
// 设置水印颜色
ctx.fillStyle = _this.fontColor;
// 设置水印文字大小
ctx.font = `${_this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(waterMarkingText, _this.interval[0], res.height - _this.fontSize);
ctx.restore();
}
// 某些平台 canvas 绘制比较慢,需要等待绘制完成
await _this.sleep(500)
// 将 canvas 画布转换为图片地址
wx.canvasToTempFilePath({
canvas: canvas,
async success(res) {
// 上传图片操作
await _this.uploadImage(res.tempFilePath)
}
})
}
image.src = imageUrl
})
}
})
}
<template>
<view class='waterMarkingCamera'>
<canvas id="myCanvas" type="2d" :style="'position:fixed;left:8888px'" />
<view class="waterMarkingCamera-icon" @tap='handleChooseImage()' v-show="!imageArr||imageArr.length" >
<slot name="W_M_C_Icon">
<text class="iconfont icon-a-xiangji">text>
slot>
view>
view>
template>
<script>
var typeDetection = Object.prototype.toString;
export default {
name: 'waterMarkingCamera',
/**
* waterMarkingCamera 水印相机
* @property {Array} attachmentList 附件列表
* @property {Array} sourceType 数据源类型 album(相册) camera(相机)
* @property {Number|String} limit 限制照片数 999
* @property {Boolean} isOverlay 是否需要遮罩 true
* @property {Array|String} waterMarkingText 水印文字 ['time','address'] ['水印文字',水印文字2] | '水印文字' time(添加时间)、address(添加地址)
* @property {Array|String} fontSize 水印文字大小 32 ['32',100] | '32'
* @property {Array|String} fontColor 水印文字颜色 '#ffffff' ['#ffffff','red','rgba(255, 255, 255,0.2)','rgb(255, 255, 255)'] | '#ffffff'
* @property {Array} interval 间距 [50, 80]
*
* */
props: {
attachmentList: {
type: Array,
default: () => {
return []
}
},
sourceType: {
type: Array,
default: () => {
return ['album', 'camera']
}
},
limit: {
type: [Number, String],
default: 999
},
isOverlay: {
type: Boolean,
default: true
},
waterMarkingText: {
type: [Array, String],
default: () => {
return ['time', 'address']
}
},
fontSize: {
type: [Array, Number, String],
default: 32
},
fontColor: {
type: [Array, String],
default: '#ffffff'
},
interval: {
type: Array,
default: () => {
return [50, 50]
}
}
},
data() {
return {
imageArr: [],
address: '你的位置信息'
}
},
mounted() {
this.imageArr = this.attachmentList
// 反转内容数组
if (typeDetection.call(this.waterMarkingText) ==
'[object Array]') {
this.waterMarkingText.reverse()
}
},
methods: {
// 选择照片
handleChooseImage() {
let _this = this
uni.getSetting({
success: async (res) => {
const chooseImage = () => {
uni.chooseMedia({
count: 1, // 最多选择一张图片
mediaType: ['image'],
sourceType: _this.sourceType, // 相册、相机
success: async (res) => {
const tempFilePath = res.tempFiles[0].tempFilePath
_this.addWaterMarking(tempFilePath)
}
})
}
// 是否有相机权限
if (!res.authSetting['scope.camera']) {
// 获取相机权限
uni.authorize({
scope: 'scope.camera',
async success() {
// 选择照片
chooseImage()
}
})
} else {
// 选择照片
chooseImage()
}
},
fail(err) {
console.log('err :>> ', err);
}
})
},
// 添加水印
addWaterMarking(imageUrl) {
uni.showLoading({
title: '上传中...',
mask: true
})
var _this = this;
//获取原图片信息
uni.getImageInfo({
src: imageUrl,
success: async function(res) {
const imgWidth = res.width; // 图片的宽
const imgHeight = res.height; // 图片的高
// 获取canvas
wx.createSelectorQuery()
.in(_this)
.select('#myCanvas') // 在 WXML 中填入的 id
.fields({
node: true,
size: true
})
.exec((resCanvas) => {
// Canvas 对象
const canvas = resCanvas[0].node
// 初始化画布大小
canvas.width = imgWidth;
canvas.height = imgHeight;
// 渲染上下文
const ctx = canvas.getContext('2d')
// 图片对象
const image = canvas.createImage()
// 图片加载完成回调
image.onload = async () => {
let waterMarkingText = _this.waterMarkingText;
// 将图片绘制到 canvas 上
ctx.drawImage(image, 0, 0, imgWidth, imgHeight)
// 添加遮罩水印
if (_this.isOverlay) {
_this.addOverlay(ctx, res, waterMarkingText)
}
// 添加文字水印
if (typeDetection.call(waterMarkingText) ==
'[object Array]') {
for (let i = 0; i < waterMarkingText.length; i++) {
// 设置水印内容
const text = waterMarkingText[i] == 'time' ?
_this.$parseTime(new Date()) :
waterMarkingText[i] ==
'address' ?
_this.address : waterMarkingText[i]
// 设置水印颜色
ctx.fillStyle = typeDetection.call(_this.fontColor) ==
'[object Array]' ?
_this.fontColor[i] : _this.fontColor;
// 设置水印文字大小
ctx.font = `${typeDetection.call(_this.fontSize) ==
'[object Array]' ?
_this.fontSize[i] : _this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(text, _this.interval[0], res.height - (
typeDetection
.call(_this
.fontSize) == '[object Array]' ?
_this.fontSize[i] : _this.fontSize) - _this
.interval[1] * i)
ctx.restore();
}
} else {
// 设置水印颜色
ctx.fillStyle = _this.fontColor;
// 设置水印文字大小
ctx.font = `${_this.fontSize}px arial`;
// 绘制水印文字
ctx.fillText(waterMarkingText, _this.interval[0], res
.height -
_this
.fontSize);
ctx.restore();
}
// 某些平台 canvas 绘制比较慢,需要等待绘制完成
await _this.sleep(500)
// 将 canvas 画布转换为图片地址
wx.canvasToTempFilePath({
canvas: canvas,
async success(res) {
// 上传图片操作
}
})
}
image.src = imageUrl
})
}
})
this.handleEmit()
},
// 添加遮罩
addOverlay(ctx, res, waterMarkingText) {
let makerHeight = 0
if (typeDetection.call(this.fontSize) ==
'[object Array]') {
for (let i = 0; i < this.fontSize; i++) {
makerHeight += (this.fontSize[i] + this
.interval[1])
}
} else {
makerHeight += (this.fontSize * waterMarkingText.length + this
.interval[1] * (waterMarkingText.length - 1))
}
ctx.rect(0, res.height - makerHeight, res.width, makerHeight);
ctx.fillStyle = "rgba(46, 46, 46,0.4)";
ctx.fill();
},
// 触发emit
handleEmit() {
this.$emit('change', this.imageArr)
this.$emit('input', this.imageArr)
this.$emit('update:modelValue', this.imageArr)
},
sleep(millisecond) {
return new Promise((resolve) => {
setTimeout(resolve, millisecond)
})
}
}
}
script>
<style lang="scss" scoped>
.waterMarkingCamera {
display: flex;
flex-flow: row;
align-items: center;
justify-content: flex-end;
padding: 20rpx 0;
&-icon {
width: 146rpx;
height: 120rpx;
border-radius: 4rpx;
font-size: 42rpx;
text-align: center;
line-height: 108rpx;
border: 2rpx dashed #666666;
}
}
style>