电脑端调用摄像头拍照:从基础到实现
文章目录
- 1. 了解`navigator.mediaDevices.getUserMedia` API
- 2. 创建 HTML 结构
- 3. 编写 JavaScript 代码
- 3.1 打开摄像头
- 3.2 拍照
- 4. 完整代码
- 5. 测试
- 6. 注意事项及部署
在现代 Web 开发中,调用摄像头进行拍照是一个常见的功能,尤其是在需要用户上传头像、进行身份验证或实时交互的场景中。本文将逐步介绍如何在电脑端通过 HTML 和 JavaScript 调用摄像头进行拍照,并上传照片。我们将使用navigator.mediaDevices.getUserMedia API 来实现这一功能。
1. 了解navigator.mediaDevices.getUserMedia API
-
MediaDevices.getUserMedia() API
-
navigator.mediaDevices.getUserMedia是一个现代浏览器提供的 API,用于访问用户的摄像头和麦克风。MediaDevices.getUserMedia()会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D 转换器等等),也可能是其他轨道类型。它返回一个Promise对象,成功后会resolve回调一个MediaStream对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise 会reject回调一个PermissionDeniedError或者NotFoundError。 -
通过这个 API,我们可以请求设备的媒体输入,并将其流式传输到 HTML 的
<video>元素中。
主要步骤
- 请求用户权限:在使用摄像头之前,必须请求用户的权限。
- 获取媒体流:通过
navigator.mediaDevices.getUserMedia获取媒体流。 - 显示视频流:将媒体流绑定到
<video>元素中。 - 拍照:使用
<canvas>元素捕获视频帧并生成图片。
2. 创建 HTML 结构
首先,我们需要创建一个简单的 HTML 页面,包含一个视频元素、一个画布元素和两个按钮(一个用于打开摄像头,一个用于拍照)。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>摄像头拍照</title><style>.btn {display: flex;width: 40%;height: 80px;align-items: center;justify-content: space-around;}.btn div {background-color: purple;color: white;border-radius: 10px;padding: 1rem;}</style></head><body><div></div><video id="video" autoplay style="width: 200px; height: 200px"></video><canvasid="canvas"width="200"height="200"style="border: 5px dotted yellowgreen"></canvas><div class="btn"><div id="open">打开摄像头</div><div id="photo">拍照</div></div></body>
</html>
3. 编写 JavaScript 代码
3.1 打开摄像头
当点击 打开摄像头 按钮时,我们需要调用navigator.mediaDevices.getUserMedia来请求摄像头权限,并将视频流绑定到 <video> 元素中。
let open = document.querySelector("#open");
let video = document.querySelector("#video");open.onclick = () => {let constraints = {video: { width: 200, height: 200 },audio: false,};navigator.mediaDevices.getUserMedia(constraints).then((stream) => {video.srcObject = stream;video.play();}).catch((error) => {console.error("摄像头打开失败:", error);});
};
3.2 拍照
当点击拍照 按钮时,我们需要使用 <canvas> 元素捕获当前视频帧,并将其转换为图片。
let photo = document.querySelector("#photo");
let canvas = document.querySelector("#canvas");photo.onclick = () => {let ctx = canvas.getContext("2d");ctx.drawImage(video, 0, 0, 200, 200);// 将画布内容转换为 Base64 格式let url = canvas.toDataURL("image/png");console.log("Base64 URL: ", url);// 将画布内容转换为 Blob 对象canvas.toBlob((blob) => {let blobUrl = URL.createObjectURL(blob);let file = new window.File([blob], "封面图.png", { type: "image/png" });console.log("Blob URL: ", blobUrl);console.log("创建的新文件:", file);// 使用FormData上传图片let formData = new FormData();formData.append("img", file);fetch("http://localhost:8000", {method: "post",body: formData,}).then((response) => {if (response.ok) {console.log("文件上传成功");} else {console.error("文件上传失败");}}).catch((error) => {console.error("图片上传失败:", error);});});
};
4. 完整代码
将上述 HTML 和 JavaScript 代码组合在一起,完整的 HTML 文件如下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>摄像头拍照</title><style>.btn {display: flex;width: 40%;height: 80px;align-items: center;justify-content: space-around;}.btn div {background-color: purple;color: white;border-radius: 10px;padding: 1rem;}</style></head><body><div></div><video id="video" autoplay style="width: 200px; height: 200px"></video><canvasid="canvas"width="200"height="200"style="border: 5px dotted yellowgreen"></canvas><div class="btn"><div id="open">打开摄像头</div><div id="photo">拍照</div></div><script>let open = document.querySelector("#open");let video = document.querySelector("#video");let photo = document.querySelector("#photo");let canvas = document.querySelector("#canvas");open.onclick = () => {let constraints = {video: { width: 200, height: 200 },audio: false,};navigator.mediaDevices.getUserMedia(constraints).then((stream) => {video.srcObject = stream;video.play();}).catch((error) => {console.error("摄像头打开失败:", error);});};photo.onclick = () => {let ctx = canvas.getContext("2d");ctx.drawImage(video, 0, 0, 200, 200);// 将画布内容转换为Base64格式let url = canvas.toDataURL("image/png");console.log("Base64 URL: ", url);// 将画布内容转换为Blob对象canvas.toBlob((blob) => {let blobUrl = URL.createObjectURL(blob);let file = new window.File([blob], "封面图.png", {type: "image/png",});console.log("Blob URL: ", blobUrl);console.log("创建的新文件:", file);// 使用FormData上传图片let formData = new FormData();formData.append("img", file);fetch("http://localhost:8000", {method: "post",body: formData,}).then((response) => {if (response.ok) {console.log("文件上传成功");} else {console.error("文件上传失败");}}).catch((error) => {console.error("图片上传失败:", error);});});};</script></body>
</html>
5. 测试
测试:在本地运行 HTML 文件,使用 live Server,确保摄像头可以正常打开,并且拍照功能可以正常工作。
截图:


6. 注意事项及部署
- 部署:将 HTML 文件部署到支持 HTTPS 的服务器上,因为
navigator.mediaDevices.getUserMedia需要在 HTTPS 环境下工作。 - 浏览器支持:确保目标浏览器支持
navigator.mediaDevices.getUserMediaAPI。 - 错误处理:在实际应用中,需要对可能出现的错误进行处理,例如用户拒绝权限请求。
相关文章:
电脑端调用摄像头拍照:从基础到实现
文章目录 1. 了解navigator.mediaDevices.getUserMedia API2. 创建 HTML 结构3. 编写 JavaScript 代码3.1 打开摄像头3.2 拍照 4. 完整代码5. 测试6. 注意事项及部署 在现代 Web 开发中,调用摄像头进行拍照是一个常见的功能,尤其是在需要用户上传头像、进…...
部署 DeepSeek R1各个版本所需硬件配置清单
DeepSeek-R1 通过其卓越的推理性能和灵活的训练机制,在 2025 年的春节期间受到了广泛关注。 DeepSeek-R1 是一款高性能的 AI 推理模型,主要通过强化学习技术来增强模型在复杂任务场景下的推理能力。 在本地部署 DeepSeek-R1 时,尤其是完整的…...
Java面试题——事务
65. Spring事务的实现方式和实现原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的。Spring事务实现主要有两种方法:编程式:beginTransaction()、commit()、rollback()等事务管理相关的方法࿰…...
算法18(力扣136)只出现一次的数字
1、问题 给你一个 非空 整数数组 nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 2、示例 (1&…...
SiliconCloud 支持deepseek,送2000w token
SiliconCloud SiliconCloud 邀请奖励持续进行,2000 万 Tokens 送不停! 邀请好友赚 2000 万 Tokens:每成功邀请一位新用户通过手机号码注册,您将获得 2000 万 Tokens;注册即送 2000 万 Tokens:受邀好友作为…...
在nodejs中使用RabbitMQ(六)sharding消息分片
RabbitMQ 的分片插件(rabbitmq_sharding)允许将消息分布到多个队列中,这在消息量很大或处理速度要求高的情况下非常有用。分片功能通过将消息拆分到多个队列中来平衡负载,从而提升消息处理的吞吐量和可靠性。它能够在多个队列之间…...
STM32 I2C通信协议说明
目录 背景 I2C协议 数据的有效性 I2C通信开始和停止条件 I2C数据传输 发送 响应 正常情况: 异常情况: 主机结束接收 写寄存器的标准流程 读寄存器的标准流程 仲裁机制 时钟同步 SDA线的仲裁 程序 背景 对单片机的三大通信中的I2C通信进…...
git bash在github的库中上传或更新本地文件
一、将本地文件上传到 GitHub 仓库 1. 创建 GitHub 仓库 如果你还没有在 GitHub 上创建仓库,首先需要创建一个新的仓库: 登录到 GitHub。点击右上角的 按钮,选择 New repository。给你的仓库起个名字,并选择 Public 或 Privat…...
Keysight E5071C (Agilent) 网络分析仪的特性和规格
安捷伦E5071C网络分析仪 Keysight E5071C网络分析仪 Keysight E5071C (Agilent) 网络分析仪的其他特性和规格包括: 宽动态范围:测试端口动态范围 > 123 dB(典型值) 快速测量速度:41 ms 全 2 端口校准,…...
总结:如何在SpringBoot中使用https协议以及自签证书?
总结:如何在SpringBoot中使用https协议以及自签证书? 前提一:什么是http协议?前提二:什么是https协议?一生成自签证书二 将证书转换为PKCS12格式三 配置SpringBoot(1)修改配置文件&a…...
Golang学习历程【第七篇 闭包type defer panic recover了解time包】
Golang学习历程【第七篇 闭包&type defer panic recover了解】 1. 闭包1.1 闭包的定义1.2 闭包的特点1.3 闭包的示例 2. 类型(type)2.1 自定义类型2.2 类型示例 3. 延迟执行(Defer)3.1 defer 的用法3.2 defer 示例 4. 恐慌(Panic…...
基于SSM+uniapp的数学辅导小程序+LW示例参考
1.项目介绍 系统角色:管理员、普通用户功能模块:用户管理、学习中心、知识分类管理、学习周报管理、口算练习管理、试题管理、考试管理、错题本等技术选型:SSM,Vue(后端管理web),uniapp等测试环…...
利用AI智能体创建云端文档知识库并集成第三方数据源(上)
许多开发者在管理和集成多种云端的数据源时经常面对各种各样的困难,所以希望能够构建一个聊天机器人来协调这些数据源,针对业务问题并提供全面的答案。本文介绍了一种解决方案,帮助大家开发一个能够从文档和数据库中回答查询的聊天机器人&…...
聚铭网络入围2025年度江苏省政府采购信息安全设备协议供货名单
近日,2025年度江苏省党政机关、事业单位及团体组织信息安全设备框架协议采购项目入围结果公布。聚铭网络凭借自身专业实力和技术优势脱颖而出,成功入围22个分包。 此次采购项目是江苏省政府采购领域级别最高、覆盖面最广的项目之一。从资格评选到后期材料…...
vue+springboot+webtrc+websocket实现双人音视频通话会议
前言 最近一些时间我有研究,如何实现一个视频会议功能,但是找了好多资料都不太理想,最终参考了一个文章 WebRTC实现双端音视频聊天(Vue3 SpringBoot) 只不过,它的实现效果里面只会播放本地的mp4视频文件&…...
2025年单片机毕业设计选题物联网计算机电气电子通信类
当然,以下是基于物联网技术设计的20个单片机类题目,旨在考察学生在物联网环境下单片机应用、系统设计、数据传输与处理等方面的能力: 基于物联网的智能家居温度湿度控制系统设计:利用单片机和传感器实现室内环境的温湿度监测&…...
堡垒机调用xshell 无反应
安装sso_client 确认db_path.ini xhsell路径 如图调整为本机安装的路径即可。 实战问题: 操作完成之后 Chrome还是无法调用,使用360浏览器没问题。...
python后端调用Deep Seek API
python后端调用Deep Seek API 需要依次下载 ●Ollama ●Deepseek R1 LLM模型 ●嵌入模型nomic-embed-text / bge-m3 ●AnythingLLM 参考教程: Deepseek R1打造本地化RAG知识库:安装部署使用详细教程 手把手教你:deepseek R1基于 AnythingLLM API 调用本地…...
Easy系列PLC 线性变换功能块(模拟量相关功能块汇总)
线性转换函数S_RTR 线性转换函数S_RTR(SCL和ST代码)_线性函数的scl语言如何编写-CSDN博客文章浏览阅读440次。博客介绍了线性转换函数S_RTR,包括其在PLC中的应用,如何与工艺PID组合使用,以及在张力开环控制中的具体实践。还提到了函数的C99兼容性,并提供了S_RTR的功能块源…...
【VB语言】EXCEL中VB宏的应用
【VB语言】EXCEL中VB宏的应用 文章目录 [TOC](文章目录) 前言一、EXCEL-VB1.实验过程2.代码 二、EXCEL-VB 生成.c.h文件1.实验过程2.代码 四、参考资料总结 前言 1.WPS-VB扩展包 提示:以下是本篇文章正文内容,下面案例可供参考 一、EXCEL-VB 1.实验过…...
【人工智能】如何选择合适的大语言模型,是能否提高工作效率的关键!!!
DeepSeek R1入门指南 导读一、提示语差异1.1 指令侧重点不同1.2 语言风格差异1.3 知识运用引导不同 二、挑选原则2.1 模型选择2.2 提示语设计2.3 避免误区 结语 导读 大家好,很高兴又和大家见面啦!!! 在前面的内容中,…...
Unity使用反射进行Protobuf(CS/SC)协议,json格式
protobuf生成的协议,有挺多协议的.利用反射生成dto进行伪协议的响应 和 发送请求 应用场景: 请求(CS)_后端先写完了,前端还搞完时,可使用此请求,可自测 响应(SC)_可自行构建一个响应,对数据进行测试 // 请求 使用物品 CS message ReqUseItem{optional Opcodes MessageID1[def…...
初学 mybatis
前言 回顾之前 不使用 mybatis 框架,我们是怎么通过Java 操作数据库的 "jdbc" 前提:使用maven 构建的项目 1 添加 关于jdbc 的依赖,以及辅助操作数据库的 commons-dubli jar包 截取 前后端项目 2 添加配置文件里面内容有&…...
java.lang.IllegalArgumentException: 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义
Tomcat 屏蔽错误信息。java.lang.IllegalArgumentException: 在请求目标中找到无效字符。有效字符在RFC 7230和RFC 3986中定义 <h1>HTTP状态 400 - 错误的请求</h1><hr class"line" /><p><b>类型</b> 异常报告</p><p&…...
C语言进阶习题(4结构体)【1】通讯录的实现
目录 1.使用结构体实现通讯录功能2.思路3. 代码实现3.1 test.c3.2 contact.c3.3 contact.h 1.使用结构体实现通讯录功能 主要功能有:显示通讯录信息,增加通讯录中人的信息,删除通讯录中人的信息,查找通信录中信息,修改…...
释放你的元数据:使用 Elasticsearch 的自查询检索器
作者:来自 Elastic Josh Asres 了解如何使用 Elasticsearch 的 “self-quering” 检索器来通过结构化过滤器提高语义搜索的相关性。 在人工智能搜索的世界中,在海量的数据集中高效地找到正确的数据至关重要。传统的基于关键词的搜索在处理涉及自然语言的…...
【Python】如何在 Linux/Windows 系统中设置 PYTHONPATH 环境变量
什么是 PYTHONPATH? PYTHONPATH 是一个环境变量,它告诉 Python 解释器在哪些目录中查找要导入的模块。这对于包含不在标准目录中的自定义模块非常有用。 Linux 系统中设置 PYTHONPATH 环境变量 在 Python 开发环境中,正确设置 PYTHONPATH …...
1.14学习总结
日常刷题单 刷了题目后,对于排序方法更加熟练,手搓代码的速度也得到了提高。 感觉字符串还不熟练,高精度更是云里雾里,上升空间极大。 同时看见今晚有个入门难度的测试,去练了练手,想看看自己是什么成分&…...
【Prometheus】prometheus黑盒监控balckbox全面解析与应用实战
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
游戏引擎学习第101天
回顾当前情况 昨天的进度基本上完成了所有内容,但我们还没有进行调试。虽然我们在运行时做的事情大致上是对的,但还是存在一些可能或者确定的bug。正如昨天最后提到的,既然现在时间晚了,就不太适合开始调试,所以今天我…...
