# PDF Creation and Conversion

> Save TextControl documents as PDF in Windows Forms: SaveSettings, JavaScript actions, PDF/UA with DescriptiveText and validation, watermarks and page formats.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > PDF Processing > PDF Creation and Conversion
- **5488 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/creation-conversion/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/creation-conversion/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/creation-conversion/llms-full.txt

---

Everything a Windows Forms application can show in a `TextControl` or build in a `ServerTextControl` becomes a PDF when it is saved with `StreamType.AdobePDF`: a letter typed by the user, a DOCX file loaded from disk or a merged invoice. TX Text Control writes the PDF with its own filter, so Adobe Acrobat isn't needed on the user's machine. The sections below show what a PDF takes over from the document, which options the save offers, how to make the PDF accessible and how to convert documents in another page format.

The first PDF, document properties, the **Save As** dialog box, PDF/A and passwords are covered step by step in [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/pdf/create/llms-full.txt) in Getting Started. PDF is part of the Professional and Enterprise editions; PDF/A and PDF/UA are part of the Enterprise edition, as [Editions and Feature Availability](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/overview/editions/llms-full.txt) lists.

### What a PDF Keeps From the Document

TX Text Control lays out the pages before it writes the PDF, so the PDF shows the same page breaks, headers, footers and table header rows as the document in the editor. Some elements of the document become interactive parts of the PDF:

| In the document | In the PDF |
|---|---|
| Hypertext links and document links | Links to websites and to targets within the document, as [Fields and Subtext Parts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/fields/#add-hypertext-links-and-bookmarks) describes |
| Form fields | Fillable PDF form fields with their names and values, as [PDF Forms](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/forms/llms-full.txt) describes |
| Signature fields | Signature fields that can be signed with a certificate when the document is saved, as [Signature Fields and Signature Appearance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/signature-fields/llms-full.txt) describes |
| SVG images | Vector graphics |
| Headings, tables, text frames, tables of contents and footnotes | The tagged structure of an accessible PDF, since version 34.0 |

`AdobePDF` saves complete documents only: a PDF can't be created from a selection or a single paragraph.

### Choose What the PDF Contains

The options of a save are properties of [SaveSettings](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/savesettings/llms-full.txt), which you pass to [Save](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/save-method/llms-full.txt). These are the ones that matter for PDF:

| Property | What it does | Described in |
|---|---|---|
| `DocumentTitle`, `Author`, `DocumentSubject`, `DocumentKeywords` and more | Document properties of the PDF | [Document Metadata](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/metadata/llms-full.txt) |
| `UserPassword`, `MasterPassword`, `DocumentAccessPermissions` | Encryption and what readers may do | [Passwords and Access Permissions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/passwords/llms-full.txt) |
| `ImageCompressionQuality`, `ImageMaxResolution` | Smaller files through compressed images | [Reduce the Size of PDF Files](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/saving-converting/#reduce-the-size-of-pdf-files) |
| [DocumentLevelJavaScriptActions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/savesettings/documentleveljavascriptactions-property/llms-full.txt) | Scripts that run when the PDF is opened | [Run JavaScript When the PDF Opens](#run-javascript-when-the-pdf-opens) |
| `EmbeddedFiles` | Files attached to the PDF, such as the XML of an electronic invoice | [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/attachments/llms-full.txt) |
| `DigitalSignature`, `SignatureFields` | A digital signature applied while saving | [Digital Signatures](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/llms-full.txt) |

`OmittedContent`, which leaves comments or tracked changes out of other formats, can't be used with PDF and PDF/A.

### Run JavaScript When the PDF Opens

`DocumentLevelJavaScriptActions` takes an array of scripts, which the PDF reader runs when it opens the document. The following handler in *Form1.cs* saves the document of `textControl1` with a script that shows a notice:

```csharp
private void pdfWithScriptButton_Click(object sender, EventArgs e)
{
    SaveSettings saveSettings = new SaveSettings()
    {
        DocumentTitle = "Quarterly Report",

        // Runs in the PDF reader when the document is opened
        DocumentLevelJavaScriptActions = new string[]
        {
            "app.alert('This report is confidential. Do not forward it.');"
        }
    };

    textControl1.Save("report-with-script.pdf", StreamType.AdobePDF, saveSettings);
}
```

The code works as follows:

- `app.alert` belongs to the JavaScript API of PDF readers such as Adobe Acrobat Reader, which Adobe documents.
- The scripts are embedded at document level. When the document is saved as PDF/A, they are left out, because PDF/A doesn't allow scripts.

The blog article [Add JavaScript to PDFs with TX Text Control in C# .NET: Time-Based Alerts Made Easy](https://www.textcontrol.com/blog/2025/06/13/add-javascript-to-pdfs-with-tx-text-control-in-c-dot-net-time-based-alerts-made-easy/) shows expiration notices with such scripts.

### Create an Accessible PDF (PDF/UA)

PDF/UA (ISO 14289) is the standard for PDF documents that people with disabilities can use with screen readers and other assistive technologies. Since version 34.0, every PDF that TX Text Control writes contains a logical structure in addition to its visible content: chapters, headings, paragraphs and sections, and marked text frames, tables, tables of contents and footnotes. Your document supplies what only its author knows:

| Element | What you set |
|---|---|
| Document | A title in [DocumentSettings.DocumentTitle](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/documentsettings/documenttitle-property/llms-full.txt) |
| Headings | A structure level in [ParagraphFormat.StructureLevel](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/paragraphformat/structurelevel-property/llms-full.txt), usually through a paragraph style |
| Images, text frames and other frames | [FrameBase.DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/framebase/descriptivetext-property/llms-full.txt) |
| Tables | Header rows with [TableRow.IsHeader](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/tablerow/isheader-property/llms-full.txt) and a summary in [Table.DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/table/descriptivetext-property/llms-full.txt) |
| Links | [HypertextLink.DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/hypertextlink/descriptivetext-property/llms-full.txt) and [DocumentLink.DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/documentlink/descriptivetext-property/llms-full.txt) |
| Form fields | [FormField.DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/formfield/descriptivetext-property/llms-full.txt) |

The following handler gives the document a title, makes its first paragraph a heading and saves the PDF only when every image, table and form field has a description:

```csharp
private void accessiblePdfButton_Click(object sender, EventArgs e)
{
    // The title that screen readers announce
    textControl1.DocumentSettings.DocumentTitle = "Quarterly Report";

    // The first paragraph becomes a level 1 heading
    textControl1.Select(0, 0);
    textControl1.Selection.ParagraphFormat.StructureLevel = 1;

    // Collect the elements that have no description yet
    List<string> missing = new List<string>();

    foreach (TXTextControl.Image image in textControl1.Images)
    {
        if (string.IsNullOrEmpty(image.DescriptiveText))
        {
            missing.Add("Image " + image.ID);
        }
    }

    foreach (Table table in textControl1.Tables)
    {
        if (string.IsNullOrEmpty(table.DescriptiveText))
        {
            missing.Add("Table " + table.ID);
        }
    }

    foreach (FormField formField in textControl1.FormFields)
    {
        if (string.IsNullOrEmpty(formField.DescriptiveText))
        {
            missing.Add("Form field " + formField.Name);
        }
    }

    if (missing.Count > 0)
    {
        MessageBox.Show("Add a description to:\n" + string.Join("\n", missing));
        return;
    }

    textControl1.Save("report-accessible.pdf", StreamType.AdobePDF);
}
```

The code works as follows:

- `Image` is written in full as `TXTextControl.Image`, because *Form1.cs* also sees `System.Drawing.Image`.
- `StructureLevel` 1 marks a first-level heading; 0 is body text. In a real document, set it in the paragraph styles of the headings.
- `Images` and `Tables` contain the images and tables of the text part with the input focus, here the main text, while `FormFields` contains the form fields of the whole document. Images and tables in headers, footers and text frames belong to other text parts, which [Find the Fields of All Text Parts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/fields/#find-the-fields-of-all-text-parts) shows how to reach.

Saved with `StreamType.AdobePDFA` instead, the same document is a PDF/A-3a document and can conform to PDF/UA at the same time, as [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/pdf-a/llms-full.txt) describes.

### Validate the Accessible PDF

The check above covers what the document knows before it's saved. Whether the PDF itself meets PDF/UA is checked by `TXTextControl.PDF.Validation`, a .NET library of Text Control that reads the PDF file or its bytes and returns a report of findings. It's published on [nuget.org](https://www.nuget.org/packages/TXTextControl.PDF.Validation), not on the Text Control Private NuGet Feed, and it doesn't need a `TextControl` or `ServerTextControl`:

- **.NET 10.** Version 34.1.0 targets .NET 10, so your Windows Forms project must target .NET 10 (`net10.0-windows`) to reference it. .NET Framework projects can't use it.
- **License.** Individuals and organizations with a valid TX Text Control license may use it free of charge. Its license must be accepted when the package is installed.

Install it with **Project** > **Manage NuGet Packages...** and the source nuget.org, or from the folder of the project:

```bash
dotnet add package TXTextControl.PDF.Validation --version 34.1.0
```

The following handler saves the document of `textControl1` as PDF into memory, validates it and writes the file only when no blocking error was found. *Form1.cs* needs `using TXTextControl.PDF.Validation;` and `using TXTextControl.PDF.Validation.Model;`:

```csharp
private void validatePdfButton_Click(object sender, EventArgs e)
{
    // Save the PDF into memory, so it can be checked before it's written
    textControl1.Save(out byte[] pdf, BinaryStreamType.AdobePDF);

    Report report = PdfUaValidator.Validate(pdf);

    if (report.Status == ValidationStatus.Failed || report.Status == ValidationStatus.Blocked)
    {
        // The findings that didn't pass, with their rule and message
        IEnumerable<string> problems = report.Findings
            .Where(finding => !finding.Passed)
            .Select(finding => $"{finding.Severity} {finding.RuleId}: {finding.Message}");

        MessageBox.Show(this, "The PDF isn't accessible yet:\n" + string.Join("\n", problems), "PDF/UA");
        return;
    }

    File.WriteAllBytes("report-accessible.pdf", pdf);
    MessageBox.Show(this, "Saved with the result " + report.Status + ".", "PDF/UA");
}
```

The code works as follows:

- `PdfUaValidator.Validate` takes the path of a PDF file or the PDF as a byte array and returns a `Report` of the `TXTextControl.PDF.Validation.Model` namespace.
- `Status` is `Passed`, `CompletedWithWarnings`, `Failed` or `Blocked`. Only failed findings of the severity `Error` make a report `Failed`; `Blocked` means the validation couldn't run completely, for example because the PDF is encrypted, so validate before you protect a PDF with a password.
- Each `Finding` has a `RuleId` such as `UA-TITLE` (the document title) or `UA-FIG-ALT` (the descriptions of images), a `Severity` of `Info`, `Warning` or `Error`, `Passed` and a `Message`.

`PdfUaValidator.ToJson(report, true)` turns the report into indented JSON, which you can store with the document or compare between two versions of a template. The validator confirms that a description exists, not that it describes the image well, so a review by people remains necessary. The package doesn't check PDF/A conformance: its `PDFA-CONFORMANCE` finding only reports whether the file declares it. The blog article [Validating PDF/UA Documents in .NET C#: A Practical Guide](https://www.textcontrol.com/blog/2026/07/06/validating-pdf-ua-documents-in-dotnet-csharp/) goes further, and the same package checks digital signatures, as [Verify the Signatures in Code](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/digital-signatures/signing/#verify-the-signatures-in-code) shows.

### Convert a Document to Another Page Format

A document keeps its page format when it is saved as PDF. To create a PDF with other pages without changing what the user sees, save a copy of the editor's document, load it into a `ServerTextControl` and change the sections there:

```csharp
private void letterPdfButton_Click(object sender, EventArgs e)
{
    // A copy of the document in the editor
    byte[] document;
    textControl1.Save(out document, BinaryStreamType.InternalUnicodeFormat);

    using (ServerTextControl tx = new ServerTextControl())
    {
        // Initialize the new instance before using it
        tx.Create();
        tx.Load(document, BinaryStreamType.InternalUnicodeFormat);

        // Page sizes and margins in 1/100 inch
        tx.PageUnit = MeasuringUnit.CentiInch;

        // US letter pages with margins of 0.75 inch in every section
        foreach (Section section in tx.Sections)
        {
            section.Format.PageSize = new PageSize();
            section.Format.PageMargins = new PageMargins(75, 75, 75, 75);
        }

        tx.Save("report-letter.pdf", StreamType.AdobePDF);
    }
}
```

The code works as follows:

- `BinaryStreamType.InternalUnicodeFormat` is the format of TX Text Control itself, so the copy keeps everything the document contains.
- [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/llms-full.txt) is the document engine without a user interface. [Create](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/create-method/llms-full.txt) must be called before any other member.
- [PageUnit](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/pageunit-property/llms-full.txt) sets the unit of page sizes and margins. The reference names its type `PageUnit`; in code, the enumeration is `MeasuringUnit`.
- Every [Section](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/section/llms-full.txt) has its own format. The [PageSize](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/pagesize/llms-full.txt) constructor without parameters creates a US letter page, 8.5 x 11 inches, and [SectionFormat.PageMargins](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/sectionformat/pagemargins-property/llms-full.txt) takes the margins.

Text and images flow onto the new pages, so the number of pages can change. The same `ServerTextControl` converts files that aren't open in the editor: [Convert a Folder of Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/saving-converting/#convert-a-folder-of-documents) turns every DOCX, DOC, RTF and HTML file of a folder into a PDF. The other direction, from PDF to an editable format, is described in [PDF Import and Its Limitations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/import/llms-full.txt).

### Add a Watermark to Every Page

A "DRAFT" or "CONFIDENTIAL" behind the text of every page marks the status of a PDF. A watermark is an image in the header of each section, fixed on the page and placed below the text; [Add a Watermark to Every Page](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/images-shapes/#add-a-watermark-to-every-page) in Images, Text Frames, and Shapes explains the method `AddWatermark` and how it centers the image. To mark only the PDF and leave the document in the editor as it is, run the method on a copy:

```csharp
private void draftPdfButton_Click(object sender, EventArgs e)
{
    // A copy of the document in the editor
    byte[] document;
    textControl1.Save(out document, BinaryStreamType.InternalUnicodeFormat);

    using (ServerTextControl tx = new ServerTextControl())
    {
        // Initialize the new instance before using it
        tx.Create();
        tx.Load(document, BinaryStreamType.InternalUnicodeFormat);

        // Page sizes, margins and image locations in twips
        tx.PageUnit = MeasuringUnit.Twips;

        AddWatermark(tx.Sections, "draft.svg");

        tx.Save("report-draft.pdf", StreamType.AdobePDF);
    }
}
```

As in [Convert a Document to Another Page Format](#convert-a-document-to-another-page-format), a `ServerTextControl` holds the copy, and [PageUnit](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/pageunit-property/llms-full.txt) gives its page sizes and margins the unit of the image. [ServerTextControl.Sections](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/sections-property/llms-full.txt) is the same kind of collection as the sections of the `TextControl`, so `AddWatermark` takes it unchanged. In Adobe Acrobat, the watermark appears in the middle of every page:

![A three-page PDF in Adobe Acrobat with a gray DRAFT watermark in the middle of the first page and of each page thumbnail in the Pages panel.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/watermark-draft-pages.42220a8d.webp)

The blog article [Adding Watermarks to PDF Documents in .NET C#](https://www.textcontrol.com/blog/2025/02/06/adding-watermarks-to-pdf-documents-in-net-c-sharp/) adds the watermark the same way before it saves the PDF.

### Next Steps

- [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/pdf-a/llms-full.txt): save documents for long-term archiving.
- [Font Embedding and Substitution](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/fonts/llms-full.txt): control which fonts end up in the PDF.
- [PDF Forms](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/forms/llms-full.txt): create PDF documents that users fill in.
- [Passwords and Access Permissions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/passwords/llms-full.txt): protect the PDF.

---

## Nearby

- **Previous:** [PDF Processing](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/llms-full.txt)
- **Next:** [PDF Import and Its Limitations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/import/llms-full.txt)
