Page 1 of 1

Barcode Scan with SpiderBasic possible?

Posted: Tue Mar 12, 2024 7:35 am
by Dirk Geppert
Hi guys,

I would like to be able to scan a QR code with my own WebApp and then process it accordingly.
Spiderbasic in combination with Purebasic for the backend is a very good choice for data processing.

Has anyone here ever successfully realised a barcode scan with Spiderbasic?

I have found two good Javascript solutions on the net that recognise QR codes very quickly on a mobile phone:

- https://nimiq.github.io/qr-scanner/demo/
- https://scanapp.org/

How can you connect Spider with this html? Do you have to reload all this via DOM injection?

Code: Select all


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>QR Scanner Demo</title>
</head>
<body>
<h1>Scan from WebCam:</h1>
<div id="video-container">
    <video id="qr-video"></video>
</div>
<div>
    <label>
        Highlight Style
        <select id="scan-region-highlight-style-select">
            <option value="default-style">Default style</option>
            <option value="example-style-1">Example custom style 1</option>
            <option value="example-style-2">Example custom style 2</option>
        </select>
    </label>
    <label>
        <input id="show-scan-region" type="checkbox">
        Show scan region canvas
    </label>
</div>
<div>
    <select id="inversion-mode-select">
        <option value="original">Scan original (dark QR code on bright background)</option>
        <option value="invert">Scan with inverted colors (bright QR code on dark background)</option>
        <option value="both">Scan both</option>
    </select>
    <br>
</div>
<b>Device has camera: </b>
<span id="cam-has-camera"></span>
<br>
<div>
    <b>Preferred camera:</b>
    <select id="cam-list">
        <option value="environment" selected>Environment Facing (default)</option>
        <option value="user">User Facing</option>
    </select>
</div>
<b>Camera has flash: </b>
<span id="cam-has-flash"></span>
<div>
    <button id="flash-toggle">📸 Flash: <span id="flash-state">off</span></button>
</div>
<br>
<b>Detected QR code: </b>
<span id="cam-qr-result">None</span>
<br>
<b>Last detected at: </b>
<span id="cam-qr-result-timestamp"></span>
<br>
<button id="start-button">Start</button>
<button id="stop-button">Stop</button>
<hr>

<h1>Scan from File:</h1>
<input type="file" id="file-selector">
<b>Detected QR code: </b>
<span id="file-qr-result">None</span>

<!--<script src="./qr-scanner.umd.min.js"></script>-->
<!--<script src="./qr-scanner.legacy.min.js"></script>-->
<script type="module">
    import QrScanner from "./qr-scanner.min.js";

    const video = document.getElementById('qr-video');
    const videoContainer = document.getElementById('video-container');
    const camHasCamera = document.getElementById('cam-has-camera');
    const camList = document.getElementById('cam-list');
    const camHasFlash = document.getElementById('cam-has-flash');
    const flashToggle = document.getElementById('flash-toggle');
    const flashState = document.getElementById('flash-state');
    const camQrResult = document.getElementById('cam-qr-result');
    const camQrResultTimestamp = document.getElementById('cam-qr-result-timestamp');
    const fileSelector = document.getElementById('file-selector');
    const fileQrResult = document.getElementById('file-qr-result');

    function setResult(label, result) {
        console.log(result.data);
        label.textContent = result.data;
        camQrResultTimestamp.textContent = new Date().toString();
        label.style.color = 'teal';
        clearTimeout(label.highlightTimeout);
        label.highlightTimeout = setTimeout(() => label.style.color = 'inherit', 100);
    }

    // ####### Web Cam Scanning #######

    const scanner = new QrScanner(video, result => setResult(camQrResult, result), {
        onDecodeError: error => {
            camQrResult.textContent = error;
            camQrResult.style.color = 'inherit';
        },
        highlightScanRegion: true,
        highlightCodeOutline: true,
    });

    const updateFlashAvailability = () => {
        scanner.hasFlash().then(hasFlash => {
            camHasFlash.textContent = hasFlash;
            flashToggle.style.display = hasFlash ? 'inline-block' : 'none';
        });
    };

    scanner.start().then(() => {
        updateFlashAvailability();
        // List cameras after the scanner started to avoid listCamera's stream and the scanner's stream being requested
        // at the same time which can result in listCamera's unconstrained stream also being offered to the scanner.
        // Note that we can also start the scanner after listCameras, we just have it this way around in the demo to
        // start the scanner earlier.
        QrScanner.listCameras(true).then(cameras => cameras.forEach(camera => {
            const option = document.createElement('option');
            option.value = camera.id;
            option.text = camera.label;
            camList.add(option);
        }));
    });

    QrScanner.hasCamera().then(hasCamera => camHasCamera.textContent = hasCamera);

    // for debugging
    window.scanner = scanner;

    document.getElementById('scan-region-highlight-style-select').addEventListener('change', (e) => {
        videoContainer.className = e.target.value;
        scanner._updateOverlay(); // reposition the highlight because style 2 sets position: relative
    });

    document.getElementById('show-scan-region').addEventListener('change', (e) => {
        const input = e.target;
        const label = input.parentNode;
        label.parentNode.insertBefore(scanner.$canvas, label.nextSibling);
        scanner.$canvas.style.display = input.checked ? 'block' : 'none';
    });

    document.getElementById('inversion-mode-select').addEventListener('change', event => {
        scanner.setInversionMode(event.target.value);
    });

    camList.addEventListener('change', event => {
        scanner.setCamera(event.target.value).then(updateFlashAvailability);
    });

    flashToggle.addEventListener('click', () => {
        scanner.toggleFlash().then(() => flashState.textContent = scanner.isFlashOn() ? 'on' : 'off');
    });

    document.getElementById('start-button').addEventListener('click', () => {
        scanner.start();
    });

    document.getElementById('stop-button').addEventListener('click', () => {
        scanner.stop();
    });

    // ####### File Scanning #######

    fileSelector.addEventListener('change', event => {
        const file = fileSelector.files[0];
        if (!file) {
            return;
        }
        QrScanner.scanImage(file, { returnDetailedScanResult: true })
            .then(result => setResult(fileQrResult, result))
            .catch(e => setResult(fileQrResult, { data: e || 'No QR code found.' }));
    });
</script>

<style>
    div {
        margin-bottom: 16px;
    }

    #video-container {
        line-height: 0;
    }

    #video-container.example-style-1 .scan-region-highlight-svg,
    #video-container.example-style-1 .code-outline-highlight {
        stroke: #64a2f3 !important;
    }

    #video-container.example-style-2 {
        position: relative;
        width: max-content;
        height: max-content;
        overflow: hidden;
    }
    #video-container.example-style-2 .scan-region-highlight {
        border-radius: 30px;
        outline: rgba(0, 0, 0, .25) solid 50vmax;
    }
    #video-container.example-style-2 .scan-region-highlight-svg {
        display: none;
    }
    #video-container.example-style-2 .code-outline-highlight {
        stroke: rgba(255, 255, 255, .5) !important;
        stroke-width: 15 !important;
        stroke-dasharray: none !important;
    }

    #flash-toggle {
        display: none;
    }

    hr {
        margin-top: 32px;
    }
    input[type="file"] {
        display: block;
        margin-bottom: 16px;
    }
</style>
</body>
</html>


Re: Barcode Scan with SpiderBasic possible?

Posted: Wed Mar 13, 2024 3:15 am
by Quin
This doesn't look horribly complicated, I imagine the HTML could be translated to SpiderBasic gadgets, and the JavaScript (<script> tags) could be loaded with LoadScript(). From the docs:
Syntax
LoadScript(URL$, Callback [, Type])
Description
Load a JavaScript script (.js) into the app
Parameters
URL$
The URL of the javascript to load.
Callback
The callback called once the loading has finished. If the loading is successful, the 'Success' callback parameter will be set to #True, if not it will be set to #False. It has to use the following syntax:
Type (optional)
Can be one of the following values:
#PB_Script_JavaScript: the script to load is a JavaScript (default)
#PB_Script_CSS: the script to load is a CSS
Procedure Callback(URL$, Success)
; Code here
EndProcedure
Return value
None.