# PDF Creation

> Create PDFs with ServerTextControl: passwords and access permissions, document-level JavaScript, links and form fields, fonts, AdaptFont and email attachments.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > PDF Processing > PDF Creation
- **4483 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/creation/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/creation/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/creation/llms-full.txt

---

Any document that TX Text Control creates, loads or merges becomes a PDF with one `Save` call. The details of that PDF are up to your code: who may open it and what readers may do with it, whether a script runs when it opens, which document elements become links and form fields and which fonts the pages use. The sections below cover these decisions for PDF documents created on the server.

The first PDF, a PDF in a byte array, document properties and a controller that returns a PDF are part of [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/create/llms-full.txt) in Getting Started. Smaller PDF files through image compression are described in [Reduce the Size of PDF Files](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/saving-converting/#reduce-the-size-of-pdf-files).

### What a PDF Keeps From the Document

TX Text Control lays out the document before it writes the PDF, so page breaks, repeated table header rows and the headers and footers of each section are part of the pages. Beyond the visible pages, elements of the document become interactive parts of the PDF:

| In the document | In the PDF |
|---|---|
| Hypertext links, document links and bookmarks | Links to websites and link targets within the document, as [Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/fields/#add-hypertext-links-and-bookmarks) describes |
| Tables of contents with links | Entries that jump to their headings, as [Tables of Contents](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/tables-of-contents/llms-full.txt) describes |
| Form fields | Interactive PDF form fields with their names and values, as [Form Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/#formats-that-keep-form-fields) describes |
| Signature fields | Signature fields, which can be signed with a certificate when the PDF is saved, as [Signature Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/signature-fields/llms-full.txt) describes |
| SVG, EMF and WMF images | Vector graphics instead of bitmaps |
| Headings, tables, text frames, footnotes and descriptive texts | The tagged structure of an accessible PDF, as [PDF/UA](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-ua/llms-full.txt) describes |

How tables and headings break across pages is set in the document: header rows that repeat on every page, table rows that don't break across pages and headings that stay with the next paragraph, as [Tables](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/tables/llms-full.txt) and [Paragraphs](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/paragraphs/#format-paragraphs) describe.

### Protect a PDF With Passwords and Permissions

Two passwords and a set of permissions protect a PDF document:

- **[UserPassword](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/loadsavesettingsbase/userpassword-property/llms-full.txt)** encrypts the document: it's required to open it. An empty string means everyone can open the document.
- **[MasterPassword](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/loadsavesettingsbase/masterpassword-property/llms-full.txt)** protects the permissions. An empty string means access isn't restricted.
- **[DocumentAccessPermissions](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/documentaccesspermissions-property/llms-full.txt)** sets what readers may do. It only has an effect when a `MasterPassword` is set, and its values can be combined.

Both passwords apply to PDF only, with an encryption key length of 128 bits. The permissions are:

| Value | Allows |
|---|---|
| `AllowAll` | All of the permissions |
| `None` | None of the permissions |
| `AllowLowLevelPrinting` | Printing |
| `AllowHighLevelPrinting` | Printing without restrictions |
| `AllowExtractContents` | Copying or otherwise extracting text and graphics |
| `AllowContentAccessibility` | Extracting content for the visually impaired only |
| `AllowGeneralEditing` | Changing the content of the document |
| `AllowAuthoring` | Adding comments and filling in form fields, including signature fields |
| `AllowAuthoringFields` | Filling in existing form fields, including signature fields |
| `AllowDocumentAssembly` | Inserting, rotating and deleting pages and creating bookmarks and thumbnails |

The following program saves an invoice that requires a password to open and may only be printed, then checks that the saved PDF is encrypted:

```csharp
using TXTextControl;

string path = "invoice-protected.pdf";

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Load("Documents/sample.docx", StreamType.WordprocessingML);

    SaveSettings saveSettings = new SaveSettings()
    {
        UserPassword = "user1234",
        MasterPassword = "owner1234",
        DocumentAccessPermissions = DocumentAccessPermissions.AllowLowLevelPrinting |
                                    DocumentAccessPermissions.AllowContentAccessibility
    };

    tx.Save(path, StreamType.AdobePDF, saveSettings);
}

// Check the result: without the password, loading must fail
using (ServerTextControl check = new ServerTextControl())
{
    check.Create();

    try
    {
        check.Load(path, StreamType.AdobePDF);
        Console.WriteLine("The PDF isn't encrypted.");
    }
    catch (FilterException exception) when (exception.Reason == FilterException.FilterError.InvalidPassword)
    {
        LoadSettings loadSettings = new LoadSettings() { UserPassword = "user1234" };
        check.Load(path, StreamType.AdobePDF, loadSettings);

        Console.WriteLine($"Encrypted, permissions: {loadSettings.DocumentAccessPermissions}");
    }
}
```

The code works as follows:

- The user password is required to open the document, and the master password is required to change its security settings.
- Loading the PDF without a password throws a [FilterException](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/filterexception/llms-full.txt) whose [Reason](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/filterexception/reason-property/llms-full.txt) is `InvalidPassword`. With the password, the load succeeds, and [LoadSettings.DocumentAccessPermissions](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/loadsettings/documentaccesspermissions-property/llms-full.txt) returns the permissions. With the master password, it returns `AllowAll`.
- A check like this in an automated pipeline makes sure that no document leaves unprotected.

A document can also be protected with a `MasterPassword` alone: everyone can open it, but the permissions apply, for example `AllowAuthoringFields | AllowHighLevelPrinting` for a form that readers fill in and print but don't change. Permissions are respected by compliant PDF readers but aren't a cryptographic protection, so confidential content needs a user password. PDF/A doesn't allow encryption, as [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-a/llms-full.txt) describes. The blog article [PDF Security Explained: Passwords, Permissions, Encryption and Digital Signatures in C# .NET](https://www.textcontrol.com/blog/2026/06/08/pdf-security-explained-passwords-permissions-encryption-and-digital-signatures-in-csharp-dotnet/) combines protection with digital signatures.

### Run JavaScript When the PDF Opens

[SaveSettings.DocumentLevelJavaScriptActions](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/documentleveljavascriptactions-property/llms-full.txt) embeds scripts that run when a PDF reader opens the document. Scripts can fill form fields, validate input, calculate values or show messages. The following program creates an invoice with a form field that a script fills with the current date, and shows a message when the invoice is past due:

```csharp
using TXTextControl;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    tx.Selection.Text = "Invoice INV-2025-001\r\nAcme Corporation\r\nDue: June 10, 2025\r\n\r\nOpened on: ";

    // A form field that the script addresses by its name
    TextFormField openedOn = new TextFormField(2000) { Name = "OpenedOn" };
    tx.FormFields.Add(openedOn);

    string script = @"
        var field = this.getField('OpenedOn');
        field.value = util.printd('m/d/yyyy', new Date());

        if (new Date() > new Date('2025-06-10T00:00:00')) {
            app.alert('Invoice INV-2025-001 is past due.');
        }";

    SaveSettings saveSettings = new SaveSettings()
    {
        DocumentLevelJavaScriptActions = new string[] { script }
    };

    tx.Save("invoice-reminder.pdf", StreamType.AdobePDF, saveSettings);
}
```

The code works as follows:

- Form fields are exported with their names, so the script finds the field with `this.getField`. The objects `this`, `util` and `app` belong to the JavaScript API of PDF readers such as Adobe Acrobat, which Adobe documents.
- `DocumentLevelJavaScriptActions` takes an array, so a document can contain several scripts.
- The scripts aren't embedded in PDF/A documents.

When Adobe Acrobat opens such a PDF, a script can show a message box. The blog article on time-based alerts linked below shows this message when a document has expired:

![Adobe Acrobat message box titled "Warning: JavaScript Window - Document Expired" that says the document has expired and names a support contact and the end of its validity](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-server/pdf-javascript-alert.5b2cc195.webp)

Most desktop PDF readers run JavaScript, but in a more limited environment than a browser. 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/) describes expiration notices, and [Inject JavaScript to PDF Documents in C#](https://www.textcontrol.com/blog/2024/06/07/inject-javascript-to-pdf-documents-in-csharp/) opens the print dialog with the document and adds a print button.

### Use the Right Fonts

A PDF contains the fonts its pages use, so the fonts must be available where the PDF is created. The Core engine brings them with your application in its *Fonts* folder, and `ServerTextControl.InstallFonts` registers a second folder, as [Fonts](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/fonts/llms-full.txt) in the Deployment Guide describes.

[FontSettings](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/fontsettings/llms-full.txt) restricts which fonts a document may use: [TrueTypeFontsOnly](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/fontsettings/truetypefontsonly-property/llms-full.txt) allows TrueType and OpenType fonts, [ScalableFontsOnly](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/fontsettings/scalablefontsonly-property/llms-full.txt) scalable fonts and [EmbeddableFontsOnly](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/fontsettings/embeddablefontsonly-property/llms-full.txt) fonts that can be embedded. All three are `false` by default. Set them, like `AdaptFontEvent`, before you load the document, so that they apply to its fonts. The following program registers an additional font folder, allows TrueType and OpenType fonts only and chooses the replacement for the fonts that don't qualify:

```csharp
using TXTextControl;

// A folder next to the application, for example with corporate fonts
ServerTextControl.InstallFonts("Additional Fonts");

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    tx.FontSettings.TrueTypeFontsOnly = true;
    tx.FontSettings.AdaptFontEvent = true;

    tx.AdaptFont += (sender, e) =>
    {
        // The replacement must be one of the supported fonts
        if (Array.IndexOf(e.SupportedFonts, "Arial") >= 0)
        {
            e.AdaptedFontName = "Arial";
        }

        Console.WriteLine($"{e.FontName} replaced with {e.AdaptedFontName}");
    };

    tx.Load("Documents/sample.docx", StreamType.WordprocessingML);
    tx.Save("sample.pdf", StreamType.AdobePDF);
}
```

[AdaptFont](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/adaptfont-event/llms-full.txt) occurs for each font that must be replaced, because a loaded document uses a font that isn't available or because `FontSettings` excludes it, and only when [AdaptFontEvent](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/fontsettings/adaptfontevent-property/llms-full.txt) is `true`. [AdaptedFontName](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/adaptfonteventargs/adaptedfontname-property/llms-full.txt) sets the replacement, which must be one of the [SupportedFonts](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/adaptfonteventargs/supportedfonts-property/llms-full.txt). A replaced font can change line and page breaks. PDF/A requires `EmbeddableFontsOnly`, as [The Rules of PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-a/#the-rules-of-pdf-a) describes; with `tx.FontSettings.EmbeddableFontsOnly = true` and `StreamType.AdobePDFA`, the same program writes a PDF/A document. [Make Fonts Available on the Server](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/creating/#make-fonts-available-on-the-server) shows how to list the available fonts, and [Fonts](https://docs.textcontrol.com/tx-text-control-dotnet-server/troubleshooting/fonts/llms-full.txt) in Troubleshooting helps when text looks different than expected.

### Send the PDF as an Email Attachment

A PDF that goes to a customer by email doesn't need a file on the server. `Save` with `BinaryStreamType.AdobePDF` writes the PDF into a byte array, and a `MemoryStream` over the array becomes the attachment of a `MailMessage` from the `System.Net.Mail` namespace of .NET:

```csharp
using System.Net;
using System.Net.Mail;
using TXTextControl;

byte[] pdf;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Load("Documents/invoice.docx", StreamType.WordprocessingML);

    // The PDF in memory, without a file
    tx.Save(out pdf, BinaryStreamType.AdobePDF);
}

using (MailMessage message = new MailMessage("billing@example.com", "customer@example.com"))
{
    message.Subject = "Invoice INV-2025-001";
    message.Body = "Please find your invoice attached.";
    message.Attachments.Add(new Attachment(new MemoryStream(pdf), "INV-2025-001.pdf", "application/pdf"));

    using (SmtpClient client = new SmtpClient("smtp.example.com", 587))
    {
        client.EnableSsl = true;
        client.Credentials = new NetworkCredential("username", "password");
        client.Send(message);
    }
}
```

Only the first part is TX Text Control: [ServerTextControl.Save](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/save-method/llms-full.txt) with the byte array overload, which [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/create/llms-full.txt) introduces. The server name, port and credentials of the SMTP server are placeholders for your mail provider's settings. The blog article [Create and Send PDF Documents as Email Attachments with .NET C#](https://www.textcontrol.com/blog/2025/01/09/create-and-send-pdf-documents-as-email-attachments-with-net-c-sharp/) puts the mail code into a class of its own.

### Create PDF Documents Efficiently

Choose the Core engine, return short jobs directly and queue long ones, and create the PDF only when the document is final: [Performance Best Practices](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/best-practices/llms-full.txt) gives the measurements behind these recommendations. Long-running jobs can notify the client when the PDF is ready, as the blog article [Generating Documents using a RESTful, Asynchronous Web API using WebHooks](https://www.textcontrol.com/blog/2022/08/22/generating-documents-using-a-restful-asynchronous-web-api-using-webhooks/) shows.

### Next Steps

- [PDF Conversion](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/conversion/llms-full.txt): convert DOCX, HTML, XLSX and Markdown documents to PDF.
- [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-a/llms-full.txt): create PDF documents for long-term archiving.
- [PDF/UA](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-ua/llms-full.txt): create accessible PDF documents.
- [Digital Signatures](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/llms-full.txt): sign the PDF documents you create.

---

## Nearby

- **Previous:** [PDF Processing](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/llms-full.txt)
- **Next:** [PDF Conversion](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/conversion/llms-full.txt)
