🔍 Add support for barcode scanning and improve QR code parsing logic
This commit is contained in:
1
parse-qr/html5-qrcode.min.js
vendored
Normal file
1
parse-qr/html5-qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@
|
||||
<link rel="icon" href="https://cdn.hatter.ink/doc/18811_3C6AA21718A09D034E40D557D51E7787/qr.png" type="image/png">
|
||||
<link rel="shortcut icon" href="https://cdn.hatter.ink/doc/18811_3C6AA21718A09D034E40D557D51E7787/qr.png" type="image/png">
|
||||
<link rel="apple-touch-icon" href="https://cdn.hatter.ink/doc/18811_3C6AA21718A09D034E40D557D51E7787/qr.png">
|
||||
<script src="html5-qrcode.min.js"></script>
|
||||
<script src="jsQR.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
@@ -50,6 +51,7 @@
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
@@ -380,7 +382,7 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>
|
||||
🔍 QR Code Parser
|
||||
🔍 QR & Barcode Parser
|
||||
<button class="refresh-btn" id="refreshBtn" title="Refresh">🔄</button>
|
||||
</h1>
|
||||
<p class="subtitle">Drag & drop, paste, or click to browse an image</p>
|
||||
@@ -415,10 +417,12 @@
|
||||
|
||||
<div class="camera-modal" id="cameraModal">
|
||||
<div class="camera-status" id="cameraStatus">Starting camera...</div>
|
||||
<video id="video" autoplay playsinline></video>
|
||||
<div id="qr-reader" style="width: 100%;"></div>
|
||||
<button class="close-camera" id="closeCamera">Close</button>
|
||||
</div>
|
||||
|
||||
<div style="display: none;"><div id="qr-reader-hidden"></div></div>
|
||||
|
||||
<script>
|
||||
const dropZone = document.getElementById('dropZone');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
@@ -437,8 +441,7 @@
|
||||
const historyList = document.getElementById('historyList');
|
||||
const clearHistoryBtn = document.getElementById('clearHistoryBtn');
|
||||
const HISTORY_KEY = 'qr_scan_history';
|
||||
let stream = null;
|
||||
let scanInterval = null;
|
||||
let html5QrcodeScanner = null;
|
||||
|
||||
function loadHistory() {
|
||||
const stored = localStorage.getItem(HISTORY_KEY);
|
||||
@@ -587,36 +590,61 @@
|
||||
preview.classList.add('visible');
|
||||
dropZone.classList.add('has-image');
|
||||
|
||||
decodeQR(e.target.result);
|
||||
decodeQR(file);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function decodeQR(dataURL) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
function decodeQR(file) {
|
||||
// 尝试使用 html5-qrcode (支持一维码和二维码)
|
||||
if (typeof Html5Qrcode !== 'undefined') {
|
||||
const html5QrCode = new Html5Qrcode('qr-reader-hidden');
|
||||
|
||||
html5QrCode.scanFile(file, true)
|
||||
.then(decodedText => {
|
||||
hideLoading();
|
||||
if (decodedText) {
|
||||
showResult(decodedText);
|
||||
} else {
|
||||
showError('No QR code or barcode found in the image. Please try with a clearer image.');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
hideLoading();
|
||||
console.error('Scan error:', err);
|
||||
showError('Failed to decode. Please try with a clearer image.');
|
||||
});
|
||||
} else {
|
||||
// 回退到 jsQR (仅支持二维码)
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
|
||||
hideLoading();
|
||||
hideLoading();
|
||||
|
||||
if (code) {
|
||||
showResult(code.data);
|
||||
} else {
|
||||
showError('No QR code found in the image. Please try with a clearer image.');
|
||||
}
|
||||
};
|
||||
img.onerror = () => {
|
||||
hideLoading();
|
||||
showError('Failed to load image');
|
||||
};
|
||||
img.src = dataURL;
|
||||
if (code) {
|
||||
showResult(code.data);
|
||||
} else {
|
||||
showError('No QR code found in the image. Please try with a clearer image.');
|
||||
}
|
||||
};
|
||||
img.onerror = () => {
|
||||
hideLoading();
|
||||
showError('Failed to load image');
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
function showResult(text) {
|
||||
@@ -663,53 +691,54 @@
|
||||
location.reload();
|
||||
});
|
||||
|
||||
cameraBtn.addEventListener('click', async () => {
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: 'environment' }
|
||||
});
|
||||
video.srcObject = stream;
|
||||
cameraModal.classList.add('visible');
|
||||
cameraStatus.textContent = 'Scanning...';
|
||||
startScan();
|
||||
} catch (err) {
|
||||
cameraStatus.textContent = 'Camera access denied or not available';
|
||||
console.error('Camera error:', err);
|
||||
}
|
||||
cameraBtn.addEventListener('click', () => {
|
||||
cameraModal.classList.add('visible');
|
||||
cameraStatus.textContent = 'Starting camera...';
|
||||
startScan();
|
||||
});
|
||||
|
||||
closeCamera.addEventListener('click', stopCamera);
|
||||
|
||||
function stopCamera() {
|
||||
if (stream) {
|
||||
stream.getTracks().forEach(track => track.stop());
|
||||
stream = null;
|
||||
if (html5QrcodeScanner) {
|
||||
html5QrcodeScanner.stop().then(() => {
|
||||
html5QrcodeScanner.clear();
|
||||
html5QrcodeScanner = null;
|
||||
}).catch(err => {
|
||||
console.error('Failed to stop scanner:', err);
|
||||
});
|
||||
}
|
||||
if (scanInterval) {
|
||||
clearInterval(scanInterval);
|
||||
scanInterval = null;
|
||||
}
|
||||
video.srcObject = null;
|
||||
cameraModal.classList.remove('visible');
|
||||
cameraStatus.textContent = 'Starting camera...';
|
||||
}
|
||||
|
||||
function startScan() {
|
||||
scanInterval = setInterval(() => {
|
||||
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||
|
||||
if (code) {
|
||||
showResult(code.data);
|
||||
if (typeof Html5Qrcode !== 'undefined') {
|
||||
html5QrcodeScanner = new Html5Qrcode('qr-reader');
|
||||
|
||||
html5QrcodeScanner.start(
|
||||
{ facingMode: 'environment' },
|
||||
{
|
||||
fps: 10,
|
||||
qrbox: { width: 250, height: 250 }
|
||||
},
|
||||
(decodedText) => {
|
||||
showResult(decodedText);
|
||||
stopCamera();
|
||||
},
|
||||
(errorMessage) => {
|
||||
// Scanning, no code found yet
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
).then(() => {
|
||||
cameraStatus.textContent = 'Scanning...';
|
||||
}).catch(err => {
|
||||
cameraStatus.textContent = 'Camera access denied or not available';
|
||||
console.error('Camera error:', err);
|
||||
});
|
||||
} else {
|
||||
// 回退到 jsQR
|
||||
cameraStatus.textContent = 'Camera not available, using fallback...';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user