Last active
April 3, 2026 13:07
-
-
Save kouameYao/9f2d45a24ce281deda647a1988915637 to your computer and use it in GitHub Desktop.
Styled qrcode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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