Мало знаний, большой вызов! Эта статья участвует в "Необходимые знания для программистов«Творческая деятельность.
Эта статья участвовала в "Проект «Звезда раскопок»”, чтобы выиграть творческий подарочный пакет и бросить вызов творческим поощрительным деньгам.
задний план
Не так давно я выполнил функцию получения камеры браузера и сканирования кода для распознавания.В этой статье разобраны точки знаний и конкретные реализации кода, связанные с этим, и организованы в содержание этой статьи.
Эта статья в основном знакомит с использованиемvueПередняя технология разработки стека технологий, активация камеры на стороне браузера📷, и выполните функцию распознавания скан-кода, чтобы выполнить переход или другие операции с распознанным QR-кодом. Содержание этого документа разделено на вводную часть, эффект реализации, техническое введение, реализацию кода, резюме и другие части.
добиться эффекта
В этом примере есть две основные страницы, домашняя страница и страница с кодом сканирования Конкретный эффект реализации показан на следующем рисунке.
- Главная: нажмите
SCAN QRCODEкнопку для ввода кодовой страницы сканирования. - Сканировать кодовую страницу: при вводе в первый раз или всплывающее окно
获取摄像头访问权限的系统提示框, нажмите Разрешить доступ, страница начнет загружать данные камеры и начнет захватывать и подбирать QR-код.Если QR-код захвачен, начинается синтаксический анализ QR-кода.После успешного синтаксического анализа появляется сообщение об успешном выполнении загрузки и идентификации отображается окно вверх.
📸онлайн опыт:дракон IR.GitHub.IO/также 5-трехразовое питание-но так…
📌Подсказка: вертикальный экран в браузере для доступа к камере устройства. Экран телефона в любом случае я обнаруживаю мало знаний, могу перейти к другой статье«Внешние знания в пятицветной мини-игре»чтобы понять.
Техническое введение
WebRTC API
WebRTC (Web Real-Time Communications) — это технология связи в реальном времени., что позволяет веб-приложению или сайтубез посредниковМежду корпусом браузера учреждения点对点(Peer-to-Peer)соединение для реализации передачи видеопотока и/или аудиопотока или других произвольных данных.WebRTCЭти стандарты включены, чтобы позволить пользователям создавать点对点(Peer-to-Peer)возможен обмен данными и конференц-связь.
три основных интерфейса:
-
MediaStream: Возможность получения синхронного потока видео и аудио через камеру и микрофон устройства. -
RTCPeerConnection:ДаWebRTCКомпоненты для создания стабильной и эффективной потоковой передачи между узлами. -
RTCDataChannel: обеспечивает высокую пропускную способность канала с малой задержкой между браузерами для передачи произвольных данных.
🔗идти кMDNУглубленное изучение:WebRTC_API
WebRTC adapter
несмотря на то чтоWebRTCСпецификация относительно надежна и стабильна, но не во всех браузерах реализованы все ее функции, а некоторым браузерам требуются некоторые или все функции.WebRTC APIПри добавлении префикса к нормальному использованию.
WebRTCорганизоватьgithubпредоставилWebRTC适配器(WebRTC adapter)решить реализацию в разных браузерахWebRTCпроблемы совместимости. Этот адаптер являетсяJavaScript垫片, что позволяет вамWebRTCкод, как описано в спецификации, во всех поддерживаемыхWebRTCНет необходимости писать префиксы или другие обходные пути совместимости в браузерах.
🔗идти кMDNУглубленное изучение:WebRTC adapter
Основной APInavigator.mediaDevices.getUserMedia
Веб-страница вызывает камеру, которую нужно вызватьgetUserMedia API,MediaDevices.getUserMedia()Пользователю будет предложено дать разрешение на использование медиа-ввода, что сгенерируетMediaStream, который содержит треки запрошенного типа мультимедиа. Этот поток может содержать видеодорожку (из аппаратных или виртуальных источников видео, таких как камеры, устройства видеозахвата, сервисы совместного использования экрана и т. д.), аудиодорожку (также из аппаратных или виртуальных источников звука, таких как микрофоны,A/D转换器д.), это может быть дорожка другого типа.
Он возвращает одинPromiseобъект, после успешногоresolveперезвони одинMediaStream对象; если пользователь отказывает в доступе или нужный медиа-источник недоступен,promiseМогуrejectперезвони одинPermissionDeniedError или NotFoundError. (вернутьpromise对象вероятно, ниresolveни будетreject, потому что пользователю не нужно разрешать или запрещать. )
Обычно вы можете использоватьnavigator.mediaDevicesполучитьMediaDevices, например:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// 使用这个stream
})
.catch(function(err) {
// 处理error
})
🔗идти кMDNУглубленное изучение:navigator.mediaDevices.getUserMedia
Библиотека разбора QR-кодаJSQR
jsQRчистыйJavaScriptБиблиотека разбора QR-кода, которая считывает необработанные изображения или камеры и находит, извлекает и анализирует любыеQR码.
Если вы хотите использоватьjsQRДля сканирования потока с веб-камеры вам необходимоImageDataИзвлеченный из видеопотока, может быть передан вjsQR.
jsQRЭкспорт метода, который принимает4параметры соответственно расшифровываются图像数据,宽,高так же как可选的对象Далее настройте поведение сканирования.
imageData: формат[r0, g0, b0, a0, r1, g1, b1, a1, ...]изUint8ClampedArray( 8位无符号整型固定数组)изrgbaПиксельные значения.
const code = jsQR(imageData, width, height, options);
if (code) {
console.log('找到二维码!', code);
}
🔗идти кgithubпонять глубже:jsQR
Код
обработать
Весь процесс сканирования кода показан на рисунке ниже: инициализация страницы, сначала проверьте, поддерживает ли ее браузерmediaDevicesСвязанныйAPI, браузер передаст камеру, в случае неудачи звонка будет выполнен обратный вызов с ошибкой, в случае успешного звонка будет захвачен видеопоток, а затем будет отсканирован скан-код.
Следующее содержимое разделяет процесс и соответственно реализует соответствующие функции.
Компонент кода сканированияScaner
структура страницы
Давайте сначала посмотрим на структуру страницы, которая в основном состоит из4Частичный состав:
- поле подсказки.
- Окно кода сканирования.
-
video: Показать видеопоток, захваченный камерой. -
canvas: рисовать видеокадры для распознавания QR-кода.
<template>
<div class="scaner" ref="scaner">
<!-- 提示框:用于在不兼容的浏览器中显示提示语 -->
<div class="banner" v-if="showBanner">
<i class="close_icon" @click="() => showBanner = false"></i>
<p class="text">若当前浏览器无法扫码,请切换其他浏览器尝试</p>
</div>
<!-- 扫码框:显示扫码动画 -->
<div class="cover">
<p class="line"></p>
<span class="square top left"></span>
<span class="square top right"></span>
<span class="square bottom right"></span>
<span class="square bottom left"></span>
<p class="tips">将二维码放入框内,即可自动扫描</p>
</div>
<!-- 视频流显示 -->
<video
v-show="showPlay"
class="source"
ref="video"
:width="videoWH.width"
:height="videoWH.height"
controls
></video>
<canvas v-show="!showPlay" ref="canvas" />
<button v-show="showPlay" @click="run">开始</button>
</div>
</template>
метод: рисовать
- рисовать линии.
- Рамка изображения (используется для рисования прямоугольной графики после успешного сканирования кода).
// 画线
drawLine (begin, end) {
this.canvas.beginPath();
this.canvas.moveTo(begin.x, begin.y);
this.canvas.lineTo(end.x, end.y);
this.canvas.lineWidth = this.lineWidth;
this.canvas.strokeStyle = this.lineColor;
this.canvas.stroke();
},
// 画框
drawBox (location) {
if (this.drawOnfound) {
this.drawLine(location.topLeftCorner, location.topRightCorner);
this.drawLine(location.topRightCorner, location.bottomRightCorner);
this.drawLine(location.bottomRightCorner, location.bottomLeftCorner);
this.drawLine(location.bottomLeftCorner, location.topLeftCorner);
}
},
Метод: Инициализировать
- Проверьте поддержку.
- Включите камеру.
- Обработка успеха и неудачи.
// 初始化
setup () {
// 判断了浏览器是否支持挂载在MediaDevices.getUserMedia()的方法
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
this.previousCode = null;
this.parity = 0;
this.active = true;
this.canvas = this.$refs.canvas.getContext("2d");
// 获取摄像头模式,默认设置是后置摄像头
const facingMode = this.useBackCamera ? { exact: 'environment' } : 'user';
// 摄像头视频处理
const handleSuccess = stream => {
if (this.$refs.video.srcObject !== undefined) {
this.$refs.video.srcObject = stream;
} else if (window.videoEl.mozSrcObject !== undefined) {
this.$refs.video.mozSrcObject = stream;
} else if (window.URL.createObjectURL) {
this.$refs.video.src = window.URL.createObjectURL(stream);
} else if (window.webkitURL) {
this.$refs.video.src = window.webkitURL.createObjectURL(stream);
} else {
this.$refs.video.src = stream;
}
// 不希望用户来拖动进度条的话,可以直接使用playsinline属性,webkit-playsinline属性
this.$refs.video.playsInline = true;
const playPromise = this.$refs.video.play();
playPromise.catch(() => (this.showPlay = true));
// 视频开始播放时进行周期性扫码识别
playPromise.then(this.run);
};
// 捕获视频流
navigator.mediaDevices
.getUserMedia({ video: { facingMode } })
.then(handleSuccess)
.catch(() => {
navigator.mediaDevices
.getUserMedia({ video: true })
.then(handleSuccess)
.catch(error => {
this.$emit("error-captured", error);
});
});
}
},
Метод: периодическое сканирование
run () {
if (this.active) {
// 浏览器在下次重绘前循环调用扫码方法
requestAnimationFrame(this.tick);
}
},
Метод: Обратный вызов в случае успеха
// 二维码识别成功事件处理
found (code) {
if (this.previousCode !== code) {
this.previousCode = code;
} else if (this.previousCode === code) {
this.parity += 1;
}
if (this.parity > 2) {
this.active = this.stopOnScanned ? false : true;
this.parity = 0;
this.$emit("code-scanned", code);
}
},
Метод: стоп
// 完全停止
fullStop () {
if (this.$refs.video && this.$refs.video.srcObject) {
// 停止视频流序列轨道
this.$refs.video.srcObject.getTracks().forEach(t => t.stop());
}
}
Метод: сканирование
- Нарисуйте кадры видео.
- Идентификация кода сканирования.
// 周期性扫码识别
tick () {
// 视频处于准备阶段,并且已经加载足够的数据
if (this.$refs.video && this.$refs.video.readyState === this.$refs.video.HAVE_ENOUGH_DATA) {
// 开始在画布上绘制视频
this.$refs.canvas.height = this.videoWH.height;
this.$refs.canvas.width = this.videoWH.width;
this.canvas.drawImage(this.$refs.video, 0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
// getImageData() 复制画布上制定矩形的像素数据
const imageData = this.canvas.getImageData(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
let code = false;
try {
// 识别二维码
code = jsQR(imageData.data, imageData.width, imageData.height);
} catch (e) {
console.error(e);
}
// 如果识别出二维码,绘制矩形框
if (code) {
this.drawBox(code.location);
// 识别成功事件处理
this.found(code.data);
}
}
this.run();
},
родительский компонент
ScanerРодительский компонент в основном загружает страницу и отображаетScanerОбратный вызов результата кода сканирования.
структура страницы
<template>
<div class="scan">
<!-- 页面导航栏 -->
<div class="nav">
<a class="close" @click="() => $router.go(-1)"></a>
<p class="title">Scan QRcode</p>
</div>
<div class="scroll-container">
<!-- 扫码子组件 -->
<Scaner
v-on:code-scanned="codeScanned"
v-on:error-captured="errorCaptured"
:stop-on-scanned="true"
:draw-on-found="true"
:responsive="false"
/>
</div>
</div>
</template>
Метод родительского компонента
import Scaner from '../components/Scaner';
export default {
name: 'Scan',
components: {
Scaner
},
data () {
return {
errorMessage: "",
scanned: ""
}
},
methods: {
codeScanned(code) {
this.scanned = code;
setTimeout(() => {
alert(`扫码解析成功: ${code}`);
}, 200)
},
errorCaptured(error) {
switch (error.name) {
case "NotAllowedError":
this.errorMessage = "Camera permission denied.";
break;
case "NotFoundError":
this.errorMessage = "There is no connected camera.";
break;
case "NotSupportedError":
this.errorMessage =
"Seems like this page is served in non-secure context.";
break;
case "NotReadableError":
this.errorMessage =
"Couldn't access your camera. Is it already in use?";
break;
case "OverconstrainedError":
this.errorMessage = "Constraints don't match any installed camera.";
break;
default:
this.errorMessage = "UNKNOWN ERROR: " + error.message;
}
console.error(this.errorMessage);
alert('相机调用失败');
}
},
mounted () {
var str = navigator.userAgent.toLowerCase();
var ver = str.match(/cpu iphone os (.*?) like mac os/);
// 经测试 iOS 10.3.3以下系统无法成功调用相机摄像头
if (ver && ver[1].replace(/_/g,".") < '10.3.3') {
alert('相机调用失败');
}
}
полный код
🔗github: GitHub.com/dragon IR/ также 5…
Суммировать
Расширение приложения
Думаю следующих функций можно добиться вызовом камеры через браузер и сканированием и идентификацией.Какие еще функции думаете很哇塞🌟Функциональное приложение может быть реализовано путем сканирования кода на стороне браузера.😂?
-
🌏Прыжок по ссылке. -
🛒проверить цену. -
🔒Аутентификация входа. -
📂загрузка документа.
совместимость
-
❗даже использоватьadapter,getUserMedia APIЕсть также неподдерживаемые в некоторых браузерах. -
❗Старые браузеры (например,iOS 10.3последующий),AndroidНишевые браузеры (например,IQOOвстроенный браузер) не совместим. -
❗QQ,微信Встроенный браузер не вызывается.