.NET PDF generator
With the help of Docotic.Pdf, you can generate PDF documents by composing them from structural elements such as pages, containers, text spans, images, links, headers, footers, tables, lists, and more. These elements are available through the high-level Layout API, provided by the free Layout add-on for Docotic.Pdf. The API also supports reusable custom components.

The Layout API lets you define documents entirely in C# or VB.NET code using a fluent approach. Based on this description, the PDF generator provided by the add-on can produce documents with arbitrarily complex layouts, ranging from simple pages to highly structured PDF reports.
PDF generation basics
To generate PDF documents using the Layout API, you need the free Layout add-on. A license key is also required to use the core library and add-ons. You can use either a free trial key or a purchased key.
Install the add-on
The recommended way is to install the add-on from NuGet.
Install-Package BitMiracle.Docotic.Pdf.Layout
The package manager will automatically handle dependencies.
If you prefer to install the add-on manually, start by downloading the ZIP archive with the Docotic.Pdf binaries. Unpack the archive and add references to the following DLLs:
BitMiracle.Docotic.Pdf.dllBitMiracle.Docotic.Pdf.Layout.dllfrom theLayout add-onsubfolder.
Get a license key
To try the library, request a free time-limited license key by filling out the form on the Docotic.Pdf download page. If you have already purchased a license, use the code provided to you after the purchase.
The Layout add-on is free and does not require an additional license. You can use the Layout API with the Docotic.Pdf license you already have.
Hello, world! with the Layout API
Here is sample code that uses the API to generate a PDF with the classic "Hello, world!" phrase:
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text("Hello, world!");
}));
This code produces a single-page PDF with the text in the top-left corner.
Understanding the code sample
The sample starts by adding a license key. Without a license, the Docotic.Pdf library will not generate anything. The PDF producing code begins on the next line.
The code creates an instance of the document builder by calling the static
PdfDocumentBuilder.Create() method. The call to the Generate method starts the PDF generation
process. This method accepts two parameters: the name of the file to produce and a delegate of type
Action<Document>. The add-on generates hello.pdf as the result of the Generate call.
To know what layout the PDF should have, the document builder calls the delegate with a Document
instance. The code of the delegate composes the document contents. In this sample, the delegate
uses the Pages method to provide the builder with another delegate that defines the layout of the
document pages.
The builder calls the delegate provided to the Pages method with a PageLayout instance. This
instance represents one or more pages in the document. The exact number of pages depends on the
content added to them.
The page delegate calls the Content method to access the layout container for the primary content
of the page(s). A chained call to the container's Text method adds the sample text span to the
page. See the guide on layout containers for a detailed explanation of how they work.
The document builder automatically splits content across pages, creating exactly as many pages as needed to contain all data added to the primary content layout container. In this sample, a single page is sufficient, so the output contains exactly one page.
Common tasks beyond the basic sample
The sample code first creates a PdfDocumentBuilder instance and then calls the Generate method
to produce a PDF. You can configure the builder before it starts generating the PDF.
For example, you can produce an encrypted PDF by providing an encryption handler to the builder. You can also specify metadata for the builder to include in the generated document. For more details on how to customize the builder, refer to the separate article.
The sample code uses only the layout container of the primary content slot, but other content slots
are available as well. Here is the full list of PageLayout methods for accessing content slots:
Background()- returns the background layer, which is covered by other content.Header()- returns the common header for all pages.Content()- returns the main page content slot.Footer()- returns the common footer for all pages.Foreground()- returns the foreground layer, which appears above other content.
Only the content in the main content slot affects the number of pages in the generated PDF. The
document builder repeats all slots other than the one provided by Content() on every page. For
more information about content slots, see the article on page layout.
Many documents use different layouts on different pages. For example, the first page may have a
cover-style design, while subsequent pages use a simpler layout. Some documents include special
pages for tables or apply different backgrounds depending on the section. To generate such
documents with Docotic.Pdf and the Layout add-on, call the Document.Pages method multiple times.
You can find a working example in our samples repository.
Organizing the code
For short code, like in the sample, it is fine to chain calls and use nested lambdas. When you build something larger, it may be more convenient to split the code into separate methods. This makes the code easier to read and maintain.
Here is how the Hello, world! sample looks when its code is split into methods.
public void GeneratePdf()
{
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}
private void BuildDocument(Document doc)
{
doc.Pages(BuildPages);
}
private void BuildPages(PageLayout pages)
{
pages.Content().Text("Hello, world!");
}
Why generate PDFs with the Docotic.Pdf Layout API
The Layout API is a developer-friendly, modern way to generate PDFs from composable building blocks without needing to understand PDF format internals. It lays out PDFs with high performance and with deterministic, predictable behavior. You can use the API in high-volume document-generation scenarios.
The API is available when using Docotic.Pdf together with the free Layout add-on. Both Docotic.Pdf and the Layout add-on are 100% managed code DLLs without unsafe code blocks. The Layout API is implemented without any third-party external dependencies such as a browser or Skia binaries, resulting in a lightweight, low-overhead solution that is easy to deploy and maintain.
API overview
The Layout API is a fluent, pleasant-to-use API. You describe the layout of your document entirely in code using flexible layout elements, and the generator flows your content, paginates it automatically, and renders the result as a PDF.
The Layout add-on uses a declarative, flow-based layout system. Its layout elements include lists, columns, rows, tables, images, text spans, headers and footers, containers, and more. Instead of manually placing elements at exact coordinates, you describe how elements should behave. The document builder then computes the final layout and creates the PDF.
The flow-based layout system ensures that the layout adapts to page size and content. Thanks to this system, the add-on excels at complex, structured, rule-based layouts. You can nest different types of containers and build sophisticated structures without sacrificing readability.
When working with the Layout API, you can chain most calls together. This leads to more compact and expressive code than with traditional APIs. The order of calls in a chain is important. Everything is strongly typed, providing compile-time safety and making the code refactor-friendly. You can also unit-test the code that uses the Layout API.
To make your layout implementation even more concise, you can extend the API with your own methods and build a clean, expressive DSL around it.
For more information on positioning and DSL creation, refer to the article explaining how to control the size, position, alignment, and rendering behavior of containers.
.NET versions and platform support
You can use the Layout API in projects targeting .NET Standard 2.1 and newer frameworks. In other words, the Layout add-on is compatible with .NET 5 through .NET 10. Additionally, .NET Core 3.0+ is supported.
You can generate PDFs with the Layout API in ASP.NET Core, MAUI apps, Unity, Xamarin, and console applications. Docotic.Pdf with the Layout add-on can produce PDFs on Windows, macOS, and Linux.
Cloud platforms and Docker images
Docotic.Pdf with the Layout add-on can run in Azure and AWS cloud environments, including serverless setups. The library and add-on fully support dynamic hardware changes, autoscaling, and other cloud-native runtime features.
In most cloud scenarios, an unbound license is required. The License FAQ explains how to choose the appropriate license for cloud applications.
The Layout API just works in Docker containers. You don't need any special configuration to generate PDFs when running the library and the Layout add-on inside a container.
Adding text to PDF files
Text is a fundamental part of any PDF document. You can use Text methods of the
LayoutContainer class to add text to a content
slot.

Text spans
In the Hello, world sample, I used the LayoutContainer.Text(string) overload to add text to the
page's primary content. Now let's look at another overload of the Text method.
public static void GenerateTextPdf()
{
PdfDocumentBuilder.Create().Generate("text-spans.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text(AddTextSpans);
}));
}
private static void AddTextSpans(TextContainer text)
{
text.Line("About VB.NET")
.Style(t => t.Strong);
text.Span("VB.NET is a multi-paradigm, object-oriented language ");
text.Span("that runs on .NET, Mono, and the ");
text.Hyperlink(
".NET Framework",
new Uri("https://dotnet.microsoft.com/download/dotnet-framework"));
text.Line(".");
text.Span("Released by Microsoft in 2002, ");
text.Line("it continues the lineage of the original Visual Basic language.");
}
This code uses the Span and Line methods of the TextContainer class to add text to the
current line. The Line method additionally completes the current line. The sample code also uses
the Hyperlink method to attach an external resource link to a specific text span.
Note how the sample code applies strong formatting to the first line using the Style method.
Let's explore the concept of text styles in more detail.
Text styles
Text styles allow you to customize the appearance of text. The
TextStyle class provides methods for changing font
size, letter spacing, colors, and other text properties. TextStyle objects are immutable, so each
method call produces a new style instance. You can apply text styles at different layout levels.
PdfDocumentBuilder.Create().Generate("text-styles.pdf", doc =>
{
doc.Pages(pages =>
{
pages.TextStyle(TextStyle.Parent.FontSize(30));
pages.Content()
.TextStyle(TextStyle.Parent.FontColor(new PdfRgbColor(0, 0, 255)))
.Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(TextStyle.Parent.Underline());
});
});
});
The TextStyle.Parent property returns a special style in which all text properties are undefined.
In the sample above, the code draws “Hello, World!” in blue, with the second word underlined, using
a 30-point font size.
This happens because the code:
- sets the font size to 30 points at the page level,
- then sets the text color to blue for the primary content slot,
- then applies the underline style to the last text span.
Each subsequent style inherits the previous ones through the TextStyle.Parent property.
Using the methods of the TextStyle class, you can, among other things, change the text direction
to right-to-left. See another example of using text style inheritance in our
samples repository.
Typography
The TextStyle class supports customizing all text properties except the associated font. To
change the default font, use the Document.TextStyleWithFont methods to create a text style based
on a specific font. You can use a font installed in the operating system or load one from a file or
stream.
After creating a font-based style, you can apply additional optional properties and then use the resulting style on a text span. This C# sample demonstrates how to use a system font.
PdfDocumentBuilder.Create().Generate("text-style-with-font.pdf", doc =>
{
var font = SystemFont.Family("Calibri");
var style = doc.TextStyleWithFont(font).FontSize(30);
doc.Pages(pages =>
{
pages.Content().Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(style);
});
});
});
The TextStyleWithFont method includes an optional parameter that specifies how the font should be
embedded in the generated document. By default, the library:
- embeds used glyphs for TrueType/OpenType fonts,
- embeds all glyphs for Type1 and CFF fonts,
- does not embed glyphs for built-in PDF fonts (Base14 fonts).
Because of these defaults, documents that use TrueType and OpenType fonts may remain small in size even when large fonts are used. You can also specify a custom font loader, fallback fonts, and a handler for missing glyphs. See the sample code in our examples repository for details on managing fonts in PDF documents.
The Layout API provides a collection of predefined styles, which you can access and modify through the Typography class.
PdfDocumentBuilder.Create().Generate("typography.pdf", doc =>
{
doc.Typography(t =>
{
var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
var arialFont = new FileInfo(Path.Combine(fontsPath, "arial.ttf"));
t.Document = doc.TextStyleWithFont(arialFont);
t.Header = t.Parent.FontSize(20).FontColor(new PdfGrayColor(20));
t.Footer = t.Footnote;
});
doc.Pages(pages =>
{
pages.Header().AlignCenter().Text("Header");
pages.Content().Text(t =>
{
t.Line("Title").Style(t => t.Title);
t.Line("Heading 1").Style(t => t.Heading1);
t.Line("Regular");
});
pages.Footer()
.Height(20)
.AlignCenter()
.Text(t => t.CurrentPageNumber());
});
});
I recommend overriding the predefined styles by configuring typography for the entire document, although this is not required and you can still apply text styles at the text-span level.
With the Typography class, you do not need to store text style references in variables. Instead,
you register the required styles using the Document.Typography methods and later access them
through the Typography object's properties. Refer to the Typography sample to see how to use
predefined and custom text styles when generating PDF documents.
Working with headers and footers
Many real-world PDF documents, such as reports or invoices, include headers and footers. This section shows how to add both to a PDF.
public static void GeneratePdfWithHeaderAndFooter()
{
PdfDocumentBuilder.Create()
.Generate("header-footer.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6).Margin(10);
BuildPagesHeader(pages.Header());
BuildPagesFooter(pages.Footer());
pages.Content().Text("Hello, world!");
}));
}
public static void BuildPagesHeader(LayoutContainer header)
{
header.TextStyle(TextStyle.Parent.FontSize(8))
.AlignRight()
.Text(t =>
{
t.Line($"Created by: {Environment.UserName}");
t.Line($"Date: {DateTime.Now}");
});
}
public static void BuildPagesFooter(LayoutContainer footer)
{
footer.AlignRight().Text(text =>
{
text.Style(t => t.Parent.FontColor(new PdfRgbColor(255, 0, 0)));
text.CurrentPageNumber();
text.Span(" / ");
text.PageCount();
});
}
The BuildPagesHeader method sets a smaller font size for the header text. It uses two lines for
the header content: one with the current user's name and another with the current date. The text is
right-aligned.
Notice that the code does not specify any explicit size for the header. It occupies the full page width minus the left and right margins, and its height depends on the height of the text lines.
The BuildPagesFooter method demonstrates how to place the current page number in the PDF footer.
The library calculates the current page number and total page count automatically. You can access
these values using the CurrentPageNumber and PageCount methods of a
TextContainer object.
The Layout API also provides a way to format page numbers. For example, you can draw hexadecimal page numbers like this:
text.CurrentPageNumber().Format(p => "0x" + p?.ToString("x2"));
Our sample repository contains another example of adding a header and footer to a PDF. That example formats page numbers as Roman numerals.
Inserting images
As the saying goes, a single picture can replace many words. In quotes or receipts, you will often include your company's logo or another important image. For this example, I will use a simple, nice-looking one.
To use an image, you must first add it to the document. The library can load images from a file or a stream. Only raster formats are supported: PNG, JPEG, JPEG 2000, BMP, GIF, and TIFF.
Once you have an Image object, you can set it as the content of one or more layout containers
by calling the container's Image method. You can scale, rotate, add padding, and arrange the
image just like any other content.
PdfDocumentBuilder.Create().Generate("image-with-text.pdf", doc =>
{
var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
var image = doc.Image(imageFile);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
The sample code uses both text and an image in the primary content slot. However, a layout container can contain only text or only an image. To include both in the page's primary content slot, you need a compound container.
I use a Column container to place the text and the image vertically, one after the other. The
Item method of the column container provides a sub-container. One call to Item creates a
container for the text, and another creates a container for the image. The compound container with
all its sub-containers becomes the main content.
To run the sample code, download the flower image from our samples repository and place it in your app's working directory.
Online images
If you have only an image URL rather than a file, download the image into a memory stream and
create an Image from that stream. The following example shows how to use online images with the
Layout API.
public static async Task AddImageWithTextFromUrl()
{
using var http = new HttpClient();
using var stream = await http.GetStreamAsync("url/to/image");
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
PdfDocumentBuilder.Create().Generate("online-image-with-text.pdf", doc =>
{
var image = doc.Image(memoryStream);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
}
Because the method performs asynchronous work (downloading an image from a URL), it is declared as
async Task rather than void. Callers must await it to ensure that PDF generation completes
correctly. In your own code, a similar method may also return a value, in which case it would be
declared as async Task<TResult>.
Creating lists
What is a list? You can think of it as a group of numbered items written one below the other. The Layout API does not provide a special container type for lists, but it is easy to implement one using other compound containers.
var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;
PdfDocumentBuilder.Create().Generate("list.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(column =>
{
for (int i = 0; i < dayNames.Length; i++)
{
column.Item().Row(row =>
{
row.Spacing(5);
row.AutoItem().Text($"{i + 1}.");
row.RelativeItem().Text(t =>
{
t.Line(dayNames[i]);
t.Line($"In Spain they call it {dayNamesSpain[i]}");
});
});
}
});
}));
The sample code creates the list as a column of rows. Each row contains two items: the first (on the left) holds the item number, and the second (on the right) holds the item text. The code explicitly sets the spacing between the items in each row.
To arrange items, the Row container must either have the size of each item specified explicitly
or calculate it. In this example, the AutoItem and RelativeItem methods are used. As a result,
the row container calculates the width required for the first item and then uses the remaining
available width for the second item.
By using this approach and adjusting the appearance of the rows as needed, you can create a list that best fits your document's layout and style.
Building tables
Many PDF documents contain tables, which is no surprise because tables improve the clarity and organization of data. This section shows how to create a table in a PDF using the Layout API.
public static void AddTable()
{
PdfDocumentBuilder.Create().Generate("table.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
var color = new PdfGrayColor(75);
pages.Content().Padding(20).Table(t =>
{
t.Columns(c =>
{
c.RelativeColumn(4);
c.RelativeColumn(1);
c.RelativeColumn(4);
});
t.Header(h =>
{
h.Cell().Background(color).Text("Month");
h.Cell().Background(color).Text("Days");
h.Cell().Background(color).Text("First Day");
});
var year = DateTime.Now.Year;
for (int yearDiff = 0; yearDiff < 4; yearDiff++)
{
for (int i = 11; i >= 0; i--)
{
var stats = GetMonthStats(year - yearDiff, i);
t.Cell().Text(stats.Item1);
t.Cell().Text(stats.Item2);
t.Cell().Text(stats.Item3);
}
}
});
}));
}
private static (string, string, string) GetMonthStats(int year, int monthIndex)
{
return (
$"{DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex]} {year}",
DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
);
}
The sample code creates a simple table that displays basic information about the months in the current year and the previous three years. The code defines three columns with relative widths. The leftmost and rightmost columns are four times wider than the middle column.
The code also defines the table header by adding header cells and specifying the text and background color for each cell. When a table does not fit on a single page, the header is repeated on every page the table occupies. You can see this behavior in the PDF generated by the sample code.
Two simple loops are used to build the rows. The outer loop iterates over the years, and the inner loop iterates over the months in reverse order. The inner loop retrieves information about each month and then adds three cells to form a row.
For more details, you can read the article that explains the features of the Table container in depth.
Creating internal PDF links
PDF documents support internal links that allow readers to jump to another location within the same file. In a PDF viewer, these links appear as clickable text or image elements. They function like hyperlinks, but instead of pointing to an external website, they navigate within the document itself.

Many PDF documents use internal links for bookmarks or a table of contents, helping readers move quickly between sections. Here is how you can add a link to a document section using the Layout API:
PdfDocumentBuilder.Create().Generate("link.pdf", doc =>
{
doc.Pages(pages =>
{
pages.Content().Column(c =>
{
const string SectionName = "Chapter 1";
c.Item().SectionLink(SectionName).Text("Link");
c.Item().PageBreak();
c.Item().Section(SectionName).Text("Target");
});
});
});
The sample code makes the text on the first page a link to the section with the specified name. It
does this by calling the SectionLink method on the layout container that contains the text. The
section may or may not exist yet at this point. The text becomes clickable in a PDF viewer.
The code then marks the text on the second page as the start of the section with the same name. Its
appearance and behavior do not change, but it becomes the target for the link on the first page.
This is done by calling the Section method on the corresponding layout container.
In this example, both the link and its target are text spans, but you can create sections and links on any layout container. It may be a container with an image, a table container, or a container you construct yourself.
See an example of how to create a PDF table of contents in our samples repository.
Designing complex PDF layouts
The Layout API provides a variety of layout containers that you can combine to produce arbitrarily complex PDF documents. You can also extend the API with your own custom components.
The examples on this page are intentionally simple, designed to create straightforward documents so you can focus on the core ideas without getting lost in details. If you'd like to see how different containers can be combined to generate a more complex PDF, take a look at the corresponding example in our samples repository on GitHub.
In addition to using built-in containers, you can define and use custom layout components. These components are especially useful when you want a single class to encapsulate both the data and the layout logic. Keeping everything in one place makes the component easier to understand, modify, and reuse, while also giving you a flexible way to handle complex layouts.
To create a custom layout component, implement the ILayoutComponent interface in your class. When
generating a PDF, the library calls the interface's Compose method and provides a LayoutContext
object. Your code can use this object to create layout elements and access information about the
document being generated.
To add a custom layout component to your layout, call the Component method of the
LayoutContainer class. In terms of sizing and positioning, a custom component behaves just like
text or images.
For an example of implementing a custom component with the ILayoutComponent interface, see the
Layout components sample.
Other ways to create PDF
Docotic.Pdf offers multiple ways to create PDFs, each suited to different scenarios. This section explains when to rely on the Layout API and when other approaches may serve you better.
When to prefer the Layout API
The Docotic.Pdf Layout API is a powerful way to generate PDFs from structured layouts. It lets you build documents by composing text, images, containers, and tables into arbitrarily complex, nested structures. The generation process is fast, uses a reasonable amount of memory, and behaves predictably.
Docotic.Pdf and the Layout add-on form a lightweight, fully self-contained set. The API does not require external libraries or browsers to generate PDFs. This makes it a solid choice for .NET microservices, cloud applications (especially serverless ones), and other environments where footprint size matters.
Because the document layout is defined in code, you can unit test any part of it. Layout logic can be reused like any other code, and you can encapsulate both data and layout behavior in custom components.
Alternatives to the Layout API
A dedicated article provides a detailed comparison of all the ways to create PDFs with Docotic.Pdf. Below are some of the most commonly used alternatives.
-
HTML to PDF conversion
Reuses existing HTML/CSS templates. Choose the HTML-to-PDF approach when your team already produces documents in HTML/CSS and you need PDF versions of those documents. -
Low-level PDF generation
Provides the maximum control available in the library over PDF structure and content. Choose this when you need pixel-level positioning or complex vector graphics. This approach is recommended for performance-critical scenarios or when the smallest possible footprint is required. -
Template-based PDF generation
Offers a fast, predictable way to fill documents without designing or arranging their elements. Choose this when you have a predefined PDF structure, such as approved or compliance-controlled templates, and only need to change text fields, replace placeholders, attach related documents, and perform similar tasks. -
PDF merging and composition
Lets you create a PDF from existing pieces instead of building it from scratch. Choose this when you have images, scanned pages, or other PDFs that need to be combined into a single file.
Comparison with other PDF generation solutions
This section contains two comparison tables: one with key takeaways and another with detailed, structured information about how Docotic.Pdf with the Layout add-on compares to other popular solutions for generating PDFs.
Key comparison takeaways
There are strong options for generating PDFs, including free ones. However, capabilities like signing, encrypting, or merging documents vary, which can limit which tools truly fit your needs.
| Solution | When to Use | Best For |
|---|---|---|
| Docotic.Pdf with the Layout add-on | When you want a high-quality, high-performance layout engine capable of producing optimized PDFs, with advanced support for signatures, encryption, and PDF editing across platforms | High-quality generation of invoices, reports, statements, and similar documents, with an excellent developer experience. Ideal when you need enterprise-grade PDF processing and professional support |
| PDFsharp + MigraDoc | When you want a free, MIT-licensed library for basic PDF generation and do not require digital signatures or modern encryption algorithms | Simple document creation in open-source or budget-constrained projects |
| QuestPDF | When you want a modern layout engine dedicated solely to PDF generation and do not need editing, signatures, or encryption | High-quality PDF generation with an MIT or low-cost commercial license, provided that all non-generation features are handled elsewhere |
| iText | When you need a mature, feature-rich PDF toolkit for both generating and processing PDFs, and you are prepared to either open-source your solution under the AGPL/GPLv3 license or purchase an expensive commercial license | Teams already familiar with the iText API and therefore unaffected by its steep learning curve |
Detailed comparison
Review the table to understand the broader context and form your own conclusions.
| Docotic.Pdf with Layout | PDFsharp + MigraDoc | QuestPDF | iText | |
|---|---|---|---|---|
| PDF capabilities | Full-featured PDF library | PDF generation and limited editing | PDF generation only | Extensive PDF functionality |
| Rendering Model | Modern, declarative, retained-mode layout engine | Box-based layout engine | Modern, declarative, retained-mode layout engine | Box-based layout engine + renderer tree |
| API kind | Fluent API | Imperative API | Fluent API | Imperative API |
| Developer Experience | Excellent. API is clean, modern, and intuitive | Good. API design is conventional | Excellent. API is clean, modern, and intuitive | Satisfactory. API is verbose and overly complex |
| Font Subsetting | Supported; only used glyphs are embedded by default | Not supported; may result in unnecessarily large PDFs | Supported; only used glyphs are embedded by default | Supported; only used glyphs are embedded by default |
| Right-to-left (RTL) content direction | Supported | Not supported | Supported | Supported |
| Digital signatures | Supported, including LTV and external signatures | Not supported | Not supported | Supported, including LTV and external signatures |
| Encryption / permissions | Fully supported | RC4 encryption only, no support for AES or certificates | Not supported | Fully supported |
| External dependecies | None | None | SkiaSharp / Skia-based components | None |
| Support | Professional support for prospects and customers; priority support with top-tier licenses | Community support; professional support can be purchased separately | Community support via GitHub | Community support for AGPL version; professional support for commercial license holders |
| License | Commercial, with free licenses for eligible use cases | MIT | MIT for individuals and small companies; commercial license required for larger businesses | AGPL for open-source use, expensive commercial license for proprietary projects |
| Developer licensing | Unlimited developers with all licenses | Unlimited developers with all licenses | Unlimited developers with MIT; 10 developers with Professional; unlimited developers with Enterprise | Unlimited developers with AGPL version; per-developer licensing with commercial license |
Conclusion
Docotic.Pdf with the Layout add-on provides a modern, high-performance, high-quality way to generate PDFs in C# and VB.NET. The library produces reports, statements, invoices, and similar documents. Its well-designed, fluent API offers an excellent developer experience. You can rely on the professional support that Bit Miracle provides for Docotic.Pdf and its add-ons.
Unlike some other PDF generation solutions, Docotic.Pdf is a full-featured PDF API. The library can sign generated PDFs with digital signatures, including LTV-enabled signatures. Docotic.Pdf is capable of using certificates stored on secure hardware such as USB tokens and smart cards. Cloud-based Hardware Security Modules (HSMs), such as Microsoft Azure Key Vault and AWS Key Management Service (KMS), are also supported.
With Docotic.Pdf, you can attach supporting documents such as spreadsheets or voice notes to the generated PDFs. To display documents on a web page or in a similar interface, you can create thumbnail images from one or more of their pages.
Next steps:
- Explore the code samples for the Layout API.
- Compare PDF generation from composable building blocks with other approaches to creating PDFs.
- Contact us with questions, feedback, or edge cases.