DEV Community

IronSoftware
IronSoftware

Posted on

VectSharp vs IronPDF: a developer comparison for 2026

VectSharp vs IronPDF: a developer comparison for 2026

Understanding IronPDF

IronPDF converts HTML/CSS/JavaScript into pixel-perfect PDFs using a Chromium rendering engine. You hand it an HTML string, a URL, or a Razor view, and it returns a PDF document. It's designed for scenarios where content structure already exists in HTML—invoices, reports, documentation, web page archives—and you need print-quality output without manually positioning every element.

The API centers on ChromePdfRenderer with methods for rendering HTML strings, files, or URLs. It handles modern web standards (CSS Grid, Flexbox, Web Fonts), executes JavaScript, and supports features like headers, footers, watermarks, and form creation. Install via NuGet (IronPdf), works cross-platform.

Key Characteristics of VectSharp

Product Status

VectSharp is an actively maintained open-source project (LGPLv3) with regular updates. Version 3.2.0 released in 2024. It's a vector graphics library, not a document converter—this distinction is critical.

Design Purpose

VectSharp creates vector graphics programmatically through a Graphics API. You draw shapes, lines, text, and paths using C# code. It's ideal for:

  • Scientific plots and data visualization from raw data
  • Geometric diagrams and technical illustrations
  • Custom chart libraries where you control every pixel
  • Situations where HTML/CSS layout would be overkill

Technical Capabilities

VectSharp.PDF outputs vector PDFs. VectSharp.SVG creates SVG files. VectSharp.Canvas integrates with Avalonia UI. The API provides drawing primitives: FillRectangle, StrokePath, DrawText, etc. You specify coordinates, colors, and transformations manually.

Support Status

Community-driven open-source. Maintainer is responsive on GitHub. No commercial support or SLA. Documentation is thorough for drawing operations but assumes you're building graphics from scratch.

Architecture Approach

VectSharp follows a painter's model: create a Document, add Page objects, get a Graphics surface, and issue drawing commands. No HTML parsing, no CSS layout engine, no browser-like rendering. You control every coordinate.

What VectSharp Cannot Do

  1. Parse HTML: VectSharp has no HTML parser. If your content is in HTML format, you must manually translate it into drawing commands.
  2. Apply CSS styles: No CSS engine. All styling (fonts, colors, spacing) must be specified programmatically.
  3. Render web content: Cannot convert URLs, Razor views, or HTML templates.
  4. Execute JavaScript: No JavaScript engine—it's a graphics library, not a browser.
  5. Layout complex documents automatically: No Flexbox, Grid, or table layout algorithms. You calculate positions.

Feature Comparison Overview

Aspect VectSharp IronPDF
Current Status Active (3.2.0, 2024) Active (monthly releases)
Primary Purpose Programmatic vector graphics HTML/web content to PDF
HTML Support None—manual drawing only Full HTML5, CSS3, JavaScript
Rendering Approach Low-level Graphics API Chromium browser engine
Installation Single NuGet, lightweight Single NuGet, includes engine
Use Case Charts from data, diagrams Invoices, reports, web archives

Troubleshooting Scenario: Converting an Invoice Template

The VectSharp Approach (Manual Drawing)

using VectSharp;
using VectSharp.PDF;
using System;

public class VectSharpInvoiceGenerator
{
    public void GenerateInvoice(InvoiceData data, string outputPath)
    {
        // Create document manually
        Document doc = new Document();
        Page page = new Page(595, 842); // A4 size in points
        doc.Pages.Add(page);
        Graphics graphics = page.Graphics;

        // Must manually position every element
        Font headerFont = new Font(FontFamily.ResolveFontFamily(
            FontFamily.StandardFontFamilies.HelveticaBold), 24);
        Font bodyFont = new Font(FontFamily.ResolveFontFamily(
            FontFamily.StandardFontFamilies.Helvetica), 12);

        // Draw company name
        graphics.DrawText("ACME Corporation", 50, 50, headerFont, 
            Colour.FromRgb(0, 0, 0));

        // Draw invoice number
        graphics.DrawText($"Invoice #{data.InvoiceNumber}", 50, 80, 
            bodyFont, Colour.FromRgb(0, 0, 0));

        // Manually draw table borders
        graphics.StrokePath(new GraphicsPath().MoveTo(50, 150)
            .LineTo(545, 150), Colour.FromRgb(0, 0, 0), 1);

        // Draw each table row with manual Y-coordinate calculation
        double yPos = 160;
        foreach (var item in data.LineItems)
        {
            graphics.DrawText(item.Description, 60, yPos, bodyFont, 
                Colour.FromRgb(0, 0, 0));
            graphics.DrawText($"${item.Amount:F2}", 450, yPos, bodyFont, 
                Colour.FromRgb(0, 0, 0));
            yPos += 20;
        }

        // Draw total with manual positioning
        graphics.DrawText("Total:", 350, yPos + 20, headerFont, 
            Colour.FromRgb(0, 0, 0));
        graphics.DrawText($"${data.Total:F2}", 450, yPos + 20, headerFont, 
            Colour.FromRgb(0, 0, 128));

        // Save PDF
        doc.SaveAsPDF(outputPath);
    }
}

public class InvoiceData
{
    public string InvoiceNumber { get; set; }
    public LineItem[] LineItems { get; set; }
    public decimal Total { get; set; }
}

public class LineItem
{
    public string Description { get; set; }
    public decimal Amount { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Troubleshooting issues commonly encountered:

  1. Font rendering inconsistencies: Standard fonts work, custom TTF fonts require loading from streams with no error feedback
  2. Text measurement challenges: No automatic text wrapping—must manually calculate line breaks
  3. Coordinate math errors: One-off pixel errors accumulate across complex layouts
  4. No templating: Changes require recompiling C# code, not editing HTML templates
  5. Image positioning: Base64 or file path images need manual width/height/position calculation
  6. Maintenance burden: Every layout change requires updating coordinate mathematics

IronPDF Approach (HTML Rendering)

using IronPdf;
using System.Threading.Tasks;

public class IronPdfInvoiceGenerator
{
    public async Task GenerateInvoiceAsync(InvoiceData data, string outputPath)
    {
        // Build HTML template (or load from file/Razor view)
        string html = $@"
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body {{ font-family: Arial, sans-serif; margin: 40px; }}
                h1 {{ color: #333; }}
                table {{ width: 100%; border-collapse: collapse; margin-top: 20px; }}
                th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                th {{ background-color: #f2f2f2; }}
                .total {{ font-size: 18px; font-weight: bold; color: #000080; }}
            </style>
        </head>
        <body>
            <h1>ACME Corporation</h1>
            <p>Invoice #{data.InvoiceNumber}</p>
            <table>
                <tr><th>Description</th><th>Amount</th></tr>
                {string.Join("", data.LineItems.Select(item => 
                    $"<tr><td>{item.Description}</td><td>${item.Amount:F2}</td></tr>"))}
            </table>
            <p class='total'>Total: ${data.Total:F2}</p>
        </body>
        </html>";

        var renderer = new ChromePdfRenderer();
        using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
        await pdf.SaveAsAsync(outputPath);
    }
}
Enter fullscreen mode Exit fullscreen mode

IronPDF eliminates coordinate mathematics. The HTML template handles layout automatically using CSS. Changes to styling or structure require editing HTML/CSS, not recalculating positions. See HTML file to PDF conversion for template-based workflows.


Troubleshooting Scenario: Adding a Company Logo

VectSharp Approach

using VectSharp;
using VectSharp.MuPDFUtils;
using VectSharp.PDF;
using System;

public class VectSharpLogoRenderer
{
    public void AddLogoToDocument(string logoPath, string outputPath)
    {
        Document doc = new Document();
        Page page = new Page(595, 842);
        doc.Pages.Add(page);
        Graphics graphics = page.Graphics;

        try
        {
            // Load image using MuPDFUtils (requires separate package)
            // Note: VectSharp.MuPDFUtils has AGPLv3 license restrictions
            var image = MuPDFUtils.ImageURIParser.ParseImageURI(logoPath);

            // Must manually calculate aspect ratio and position
            double imageWidth = 100;
            double imageHeight = (image.Height / image.Width) * imageWidth;

            graphics.DrawRasterImage(50, 50, imageWidth, imageHeight, image);

            // Add text below (manual positioning)
            Font font = new Font(FontFamily.ResolveFontFamily(
                FontFamily.StandardFontFamilies.Helvetica), 14);
            graphics.DrawText("Company Report", 50, 50 + imageHeight + 10, 
                font, Colour.FromRgb(0, 0, 0));
        }
        catch (Exception ex)
        {
            // Image loading can fail silently with unclear errors
            Console.WriteLine($"Image load failed: {ex.Message}");
        }

        doc.SaveAsPDF(outputPath);
    }
}
Enter fullscreen mode Exit fullscreen mode

Troubleshooting challenges:

  1. License complexity: MuPDFUtils uses AGPLv3 (stricter than VectSharp's LGPLv3)
  2. Format support unclear: PNG works, JPEG sometimes, WebP uncertain—must test
  3. Memory errors: Large images can crash with cryptic native exceptions
  4. No caching: Every render reloads image from disk
  5. Position calculation: Logo placement relative to text requires manual math
  6. No responsive behavior: Image doesn't adapt to content height changes

IronPDF Approach

using IronPdf;
using System.Threading.Tasks;

public class IronPdfLogoRenderer
{
    public async Task AddLogoToDocumentAsync(string logoPath, string outputPath)
    {
        string html = $@"
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body {{ font-family: Arial; margin: 40px; }}
                .logo {{ width: 200px; height: auto; }}
                h1 {{ margin-top: 20px; }}
            </style>
        </head>
        <body>
            <img src='{logoPath}' class='logo' alt='Company Logo' />
            <h1>Company Report</h1>
            <p>Generated on {DateTime.Now:yyyy-MM-dd}</p>
        </body>
        </html>";

        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PrintHtmlBackgrounds = true;

        using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
        await pdf.SaveAsAsync(outputPath);
    }
}
Enter fullscreen mode Exit fullscreen mode

IronPDF handles image loading automatically. Supports PNG, JPEG, WebP, SVG, even base64-encoded images. CSS controls sizing and positioning. The browser engine manages aspect ratio and layout reflow. Rendering options documentation covers image optimization.


Troubleshooting Scenario: Multi-Page Report with Dynamic Content

VectSharp Approach

using VectSharp;
using VectSharp.PDF;

public class VectSharpMultiPageReport
{
    public void GenerateReport(ReportData data, string outputPath)
    {
        Document doc = new Document();
        Font font = new Font(FontFamily.ResolveFontFamily(
            FontFamily.StandardFontFamilies.Helvetica), 12);

        // Must manually paginate content
        const double pageHeight = 842; // A4
        const double marginTop = 50;
        const double marginBottom = 50;
        const double usableHeight = pageHeight - marginTop - marginBottom;
        const double lineHeight = 20;

        Page currentPage = new Page(595, pageHeight);
        doc.Pages.Add(currentPage);
        Graphics graphics = currentPage.Graphics;
        double currentY = marginTop;

        foreach (var section in data.Sections)
        {
            // Check if we need a new page
            if (currentY + lineHeight > usableHeight)
            {
                currentPage = new Page(595, pageHeight);
                doc.Pages.Add(currentPage);
                graphics = currentPage.Graphics;
                currentY = marginTop;
            }

            graphics.DrawText(section.Title, 50, currentY, font, 
                Colour.FromRgb(0, 0, 0));
            currentY += lineHeight;

            // Must handle text wrapping manually
            foreach (var line in WrapText(section.Content, 495, font))
            {
                if (currentY + lineHeight > usableHeight)
                {
                    currentPage = new Page(595, pageHeight);
                    doc.Pages.Add(currentPage);
                    graphics = currentPage.Graphics;
                    currentY = marginTop;
                }

                graphics.DrawText(line, 50, currentY, font, 
                    Colour.FromRgb(0, 0, 0));
                currentY += lineHeight;
            }
        }

        doc.SaveAsPDF(outputPath);
    }

    private string[] WrapText(string text, double maxWidth, Font font)
    {
        // Must implement text measurement and wrapping manually
        // This is a simplified placeholder—real implementation is complex
        return text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    }
}
Enter fullscreen mode Exit fullscreen mode

Troubleshooting issues:

  1. Pagination logic errors: Off-by-one errors when calculating page breaks
  2. Text measurement inaccuracies: Font metrics don't account for kerning or ligatures
  3. Header/footer challenges: Must manually draw on every page
  4. Table pagination: Splitting tables across pages requires complex state tracking
  5. Orphan/widow control: No automatic prevention of single-line breaks
  6. Performance: Large documents require many Graphics object allocations

IronPDF Approach

using IronPdf;
using System.Threading.Tasks;
using System.Linq;

public class IronPdfMultiPageReport
{
    public async Task GenerateReportAsync(ReportData data, string outputPath)
    {
        string html = $@"
        <!DOCTYPE html>
        <html>
        <head>
            <style>
                body {{ font-family: Arial; margin: 40px; }}
                h2 {{ color: #333; page-break-before: always; }}
                h2:first-of-type {{ page-break-before: avoid; }}
                p {{ line-height: 1.6; }}
                @page {{ margin: 1in; }}
            </style>
        </head>
        <body>
            {string.Join("", data.Sections.Select(section => $@"
                <h2>{section.Title}</h2>
                <p>{section.Content}</p>
            "))}
        </body>
        </html>";

        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.MarginTop = 20;
        renderer.RenderingOptions.MarginBottom = 20;
        renderer.RenderingOptions.TextHeader.CenterText = "Company Report";
        renderer.RenderingOptions.TextFooter.CenterText = "Page {page} of {total-pages}";

        using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
        await pdf.SaveAsAsync(outputPath);
    }
}
Enter fullscreen mode Exit fullscreen mode

IronPDF automatically paginates content. CSS page-break-before controls section starts. Headers and footers support page numbering with {page} and {total-pages} placeholders. Tables split across pages automatically. Pixel-perfect HTML to PDF guide explains advanced layout control.


API Mapping Reference

VectSharp Concept IronPDF Equivalent
Document / Page ChromePdfRenderer.RenderHtmlAsPdf() creates PdfDocument
Graphics.FillRectangle() Use HTML <div> with CSS background-color
Graphics.StrokePath() Use SVG <path> elements or CSS borders
Graphics.DrawText() Use HTML text elements (<p>, <h1>, etc.)
Font / FontFamily CSS font-family, font-size, font-weight
Colour.FromRgb() CSS rgb() or hex colors
Manual pagination logic Automatic via CSS page-break-* properties
doc.SaveAsPDF() pdf.SaveAs() or pdf.SaveAsAsync()
Image drawing coordinates <img> tag with CSS positioning
Manual table construction HTML <table> elements with CSS styling
GraphicsPath for shapes SVG inline or CSS border-radius / clip-path
No templating system HTML templates, Razor views, or string interpolation
Manual wrapping calculation Browser's automatic text flow

Comprehensive Feature Comparison

Feature Category VectSharp IronPDF
Status & Support
Active Development Yes (open-source) Yes (commercial, monthly)
Commercial Support No Yes—engineering team
License LGPLv3 (AGPLv3 for raster) Commercial + trial
.NET 9 Support Yes Yes
Primary Use Case
HTML Rendering No—not designed for it Yes—core purpose
Programmatic Graphics Yes—draw charts, plots No—use HTML/Canvas instead
Scientific Visualization Yes—ideal HTML + Plotly/D3 via JavaScript
Invoice/Report Gen Manual drawing required Template-based rendering
Content Creation
HTML Parsing No Yes
CSS Styling No Full CSS3 support
JavaScript Execution No Yes—Chrome V8 engine
Responsive Layouts No Yes—viewport control
Web Fonts Manual font loading Automatic from CDN or files
SVG Support Outputs SVG Renders SVG in HTML
Development Experience
Code Complexity High for documents Low for HTML content
Templating No—pure C# HTML/Razor/Blazor templates
Designer Collaboration No—requires C# changes Yes—designers edit HTML/CSS
Maintenance Coordinate math updates CSS/HTML updates
Debugging Manual inspection Browser DevTools preview
Document Features
Automatic Pagination No Yes
Headers/Footers Manual per-page Built-in with placeholders
Table of Contents Manual implementation Automatic from headings
Bookmarks Manual API calls Automatic from HTML structure
Hyperlinks Manual link regions Automatic from <a> tags
Forms Not applicable CreatePdfFormsFromHtml

Installation Comparison

VectSharp:

Install-Package VectSharp.PDF
# For image support:
Install-Package VectSharp.MuPDFUtils  # AGPLv3 license
# Or:
Install-Package VectSharp.ImageSharpUtils  # LGPLv3, slower
Enter fullscreen mode Exit fullscreen mode
using VectSharp;
using VectSharp.PDF;

Document doc = new Document();
Page page = new Page(595, 842);
doc.Pages.Add(page);
Graphics graphics = page.Graphics;

Font font = new Font(FontFamily.ResolveFontFamily(
    FontFamily.StandardFontFamilies.Helvetica), 14);
graphics.DrawText("Hello", 50, 50, font, Colour.FromRgb(0, 0, 0));

doc.SaveAsPDF("output.pdf");
Enter fullscreen mode Exit fullscreen mode

IronPDF:

Install-Package IronPdf
Enter fullscreen mode Exit fullscreen mode
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
Enter fullscreen mode Exit fullscreen mode

Conclusion

VectSharp and IronPDF solve fundamentally different problems. VectSharp is a vector graphics API for creating plots, diagrams, and technical illustrations programmatically. It offers precision control over every coordinate but requires manual management of layout, pagination, and text flow. Teams building custom chart libraries or scientific visualization tools will find VectSharp's drawing primitives exactly what they need.

IronPDF converts HTML/CSS/JavaScript into PDFs. It's designed for scenarios where content structure already exists in markup or where designers/stakeholders need to update templates without recompiling C# code. The trade-off is less pixel-level control in exchange for automatic layout management and web-standard compatibility.

Migration from VectSharp to IronPDF typically happens when:

  • Stakeholders request "just add our HTML invoice template"
  • Coordinate math becomes unmaintainable as reports grow
  • Designers need to update styles without developer involvement
  • Dynamic content requires complex pagination logic
  • Existing web views need PDF export capability
  • Text wrapping and table layout become too complex to implement manually

Conversely, stick with VectSharp if you're:

  • Building a charting library from scratch with full control
  • Creating mathematical diagrams with precise geometric calculations
  • Generating scientific plots where browser rendering would be overkill
  • Avoiding any HTML/CSS involvement by architectural requirement

Have you built document generators using either approach? What tipped the decision toward drawing APIs versus HTML rendering?

Related Resources:

Top comments (0)