# Flatten Forms

> Flatten form fields into static text with ServerTextControl: selected fields or field types, during a merge with Replace, before signing and in the browser.

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

---

A signed contract, an approved application or an invoice sent to a customer should show the values that were entered, not fields that anyone can still change. Flattening replaces each form field with the text it shows, so that the PDF you archive or send contains plain text. You decide which fields to flatten and when: all fields or only some, while merging data, before a digital signature is applied or in the browser.

The examples below use the order form that [Create a Fillable Form](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/#create-a-fillable-form) creates in Document Processing, with the form fields `Customer`, `Product`, `InvoiceDate` and `TermsAccepted`, saved as *Documents/order-form.tx*.

### What Flattening Does

A flattened form field is removed from the document, and the text it showed stays in its place:

| Form field | Text that remains |
|---|---|
| [TextFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textformfield/llms-full.txt) | The entered text |
| [SelectionFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/llms-full.txt) | The text of the selected item |
| [DateFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/llms-full.txt) | The date as the field displays it, formatted with its [DateFormat](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/dateformat-property/llms-full.txt) |
| [CheckFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/llms-full.txt) | The character that displays the state of the check box, set with [CheckedCharacter](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/checkedcharacter-property/llms-full.txt) and [UncheckedCharacter](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/uncheckedcharacter-property/llms-full.txt) |

The following PDF documents, from the blog article [Convert MS Word DOCX to PDF with Form Fields in C# .NET](https://www.textcontrol.com/blog/2025/02/26/convert-ms-word-docx-to-pdf-with-form-fields-in-csharp-dotnet/), show the same Word form saved with its form fields and saved after flattening. The flattened version has the text of each field without a field around it, and the check boxes are characters:

![The same PDF form with highlighted, fillable form fields on the left and with flattened fields that are plain text and check box characters on the right](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-server/form-fields-flattened.70c25c19.webp)

Keep three things in mind:

- **Read the values first.** After flattening, a PDF has no fields whose values your code could read, only text at positions on the page. Store the values before you flatten, as [Import Form Data](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/import-data/llms-full.txt) and [Read and Check the Values of a Filled Form](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/#read-and-check-the-values-of-a-filled-form) describe.
- **Flattening doesn't protect the content.** A PDF can still be changed without a trace. A digital signature makes changes detectable, as [Flatten, Then Sign](#flatten-then-sign) shows.
- **Signature fields stay.** A [SignatureField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/signaturefield/llms-full.txt) isn't a form field, so flattening doesn't remove it.

### Flatten Some Fields and Keep Others

A form can go out partly filled: the values your application knows are fixed, and the fields the recipient still has to fill in stay fillable. The following program fills the order form with the data of *Documents/order.json*, flattens all form fields except `TermsAccepted` and checks which fields the saved PDF still contains:

```json
[
  {
    "Customer": "Acme Corporation",
    "Product": "Priority Support - 12 Months",
    "InvoiceDate": "2025-05-27"
  }
]
```

```csharp
using TXTextControl;
using TXTextControl.DocumentServer;
using TXTextControl.DocumentServer.PDF;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Load("Documents/order-form.tx", StreamType.InternalUnicodeFormat);

    // Fill the form fields with the data and keep them
    using (MailMerge mailMerge = new MailMerge
    {
        TextComponent = tx,
        FormFieldMergeType = FormFieldMergeType.Preselect
    })
    {
        mailMerge.MergeJsonData(File.ReadAllText("Documents/order.json"));
    }

    // The main text, text frames, headers and footers
    foreach (IFormattedText textPart in tx.TextParts)
    {
        TextFieldCollection formFields = textPart.GetTextFields(TextFieldType.FormFields);

        // Collect first: removing a field changes the collection
        List<TextField> flatten = new List<TextField>();

        foreach (TextField field in formFields)
        {
            if (field.Name != "TermsAccepted")
            {
                flatten.Add(field);
            }
        }

        // true: the fields are removed, their text stays
        foreach (TextField field in flatten)
        {
            formFields.Remove(field, true);
        }
    }

    tx.Save("order-confirmation.pdf", StreamType.AdobePDF);
}

// The form fields that are still fillable in the PDF
foreach (var field in Forms.GetAcroFormFields("order-confirmation.pdf"))
{
    Console.WriteLine($"Fillable: {field.FieldName}");
}
```

The code works as follows:

- [FormFieldMergeType](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/formfieldmergetype-property/llms-full.txt) `Preselect` fills the form fields whose names match the data and keeps them as form fields. `TermsAccepted` has no value in the data, so it stays unchanged.
- [IFormattedText.GetTextFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/iformattedtext/gettextfields-method/llms-full.txt) returns the form fields of a text part as a [TextFieldCollection](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldcollection/llms-full.txt), whose [Remove](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldcollection/remove-method/llms-full.txt) takes a second parameter: with `true`, the field is removed and its text stays; with one parameter, the text is deleted as well.
- The fields are collected before any of them is removed, because removing a field changes the collection.
- [Forms.GetAcroFormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver-pdf/forms/getacroformfields-method/llms-full.txt) reads the form fields of the saved PDF, so the loop lists the fields that are still fillable.

To choose fields by another property, such as [ID](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfield/id-property/llms-full.txt), change the condition. The blog article [Programmatically Fill, Flatten, and Export DOCX Form Templates to PDF in C# .NET](https://www.textcontrol.com/blog/2026/04/10/programmatically-fill-flatten-and-export-docx-form-templates-to-pdf-in-csharp-dotnet/) compares the two merge types for a DOCX form template: `Preselect`, which keeps the fields editable, and `Replace`, which flattens them.

### Flatten All Fields of One Type

`GetTextFields` returns the fields of the types you pass, and [TextFieldCollection.Clear](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldcollection/clear-method/llms-full.txt) with `true` removes all of them and keeps their text. The following program flattens the check boxes and date fields of a filled form, *Documents/form-filled.tx*, and leaves the text boxes and selection fields fillable:

```csharp
using TXTextControl;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Load("Documents/form-filled.tx", StreamType.InternalUnicodeFormat);

    foreach (IFormattedText textPart in tx.TextParts)
    {
        // true: the fields are removed, their text stays
        textPart.GetTextFields(TextFieldType.CheckFormField | TextFieldType.DateFormField).Clear(true);
    }

    tx.Save("form-reviewed.pdf", StreamType.AdobePDF);
}
```

[TextFieldType](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldtype/enumeration/llms-full.txt) values can be combined. `TextFieldType.FormFields` stands for all form field types, so `GetTextFields(TextFieldType.FormFields).Clear(true)` flattens every form field of a text part. Use `GetTextFields` for this: [FormFieldCollection.Clear](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfieldcollection/clear-method/llms-full.txt) has no parameter to keep the text, and [FormFieldCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfieldcollection/remove-method/llms-full.txt) removes a single form field.

### Flatten During a Merge

When the form is final as soon as the data is merged, `FormFieldMergeType.Replace` fills and flattens in one step. The following program merges *Documents/order.json* into the order form and saves the result as PDF/A for the archive:

```csharp
using TXTextControl;
using TXTextControl.DocumentServer;

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

    // PDF/A requires fonts that can be embedded
    tx.FontSettings.EmbeddableFontsOnly = true;
    tx.Load("Documents/order-form.tx", StreamType.InternalUnicodeFormat);

    using (MailMerge mailMerge = new MailMerge
    {
        TextComponent = tx,
        FormFieldMergeType = FormFieldMergeType.Replace
    })
    {
        mailMerge.FormFieldMerged += (sender, e) =>
        {
            if (!e.Merged)
            {
                Console.WriteLine($"No value for {e.FormField.Name}");
            }
        };

        mailMerge.MergeJsonData(File.ReadAllText("Documents/order.json"));
    }

    tx.Save("order-archive.pdf", StreamType.AdobePDFA);
}
```

The code works as follows:

- `Replace` replaces the form fields with the values of the data, so the saved document has no form fields left. It can't keep single fields fillable; for that, fill with `Preselect` and flatten yourself, as shown above.
- Form fields without a value are removed according to [RemoveEmptyFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/removeemptyfields-property/llms-full.txt), which is `true` by default. `TermsAccepted` has no value in *order.json*, so the check box is removed together with its character. With `RemoveEmptyFields` set to `false`, the field's current text stays in the document.
- [FormFieldMerged](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver/mailmerge/formfieldmerged-event/llms-full.txt) occurs for each form field, and `e.Merged` is `false` for a field that received no value.
- The value for a `SelectionFormField` must match one of its items.

[Merge Form Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/mail-merge/fields/#merge-form-fields) compares the three merge types, and [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-a/llms-full.txt) describes the archive format.

### Flatten, Then Sign

A digital signature is created while the document is saved and covers the content at that moment. Flatten before you save, so that the signed PDF contains the final values. The following program flattens a filled form and saves it as a signed PDF/A document:

```csharp
using System.Security.Cryptography.X509Certificates;
using TXTextControl;

// Load the certificate including its private key
X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12FromFile(
    "certificate.pfx",
    "123",
    X509KeyStorageFlags.Exportable);

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.FontSettings.EmbeddableFontsOnly = true;
    tx.Load("Documents/form-filled.tx", StreamType.InternalUnicodeFormat);

    // Flatten all form fields of all text parts
    foreach (IFormattedText textPart in tx.TextParts)
    {
        textPart.GetTextFields(TextFieldType.FormFields).Clear(true);
    }

    SaveSettings saveSettings = new SaveSettings()
    {
        DigitalSignature = new DigitalSignature(certificate, null)
    };

    tx.Save("form-signed.pdf", StreamType.AdobePDFA, saveSettings);
}
```

[SaveSettings.DigitalSignature](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/savesettings/digitalsignature-property/llms-full.txt) signs the whole document. `X509CertificateLoader` requires .NET 9 or later; [Digitally Sign a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/pdf/sign/llms-full.txt) shows the .NET 8 alternative, creates a test certificate and signs signature fields instead. Signature fields keep their place when the form fields are flattened, as [Signature Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/signature-fields/llms-full.txt) describes.

### Flatten in the Browser

- **Document Editor.** The JavaScript method [flattenFormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/txtextcontrol/flattenformfields-method/llms-full.txt) converts all form fields to static text, and [SaveSettings.flattenFormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/txtextcontrol-savesettings/flattenformfields-property/llms-full.txt) flattens them when the document is saved. [Read the Values](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/form-fields/#read-the-values) exports a flattened PDF.
- **Document Viewer.** The viewer has no method that flattens form fields. Save the filled form with `mergeFormFields`, as [Save the Filled Form](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-viewer/form-fields/#save-the-filled-form) shows, and flatten it on the server with the code above.

### Forms That Arrive as PDF

The [Forms](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver-pdf/forms/llms-full.txt) class reads the form fields of a PDF file, but TX Text Control has no method that flattens the fields of an existing PDF. To archive a PDF form that a customer filled in, read its values with `GetAcroFormFields` and transfer them into your own template of the form, as [Import Form Data](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/import-data/llms-full.txt) shows. Then flatten the template with one of the methods above and save it as PDF or PDF/A.

### Next Steps

- [Import Form Data](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/import-data/llms-full.txt): read the values of filled PDF forms before you flatten them.
- [AcroForms](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/acroforms/llms-full.txt): create fillable PDF forms.
- [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/pdf-a/llms-full.txt): archive flattened forms.
- [Digital Signatures](https://docs.textcontrol.com/tx-text-control-dotnet-server/digital-signatures/llms-full.txt): sign the final documents.

---

## Nearby

- **Previous:** [Export XFDF](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/export-xfdf/llms-full.txt)
- **Next:** [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/attachments/llms-full.txt)
