*/ private static function logoCandidates(): array { $paths = []; $env = getenv('AC_QR_LOGO_PATH'); if (is_string($env) && $env !== '') { $paths[] = $env; } $paths[] = dirname(__DIR__) . '/assets/ac_qr_logo.png'; $paths[] = __DIR__ . '/../assets/ac_qr_logo.png'; $paths[] = dirname(__DIR__, 2) . '/ac-platform-php/assets/ac_qr_logo.png'; $paths[] = dirname(__DIR__, 2) . '/ac-platform-php/public/assets/ac_qr_logo.png'; return $paths; } /** @return \GdImage|false */ private static function loadLogoImage(string $path) { $bytes = @file_get_contents($path); if (!is_string($bytes) || $bytes === '') { return false; } $img = @imagecreatefromstring($bytes); return $img !== false ? $img : false; } private static function logoPath(): ?string { foreach (self::logoCandidates() as $path) { if (is_readable($path)) { return $path; } } return null; } private static function rawQrPng(string $text, int $size): ?string { $qrencode = trim((string) shell_exec('command -v qrencode 2>/dev/null') ?? ''); if ($qrencode === '') { return null; } $size = max(128, min(512, $size)); $moduleSize = max(3, (int) round($size / 33)); $cmd = sprintf( '%s -l H -t PNG -s %d -m 2 -o - %s 2>/dev/null', escapeshellcmd($qrencode), $moduleSize, escapeshellarg($text) ); $out = shell_exec($cmd); if (!is_string($out) || strlen($out) < 8) { return null; } return $out; } private static function overlayLogo(string $pngBytes): ?string { if (!extension_loaded('gd')) { return null; } $logoPath = self::logoPath(); if ($logoPath === null) { return null; } $qr = @imagecreatefromstring($pngBytes); if ($qr === false) { return null; } $logo = self::loadLogoImage($logoPath); if ($logo === false) { imagedestroy($qr); return null; } $qrW = imagesx($qr); $qrH = imagesy($qr); if ($qrW < 32 || $qrH < 32) { imagedestroy($qr); imagedestroy($logo); return null; } $logoBox = (int) round(min($qrW, $qrH) * self::LOGO_FRACTION); $border = max(2, (int) round(min($qrW, $qrH) * self::BORDER_FRACTION)); $plate = $logoBox + 2 * $border; $plateX = (int) floor(($qrW - $plate) / 2); $plateY = (int) floor(($qrH - $plate) / 2); $white = imagecolorallocate($qr, 255, 255, 255); imagefilledrectangle($qr, $plateX, $plateY, $plateX + $plate - 1, $plateY + $plate - 1, $white); $srcW = imagesx($logo); $srcH = imagesy($logo); $dstX = $plateX + $border; $dstY = $plateY + $border; imagecopyresampled($qr, $logo, $dstX, $dstY, 0, 0, $logoBox, $logoBox, $srcW, $srcH); ob_start(); imagepng($qr); $out = ob_get_clean(); imagedestroy($qr); imagedestroy($logo); if (!is_string($out) || strlen($out) < 8) { return null; } return $out; } }