A portable .NET library for converting Markdown, HTML, and plain text to PDF using embedded wkhtmltopdf. Windows-only, no external dependencies required.
$ dotnet add package MarkdownToPdf.NETA comprehensive .NET library for generating PDF files from Markdown and plain text with customizable styling and metadata support.
Inline code and code blocksBlockquotes with styling
Install the package via NuGet Package Manager:
dotnet add package MarkdownToPdf.NET
Or via Package Manager Console:
Install-Package MarkdownToPdf.NET
✅ No additional setup required! The package includes all necessary native dependencies for Windows, Linux, and macOS.
Note: While the package name is
MarkdownToPdf.NET, the namespace remains for consistency and ease of use.
PdfTools.*The library automatically handles the following dependencies:
<PackageReference Include="MarkdownToPdf.NET" Version="1.0.1" />
<PackageReference Include="Markdig" Version="0.33.0" />
<PackageReference Include="DinkToPdf" Version="1.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />This package includes embedded native libraries for cross-platform support:
libwkhtmltox.dlllibwkhtmltox.so (when available)libwkhtmltox.dylib (when available)No separate installation of wkhtmltopdf is required!
using PdfTools.Services;
using PdfTools.Models;
// Create generator instance
var generator = new PdfGenerator();
// Generate PDF from markdown
string markdown = @"
# My Document
This is a **sample** document with *formatting*.
## Features
- Beautiful styling
- Easy to use
- Professional output
";
generator.GenerateFromMarkdown(markdown, "output.pdf");
// Generate PDF from plain text
string text = "This is plain text that will be converted to a nicely formatted PDF.";
generator.GenerateFromText(text, "text-output.pdf");var options = new PdfOptions
{
Title = "My Custom Document",
Author = "John Doe",
Subject = "Sample PDF Generation",
PageSize = "A4",
Orientation = "Portrait",
Margins = new PdfMargins
{
Top = 25,
Bottom = 25,
Left = 20,
Right = 20
},
CustomCss = @"
body { font-family: 'Times New Roman'; }
h1 { color: #ff6b6b; }
"
};
generator.GenerateFromMarkdown(markdown, "custom-output.pdf", options);// Method 1: Using enhanced CSS with modern typography and better visual design
generator.GenerateFromMarkdownWithEnhancedStyling(markdown, "enhanced-output.pdf", "My Enhanced Document");
// Method 2: Create enhanced options using factory wrapper
var enhancedOptions = PdfOptionsFactory.CreateDefaultWithEnhancements("Professional Report");
generator.GenerateFromMarkdown(markdown, "professional-output.pdf", enhancedOptions);
// Method 3: Create enhanced options directly from provider
var directOptions = EnhancedCssProvider.CreateDefaultOptionsWithEnhancements();
directOptions.Title = "My Custom Title";
generator.GenerateFromMarkdown(markdown, "direct-output.pdf", directOptions);
// Method 4: Create enhanced options with custom CSS
var customOptions = PdfOptionsFactory.CreateEnhanced("Custom Report", @"
.custom-highlight {
background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
padding: 1rem;
border-radius: 8px;
}
");
generator.GenerateFromMarkdown(markdown, "custom-output.pdf", customOptions);// Create options optimized for professional documents
var professionalOptions = PdfOptionsFactory.CreateProfessional(
title: "Annual Report 2024",
author: "Company Name",
subject: "Financial Analysis"
);
generator.GenerateFromMarkdown(markdown, "annual-report.pdf", professionalOptions);
// For technical documentation
var technicalOptions = PdfOptionsFactory.CreateTechnical("API Documentation");
generator.GenerateFromMarkdown(markdown, "api-docs.pdf", technicalOptions);// Get PDF as byte array (useful for web applications)
byte[] pdfBytes = generator.GenerateFromMarkdownToBytes(markdown, options);
// In ASP.NET Controller
return File(pdfBytes, "application/pdf", "document.pdf");using PdfTools.Extensions;
// In Program.cs or Startup.cs
builder.Services.AddPdfTools();
// Or with custom converter
builder.Services.AddPdfTools(provider =>
{
// Custom converter configuration
return new SynchronizedConverter(new PdfTools());
});[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly IPdfGenerator _pdfGenerator;
public PdfController(IPdfGenerator pdfGenerator)
{
_pdfGenerator = pdfGenerator;
}
[HttpPost("from-markdown")]
public IActionResult GenerateFromMarkdown([FromBody] MarkdownRequest request)
{
try
{
var options = new PdfOptions
{
Title = request.Title,
Author = request.Author
};
var pdfBytes = _pdfGenerator.GenerateFromMarkdownToBytes(
request.Markdown, options);
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (Exception ex)
{
return BadRequest($"PDF generation failed: {ex.Message}");
}
}
}// Generate PDF from markdown to file
void GenerateFromMarkdown(string markdown, string outputPath, PdfOptions? options = null);
// Generate PDF from text to file
void GenerateFromText(string text, string outputPath, PdfOptions? options = null);
// Generate PDF from HTML to file
void GenerateFromHtml(string html, string outputPath, PdfOptions? options = null);
// Generate PDF from markdown to byte array
byte[] GenerateFromMarkdownToBytes(string markdown, PdfOptions? options = null);
// Generate PDF from text to byte array
byte[] GenerateFromTextToBytes(string text, PdfOptions? options = null);public class PdfOptions
{
public string? Title { get; set; } // PDF metadata title
public string? Author { get; set; } // PDF metadata author
public string? Subject { get; set; } // PDF metadata subject
public string Orientation { get; set; } // "Portrait" or "Landscape"
public string PageSize { get; set; } // "A4", "Letter", "Legal", etc.
public string? CustomCss { get; set; } // Custom CSS overrides
public PdfMargins Margins { get; set; } // Page margins
}
public class PdfMargins
{
public int Top { get; set; } // Top margin in mm
public int Bottom { get; set; } // Bottom margin in mm
public int Left { get; set; } // Left margin in mm
public int Right { get; set; } // Right margin in mm
}The library provides specific exception types for different error scenarios:
try
{
generator.GenerateFromMarkdown(markdown, outputPath);
}
catch (InvalidInputException ex)
{
// Handle invalid input (null/empty content, invalid paths)
Console.WriteLine($"Invalid input: {ex.Message}");
}
catch (PdfGenerationException ex)
{
// Handle PDF generation errors
Console.WriteLine($"PDF generation failed: {ex.Message}");
}
catch (FileOperationException ex)
{
// Handle file I/O errors
Console.WriteLine($"File operation failed: {ex.Message}");
}The library includes beautiful default CSS styling that provides:
The library now includes enhanced CSS options with advanced typography and modern design:
// Use enhanced CSS for better visual appearance
var enhancedOptions = PdfOptionsFactory.CreateEnhanced("Document Title");
// Enhanced CSS includes:
// - CSS Variables for consistent theming
// - Google Fonts integration (Inter, JetBrains Mono)
// - Advanced typography with font features
// - Professional gradients and shadows
// - Responsive image containers
// - Smart page break controls
// - Enhanced status indicators and alertsDefault CSS: Clean, professional styling
var options = PdfOptionsFactory.CreateDefault("Document Title");Enhanced CSS: Modern typography with advanced features
// Method 1: Factory wrapper (recommended)
var options = PdfOptionsFactory.CreateDefaultWithEnhancements("Enhanced Document");
// Method 2: Direct provider access
var options = EnhancedCssProvider.CreateDefaultOptionsWithEnhancements();
// Method 3: Convenience method
generator.GenerateFromMarkdownWithEnhancedStyling(markdown, "output.pdf", "Title");
// Method 4: Enhanced with custom CSS
var options = PdfOptionsFactory.CreateEnhanced("Document", "custom css here");Professional CSS: Optimized for business documents
var options = PdfOptionsFactory.CreateProfessional("Annual Report", "Author", "Subject");Technical CSS: Specialized for technical documentation
var options = PdfOptionsFactory.CreateTechnical("API Documentation");The enhanced CSS includes utility classes for better content styling:
<!-- Status indicators -->
<div class="alert alert-info">Information message</div>
<div class="alert alert-warning">Warning message</div>
<div class="alert alert-success">Success message</div>
<div class="alert alert-danger">Error message</div>
<!-- Highlighted content -->
<div class="highlight">Important highlighted content</div>
<!-- Cards and containers -->
<div class="card">Card content with shadow and border</div>
<!-- Grid layouts -->
<div class="grid">
<div class="metric-card">Metric 1</div>
<div class="metric-card">Metric 2</div>
</div>
<!-- Page breaks -->
<div class="page-break-before">Content starts on new page</div>
<div class="no-break">Keep this content together</div>You can override any styles using the CustomCss property in PdfOptions.
This section provides step-by-step instructions for building, testing, and deploying the MarkdownToPdf.NET package.
git clone https://github.com/eochieng_microsoft/PdfTools.git
cd PdfToolsdotnet clean PdfTools.slndotnet restore PdfTools/PdfTools.csproj# Debug build
dotnet build PdfTools/PdfTools.csproj
# Release build (recommended for packaging)
dotnet build PdfTools/PdfTools.csproj --configuration Release# Creates package in bin/Release directory
dotnet pack PdfTools/PdfTools.csproj --configuration Release# List generated packages
ls PdfTools/bin/Release/*.nupkg
# Expected output: MarkdownToPdf.NET.{version}.nupkg# Replace YOUR_API_KEY with your actual API key
dotnet nuget push "PdfTools/bin/Release/MarkdownToPdf.NET.{version}.nupkg" \
--api-key YOUR_API_KEY \
--source https://api.nuget.org/v3/index.json# Example: 1.2.1 → 1.2.2
# Update version in PdfTools.csproj
# Test, build, and deploy# Example: 1.2.1 → 1.3.0
# Update version in PdfTools.csproj
# Update README with new features
# Test extensively, build, and deploy# Example: 1.2.1 → 2.0.0
# Update version in PdfTools.csproj
# Update documentation
# Consider migration guide
# Test thoroughly, build, and deployThis library uses the following open-source packages:
Make sure to comply with their respective licenses in your applications.