[chore:] logging for PdfBuilder.cs
This commit is contained in:
+303
-210
@@ -18,45 +18,73 @@ public class PdfBuilder
|
|||||||
|
|
||||||
public PdfBuilder(PdfExportSettings? settings = null)
|
public PdfBuilder(PdfExportSettings? settings = null)
|
||||||
{
|
{
|
||||||
EnsureFontResolverRegistered();
|
|
||||||
_settings = settings ?? new PdfExportSettings();
|
|
||||||
|
|
||||||
// Select first font from build output fonts folder (AppContext.BaseDirectory/fonts)
|
|
||||||
var chosenFamily = "Arial";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Directory.Exists(Global._instance.font_path))
|
EnsureFontResolverRegistered();
|
||||||
{
|
_settings = settings ?? new PdfExportSettings();
|
||||||
var first = Directory.EnumerateFiles(Global._instance.font_path, "*.ttf").FirstOrDefault();
|
|
||||||
if (!string.IsNullOrEmpty(first))
|
// Select first font from build output fonts folder (AppContext.BaseDirectory/fonts)
|
||||||
chosenFamily = StripStyleSuffix(Path.GetFileNameWithoutExtension(first)) ?? chosenFamily;
|
var chosenFamily = "Arial";
|
||||||
}
|
try
|
||||||
}
|
{
|
||||||
catch
|
if (Directory.Exists(Global._instance.font_path))
|
||||||
{
|
{
|
||||||
chosenFamily = "Arial";
|
var first = Directory.EnumerateFiles(Global._instance.font_path, "*.ttf").FirstOrDefault();
|
||||||
}
|
if (!string.IsNullOrEmpty(first))
|
||||||
|
chosenFamily = StripStyleSuffix(Path.GetFileNameWithoutExtension(first)) ?? chosenFamily;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while searching for fonts: {ex.Message}",Logger.LogType.Error);
|
||||||
|
chosenFamily = "Arial";
|
||||||
|
}
|
||||||
|
|
||||||
|
_boldFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Bold);
|
||||||
|
_regularFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Regular);
|
||||||
|
_smallFont = new XFont(chosenFamily, _settings.smallFontSize, XFontStyleEx.Regular);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while font resolving: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_boldFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Bold);
|
|
||||||
_regularFont = new XFont(chosenFamily, _settings.fontSize, XFontStyleEx.Regular);
|
|
||||||
_smallFont = new XFont(chosenFamily, _settings.smallFontSize, XFontStyleEx.Regular);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EnsureFontResolverRegistered()
|
private static void EnsureFontResolverRegistered()
|
||||||
{
|
{
|
||||||
if (GlobalFontSettings.FontResolver != null) return;
|
try
|
||||||
//var fontsDir = Path.Combine(AppContext.BaseDirectory, "fonts");
|
{
|
||||||
GlobalFontSettings.FontResolver = new StableFontResolver(Global._instance.font_path);
|
if (GlobalFontSettings.FontResolver != null) return;
|
||||||
|
//var fontsDir = Path.Combine(AppContext.BaseDirectory, "fonts");
|
||||||
|
GlobalFontSettings.FontResolver = new StableFontResolver(Global._instance.font_path);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while ensuring font resolver register state: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string StripStyleSuffix(string name)
|
private static string StripStyleSuffix(string name)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name)) return name;
|
try
|
||||||
var idx = name.IndexOf('-');
|
{
|
||||||
if (idx < 0) idx = name.IndexOf('_');
|
if (string.IsNullOrEmpty(name)) return name;
|
||||||
if (idx > 0)
|
var idx = name.IndexOf('-');
|
||||||
return name.Substring(0, idx);
|
if (idx < 0) idx = name.IndexOf('_');
|
||||||
return name;
|
if (idx > 0)
|
||||||
|
return name.Substring(0, idx);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while stripping style suffix: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -69,42 +97,50 @@ public class PdfBuilder
|
|||||||
public void CreateAddressLabelPdfFromAddressSetWithPlaceholder(int addressSetId, string placeholderText,
|
public void CreateAddressLabelPdfFromAddressSetWithPlaceholder(int addressSetId, string placeholderText,
|
||||||
string outputPath)
|
string outputPath)
|
||||||
{
|
{
|
||||||
// Find the AddressSet by ID
|
|
||||||
var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId);
|
|
||||||
if (addressSet == null)
|
|
||||||
throw new ArgumentException($"AddressSet with ID {addressSetId} not found");
|
|
||||||
|
|
||||||
if (addressSet.KasPersons == null || addressSet.KasPersons.Count == 0)
|
|
||||||
throw new ArgumentException($"AddressSet with ID {addressSetId} contains no addresses");
|
|
||||||
|
|
||||||
// Generate markdown addresses from all KasPersons in the set
|
|
||||||
//var addresses = new string?[addressSet.KasPersons.Count];
|
|
||||||
var addresses = new List<string>();
|
|
||||||
|
|
||||||
// find customer (owner) to include sender_address
|
|
||||||
string senderLine = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var owner = Settings._instance.customers.customers.FirstOrDefault(c => c.ID == addressSet.owner_id);
|
// Find the AddressSet by ID
|
||||||
if (owner != null && !string.IsNullOrWhiteSpace(owner.sender_address))
|
var addressSet = Settings._instance.addressSets.GetAddressSetByID(addressSetId);
|
||||||
senderLine = "<font6>" + owner.sender_address.Replace("\n", " ").Trim() + "</font6>\n";
|
if (addressSet == null)
|
||||||
}
|
throw new ArgumentException($"AddressSet with ID {addressSetId} not found");
|
||||||
catch
|
|
||||||
{
|
|
||||||
senderLine = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < addressSet.KasPersons.Count; i++)
|
if (addressSet.KasPersons == null || addressSet.KasPersons.Count == 0)
|
||||||
{
|
throw new ArgumentException($"AddressSet with ID {addressSetId} contains no addresses");
|
||||||
var addr = AddressCreator.CreateFinalMarkdownString(addressSet.KasPersons[i].id);
|
|
||||||
if (string.IsNullOrWhiteSpace(addr)) continue;
|
|
||||||
if (!string.IsNullOrEmpty(senderLine))
|
|
||||||
addresses.Add(senderLine + (addr ?? ""));
|
|
||||||
else
|
|
||||||
addresses.Add(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
|
// Generate markdown addresses from all KasPersons in the set
|
||||||
|
//var addresses = new string?[addressSet.KasPersons.Count];
|
||||||
|
var addresses = new List<string>();
|
||||||
|
|
||||||
|
// find customer (owner) to include sender_address
|
||||||
|
string senderLine = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var owner = Settings._instance.customers.customers.FirstOrDefault(c => c.ID == addressSet.owner_id);
|
||||||
|
if (owner != null && !string.IsNullOrWhiteSpace(owner.sender_address))
|
||||||
|
senderLine = "<font6>" + owner.sender_address.Replace("\n", " ").Trim() + "</font6>\n";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
senderLine = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < addressSet.KasPersons.Count; i++)
|
||||||
|
{
|
||||||
|
var addr = AddressCreator.CreateFinalMarkdownString(addressSet.KasPersons[i].id);
|
||||||
|
if (string.IsNullOrWhiteSpace(addr)) continue;
|
||||||
|
if (!string.IsNullOrEmpty(senderLine))
|
||||||
|
addresses.Add(senderLine + (addr ?? ""));
|
||||||
|
else
|
||||||
|
addresses.Add(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while creating address label pdf from address set with placeholder: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -115,26 +151,34 @@ public class PdfBuilder
|
|||||||
/// <param name="outputPath">Path where the PDF should be saved</param>
|
/// <param name="outputPath">Path where the PDF should be saved</param>
|
||||||
public void CreateAddressLabelPdfWithPlaceholder(List<string> addresses, string placeholderText, string outputPath)
|
public void CreateAddressLabelPdfWithPlaceholder(List<string> addresses, string placeholderText, string outputPath)
|
||||||
{
|
{
|
||||||
if (addresses == null || addresses.Count == 0)
|
try
|
||||||
throw new ArgumentException("Addresses array cannot be null or empty");
|
|
||||||
|
|
||||||
var document = new PdfDocument();
|
|
||||||
|
|
||||||
var addressIndex = 0;
|
|
||||||
var isFirstCell = true;
|
|
||||||
|
|
||||||
while (addressIndex < addresses.Count || isFirstCell)
|
|
||||||
{
|
{
|
||||||
var page = document.AddPage();
|
if (addresses == null || addresses.Count == 0)
|
||||||
page.Size = PageSize.A4;
|
throw new ArgumentException("Addresses array cannot be null or empty");
|
||||||
|
|
||||||
using (var gfx = XGraphics.FromPdfPage(page))
|
var document = new PdfDocument();
|
||||||
{
|
|
||||||
DrawPageWithPlaceholder(gfx, addresses, ref addressIndex, ref isFirstCell, placeholderText);
|
var addressIndex = 0;
|
||||||
}
|
var isFirstCell = true;
|
||||||
|
|
||||||
|
while (addressIndex < addresses.Count || isFirstCell)
|
||||||
|
{
|
||||||
|
var page = document.AddPage();
|
||||||
|
page.Size = PageSize.A4;
|
||||||
|
|
||||||
|
using (var gfx = XGraphics.FromPdfPage(page))
|
||||||
|
{
|
||||||
|
DrawPageWithPlaceholder(gfx, addresses, ref addressIndex, ref isFirstCell, placeholderText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.Save(outputPath);
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
document.Save(outputPath);
|
{
|
||||||
|
Logger.Log($"Error while creating address label pdf with placeholder: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex)
|
private void DrawPage(XGraphics gfx, List<string> addresses, ref int addressIndex)
|
||||||
@@ -159,193 +203,242 @@ public class PdfBuilder
|
|||||||
private void DrawPageWithPlaceholder(XGraphics gfx, List<string> addresses, ref int addressIndex,
|
private void DrawPageWithPlaceholder(XGraphics gfx, List<string> addresses, ref int addressIndex,
|
||||||
ref bool isFirstCell, string placeholderText)
|
ref bool isFirstCell, string placeholderText)
|
||||||
{
|
{
|
||||||
for (var row = 0; row < _settings.rowsPerPage; row++)
|
try
|
||||||
for (var col = 0; col < _settings.columnsPerPage; col++)
|
|
||||||
{
|
{
|
||||||
var x = MmToPoints(_settings.pageMarginLeftMm + col * GetCellWidthMm());
|
for (var row = 0; row < _settings.rowsPerPage; row++)
|
||||||
var y = MmToPoints(_settings.pageMarginTopMm + row * GetCellHeightMm());
|
for (var col = 0; col < _settings.columnsPerPage; col++)
|
||||||
|
{
|
||||||
|
var x = MmToPoints(_settings.pageMarginLeftMm + col * GetCellWidthMm());
|
||||||
|
var y = MmToPoints(_settings.pageMarginTopMm + row * GetCellHeightMm());
|
||||||
|
|
||||||
// First cell: placeholder
|
// First cell: placeholder
|
||||||
if (isFirstCell)
|
if (isFirstCell)
|
||||||
{
|
{
|
||||||
DrawCell(gfx, x, y, placeholderText);
|
DrawCell(gfx, x, y, placeholderText);
|
||||||
isFirstCell = false;
|
isFirstCell = false;
|
||||||
}
|
}
|
||||||
else if (addressIndex < addresses.Count)
|
else if (addressIndex < addresses.Count)
|
||||||
{
|
{
|
||||||
DrawCell(gfx, x, y, addresses[addressIndex]);
|
DrawCell(gfx, x, y, addresses[addressIndex]);
|
||||||
addressIndex++;
|
addressIndex++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DrawEmptyCell(gfx, x, y);
|
DrawEmptyCell(gfx, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while drawing page with placholder: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCell(XGraphics gfx, double x, double y, string? address)
|
private void DrawCell(XGraphics gfx, double x, double y, string? address)
|
||||||
{
|
{
|
||||||
var cellWidthPoints = MmToPoints(GetCellWidthMm());
|
try
|
||||||
var cellHeightPoints = MmToPoints(GetCellHeightMm());
|
{
|
||||||
|
var cellWidthPoints = MmToPoints(GetCellWidthMm());
|
||||||
|
var cellHeightPoints = MmToPoints(GetCellHeightMm());
|
||||||
|
|
||||||
// Draw cell border
|
// Draw cell border
|
||||||
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
|
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
|
||||||
gfx.DrawRectangle(XPens.Black, rect);
|
gfx.DrawRectangle(XPens.Black, rect);
|
||||||
|
|
||||||
// Draw address content if available
|
// Draw address content if available
|
||||||
if (!string.IsNullOrEmpty(address)) DrawMarkdownText(gfx, address, x, y, cellWidthPoints, cellHeightPoints);
|
if (!string.IsNullOrEmpty(address)) DrawMarkdownText(gfx, address, x, y, cellWidthPoints, cellHeightPoints);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while drawing cell: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawEmptyCell(XGraphics gfx, double x, double y)
|
private void DrawEmptyCell(XGraphics gfx, double x, double y)
|
||||||
{
|
{
|
||||||
var cellWidthPoints = MmToPoints(GetCellWidthMm());
|
try
|
||||||
var cellHeightPoints = MmToPoints(GetCellHeightMm());
|
{
|
||||||
|
var cellWidthPoints = MmToPoints(GetCellWidthMm());
|
||||||
|
var cellHeightPoints = MmToPoints(GetCellHeightMm());
|
||||||
|
|
||||||
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
|
var rect = new XRect(x, y, cellWidthPoints, cellHeightPoints);
|
||||||
gfx.DrawRectangle(XPens.Black, rect);
|
gfx.DrawRectangle(XPens.Black, rect);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while drawing empty cell: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMarkdownText(XGraphics gfx, string text, double x, double y, double cellWidth, double cellHeight)
|
private void DrawMarkdownText(XGraphics gfx, string text, double x, double y, double cellWidth, double cellHeight)
|
||||||
{
|
{
|
||||||
var paddingLeftPoints = MmToPoints(_settings.cellPaddingLeftMm);
|
try
|
||||||
var paddingRightPoints = MmToPoints(_settings.cellPaddingRightMm);
|
|
||||||
var paddingTopPoints = MmToPoints(_settings.cellPaddingTopMm);
|
|
||||||
var paddingBottomPoints = MmToPoints(_settings.cellPaddingBottomMm);
|
|
||||||
|
|
||||||
var maxWidth = Math.Max(0, cellWidth - paddingLeftPoints - paddingRightPoints);
|
|
||||||
|
|
||||||
// Split text by newlines and remove empty trailing lines
|
|
||||||
var rawLines = text.Split(new[] { "\n" }, StringSplitOptions.None);
|
|
||||||
var lines = rawLines.Where(l => l != null).ToArray();
|
|
||||||
|
|
||||||
// Use a conservative line height in points
|
|
||||||
var lineHeight = _regularFont.Size * 1.2;
|
|
||||||
|
|
||||||
// Calculate total height of the text block
|
|
||||||
var totalHeight = lines.Length * lineHeight;
|
|
||||||
|
|
||||||
// Start drawing from the top of the cell (align addresses to top)
|
|
||||||
var startY = y + paddingTopPoints;
|
|
||||||
|
|
||||||
var currentY = startY;
|
|
||||||
|
|
||||||
foreach (var line in lines)
|
|
||||||
{
|
{
|
||||||
// Stop if we've reached the top boundary
|
var paddingLeftPoints = MmToPoints(_settings.cellPaddingLeftMm);
|
||||||
if (currentY + lineHeight > y + cellHeight - paddingBottomPoints + 0.001)
|
var paddingRightPoints = MmToPoints(_settings.cellPaddingRightMm);
|
||||||
break;
|
var paddingTopPoints = MmToPoints(_settings.cellPaddingTopMm);
|
||||||
|
var paddingBottomPoints = MmToPoints(_settings.cellPaddingBottomMm);
|
||||||
|
|
||||||
// Parse and draw the line with markdown support
|
var maxWidth = Math.Max(0, cellWidth - paddingLeftPoints - paddingRightPoints);
|
||||||
DrawLineWithMarkdown(gfx, line, x + paddingLeftPoints, currentY, maxWidth);
|
|
||||||
currentY += lineHeight;
|
// Split text by newlines and remove empty trailing lines
|
||||||
|
var rawLines = text.Split(new[] { "\n" }, StringSplitOptions.None);
|
||||||
|
var lines = rawLines.Where(l => l != null).ToArray();
|
||||||
|
|
||||||
|
// Use a conservative line height in points
|
||||||
|
var lineHeight = _regularFont.Size * 1.2;
|
||||||
|
|
||||||
|
// Calculate total height of the text block
|
||||||
|
var totalHeight = lines.Length * lineHeight;
|
||||||
|
|
||||||
|
// Start drawing from the top of the cell (align addresses to top)
|
||||||
|
var startY = y + paddingTopPoints;
|
||||||
|
|
||||||
|
var currentY = startY;
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
// Stop if we've reached the top boundary
|
||||||
|
if (currentY + lineHeight > y + cellHeight - paddingBottomPoints + 0.001)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Parse and draw the line with markdown support
|
||||||
|
DrawLineWithMarkdown(gfx, line, x + paddingLeftPoints, currentY, maxWidth);
|
||||||
|
currentY += lineHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while drawing markdown text: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawLineWithMarkdown(XGraphics gfx, string line, double x, double y, double maxWidth)
|
private void DrawLineWithMarkdown(XGraphics gfx, string line, double x, double y, double maxWidth)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(line)) return;
|
try
|
||||||
var currentX = x;
|
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
while (i < line.Length)
|
|
||||||
{
|
{
|
||||||
if (currentX - x >= maxWidth)
|
if (string.IsNullOrWhiteSpace(line)) return;
|
||||||
break;
|
var currentX = x;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
var remainingWidth = maxWidth - (currentX - x);
|
while (i < line.Length)
|
||||||
|
|
||||||
// Check for small-font tag <font6> ... </font6>
|
|
||||||
if (i <= line.Length - 7 && line.Substring(i, 7) == "<font6>")
|
|
||||||
{
|
{
|
||||||
var endTag = line.IndexOf("</font6>", i + 7, StringComparison.Ordinal);
|
if (currentX - x >= maxWidth)
|
||||||
if (endTag != -1)
|
break;
|
||||||
{
|
|
||||||
var inner = line.Substring(i + 7, endTag - (i + 7));
|
|
||||||
if (!string.IsNullOrEmpty(inner))
|
|
||||||
{
|
|
||||||
var measuredSmall = gfx.MeasureString(inner, _smallFont);
|
|
||||||
|
|
||||||
if (measuredSmall.Width > remainingWidth)
|
var remainingWidth = maxWidth - (currentX - x);
|
||||||
|
|
||||||
|
// Check for small-font tag <font6> ... </font6>
|
||||||
|
if (i <= line.Length - 7 && line.Substring(i, 7) == "<font6>")
|
||||||
|
{
|
||||||
|
var endTag = line.IndexOf("</font6>", i + 7, StringComparison.Ordinal);
|
||||||
|
if (endTag != -1)
|
||||||
|
{
|
||||||
|
var inner = line.Substring(i + 7, endTag - (i + 7));
|
||||||
|
if (!string.IsNullOrEmpty(inner))
|
||||||
{
|
{
|
||||||
inner = TruncateTextToWidth(gfx, inner, _smallFont, remainingWidth);
|
var measuredSmall = gfx.MeasureString(inner, _smallFont);
|
||||||
measuredSmall = gfx.MeasureString(inner, _smallFont);
|
|
||||||
|
if (measuredSmall.Width > remainingWidth)
|
||||||
|
{
|
||||||
|
inner = TruncateTextToWidth(gfx, inner, _smallFont, remainingWidth);
|
||||||
|
measuredSmall = gfx.MeasureString(inner, _smallFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx.DrawString(inner, _smallFont, XBrushes.Black,
|
||||||
|
new XRect(currentX, y, remainingWidth, _smallFont.Size * 1.2),
|
||||||
|
XStringFormats.TopLeft);
|
||||||
|
currentX += measuredSmall.Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx.DrawString(inner, _smallFont, XBrushes.Black,
|
i = endTag + 8; // move past </font6>
|
||||||
new XRect(currentX, y, remainingWidth, _smallFont.Size * 1.2),
|
continue;
|
||||||
XStringFormats.TopLeft);
|
|
||||||
currentX += measuredSmall.Width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = endTag + 8; // move past </font6>
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check for bold marker (**)
|
// Check for bold marker (**)
|
||||||
if (i < line.Length - 1 && line[i] == '*' && line[i + 1] == '*')
|
if (i < line.Length - 1 && line[i] == '*' && line[i + 1] == '*')
|
||||||
{
|
|
||||||
// Find closing **
|
|
||||||
var endIndex = line.IndexOf("**", i + 2, StringComparison.Ordinal);
|
|
||||||
if (endIndex != -1)
|
|
||||||
{
|
{
|
||||||
var boldText = line.Substring(i + 2, endIndex - (i + 2));
|
// Find closing **
|
||||||
var measured = gfx.MeasureString(boldText, _boldFont);
|
var endIndex = line.IndexOf("**", i + 2, StringComparison.Ordinal);
|
||||||
|
if (endIndex != -1)
|
||||||
|
{
|
||||||
|
var boldText = line.Substring(i + 2, endIndex - (i + 2));
|
||||||
|
var measured = gfx.MeasureString(boldText, _boldFont);
|
||||||
|
|
||||||
|
if (measured.Width > remainingWidth)
|
||||||
|
{
|
||||||
|
boldText = TruncateTextToWidth(gfx, boldText, _boldFont, remainingWidth);
|
||||||
|
measured = gfx.MeasureString(boldText, _boldFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw bold text and measure width accurately
|
||||||
|
gfx.DrawString(boldText, _boldFont, XBrushes.Black,
|
||||||
|
new XRect(currentX, y, remainingWidth, _boldFont.Size * 1.2),
|
||||||
|
XStringFormats.TopLeft);
|
||||||
|
currentX += measured.Width;
|
||||||
|
i = endIndex + 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular text until next ** or end of line
|
||||||
|
var nextBoldIndex = line.IndexOf("**", i, StringComparison.Ordinal);
|
||||||
|
var textEnd = nextBoldIndex == -1 ? line.Length : nextBoldIndex;
|
||||||
|
var regularText = line.Substring(i, textEnd - i);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(regularText))
|
||||||
|
{
|
||||||
|
var measured = gfx.MeasureString(regularText, _regularFont);
|
||||||
|
|
||||||
if (measured.Width > remainingWidth)
|
if (measured.Width > remainingWidth)
|
||||||
{
|
{
|
||||||
boldText = TruncateTextToWidth(gfx, boldText, _boldFont, remainingWidth);
|
regularText = TruncateTextToWidth(gfx, regularText, _regularFont, remainingWidth);
|
||||||
measured = gfx.MeasureString(boldText, _boldFont);
|
measured = gfx.MeasureString(regularText, _regularFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bold text and measure width accurately
|
gfx.DrawString(regularText, _regularFont, XBrushes.Black,
|
||||||
gfx.DrawString(boldText, _boldFont, XBrushes.Black,
|
new XRect(currentX, y, remainingWidth, _regularFont.Size * 1.2), XStringFormats.TopLeft);
|
||||||
new XRect(currentX, y, remainingWidth, _boldFont.Size * 1.2),
|
|
||||||
XStringFormats.TopLeft);
|
|
||||||
currentX += measured.Width;
|
currentX += measured.Width;
|
||||||
i = endIndex + 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular text until next ** or end of line
|
|
||||||
var nextBoldIndex = line.IndexOf("**", i, StringComparison.Ordinal);
|
|
||||||
var textEnd = nextBoldIndex == -1 ? line.Length : nextBoldIndex;
|
|
||||||
var regularText = line.Substring(i, textEnd - i);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(regularText))
|
|
||||||
{
|
|
||||||
var measured = gfx.MeasureString(regularText, _regularFont);
|
|
||||||
|
|
||||||
if (measured.Width > remainingWidth)
|
|
||||||
{
|
|
||||||
regularText = TruncateTextToWidth(gfx, regularText, _regularFont, remainingWidth);
|
|
||||||
measured = gfx.MeasureString(regularText, _regularFont);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx.DrawString(regularText, _regularFont, XBrushes.Black,
|
i = textEnd;
|
||||||
new XRect(currentX, y, remainingWidth, _regularFont.Size * 1.2), XStringFormats.TopLeft);
|
|
||||||
currentX += measured.Width;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i = textEnd;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while drawing markdown line: {ex.Message}",Logger.LogType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string TruncateTextToWidth(XGraphics gfx, string text, XFont font, double maxWidth)
|
private string TruncateTextToWidth(XGraphics gfx, string text, XFont font, double maxWidth)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(text))
|
try
|
||||||
return text;
|
|
||||||
|
|
||||||
for (var len = text.Length; len > 0; len--)
|
|
||||||
{
|
{
|
||||||
var truncated = text.Substring(0, len);
|
if (string.IsNullOrEmpty(text))
|
||||||
var measured = gfx.MeasureString(truncated, font);
|
return text;
|
||||||
if (measured.Width <= maxWidth)
|
|
||||||
return truncated;
|
for (var len = text.Length; len > 0; len--)
|
||||||
|
{
|
||||||
|
var truncated = text.Substring(0, len);
|
||||||
|
var measured = gfx.MeasureString(truncated, font);
|
||||||
|
if (measured.Width <= maxWidth)
|
||||||
|
return truncated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Log($"Error while truncating text to width: {ex.Message}",Logger.LogType.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user