🔍 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="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="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">
|
<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>
|
<script src="jsQR.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-btn {
|
.refresh-btn {
|
||||||
@@ -380,7 +382,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>
|
<h1>
|
||||||
🔍 QR Code Parser
|
🔍 QR & Barcode Parser
|
||||||
<button class="refresh-btn" id="refreshBtn" title="Refresh">🔄</button>
|
<button class="refresh-btn" id="refreshBtn" title="Refresh">🔄</button>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="subtitle">Drag & drop, paste, or click to browse an image</p>
|
<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-modal" id="cameraModal">
|
||||||
<div class="camera-status" id="cameraStatus">Starting camera...</div>
|
<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>
|
<button class="close-camera" id="closeCamera">Close</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div style="display: none;"><div id="qr-reader-hidden"></div></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const dropZone = document.getElementById('dropZone');
|
const dropZone = document.getElementById('dropZone');
|
||||||
const fileInput = document.getElementById('fileInput');
|
const fileInput = document.getElementById('fileInput');
|
||||||
@@ -437,8 +441,7 @@
|
|||||||
const historyList = document.getElementById('historyList');
|
const historyList = document.getElementById('historyList');
|
||||||
const clearHistoryBtn = document.getElementById('clearHistoryBtn');
|
const clearHistoryBtn = document.getElementById('clearHistoryBtn');
|
||||||
const HISTORY_KEY = 'qr_scan_history';
|
const HISTORY_KEY = 'qr_scan_history';
|
||||||
let stream = null;
|
let html5QrcodeScanner = null;
|
||||||
let scanInterval = null;
|
|
||||||
|
|
||||||
function loadHistory() {
|
function loadHistory() {
|
||||||
const stored = localStorage.getItem(HISTORY_KEY);
|
const stored = localStorage.getItem(HISTORY_KEY);
|
||||||
@@ -587,36 +590,61 @@
|
|||||||
preview.classList.add('visible');
|
preview.classList.add('visible');
|
||||||
dropZone.classList.add('has-image');
|
dropZone.classList.add('has-image');
|
||||||
|
|
||||||
decodeQR(e.target.result);
|
decodeQR(file);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeQR(dataURL) {
|
function decodeQR(file) {
|
||||||
const img = new Image();
|
// 尝试使用 html5-qrcode (支持一维码和二维码)
|
||||||
img.onload = () => {
|
if (typeof Html5Qrcode !== 'undefined') {
|
||||||
const canvas = document.createElement('canvas');
|
const html5QrCode = new Html5Qrcode('qr-reader-hidden');
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
canvas.width = img.width;
|
html5QrCode.scanFile(file, true)
|
||||||
canvas.height = img.height;
|
.then(decodedText => {
|
||||||
ctx.drawImage(img, 0, 0);
|
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 imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
||||||
|
|
||||||
hideLoading();
|
hideLoading();
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
showResult(code.data);
|
showResult(code.data);
|
||||||
} else {
|
} else {
|
||||||
showError('No QR code found in the image. Please try with a clearer image.');
|
showError('No QR code found in the image. Please try with a clearer image.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
img.onerror = () => {
|
img.onerror = () => {
|
||||||
hideLoading();
|
hideLoading();
|
||||||
showError('Failed to load image');
|
showError('Failed to load image');
|
||||||
};
|
};
|
||||||
img.src = dataURL;
|
img.src = e.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showResult(text) {
|
function showResult(text) {
|
||||||
@@ -663,53 +691,54 @@
|
|||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
cameraBtn.addEventListener('click', async () => {
|
cameraBtn.addEventListener('click', () => {
|
||||||
try {
|
cameraModal.classList.add('visible');
|
||||||
stream = await navigator.mediaDevices.getUserMedia({
|
cameraStatus.textContent = 'Starting camera...';
|
||||||
video: { facingMode: 'environment' }
|
startScan();
|
||||||
});
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
closeCamera.addEventListener('click', stopCamera);
|
closeCamera.addEventListener('click', stopCamera);
|
||||||
|
|
||||||
function stopCamera() {
|
function stopCamera() {
|
||||||
if (stream) {
|
if (html5QrcodeScanner) {
|
||||||
stream.getTracks().forEach(track => track.stop());
|
html5QrcodeScanner.stop().then(() => {
|
||||||
stream = null;
|
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');
|
cameraModal.classList.remove('visible');
|
||||||
|
cameraStatus.textContent = 'Starting camera...';
|
||||||
}
|
}
|
||||||
|
|
||||||
function startScan() {
|
function startScan() {
|
||||||
scanInterval = setInterval(() => {
|
if (typeof Html5Qrcode !== 'undefined') {
|
||||||
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
html5QrcodeScanner = new Html5Qrcode('qr-reader');
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
canvas.width = video.videoWidth;
|
html5QrcodeScanner.start(
|
||||||
canvas.height = video.videoHeight;
|
{ facingMode: 'environment' },
|
||||||
const ctx = canvas.getContext('2d');
|
{
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
fps: 10,
|
||||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
qrbox: { width: 250, height: 250 }
|
||||||
const code = jsQR(imageData.data, imageData.width, imageData.height);
|
},
|
||||||
|
(decodedText) => {
|
||||||
if (code) {
|
showResult(decodedText);
|
||||||
showResult(code.data);
|
|
||||||
stopCamera();
|
stopCamera();
|
||||||
|
},
|
||||||
|
(errorMessage) => {
|
||||||
|
// Scanning, no code found yet
|
||||||
}
|
}
|
||||||
}
|
).then(() => {
|
||||||
}, 100);
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user