qr-secure-send 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.html +75 -30
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -73,7 +73,7 @@
73
73
  button.secondary:hover { background: #30363d; }
74
74
 
75
75
  #qr-output { text-align: center; margin-top: 1rem; }
76
- #qr-output canvas { border-radius: 8px; max-width: 100%; }
76
+ #qr-output canvas { border-radius: 8px; max-width: 100%; image-rendering: pixelated; }
77
77
 
78
78
  #scanner-region { width: 100%; border-radius: 8px; overflow: hidden; position: relative; }
79
79
  #scanner-region video { width: 100%; border-radius: 8px; display: block; }
@@ -244,15 +244,15 @@
244
244
  const VERSION_TABLE = [
245
245
  null, // index 0 unused
246
246
  [16,10,1,16,0,0],[28,16,1,28,0,0],[44,26,1,44,0,0],[64,18,2,32,0,0],
247
- [86,24,2,43,0,0],[108,16,2,27,2,28],[124,18,2,31,2,32],[154,22,2,38,2,39],
248
- [182,22,2,36,2,37],[216,26,2,43,2,44],[254,30,2,50,2,51],[290,22,2,36,4,37],
249
- [334,22,2,37,4,38],[365,24,4,40,2,41],[415,24,2,41,4,42],[453,28,4,45,2,46],
250
- [507,28,2,42,4,43],[563,26,4,46,2,47],[627,26,2,44,4,45],[669,26,4,47,2,48],
251
- [714,22,2,45,6,46],[782,24,6,43,2,44],[860,28,6,45,2,46],[914,28,8,47,0,0],
252
- [1000,22,4,46,4,47],[1062,24,4,43,6,44],[1128,22,2,45,8,46],[1193,24,4,45,6,46],
253
- [1267,24,6,45,4,46],[1373,28,6,47,4,48],[1455,28,6,47,4,48],[1541,28,8,47,2,48],
254
- [1631,28,8,47,4,48],[1725,28,6,47,8,48],[1812,28,8,47,4,48],[1914,28,8,47,8,48],
255
- [1992,28,10,47,4,48],[2102,28,8,47,8,48],[2216,28,12,47,4,48],[2334,28,14,47,4,48]
247
+ [86,24,2,43,0,0],[108,16,4,27,0,0],[124,18,4,31,0,0],[154,22,2,38,2,39],
248
+ [182,22,3,36,2,37],[216,26,4,43,1,44],[254,30,1,50,4,51],[290,22,6,36,2,37],
249
+ [334,22,8,37,1,38],[365,24,4,40,5,41],[415,24,5,41,5,42],[453,28,7,45,3,46],
250
+ [507,28,10,46,1,47],[563,26,9,43,4,44],[627,26,3,44,11,45],[669,26,3,41,13,42],
251
+ [714,26,17,42,0,0],[782,28,17,46,0,0],[860,28,4,47,14,48],[914,28,6,45,14,46],
252
+ [1000,28,8,47,13,48],[1062,28,19,46,4,47],[1128,28,22,45,3,46],[1193,28,3,45,23,46],
253
+ [1267,28,21,45,7,46],[1373,28,19,47,10,48],[1455,28,2,46,29,47],[1541,28,10,46,23,47],
254
+ [1631,28,14,46,21,47],[1725,28,14,46,23,47],[1812,28,12,47,26,48],[1914,28,6,47,34,48],
255
+ [1992,28,29,46,14,47],[2102,28,13,46,32,47],[2216,28,40,47,7,48],[2334,28,18,47,31,48]
256
256
  ];
257
257
 
258
258
  // Byte-mode capacity per version at EC level M
@@ -715,13 +715,15 @@
715
715
 
716
716
  function toCanvas(container, text, options = {}) {
717
717
  const { matrix, size } = encode(text);
718
- const scale = Math.max(1, Math.floor((options.width || 320) / size));
718
+ const scale = Math.max(4, Math.floor((options.width || 500) / size));
719
719
  const margin = (options.margin !== undefined ? options.margin : 2) * scale;
720
720
 
721
721
  const canvas = document.createElement("canvas");
722
722
  const total = size * scale + margin * 2;
723
723
  canvas.width = total;
724
724
  canvas.height = total;
725
+ canvas.style.maxWidth = "100%";
726
+ canvas.style.height = "auto";
725
727
  const ctx = canvas.getContext("2d");
726
728
 
727
729
  ctx.fillStyle = "#ffffff";
@@ -742,25 +744,47 @@
742
744
 
743
745
 
744
746
  // =========================================================================
745
- // QR CODE SCANNER — Uses native BarcodeDetector API (Chrome, Edge, Safari)
746
- // Falls back to manual paste for unsupported browsers (Firefox).
747
- // No external libraries required.
747
+ // QR CODE SCANNER — Uses native BarcodeDetector API where available,
748
+ // falls back to jsQR library (loaded from CDN) for other browsers.
748
749
  // =========================================================================
749
750
 
750
751
  const QRScan = (() => {
751
752
  let stream = null;
752
753
  let animId = null;
753
754
  let running = false;
755
+ let jsQRPromise = null;
756
+
757
+ const hasBarcodeDetector = "BarcodeDetector" in window;
758
+
759
+ function loadJsQR() {
760
+ if (jsQRPromise) return jsQRPromise;
761
+ jsQRPromise = new Promise((resolve, reject) => {
762
+ const script = document.createElement("script");
763
+ script.src = "https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js";
764
+ script.onload = () => resolve(window.jsQR);
765
+ script.onerror = () => reject(new Error("Failed to load QR scanner library"));
766
+ document.head.appendChild(script);
767
+ });
768
+ return jsQRPromise;
769
+ }
754
770
 
755
- const isSupported = "BarcodeDetector" in window;
771
+ // Always report supported we have a fallback
772
+ const isSupported = true;
756
773
 
757
774
  async function start(regionEl, onResult, onError) {
758
- if (!isSupported) {
759
- onError("BarcodeDetector is not supported in this browser. Use Chrome, Edge, or Safari.");
760
- return false;
761
- }
775
+ let detector = null;
776
+ let jsQRFn = null;
762
777
 
763
- const detector = new BarcodeDetector({ formats: ["qr_code"] });
778
+ if (hasBarcodeDetector) {
779
+ detector = new BarcodeDetector({ formats: ["qr_code"] });
780
+ } else {
781
+ try {
782
+ jsQRFn = await loadJsQR();
783
+ } catch (e) {
784
+ onError("Failed to load QR scanner. Check your internet connection.");
785
+ return false;
786
+ }
787
+ }
764
788
 
765
789
  try {
766
790
  stream = await navigator.mediaDevices.getUserMedia({
@@ -783,14 +807,35 @@
783
807
 
784
808
  running = true;
785
809
 
810
+ // Reusable canvas for jsQR frame capture
811
+ let scanCanvas = null;
812
+ let scanCtx = null;
813
+
786
814
  const scan = async () => {
787
815
  if (!running) return;
788
816
  try {
789
- const codes = await detector.detect(video);
790
- if (codes.length > 0) {
791
- // onResult returns true if scan should stop (successful decode)
792
- const shouldStop = await onResult(codes[0].rawValue);
793
- if (shouldStop) return;
817
+ if (detector) {
818
+ const codes = await detector.detect(video);
819
+ if (codes.length > 0) {
820
+ const shouldStop = await onResult(codes[0].rawValue);
821
+ if (shouldStop) return;
822
+ }
823
+ } else if (jsQRFn) {
824
+ if (video.videoWidth > 0 && video.videoHeight > 0) {
825
+ if (!scanCanvas) {
826
+ scanCanvas = document.createElement("canvas");
827
+ scanCanvas.width = video.videoWidth;
828
+ scanCanvas.height = video.videoHeight;
829
+ scanCtx = scanCanvas.getContext("2d", { willReadFrequently: true });
830
+ }
831
+ scanCtx.drawImage(video, 0, 0, scanCanvas.width, scanCanvas.height);
832
+ const imageData = scanCtx.getImageData(0, 0, scanCanvas.width, scanCanvas.height);
833
+ const code = jsQRFn(imageData.data, imageData.width, imageData.height);
834
+ if (code) {
835
+ const shouldStop = await onResult(code.data);
836
+ if (shouldStop) return;
837
+ }
838
+ }
794
839
  }
795
840
  } catch (_) {}
796
841
  animId = requestAnimationFrame(scan);
@@ -912,19 +957,19 @@
912
957
  return;
913
958
  }
914
959
 
915
- QRGen.toCanvas(output, payload, { width: 320, margin: 2 });
960
+ QRGen.toCanvas(output, payload, { width: 500, margin: 2 });
916
961
  info.style.display = "block";
917
962
  } catch (e) {
918
963
  errEl.textContent = "Failed to generate QR code: " + e.message;
919
964
  }
920
965
  });
921
966
 
922
- // Browser compatibility warning
923
- if (!QRScan.isSupported) {
967
+ // Browser compatibility note
968
+ if (!("BarcodeDetector" in window)) {
924
969
  document.getElementById("compat-warning").style.display = "block";
925
970
  document.getElementById("compat-warning").textContent =
926
- "Your browser does not support QR scanning (BarcodeDetector API). " +
927
- "Use Chrome, Edge, or Safari for camera scanning.";
971
+ "Your browser lacks native QR scanning. A fallback library will be " +
972
+ "loaded from the internet when you start the camera.";
928
973
  }
929
974
 
930
975
  // QR Scanning
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qr-secure-send",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Encrypt and transfer secrets via QR code",
5
5
  "keywords": ["qr", "qrcode", "encryption", "password", "secure", "transfer"],
6
6
  "author": "",