'HELLO WORLD', 'filename' => 'hello-world.png'], ['data' => 'A', 'filename' => 'single-char.png'], ['data' => 'HELLO', 'filename' => 'hello.png'], ['data' => 'https://example.com', 'filename' => 'url.png'], ['data' => 'Test QR Code', 'filename' => 'test-text.png'], ]; $config = new QrCodeConfig( version: QrCodeVersion::fromNumber(1), errorCorrectionLevel: ErrorCorrectionLevel::M, encodingMode: EncodingMode::BYTE ); foreach ($testCases as $testCase) { echo "Generating: '{$testCase['data']}'\n"; $matrix = QrCodeGenerator::generate($testCase['data'], $config); $size = $matrix->getSize(); // Generate PNG with good quality $moduleSize = 20; // 20px per module $quietZone = 4; // 4 modules quiet zone $canvasSize = ($size + 2 * $quietZone) * $moduleSize; // Create image $image = imagecreatetruecolor($canvasSize, $canvasSize); $white = imagecolorallocate($image, 255, 255, 255); $black = imagecolorallocate($image, 0, 0, 0); // Fill with white (background) imagefill($image, 0, 0, $white); // Draw quiet zone (already white) // Draw modules $offset = $quietZone * $moduleSize; for ($row = 0; $row < $size; $row++) { for ($col = 0; $col < $size; $col++) { $isDark = $matrix->getModuleAt($row, $col)->isDark(); if ($isDark) { $x = $offset + ($col * $moduleSize); $y = $offset + ($row * $moduleSize); imagefilledrectangle( $image, $x, $y, $x + $moduleSize - 1, $y + $moduleSize - 1, $black ); } } } // Save PNG $filepath = $outputDir . '/' . $testCase['filename']; imagepng($image, $filepath, 0); // 0 = no compression for best quality imagedestroy($image); $fileSize = filesize($filepath); echo " ✅ Saved: {$testCase['filename']} ({$fileSize} bytes, {$canvasSize}x{$canvasSize}px)\n\n"; } echo "=== Summary ===\n"; echo "PNG QR codes generated successfully!\n"; echo "PNG format is more reliable for QR code scanners than SVG.\n"; echo "Output directory: {$outputDir}\n";