包含Javascript的HTML静态页面调取本机摄像头

news2025/6/3 22:04:16

在实际业务开发中,需要在带有摄像头的工作机上拍摄施工现场工作过程的图片,然后上传到服务器备存。

这便需要编写可以运行在浏览器上的代码,并在代码中实现Javascript调取摄像头、截取帧保存为图片的功能。

为了使用户更快掌握JS调取摄像头的实现机制,现将其与服务器端连接的代码剥离,仅展示包念JavaScript调用摄像头的HTML代码。

JsInvokeVideo.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>摄像头访问示例</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 20px;
        }
        .container {
            max-width: 800px;
            margin: 0 auto;
        }
        video {
            width: 100%;
            max-width: 640px;
            background-color: #000;
            border-radius: 8px;
        }
        canvas {
            display: none;
        }
        .controls {
            margin-top: 20px;
        }
        button {
            padding: 10px 20px;
            margin: 5px;
            font-size: 16px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
        }
        button:hover {
            background-color: #45a049;
        }
        #captureButton {
            background-color: #f44336;
        }
        #captureButton:hover {
            background-color: #d32f2f;
        }
        #downloadLink {
            display: none;
            margin-top: 10px;
            text-decoration: none;
            color: #2196F3;
        }
        .captured-image {
            margin-top: 20px;
            max-width: 100%;
            border-radius: 8px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>摄像头访问示例</h1>
        
        <video id="videoElement" autoplay></video>
        <canvas id="canvasElement"></canvas>
        
        <div class="controls">
            <button id="startButton">启动摄像头</button>
            <button id="stopButton" disabled>停止摄像头</button>
            <button id="captureButton" disabled>拍照</button>
            <a id="downloadLink" href="#" download="captured-image.jpg">下载图片</a>
        </div>
        
        <img id="capturedImage" class="captured-image" src="" alt="拍摄的照片">
    </div>

    <script>
        // 获取DOM元素
        const videoElement = document.getElementById('videoElement');
        const canvasElement = document.getElementById('canvasElement');
        const startButton = document.getElementById('startButton');
        const stopButton = document.getElementById('stopButton');
        const captureButton = document.getElementById('captureButton');
        const downloadLink = document.getElementById('downloadLink');
        const capturedImage = document.getElementById('capturedImage');
        
        // 存储摄像头流
        let stream = null;
        
        // 启动摄像头
        startButton.addEventListener('click', async () => {
            try {
                // 请求媒体设备
                stream = await navigator.mediaDevices.getUserMedia({ 
                    video: { width: 640, height: 480 },
                    audio: false
                });
                
                // 将流连接到视频元素
                videoElement.srcObject = stream;
                
                // 更新按钮状态
                startButton.disabled = true;
                stopButton.disabled = false;
                captureButton.disabled = false;
                
                console.log('摄像头已启动');
            } catch (error) {
                console.error('访问摄像头时出错:', error);
                alert('无法访问摄像头,请确保您已授予权限。');
            }
        });
        
        // 停止摄像头
        stopButton.addEventListener('click', () => {
            if (stream) {
                // 停止所有轨道
                stream.getTracks().forEach(track => {
                    track.stop();
                });
                
                // 清除视频源
                videoElement.srcObject = null;
                
                // 更新按钮状态
                startButton.disabled = false;
                stopButton.disabled = true;
                captureButton.disabled = true;
                
                console.log('摄像头已停止');
            }
        });
        
        // 拍照
        captureButton.addEventListener('click', () => {
            const context = canvasElement.getContext('2d');
            
            // 设置canvas尺寸与视频相同
            canvasElement.width = videoElement.videoWidth;
            canvasElement.height = videoElement.videoHeight;
            
            // 将当前视频帧绘制到canvas
            context.drawImage(videoElement, 0, 0, canvasElement.width, canvasElement.height);
            
            // 显示拍摄的图片
            const imageDataURL = canvasElement.toDataURL('image/jpeg');
            capturedImage.src = imageDataURL;
            
            // 启用下载链接
            downloadLink.href = imageDataURL;
            downloadLink.style.display = 'inline-block';
            
            console.log('照片已拍摄');
        });
        
        // 页面关闭时停止摄像头
        window.addEventListener('beforeunload', () => {
            if (stream) {
                stream.getTracks().forEach(track => {
                    track.stop();
                });
            }
        });
    </script>
</body>
</html>

无须配置服务器,将上述代码保存为JsInvokeVideo.html,双击运行即可。

注意:编辑该html文件时一定要保存编码为UTF-8,否则运行时会显示乱码,如下所示:

用文本文件打开该JsInvokeVideo.html文件,点击“另存为”,选择编码为“UTF-8”,重新运行会显示正常:

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

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

相关文章

PCB设计实践(三十一)PCB设计中机械孔的合理设计与应用指南

一、机械孔的基本概念与分类 机械孔是PCB设计中用于实现机械固定、结构支撑、散热及电气连接的关键结构元件&#xff0c;其分类基于功能特性、制造工艺和应用场景的差异&#xff0c;主要分为以下几类&#xff1a; 1. 金属化机械孔 通过电镀工艺在孔内壁形成导电层&#xff0c;…

【Linux篇章】Linux 进程信号2:解锁系统高效运作的 “隐藏指令”,开启性能飞跃新征程(精讲捕捉信号及OS运行机制)

本篇文章将以一个小白视角&#xff0c;通俗易懂带你了解信号在产生&#xff0c;保存之后如何进行捕捉&#xff1b;以及在信号这个话题中&#xff1b;OS扮演的角色及背后是如何进行操作的&#xff1b;如何理解用户态内核态&#xff1b;还有一些可以引出的其他知识点&#xff1b;…

多功能秒达开源工具箱源码|完全开源的中文工具箱

源码介绍 完全开源的中文工具箱永远的自由软件轻量级运行全平台支持&#xff08;包括ARMv8&#xff09;类似GPT的智能支持高效UI高度集成提供Docker映像和便携式版本支持桌面版开源插件库 下载地址 百度网盘下载 提取码&#xff1a;p9ck ▌本文由 6v6-博客网 整理分享 ▶ 更多…

用nz-tabel写一个合并表格

用nz-tabel写一个合并表格 <nz-table #basicTable [nzData]"tableSearchStatus.dataList" nzBordered><thead><tr><th>班级</th><th>姓名</th><th>年龄</th><th>电话</th></tr></thead&…

leetcode hot100刷题日记——29.合并两个有序链表

解答&#xff1a; 方法一&#xff1a;递归 递归的边界条件是啥呢&#xff1f; 递归别想那么多具体步骤&#xff0c;考虑大步骤&#xff0c;小的递归自己会去做的 class Solution { public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {//递归比较大小//先考虑…

【计算机网络】第1章:概述—分组延时、丢失和吞吐量

目录 一、分组延时、丢失 1. 节点处理延时&#xff1a; 2. 排队延时&#xff1a; 3. 传输延时: 4. 传播延时: 5. 节点延时 6. 排队延时 7. 分组丢失 二、吞吐量 三、总结 &#xff08;一&#xff09;分组延时 1. 处理延时&#xff08;Processing Delay&#xff09; …

DeepSeek R1 模型小版本升级,DeepSeek-R1-0528都更新了哪些新特性?

DeepSeek-R1‑0528 技术剖析&#xff1a;思维链再进化&#xff0c;推理性能飙升 目录 版本概览深度思考能力再升级基准测试成绩功能与体验更新API 变动与示例模型开源与下载结语 版本概览 DeepSeek 团队今日发布 DeepSeek‑R1‑0528 —— 基于 DeepSeek V3 Base&#xff08;2…

SQL正则表达式总结

这里写目录标题 一、元字符二、正则表达函数1、 regexp_like(x,pattern[,match_option])2、 regexp_instr(x,pattern[,start[,occurrence[,return_option[, match_option]]]]) 3、 REGEXP_SUBSTR(x,pattern[,start[,occurrence[, match_option]]]) 4、 REGEXP_REPLACE(x,patter…

力扣经典算法篇-13-接雨水(较难,动态规划,加法转减法优化,双指针法)

1、题干 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

STM32 -- USB虚拟串口通信

本篇操作: 通过CubeMX Keil&#xff0c;配置STM32作为USB设备端&#xff0c;与电脑上位机进行通信&#xff08;CDC&#xff09;&#xff1b;通用带USB功能的 STM32 芯片 &#xff08;如F1、F4等&#xff0c;系统时钟配置不同&#xff0c;代码通用&#xff09;。 目录 一、 S…

uni-app开发特殊社交APP

uni-app开发特殊社交APP 目录 1.展示APP功能 2.展示项目结构 3.关于我的GitHub 引言 博主最近自己在GitHub上面上传了一个关于社交软件的项目&#xff08;该项目早已开发完毕&#xff09;, 这个社交软件比较特殊, 被称之为blind-date&#xff0c; blind-date 是基于 uni-…

Linux中Shell脚本的常用命令

一、设置主机名称 1、通过修改系统文件来修改主机名称 [rootsakura1 桌面]# vim /etc/hostname sakura /etc/hostname&#xff1a;Linux 系统中存储主机名的配置文件。修改完文件后&#xff0c;在当前的shell中是不生效的&#xff0c;需要关闭当前shell后重新开启才能看到效…

RabbitMQ项目实战

先参考文章&#xff1a;&#xff08;必看&#xff09; 06-MQ基础_mq服务-CSDN博客 07-MQ高级&#xff08;幂等性&#xff09;-CSDN博客 https://cloud.iocoder.cn/message-queue/rabbitmq/#_2-0-%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96%E4%B8%8E%E9%85%8D%E7%BD%AE 1、Rabbi…

安卓开发用到的设计模式(3)行为型模式

安卓开发用到的设计模式&#xff08;3&#xff09;行为型模式 文章目录 安卓开发用到的设计模式&#xff08;3&#xff09;行为型模式1. 命令模式&#xff08;Command Pattern&#xff09;2. 策略模式&#xff08;Strategy Pattern&#xff09;3. 观察者模式&#xff08;Observ…

尚硅谷redis7 90-92 redis集群分片之集群扩容

90 redis集群分片之集群扩容 三主三从不够用了&#xff0c;进行扩容变为4主4从 问题&#xff1a;1.新建两个redis实例&#xff0c;怎么加入原有集群&#xff1f;2.原有的槽位分3段&#xff0c;又加进来一个槽位怎么算&#xff1f; 新建6387、6388两个服务实例配置文件新建后启…

离散化算法的二分法应用

我们思考一个问题&#xff1a;其实这里的二分法回归本源也是基于下标映射的原理&#xff0c;只是实现是借助二分的形式。 在排序好的数组中对目标数值进行二分搜索&#xff0c;在 O(logn) 的时间复杂度内找到该数值是整体数据中的第几个。 具体的我们可以如下操作&#xff1a; …

半导体厂房设计建造流程、方案和技术要点-江苏泊苏系统集成有限公司

半导体厂房设计建造流程、方案和技术要点-江苏泊苏系统集成有限公司 半导体厂房的设计建造是一项高度复杂、专业性极强的系统工程&#xff0c;涉及洁净室、微振动控制、电磁屏蔽、特殊气体/化学品管理等关键技术。 一、设计建造流程&#xff1a; 1.需求定义与可行性分析 &a…

一种通用图片红色印章去除的工具设计

朋友今天下午需要处理个事情&#xff0c;问我有没有什么好的办法能够去除&#xff0c;核心问题是要去除图片上的印章。记得以前处理过类似的需求&#xff0c;photoshop操作比较简单&#xff0c;本质是做运算。这种处理方式有很多&#xff0c;比如现在流行的大模型&#xff0c;一…

RapidOCR集成PP-OCRv5_det mobile模型记录

该文章主要摘取记录RapidOCR集成PP-OCRv5_mobile_det记录&#xff0c;涉及模型转换&#xff0c;模型精度测试等步骤。原文请前往官方博客&#xff1a; https://rapidai.github.io/RapidOCRDocs/main/blog/2025/05/26/rapidocr%E9%9B%86%E6%88%90pp-ocrv5_det%E6%A8%A1%E5%9E%8B…

Dify理论+部署+实战

概述 一个功能强大的开源AI应用开发平台&#xff0c;融合后端即服务&#xff08;Backend as Service&#xff09;和LLMOps理念&#xff0c;使开发者能够快速搭建生产级的生成式AI应用。 核心优势 直观的用户界面&#xff1a;提供简洁明了的操作界面&#xff0c;使得用户能够…