TX Text Control .NET Server

Creating Documents

Topic

Before a document has any content, it has a ServerTextControl instance and an empty page in US letter format. You create and dispose instances correctly in console applications and ASP.NET Core, set the page format of a new document, assemble content from text, HTML snippets and other documents, store document properties and make sure the fonts are available on the server.

Create a Document walks through inserting formatted text, a table and a header. Character formatting is covered in Text and paragraph formatting in Paragraphs. Input files of the console applications below are in a Documents folder that is copied to the output directory.

Create and Dispose Instances

Every piece of document processing code follows the same lifecycle:

  1. Create the instance with the ServerTextControl constructor.
  2. Initialize it with Create before you use any other member. Create returns true if the instance could be initialized and false if it couldn't. IsCreated tells you later whether the instance is completely created.
  3. Work with the document, then dispose the instance. A using statement releases its resources as soon as the block ends.
using TXTextControl;

using (ServerTextControl tx = new ServerTextControl())
{
    // Create returns false if the instance couldn't be initialized
    if (!tx.Create())
    {
        throw new InvalidOperationException("ServerTextControl could not be created.");
    }

    tx.Text = "This document was created with ServerTextControl.";
    tx.Save("created.docx", StreamType.WordprocessingML);
}

If Create fails and the instance is used anyway, its members throw the error "The TXTextControl object must have been completely loaded to use this method." On Windows, Create fails most often because no new window handle can be created, usually because instances weren't disposed. ResetContents deletes the entire contents of an instance; Clear, in contrast, deletes only the selected text or the character right of the input position.

In an ASP.NET Core application, create one instance inside the action or service method that produces the document, as the Save as DOCX and PDF tutorial does. TX Text Control is thread safe, but it uses critical sections for shared resources, so threads that use it can wait for each other. Performance and Scalability describes how to process many documents in parallel.

Set the Page Format of a New Document

A new document has one section with US letter pages (8.5 x 11 inches), page margins of 1 inch and the font Arial at 10 pt. ServerTextControl.PageSize and PageMargins are measured in the unit of PageUnit, which is 1/100 inch by default. The following program prints the default format and then changes the margins and the orientation of the document:

using TXTextControl;

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

    // US letter with 1-inch margins, in 1/100 inch
    Console.WriteLine($"Page size: {tx.PageSize.Width} x {tx.PageSize.Height}");
    Console.WriteLine($"Margins: {tx.PageMargins.Left}, {tx.PageMargins.Top}, {tx.PageMargins.Right}, {tx.PageMargins.Bottom}");

    // Margins of 0.5 inch on every side and landscape orientation
    tx.PageMargins = new PageMargins(50, 50, 50, 50);
    tx.Landscape = true;

    tx.Text = "This document uses landscape pages with narrow margins.";

    tx.Save("landscape.pdf", StreamType.AdobePDF);
}

The code works as follows:

A document whose parts need different page formats, such as a landscape page in a portrait report, is divided into sections, which Sections describes.

Build a Document From Pieces

Documents are rarely typed in one go. The following program builds a report from a heading and a paragraph and appends an HTML snippet:

using TXTextControl;

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

    // Prepare text and formatting in a Selection object, then insert it in one step
    tx.Selection = new Selection()
    {
        Text = "Quarterly Report\r\n",
        FontName = "Arial",
        FontSize = 480, // 24 pt
        Bold = true
    };

    tx.Selection = new Selection()
    {
        Text = "Revenue grew in all regions this quarter.\r\n",
        FontName = "Arial",
        FontSize = 240 // 12 pt
    };

    // Append an HTML snippet in a new paragraph at the end of the document
    tx.Append("<p>Prepared by the <strong>reporting service</strong>.</p>",
        StringStreamType.HTMLFormat,
        AppendSettings.StartWithNewParagraph);

    tx.Save("report.docx", StreamType.WordprocessingML);
}

The code works as follows:

  • Assigning a prepared Selection object inserts its text with all its attributes at the input position. This is faster than inserting text and formatting it afterward, as the blog article Speed Up Document Generation by Factor 2 Using Selection Objects measures.
  • Append adds a document to the end of the existing content. It loads from a file, a byte array or a string, like Load, but doesn't replace what is already there.

The last parameter of Append is a value of AppendSettings:

ValueThe appended document starts
NoneAt the end of the last paragraph
StartWithNewParagraphIn a new paragraph at the end of the document
StartWithNewSectionIn a new section at the end of the document

To put a document in place of a placeholder or at the input position instead of at the end, use Selection.Load, as Load, Append or Insert shows.

Combine Several Documents

To combine documents such as a cover page and several chapters, load the first one and append the others. The following program starts each document in a new section and saves the result as one PDF:

using TXTextControl;

string[] files =
{
    "Documents/cover.docx",
    "Documents/chapter1.docx",
    "Documents/chapter2.docx"
};

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

    // The first document replaces the empty contents
    tx.Load(files[0], StreamType.WordprocessingML);

    // Every further document is appended in a new section
    for (int i = 1; i < files.Length; i++)
    {
        tx.Append(files[i], StreamType.WordprocessingML, AppendSettings.StartWithNewSection);
    }

    Console.WriteLine($"Sections: {tx.Sections.Count}, pages: {tx.Pages}");

    tx.Save("combined.pdf", StreamType.AdobePDF);
}

Documents that come from a database are appended from a byte array in the same way: tx.Append(bytes, BinaryStreamType.WordprocessingML, AppendSettings.StartWithNewSection);. Loading Documents compares Load, Append and Selection.Load in more detail.

Store Document Properties

ServerTextControl.DocumentSettings holds the title, author, subject, keywords and user-defined properties of a new or loaded document, and Save stores them with the document, for example tx.DocumentSettings.DocumentTitle = "Quarterly Report";. Document Metadata describes how DocumentSettings, SaveSettings and LoadSettings work together, and Document Properties in the Document Editor section lists which formats store which properties.

Make Fonts Available on the Server

A document looks the same on every server only if the fonts it uses are available there. The Core engine uses the fonts of the Fonts folder that its NuGet package adds to your application, not the fonts installed on the machine, and the Classic engine uses the fonts installed on Windows; Fonts in the Deployment Guide describes the folder, the fonts it contains and how to add your own.

When a font of a document isn't available, TX Text Control replaces it. To list the available fonts and find out which fonts were replaced, call GetSupportedFonts and handle the AdaptFont event:

using TXTextControl;

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

    string[] fonts = tx.GetSupportedFonts();

    if (fonts != null)
    {
        Console.WriteLine($"{fonts.Length} fonts available");
    }

    // Report every font that isn't available and its replacement
    tx.FontSettings.AdaptFontEvent = true;
    tx.AdaptFont += (sender, e) =>
        Console.WriteLine($"{e.FontName} replaced with {e.AdaptedFontName}");

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

GetSupportedFonts returns the names of the fonts that are available. AdaptFont occurs only when FontSettings.AdaptFontEvent is true; its default is false, so set it before you load the document. In the event arguments, FontName is the original font and AdaptedFontName the font that replaces it. To choose the replacement yourself or to allow only certain kinds of fonts, see Use the Right Fonts in PDF Creation. Fonts in the Troubleshooting section helps when text looks different than expected.

Next Steps