Hbuilder 上的水印相机实现方案 (vue3 + vite + hbuilder)

效果

在这里插入图片描述

在这里插入图片描述

思路

  • 通过 live-pusher 这个视频推流的组件来获取摄像头
  • 拿到视频的一帧图片之后,跳转到正常的 vue 页面,通过 canvas 来处理图片+水印

源码

live-pusher 这个组件必须是 nvue

至于什么是 nvue,看这个官方文档吧 https://uniapp.dcloud.net.cn/tutorial/nvue-outline.html

// index.nvue
<template><view class="pengke-camera" :style="{ width: windowWidth, height: windowHeight }"><!-- live-pusher 显示实时画面 --><live-pusherid="livePusher"class="livePusher"mode="FHD"device-position="back":muted="true":enable-camera="true":enable-mic="false":auto-focus="true":zoom="false":style="{ width: windowWidth, height: windowHeight }"></live-pusher><!-- 拍照按钮 --><view class="menu"><cover-image class="menu-snapshot" @tap="snapshot" src="./icon/snapshot.png"></cover-image></view></view>
</template><script>
export default {data() {return {windowWidth: '',windowHeight: '',livePusher: null}},onLoad() {this.initCamera()},onReady() {const pages = getCurrentPages()const currentPage = pages[pages.length - 1]this.livePusher = uni.createLivePusherContext('livePusher', currentPage)this.livePusher.startPreview()},methods: {initCamera() {uni.getSystemInfo({success: res => {this.windowWidth = res.windowWidththis.windowHeight = res.windowHeight}})},snapshot() {this.livePusher.snapshot({success: e => {const path = e.message.tempImagePathuni.navigateTo({url: `/pages/camera/preview?img=${encodeURIComponent(path)}`})},fail: err => {console.error('拍照失败', err)}})}}
}
</script><style lang="less">
.pengke-camera {position: relative;.livePusher {position: absolute;top: 0;left: 0;width: 100%;height: 100%;}.menu {position: absolute;bottom: 60rpx;left: 0;right: 0;display: flex;justify-content: center;align-items: center;z-index: 10;pointer-events: auto;.menu-snapshot {width: 130rpx;height: 130rpx;background-color: #fff;border-radius: 65rpx;box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.2);}}
}</style>

预览文件 preview.vue

// preview.vue
<template><view class="preview-page"><!-- 可见 canvas 显示图 + 水印 --><canvascanvas-id="watermarkCanvas"id="watermarkCanvas"class="watermark-canvas":style="{ width: screenWidth + 'px', height: screenHeight + 'px' }"></canvas><!-- 操作按钮 --><view class="preview-actions"><button class="action-btn cancel-btn" @click="goBack">取消</button><button class="action-btn confirm-btn" @click="exportImage">确认</button></view></view>
</template><script setup>
import { ref, nextTick, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import message from '@/utils/message'const imgUrl = ref('')
const canvasWidth = ref(0)
const canvasHeight = ref(0)
const currentTime = ref('')
const locationText = ref('正在获取位置信息...')const screenWidth = uni.getSystemInfoSync().windowWidth
const screenHeight = uni.getSystemInfoSync().windowHeightonLoad((options) => {if (options.img) {imgUrl.value = decodeURIComponent(options.img)initImage()}updateTime()updateLocation()
})function updateTime() {const now = new Date()currentTime.value = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
}function updateLocation() {uni.getLocation({type: 'wgs84',success: (res) => {locationText.value = `经度: ${res.longitude}  纬度: ${res.latitude}`drawCanvas()},fail: () => {locationText.value = '位置信息获取失败'drawCanvas()}})
}function initImage() {uni.getImageInfo({src: imgUrl.value,success(res) {canvasWidth.value = res.widthcanvasHeight.value = res.heightdrawCanvas()},fail(err) {console.error('图片信息获取失败:', err)}})
}// 绘制预览 canvas
function drawCanvas() {if (!imgUrl.value || !canvasWidth.value || !canvasHeight.value) returnnextTick(() => {const ctx = uni.createCanvasContext('watermarkCanvas')// 绘制原图ctx.drawImage(imgUrl.value, 0, 0, screenWidth, screenHeight)// 设置水印样式ctx.setFontSize(16)ctx.setFillStyle('white')ctx.setTextAlign('left')ctx.fillText(currentTime.value, 20, screenHeight - 160)ctx.setFontSize(16)ctx.fillText(locationText.value, 20, screenHeight - 120)ctx.draw()})
}// 点击确认导出
function exportImage() {// 显示加载提示uni.showLoading({title: '导出中...',mask: true  // 防止点击遮罩层关闭})uni.canvasToTempFilePath({canvasId: 'watermarkCanvas',destWidth: canvasWidth.value,destHeight: canvasHeight.value,success: (res) => {// 隐藏加载提示uni.hideLoading()console.log('导出成功:', res.tempFilePath)message.success(`导出成功! 文件路径为 ${res.tempFilePath}`)uni.previewImage({ urls: [res.tempFilePath] })},fail: (err) => {// 隐藏加载提示uni.hideLoading()console.error('导出失败:', err)uni.showToast({ title: '导出失败', icon: 'none' })}})
}function goBack() {uni.navigateBack()
}
</script><style scoped lang="scss">
.preview-page {width: 100vw;height: 100vh;position: relative;background: #000;overflow: hidden;
}.watermark-canvas {position: absolute;left: 0;top: 0;z-index: 1;
}.preview-actions {position: fixed;left: 0;right: 0;bottom: 60rpx;display: flex;justify-content: center;gap: 40rpx;z-index: 10;
}.action-btn {padding: 0 40rpx;height: 80rpx;line-height: 80rpx;border-radius: 40rpx;font-size: 28rpx;background: #fff;color: #333;border: none;opacity: 0.9;
}.cancel-btn {background: #eee;
}.confirm-btn {background: #19be6b;color: #fff;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark,IDEA编写Maven项目

IDEA中编写Maven项目 1.打开IDEA新建项目2.选择java语言&#xff0c;构建系统选择Maven 3.IDEA中配置Maven 注&#xff1a;这些文件都是我们老师帮我们在网上找了改动后给我们的&#xff0c;大家可自行在网上查找 编写代码测试HDFS连接 1.在之前创建的pom.xml文件中添加下…

初识Redis · C++客户端set和zset

目录 前言&#xff1a; set sadd sismember smembers spop scard sinter sinterstore zset zadd zrange zcard zrem zrank zscore 前言&#xff1a; 前文我们已经介绍了string list hash在Redis-plus-plus的使用&#xff0c;本文我们开始介绍set和zset在redis-plus-pl…

sed命令笔记250419

sed命令笔记250419 sed&#xff08;Stream Editor&#xff09;是 Linux/Unix 系统中强大的流编辑器&#xff0c;主要用于对文本进行过滤和转换&#xff08;按行处理&#xff09;。它支持正则表达式&#xff0c;适合处理文本替换、删除、插入等操作。以下是 sed 的详细解析&…

ubuntu-24.04.2-live-server-arm64基于cloud-init实现分区自动扩容(LVM分区模式)

1. 环境 虚拟机镜像ISO&#xff1a;ubuntu-24.04.2-live-server-arm64.iso 2. 定制cloud-init镜像 2.1 安装OS 基于ubuntu-24.04.2-live-server-arm64.iso&#xff0c;通过virt-manager安装操作系统&#xff0c;语言建议选择英文&#xff0c;分区选择基于LVM的自动分区&…

vue3专题1------父组件中更改子组件的属性

理解 Vue 3 中父组件如何引用子组件的属性是一个很重要的概念。 这里涉及到 defineExpose 和 ref 这两个关键点。 方法&#xff1a;使用 defineExpose 在子组件中暴露属性&#xff0c;然后在父组件中使用 ref 获取子组件实例并访问暴露的属性。 下面我将详细解释这个过程&…

数据仓库分层架构解析:从理论到实战的完整指南​​

数据仓库分层是构建高效数据体系的核心方法论。本文系统阐述ODS、DWD、DWS、ADS四层架构的设计原理&#xff0c;结合电商用户行为分析场景&#xff0c;详解各层功能及协作流程&#xff0c;并给出分层设计的原则与避坑指南&#xff0c;帮助读者掌握分层架构的落地方法。 一、为什…

从零搭建一套前端开发环境

一、基础环境搭建 1.NVM(Node Version Manager)安装 简介 nvm&#xff08;Node Version Manager&#xff09; 是一个用于管理多个 Node.js 版本的工具&#xff0c;允许开发者在同一台机器上轻松安装、切换和使用不同版本的 Node.js。它特别适合需要同时维护多个项目&#xff…

计算机组成原理笔记(十六)——4.1基本算术运算的实现

计算机中最基本的算术运算是加法运算&#xff0c;加、减、乘、除运算最终都可以归结为加法运算。 4.1.1加法器 一、加法器的基本单元 加法器的核心单元是 全加器&#xff08;Full Adder, FA&#xff09;&#xff0c;而所有加法器都由 半加器&#xff08;Half Adder, HA&…

利用Qt创建一个模拟问答系统

界面&#xff1a; 添加了聊天显示区域&#xff08;QTextEdit&#xff09; 添加了发送按钮和清空对话按钮 优化了布局和窗口大小添加了时间戳显示 2、功能&#xff1a; 支持实时对话可以清空对话历史 支持按回车发送消息 添加了简单的关键词匹配响应系统 交互体验&#x…

神经光子渲染:物理级真实感图像生成——从麦克斯韦方程到深度学习

一、技术背景与核心突破 2025年&#xff0c;神经光子渲染&#xff08;Photonic Neural Rendering, PNR&#xff09;技术通过物理光学方程与神经辐射场的深度融合&#xff0c;在AIGC检测工具&#xff08;如GPTDetector 5.0&#xff09;的识别准确率从98%降至12%。该技术突破性地…

Linux中手动安装7-Zip软件文档

7zip位于EPEL源中&#xff0c;如果服务器可以联网或者配置了本地EPEL源则可以直接安装 yum install p7zip p7zip-plugins -y对于无法联网且没有配置本地EPEL源的服务器&#xff0c;可以通过官网下载安装包后&#xff0c;上传至服务器&#xff0c;手动安装 ## 下载地址&#x…

[密码学基础]GM/T 0018-2023 密码设备应用接口规范深度解析:技术革新与开发者实践

GM/T 0018-2023 密码设备应用接口规范深度解析&#xff1a;技术革新与开发者实践 GM/T 0018-2023《密码设备应用接口规范》是中国密码行业的重要标准&#xff0c;于2023年12月4日发布&#xff0c;2024年6月1日正式实施&#xff0c;替代了2012年版标准。该标准旨在规范密码设备…

8.QT-按钮类控件|Push Button|Radio Button|Check Box|Tool Button(C++)

Push Button 使⽤ QPushButton 表⽰⼀个按钮.这也是当前我们最熟悉的⼀个控件了. QPushButton 继承⾃ QAbstractButton .这个类是⼀个抽象类.是其他按钮的⽗类 在Qt Designer中也能够看到这⾥的继承关系 属性说明text按钮中的⽂本icon按钮中的图标iconSize按钮中图标的尺⼨sh…

CFIS-YOLO:面向边缘设备的木材缺陷检测轻量级网络解析

论文地址:https://arxiv.org/pdf/2504.11305 目录 一、论文核心贡献 二、创新点详解 2.1 CARAFE动态上采样 工作原理 优势对比 2.2 C2f_FNB轻量模块 计算效率 2.3 Inner-SIoU损失函数 三、实验验证 3.1 消融实验 3.2 对比实验 四、应用部署 4.1 边缘设备部署流程…

BUUCTF PWN刷题笔记(1-9)

才知道&#xff0c;由于栈对齐&#xff0c;直接动调看栈估计会错&#xff0c;用cyclic看 1.test_your_nc NC连接一下&#xff0c;这个网站似乎直接访问是不中的&#xff0c;怀疑是没开启web的端口。NC链接输入cat flag就OK了&#xff0c;应该只是让我这样的小菜鸟培养自信用的…

C#处理网络传输中不完整的数据流

1、背景 在读取byte数组的场景&#xff08;例如&#xff1a;读取文件、网络传输数据&#xff09;中&#xff0c;特别是网络传输的场景中&#xff0c;非常有可能接收了不完整的byte数组&#xff0c;在将byte数组转换时&#xff0c;因字符的缺失/增多&#xff0c;转为乱码。如下…

PostgreSQL 用户资源管理

PostgreSQL 用户资源管理 PostgreSQL 提供了多种机制来管理和限制用户对数据库资源的使用&#xff0c;以下是全面的资源管理方法&#xff1a; 1 连接限制 1.1 限制最大连接数 -- 在 postgresql.conf 中设置 max_connections 100 -- 全局最大连接数-- 为特定用户设置连接限…

新书速览|OpenCV计算机视觉开发实践:基于Qt C++

《OpenCV计算机视觉开发实践:基于Qt C》 本书内容 OpenCV是计算机视觉领域的开发者必须掌握的技术。《OpenCV计算机视觉开发实践:基于Qt C》基于 OpenCV 4.10与Qt C进行编写&#xff0c;全面系统地介绍OpenCV的使用及实战案例&#xff0c;并配套提供全书示例源码、PPT课件与作…

【上位机——MFC】消息映射机制

消息映射机制 Window消息分类消息映射机制的使用代码示例 MFC框架利用消息映射机制把消息、命令与它们的处理函数映射起来。具体实现方法是在每个能接收和处理消息的类中&#xff0c;定义一个消息和消息函数指针对照表&#xff0c;即消息映射表。 在不重写WindowProc虚函数的大…

docker学习笔记2-最佳实践

一、在容器中启动mysql的最佳实践 &#xff08;一&#xff09;查找目录 1、mysql的配置文件路径 /etc/mysql/conf.d 2、mysql的数据目录 /var/lib/mysql 3、环境变量 4、端口 mysql的默认端口3306。 &#xff08;二&#xff09;启动命令 docker run -d -p 3306:3306 …