当前位置: 首页 > news >正文

【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飞车,可一起来玩玩鸭~

相关文章:

  • Vue CLI:Vue CLI是一个强大的工具,可以帮助开发者快速地创建和管理Vue项目。我们可以讨论它的一些核心特性,比如热重载、懒加载等
  • 【云原生】kubernetes中pod的生命周期、探测钩子的实战应用案例解析
  • C++入门5——C/C++动态内存管理(new与delete)
  • 使用 C++ 在当前进程中获取指定模块的基址
  • HackTheBox-Machines--Sense
  • 标题:Go语言中的YAML魔法:轻松配置你的环境
  • Python打印当前目录下,所有文件名的首字母
  • Centos7安装Docker和DockerCompose
  • DynamiCrafter ComfyUI 教程 | 对图片转视频的效果进行精细化控制
  • Spark_SparkOnHive_海豚调度跑任务写入Hive表失败解决
  • Mac/Linux getline 无法读取文件内容(读取内容无法显示)
  • 【数据库】MySQL表的操作
  • jenkins的简单使用
  • 函数尾调用优化
  • 面试官:对于MQ中的消息丢失你是如何理解的?
  • CSS中外联样式表代表的含义
  • Docker入门(二) - Dockerfile
  • java 多线程基础, 我觉得还是有必要看看的
  • java8 Stream Pipelines 浅析
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • laravel5.5 视图共享数据
  • PermissionScope Swift4 兼容问题
  • 仿天猫超市收藏抛物线动画工具库
  • 机器学习学习笔记一
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 浅谈Golang中select的用法
  • 如何学习JavaEE,项目又该如何做?
  • 什么软件可以剪辑音乐?
  • Java总结 - String - 这篇请使劲喷我
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • 选择阿里云数据库HBase版十大理由
  • ​第20课 在Android Native开发中加入新的C++类
  • #1015 : KMP算法
  • #Linux(make工具和makefile文件以及makefile语法)
  • %check_box% in rails :coditions={:has_many , :through}
  • (Charles)如何抓取手机http的报文
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (二)c52学习之旅-简单了解单片机
  • (二)PySpark3:SparkSQL编程
  • (七)Knockout 创建自定义绑定
  • (五)MySQL的备份及恢复
  • .NET Core 中插件式开发实现
  • .NET 命令行参数包含应用程序路径吗?
  • .NET单元测试
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • /run/containerd/containerd.sock connect: connection refused
  • @Bean, @Component, @Configuration简析
  • @ConfigurationProperties注解对数据的自动封装
  • @DS 多数据源 + @Transactional(rollbackFor = Exception.class) 导致@DS 多数据源没法使用
  • @RequestBody与@RequestParam
  • []C/C++读取串口接收到的数据程序