Skip to content

Instantly share code, notes, and snippets.

@kouameYao
Last active April 3, 2026 13:07
Show Gist options
  • Select an option

  • Save kouameYao/9f2d45a24ce281deda647a1988915637 to your computer and use it in GitHub Desktop.

Select an option

Save kouameYao/9f2d45a24ce281deda647a1988915637 to your computer and use it in GitHub Desktop.
Styled qrcode
import * as QRCode from 'qrcode';
import { createCanvas, loadImage } from 'canvas';
import { join } from 'path';
export async function generateStylizedQrCodeWithLogo(
data: string = 'https://checkout-dev.paynah.com/fr';,
): Promise<string> {
const canvasSize = 300;
const canvas = createCanvas(canvasSize, canvasSize);
const ctx = canvas.getContext('2d') as any;
// Générer le QR code en tant que matrice de données
const qrData = QRCode.create(data, {
errorCorrectionLevel: 'M',
});
const modules = qrData.modules;
const size = modules.size;
const cellSize = canvasSize / (size + 2); // +2 pour la marge
const dotRadius = cellSize * 0.4; // Rayon des points
// Remplir le fond en blanc
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvasSize, canvasSize);
// Dessiner les modules du QR code sous forme de points (sans les coins de positionnement)
ctx.fillStyle = '#000000';
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
if (modules.get(x, y)) {
// Éviter de dessiner les zones des carrés de positionnement
if (!isPositionSquareArea(x, y, size)) {
const centerX = (x + 1) * cellSize + cellSize / 2;
const centerY = (y + 1) * cellSize + cellSize / 2;
// Dessiner un cercle au lieu d'un carré
ctx.beginPath();
ctx.arc(centerX, centerY, dotRadius, 0, 2 * Math.PI);
ctx.fill();
}
}
}
}
// Ici je dessiner les trois cercles
drawCircularPositionMarker(ctx, cellSize, cellSize, cellSize * 7); // Coin supérieur gauche
drawCircularPositionMarker(
ctx,
(size - 6) * cellSize,
cellSize,
cellSize * 7,
); // Coin supérieur droit
drawCircularPositionMarker(
ctx,
cellSize,
(size - 6) * cellSize,
cellSize * 7,
); // Coin inférieur gauche
// Ajouter le logo au centre
try {
const logoPath = join(__dirname, '../public/p-one.png');
const logo = await loadImage(logoPath);
const logoSize = 80;
const logoX = (canvasSize - logoSize) / 2;
const logoY = (canvasSize - logoSize) / 2;
// Créer un fond blanc circulaire pour le logo
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(canvasSize / 2, canvasSize / 2, logoSize / 2 + 5, 0, 2 * Math.PI);
ctx.fill();
ctx.drawImage(logo, logoX, logoY, logoSize, logoSize);
} catch (error) {
console.warn('Logo non trouvé, continuation sans logo');
}
// Convertir en base64
const buffer = canvas.toBuffer('image/png');
const base64QR = buffer.toString('base64');
return `data:image/png;base64,${base64QR}`;
}
// Fonction pour vérifier si une position fait partie d'un carré de positionnement
function isPositionSquareArea(x: number, y: number, size: number): boolean {
// Coin supérieur gauche (0-6, 0-6)
if (x >= 0 && x < 7 && y >= 0 && y < 7) return true;
// Coin supérieur droit (size-7 à size-1, 0-6)
if (x >= size - 7 && x < size && y >= 0 && y < 7) return true;
// Coin inférieur gauche (0-6, size-7 à size-1)
if (x >= 0 && x < 7 && y >= size - 7 && y < size) return true;
return false;
}
// Fonction pour dessiner un marqueur de position circulaire
function drawCircularPositionMarker(
ctx: any,
x: number,
y: number,
size: number,
) {
const centerX = x + size / 2;
const centerY = y + size / 2;
const outerRadius = size / 2;
const innerRadius = size / 6;
// Cercle extérieur (noir)
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI);
ctx.fill();
// Cercle intérieur (blanc)
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(centerX, centerY, outerRadius * 0.7, 0, 2 * Math.PI);
ctx.fill();
// Point central (noir)
ctx.fillStyle = '#000000';
ctx.beginPath();
ctx.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI);
ctx.fill();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment