Files
predavanja/Events-WebApi/Events.FilesAPI/Features/Certificates/CertificatePdfDocumentWriter.cs
2026-05-10 23:39:55 +02:00

128 lines
3.9 KiB
C#

using System.Text;
using PdfSharpCore;
using PdfSharpCore.Drawing;
using PdfSharpCore.Fonts;
using PdfSharpCore.Pdf;
using PdfSharpCore.Utils;
namespace Events.FilesAPI.Features.Certificates;
internal static class CertificatePdfDocumentWriter
{
private const string FontFamilyName = "Arial";
private static int initialized;
public static byte[] CreateCertificate(CertificatePdfModel model)
{
EnsureFontsConfigured();
using var document = new PdfDocument();
PdfPage page = document.AddPage();
page.Size = PageSize.A4;
using XGraphics graphics = XGraphics.FromPdfPage(page);
var titleFont = new XFont(FontFamilyName, 20, XFontStyle.Bold);
var headingFont = new XFont(FontFamilyName, 13, XFontStyle.Bold);
var textFont = new XFont(FontFamilyName, 12, XFontStyle.Regular);
double marginLeft = 50;
double y = 60;
double contentWidth = page.Width - marginLeft * 2;
graphics.DrawString(model.Title, titleFont, XBrushes.DarkBlue, new XRect(marginLeft, y, contentWidth, 30), XStringFormats.TopLeft);
y += 52;
foreach (string paragraph in BuildParagraphs(model))
{
DrawParagraph(graphics, paragraph, textFont, marginLeft, ref y, contentWidth);
y += 8;
}
graphics.DrawString("Sports", headingFont, XBrushes.Black, new XRect(marginLeft, y, contentWidth, 20), XStringFormats.TopLeft);
y += 26;
foreach (string sportName in model.SportNames)
{
DrawParagraph(graphics, $"- {sportName}", textFont, marginLeft + 12, ref y, contentWidth - 12);
y += 4;
}
y += 12;
DrawParagraph(graphics, $"Event ID: {model.EventId}", textFont, marginLeft, ref y, contentWidth);
y += 4;
DrawParagraph(graphics, $"Person ID: {model.PersonId}", textFont, marginLeft, ref y, contentWidth);
using var stream = new MemoryStream();
document.Save(stream, false);
return stream.ToArray();
}
private static void EnsureFontsConfigured()
{
if (Interlocked.Exchange(ref initialized, 1) == 1)
return;
GlobalFontSettings.FontResolver = new FontResolver();
}
private static IEnumerable<string> BuildParagraphs(CertificatePdfModel model)
{
yield return $"This confirms that {model.PersonFullName} participated in the event \"{model.EventName}\".";
if (!string.IsNullOrWhiteSpace(model.PersonFullNameTranscription) &&
!string.Equals(model.PersonFullName, model.PersonFullNameTranscription, StringComparison.OrdinalIgnoreCase))
{
yield return $"Transcribed full name: {model.PersonFullNameTranscription}.";
}
yield return $"Event date: {model.EventDate:dd.MM.yyyy}.";
yield return "The person competed in the following sports:";
}
private static void DrawParagraph(XGraphics graphics, string text, XFont font, double left, ref double y, double width)
{
foreach (string line in WrapText(graphics, text, font, width))
{
graphics.DrawString(line, font, XBrushes.Black, new XRect(left, y, width, 18), XStringFormats.TopLeft);
y += 18;
}
}
private static IEnumerable<string> WrapText(XGraphics graphics, string text, XFont font, double width)
{
if (string.IsNullOrWhiteSpace(text))
{
yield return string.Empty;
yield break;
}
var words = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
var lineBuilder = new StringBuilder();
foreach (string word in words)
{
string candidate = lineBuilder.Length == 0 ? word : $"{lineBuilder} {word}";
if (graphics.MeasureString(candidate, font).Width <= width)
{
lineBuilder.Clear();
lineBuilder.Append(candidate);
continue;
}
if (lineBuilder.Length > 0)
{
yield return lineBuilder.ToString();
lineBuilder.Clear();
lineBuilder.Append(word);
}
else
{
yield return word;
}
}
if (lineBuilder.Length > 0)
yield return lineBuilder.ToString();
}
}