Load and Modify a PDF
An existing PDF document can be loaded into ServerTextControl, read and changed. You read its text, metadata, attachments and form field values, add a watermark and save the result as a new PDF. Along the way, you learn what happens to a PDF when TX Text Control imports it, so you know what to expect from the result.
What Happens When You Load a PDF
PDF is a page description format, like PostScript. It was designed to display and print a document exactly the same everywhere, not to be edited again. A PDF file describes what each character looks like and where it is placed on the page, but not necessarily which character it is. It usually contains no information about the reading order, or whether a piece of text is a heading or a table cell.
When you load a PDF, TX Text Control converts it into an editable document:
- It extracts all text it can find, adds missing spaces and paragraph breaks, and sorts the text blocks into their logical order.
- It keeps text formatting such as font names, sizes and styles.
- By default, it uses tables, images and text frames to rebuild a document that looks as close as possible to the original pages.
Keep the limits in mind:
- The result is a reconstruction. The loaded document is not the original PDF. When you save it, TX Text Control creates a new PDF from the reconstructed document. Importing a PDF is well suited for reading content and for small changes, not for extensive editing.
- Text cannot always be extracted. Most PDF files contain character mappings that make text extraction possible, but some do not.
- Structure is guessed. Paragraphs, tables and sections are rebuilt from the positions of the characters, because a PDF rarely stores them.
The LoadSettings.PDFImportSettings property controls how the document is rebuilt. The default rebuilds the pages with tables, images and text frames and provides the files embedded in the PDF; Read the Text below uses GenerateLines, which loads only the text. PDF Import in Supported File Formats lists all values of the PDFImportSettings enumeration.
If users only need to view a PDF in the browser, the Document Viewer is usually the better choice. See "View PDFs Without Changing Them" at the end of this page.
Prerequisites
- A .NET console application with the
TXTextControl.TextControl.Core.SDKpackage (orTXTextControl.TextControl.ASP.SDKon Windows) installed from the Text Control Private NuGet Feed. Create a PDF shows how to set it up. - A PDF file named input.pdf in the project. Set its Copy to Output Directory property to Copy always.
Load a PDF
Load a PDF with ServerTextControl.Load and StreamType.AdobePDF. Pass a LoadSettings object when you want to choose the import mode or read information about the loaded document afterwards:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
LoadSettings loadSettings = new LoadSettings();
// Load the PDF and convert it into an editable document
tx.Load("input.pdf", StreamType.AdobePDF, loadSettings);
Console.WriteLine($"Loaded {loadSettings.LoadedFile}, {loadSettings.BytesRead} bytes read.");
}
To load a PDF from memory, for example from an upload or a database, pass the byte array with BinaryStreamType.AdobePDF inside the same using block:
byte[] data = File.ReadAllBytes("input.pdf");
tx.Load(data, BinaryStreamType.AdobePDF, loadSettings);
Read the Text
To get the plain text of a PDF, load it with PDFImportSettings.GenerateLines and read the Text property:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
LoadSettings loadSettings = new LoadSettings()
{
PDFImportSettings = PDFImportSettings.GenerateLines
};
tx.Load("input.pdf", StreamType.AdobePDF, loadSettings);
Console.WriteLine(tx.Text);
}
To find text together with its page and position, use the Lines class. It reads the text lines of a PDF file or byte array without a ServerTextControl instance and searches them for a string, a regular expression or a geometric area:
using TXTextControl.DocumentServer.PDF.Contents;
Lines pdfLines = new Lines("input.pdf");
foreach (ContentLine line in pdfLines.Find("Total:"))
{
Console.WriteLine($"Page {line.Page} (X: {line.X}, Y: {line.Y}): {line.Text}");
}
The coordinates of a ContentLine are given in points (1/72 inch).
Read Metadata and Attachments
After a PDF has been loaded, the LoadSettings object contains the document's metadata and its embedded files:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
LoadSettings loadSettings = new LoadSettings();
tx.Load("input.pdf", StreamType.AdobePDF, loadSettings);
// Metadata
Console.WriteLine($"Title: {loadSettings.DocumentTitle}");
Console.WriteLine($"Author: {loadSettings.Author}");
Console.WriteLine($"Subject: {loadSettings.DocumentSubject}");
Console.WriteLine($"Created: {loadSettings.CreationDate}");
// Attachments (embedded files)
if (loadSettings.EmbeddedFiles != null)
{
foreach (EmbeddedFile embeddedFile in loadSettings.EmbeddedFiles)
{
// The name can contain a path, so use only the file name
string fileName = Path.GetFileName(embeddedFile.FileName);
// The data is either a string or a byte array
if (embeddedFile.Data is byte[] bytes)
{
File.WriteAllBytes(fileName, bytes);
}
else
{
File.WriteAllText(fileName, embeddedFile.Data.ToString());
}
Console.WriteLine($"{fileName} written.");
}
}
}
Text properties without a value are empty strings, DocumentKeywords is null when the PDF has no keywords, and a missing date is DateTime.MinValue (January 1, 0001). PDF/A-3 documents often carry attachments, for example the XML data of an electronic invoice.
Read Form Field Values
Interactive PDF forms (AcroForms) that users have filled in are read with the Forms.GetAcroFormFields method. It reads the fields directly from the PDF file or a byte array, so you do not need a ServerTextControl instance:
using TXTextControl.DocumentServer.PDF;
using TXTextControl.DocumentServer.PDF.AcroForms;
var fields = Forms.GetAcroFormFields("form.pdf");
foreach (var field in fields)
{
switch (field)
{
case FormTextField textField:
Console.WriteLine($"{textField.FieldName}: {textField.Value}");
break;
case FormCheckBox checkBox:
Console.WriteLine($"{checkBox.FieldName}: {checkBox.IsChecked}");
break;
}
}
Give form fields meaningful names when you create forms, so that the values can be mapped to your data model. To let users fill in a form in the browser, use the Document Viewer described below.
Add a Watermark
As a simple change, add an image such as a "DRAFT" stamp behind the text on every page. The image is placed in the header of each section, because header content is repeated on every page, and it is inserted with ImageInsertionMode.FixedOnPage and BelowTheText, so the text flow is not changed. Add an image file named draft.svg to the project, set it to Copy always, and use this code:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("input.pdf", StreamType.AdobePDF);
foreach (Section section in tx.Sections)
{
// Add a header to the section and get it
section.HeadersAndFooters.Add(HeaderFooterType.Header);
HeaderFooter header =
section.HeadersAndFooters.GetItem(HeaderFooterType.Header);
// Insert the image at a fixed position behind the text
Image watermark = new Image { FileName = "draft.svg" };
header.Images.Add(
watermark,
1,
new System.Drawing.Point(0, 0),
ImageInsertionMode.FixedOnPage | ImageInsertionMode.BelowTheText);
}
// Save the modified document as a new PDF
tx.Save("output.pdf", StreamType.AdobePDF);
}
The location is given in twips (1/1440 inch). An SVG image stays sharp at any zoom level in the PDF. The blog post Adding Watermarks to PDF Documents in .NET C# shows how to center the image on pages of different sizes.
Save the Result as PDF
The last line of the watermark example saves the document with StreamType.AdobePDF. Everything from Create a PDF applies here as well: you can save to a byte array, create PDF/A with StreamType.AdobePDFA, set document properties with SaveSettings, or sign the PDF while saving it. The metadata you read from LoadSettings can be written again with the matching SaveSettings properties.
Load Password-Protected PDFs
A PDF that is protected with a user password cannot be loaded without it. Load throws a FilterException. Ask the user for the password and load the file again with LoadSettings.UserPassword:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
try
{
tx.Load("protected.pdf", StreamType.AdobePDF);
}
catch (FilterException)
{
LoadSettings loadSettings = new LoadSettings()
{
UserPassword = "user1234"
};
tx.Load("protected.pdf", StreamType.AdobePDF, loadSettings);
Console.WriteLine($"Permissions: {loadSettings.DocumentAccessPermissions}");
}
}
After loading, LoadSettings.DocumentAccessPermissions tells you which operations the document allows, such as printing or extracting content. Your application is responsible for respecting them. If you pass the correct owner password in LoadSettings.MasterPassword, all operations are allowed.
View PDFs Without Changing Them
ServerTextControl converts a PDF into an editable document so that your code can read and change it. If users only need to read a PDF in a web application, fill in its form fields or sign it, use the Document Viewer instead. It displays documents in several formats, including PDF, DOCX and RTF, and lets users fill in forms, sign documents and add annotations. See Document Viewer in Getting Started, for example Document Viewer with ASP.NET Core.
By default, the Document Viewer imports a PDF with the same engine, so it shows the rebuilt document that What Happens When You Load a PDF describes. To display the PDF pages exactly as they are, let the viewer render them with PDF.js, as Loading Documents shows.
Next Steps
- Digitally Sign a PDF: sign the PDF you save with a certificate.
- Text Extraction: more ways to extract and search text in PDF documents.
- PDF Forms: create, flatten and read PDF form fields.
- PDF Conversion: converting documents to and from PDF.