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). 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.
- 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
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 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:
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:
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#.
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 “add content” example:
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:
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).
Extract text
iText extracts text through PdfTextExtractor with a strategy. Here both libraries read the two-column part of the report’s first page, and print three lines:
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);
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.
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);
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#.
Fill and flatten a form
iText fills through the AcroForm object (chapter 5, PdfFormCreator) and flattens with FlattenFields:
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}");
form fields left: 0using 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}");
form fields left: 0In 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 and flatten a PDF form.
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). This sample follows iText’s PAdES high-level API article, including its way of reading a PEM file. In 9.8.0, DigestAlgorithms is in iText.Kernel.Crypto (API reference):
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");
signed contract-signed-itext.pdfOnePDF takes the X509Certificate2 that .NET loads from a .pfx:
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");
signed contract-signed-onepdf.pdfpdfsig 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#.
Merge, split, PDF/A and PDF/UA
- Merge. A plain
PdfMerger.Mergeloop drops form fields, as iText’s knowledge base notes.PdfDocument.Mergekeeps fields, bookmarks and links in one call. Both versions side by side: merge PDF files in C#. - Split.
PdfDocument.Split(doc, pagesPerPart)or with page ranges (split a PDF in C#). - PDF/A. iText uses a
PdfADocumentsubclass 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#). - PDF/UA. Likewise a save option, PDF/UA-1 or PDF/UA-2, with layout documents tagged by default (PDF/UA in C#).
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# 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, and our 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.
- Getting started with OnePDF.
- Choosing a C# PDF library for licenses and features compared.
- The other migration guides in the docs: from PDFsharp, from QuestPDF, from PdfPig.