您的位置:首页 > 娱乐 > 八卦 > 【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

2024/10/6 10:35:19 来源:https://blog.csdn.net/yasyList/article/details/139295208  浏览:    关键词:【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

效果图

在这里插入图片描述
在这里插入图片描述

template

下方的image图片自行寻找替换!

<template><view><camerav-if="!tempImagePath && cameraHeight !== 0":resolution="'high'":frame-size="'large'":device-position="device":flash="flash":style="{position: 'fixed',top: '0',width: cameraWidth + 'px',height: cameraHeight + 'px',}"></camera><imagev-else:src="tempImagePath"mode="widthFix"style="width: 100%"></image><view class="watermark" v-if="cameraHeight !== 0"><view class="time"><text class="times-r">{{ time }}</text><text class="times-date"><text class="year-date">{{ date }}</text><text class="weeks-date">{{ week }}</text></text></view><view class="location_box"><view class="location">{{ address }}</view></view></view><canvastype="2d"id="canvas":style="{position: 'fixed',top: '-10000px',left: '-10000px',width: canvasWidth + 'px',height: canvasHeight + 'px',}"></canvas><view class="handle" id="myContainer"><button class="handle_card" @click="chooseLocation"><imageclass="handle_card_icon":src="require('./image/wz.png')"mode="widthFix"/><view class="handle_card_name">定位</view></button><button class="handle_card" @click="setDevice"><imageclass="handle_card_icon":src="require('./image/qh.png')"mode="widthFix"/><view class="handle_card_name">切换</view></button><button class="handle_ps" @click="takePhoto"><imageclass="handle_ps_image":src="require('./image/ps.png')"mode="widthFix"/><view class="handle_ps_name">拍摄</view></button><button class="handle_card" @click="setFlash"><imageclass="handle_card_icon":src="require('./image/sd.png')"mode="widthFix"/><view class="handle_card_name">闪光</view></button><button class="handle_card" open-type="share"><imageclass="handle_card_icon":src="require('./image/fx.png')"mode="widthFix"/><view class="handle_card_name">分享</view></button></view></view>
</template>

js

开发者秘钥key自行填写,用于定位位置功能!
showToast和showLoading为自行封装的弹窗
如果没有直接用官网的uni.showToast

<script>
const mapSDK = new QQMapWX({key: "", //申请的开发者秘钥key
});
import { showToast, showLoading } from "@/js/common.js";
export default {data() {return {device: "back",flash: "",date: "",time: "",week: "",address: "",addressName: "",cameraWidth: 0,cameraHeight: 0,canvasWidth: 0,canvasHeight: 0,tempImagePath: "",timer: null,};},created() {const systemInfo = uni.getSystemInfoSync();const screenWidth = systemInfo.screenWidth;const screenHeight = systemInfo.screenHeight;const statusBarHeight = systemInfo.statusBarHeight;const menuButtonInfo = uni.getMenuButtonBoundingClientRect();const cameraWidth = screenWidth;uni.createSelectorQuery().select("#myContainer").boundingClientRect((rect) => {const cameraHeight =screenHeight -statusBarHeight -menuButtonInfo.height -(menuButtonInfo.top - systemInfo.statusBarHeight) * 2 -rect.height;this.cameraWidth = cameraWidth;this.cameraHeight = cameraHeight;this.getTime();this.getLocation();}).exec();},methods: {// 获取并更新时间的方法getTime() {if (this.timer) {clearInterval(this.timer);this.timer = null;}this.timer = setInterval(() => {const timeData = this.formatTime();this.date = timeData.date;this.time = timeData.time;this.week = timeData.week;}, 1000);},// 获取并更新位置信息的方法getLocation() {uni.getLocation({success: (Locares) => {mapSDK.reverseGeocoder({location: {latitude: Locares.latitude,longitude: Locares.longitude,},get_poi: 1,success:(res)=> {this.address = res.address;}})})}})},// 拍摄事件takePhoto() {const ctx = uni.createCameraContext();ctx.takePhoto({quality: "high",success: (res) => {this.canvasWidth = res.width;this.canvasHeight = res.height;this.tempImagePath = res.tempImagePath;this.addWatermark(this.tempImagePath).then((addWatermark) => {uni.saveImageToPhotosAlbum({filePath: addWatermark,success: () => {showToast("保存成功");this.tempImagePath = "";},});}).catch((e) => {showToast(e);})}})},/*** 给图片添加水印*/addWatermark(imageUrl) {return new Promise((resolve, reject) => {showLoading("图片生成中...");const query = uni.createSelectorQuery();query.select("#canvas").fields({node: true,}).exec((res) => {const canvas = res[0].node;const ctx = canvas.getContext("2d");const { canvasWidth, canvasHeight } = this;canvas.width = canvasWidth;canvas.height = canvasHeight;// 绘制背景图片const image = canvas.createImage();image.src = imageUrl;image.onload = () => {const sizeX = this.canvasWidth / 375;ctx.drawImage(image, 0, 0);ctx.font = `${35 * sizeX}px 黑体`;ctx.fillStyle = "#ffffff";ctx.textBaseline = "bottom";// 绘制时间ctx.fillText(this.time, 10 * sizeX, canvasHeight - 30 * sizeX);const timeWidth = ctx.measureText(this.time).width;// 绘制边框线条ctx.beginPath();ctx.lineCap = "round";ctx.moveTo(timeWidth + 16 * sizeX, canvasHeight - 59 * sizeX);ctx.lineTo(timeWidth + 16 * sizeX, canvasHeight - 36 * sizeX);ctx.lineWidth = 3 * sizeX;ctx.strokeStyle = "#7FCAF4";ctx.stroke();// 绘制年月日ctx.font = `${12 * sizeX}px 黑体`;ctx.fillText(this.date,timeWidth + 22 * sizeX,canvasHeight - 49 * sizeX);// 绘制周几ctx.fillText(this.week,timeWidth + 22 * sizeX,canvasHeight - 34 * sizeX);// 绘制地址ctx.font = `${14 * sizeX}px 黑体`;ctx.fillText(this.address, 10 * sizeX, canvasHeight - 10 * sizeX);uni.canvasToTempFilePath({canvas,success: (res) => {uni.hideLoading();console.log(canvas, res.tempFilePath, 199);resolve(res.tempFilePath);},fail: (e) => {uni.hideLoading();reject(new Error(JSON.stringify(e)));},});};});});},/*** 切换摄像头*/setDevice() {this.device = this.device === "back" ? "front" : "back";const text = this.device === "back" ? "后置" : "前置";showToast(`摄像头${text}`)},/*** 闪光灯开关*/setFlash() {this.flash = this.flash === "torch" ? "off" : "torch";},/*** 选择位置信息*/chooseLocation() {uni.chooseLocation({success: (res) => {this.address = res.address;},fail(err) {console.log(err);},});},formatTime() {const date = new Date();const year = date.getFullYear();const month = date.getMonth() + 1;const day = date.getDate();const weekDay = ["日", "一", "二", "三", "四", "五", "六"][date.getDay()];const hour = date.getHours();const minute = date.getMinutes();// const second = date.getSeconds(); 如果需要秒显示,自行修改const formatNumber = (n) => {const s = n.toString();return s[1] ? s : "0" + s;};return {date: [year, month, day].map(formatNumber).join("-"),time: [hour, minute].map(formatNumber).join(":"),week: "星期" + weekDay,};},},
};
</script>

sass样式

<style lang="scss">
.handle {position: fixed;bottom: 0;width: 100%;height: 15%;display: flex;justify-content: space-around;align-items: center;font-size: 28rpx;background: rgb(255, 255, 255);padding-bottom: constant(safe-area-inset-bottom);padding-bottom: env(safe-area-inset-bottom);
}.handle_ps,
.handle_card {display: flex;flex-direction: column;text-align: center;height: 75px;line-height: 25px;background: #ffffff;padding: 0;font-size: 25rpx;
}
.handle_ps {&::after {border: none;}
}
.handle_card::after {border: none;
}
.handle_ps_image {width: 50px;height: 50px;
}
.handle_card_name {font-size: 25rpx;
}.handle_card_icon {width: 40px;height: 40px;margin: 5px;
}
.watermark {position: fixed;bottom: 16%;left: 10px;color: #fff;
}
.location_box {display: flex;line-height: 25px;height: 25px;
}
.time {display: flex;.times-r {position: relative;font-size: 75rpx;padding-right: 25rpx;&::before {content: "";position: absolute;width: 6rpx;height: 53%;border-radius: 10rpx;background: #7fcaf4;right: 8rpx;top: 50%;transform: translateY(-50%);}}.times-date {padding-left: 5rpx;display: flex;flex-direction: column;justify-content: center;font-size: 24rpx;.year-date,.weeks-date {display: block;}}
}
.time,
.location {color: #fff;
}
</style>

第二种(新)不用再写一遍html,直接初始化canvas生成

template:

新增以下canvas,作为初始化用
<canvastype="2d"id="canvasView":style="{width: cameraWidth + 'px',height: cameraHeight + 'px',}"
></canvas>老方法别动:12个canvas
<canvastype="2d"id="canvas":style="{width: canvasWidth + 'px',height: canvasHeight + 'px',}"
></canvas>

关于这二者的区别就是:
前面是没有拍照的时候做预览用的。
第二个是因为拍照后 需要把照片合并上去。就这原因,没办法。

image修改:

<imagev-else:src="tempImagePath"mode="widthFix"style="width: 100%; position: absolute"
/>

template全代码

<template><view><camerav-if="!tempImagePath && cameraHeight !== 0":resolution="'high'":frame-size="'large'":device-position="device":flash="flash":style="{position: 'fixed',top: '0',width: cameraWidth + 'px',height: cameraHeight + 'px',}"></camera><imagev-else:src="tempImagePath"mode="widthFix"style="width: 100%; position: absolute"/><canvastype="2d"id="canvasView":style="{width: cameraWidth + 'px',height: cameraHeight + 'px',}"></canvas><canvastype="2d"id="canvas":style="{width: canvasWidth + 'px',height: canvasHeight + 'px',display: 'none',}"></canvas><view class="handle" id="myContainer"><button class="handle_card" @click="chooseLocation"><imageclass="handle_card_icon"src=""mode="widthFix"/><view class="handle_card_name">定位</view></button><button class="handle_card" @click="setDevice"><imageclass="handle_card_icon"src=""mode="widthFix"/><view class="handle_card_name">切换</view></button><button class="handle_ps" @click="takePhoto"><imageclass="handle_ps_image"src=""mode="widthFix"/><view class="handle_ps_name">拍摄</view></button><button class="handle_card" @click="setFlash"><imageclass="handle_card_icon"src=""mode="widthFix"/><view class="handle_card_name">闪光</view></button><button class="handle_card" open-type="share"><imageclass="handle_card_icon"src=""mode="widthFix"/><view class="handle_card_name">分享</view></button></view></view>
</template>

js全代码
还是自己看吧,这里不废话

<script>
import { locationToAddress } from "@/js/location";
import { showToast, showLoading } from "@/js/common.js";
export default {data() {return {device: "back",flash: "",date: "",time: "",week: "",address: "",addressName: "",cameraWidth: 0,cameraHeight: 0,canvasWidth: 0,canvasHeight: 0,tempImagePath: "",timer: null,};},created() {uni.createSelectorQuery().select("#myContainer").boundingClientRect((rect) => {const systemInfo = uni.getSystemInfoSync();const screenWidth = systemInfo.screenWidth;const screenHeight = systemInfo.screenHeight;const statusBarHeight = systemInfo.statusBarHeight;const menuButtonInfo = uni.getMenuButtonBoundingClientRect();const cameraWidth = screenWidth;const cameraHeight =screenHeight -statusBarHeight -menuButtonInfo.height -(menuButtonInfo.top - systemInfo.statusBarHeight) * 2 -rect.height -6;this.cameraWidth = cameraWidth;this.cameraHeight = cameraHeight;this.getTime();this.getLocation();}).exec();},methods: {// 画图drawCanvas(canvasId, type = "init") {const _this = this;return new Promise((resolve, reject) => {const query = uni.createSelectorQuery();query.select(canvasId).fields({node: true,}).exec((res) => {const canvas = res[0].node;const ctx = canvas.getContext("2d");let camerW = null;let camerH = null;if (type === "init") {camerW = this.cameraWidth;camerH = this.cameraHeight;const drp = uni.getWindowInfo().pixelRatio;canvas.width = camerW * drp;canvas.height = camerH * drp;ctx.scale(drp, drp);draw();} else {showLoading("图片生成中...");camerW = this.canvasWidth;camerH = this.canvasHeight;canvas.width = camerW;canvas.height = camerH;const image = canvas.createImage();image.src = this.tempImagePath;image.onload = () => {ctx.drawImage(image, 0, 0);draw();};}function draw() {const sizeX = camerW / 375;ctx.font = `${35 * sizeX}px 黑体`;ctx.fillStyle = "#ffffff";ctx.textBaseline = "bottom";// 绘制时间ctx.fillText(_this.time, 10 * sizeX, camerH - 30 * sizeX);const timeWidth = ctx.measureText(_this.time).width;// 绘制边框线条ctx.beginPath();ctx.lineCap = "round";ctx.moveTo(timeWidth + 16 * sizeX, camerH - 59 * sizeX);ctx.lineTo(timeWidth + 16 * sizeX, camerH - 36 * sizeX);ctx.lineWidth = 1.7 * sizeX;ctx.strokeStyle = "#A9A9A8";ctx.stroke();// 绘制年月日ctx.font = `${12 * sizeX}px 黑体`;ctx.fillText(_this.date,timeWidth + 22 * sizeX,camerH - 49 * sizeX);// 绘制周几ctx.fillText(_this.week,timeWidth + 22 * sizeX,camerH - 34 * sizeX);// 绘制天气ctx.fillText("多云27℃",timeWidth + 60 * sizeX,camerH - 34 * sizeX);// 绘制地址ctx.font = `${14 * sizeX}px 黑体`;ctx.fillText(_this.address, 10 * sizeX, camerH - 10 * sizeX);uni.canvasToTempFilePath({canvas,success: (res) => {uni.hideLoading();resolve(res.tempFilePath);},fail: (e) => {uni.hideLoading();reject(new Error(JSON.stringify(e)));},});}});});},// 获取并更新时间的方法getTime() {this.timeSet();if (this.timer) {clearInterval(this.timer);this.timer = null;}this.timer = setInterval(() => {this.timeSet();this.drawCanvas("#canvasView", "init");}, 1000);},// 时间更新timeSet() {const timeData = this.formatTime();this.date = timeData.date;this.time = timeData.time;this.week = timeData.week;},// 获取并更新位置信息的方法getLocation() {uni.getLocation({success: (Locares) => {locationToAddress(Locares).then((res) => {this.address = res.address;// 初始化画图this.drawCanvas("#canvasView", "init");});},});},// 拍摄事件takePhoto() {const ctx = uni.createCameraContext();ctx.takePhoto({quality: "high",success: (res) => {this.canvasWidth = res.width;this.canvasHeight = res.height;this.tempImagePath = res.tempImagePath;this.drawCanvas("#canvas", "draw").then((imgPath) => {uni.saveImageToPhotosAlbum({filePath: imgPath,complete: (e) => {showToast(e.errMsg.includes('fail cancel') ? "保存失败":'保存成功');this.tempImagePath = "";},});}).catch((e) => {showToast(e);});},});},//  切换摄像头setDevice() {this.device = this.device === "back" ? "front" : "back";const text = this.device === "back" ? "后置" : "前置";showToast(`摄像头${text}`);},//  闪光灯开关setFlash() {this.flash = this.flash === "torch" ? "off" : "torch";},// 选择位置信息chooseLocation() {uni.chooseLocation({success: (res) => {this.address = res.address;this.drawCanvas("#canvasView", "init");}});},// 时间转换formatTime() {const date = new Date();const [year, month, day, hour, minute] = [date.getFullYear(),String(date.getMonth() + 1).padStart(2, "0"),String(date.getDate()).padStart(2, "0"),String(date.getHours()).padStart(2, "0"),String(date.getMinutes()).padStart(2, "0"),];const weekDay = ["日", "一", "二", "三", "四", "五", "六"][date.getDay()];return {date: `${year}-${month}-${day}`,time: `${hour}:${minute}`,week: `星期${weekDay}`,};},},onUnload() {clearInterval(this.timer);},
};
</script>

除了新增合并drawCanvas函数,其他的没变。
这样就不用html也写一遍了

在这里插入图片描述
感谢你的阅读,如对你有帮助请收藏+关注!
只分享干货实战精品从不啰嗦!!!
如某处不对请留言评论,欢迎指正~
博主可收徒、常玩QQ飞车,可一起来玩玩鸭~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com