vue3+h5实现自定义拍照功能

vue制作拍照、录像功能 【代码】vue制作拍照、录像功能。 阅读详情
AI摘要

本文介绍了如何在Vue3和H5环境下实现手机端的自定义拍照功能。首先,需要确保应用在HTTPS或localhost环境下运行,并且用户已经授权访问摄像头。接着,通过创建一个自定义的拍照组件takePicture.vue来实现拍照功能,并使用compressImage.ts文件进行图片压缩。

在手机端,调用摄像头需要在 HTTPS 或 localhost 下访问,还需要用户事先进行授权

效果图:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/72d14669688c443b840031284b03b4cb.png
在这里插入图片描述
takePicture.vue(自定义拍照组件)

<template>
    <div ref="wrapperRefRef">
      <div class="take-picture" v-if="imgUrl">
        <img :src="imgUrl" alt="">
      </div>
      <video ref="videoRef" class="take-picture" v-else></video>
      
      <div class="wrapper_btm" v-if="imgUrl">
        <span class="open_album" @click="closePicture">取消</span>
        <van-button type="primary" @click="refreshPicture" class="take-picture-btn">返回</van-button>
        <span class="close_picture" @click="submitResult">确定</span>
      </div>
      <div class="wrapper_btm" v-else>
        <input type="file" accept="image/*" ref="galleryRef" @change="handleFileChange" style="display: none;"/>
        <span class="open_album" @click="openGallery">相册</span>
        <van-button type="primary" @click="handleShoot" class="take-picture-btn">拍照</van-button>
        <span class="close_picture" @click="closePicture">关闭</span>
        
      </div>
    </div>
</template>
<script lang="ts" setup>

import { ref, onMounted, defineEmits, defineProps, watch } from "vue";
import { showToast, showNotify} from 'vant';
import { compressImage } from '@/utils/compressImage';

// import { emit } from "process";
const emit = defineEmits(["closePicture", "pictureResult"])
const videoRef = ref<HTMLVideoElement | null>(null);
const imgUrl = ref('');
const imgResult = ref<File | null>(null);

const props = defineProps({  
  show: {  
    type: Boolean,  
    required: true,
    default: false,
  },
});

// 获取媒体流,检测是否支持getUserMedia拍照
const getMediaStream = async () => {
  try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { 
            facingMode: { exact: 'environment' } 
        },
        audio: false,
      });
      if (videoRef.value) {
        videoRef.value.srcObject = stream;
        videoRef.value.play();
      }
  } catch (error) {
      console.error('无法获取媒体流', error);
      showNotify({ type: 'danger', message: '无法获取媒体流' });
  }
};
// 点击拍照
const handleShoot = () =>  {
  if (!videoRef.value) return;
  // 设置canvas画布  
  const canvas = document.createElement("canvas");
  canvas.width = videoRef.value.videoWidth;
  canvas.height = videoRef.value.videoHeight;
  // 获取canvas上下文对象
  const ctx = canvas.getContext("2d");
  // 截图操作
  ctx?.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height);
  // 转为文件流
  const img = canvas.toDataURL("image/jpeg");
  canvas.toBlob((blob) => {
      if (blob) {
          const newFile = new File([blob], 'takePicture.jpg', { type: 'image/jpeg' });
          imgResult.value = newFile;
      }
  }, 'image/jpeg', 1); // 0.8 为压缩质量
  imgUrl.value = img;
}
const galleryRef = ref<HTMLInputElement | null>(null);
// 打开相册
const openGallery = () => {
  galleryRef.value?.click();
}
// 相册文件选择
const handleFileChange = (e: any) => {
    // 调用压缩图片方法
    compressImage(e.target.files[0], (file) => {
        emit("pictureResult", file);
        // 关闭相机
        closePicture();
    });
};
// 重置相机
const refreshPicture = () => {
  if (videoRef.value) {
    videoRef.value.srcObject = null;
  }
  imgUrl.value = '';
  getMediaStream();
}
// 关闭相机
const closePicture = () => {
  if (videoRef.value) {
    videoRef.value.srcObject = null;
  }
  imgUrl.value = '';
  emit("closePicture", false);
}
// 提交拍照
const submitResult = () => {
  emit("pictureResult", imgResult.value);
  closePicture();
}

onMounted(() => {
  getMediaStream();
  watch(() => props.show, (newValue, oldValue) => {
    console.log('newValue', newValue)
    if (newValue) {
      getMediaStream();
    }
  });
});
</script>
<style scoped>
.take-picture{
  width: 100%;
  height: 80vh;
  position: absolute;
  top: 0;
  left: 0;
  /* background: rgba(255,255,255,.5); */
}
.wrapper_btm{
  display: flex;
  width: 100%;
  height: 20vh;
  background: rgb(10, 10, 10);
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  /* align-items: center; */
  position: absolute;
  bottom: 0;
  left: 0;
}
.take-picture-btn{
  width: 4rem !important;
  height: 4rem !important;
  border-radius: 50% !important;
  background: #fff !important;
  border: none !important;
  color: #000;
}
.open_album{
  font-size: 1rem;
  position: absolute;
  top: 50%;
  left: 25%;
  /* left: 50%; */
  transform: translateY(-50%);
  color: #fff;
}
.close_picture{
  font-size: 1rem;
  position: absolute;
  top: 50%;
  right: 25%;
  /* left: 50%; */
  transform: translateY(-50%);
  color: #fff;
}
</style>

使用拍照组件

<template>
<van-overlay :show="show" @click="show = false">
<takePicture @closePicture="show = false" :show="show" @pictureResult="handlePictureResult" />
</van-overlay>
</template>
<script lang="ts" setup>
import { ref, reactive, defineEmits, defineProps, getCurrentInstance  } from 'vue';
const show = ref(false);
// 使用takePicture组件的拍照返回结果
const handlePictureResult = (result: File) => {
    console.log('拍照返回结果', result);
    // 上传图片
    const img1 = document.createElement('img');
    img1.src = URL.createObjectURL(result);
    img1.style.width = '100%';
    img1.style.height = '100%';
    document.body.appendChild(img1);
}
</script>

compressImage.ts文件压缩

// 压缩图片质量
export const compressImage = (file: File, callback: (file: File) => void) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = (e) => {
        const img = new Image();
        img.src = e.target?.result as string;
        img.onload = () => {
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            const MAX_WIDTH = 800;
            const MAX_HEIGHT = 800;
            let width = img.width;
            let height = img.height;
            if (width > height) {
                if (width > MAX_WIDTH) {
                    height *= MAX_WIDTH / width;
                    width = MAX_WIDTH;
                }
            } else {
                if (height > MAX_HEIGHT) {
                    width *= MAX_HEIGHT / height;
                    height = MAX_HEIGHT;
                }
            }
            canvas.width = width;
            canvas.height = height;
            ctx?.drawImage(img, 0, 0, width, height);

            // const newFile = new File([canvas.toDataURL('image/jpeg', 0.8).split(',')[1]], file.name, { type: 'image/jpeg' });
            // callback(newFile);
            canvas.toBlob((blob) => {
                if (blob) {
                    const newFile = new File([blob], file.name, { type: 'image/jpeg' });
                    callback(newFile);
                }
            }, 'image/jpeg', 0.9); // 0.8 为压缩质量
        };
    };
};

非vue版本代码

<!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>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background-color: #000;
            color: #fff;
            overflow: hidden;
        }
        
        .container {
            position: relative;
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
        }
        
        .take-picture {
            width: 100%;
            height: 80vh;
            object-fit: cover;
            background-color: #222;
        }
        
        .wrapper_btm {
            display: flex;
            width: 100%;
            height: 20vh;
            background: rgb(10, 10, 10);
            flex-wrap: wrap;
            align-content: center;
            justify-content: center;
            position: absolute;
            bottom: 0;
            left: 0;
        }
        
        .take-picture-btn {
            width: 4rem;
            height: 4rem;
            border-radius: 50%;
            background: #fff;
            border: none;
            color: #000;
            font-size: 1rem;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        
        .open_album, .close_picture {
            font-size: 1rem;
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            color: #fff;
            cursor: pointer;
        }
        
        .open_album {
            left: 25%;
        }
        
        .close_picture {
            right: 25%;
        }
        
        /* Toast 通知样式 */
        .toast-container {
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            z-index: 1000;
            max-width: 90%;
        }
        
        .toast {
            background-color: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 12px 20px;
            border-radius: 8px;
            margin-bottom: 10px;
            text-align: center;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            animation: fadeIn 0.3s, fadeOut 0.3s 2.7s forwards;
        }
        
        .toast.danger {
            background-color: rgba(231, 76, 60, 0.9);
        }
        
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }
        
        @keyframes fadeOut {
            from { opacity: 1; }
            to { opacity: 0; }
        }
        
        /* 按钮样式 */
        .van-button {
            display: inline-block;
            padding: 8px 16px;
            border: none;
            border-radius: 4px;
            background-color: #07c;
            color: white;
            font-size: 14px;
            cursor: pointer;
            transition: background-color 0.2s;
        }
        
        .van-button:active {
            background-color: #005ba3;
        }
        
        .van-button.primary {
            background-color: #07c;
        }
    </style>
</head>
<body>
    <div class="container">
        <div id="image-container" class="take-picture" style="display: none;">
            <img id="captured-image" alt="Captured image" style="width: 100%; height: 100%; object-fit: contain;">
        </div>
        <video id="video" class="take-picture" autoplay playsinline></video>
        
        <div id="result-buttons" class="wrapper_btm" style="display: none;">
            <span class="open_album" onclick="closePicture()">取消</span>
            <button type="button" onclick="refreshPicture()" class="take-picture-btn">返回</button>
            <span class="close_picture" onclick="submitResult()">确定</span>
        </div>
        
        <div id="camera-buttons" class="wrapper_btm">
            <input type="file" id="gallery-input" accept="image/*" style="display: none;">
            <span class="open_album" onclick="openGallery()">相册</span>
            <button onclick="handleShoot()" class="take-picture-btn">拍照</button>
            <span class="close_picture" onclick="closePicture()">关闭</span>
        </div>
    </div>

    <div id="toast-container" class="toast-container"></div>

    <script>
        // 全局变量
        let videoElement = null;
        let imageContainer = null;
        let capturedImage = null;
        let galleryInput = null;
        let cameraButtons = null;
        let resultButtons = null;
        let imgUrl = '';
        let imgResult = null;
        let stream = null;

        // 初始化函数
        function init() {
            videoElement = document.getElementById('video');
            imageContainer = document.getElementById('image-container');
            capturedImage = document.getElementById('captured-image');
            galleryInput = document.getElementById('gallery-input');
            cameraButtons = document.getElementById('camera-buttons');
            resultButtons = document.getElementById('result-buttons');
            
            // 添加文件选择事件监听
            galleryInput.addEventListener('change', handleFileChange);
            
            // 初始化相机
            getMediaStream();
        }

        // 获取媒体流
        async function getMediaStream() {
            try {
                stream = await navigator.mediaDevices.getUserMedia({
                    video: { facingMode: 'environment' },
                    audio: false,
                });
                videoElement.srcObject = stream;
            } catch (error) {
                console.error('无法获取媒体流', error);
                showNotify('无法获取媒体流', 'danger');
            }
        }

        // 拍照功能
        function handleShoot() {
            if (!videoElement) return;
            
            // 创建canvas进行截图
            const canvas = document.createElement("canvas");
            canvas.width = videoElement.videoWidth;
            canvas.height = videoElement.videoHeight;
            
            // 获取canvas上下文
            const ctx = canvas.getContext("2d");
            
            // 截图操作
            ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
            
            // 转为DataURL
            const imgDataUrl = canvas.toDataURL("image/jpeg");
            
            // 转为Blob对象
            canvas.toBlob((blob) => {
                if (blob) {
                    imgResult = new File([blob], 'takePicture.jpg', { type: 'image/jpeg' });
                }
            }, 'image/jpeg', 0.8);
            
            // 显示图片
            capturedImage.src = imgDataUrl;
            imgUrl = imgDataUrl;
            
            // 切换显示
            videoElement.style.display = 'none';
            imageContainer.style.display = 'block';
            cameraButtons.style.display = 'none';
            resultButtons.style.display = 'flex';
            
            // 停止视频流
            if (stream) {
                stream.getTracks().forEach(track => track.stop());
            }
        }

        // 打开相册
        function openGallery() {
            galleryInput.click();
        }

        // 处理文件选择
        function handleFileChange(e) {
            if (e.target.files && e.target.files[0]) {
                const file = e.target.files[0];
                compressImage(file, (compressedFile) => {
                    // 这里应该触发一个事件,但简化处理直接显示
                    capturedImage.src = URL.createObjectURL(compressedFile);
                    imgResult = compressedFile;
                    
                    // 切换显示
                    videoElement.style.display = 'none';
                    imageContainer.style.display = 'block';
                    cameraButtons.style.display = 'none';
                    resultButtons.style.display = 'flex';
                    
                    // 关闭相机
                    if (stream) {
                        stream.getTracks().forEach(track => track.stop());
                    }
                });
            }
        }

        // 图片压缩函数
        function compressImage(file, callback) {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function(event) {
                const img = new Image();
                img.src = event.target.result;
                img.onload = function() {
                    const canvas = document.createElement('canvas');
                    const ctx = canvas.getContext('2d');
                    
                    // 设置最大尺寸
                    let width = img.width;
                    let height = img.height;
                    const maxWidth = 1200;
                    const maxHeight = 1200;
                    
                    if (width > height) {
                        if (width > maxWidth) {
                            height *= maxWidth / width;
                            width = maxWidth;
                        }
                    } else {
                        if (height > maxHeight) {
                            width *= maxHeight / height;
                            height = maxHeight;
                        }
                    }
                    
                    canvas.width = width;
                    canvas.height = height;
                    
                    ctx.drawImage(img, 0, 0, width, height);
                    
                    canvas.toBlob(function(blob) {
                        const compressedFile = new File([blob], file.name, {
                            type: 'image/jpeg',
                            lastModified: Date.now()
                        });
                        callback(compressedFile);
                    }, 'image/jpeg', 0.7);
                };
            };
        }

        // 重置相机
        function refreshPicture() {
            // 清除图片
            capturedImage.src = '';
            imgUrl = '';
            
            // 切换显示
            imageContainer.style.display = 'none';
            videoElement.style.display = 'block';
            resultButtons.style.display = 'none';
            cameraButtons.style.display = 'flex';
            
            // 重新获取媒体流
            getMediaStream();
        }

        // 关闭相机
        function closePicture() {
            // 停止媒体流
            if (stream) {
                stream.getTracks().forEach(track => track.stop());
            }
            
            // 清除图片
            capturedImage.src = '';
            imgUrl = '';
            
            // 切换显示
            imageContainer.style.display = 'none';
            videoElement.style.display = 'block';
            resultButtons.style.display = 'none';
            cameraButtons.style.display = 'flex';
            
            // 在实际应用中,这里应该触发一个关闭事件
            console.log("相机已关闭");
        }

        // 提交结果
        function submitResult() {
            if (imgResult) {
                // 在实际应用中,这里应该触发一个结果事件
                console.log("图片已提交", imgResult);
                showToast('图片已保存');
            } else {
                showNotify('没有可提交的图片', 'danger');
            }
            
            closePicture();
        }

        // 显示Toast
        function showToast(message) {
            const toast = document.createElement('div');
            toast.className = 'toast';
            toast.textContent = message;
            
            const container = document.getElementById('toast-container');
            container.appendChild(toast);
            
            // 3秒后移除toast
            setTimeout(() => {
                container.removeChild(toast);
            }, 3000);
        }

        // 显示通知
        function showNotify(message, type = '') {
            const toast = document.createElement('div');
            toast.className = type ? `toast ${type}` : 'toast';
            toast.textContent = message;
            
            const container = document.getElementById('toast-container');
            container.appendChild(toast);
            
            // 3秒后移除通知
            setTimeout(() => {
                container.removeChild(toast);
            }, 3000);
        }

        // 页面加载完成后初始化
        window.addEventListener('load', init);
    </script>
</body>
</html>
Uniapp或H5之ORC识别与自定义照相机 在现代移动应用中,OCR(光学字符识别)和自定义照相机功能已经成为提升用户体验与增强应用功能的重要组成部分。本文将详细探讨如何在Uniapp和H5环境中实现OCR识别与自定义照相机功能,包括技术选型、实现原理以及具体的操作步骤。在H5中,我们可以利用HTML5的元素和WebRTC API(如getUserMedia)来实现自定义照相机功能。元素用于显示摄像头捕获的实时视频流,而getUserMedia API则用于获取用户的摄像头权限并捕获视频流。 阅读详情

相关推荐

vuejs组件分享H5图片上传、压缩,拍照旋转

处理问题   这里用h5做图片上传考虑到浏览器支持的问题,这里考虑的场景是在做webapp的时候   1.移动web图片上传还包括拍摄上传,但是在移动端会出现拍摄的照片会旋转,处理这个问题需要得到图片旋转的情况,可以用exif.js来获取,具体可以参看文档   2.图片压缩   3.旋转 一、代码 1组件代码 template> div>

-根号四 - 的博客 8454

移动端H5实现自定义拍照界面

在手机端,为了让用户能够在页面中手动切换摄像头,需要检测手机端设备是否有多个摄像头,在有多个摄像头时,提供给用户切换摄像头的选项。对于一些高级功能,例如人脸检测和识别,美颜,以及其他高级图像处理功能可以使用第三方库,如 openCV.js,tracking.js,face-api.js 等来实现。虽然在手机端实现自定义拍照界面有一定的挑战,但是通过使用 MediaDevices API 和相关第三方库,还有经验丰富的开发人员在这个问题上是有解决方案的。标签来截取当前摄像头的画面,通过。

风清扬的专栏 6068

【uniapp】H5扫码方案,解决uni.scanCode不支持H5的问题

1. 背景   uniapp 中自带的 uni.scanCode 只能应用于 非H5,在H5上是没有提供该类扫码功能。   在参考了前辈的文章后(在此特别感谢 uniapp H5扫码实现 提供的方案和灵感),本文的解决方案是:通过调用相机拍照,拍完进行二维码识别。 2. 效果 完整demo下载地址(希望花您两秒钟的时间点个 star,这将是我持续创作的动力):https://gitee.com/Jokerlsss/h5-scan-code 点击按钮调起相机(或相册) 拍照(或选择照片)后确认,自动识别

weixin_42678675的博客 1万+

vue3实现自定义相机拍照、扫描二维码等功能

【代码】vue3实现自定义相机拍照、扫描二维码等功能。

xhwy_zh的博客 1887

Vue3 - 详细实现移动端H5网页调用摄像头拍照功能,微信公众号网页h5页面打开本地摄像头并点击按钮照相,vue3获取摄像头画面执行拍照保存,调整摄像头前置后置抓拍图片给用户展示或保存手机上传服务器

vue3,H5网页,手机移动端,vue3摄像头拍照,前端h5调用手机摄像头,移动端网页调用摄像头,H5实现手机拍照和选择上传,调用本地摄像头实现拍照,vue3调用摄像头拍照,手机浏览器开启摄像头并进行拍照,H5移动端网页中调用手机摄像头,H5实现web调用摄像头在线照相,vue3h5调用摄像头,微信公众号网页如何调用摄像头拍照,公众号H5页面实现打开摄像头照相,怎么生成临时图片,vue3项目调用摄像头实现拍照功能,摄像头打不开没反应,浏览器不兼容怎么办,摄像头权限不弹出,只能在本地运行,拒绝权限后怎么办,

🏆 前端领域优质创作者 1万+

vue3 - 实现移动端H5网页调用手机相册选取图片或打开摄像头相机拍照上传,H5调用本地相册/相机上传图片详细教程,如何在h5网站浏览器中打开本机相册或相机选择相片(附图片压缩功能及上传服务器示例)

vue3手机H5网页,调起安卓苹果ios手机相册和相机,H5实现调用手机摄像头相册实现图片压缩预览删除,vue3项目调用摄像头和相册,H5调用手机摄像头,vue3 H5拍照上传,手机网站浏览器移动端调取相机或相册,实现拍照上传功能,解决苹果ios手机无法打开相册相机问题,无法唤起摄像头怎么办,调取本机系统的相册,vue3 h5网页调用相机拍照和相册,实现多张图片上传功能,实时拍照上传,VUE3如何唤起手机摄像头拍照上传,H5调起手机端的摄像头,html5调用手机摄像头,实现H5调起手机相机和相册,图片压缩,

✅ 精选推荐文章 1万+

vue3.0 + ts H5拍照组件

添加了旋转功能, 添加拍照图标修改插槽;添加照片清晰度分辨率设置;实现了简单的拍照功能,拍照成功返回文件对象;

wanglun_的博客 829

uniapp(移动端H5网页):实现调用本地摄像头实现拍照+保存到本地或上传到服务器,vue3获取浏览器摄像头开启权限,调起摄像头进行拍照并查看预览等功能(支持前置和后置摄像头,解决网站申请权限问题)

uni-app手机H5页面调取浏览器摄像头实现拍照功能,获取网页摄像头权限开启,uniApp H5网页调用本地摄像头实现拍照,Uniapp h5实现调用手机拍照,uniapp项目调用摄像头实现拍照功能并切换前置后置摄像头拍照,uniappH5如何调起摄像头,进行拍照并能保存到本地,打开摄像头保存图片,UNI-APP开启摄像头,并进行拍照_实现浏览器调用摄像头,调用电脑摄像头进行拍照并上传到服务器保存,前端调用本地摄像头实现拍照,摄像头权限没有提示怎么办,拒绝摄像头权限再也打不开了,拍照画面全黑,UNIAPP

✅ 精选推荐文章 4859

vue+vant组件+h5plus使用Hbuilderx实现拍照选取图片功能

这几天用cordova用的头大,用cordova插件cordova-plugin-camera感觉不好用,而且在某些机型有点问题== 所以改成用HubuilderX进行打包,并且使用h5plus的api进行拍照调用 官方api: 点击这里进入 注意的是 :该程序必须打包成apk在真机或者模拟器运行,不然会报错 github项目地址:从这里进入 先上效果图: 具体实现: android.js //获取系统方法 function takePhoto(callback) { var cmr =

weixin_38992765的博客 3189

仿照手机相机做的一个H5端自定义相机

h5端的一个自定义手机拍照,不是直接全屏调用手机里自带的照相机,用户可以直接用getUserMedia获得摄像头提供的视频流。 调取本地视频或音频设备的接口,出于安全的考虑,只能在localhost或者https下使用

PCIE配置和地址空间

来源:https://www.jianshu.com/p/574e9a2cbc4e 每个PCIe设备,有这么一段空间,Host软件可以读取它获得该设备的一些信息,也可以通过它来配置该设备,这段空间就叫做PCIe的配置空间。不同于每个设备的其它空间,PCIe设备的配置空间是协议规定好的,哪个地方放什么内容,都是有定义的。PCI或者PCI-X时代就有配置空间的概念,那时的配置空间如下: 图6.1 整个配置空间就是一系列寄存器的集合,其中Type 0是Endpoint的配置,Type 1是Brid.

qq_28643619的博客 4060

Vue中使用h5 Plus的方法

零、前言 npm上Vue中使用的库数不胜数,作为移动App端的又一泰斗,h5 plus当然也是可以被使用进来的。H5Plus是一种基于HTML、JS、CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任意调用手机的原生能力,实现与原生App同样强大的功能和性能。 一、安装库 1.安装库 cnpm i vue-awesome-mui -S 如果没有cnpm那就npm吧! ...

千里小马哥的博客 2万+

Linux基础——“C语言高级编程” C语言中的细节你真的知道吗?

文章目录GCC简介 GCC简介 gcc 所支持后缀名解释 .c c原始程序 .C / .cc /.cxx C++原始程

weixin_44278698的博客 2511

记录--如何在H5中实现OCR拍照识别身份证功能

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 业务背景 由于当前项目中需要实现身份证拍照识别的功能,如果是小程序可以使用微信提供的 ocr-navigator 插件实现,但是在企业微信的H5中没有提供该插件,所以需要手动实现该功能。 需求分析及资料查阅 众所周知,前端H5中浏览器打开相机打开的是原生相机,无法在相机的界面上覆盖自定义的元素,比如实现类似下面的UI界面,无法使用...

林恒的博客 2201

手把手教你用MaxEnt+ArcGIS玩转物种分布预测

本文详细介绍了如何利用MaxEnt最大熵模型与ArcGIS软件进行物种分布预测。通过实战案例,从数据收集、环境变量处理、模型参数设置到结果可视化分析,手把手教你掌握生态位模型的核心流程。结合SDM toolbox插件,可高效完成数据预处理与高级空间分析,是生态学与保护生物学研究的实用指南。

weixin_29309475的博客 560

vivado 工程修改芯片型号

vivado工程芯片与实际板子不匹配时,需要修改工程的芯片型号,并对原工程的ip进行同步更新,之后生成新的bit文件,烧录到板子中

k7126685的博客 1万+

vue-h5:在h5中实现相机拍照加上身份证人相框和国徽框

参考: https://blog.youkuaiyun.com/weixin_45148022/article/details/135696629https://juejin.cn/post/7327353533618978842?searchId=20241101133433B2BB37A081FD6A02DA60https://www.freesion.com/article/67641324321/https://github.com/AlexKratky/vue-camera-lib效果:调用组件的主要组件方法

beekim的博客 3870

QMT中ContextInfo的使用注意

QMT中ContextInfo下声明的全局变量的使用注意事项

路在何方 2810

vue嵌入h5页面拍照获取照片旋转问题

在h5页面中经常会需要获取相册或者拍照上传照片,可以使用最简单的 <input type="file" name="photo" accept=".jpg,.png" multiple> 直接进行获取,当点击按钮时会让你进行选择是拍照还是文件选择,选择文件中的照片进行上传显示正常,但是当选择照片进行拍照时会出现拍摄的照片发生旋转问题,本来是只有ios才会出现该问题,好像是因为io...

jjy8040的博客 2713

基于Lumerical的1550 nm InGaAs/InP与InGaAs/InAlAs APD设计与功率饱和度优化

摘要 本研究利用Ansys Lumerical软件对1550 nm激光雷达应用的InGaAs/InP和InGaAs/InAlAs雪崩光电二极管(APD)进行仿真设计与优化。通过FDTD光学仿真获取光吸收分布,结合CHARGE模块的电学仿真分析暗电流、光电流及雪崩增益特性。重点研究了两种材料体系的性能差异,并针对近距离强反射导致的功率饱和问题提出结构优化方案。仿真结果表明,InGaAs/InAlAs APD具有更优的过量噪声特性,而优化的电荷层设计可显著提升器件的功率饱和阈值。研究提供了完整的仿真流程与代码实

huanghm88的专栏 97

(四)C++自制植物大战僵尸游戏启动流程

鼠标左键单机VS2022上方工具栏中进行项目启动。第一次启动项目需要编译项目中所有代码文件,编译生成需要一定的时间。不同性能的电脑需要消耗的时间差别可能较大,通常在几分钟到几十分钟之间。编译成功后会自动启动运行游戏。qi编译成功后自动启动运行游戏如下图。

尔灵尔亿的博客 2466

Vue.js实战——H5拍照迁移至Android App_14

一、目标 1、解决从纯H5开发且带拍照功能的App迁移至Android平台时,保证拍照和裁剪功能正常; 2、解析实现过程中碰到的各种问题; 二、实现效果 为了达成上述目标,先大体介绍下思路: 1)Android平台下支持h5的input拍照标签,但是需要在Android侧对拍照过程做一些特殊处理才能正常获取到此拍照图片; 2)Android平...

编码之旅 790

英伟达 Jetson AGX Thor 官方入门教程(二)CUDA、Docker、JetPack 设置

本文详细介绍了NVIDIA Jetson AGX Thor开发套件的安装与配置流程。主要内容包括:1) BSP安装的三种方法(Jetson ISO、SDK Manager和Linux刷写脚本)及其适用场景;2) Docker环境的完整配置步骤及测试方法;3) CUDA工具包的两种安装方式(容器化和原生安装)及其性能对比;4) JetPack SDK的安装选项。文章提供了详细的命令行操作指南和故障排除建议,帮助开发者快速搭建AI开发环境,充分发挥Jetson平台的硬件性能优势。

机器人控制与仿真应用 1736

vue3.0 + ts H5拍照详细代码

pc端调用摄像头,本地实现H5拍照功能;解决拍照模糊问题;解决角度问题;

wanglun_的博客 676

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Vue H5页面实现拍照解析二维码功能

因为需要做移动端实现扫码功能(app和h5都可用),H5不能调用手机扫码功能。所以采用先拍照获取二维码文件流再解析二维码数据。 需要以下3个js文件支持,网上可以下载到:(引用顺序如下) 上面js我做了些修改,方便把识别的结果通过回调函数返回出来。 1.qrcode.js (function($) { var Qrcode = function(tempBtn, backfun) { var _this_ = this; var isWeiboWebView = /__weibo..

ui设计前端工程师 944

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

APP开发-使用Vue3+vant+html5+ 实现相机拍照,选取相册图片,裁剪图片以及提取图片中的文字等功能(一)

一、

不觉晓晓的博客 8734
上一篇: uniapp使用高德地图定位,并显示,map报错getLocation:fail translate coordinate system fail,<AMap JSAPI> KEY异常
下一篇: linux、window系统实现一个脚本用于检测ip+端口是否可以正常通讯,如果不可以替换文件中的指定字符,用于实现php程序中数据库不能使用了自动切换到另一个数据库
if时光重来
博客等级 码龄8年 248粉丝 217原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值