# Document Metadata

> Update PDF metadata in a WPF app: what a PDF stores, new keywords for an existing file, a JSON index of PDFs with ServerTextControl and a PDF/UA title check.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > PDF Processing > Document Metadata
- **3154 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/metadata/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/metadata/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/metadata/llms-full.txt

---

Every PDF carries a small set of facts about itself: a title, an author, a subject, keywords, the application that created it and its dates. PDF readers show them as document properties, Windows Search and document management systems index them, and PDF/UA requires a title. With TX Text Control .NET for WPF, this metadata is part of the document in the `TextControl`: a loaded document brings it along, code or the user changes it, and the next save writes it. Find out which values a PDF stores, how to change the metadata of an existing PDF, how to read it from many files and how to read the raw metadata.

The document properties of a first PDF are set in [Create a PDF](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/pdf/create/llms-full.txt) in Getting Started, and [Loading Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/loading/#read-information-about-a-loaded-document) reads them after loading.

### Where Metadata Lives

The metadata of the document in the editor is the [DocumentSettings](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/documentsettings/llms-full.txt) object of the `TextControl`: `Load` fills it, code and the sidebar change it, and every `Save` stores it, so a PDF that is loaded and saved again keeps its metadata. [SaveSettings](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/savesettings/llms-full.txt) overrides values for a single save, and [LoadSettings](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/loadsettings/llms-full.txt) reports what one `Load` found. [Document Properties](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/properties/llms-full.txt) describes these properties, the DocumentSettings panel of the WPF `Sidebar` and how `SaveSettings` overrides them, for every format.

A PDF stores the title, author, subject, keywords, creating application, creation date and modification date. The modification date has no `DocumentSettings` property: set it with [SaveSettings.LastModificationDate](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/savesettings/lastmodificationdate-property/llms-full.txt) and read it with [LoadSettings.LastModificationDate](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/loadsettings/lastmodificationdate-property/llms-full.txt). [Save the Document as PDF](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/pdf/create/#save-the-document-as-pdf) in Getting Started sets all of them for a first PDF and shows them in the **Document Properties** dialog of Adobe Acrobat.

The fields of the sidebar panel are listed in [Show the Document Settings Panel](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/properties/#show-the-document-settings-panel); its attachments category is described in [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/attachments/#let-users-manage-attachments-in-the-sidebar).

### Update the Metadata of an Existing PDF

Loading a PDF fills `DocumentSettings`, so changing one value and saving keeps all others. The handlers on this page go into *MainWindow.xaml.cs*, which needs `using System;`, `using System.Windows;` and `using TXTextControl;`. The following one replaces the keywords of an invoice:

```csharp
private void updatePdfButton_Click(object sender, RoutedEventArgs e)
{
    textControl1.Load("invoice.pdf", StreamType.AdobePDF);

    // Filled from the loaded PDF
    DocumentSettings documentSettings = textControl1.DocumentSettings;
    MessageBox.Show(this, $"Title: {documentSettings.DocumentTitle}\nCreated with: {documentSettings.CreatorApplication}");

    documentSettings.DocumentKeywords = new string[] { "invoice", "INV-2025-001", "paid" };

    textControl1.Save("invoice-paid.pdf", StreamType.AdobePDF,
        new SaveSettings() { LastModificationDate = DateTime.Now });
}
```

The saved PDF names the original creating application unless you set a new `CreatorApplication`. Its pages are rebuilt from the imported content, as [PDF Import and Its Limitations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/import/llms-full.txt) describes, so it's a new PDF with the old metadata.

### Build a Keyword Index of PDF Files

For many files, a [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/servertextcontrol/llms-full.txt) reads the metadata without touching the editor. It is the TX Text Control without a user interface and is part of the WPF package. The following handler writes the title, author, keywords and creation date of each PDF in *Invoices* to *index.json*, with `using System.Collections.Generic;`, `using System.IO;`, `using System.Linq;` and `using System.Text.Json;`:

```csharp
private void buildIndexButton_Click(object sender, RoutedEventArgs e)
{
    List<object> index = new List<object>();

    using (ServerTextControl tx = new ServerTextControl())
    {
        // Initialize the new instance before using it
        tx.Create();

        foreach (string file in Directory.GetFiles("Invoices", "*.pdf"))
        {
            // Text only: the metadata doesn't need the layout of the pages
            LoadSettings loadSettings = new LoadSettings()
            {
                PDFImportSettings = PDFImportSettings.GenerateLines
            };

            tx.Load(file, StreamType.AdobePDF, loadSettings);

            index.Add(new
            {
                File = System.IO.Path.GetFileName(file),
                Title = loadSettings.DocumentTitle,
                Author = loadSettings.Author,
                Keywords = (loadSettings.DocumentKeywords ?? Array.Empty<string>()).Select(keyword => keyword.Trim()).ToArray(),
                Created = loadSettings.CreationDate == DateTime.MinValue ? (DateTime?)null : loadSettings.CreationDate
            });
        }
    }

    File.WriteAllText("index.json", JsonSerializer.Serialize(index, new JsonSerializerOptions { WriteIndented = true }));
}
```

A PDF without keywords returns `null` for `DocumentKeywords`, and one without a creation date `DateTime.MinValue`; the index turns them into an empty array and `null`. For keywords that help search, the blog article [Enhancing PDF Searchability in Large Repositories by Adding and Reading Keywords Using C# .NET](https://www.textcontrol.com/blog/2025/06/24/enhancing-pdf-searchability-in-large-repositories-by-adding-and-reading-keywords-using-csharp-dotnet/) suggests consistent tags and 5 to 10 keywords per document.

### Store Custom Properties

Data of your own, such as an invoice number, goes into the [UserDefinedDocumentProperties](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/documentsettings/userdefineddocumentproperties-property/llms-full.txt) of `DocumentSettings`, as [Set the Properties in Code](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/properties/#set-the-properties-in-code) shows. The TX Text Control format, RTF, DOC and DOCX save and load these properties, PDF doesn't, so keep such data in a DOCX version of the document or in an [attachment](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/attachments/llms-full.txt) of the PDF.

### Give an Accessible PDF Its Title

A PDF without a title fails PDF/UA validation, the check for accessible documents. TX Text Control writes the tagged structure of an accessible PDF since version 34.0, as [Create an Accessible PDF (PDF/UA)](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/creation-conversion/#create-an-accessible-pdf-pdf-ua) explains, and takes the title from `DocumentSettings.DocumentTitle`. The following handler asks the user for a missing title by opening a sidebar named `sidebarLeft`, declared as in [Show the Document Settings Panel](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/properties/#show-the-document-settings-panel), and saves only once there is one:

```csharp
private void saveAccessiblePdfButton_Click(object sender, RoutedEventArgs e)
{
    if (string.IsNullOrWhiteSpace(textControl1.DocumentSettings.DocumentTitle))
    {
        // Let the user enter the title first
        sidebarLeft.ContentLayout = TXTextControl.WPF.Sidebar.SidebarContentLayout.DocumentSettings;
        sidebarLeft.IsShown = true;
        MessageBox.Show(this, "Enter a title for the document, then save it again.");
        return;
    }

    textControl1.Save("invoice.pdf", StreamType.AdobePDF);
}
```

A complete check of the title and the descriptive texts of images and tables is built in the blog article [Preflighting PDF/UA Documents with TX Text Control in .NET C#](https://www.textcontrol.com/blog/2025/12/29/preflighting-pdf-ua-documents-with-tx-text-control-dotnet-csharp/).

### Read the Raw Metadata of a PDF

`LoadEmbeddedData` in the [PDFImportSettings](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/pdfimportsettings/enumeration/llms-full.txt) makes `Load` return the metadata as stored in the PDF file, through [LoadSettings.EmbeddedData](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/loadsettings/embeddeddata-property/llms-full.txt). Its keys are [EmbeddedDataFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/embeddeddataformat/enumeration/llms-full.txt) values, and `MetaData` is the one for metadata:

```csharp
private void showRawMetadataButton_Click(object sender, RoutedEventArgs e)
{
    LoadSettings loadSettings = new LoadSettings()
    {
        PDFImportSettings = PDFImportSettings.GenerateTextFrames | PDFImportSettings.LoadEmbeddedData
    };

    textControl1.Load("invoice.pdf", StreamType.AdobePDF, loadSettings);

    if (loadSettings.EmbeddedData != null &&
        loadSettings.EmbeddedData.TryGetValue(EmbeddedDataFormat.MetaData, out object metaData))
    {
        MessageBox.Show(this, metaData.ToString());
    }
}
```

`GenerateTextFrames` is the default import, so the editor shows the PDF as usual. `EmbeddedData` is filled only when `LoadEmbeddedData` is set, and only with the formats the PDF provides; [Text Extraction](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/text-extraction/llms-full.txt) uses the `TextCoordinates` entry.

### Next Steps

- [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/attachments/llms-full.txt): embed files with metadata of their own.
- [PDF/A](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/pdf-a/llms-full.txt): archive documents with their metadata.
- [Document Properties](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/properties/llms-full.txt): the document properties of every format and the DocumentSettings panel.
- [Loading Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/loading/llms-full.txt): the information `LoadSettings` returns for any format.

---

## Nearby

- **Previous:** [Text Extraction](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/text-extraction/llms-full.txt)
- **Next:** [Passwords and Access Permissions](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/pdf/passwords/llms-full.txt)
