fontDir = public_path('assets/certificates/fonts').DIRECTORY_SEPARATOR; $this->imgDir = public_path('assets/certificates/images').DIRECTORY_SEPARATOR; } /** * @param array> $students */ public function generate(array $students, string $certDate): string { $edwardianFont = \TCPDF_FONTS::addTTFfont($this->fontDir.'Edwardian Script ITC Regular.ttf', 'TrueTypeUnicode', '', 32); $garamondBold = \TCPDF_FONTS::addTTFfont($this->fontDir.'Garamond Bold.ttf', 'TrueTypeUnicode', '', 32); $ebGaramond = \TCPDF_FONTS::addTTFfont($this->fontDir.'EBGaramond-Regular.ttf', 'TrueTypeUnicode', '', 32); $pdf = new \TCPDF('L', 'pt', 'A4', true, 'UTF-8', false); $pdf->SetCreator('Al Rahma Sunday School'); $pdf->SetTitle('Student Certificates'); $pdf->SetMargins(0, 0, 0, true); $pdf->SetAutoPageBreak(false, 0); $pdf->setPrintHeader(false); $pdf->setPrintFooter(false); $pdf->SetHeaderMargin(0); $pdf->SetFooterMargin(0); $W = $pdf->getPageWidth(); $H = $pdf->getPageHeight(); foreach ($students as $student) { $pdf->AddPage(); $name = $student['firstname'].' '.$student['lastname']; $grade = $this->formatGrade((string) ($student['grade'] ?? '')); $certNumber = (string) ($student['cert_number'] ?? ''); $verifyUrl = is_string($student['verify_url'] ?? null) ? $student['verify_url'] : null; $this->drawCertificate( $pdf, $W, $H, $name, $grade, $certDate, $certNumber, $verifyUrl, $edwardianFont, $garamondBold, $ebGaramond ); } return (string) $pdf->Output('', 'S'); } private function drawCertificate( \TCPDF $pdf, float $W, float $H, string $name, string $grade, string $certDate, string $certNumber, ?string $verifyUrl, string $edwardianFont, string $garamondBold, string $ebGaramond ): void { $pdf->Image($this->imgDir.'title.png', 126, 0, 600); $pdf->Image($this->imgDir.'background.png', 280, 176, 291, 340); $pdf->Image($this->imgDir.'signature.png', 140, 410, 90, 80); $pdf->SetFont('times', 'B', 24); $pdf->SetTextColor(0, 0, 0); $pdf->SetXY(0, 151); $pdf->Cell($W, 24, 'Presented to:', 0, 0, 'C'); if (! empty($verifyUrl)) { $style = [ 'border' => false, 'padding' => 0, 'fgcolor' => [0, 0, 0], 'bgcolor' => false, ]; $pdf->write2DBarcode($verifyUrl, 'QRCODE,L', 120, 162, 42, 42, $style, 'N'); } $pdf->SetFont($edwardianFont, '', 38); $nameX = ($W - $pdf->GetStringWidth($name)) / 2; $this->drawGradientText($pdf, $edwardianFont, 38, $name, $nameX, 221.5); $pdf->SetFont('times', '', 20); $pdf->SetXY(0, 236); $pdf->Cell(600, 20, '___________________________________', 0, 0, 'R'); $pdf->SetFont($ebGaramond, '', 20); $pdf->SetXY(0, 273); $pdf->Cell($W, 20, 'for successfully completing the requirements of', 0, 0, 'C'); $pdf->SetFont($garamondBold, '', 20); $pdf->SetXY(0, 310); $pdf->Cell($W, 20, $grade, 0, 0, 'C'); $pdf->SetFont('times', '', 20); $pdf->SetXY(0, 343); $pdf->Cell($W, 20, 'at', 0, 0, 'C'); $pdf->SetFont($garamondBold, '', 20); $pdf->SetXY(0, 375); $pdf->Cell($W, 20, 'Al Rahma Sunday School', 0, 0, 'C'); $this->drawGradientText($pdf, $edwardianFont, 26, $certDate, 586, 456); $pdf->SetFont('times', '', 20); $pdf->SetXY(0, 463); $pdf->Cell(742, 20, '_________________', 0, 0, 'R'); $pdf->SetXY(650, 492); $pdf->Cell(80, 20, 'Date', 0, 0, 'C'); $pdf->SetXY(106, 463); $pdf->Cell(200, 20, '_________________', 0, 0, 'L'); $pdf->SetXY(106, 492); $pdf->Cell(168, 20, 'Signature', 0, 0, 'C'); if ($certNumber !== '') { $pdf->SetFont('helvetica', '', 8); $pdf->SetTextColor(150, 150, 150); $pdf->SetXY(70.86, $H - 39.68); $pdf->Cell(200, 12, 'Certificate No. '.$certNumber, 0, 0, 'L'); $pdf->SetTextColor(0, 0, 0); } } private function drawGradientText(\TCPDF $pdf, string $fontName, float $fontSize, string $text, float $x, float $y): void { $pdf->SetFont($fontName, '', $fontSize); for ($i = 0; $i < 6; $i++) { $pdf->setAlpha(($i + 1) * 25 / 255); $pdf->SetTextColor(0, 0, 0); $pdf->Text($x + $i / 5, $y + $i / 5, $text); } $pdf->setAlpha(1); $pdf->SetTextColor(0, 0, 0); $pdf->Text($x, $y, $text); } private function formatGrade(string $raw): string { $clean = trim($raw); $lower = strtolower($clean); if (preg_match('/^\d+$/', $clean) && (int) $clean >= 1 && (int) $clean <= 9) { return 'Grade '.$clean; } if ($lower === 'youth') { return 'Youth'; } if ($lower === 'kg') { return 'Kindergarten'; } return $clean; } }