---
title: "Migrating from iText 7 and iTextSharp to OnePDF"
url: https://recursiveai.org/onepdf/articles/migrate-from-itext/
description: "Move C# code from iText 7, 8 or 9 (and iTextSharp) to OnePDF: the API map, side-by-side samples run on both libraries, and what has no equivalent."
date: 2026-10-26
author: OnePDF team
---

# Migrating from iText 7 and iTextSharp to OnePDF

Move C# code from iText 7, 8 or 9 (and iTextSharp) to OnePDF: the API map, side-by-side samples run on both libraries, and what has no equivalent.

October 26, 2026 · OnePDF team

Moving from iText to OnePDF is mostly a change of entry points: `PdfDocument.Open` replaces `PdfReader` and `PdfWriter`, OnePdf.Layout replaces `Document` and its elements, and one-call methods such as `Merge`, `Flatten`, `Sign`, `Redact` and `AddTextStamp` replace helper classes and canvas code. The usual reason to move is the license. iText Core is AGPL-3.0 or commercial, and OnePDF is MIT OR Apache-2.0. This guide maps the iText 7 to 9 API to OnePDF, runs five common jobs on both libraries side by side, and lists what OnePDF doesn’t do, so you can tell early whether your code can move. The iText code is written from iText’s own tutorial, knowledge base and API reference. Every sample was compiled and run, iText 9.8.0 and OnePDF 1.11.0, on .NET 10, against the same input files.

## Check these first

- **.NET version.** OnePDF targets .NET 10 only. iText 9.8.0 targets .NET Framework 4.6.1 and .NET Standard 2.0 ([NuGet](https://www.nuget.org/packages/itext/9.8.0)). Code that must stay on .NET Framework can’t move.
- **HTML to PDF.** OnePDF has no HTML engine, so there is nothing to replace pdfHTML with. Generate documents with OnePdf.Layout instead, or keep an HTML renderer for that part.
- **OCR, XFA forms, PAdES B-LT and B-LTA.** No equivalent of pdfOCR or pdfXFA, and signatures stop at PAdES B-T. Details are [below](#gaps).
- **Page numbers start at 0.** iText numbers pages from 1 (`GetPage(1)` is the first page). OnePDF indexes from 0 (`Pages[0]`). This is the most common bug in a port.

## The API map

| iText 7, 8 or 9 | OnePDF 1.11.0 |
|---|---|
| `new PdfDocument(new PdfReader(src))` | `PdfDocument.Open(path \| stream \| bytes)` |
| `new PdfDocument(new PdfReader(src), new PdfWriter(dest))` (stamping mode) | `PdfDocument.Open(src, new PdfOpenOptions { AllowEditing = true })`, then `doc.Save(dest)` |
| `new PdfDocument(new PdfWriter(dest))` + `Document`, `Paragraph`, `Table`, `Cell` | `LayoutDocument.Compose(...)` with `Text`, `Table`, `HeaderRow`, `Row` (OnePdf.Layout) |
| `pdf.Close()` writes the file | `doc.Save(...)` writes it, `Dispose` releases it |
| `pdf.GetNumberOfPages()`, `pdf.GetPage(i)` (from 1) | `doc.PageCount`, `doc.Pages[i]` (from 0) |
| `PdfCanvas` on a page | `page.BeginContent()` → `PdfPageContentBuilder`, then `Commit()` |
| Watermark with `PdfCanvas`, `PdfExtGState` and `ShowTextAligned` | `doc.AddTextStamp`, `doc.AddImageStamp` |
| `PdfTextExtractor.GetTextFromPage` | `page.ExtractText()` (reading order, words and lines with positions) |
| `PdfMerger`, `CopyPagesTo` + `PdfPageFormCopier` | `PdfDocument.Merge`, `doc.ImportPages` |
| `PdfSplitter` | `PdfDocument.Split` |
| `PdfFormCreator.GetAcroForm` / `PdfAcroForm.GetAcroForm`, `GetField(name).SetValue(v)` | `doc.Form`, `form.SetValue(name, v)` |
| `form.FlattenFields()` | `doc.Flatten()` |
| `PdfSigner`, `PdfPadesSigner` + a BouncyCastle adapter package | `doc.Sign(...)` with an `X509Certificate2` or an external signer |
| Signature validation | `doc.VerifySignatures(...)` |
| `PdfADocument` | `PdfSaveOptions.PdfA` on save |
| `PdfUADocument` | `PdfSaveOptions.PdfUA` on save, tagged layout by default |
| `WriterProperties.SetStandardEncryption` | `PdfSaveOptions.Encryption` |
| pdfSweep add-on (redaction) | `doc.Redact(...)` in the core package |
| pdfCalligraph add-on (complex scripts) | OnePdf.Layout shapes Arabic, Indic and other scripts |
| pdfHTML, pdfOCR, pdfXFA add-ons | No equivalent |

## Before you start

*Terminal · NuGet*

```
dotnet remove package itext
dotnet add package RecursiveAI.OnePdf --version 1.11.0
dotnet add package RecursiveAI.OnePdf.Layout --version 1.11.0
```

Add `RecursiveAI.OnePdf.Layout` only if you generate documents. Remove the `itext.bouncy-castle-adapter` package too if you signed with iText: OnePDF uses .NET’s own cryptography. The inputs below are a six-page report, the OPM [SF 2823](https://www.opm.gov/forms/pdf_fill/sf2823.pdf) form and a one-page contract.

## Create a document with a table

iText builds a document by adding elements to a `Document`, as in its [Jump-Start tutorial, chapter 1](https://kb.itextpdf.com/itext/itext-7-jump-start-tutorial-chapter-1):

*Program.cs · iText 9.8.0*

```
using iText.IO.Font.Constants;
using iText.Kernel.Font;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
 
using PdfDocument pdf = new PdfDocument(new PdfWriter("summary-itext.pdf"));
using Document document = new Document(pdf, PageSize.LETTER);
document.SetMargins(54, 54, 54, 54);
 
PdfFont bold = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
document.Add(new Paragraph("Harbor trial summary").SetFont(bold).SetFontSize(20));
document.Add(new Paragraph("Six crews fished the harbor for six weeks."));
 
Table table = new Table(UnitValue.CreatePercentArray(new float[] { 3, 1 })).UseAllAvailableWidth();
table.AddHeaderCell(new Cell().Add(new Paragraph("Quay").SetFont(bold)));
table.AddHeaderCell(new Cell().Add(new Paragraph("Catch (kg)").SetFont(bold)));
table.AddCell(new Cell().Add(new Paragraph("North")));
table.AddCell(new Cell().Add(new Paragraph("1,240")));
table.AddCell(new Cell().Add(new Paragraph("South")));
table.AddCell(new Cell().Add(new Paragraph("980")));
document.Add(table);
```

OnePdf.Layout describes the same page with nested delegates:

*Program.cs · OnePdf.Layout 1.11.0*

```
using OnePdf.Layout;
 
LayoutDocument.Compose(doc =>
{
    doc.Title("Harbor trial summary").Language("en-US");
    doc.Page(page =>
    {
        page.Size(PageSize.Letter);
        page.Margin(54);
        page.Content().Column(col =>
        {
            col.Spacing(8);
            col.Item().Heading(1).Text("Harbor trial summary").FontSize(20).Bold();
            col.Item().Text("Six crews fished the harbor for six weeks.");
            col.Item().Table(table =>
            {
                table.Columns(c => { c.Relative(3); c.Relative(1); });
                table.CellPadding(4);
                table.CellBorder(0.5, Colors.Black);
                table.HeaderRow(r => { r.Cell().Text("Quay").Bold(); r.Cell().Text("Catch (kg)").Bold(); });
                table.Row(r => { r.Cell().Text("North"); r.Cell().Text("1,240"); });
                table.Row(r => { r.Cell().Text("South"); r.Cell().Text("980"); });
            });
        });
    });
}).Save("summary-onepdf.pdf");
```

Both files show the heading, the sentence and the two-row table. The differences come with the defaults. OnePdf.Layout tags the document for accessibility (the heading is an `H1`, the header row `TH` cells) and embeds a subset of Liberation Sans, so text is the same on every machine. Header rows repeat on every page when a table breaks across pages, and the footer can count pages (“Page 3 of 7”). More in [create a PDF in C#](https://recursiveai.org/onepdf/articles/create-pdf-csharp/).

## Stamp a watermark on every page

In iText, an existing PDF is edited in stamping mode, a `PdfReader` and a `PdfWriter` on one document, and drawn on with a `PdfCanvas`. This is the watermark part of the tutorial’s [chapter 5](https://kb.itextpdf.com/itext/itext-7-jump-start-tutorial-chapter-5) “add content” example:

*Program.cs · iText 9.8.0*

```
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Extgstate;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
 
// Stamping mode: a reader and a writer on one PdfDocument.
using PdfDocument pdf = new PdfDocument(new PdfReader("report.pdf"), new PdfWriter("report-stamped-itext.pdf"));
using Document document = new Document(pdf);
for (int i = 1; i <= pdf.GetNumberOfPages(); i++)              // pages are numbered from 1
{
    PdfPage page = pdf.GetPage(i);
    Rectangle size = page.GetPageSize();
    PdfCanvas canvas = new PdfCanvas(page);
    canvas.SaveState();
    canvas.SetExtGState(new PdfExtGState().SetFillOpacity(0.2f));
    document.ShowTextAligned(new Paragraph("CONFIDENTIAL").SetFontSize(60),
        size.GetWidth() / 2, size.GetHeight() / 2, i, TextAlignment.CENTER, VerticalAlignment.MIDDLE, (float)(Math.PI / 4));
    canvas.RestoreState();
}
```

OnePDF opens the file for editing and has a stamp helper that draws once into a shared form, places it on every page and compensates for rotated pages:

*Program.cs · OnePDF 1.11.0*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("report.pdf", new PdfOpenOptions { AllowEditing = true });
doc.AddTextStamp("CONFIDENTIAL", doc.AddStandardFont("Helvetica"), 60,
    new PdfStampOptions { Opacity = 0.2, RotationDegrees = 45 });   // every page, centered
doc.Save("report-stamped-onepdf.pdf");
```

Both put a faint diagonal “CONFIDENTIAL” across each of the six pages. For anything other than a stamp, `page.BeginContent()` gives a builder with text, images, paths, colors and transparency, like `PdfCanvas`, and leaves the page’s own content untouched ([add an image or watermark](https://recursiveai.org/onepdf/articles/add-image-to-pdf-csharp/)).

## Extract text

iText extracts text through [`PdfTextExtractor`](https://api.itextpdf.com/iText/dotnet/9.8.0/classi_text_1_1_kernel_1_1_pdf_1_1_canvas_1_1_parser_1_1_pdf_text_extractor.html) with a strategy. Here both libraries read the two-column part of the report’s first page, and print three lines:

*Program.cs · iText 9.8.0*

```
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;
using iText.Kernel.Pdf.Canvas.Parser.Listener;
 
using PdfDocument pdf = new PdfDocument(new PdfReader("report.pdf"));
string text = PdfTextExtractor.GetTextFromPage(pdf.GetPage(1), new LocationTextExtractionStrategy());
foreach (string line in text.Split('\n').Skip(8).Take(3))
    Console.WriteLine(line);
```

*Output · Console*

```
Left column: crews on the north quay. Left column: Right column: crews on the south quay. Right column:
crews on the north quay. Left column: crews on the crews on the south quay. Right column: crews on the
north quay. Left column: crews on the north quay. Left south quay. Right column: crews on the south quay.
```

*Program.cs · OnePDF 1.11.0*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("report.pdf");
string text = doc.Pages[0].ExtractText().Text;                    // pages are numbered from 0
foreach (string line in text.Split('\n').Skip(11).Take(3))
    Console.WriteLine(line);
```

*Output · Console*

```
Left column: crews on the north quay. Left column:
crews on the north quay. Left column: crews on the
north quay. Left column: crews on the north quay. Left
```

`LocationTextExtractionStrategy` joins text at the same height into one line, so the two columns come out interleaved. OnePDF returns the left column, then the right, in reading order. It also gives every word and line with its position, a layout mode like `pdftotext -layout`, and right-to-left text in logical order. See [extract text from a PDF in C#](https://recursiveai.org/onepdf/articles/extract-text-from-pdf-csharp/).

## Fill and flatten a form

iText fills through the AcroForm object ([chapter 5](https://kb.itextpdf.com/itext/itext-7-jump-start-tutorial-chapter-5), [`PdfFormCreator`](https://api.itextpdf.com/iText/dotnet/9.8.0/classi_text_1_1_forms_1_1_fields_1_1_pdf_form_creator.html)) and flattens with `FlattenFields`:

*Program.cs · iText 9.8.0*

```
using iText.Forms;
using iText.Forms.Fields;
using iText.Kernel.Pdf;
 
using (PdfDocument pdf = new PdfDocument(new PdfReader("sf2823.pdf"), new PdfWriter("sf2823-flat-itext.pdf")))
{
    PdfAcroForm form = PdfFormCreator.GetAcroForm(pdf, true);
    form.GetField("Name").SetValue("Lovelace, Ada");
    form.GetField("DOB").SetValue("12/10/1985");
    form.GetField("Type of Insured").SetValue("Employee");
    form.FlattenFields();
}
 
using PdfDocument flat = new PdfDocument(new PdfReader("sf2823-flat-itext.pdf"));
Console.WriteLine($"form fields left: {PdfFormCreator.GetAcroForm(flat, false)?.GetAllFormFields().Count ?? 0}");
```

*Output · Console*

```
form fields left: 0
```

*Program.cs · OnePDF 1.11.0*

```
using OnePdf;
 
using (PdfDocument doc = PdfDocument.Open("sf2823.pdf", new PdfOpenOptions { AllowEditing = true }))
{
    PdfAcroForm form = doc.Form!;
    form.SetValue("Name", "Lovelace, Ada");
    form.SetValue("DOB", "12/10/1985");
    form.SetValue("Type of Insured", "Employee");
    doc.Flatten();
    doc.Save("sf2823-flat-onepdf.pdf");
}
 
using PdfDocument flat = PdfDocument.Open("sf2823-flat-onepdf.pdf");
Console.WriteLine($"form fields left: {flat.Form?.TerminalFields.Count() ?? 0}");
```

*Output · Console*

```
form fields left: 0
```

In both files, page 1 shows the name and date as plain page content (`pdftotext` finds both) and no fields are left. OnePDF’s `SetValue` checks the value against the field: an option that isn’t in a choice list or a check box state the box doesn’t have throws, naming the field. It generates the appearance of each field it fills, so the value shows in every viewer. See [fill PDF form fields](https://recursiveai.org/onepdf/articles/fill-pdf-form-csharp/) and [flatten a PDF form](https://recursiveai.org/onepdf/articles/flatten-pdf-csharp/).

## Sign a PDF (PAdES)

iText 9 signs PAdES baseline signatures with `PdfPadesSigner`. Keys and certificates go through iText’s BouncyCastle wrapper types, so one of its two adapter packages must be installed ([Bouncy Castle changes](https://kb.itextpdf.com/itext/bouncy-castle-changes)). This sample follows iText’s [PAdES high-level API](https://kb.itextpdf.com/itext/pades-signing-high-level-api) article, including its way of reading a PEM file. In 9.8.0, `DigestAlgorithms` is in `iText.Kernel.Crypto` ([API reference](https://api.itextpdf.com/iText/dotnet/9.8.0/classi_text_1_1_kernel_1_1_crypto_1_1_digest_algorithms.html)):

*Program.cs · iText 9.8.0 · itext.bouncy-castle-adapter 9.8.0*

```
using iText.Bouncycastleconnector;
using iText.Commons.Bouncycastle;
using iText.Commons.Bouncycastle.Cert;
using iText.Commons.Bouncycastle.Crypto;
using iText.Commons.Bouncycastle.Openssl;
using iText.Kernel.Crypto;
using iText.Kernel.Pdf;
using iText.Signatures;
 
// signer.pem: the signer's certificate and its encrypted private key.
IBouncyCastleFactory factory = BouncyCastleFactoryCreator.GetFactory();
var chain = new List<IX509Certificate>();
IPrivateKey? key = null;
using (TextReader file = new StreamReader("signer.pem"))
{
    IPemReader parser = factory.CreatePEMParser(file, "test".ToCharArray());
    for (object item = parser.ReadObject(); item != null; item = parser.ReadObject())
    {
        if (item is IX509Certificate certificate) chain.Add(certificate);
        if (item is IPrivateKey privateKey) key = privateKey;
    }
}
 
var signer = new PdfPadesSigner(new PdfReader("contract.pdf"), new FileStream("contract-signed-itext.pdf", FileMode.Create));
SignerProperties properties = new SignerProperties().SetFieldName("Approval").SetReason("I approve this contract");
signer.SignWithBaselineBProfile(properties, chain.ToArray(), new PrivateKeySignature(key!, DigestAlgorithms.SHA256));
Console.WriteLine("signed contract-signed-itext.pdf");
```

*Output · Console*

```
signed contract-signed-itext.pdf
```

OnePDF takes the `X509Certificate2` that .NET loads from a `.pfx`:

*Program.cs · OnePDF 1.11.0*

```
using System.Security.Cryptography.X509Certificates;
using OnePdf;
 
using X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile("signer.pfx", "test");
using PdfDocument doc = PdfDocument.Open("contract.pdf", new PdfOpenOptions { AllowEditing = true });
doc.Sign("contract-signed-onepdf.pdf", PdfSigningCredential.FromCertificate(certificate),
    new PdfSigningOptions { FieldName = "Approval", Reason = "I approve this contract" });   // PAdES B-B by default
Console.WriteLine("signed contract-signed-onepdf.pdf");
```

*Output · Console*

```
signed contract-signed-onepdf.pdf
```

`pdfsig` reports both files the same way: `ETSI.CAdES.detached`, “Total document signed”, “Signature is Valid.” For a key in an HSM or a cloud key service, pass a signing function to `PdfSigningCredential.FromExternalSigner`. That covers what iText’s `IExternalSignature` does. Time-stamps (B-T), visible and certification signatures, and verification are in [sign a PDF in C#](https://recursiveai.org/onepdf/articles/sign-pdf-csharp/).

## Merge, split, PDF/A and PDF/UA

- **Merge.** A plain `PdfMerger.Merge` loop drops form fields, as iText’s knowledge base notes. `PdfDocument.Merge` keeps fields, bookmarks and links in one call. Both versions side by side: [merge PDF files in C#](https://recursiveai.org/onepdf/articles/merge-pdf-csharp/).
- **Split.** `PdfDocument.Split(doc, pagesPerPart)` or with page ranges ([split a PDF in C#](https://recursiveai.org/onepdf/articles/split-pdf-csharp/)).
- **PDF/A.** iText uses a `PdfADocument` subclass from the start. OnePDF makes it a save option, which writes the output intent and XMP itself and refuses with the violations listed ([create PDF/A in C#](https://recursiveai.org/onepdf/articles/create-pdf-a-csharp/)).
- **PDF/UA.** Likewise a save option, PDF/UA-1 or PDF/UA-2, with layout documents tagged by default ([PDF/UA in C#](https://recursiveai.org/onepdf/articles/pdf-ua-csharp/)).

## What has no equivalent in OnePDF

- **HTML to PDF** (pdfHTML). There is no HTML or CSS engine.
- **OCR** (pdfOCR). Text is read only where the PDF has a text layer.
- **XFA forms** (pdfXFA). OnePDF fills and flattens AcroForm fields. In a hybrid form it works on the AcroForm side and drops the XFA description when it merges or fully flattens the form, and an XFA-only form can’t be filled.
- **PAdES B-LT and B-LTA**, that is long-term validation data (`/DSS`). OnePDF writes B-B and B-T and document time-stamps.
- **Public-key (certificate) encryption.** Password encryption is supported: OnePDF writes AES-128 and AES-256, and reads the older RC4 handlers too.
- **Rendering to images** (iText’s pdfRender add-on). OnePDF doesn’t rasterize pages. For page images in .NET, see [PDF to image in C#](https://oneimage.dev/articles/pdf-to-image-csharp/) on oneimage.dev.
- **.NET Framework and .NET Standard** targets, as above.

## iTextSharp 5

iTextSharp is iText 5 for .NET, with a different API from iText 7 onward. iText describes its status and license on its [iTextSharp page](https://itextpdf.com/products/itextsharp), and our [iText license](https://recursiveai.org/onepdf/articles/itext-license/) article covers the versions. Porting from iTextSharp works by task rather than by class name: find the job in the map above (open, stamp, fill, merge, sign, extract) and use the OnePDF call for it.

## Where next

- [iText license cost, AGPL terms and permissive alternatives](https://recursiveai.org/onepdf/articles/itext-license/).
- [Getting started with OnePDF](https://recursiveai.org/onepdf/docs/getting-started/).
- [Choosing a C# PDF library](https://recursiveai.org/onepdf/articles/csharp-pdf-library/) for licenses and features compared.
- The other migration guides in the docs: [from PDFsharp](https://recursiveai.org/onepdf/docs/migrating-from-pdfsharp/), [from QuestPDF](https://recursiveai.org/onepdf/docs/migrating-from-questpdf/), [from PdfPig](https://recursiveai.org/onepdf/docs/migrating-from-pdfpig/).
