91 lines
5.5 KiB
HTML
91 lines
5.5 KiB
HTML
|
|
<!-- ═══════════════ QR CODE READER ═══════════════ -->
|
|||
|
|
<div class="page" id="page-qrreader">
|
|||
|
|
<button class="back-btn" onclick="showPage('home')">← Back to Tools</button>
|
|||
|
|
<div class="section-header">
|
|||
|
|
<h2><i class="fas fa-camera" style="color:var(--cyan)"></i> QR Code Reader</h2>
|
|||
|
|
<p>Scan QR codes using your camera or upload an image file.</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;">
|
|||
|
|
<!-- Left: Input -->
|
|||
|
|
<div>
|
|||
|
|
<div class="panel-label">Scan Method</div>
|
|||
|
|
<div class="btn-group">
|
|||
|
|
<button class="btn btn-primary" id="qrCameraBtn" onclick="startQrCamera()"><i class="fas fa-video"></i> Use Camera</button>
|
|||
|
|
<button class="btn btn-secondary" id="qrStopBtn" onclick="stopQrCamera()" style="display:none;"><i class="fas fa-stop"></i> Stop Camera</button>
|
|||
|
|
<label class="btn btn-secondary" style="cursor:pointer;">
|
|||
|
|
<i class="fas fa-upload"></i> Upload Image
|
|||
|
|
<input type="file" id="qrFileInput" accept="image/*" onchange="scanQrFromFile(event)" style="display:none;" />
|
|||
|
|
</label>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Camera feed -->
|
|||
|
|
<div id="qrCameraContainer" style="display:none;margin-top:16px;">
|
|||
|
|
<video id="qrVideo" style="width:100%;border-radius:var(--radius);border:1px solid var(--border);background:#000;" autoplay playsinline muted></video>
|
|||
|
|
<canvas id="qrScanCanvas" style="display:none;"></canvas>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Image preview -->
|
|||
|
|
<div id="qrImagePreview" style="display:none;margin-top:16px;">
|
|||
|
|
<img id="qrPreviewImg" alt="Uploaded QR image" src="" style="width:100%;border-radius:var(--radius);border:1px solid var(--border);" />
|
|||
|
|
<canvas id="qrImgCanvas" style="display:none;"></canvas>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Right: Result -->
|
|||
|
|
<div>
|
|||
|
|
<div class="panel-label">Scan Result</div>
|
|||
|
|
<div id="qrReaderPlaceholder" style="color:var(--text-muted);font-size:0.85rem;padding:40px 20px;text-align:center;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius);">
|
|||
|
|
<i class="fas fa-qrcode" style="font-size:3rem;margin-bottom:12px;display:block;opacity:0.3;"></i>
|
|||
|
|
Point your camera at a QR code or upload an image to scan.
|
|||
|
|
</div>
|
|||
|
|
<div id="qrReaderResult" style="display:none;">
|
|||
|
|
<div class="result-card">
|
|||
|
|
<div class="panel-label">Decoded Content</div>
|
|||
|
|
<div id="qrDecodedText" style="font-family:var(--font-mono);font-size:0.9rem;padding:14px;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius-sm);word-break:break-all;margin-bottom:12px;color:var(--cyan);"></div>
|
|||
|
|
<div class="panel-label">Type</div>
|
|||
|
|
<div id="qrDecodedType" style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:12px;"></div>
|
|||
|
|
<div class="btn-group">
|
|||
|
|
<button class="btn btn-green" onclick="copyText(document.getElementById('qrDecodedText').textContent)"><i class="fas fa-copy"></i> Copy</button>
|
|||
|
|
<button class="btn btn-secondary" id="qrOpenLinkBtn" style="display:none;" onclick="window.open(document.getElementById('qrDecodedText').textContent,'_blank')"><i class="fas fa-external-link-alt"></i> Open Link</button>
|
|||
|
|
</div>
|
|||
|
|
<div class="panel-label" style="margin-top:12px;">Scan History</div>
|
|||
|
|
<div id="qrScanHistory"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="status" id="qrReaderStatus"></div>
|
|||
|
|
<div class="api-usage">
|
|||
|
|
<button class="api-usage-toggle" onclick="toggleApiUsage(this)"><span><i class="fas fa-terminal"></i> API Usage <span class="badge">Client-side</span></span><i class="fas fa-chevron-down"></i></button>
|
|||
|
|
<div class="api-usage-body">
|
|||
|
|
<div class="api-baseurl-note">ℹ️ QR Code reading runs entirely <strong>client-side</strong> using the <code>jsQR</code> library. No server API is needed.</div>
|
|||
|
|
<div class="api-endpoint">
|
|||
|
|
<div class="api-desc">Decode QR codes from image data using the jsQR library (works in Node.js and browsers).</div>
|
|||
|
|
<div class="api-code"><button class="api-code-copy" onclick="copyApiCode(this)">Copy</button><span class="cm">// Install: npm install jsqr</span>
|
|||
|
|
<span class="cm">// Browser CDN: https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js</span>
|
|||
|
|
|
|||
|
|
<span class="cm">// Read from a canvas element:</span>
|
|||
|
|
<span class="kw">const</span> canvas = document.<span class="fn">getElementById</span>(<span class="str">'myCanvas'</span>);
|
|||
|
|
<span class="kw">const</span> ctx = canvas.<span class="fn">getContext</span>(<span class="str">'2d'</span>);
|
|||
|
|
<span class="kw">const</span> imageData = ctx.<span class="fn">getImageData</span>(0, 0, canvas.width, canvas.height);
|
|||
|
|
|
|||
|
|
<span class="kw">const</span> code = <span class="fn">jsQR</span>(imageData.data, imageData.width, imageData.height);
|
|||
|
|
<span class="kw">if</span> (code) {
|
|||
|
|
console.<span class="fn">log</span>(<span class="str">"Decoded:"</span>, code.data);
|
|||
|
|
<span class="cm">// → "https://example.com"</span>
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
<span class="cm">// Read from camera (MediaDevices API):</span>
|
|||
|
|
<span class="kw">const</span> stream = <span class="kw">await</span> navigator.mediaDevices.<span class="fn">getUserMedia</span>({ video: { facingMode: <span class="str">'environment'</span> } });
|
|||
|
|
<span class="kw">const</span> video = document.<span class="fn">createElement</span>(<span class="str">'video'</span>);
|
|||
|
|
video.srcObject = stream;
|
|||
|
|
video.<span class="fn">play</span>();
|
|||
|
|
<span class="cm">// Then draw video frames to canvas and scan with jsQR</span></div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|