Advanced: Built-in QR Scanner
Relevant source files
The following files were used as context for generating this wiki page:
The Built-in QR Scanner is an advanced feature of the QR-Tool designed to provide immediate feedback on the scannability of a newly generated QR code. Instead of requiring the user to scan the code with an external device, the application automatically performs a client-side scan on the generated QR code image. This serves as a quality assurance check, verifying that the code is valid and decodable before the user downloads it.
This system leverages the @zxing/browser library to perform the decoding directly on the HTML <canvas> element where the QR code is rendered. The result of the scan—success, warning, or failure—is then displayed to the user in real-time.
Sources: README.md, src/App.jsx:25,510-525, src/utils/qr-scanner.js
Architecture and Dependencies
The scanner functionality is implemented entirely on the client-side and relies on a key external library.
Core Dependency
The scanning capability is provided by the @zxing/browser library, which is a JavaScript port of the ZXing ("Zebra Crossing") multi-format 1D/2D barcode image processing library. This dependency is declared in the project's package.json.
"dependencies": {
"@zxing/browser": "^0.1.5",
"qrcode.react": "^4.2.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
}
Sources: package.json:13-18
System Architecture
The scanner is architecturally simple, consisting of a utility module (qr-scanner.js) that is imported and used by the main App component. The App component passes the rendered QR code canvas to the scanner utility, which in turn uses the @zxing/browser library to perform the decoding.
The following diagram illustrates the component and module relationships.
Integration and Triggering Flow
The QR scanner is automatically triggered within the App component whenever the generated QR code changes. This is managed by a React.useEffect hook that observes changes to the qrProps object.
Trigger Mechanism
- A user modifies an input (e.g., URL, text, color).
- The
qrPropsobject inApp.jsxis re-calculated. - A
useEffecthook, which depends onqrProps, is triggered. - Inside the hook, a
setTimeoutof 500ms is initiated. This debounce prevents scanning on every keystroke, improving performance. - After the delay, the
testQRScanfunction is called with the QR code's<canvas>element. - The result from
testQRScanupdates thescanResultstate, which causes the UI to display a feedback message.
For performance reasons, the scan is automatically skipped if the QR code size exceeds 2048px. In this case, a default success message is shown.
Sources: src/App.jsx:510-525
Sequence Diagram
This diagram shows the sequence of events from a user action to the UI update with the scan result.
Scanning Logic
The core scanning logic is encapsulated in the testQRScan function within src/utils/qr-scanner.js.
testQRScan(canvas, includeMargin)
This asynchronous function attempts to decode the QR code from a given <canvas> element.
- Parameters:
canvas: TheHTMLCanvasElementcontaining the rendered QR code.includeMargin: A boolean indicating if the QR code's quiet zone (margin) is part of the canvas. This seems to be used for context but not directly in the decoding call.
- Process:
- It first checks if a
canvasis provided. If not, it returns a failure state. - It instantiates
BrowserQRCodeReader. - It wraps the core logic in a
try...catchblock to handle errors from the ZXing library (e.g., if no QR code is found). - It calls
reader.decodeFromCanvas(canvas)to attempt decoding. - If successful, it returns a success object:
{ status: 'success', message: '✅ QR hợp lệ và có thể quét được' }. - If the
decodeFromCanvascall throws an error, thecatchblock executes, returning a failure object:{ status: 'error', message: '❌ Lỗi: Không thể quét QR. Thử tăng kích thước hoặc độ tương phản.' }.
- It first checks if a
The following flowchart details the logic within testQRScan.
Sources: src/utils/qr-scanner.js:9-30
Resource Management
To prevent memory leaks or unnecessary resource consumption (like holding onto camera permissions, even if not used here), the application includes a cleanup mechanism.
cleanupReader()
- This function is exported from
qr-scanner.js. - It checks for a global
readerinstance and calls itsreset()method. Thereset()method in@zxing/browserstops any ongoing scan and releases associated resources. - This function is called from a top-level
useEffectcleanup function inApp.jsx, ensuring resources are freed when the component unmounts.
// src/App.jsx
React.useEffect(() => {
return () => cleanupReader();
}, []);
Sources: src/App.jsx:291-293, src/utils/qr-scanner.js:32-38
UI Feedback
The result of the scan is communicated to the user through a status message displayed above the QR code preview.
Scan Result State
The scanResult state in App.jsx is an object that holds the outcome of the scan.
| Property | Type | Description |
|---|---|---|
status | string | The status of the scan: success, warning, or error. |
message | string | The user-facing feedback message. |
Sources: src/App.jsx:453, 523, src/utils/qr-scanner.js:13, 22, 27
Display Logic
A conditional block in App.jsx renders a div whose styling (colors and border) is determined by the scanResult.status.
success: Green-themed (emerald) banner.warning: Yellow-themed (amber) banner.error: Red-themed (rose) banner.
// src/App.jsx
{scanResult && (
<div
className={`mb-4 rounded-xl border-2 px-4 py-3 text-sm font-bold ${
scanResult.status === 'success'
? 'bg-emerald-50 ...'
: scanResult.status === 'warning'
? 'bg-amber-50 ...'
: 'bg-rose-50 ...'
}`}
role="status"
aria-live="polite"
>
{scanResult.message}
</div>
)}
Sources: src/App.jsx:904-921
Summary
The built-in QR scanner is a crucial quality-of-life feature in QR-Tool. By automatically validating the generated QR code using the @zxing/browser library, it provides users with immediate confidence that their QR code is functional. The integration is handled efficiently through React hooks with debouncing, and clear UI feedback communicates the scannability status, preventing users from downloading a potentially faulty QR code.
Sources: README.md, src/App.jsx, src/utils/qr-scanner.js