Table of Contents

Conversion options

Everything optional about a conversion lives on ConvertOptions. Pass null, or leave it out, for the defaults. Each conversion reads its options once, at the start, so use a fresh object per call rather than changing a shared one.

Pages, metadata and progress

This converts pages 1 and 3 of a report, stamps PDF metadata and prints each stage as it happens:

using DocWright;
using DocWright.Core.Primitives;

var options = new ConvertOptions
{
    Pages = PageRange.Parse("1,3"),          // print-dialog syntax: "1-3,7,12-"
    Progress = new StageLogger(),
};

// Metadata is get-only: set its properties rather than replacing it.
options.Metadata.Title = "Quarterly line report";
options.Metadata.Author = "Finance";
options.Metadata.Subject = "Q3 2026";
options.Metadata.CreationDate = new DateTimeOffset(2026, 10, 1, 9, 0, 0, TimeSpan.Zero);

using (FileStream input = File.OpenRead("quarterly-report.docx"))
using (FileStream output = File.Create("pages-1-and-3.pdf"))
{
    ConversionResult result = converter.Convert(input, output, options);
    Console.WriteLine($"Wrote {result.PageCount} page(s).");
}

The progress reporter used above:

/// <summary>Prints each stage once. Reports arrive on the converting thread, in order.</summary>
internal sealed class StageLogger : IProgress<ConversionProgress>
{
    private ConversionStage? last;

    public void Report(ConversionProgress value)
    {
        if (value.Stage != this.last)
        {
            this.last = value.Stage;
            string pages = value.HasPageProgress ? $" ({value.PagesCompleted}/{value.PagesTotal} pages)" : "";
            Console.WriteLine($"{value.Stage}{pages}");
        }
    }
}

Output

Preparing
ReadingDocument
ResolvingDocument
LayingOutDocument
RenderingPages (0/2 pages)
Completed (2/2 pages)
Wrote 2 page(s).
Tip

System.Progress<T> posts each report to the thread pool, so in a console app its lines can print after the conversion returns, or out of order. Implement IProgress<ConversionProgress> yourself, as above, when order matters. In a UI app, Progress<T> is what you want: it reports on the UI thread.

Every option

Option Default Meaning
Pages PageRange.All Which pages to render. PageRange.Parse accepts print-dialog syntax: "1-3,7,12-".
SourceFormat Auto What the input is. Required for plain text, which is never detected, and advisable for Markdown.
Metadata empty PDF Title, Author, Subject, Keywords, Creator, Producer, CreationDate and Conformance (PDF/A). Get-only: set its properties.
Limits safe defaults Caps on size, time, pages, memory and nesting. See Hardening untrusted input.
Diagnostics null Where warnings about degraded content go. See Diagnostics and strict mode.
Progress null Stage and page-count callbacks.
StrictMode false Throw UnsupportedFeatureException instead of rendering a degraded result.
Password null Opens an encrypted document or PDF. See Encryption.
TaggedPdf false Write a structure tree for assistive technology. See PDF/A and tagged PDF.
DefaultLanguage null The PDF language when the document declares none, for example "en-GB".
FontDirectories, FontFallbackChain, ScriptFallbackFonts empty Font sources and substitutes. See Fonts and complex scripts.
WarnOnFontSubstitution, FailOnFontSubstitution false Report, or refuse, font substitutions.
TextShaper null A text shaper for complex scripts, such as HarfBuzzTextShaper.
RenderRevisions false Reserved: drawing revision marks is not implemented yet. Revisions are always applied.

Deterministic by default

DocWright writes no timestamp unless you set Metadata.CreationDate. The same input and options therefore give byte-identical output on every machine, which makes PDFs easy to cache, hash and test. Set the date when you want it recorded.

Telling DocWright what the input is

Convert, ConvertAsync and ConvertToImages detect DOCX, DOC, RTF and HTML from their content. Markdown has only a weak signature and plain text has none, so name them:

using DocWright;
using DocWright.Core.Primitives;

// Markdown's signature is weak and plain text has none: say what the input is.
using (FileStream input = File.OpenRead("article.md"))
using (FileStream output = File.Create("article.pdf"))
{
    converter.Convert(input, output, new ConvertOptions { SourceFormat = FormatDetection.Markdown });
}
article.md → article.pdf
A Markdown article rendered to PDF with headings, paragraphs and a list

Load takes the format as its second argument instead: converter.Load(stream, FormatDetection.Text).

Things that follow the document, not an option

  • Hidden text is never rendered. Text marked hidden in Word takes no space and is left out of the PDF entirely, including the PDF's extractable text, so hidden notes and prices can't leak. GetText() and the text exports still include it, because it is still in the document.
  • East Asian line breaking follows the document's compatibility mode, as it does in Word. To get Word 2013's rules for an older document, set document.Settings.CompatibilityMode = 15 before converting.