uniapp 拍照图片加水印
uniapp 封装组件 拍照加水印,保存图片加水印路由定义回调函数,函数名不可更改,用于拍照页面往回传递参数
·
有些app拍照时需要带有时间地址水印,防止随便上传图片拍照作假之类的行为
水印相机用法
首先 组件注册
- 在需要该操作的页面引入组件并注册
html
<mark-camera ref="camera"></mark-camera>
js
// 引入 import MarkCamera from "@/components/water-mark-camera/index.vue"
其次 定义一个方法跳转到拍照页面去
-
路由
js
//打开相机 openCamera(){ uni.navigateTo({ url:'/pages/my/settings/water-mark/water-mark', }) },
-
定义回调函数,函数名不可更改,用于拍照页面往回传递参数
js
//回调 setImage(info){ this.$refs.camera.watermark(info) },
注意:
- 拍照页面 直接调用上一个页面的setImage()方法,把数据存到上一个页面中去
js
//返回的参数 用于canvas写入画布中的数据 // { // path: _this.snapshotsrc, //照片路径 // info: { // username: this.username, //标题名 // address: this.address, //地址 // time: this.time //日期时间 // }, // } //给上一页 设置 setImage() { let pages = getCurrentPages(); let prevPage = pages[pages.length - 2]; //上一个页面 //直接调用上一个页面的setImage()方法,把数据存到上一个页面中去 prevPage.$vm.setImage({ path: _this.snapshotsrc, //照片路径 info: { username: this.username, //标题名 address: this.address, //地址 time: this.time //日期时间 }, }) uni.navigateBack(); }
另:拍照时的水印样式和保存后的水印样式 需要在两处调整
- 拍照时的需要在拍照页css处调整
- 保存后的为canvas后添加的样式需要在js中调整
附组件源码
<template>
<!-- 水印相机 -->
<view class="page">
<view style="height: 80rpx;"></view>
<view v-if="isShowList">拍摄结果预览图,见下方</view>
<view class="img-list" v-if="isShowList">
<view class="img-item" v-for="(item,index) in imgList" :key="index" @click="lookImg(index)">
<image :src="item"></image>
</view>
</view>
<canvas id="canvas-clipper" canvas-id="canvas-clipper" type="2d" :style="{width: canvasSiz.width+'px',height: canvasSiz.height+'px',position: 'absolute',left:'-500000px',top: '-500000px'}" />
</view>
</template>
<script>
export default {
props:{
//显示拍摄结果预览图
isShowList:{
type:Boolean,
default:true
}
},
data() {
return {
windowWidth:'',
windowHeight:'',
imagesrc: null,
imgList:[],
canvasSiz:{
width:188,
height:273
}
};
},
onLoad() {
// _this= this;
// this.init();
},
methods: {
//添加照片水印
watermark(info){
let _this = this
_this.init();
// console.log("获取到的数据为",info)
uni.getImageInfo({
src: info.path,
success: function(image) {
console.log(image,_this.canvasSiz);
_this.canvasSiz.width =image.width;
_this.canvasSiz.height =image.height;
let maxWidth = image.width - 60;
// console.log("获取最大宽度",maxWidth)
//担心尺寸重置后还没生效,故做延迟
setTimeout(()=>{
let ctx = uni.createCanvasContext('canvas-clipper', _this);
ctx.drawImage(
info.path,
0,
0,
image.width,
image.height
);
//具体位置如需和相机页面上一致还需另外做计算,此处样式调整
ctx.setFillStyle('white');
ctx.setFontSize(50);
ctx.fillText(info.info.username, 20, 150);
ctx.setFontSize(50);
let previousRowHeight = _this.textPrewrap(ctx,info.info.address,20,220,70,maxWidth,3);
//再来加个时间水印
ctx.setFontSize(40);
ctx.fillText(info.info.time, 20, previousRowHeight+70);
ctx.draw(false, () => {
uni.canvasToTempFilePath(
{
destWidth: image.width,
destHeight: image.height,
canvasId: 'canvas-clipper',
fileType: 'jpg',
success: function(res) {
_this.savePhoto(res.tempFilePath);
}
},
_this
);
});
},500)
}
});
},
/**
ctx: 画布的上下文环境
content: 需要绘制的文本内容
drawX: 绘制文本的x坐标
drawY: 绘制文本的y坐标
lineHeight:文本之间的行高
lineMaxWidth:每行文本的最大宽度
lineNum:最多绘制的行数
*/
textPrewrap(ctx, content, drawX, drawY, lineHeight, lineMaxWidth, lineNum) {
let _this = this
var drawTxt = ''; // 当前绘制的内容
var drawLine = 1; // 第几行开始绘制
var drawIndex = 0; // 当前绘制内容的索引
// 判断内容是否可以一行绘制完毕
if (ctx.measureText(content).width <= lineMaxWidth) {
ctx.fillText(content.substring(drawIndex, i), drawX, drawY);
} else {
for (var i = 0; i < content.length; i++) {
drawTxt += content[i];
if (ctx.measureText(drawTxt).width >= lineMaxWidth) {
if (drawLine >= lineNum) {
ctx.fillText(content.substring(drawIndex, i) + '..', drawX, drawY);
break;
} else {
ctx.fillText(content.substring(drawIndex, i + 1), drawX, drawY);
drawIndex = i + 1;
drawLine += 1;
drawY += lineHeight;
drawTxt = '';
}
} else {
// 内容绘制完毕,但是剩下的内容宽度不到lineMaxWidth
if (i === content.length - 1) {
ctx.fillText(content.substring(drawIndex), drawX, drawY);
return drawY;
console.log("最后高度为",drawY);
}
}
}
}
},
//保存图片到相册,方便核查
savePhoto(path){
let _this = this
this.imgList.push(path)
this.imagesrc = path;
// 保存到相册
uni.saveImageToPhotosAlbum({
filePath: path,
success: () => {
uni.showToast({
title: '已保存至相册',
duration: 2000
});
}
});
},
lookImg(index){
// 预览图片
uni.previewImage({
current:index,
urls: this.imgList,
});
},
//初始化
init(){
let _this = this;
uni.getSystemInfo({
success: function(res) {
_this.windowWidth = res.windowWidth;
_this.windowHeight = res.windowHeight;
}
});
}
}
};
</script>
<style lang="less">
.page {
width: 750rpx;
justify-content: center;
align-items: center;
flex-direction:column;
display: flex;
.buttons {
width: 600rpx;
}
}
.img-list{
padding: 20rpx;
display: flex;
align-items: center;
justify-content: flex-start;
flex-wrap: wrap;
}
.img-item{
width: 100rpx;
height: 100rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
}
.img-item image{
width: 100%;
height: 100%;
}
</style>
拍照页面源码
<template>
<view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
<view class="preview" :style="{ width: windowWidth, height: windowHeight}">
<live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="0" whiteness="0"
:aspect="aspect" min-bitrate="1000" audio-quality="16KHz" device-position="back" auto-focus="false"
muted="true" :enable-camera="true" :enable-mic="false" :zoom="false" @statechange="statechange"
:style="{ width: windowWidth, height: windowHeight }"></live-pusher>
<!--提示语-->
<cover-view class="remind">
<text class="remind-text remind-name" style="">{{ prjName}}:{{username}}</text>
<text class="remind-text remind-address" style="">{{ address }}</text>
<text class="remind-text remind-time" style="">{{ time }}</text>
</cover-view>
</view>
<view class="menu">
<!--底部菜单区域背景-->
<cover-image class="menu-mask" src="@/static/camera/bar.png"></cover-image>
<!--返回键-->
<cover-image class="menu-back" @tap="back" src="@/static/camera/back.png"></cover-image>
<!--快门键-->
<cover-image class="menu-snapshot" @tap="snapshot" src="@/static/camera/shutter.png"></cover-image>
<!--反转键-->
<cover-image class="menu-flip" @tap="flip" src="@/static/camera/flip.png"></cover-image>
</view>
<canvas id="canvas-clipper" canvas-id="canvas-clipper" type="2d" :style="{width: canvasSiz.width+'px',height: canvasSiz.height+'px',position: 'absolute',left:'-500000px',top: '-500000px'}" />
</view>
</template>
<script>
let _this = null;
export default {
data() {
return {
message: 'live-camer', //水印内容
username: '张三',
prjName:'项目名称',
address: '无法获取地址',
time: '2022-2-14 10:23',
poenCarmeInterval: null, //打开相机的轮询
aspect: '2:3', //比例
windowWidth: '', //屏幕可用宽度
windowHeight: '', //屏幕可用高度
camerastate: false, //相机准备好了
livePusher: null, //流视频对象
snapshotsrc: null, //快照,
timer: null, //定时器
// ----------添加水印
imagesrc: null,//照片src
//canvas尺寸
canvasSiz:{
width:188,
height:273
}
};
},
onLoad(e) {
_this = this;
this.initCamera();
},
onReady() {
this.getAddress();
let date = new Date()
this.time = this.dateFormat("YYYY-mm-dd HH:MM", date);
this.livePusher = uni.createLivePusherContext('livePusher', this);
this.startPreview(); //开启预览并设置摄像头
this.poenCarme();
},
onShow() {
clearInterval(this.timer)
// 每隔10秒刷新地址和时间
this.timer = setInterval(() => {
this.getAddress();
let date = new Date()
this.time = this.dateFormat("YYYY-mm-dd HH:MM", date);
}, 10000);
},
onUnload() {
clearInterval(this.timer)
},
methods: {
getAddress() {
uni.getLocation({
type: 'gcj02',
geocode: true,
isHighAccuracy: true,
success: (res) => {
this.address = res.address.province + res.address.city + res.address.district + res
.address.street + res.address.streetNum + res.address.poiName;
console.log('当前位置:', this.address);
// console.log('当前位置的经度:' + res.longitude);
// console.log('当前位置的纬度:' + res.latitude);
}
});
},
//轮询打开
poenCarme() {
//#ifdef APP-PLUS
if (plus.os.name == 'Android') {
this.poenCarmeInterval = setInterval(function() {
// console.log(_this.camerastate,'轮询打开-----');
if (!_this.camerastate) _this.startPreview();
}, 2500);
}
//#endif
},
//初始化相机
initCamera() {
uni.getSystemInfo({
success: function(res) {
_this.windowWidth = res.windowWidth;
_this.windowHeight = res.windowHeight;
let zcs = _this.aliquot(_this.windowWidth, _this.windowHeight);
_this.aspect = _this.windowWidth / zcs + ':' + _this.windowHeight / zcs;
// console.log('画面比例:' + _this.aspect);
}
});
},
//整除数计算
aliquot(x, y) {
if (x % y == 0) return y;
return this.aliquot(y, x % y);
},
//开始预览
startPreview() {
this.livePusher.startPreview({
success: a => {
// console.log('开始预览',a);
}
});
},
//停止预览
stopPreview() {
this.livePusher.stopPreview({
success: a => {
_this.camerastate = false; //标记相机未启动
// clearInterval(_this.poenCarmeInterval)
console.log('清定轮询,相机未启动-----');
}
});
},
//状态
statechange(e) {
//状态改变
// console.log(e);
if (e.detail.code == 1007) {
_this.camerastate = true;
} else if (e.detail.code == -1301) {
_this.camerastate = false;
}
},
//返回
back() {
uni.navigateBack();
},
//抓拍
snapshot() {
this.livePusher.snapshot({
success: e => {
_this.snapshotsrc = e.message.tempImagePath;
_this.stopPreview();
_this.setImage();
}
});
},
//反转
flip() {
this.livePusher.switchCamera();
},
//给上一页 设置
setImage() {
let pages = getCurrentPages();
let prevPage = pages[pages.length - 2]; //上一个页面
//直接调用上一个页面的setImage()方法,把数据存到上一个页面中去
prevPage.$vm.setImage({
path: _this.snapshotsrc,
info: {
username: this.username,
address: this.address,
time: this.time
},
})
uni.navigateBack();
},
dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1]
.length, "0")))
};
};
return fmt;
},
}
};
</script>
<style lang="less">
.live-camera {
justify-content: center;
align-items: center;
}
.preview {
justify-content: center;
align-items: center;
}
.remind {
position: absolute;
bottom: 240rpx;
left: 20rpx;
z-index: 100;
background-color: rgba(176, 192, 217, 0.5);
border-radius: 10rpx;
overflow: hidden;
}
.remind-text {
box-sizing: border-box;
padding:0 20rpx;
color: #dddddd;
width: 400rpx;
min-height: 60rpx;
line-height: 50rpx;
}
.remind-name {
height: 80rpx;
line-height: 80rpx;
font-size: 40rpx;
font-weight: 600;
color: #fff;
background-color: rgba(76, 176, 229, 0.4);
}
.remind-address {
font-size: 36rpx;
}
.remind-time {
font-size: 30rpx;
}
.menu {
position: absolute;
left: 0;
bottom: 0;
width: 750rpx;
height: 180rpx;
z-index: 98;
align-items: center;
justify-content: center;
}
.menu-mask {
position: absolute;
left: 0;
bottom: 0;
width: 750rpx;
height: 180rpx;
z-index: 98;
}
.menu-back {
position: absolute;
left: 30rpx;
bottom: 50rpx;
width: 80rpx;
height: 80rpx;
z-index: 99;
align-items: center;
justify-content: center;
}
.menu-snapshot {
width: 130rpx;
height: 130rpx;
z-index: 99;
}
.menu-flip {
position: absolute;
right: 30rpx;
bottom: 50rpx;
width: 80rpx;
height: 80rpx;
z-index: 99;
align-items: center;
justify-content: center;
}
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)