目录
一、需求
二、开发语言
三、效果
四、业务逻辑:
五、web端调用摄像头
六、示例代码
1、前端
2、后端
一、需求
web端使用jquery调用摄像头拍照,并使用PHP把base64编码转换成png格式图片,下载到本地。
由于js不能指定图片存储的位置,所以需要把base64图像数据传到后台,由后台存储到指定位置。
二、开发语言
前端:JS
后端:PHP
三、效果
点击“拍摄图像”按钮,自动连续拍摄10张并上传到后台,存放到指定位置,并在前端显示预览图像
四、业务逻辑:
① 前端点击“拍摄图像”按钮,开始拍照,我这里的需求是连续拍摄10张
② 前端获取到base64编码图像数据,并发送到后端
③ 后端接收到base64编码后,转换成PNG格式并保存到指定位置
④ 图片存储成功后,返回图片路径给前端
⑤ 前端显示拍摄的图像
五、web端调用摄像头
web端调用摄像头使用“webcam.js”插件,使用webcam.js调用摄像头前提是项目是https,否则没有获取摄像头的权限。
WebcamJS:jQuery移动端调用摄像头拍照插件WebcamJS
六、示例代码
1、前端
HTML:图像采集区
<style type="text/css">
#open-power{
transition: transform 0.3s ease-in-out; /* 添加过渡效果,使变换更平滑 */
transform-origin: center center; /* 变换原点设置为图片中心 */
width: 100%; /* 初始尺寸设置为容器宽度 */
height: auto; /* 保持图片的宽高比 */
}
#imageContainer{
overflow: hidden; /* 隐藏超出容器的部分 */
position: relative; /* 如果需要相对于容器定位图片,可以添加这个属性 */
margin: 0 auto;
background:rgba(41, 123, 255, 0.06);
border-radius:18px;
border:1px dashed #297BFF;
cursor:pointer;
box-shadow:4px 4px 18px 0px rgb(0 0 0 / 8%);
padding: 10px;
}
.main__camera-power{
background: none;
border-radius: 0;
border: none;
cursor:none;
margin: 0 auto;
box-shadow:none;
padding: 0px;
}
</style>
<div class="layui-col-md8 layui-col-sm8 layui-col-xs12">
<div class="layui-row">
<div class="layui-col-md12 layui-col-sm12 layui-col-xs12">
<fieldset class="layui-elem-field">
<legend>图像采集区</legend>
<div class="layui-field-box">
<!-- 图像 -->
<div id="imageContainer">
<div id="open-power" class="main__camera-power flex-center">
<span class="main__camera-power--span">
<img src="/home/images/camera.png" alt="power" />
</span>
<p class="main__camera-power--hint">请开启摄像头权限</p>
</div>
</div>
</div>
</fieldset>
</div>
</div>
</div>
HTML:拍摄图像按钮
<div class="layui-col-md6 layui-col-sm6 layui-col-xs12">
<div class="paizhao" style=" width: 4.5rem; height: 4rem; margin: 0 1rem; background: #F0F0F0; text-align: center; box-shadow: 4px 4px 10px #888888; font-size: 0.9rem; border-radius: 10px; cursor: pointer; color: #000; font-size: 0.9rem;" >
<i class="layui-icon layui-icon-camera-fill" style="font-size: 30px; color: #555;"></i> <br/>拍摄图像
</div>
</div>
HTML:图片预览区域
<style>
/* 图像预览区域 */
#results { background:#f8f8f8; }
#results > img { width: 160px; height: 120px; margin: 3px}
</style>
<div class="layui-row" style="width: 98%; margin: 1% auto; ">
<div class="layui-col-md12 layui-col-sm12 layui-col-xs12">
<div style="border: 1px solid #e6e6e6; height: 120px;overflow:auto;">
<div id="results" style=""><p>Your captured images will appear here...</p></div>
</div>
</div>
</div>
JS:
<script src="/home/js/jquery-1.12.3.min.js"></script>
<script src="/home/js/webcam.js" type="text/javascript" charset="utf-8"></script>
// 初始化操作 设置摄像头区域
$(function(){
// 获取窗口尺寸并设置摄像头宽高为80%
function setCameraSize() {
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var cameraWidth = windowWidth * 0.45;
var cameraHeight = windowHeight * 0.68;
$("#imageContainer").css('width',cameraWidth)
$("#imageContainer").css('height',cameraHeight)
// 设置摄像头宽高
Webcam.set({
width: cameraWidth,
height: cameraHeight,
jpeg_quality: 90
});
// 附加摄像头到容器
Webcam.attach('#open-power');
}
// 初始设置
setCameraSize();
// 监听窗口大小改变事件
window.addEventListener('resize', setCameraSize);
});
// 拍摄图像
var c = 1 // 图像张数
var c2 = 1; // 图像张数
var timer = null
// 开始拍照
$(".paizhao").click(function () {
c = 1
c2 = 1
// 拍照前先清空div里已存在的图像
document.getElementById('results').innerHTML = '';
var yinpian = $('#yinpian').val();
if (yinpian == '') {
layer.msg('请先选择饮片名称', {time: 3000, icon:2});
clearTimeout( timer );
return false
}
layer.msg('图像正在采集并处理,请稍后...', {time: 3000, icon:0});
tip_html = '<br/><span style="color:green">【'+yinpian+'】</span>图像正在采集并处理,请稍后...'
$("#systip").prepend(tip_html)
// 开始拍照
take_snapshot();
// 定时 每250ms拍摄一次
timer = setInterval( take_snapshot, 250 );
})
function take_snapshot() {
// 获取饮片名称
var yinpian = $('#yinpian').val();
if (yinpian == '') {
layer.msg('请先选择饮片名称', {time: 3000, icon:2});
clearTimeout( timer );
return false
}
Webcam.snap( function(data_uri) {
// 图片保存到本地
saveJpg(data_uri,yinpian)
} );
// 图片数量+1
c = c+1
if (c > 10) {
// 十张采集完成,结束采集
clearTimeout( timer );
timer = null;
}
}
// Base64保存为jpg
function saveJpg(base64data,yinpian) {
$.ajax({
url:'/index/index/saveJpg',
type:'POST',
dataType:'JSON',
data:{img:base64data,yinpian:yinpian},
success:function (res) {
console.log(res)
var img_html = ''
if (res.code == '200') {
// 把返回的图像地址追加显示到图像预览区域
var img = new Image();
img.src = '/'+res.data
document.getElementById('results').appendChild( img );
console.log(img)
c2 = c2+1
console.log(c2)
if (c2 > 10) {
layer.msg('10张采集完成,请调整饮片再次采集', {time: 3000, icon:1});
tip_html = '<br/><span style="color:green">【'+yinpian+'】</span>图像10张采集完成,请调整图像再次采集!'
$("#systip").prepend(tip_html)
}
}
}
})
}
2、后端
接收前端传来的base64编码,把base64编码数据转存成png,并存放到指定位置
/**
* base64保存为jpg
*/
public function saveJpg()
{
if (request()->isPost()) {
$baseImg = trim(input('post.img')); // base64编码
$yinpian = trim(input('post.yinpian')); // 饮片名称
if (!empty($baseImg) && !empty($yinpian)) {
//图片存放的路径
$path = "uploads/images/".$yinpian.'/';
if (!file_exists($path)) {
mkdir($path, 0700, true); //创建目录
chmod($path, 0700); //赋予权限
}
$uid = session('uid');
//确保图片名唯一,防止重名产生覆盖
$imageName = 'wx_' .$uid.'_' . rand(1000, 9000) . time(). '.jpg';
//判断是否有逗号 如果有就截取后半部分
if (strstr($baseImg,",")){
$baseImg = explode(',',$baseImg);
$baseImg = $baseImg[1];
}
//图片路径
$imageSrc= $path . $imageName;
//生成文件夹和图片
$r = file_put_contents($imageSrc, base64_decode($baseImg));
if($r){
return apiResponse('200','图像保存成功',$imageSrc);
}else{
return apiResponse('110','图像保存失败');
}
}else{
return apiResponse('110','初始化失败,请刷新页面');
}
}else{
return apiResponse('110','非法请求');
}
}
如果有控制摄像头放大缩小画面的需求,可参考另外一篇【PHP】控制摄像头缩放监控画面大小,并保存可视画面为图片_代码怎么实现监控视频怎么放大画面-CSDN博客