<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nizamuddien T I</title>
    <description>The latest articles on DEV Community by Nizamuddien T I (@nizamuddien_ti_23261a78b).</description>
    <link>https://dev.to/nizamuddien_ti_23261a78b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1707862%2Fe06563ec-c2ff-4ed6-a3dd-e985a566e8af.jpg</url>
      <title>DEV Community: Nizamuddien T I</title>
      <link>https://dev.to/nizamuddien_ti_23261a78b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nizamuddien_ti_23261a78b"/>
    <language>en</language>
    <item>
      <title>Fixing HTML Table Rowspan Issues in PDFs with IronPDF and C#</title>
      <dc:creator>Nizamuddien T I</dc:creator>
      <pubDate>Sat, 28 Feb 2026 14:12:33 +0000</pubDate>
      <link>https://dev.to/nizamuddien_ti_23261a78b/fixing-html-table-rowspan-issues-in-pdfs-with-ironpdf-and-c-4695</link>
      <guid>https://dev.to/nizamuddien_ti_23261a78b/fixing-html-table-rowspan-issues-in-pdfs-with-ironpdf-and-c-4695</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Understanding the Rowspan Issue&lt;/li&gt;
&lt;li&gt;Visual Comparison&lt;/li&gt;
&lt;li&gt;The Solution&lt;/li&gt;
&lt;li&gt;Implementation Guide&lt;/li&gt;
&lt;li&gt;Custom Font Embedding&lt;/li&gt;
&lt;li&gt;Results&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Generating PDFs from HTML is straightforward—until you encounter complex table layouts. One of the most common real-world issues developers face when converting HTML tables to PDFs using &lt;strong&gt;IronPDF&lt;/strong&gt; is &lt;strong&gt;rowspan misalignment&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;While your tables may appear perfect in a browser, they often render incorrectly in PDF output due to the fundamental differences between how browsers and PDF renderers handle dynamic layouts.&lt;/p&gt;

&lt;p&gt;This tutorial shows how to preprocess tables with rowspan using &lt;em&gt;HtmlAgilityPack&lt;/em&gt; and generate clean PDFs with &lt;strong&gt;IronPDF&lt;/strong&gt; in C#. Step-by-step guidance, sample code, and a GitHub repository make it easy to implement this fix in your projects. Perfect for .NET developers working with complex HTML-to-PDF conversions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Rowspan Issue
&lt;/h2&gt;

&lt;p&gt;What is Rowspan?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;rowspan&lt;/code&gt; attribute in HTML tables allows a single cell to span multiple rows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Rows&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Description&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;rowspan=&lt;/span&gt;&lt;span class="s"&gt;"100"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Row span 100&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;1&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Row 1&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Row 2&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;3&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Row 3&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
        ........    // other rows
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;100&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;Row 100&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;The Problem:&lt;/p&gt;

&lt;p&gt;When browsers render this HTML, they dynamically calculate cell positions and maintain layout consistency. However, PDF rendering requires fixed layouts with predefined coordinates. This fundamental difference causes several issues:&lt;/p&gt;

&lt;p&gt;Common Problems:&lt;/p&gt;

&lt;p&gt;🔴 Misaligned columns - Columns shift position incorrectly&lt;br&gt;
🔴 Broken borders - Table borders appear disconnected&lt;br&gt;
🔴 Inconsistent row heights - Rows have unpredictable heights&lt;br&gt;
🔴 Overlapping content - Text or cells may overlap&lt;/p&gt;
&lt;h5&gt;
  
  
  Why This Happens:
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;PDF rendering engines don't dynamically recalculate layouts like browsers do.&lt;/li&gt;
&lt;li&gt;Rowspan cells need explicit height calculations.&lt;/li&gt;
&lt;li&gt;The renderer doesn't know the total height needed for spanned rows until it processes all rows.&lt;/li&gt;
&lt;li&gt;This creates ambiguity in cell positioning and sizing.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Visual Comparison
&lt;/h2&gt;
&lt;h5&gt;
  
  
  Browser Rendering (Works Fine):
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd17vy5u33slooheie3ui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd17vy5u33slooheie3ui.png" alt=" " width="533" height="401"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  PDF Without Fix (Broken):
&lt;/h5&gt;

&lt;p&gt;Page - 1:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhd81h3bp4gkr68tg3v5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhd81h3bp4gkr68tg3v5.png" alt=" " width="398" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Page - 2:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvgds3e7fbob1w5kp5yc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftvgds3e7fbob1w5kp5yc.png" alt=" " width="388" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Page - 5 (&lt;em&gt;Page - 3 and 4 are blank&lt;/em&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucn0eocpnj6ngtn3nfa6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fucn0eocpnj6ngtn3nfa6.png" alt=" " width="391" height="321"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;the rows are continued till 100&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Page - 8 (&lt;em&gt;Final page&lt;/em&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72lv7jddqhbgi15xhefo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72lv7jddqhbgi15xhefo.png" alt=" " width="398" height="188"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Solution:
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Pre-Render Normalization
&lt;/h3&gt;
&lt;h5&gt;
  
  
  How It Works
&lt;/h5&gt;

&lt;p&gt;Instead of trying to fix the PDF rendering directly, we normalize the HTML before rendering it to PDF. This approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Detects rowspan usage&lt;/strong&gt; - Scans all table cells for rowspan attributes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expands table structure&lt;/strong&gt; - Replaces rowspan with explicit rows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inserts layout-safe filler cells&lt;/strong&gt; - Adds empty cells to maintain column alignment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preserves visual alignment&lt;/strong&gt; - Applies CSS styling to hide borders on filler cells&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates clean PDFs&lt;/strong&gt; - IronPDF renders the normalized structure perfectly&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;
  
  
  Algorithm Overview
&lt;/h5&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: HTML with rowspan="100"
  │
  ├─ Parse HTML using HtmlAgilityPack
  │
  ├─ For each table:
  │   ├─ Iterate through all rows
  │   ├─ Track active rowspans per column index
  │   ├─ For cells with rowspan:
  │   │  ├─ Remove bottom border from original cell
  │   │  ├─ Create (rowspan-1) cloned cells
  │   │  ├─ Remove borders from clones
  │   │  └─ Queue them for insertion in subsequent rows
  │   └─ Insert queued cells at appropriate column positions
  │
  └─ Output: HTML with normalized table structure

Result: PDF with perfect table alignment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h5&gt;
  
  
  Key Benefits
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Benefit&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simple Implementation&lt;/td&gt;
&lt;td&gt;Works with standard HTML/CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No Library Modifications&lt;/td&gt;
&lt;td&gt;Uses IronPDF as-is&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compatible&lt;/td&gt;
&lt;td&gt;Works with any table structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Predictable Results&lt;/td&gt;
&lt;td&gt;Normalizes HTML before rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No Performance Impact&lt;/td&gt;
&lt;td&gt;Runs in milliseconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h2&gt;
  
  
  Implementation Guide
&lt;/h2&gt;
&lt;h6&gt;
  
  
  Step 1: Install Required Dependencies
&lt;/h6&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- Add to .csproj --&amp;gt;
&amp;lt;ItemGroup&amp;gt;
  &amp;lt;PackageReference Include="IronPdf" Version="2024.12.3" /&amp;gt;
  &amp;lt;PackageReference Include="HtmlAgilityPack" Version="1.11.61" /&amp;gt;
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h6&gt;
  
  
  Step 2: Create the RowSpan Expander Helper
&lt;/h6&gt;

&lt;p&gt;&lt;em&gt;The core logic that fixes rowspan issues:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using HtmlAgilityPack;

namespace IronPdfMVC.Helpers
{
    public static class RowspanExpander
    {
        private const string STYLE_ATTRIBUTE = "style";

        /// &amp;lt;summary&amp;gt;
        /// Expands all rowspans in HTML tables to create a normalized structure
        /// &amp;lt;/summary&amp;gt;
        public static string ExpandRowspans(string html)
        {
            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            var tables = doc.DocumentNode.SelectNodes("//table");
            if (tables == null)
                return html;

            foreach (var table in tables)
            {
                ExpandTable(table);
            }

            return doc.DocumentNode.OuterHtml;
        }

        private static void ExpandTable(HtmlNode table)
        {
            var rows = table.SelectNodes(".//tr");
            if (rows == null)
                return;

            // Tracks active rowspans per column index
            // Key: column index, Value: queue of cloned cells to insert
            var activeRowspans = new Dictionary&amp;lt;int, Queue&amp;lt;HtmlNode&amp;gt;&amp;gt;();

            foreach (var row in rows)
            {
                var cells = row.Elements("td")
                               .Concat(row.Elements("th"))
                               .ToList();

                int colIndex = 0;

                // Step 1: Inject pending rowspan cells from previous rows
                while (activeRowspans.ContainsKey(colIndex))
                {
                    var queue = activeRowspans[colIndex];
                    if (queue.Count == 0)
                    {
                        activeRowspans.Remove(colIndex);
                        break;
                    }

                    var clonedCell = queue.Dequeue();
                    InsertCellAtColumn(row, clonedCell.Clone(), colIndex);
                    colIndex++;
                }

                // Step 2: Process current row's cells
                foreach (var cell in cells)
                {
                    // Skip columns with active rowspans from previous rows
                    while (activeRowspans.ContainsKey(colIndex))
                    {
                        colIndex++;
                    }

                    // Check if this cell has a rowspan &amp;gt; 1
                    if (cell.Attributes["rowspan"] != null &amp;amp;&amp;amp;
                        int.TryParse(cell.Attributes["rowspan"].Value, out int span) &amp;amp;&amp;amp;
                        span &amp;gt; 1)
                    {
                        // Remove bottom border to create seamless appearance
                        AppendInlineStyle(cell, "border-bottom: none;");

                        var clones = new Queue&amp;lt;HtmlNode&amp;gt;();

                        // Create (span - 1) filler cells
                        for (int i = 1; i &amp;lt; span; i++)
                        {
                            var clone = cell.Clone();
                            clone.Attributes.Remove("rowspan");
                            clone.InnerHtml = string.Empty; // Empty the cell content

                            // Style filler cells to be invisible
                            AppendInlineStyle(clone, 
                                "border-top: none;border-bottom: none;padding-top: 0;padding-bottom: 0;");

                            clones.Enqueue(clone);
                        }

                        // Queue these cells for insertion in subsequent rows
                        activeRowspans[colIndex] = clones;

                        // Remove rowspan attribute (now handled by explicit cells)
                        cell.Attributes.Remove("rowspan");
                    }

                    colIndex++;
                }
            }
        }

        /// &amp;lt;summary&amp;gt;
        /// Appends CSS styles to a cell's inline style attribute
        /// &amp;lt;/summary&amp;gt;
        private static void AppendInlineStyle(HtmlNode node, string style)
        {
            var existing = node.GetAttributeValue(STYLE_ATTRIBUTE, string.Empty);

            if (!string.IsNullOrWhiteSpace(existing) &amp;amp;&amp;amp; !existing.Trim().EndsWith(";"))
            {
                existing += ";";
            }

            node.SetAttributeValue(STYLE_ATTRIBUTE, existing + style);
        }

        /// &amp;lt;summary&amp;gt;
        /// Inserts a cell at the specified column position
        /// &amp;lt;/summary&amp;gt;
        private static void InsertCellAtColumn(HtmlNode row, HtmlNode cell, int colIndex)
        {
            var existingCells = row.Elements("td")
                                   .Concat(row.Elements("th"))
                                   .ToList();

            if (colIndex &amp;gt;= existingCells.Count)
            {
                row.AppendChild(cell);
            }
            else
            {
                row.InsertBefore(cell, existingCells[colIndex]);
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Step 3: Create the PDF Generation Controller
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using IronPdf;
using IronPdfMVC.Enums;
using IronPdfMVC.Factories;
using IronPdfMVC.Helpers;
using IronPdfMVC.Models;
using Microsoft.AspNetCore.Mvc;

namespace IronPdfMVC.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var model = new PrintModel
            {
                RowspanOutput = RowspanOutput.Raw,
                RowspanOutputOptions = typeof(RowspanOutput).ToSelectList(RowspanOutput.Raw),
                SelectedFont = "ToThePointRegular",
            };
            return View(model);
        }

        [HttpPost]
        public IActionResult PrintPdf(PrintModel model)
        {
            // Build CSS for table styling
            var normalCss = @"
                table, th, td {
                    border: 1px solid black;
                    border-collapse: collapse;
                    padding: 8px;
                }
            ";

            // Build HTML content with table containing rowspan
            string htmlContent = $@"
                &amp;lt;!DOCTYPE html&amp;gt;
                &amp;lt;html lang=""en""&amp;gt;
                &amp;lt;head&amp;gt;
                    &amp;lt;meta charset=""UTF-8""&amp;gt;
                    &amp;lt;meta name=""viewport"" content=""width=device-width, initial-scale=1.0""&amp;gt;
                    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
                    &amp;lt;style&amp;gt;{normalCss}";

            // Add custom font CSS if selected
            if (model.UseCustomFont)
            {
                htmlContent += GetFontEmbeddingCss(model.SelectedFont);
            }

            htmlContent += @"
                    &amp;lt;/style&amp;gt;
                &amp;lt;/head&amp;gt;
                &amp;lt;body&amp;gt;
                    &amp;lt;h2&amp;gt;Table with Rowspan&amp;lt;/h2&amp;gt;
                    &amp;lt;table&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th&amp;gt;&amp;lt;/th&amp;gt;
                            &amp;lt;th&amp;gt;Rows&amp;lt;/th&amp;gt;
                            &amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;td rowspan=""100""&amp;gt;Row span 100&amp;lt;/td&amp;gt;";

            // Add table rows (1-100)
            htmlContent = InvoicePdfFactory.PrepareRowspanTableContent(htmlContent);

            htmlContent += @"
                        &amp;lt;/table&amp;gt;
                    &amp;lt;/body&amp;gt;
                &amp;lt;/html&amp;gt;";

            // Create PDF renderer
            var renderer = new ChromePdfRenderer();
            PdfDocument pdf;

            // Apply rowspan fix if selected
            if (model.RowspanOutput == RowspanOutput.Fixed)
            {
                // FIX: Normalize HTML before rendering
                var expandedHtml = RowspanExpander.ExpandRowspans(htmlContent);
                pdf = renderer.RenderHtmlAsPdf(expandedHtml);
                pdf.SaveAs("Fixed_Rowspan.pdf");
            }
            else
            {
                // Raw: Render without fix
                pdf = renderer.RenderHtmlAsPdf(htmlContent);
                pdf.SaveAs("Raw_Rowspan.pdf");
            }

            // Return PDF to user
            return File(pdf.BinaryData, "application/pdf");
        }

        private string GetFontEmbeddingCss(string fontName)
        {
            // Load font file from wwwroot/fonts/
            var fontPath = Path.Combine(
                Directory.GetCurrentDirectory(), 
                "wwwroot", 
                "fonts", 
                $"{fontName}.ttf"
            );

            // Read and encode to Base64
            var fontBytes = System.IO.File.ReadAllBytes(fontPath);
            var fontBase64 = Convert.ToBase64String(fontBytes);

            // Return @font-face CSS with embedded font
            return $@"
                @font-face {{
                    font-family: 'CustomFont';
                    src: url('data:font/ttf;base64,{fontBase64}') format('truetype');
                    font-weight: normal;
                    font-style: normal;
                    font-display: swap;
                }}
                body, table, td, th {{ 
                    font-family: 'CustomFont', sans-serif; 
                }}
            ";
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Custom Font Embedding
&lt;/h2&gt;

&lt;h6&gt;
  
  
  Why Embed Fonts?
&lt;/h6&gt;

&lt;p&gt;When you generate PDFs, you need to ensure the fonts are available on the server and properly embedded in the PDF. Without embedding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Fonts may not render on all systems&lt;/li&gt;
&lt;li&gt;❌ PDF viewers might substitute fonts&lt;/li&gt;
&lt;li&gt;❌ Brand typography becomes inconsistent&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  How It Works
&lt;/h6&gt;

&lt;p&gt;The process involves three steps:&lt;br&gt;
&lt;strong&gt;Step 1: Load Font File&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fontPath = Path.Combine(
    Directory.GetCurrentDirectory(), 
    "wwwroot", 
    "fonts", 
    "ToThePointRegular.ttf"
);
var fontBytes = System.IO.File.ReadAllBytes(fontPath);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Encode to Base64&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fontBase64 = Convert.ToBase64String(fontBytes);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Embed in CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var fontCss = $@"
    @font-face {{
        font-family: 'ToThePoint';
        src: url('data:font/ttf;base64,{fontBase64}') format('truetype');
        font-weight: normal;
        font-style: normal;
        font-display: swap;
    }}
    body, table, td, th {{ font-family: 'ToThePoint', sans-serif; }}
";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Font Format Support
&lt;/h6&gt;

&lt;p&gt;IronPDF supports multiple font formats:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;CSS Format&lt;/th&gt;
&lt;th&gt;Support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TrueType&lt;/td&gt;
&lt;td&gt;.ttf&lt;/td&gt;
&lt;td&gt;&lt;code&gt;format('truetype')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenType&lt;/td&gt;
&lt;td&gt;.otf&lt;/td&gt;
&lt;td&gt;&lt;code&gt;format('opentype')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WOFF&lt;/td&gt;
&lt;td&gt;.woff&lt;/td&gt;
&lt;td&gt;&lt;code&gt;format('woff')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WOFF2&lt;/td&gt;
&lt;td&gt;.woff2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;format('woff2')&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅ Good&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h6&gt;
  
  
  Complete Font Embedding Example
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Embed multiple font weights
var fontCss = $@"
    @font-face {{
        font-family: 'CustomFont';
        src: url('data:font/ttf;base64,{regular}') format('truetype');
        font-weight: normal;
    }}

    @font-face {{
        font-family: 'CustomFont';
        src: url('data:font/ttf;base64,{bold}') format('truetype');
        font-weight: bold;
    }}

    @font-face {{
        font-family: 'CustomFont';
        src: url('data:font/ttf;base64,{italic}') format('truetype');
        font-style: italic;
    }}

    body, table, td, th {{ 
        font-family: 'CustomFont', Arial, sans-serif; 
    }}
";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;h6&gt;
  
  
  Transformed HTML:
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;table&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td style="border-bottom: none;"&amp;gt;Row span 100&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;Row 1&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td style="border-top: none; border-bottom: none; padding-top: 0; padding-bottom: 0;"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;!-- ↑ Filler cell created by RowspanExpander --&amp;gt;
    &amp;lt;td&amp;gt;Row 2&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td style="border-top: none; border-bottom: none; padding-top: 0; padding-bottom: 0;"&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;!-- ↑ Filler cell created by RowspanExpander --&amp;gt;
    &amp;lt;td&amp;gt;Row 3&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  ...
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  PDF Rendering Result:
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;✅ All columns properly aligned&lt;/li&gt;
&lt;li&gt;✅ Seamless borders maintained&lt;/li&gt;
&lt;li&gt;✅ Consistent row heights&lt;/li&gt;
&lt;li&gt;✅ Professional appearance&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;By implementing the rowspan expansion approach, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Reliably generate PDFs with complex table layouts&lt;/li&gt;
&lt;li&gt;✅ Maintain visual consistency across all devices and viewers&lt;/li&gt;
&lt;li&gt;✅ Embed custom fonts for branded documents&lt;/li&gt;
&lt;li&gt;✅ Scale to production with minimal performance impact&lt;/li&gt;
&lt;li&gt;✅ Handle edge cases with proper error handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/nizambajal/ironpdf-rowspan-fix-dotnet" rel="noopener noreferrer"&gt;https://github.com/nizambajal/ironpdf-rowspan-fix-dotnet&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;IronPDF Docs:&lt;/strong&gt; &lt;a href="https://ironsoftware.com/csharp/pdf/" rel="noopener noreferrer"&gt;https://ironsoftware.com/csharp/pdf/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;HtmlAgilityPack:&lt;/strong&gt; &lt;a href="https://html-agility-pack.net/" rel="noopener noreferrer"&gt;https://html-agility-pack.net/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;HTML Tables MDN:&lt;/strong&gt; &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>ironpdf</category>
      <category>pdf</category>
    </item>
  </channel>
</rss>
