Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* This val creates a QR code scanner using the device's camera.
* It uses the jsQR library to decode QR codes from video frames.
* The app displays the scanned QR code content and additional information.
*
* We'll use the following approach:
* 1. Set up a video element to capture camera feed
* 2. Use canvas to process video frames
* 3. Use jsQR to decode QR codes from the frames
* 4. Display the QR code content and additional information
* 5. Add extensive debugging to identify issues
*/
/** @jsxImportSource https://esm.sh/react */
import React, { useState, useEffect, useRef } from "https://esm.sh/react";
import { createRoot } from "https://esm.sh/react-dom/client";
import jsQR from "https://esm.sh/jsqr";
function App() {
const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
const [qrCode, setQrCode] = useState<string | null>(null);
const [qrInfo, setQrInfo] = useState<any>(null);
const [error, setError] = useState<string | null>(null);
const [debug, setDebug] = useState<string[]>([]);
const addDebug = (message: string) => {
setDebug(prev => [...prev, `${new Date().toISOString()}: ${message}`]);
};
useEffect(() => {
const startCamera = async () => {
try {
addDebug("Attempting to access camera...");
const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } });
addDebug("Camera access granted.");
if (videoRef.current) {
videoRef.current.srcObject = stream;
addDebug("Video source set.");
videoRef.current.onloadedmetadata = () => {
addDebug(`Video dimensions: ${videoRef.current!.videoWidth}x${videoRef.current!.videoHeight}`);
};
} else {
addDebug("Video ref is null.");
}
} catch (error) {
console.error("Error accessing camera:", error);
setError(`Error accessing camera: ${error}`);
addDebug(`Camera access error: ${error}`);
}
};
startCamera();
return () => {
if (videoRef.current && videoRef.current.srcObject) {
const tracks = (videoRef.current.srcObject as MediaStream).getTracks();
tracks.forEach(track => track.stop());
addDebug("Camera stopped.");
}
};
}, []);
useEffect(() => {
const scanQRCode = () => {
if (videoRef.current && canvasRef.current) {
const video = videoRef.current;
const canvas = canvasRef.current;
const context = canvas.getContext('2d');
if (context && video.readyState === video.HAVE_ENOUGH_DATA) {
canvas.height = video.videoHeight;
canvas.width = video.videoWidth;
context.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
addDebug(`Scanning frame: ${canvas.width}x${canvas.height}`);
const code = jsQR(imageData.data, imageData.width, imageData.height);
if (code) {
setQrCode(code.data);
setQrInfo({
location: code.location,
version: code.version,
moduleSize: code.moduleSize,
});
addDebug(`QR Code found: ${code.data}`);
}
} else {
addDebug(`Video not ready. ReadyState: ${video.readyState}`);
}
} else {
addDebug("Video or canvas ref is null.");
}
requestAnimationFrame(scanQRCode);
};
scanQRCode();
}, []);
return (
<div>
curtcox-qrcodescanner.web.val.run
August 23, 2024