Поиск по сайту:

Как сканировать QR-коды в веб-браузерах с помощью Web Workers и jsQR


QR-коды стали гораздо более популярными в последние годы. Они широко используются для доставки информации и облегчения регистрации. Хотя чаще всего они встречаются как часть нативных мобильных приложений, вы также можете включить QR-сканирование в свои веб-сайты.

Вот как можно использовать популярную библиотеку jsQR в сочетании с Web Workers, чтобы обеспечить высокопроизводительное сканирование QR-кодов в Интернете. Мы предполагаем, что вы уже знакомы с основами JavaScript и у вас есть работающий сайт, на который вы готовы добавить свой код.

1. Начало работы

Начните с загрузки библиотеки jsQR в предварительно скомпилированном распространяемом формате. Убедитесь, что он общедоступен на вашем веб-сервере; в этой статье мы предполагаем, что URL-адрес — /jsQR.js. jsQR также доступен в виде пакета npm, если у вас настроена процедура сборки.

Этот пакет обеспечивает обнаружение в реальном времени QR-кодов, видимых в видеопотоке. Он извлекает данные из кода и передает их вашему приложению.

2. Получение изображения с камеры

Следующим шагом является получение MediaStream из браузера. Используйте API mediaDevices, чтобы получить новый поток с камеры пользователя:

const getCamera = async () => {
 
    if (!navigator.mediaDevices) {
        throw new Error("mediaDevices API unavailable.");
    }
 
    const devices = await navigator.mediaDevices.enumerateDevices();
    const cameras = devices.filter(d => (d.kind === "videoinput"));
    return cameras[0];
 
};

Выбираем первую попавшуюся камеру. Вы можете добавить дополнительную логику, чтобы включить выбор конкретной камеры, указанной пользователем. В реальном приложении также следует улучшить обработку ошибок, когда API mediaDevices недоступен. Это может быть связано с тем, что пользователь использует старый веб-браузер или навсегда заблокировал разрешение на доступ к камере.

Используйте функцию getCamera() для получения видеопотока. Прикрепите поток к элементу <video>, чтобы его можно было воспроизвести и отобразить пользователю:

<video  
    autoplay="true"
    id="video"
    muted="true" />
const stream = await getCamera();
const video = document.getElementById("video");
 
video.srcObject = stream;
await video.play();

3. Создание холста

Следующим шагом является создание элемента canvas. Видеоданные будут передаваться с камеры на холст, где пиксели изображения будут извлекаться и передаваться в jsQR. Размер холста должен соответствовать размерам видеопотока.

const videoTracks = await stream.getVideoTracks();
const videoTrackSettings = videoTracks[0].getSettings();
 
const canvas = document.createElement("canvas");
canvas.height = videoTrackSettings.height;
canvas.width = videoTrackSettings.width;
 
const canvasContext = canvas.getContext("2d");

Контекст холста будет использоваться на следующем шаге для рисования каждого кадра видеопотока на холсте.

4. Добавление jsQR

Затем добавьте jsQR в свой код. Запуск jsQR в веб-воркере позволяет браузеру делегировать его фоновому процессу, повышая производительность. jsQR должен сканировать каждый видеокадр, поэтому запуск его в основном потоке JavaScript может привести к серьезным замедлениям на слабых устройствах.

Основной поток и ваш веб-воркер могут общаться с помощью сообщений. Ваш основной поток будет сообщать обработчику jsQR каждый раз, когда доступен новый видеокадр. Рабочий проверит этот кадр на наличие QR-кодов в своем фоновом потоке, а затем отправит сообщение в основной поток, когда кадр будет обработан.

Загрузите своего работника в свой основной код JavaScript и добавьте прослушиватель сообщений:

const qrWorker = new Worker("/qr-worker.js");
 
qrWorker.addEventListener("message", ({data}) => {
 
    if (data) {
        // Data from QR code available 
        // 
        // Handle a successful scan here.
    }
    else {
        // No QR code detected in this frame
        // 
        // Feed the next frame to the QR worker 
        // now (this code is introduced below).
        tick();     
    }
 
});

Затем добавьте qr-worker.js в свой проект. Он должен быть общедоступным по URL-адресу, указанному конструктору Worker. Браузеры загружают веб-воркер в то время, когда это необходимо.

importScripts("jsQR.js");
 
self.addEventListener("message", e => {
    const {data, width, height} = e.data;
    const qrData = jsQR(data, width, height);
    self.postMessage(qrData);
});

Функция importScripts() загружает библиотеку jsQR. Этот вызов эквивалентен тегу <script> в вашем HTML, но делает содержимое скрипта доступным для вашего веб-воркера.

Добавлен прослушиватель сообщений для получения событий из основного потока вашего JavaScript. Каждое событие должно включать данные, ширину и высоту видеокадра, передаваемого с камеры. Эти значения передаются jsQR, который пытается обнаружить QR-код внутри кадра. Результат отправляется обратно в основной поток.

5. Подключение всего

Последним шагом является создание цикла обновления, который периодически передает видеокадры рабочему процессу jsQR.

const updateJsQr = () => {
    canvasContext.drawImage(video, 0, 0, canvas.width, canvas.height);
    const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);
    qrWorker.postMessage({data: imageData, height: canvas.height, width: canvas.width});
}
 
const tick = () => requestAnimationFrame(updateJsQr);
 
tick();

Функция tick() запрашивает у браузера время для вызова updateJsQr() перед следующей перерисовкой. Эта функция получает текущий видеокадр, рисует его на холсте, а затем извлекает полученные данные изображения, готовые для передачи в jsQR. Метод postMessage() в рабочем экземпляре фактически отправляет данные.

Затем рабочий будет действовать с данными, как показано в приведенном выше коде. Результат обнаружения передается обратно в основной поток, который обрабатывает его, как показано на шаге 4. Когда QR-код обнаружен, ваше приложение должно использовать полученные данные для продвижения вперед в своем потоке. Когда код не обнаружен, tick() вызывается снова, чтобы передать следующий кадр QR-воркеру, готовый к оценке.

Этот механизм гарантирует, что вы не перегрузите браузер одновременным запуском нескольких обнаружений кадров. Каждый вызов jsQR() потенциально дорог, поэтому вам нужно подождать, пока не станет известен результат, прежде чем планировать другой. Цикл поддерживается только до тех пор, пока не будет получен успешный результат, при этом jsQR обрабатывает один кадр за раз. Пользовательский интерфейс вашего сайта и его предварительный просмотр камеры в реальном времени будут оставаться отзывчивыми, поскольку работник работает независимо в фоновом режиме.

6. Данные результатов jsQR

Каждый успешный вызов jsQR() возвращает объект результата со следующими свойствами:

  • data — строковые данные, извлеченные из QR-кода (это единственное свойство, используемое в приведенном выше примере).
  • binaryData — массив Uint8ClampedArray, содержащий необработанные байты, считанные из QR-кода.
  • версия – обнаруженная версия QR-кода.
  • location — объект, описывающий положение обнаруженного QR-кода в видеокадре, включая точки для каждого угла.

Данные недоступны, когда jsQR не может обнаружить код на предоставленном изображении.

7. Заключение

Сочетание jsQR с Web Workers позволяет реализовать высокопроизводительное сканирование QR-кода в веб-приложении. QR-коды — это простой и удобный механизм обмена данными, с которым уже знакомо большинство мобильных пользователей.

Хотя вы можете использовать jsQR как часть своего основного цикла, вам нужно будет реализовать агрессивное регулирование, чтобы ваш пользовательский интерфейс оставался отзывчивым. Это приведет к более длительной задержке до успешного обнаружения. Web Workers поддерживаются во всех современных браузерах и значительно повышают производительность этого решения, обеспечивая сканирование за доли секунды при оптимальных условиях освещения.




Все права защищены. © Linux-Console.net • 2019-2024