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
- Parse HTML: VectSharp has no HTML parser. If your content is in HTML format, you must manually translate it into drawing commands.
- Apply CSS styles: No CSS engine. All styling (fonts, colors, spacing) must be specified programmatically.
- Render web content: Cannot convert URLs, Razor views, or HTML templates.
- Execute JavaScript: No JavaScript engine—it's a graphics library, not a browser.
- 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; }
}
Troubleshooting issues commonly encountered:
- Font rendering inconsistencies: Standard fonts work, custom TTF fonts require loading from streams with no error feedback
- Text measurement challenges: No automatic text wrapping—must manually calculate line breaks
- Coordinate math errors: One-off pixel errors accumulate across complex layouts
- No templating: Changes require recompiling C# code, not editing HTML templates
- Image positioning: Base64 or file path images need manual width/height/position calculation
- 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);
}
}
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);
}
}
Troubleshooting challenges:
- License complexity: MuPDFUtils uses AGPLv3 (stricter than VectSharp's LGPLv3)
- Format support unclear: PNG works, JPEG sometimes, WebP uncertain—must test
- Memory errors: Large images can crash with cryptic native exceptions
- No caching: Every render reloads image from disk
- Position calculation: Logo placement relative to text requires manual math
- 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);
}
}
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);
}
}
Troubleshooting issues:
- Pagination logic errors: Off-by-one errors when calculating page breaks
- Text measurement inaccuracies: Font metrics don't account for kerning or ligatures
- Header/footer challenges: Must manually draw on every page
- Table pagination: Splitting tables across pages requires complex state tracking
- Orphan/widow control: No automatic prevention of single-line breaks
- 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);
}
}
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
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");
IronPDF:
Install-Package IronPdf
using IronPdf;
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
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)