Initial commit: QR code generator (encodage et rendu côté navigateur)
This commit is contained in:
commit
8be33ed3f6
11 files changed
+2864
No files matched your search
+129
@@ -0,0 +1,129 @@
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
const textEl = document.getElementById("qr-text");
|
||||
const cellSizeEl = document.getElementById("qr-cell-size");
|
||||
const correctionEl = document.getElementById("qr-correction");
|
||||
const fgColorEl = document.getElementById("qr-fg-color");
|
||||
const bgColorEl = document.getElementById("qr-bg-color");
|
||||
const logoInputEl = document.getElementById("qr-logo-input");
|
||||
const logoClearBtn = document.getElementById("qr-logo-clear");
|
||||
const generateBtn = document.getElementById("generate-btn");
|
||||
const downloadBtn = document.getElementById("download-btn");
|
||||
const canvas = document.getElementById("qr-canvas");
|
||||
const statusEl = document.getElementById("qr-status");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
let logoImage = null;
|
||||
|
||||
function readLogoFile(file) {
|
||||
if (!file) return;
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
logoImage = img;
|
||||
render();
|
||||
};
|
||||
img.src = reader.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
logoInputEl.addEventListener("change", (e) => {
|
||||
readLogoFile(e.target.files[0]);
|
||||
});
|
||||
|
||||
logoClearBtn.addEventListener("click", () => {
|
||||
logoImage = null;
|
||||
logoInputEl.value = "";
|
||||
render();
|
||||
});
|
||||
|
||||
function render() {
|
||||
const text = textEl.value;
|
||||
statusEl.classList.remove("error");
|
||||
|
||||
if (!text) {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = 280;
|
||||
canvas.height = 280;
|
||||
statusEl.textContent = "Saisissez un texte ou une URL pour générer le QR code.";
|
||||
return;
|
||||
}
|
||||
|
||||
const cellSize = parseInt(cellSizeEl.value, 10) || 8;
|
||||
const requestedLevel = correctionEl.value;
|
||||
const level = logoImage ? "H" : requestedLevel;
|
||||
const fgColor = fgColorEl.value || "#000000";
|
||||
const bgColor = bgColorEl.value || "#ffffff";
|
||||
const margin = 4; // modules
|
||||
|
||||
try {
|
||||
const qr = qrcode(0, level);
|
||||
qr.addData(text);
|
||||
qr.make();
|
||||
|
||||
const moduleCount = qr.getModuleCount();
|
||||
const size = (moduleCount + margin * 2) * cellSize;
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillRect(0, 0, size, size);
|
||||
|
||||
ctx.fillStyle = fgColor;
|
||||
for (let row = 0; row < moduleCount; row++) {
|
||||
for (let col = 0; col < moduleCount; col++) {
|
||||
if (qr.isDark(row, col)) {
|
||||
ctx.fillRect((col + margin) * cellSize, (row + margin) * cellSize, cellSize, cellSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (logoImage) {
|
||||
const logoSize = size * 0.22;
|
||||
const pad = logoSize * 0.14;
|
||||
const x = (size - logoSize) / 2;
|
||||
const y = (size - logoSize) / 2;
|
||||
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillRect(x - pad, y - pad, logoSize + pad * 2, logoSize + pad * 2);
|
||||
|
||||
ctx.imageSmoothingEnabled = true;
|
||||
ctx.drawImage(logoImage, x, y, logoSize, logoSize);
|
||||
}
|
||||
|
||||
statusEl.textContent = logoImage
|
||||
? `QR code généré (correction ${level}, forcée par le logo).`
|
||||
: `QR code généré (correction ${level}).`;
|
||||
} catch (err) {
|
||||
statusEl.textContent = "Erreur : " + (err.message || "contenu trop long pour être encodé.");
|
||||
statusEl.classList.add("error");
|
||||
}
|
||||
}
|
||||
|
||||
function downloadPng() {
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) return;
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "qrcode.png";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}, "image/png");
|
||||
}
|
||||
|
||||
[textEl, cellSizeEl, correctionEl, fgColorEl, bgColorEl].forEach((el) => {
|
||||
el.addEventListener("input", render);
|
||||
});
|
||||
|
||||
generateBtn.addEventListener("click", render);
|
||||
downloadBtn.addEventListener("click", downloadPng);
|
||||
|
||||
render();
|
||||
})();
|
||||
Reference in new issue
Block a user