JetsonPDF.PdfToTiffConverter 1.1.0

dotnet add package JetsonPDF.PdfToTiffConverter --version 1.1.0
                    
NuGet\Install-Package JetsonPDF.PdfToTiffConverter -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JetsonPDF.PdfToTiffConverter" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JetsonPDF.PdfToTiffConverter" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="JetsonPDF.PdfToTiffConverter" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JetsonPDF.PdfToTiffConverter --version 1.1.0
                    
#r "nuget: JetsonPDF.PdfToTiffConverter, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JetsonPDF.PdfToTiffConverter@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JetsonPDF.PdfToTiffConverter&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=JetsonPDF.PdfToTiffConverter&version=1.1.0
                    
Install as a Cake Tool

JetsonPDF.PdfToTiffConverter

Rasterises a parsed JetsonPDF document into a multipage TIFF by driving the real WPF layout/render path. Each ReadPage is converted to XAML through JetsonPDF.Wpf.PdfToXamlConverter, parsed with XamlReader.Parse, measured/arranged at its MediaBox in device-independent pixels, and captured by RenderTargetBitmap at the requested DPI. The RGBA bytes are then fed to the managed JetsonPDF.Tiff.TiffWriter — no GDI+ / System.Drawing / TiffBitmapEncoder involved.

PDF bytes  ─►  JetsonPDF.Reader  ─►  ReadDocument
                                          │
                                          ▼
                            JetsonPDF.Wpf PdfToXamlConverter
                                          │
                                          ▼
                              XamlReader.Parse (live WPF tree)
                                          │
                                          ▼
                              RenderTargetBitmap (per page)
                                          │
                                          ▼
                              JetsonPDF.Tiff TiffWriter (multi-frame TIFF)
using JetsonPDF.Tiff;

await PdfToTiffConverter.ConvertToFileAsync(
    "input.pdf",
    "output.tif",
    new PdfToTiffOptions { Dpi = 200 });

Contents


Overview

JetsonPDF.PdfToTiffConverter is the WPF-hosted rasteriser in the JetsonPDF family. It exists so any PDF that the WPF viewer can render — vector content, embedded fonts, gradients, images, transparency, form widgets — round-trips out as a multipage TIFF without a separate rasterisation engine. Because the output goes through the same WPF tree as the on-screen viewer, anything visible on a PdfToXamlConverter canvas will appear in the TIFF.

How it works:

  1. Read. The PDF is parsed by JetsonPDF.Reader into a ReadDocument.
  2. Convert. Each ReadPage becomes a XAML Canvas via JetsonPDF.Wpf.PdfToXamlConverter (the same converter the WPF viewer sample uses).
  3. Layout. XamlReader.Parse materialises the canvas; it's wrapped in a Border so a solid background paints below the content (defaults to opaque white so transparent regions aren't black), then Measure / Arrange runs at the page's MediaBox in DIPs.
  4. Rasterise. A RenderTargetBitmap at the requested DPI captures the tree into a Pbgra32 BitmapSource.
  5. Encode. RGBA bytes flow into JetsonPDF.Tiff.TiffWriter.Encode, producing a multi-frame TIFF in Color, Grayscale, or BlackAndWhite per PdfToTiffOptions.ColorMode.

WPF rendering requires an STA thread. The converter throws InvalidOperationException if invoked from MTA — see STA threading for how to satisfy this from a console host.

Quick start

Add a project reference to JetsonPDF.PdfToTiffConverter, then:

using JetsonPDF.Tiff;

// Synchronous (typical from STA WPF code):
PdfToTiffConverter.ConvertToFile(
    "input.pdf",
    "output.tif",
    new PdfToTiffOptions
    {
        Dpi = 300,
        Compression = TiffCompression.Deflate,
        ColorMode = TiffColorMode.Color,
    });

// Async:
await PdfToTiffConverter.ConvertToFileAsync(
    "input.pdf",
    "output.tif",
    new PdfToTiffOptions { Dpi = 200 });

For a stream-based pipeline with a pre-parsed document:

using JetsonPDF.Reading;
using JetsonPDF.Tiff;

ReadDocument doc = Reader.Load("input.pdf");
using FileStream output = File.Create("output.tif");
await PdfToTiffConverter.ConvertAsync(doc, output, new PdfToTiffOptions
{
    Dpi = 150,
    ColorMode = TiffColorMode.Grayscale,
});

Entry points

Member Signature (return type omitted) Use when
ConvertToFile (string pdfPath, string tiffPath, PdfToTiffOptions? options, IProgress<TiffConversionProgress>? progress) You have a PDF path and want a TIFF file. Synchronous; safe to call from STA.
ConvertToFileAsync same parameters Awaitable form of ConvertToFile. Underlying XAML conversion is synchronous on WPF — awaiting is mostly for cooperative non-blocking.
ConvertAsync (ReadDocument document, Stream output, PdfToTiffOptions? options, IProgress<TiffConversionProgress>? progress) The document is already parsed, or the destination is a non-file stream (memory, pipe, network). The stream is not closed by the method. Rejects OneTiffPerPage because it can't synthesise per-page paths.
RenderPageAsync (ReadPage page, PdfToTiffOptions? options) → Task<BitmapSource> You want a single page as a frozen Pbgra32 BitmapSource to feed a different encoder (PNG per page, in-memory thumbnail strip, paginated image control). ColorMode is not applied — the writer would have applied it; here you get full colour.

All four methods accept the same PdfToTiffOptions. The null default yields the defaults documented below.

PdfToTiffOptions

Property Type Default Notes
Dpi double 150 Output raster resolution. Pixel size per page is ceil(pageWidthPoints * Dpi / 72) by ceil(pageHeightPoints * Dpi / 72). Must be positive; otherwise ArgumentOutOfRangeException.
Compression TiffCompression Deflate TIFF frame compression. See Compression and color matrices.
ColorMode TiffColorMode Color Per-frame pixel format. See same section. Conversion from the always-rendered full-colour bitmap is done by the managed writer.
BlackAndWhiteThreshold int 128 Luminance cutoff (0..255) used when ColorMode is BlackAndWhite. Pixels with luminance below this become black.
MultipageStrategy TiffMultipageStrategy SingleMultiPage One TIFF with N frames, or N single-page TIFFs. See Multi-page strategies.
Pages IReadOnlyList<int>? null 1-based page numbers to include, in order. null or empty means all pages. Out-of-range entries throw. See Page filtering.
BackgroundArgb string? "#FFFFFFFF" Page background painted before PDF content so transparent regions don't show through as TIFF's default black. Parsed by ColorConverter.ConvertFromString. Set to null to disable the fill.
RowsPerStrip int 64 Approximate rows per TIFF strip. 0 puts the whole page in a single strip.
XamlOptions PdfToXamlOptions? null Forwarded to the underlying PdfToXamlConverter. Use this to tune the XAML conversion (font fallbacks, etc.).

PdfToTiffOptions is an init-only record-like class — set every property in the object initialiser; instances are effectively immutable after construction.

Compression and color matrices

Compression

TiffCompression value Status Notes
None Supported Uncompressed; largest files.
PackBits Supported Simple RLE; modest gains on scanned/B&W content. Round-trips cleanly through the managed reader.
Deflate Supported (default) Modern lossless, browser-friendly, smallest among the lossless options for most natural-image pages.
AdobeDeflate Supported Identical compressed payload to Deflate; different TIFF tag value (8 vs. 32946). Pick this if a consumer specifically expects Adobe's tag.
CcittGroup3Fax, CcittGroup4Fax, Lzw, Jpeg, OldJpeg Not yet supported on write The managed reader can decode them; no managed encoder ships yet. Requesting one throws NotSupportedException from TiffWriter.

Color modes

TiffColorMode Output When to use
Color (default) 24-bit RGB General-purpose. Faithful colour reproduction of vector content, gradients, embedded images.
Grayscale 8-bit BlackIsZero, ITU-R BT.601 luminance Text-heavy / monochrome originals where colour is unnecessary; ~⅓ the size of Color.
BlackAndWhite 1-bit BlackIsZero Scanned-document / fax workflows. Threshold-driven (see BlackAndWhiteThreshold). Use with PackBits for predictable size; CCITT-G4 would be smaller still but isn't encoded yet (see above).

Rendering is always done in full colour (Pbgra32) by WPF; the managed writer performs the down-conversion when packing the frame, so re-running with a different ColorMode doesn't require re-rendering on your side if you've cached BitmapSources from RenderPageAsync.

Multi-page strategies

TiffMultipageStrategy selects between two outputs:

SingleMultiPage (default)

One TIFF file (or stream) containing N IFD entries — one per selected page. Most TIFF viewers and editors handle multi-frame TIFFs natively. Use this when downstream tooling expects "one document, one file."

PdfToTiffConverter.ConvertToFile("doc.pdf", "doc.tif",
    new PdfToTiffOptions { MultipageStrategy = TiffMultipageStrategy.SingleMultiPage });

OneTiffPerPage

N separate TIFFs, one per selected page. Only valid on the file-path entry points (ConvertToFile / ConvertToFileAsync) — the stream-based ConvertAsync can't synthesise per-page destinations and throws if you pass this strategy.

The tiffPath argument is treated as a filename pattern:

  • If it contains a {0} composite-format token, it's passed through string.Format(CultureInfo.InvariantCulture, pattern, pageNumber). Example: "page-{0:D3}.tif" produces page-001.tif, page-002.tif, …
  • Otherwise, -p001, -p002, … is inserted immediately before the extension. Example: "out.tif" produces out-p001.tif, out-p002.tif, …
PdfToTiffConverter.ConvertToFile(
    "doc.pdf",
    @"C:\out\page-{0:D3}.tif",
    new PdfToTiffOptions { MultipageStrategy = TiffMultipageStrategy.OneTiffPerPage });
// → C:\out\page-001.tif, C:\out\page-002.tif, ...

Parent directories are created automatically.

Page filtering

PdfToTiffOptions.Pages is an ordered list of 1-based page numbers. The output frames appear in the order given — duplicates and reordering are allowed.

new PdfToTiffOptions
{
    // First the cover, then pages 3 through 5, then page 1 again.
    Pages = new[] { 1, 3, 4, 5, 1 },
}

For string-spec inputs (CLI args, config files), use ParsePageRange:

int[] pages = PdfToTiffOptions.ParsePageRange("1-3,5,7-9");
// → { 1, 2, 3, 5, 7, 8, 9 }

new PdfToTiffOptions { Pages = pages };

Spec syntax:

  • Comma-separated entries; whitespace inside an entry is ignored.
  • Each entry is either a single 1-based number (5) or a lo-hi range (7-9). Inclusive on both ends.
  • Descending ranges (9-7) throw FormatException.
  • Non-numeric or zero/negative entries throw FormatException.
  • Duplicates are preserved: "1,1" emits page 1 twice.

Out-of-range page numbers (greater than document.Pages.Count) throw ArgumentOutOfRangeException from the converter itself, not from ParsePageRange.

Progress reporting

Every entry point accepts an optional IProgress<TiffConversionProgress> sink. The converter fires a report at each phase transition:

Stage When
TiffConversionStage.Starting Once, before any page work.
TiffConversionStage.ConvertingXaml Per page, before PdfToXamlConverter runs.
TiffConversionStage.Rendering Per page, after the XAML is parsed and Measure/Arrange begin.
TiffConversionStage.Encoding Per frame, as the managed TiffWriter packs it into the output.
TiffConversionStage.Completed Once, after everything is written.

TiffConversionProgress exposes:

  • CompletedPages / TotalPages — raw page counters.
  • CurrentPage — 1-based page being rasterised (render stages) or frame being encoded.
  • Stage — the enum above.
  • Fraction — a smooth [0, 1] value weighted 0.9 render / 0.1 encode, so a bound ProgressBar doesn't jump a whole page at a time.
  • Description — a ready-to-bind status string ("Rendering page 3 of 12…").

Binding to a WPF ProgressBar + TextBlock:

var progress = new Progress<TiffConversionProgress>(p =>
{
    progressBar.Value = p.Fraction * 100;
    statusLabel.Text  = p.Description;
});

await PdfToTiffConverter.ConvertToFileAsync(
    "input.pdf", "output.tif", new PdfToTiffOptions { Dpi = 200 }, progress);

Progress<T> marshals callbacks back to the captured SynchronizationContext, so updates land on the UI thread automatically when the call is launched from one.

STA threading

The converter drives the live WPF render pipeline (Measure, Arrange, RenderTargetBitmap). WPF requires those calls run on an STA thread; the converter checks Thread.CurrentThread.GetApartmentState() inside the encode loop and throws InvalidOperationException on MTA.

From a WPF application

Application.Run already runs on STA. Just call the converter from any UI-thread context — a click handler, Task.Run is not appropriate here because it dispatches to the thread pool (MTA).

From a console application

Mark Main with [STAThread]:

using System.Threading;
using JetsonPDF.Tiff;

internal static class Program
{
    [STAThread]
    private static int Main(string[] args)
    {
        PdfToTiffConverter.ConvertToFile("input.pdf", "output.tif",
            new PdfToTiffOptions { Dpi = 200 });
        return 0;
    }
}

From an MTA host (ASP.NET background worker, generic-host service, …)

Marshal onto a dedicated STA thread:

void ConvertOnSta(string pdfPath, string tiffPath)
{
    Exception? error = null;
    var t = new Thread(() =>
    {
        try
        {
            PdfToTiffConverter.ConvertToFile(pdfPath, tiffPath,
                new PdfToTiffOptions { Dpi = 200 });
        }
        catch (Exception ex) { error = ex; }
    });
    t.SetApartmentState(ApartmentState.STA);
    t.Start();
    t.Join();
    if (error is not null) throw error;
}

Thread.SetApartmentState must be called before Start. A Task-based or pool-based dispatch is not sufficient because pool threads are MTA.

See also

  • JetsonPDF.Tiff — the managed TIFF reader/writer this package encodes through. TiffCompression, TiffWriteOptions, TiffWriter, and TiffImage (decode side) live there. Useful directly when you need to read or transform existing TIFFs without going through the PDF path.
  • JetsonPDF.OpenSilver.PdfToTiffBrowserConverter — the browser-side (WebAssembly) equivalent. Same PdfToTiffOptions / TiffConversionProgress surface, but rasterises with html2canvas instead of WPF. No STA requirement, but limited to what the browser canvas can render.
  • JetsonPDF.WpfPdfToXamlConverter (the layout pipeline this converter delegates to) and PdfToXamlOptions (the value passed through PdfToTiffOptions.XamlOptions).
  • JetsonPDF.ReaderReader.Load and the ReadDocument / ReadPage types the stream-based ConvertAsync expects.

Limitations

  • Windows-only. The converter targets net8.0-windows and depends on WPF (UseWPF=true). It will not load on Linux/macOS .NET runtimes.
  • STA only. Calls from an MTA thread throw immediately. See STA threading.
  • CCITT-G3 / CCITT-G4 / LZW / JPEG / OldJpeg compression on write. The managed TiffWriter doesn't ship encoders for these yet; passing them via Compression throws NotSupportedException. The reader can decode all of them, so round-tripping a CCITT-encoded TIFF through read → re-encode currently requires picking Deflate or PackBits for the second pass. Use BlackAndWhite + PackBits for the closest approximation of a CCITT-G4 fax workflow.
  • PDF fidelity matches the WPF viewer. Anything the WPF PdfToXamlConverter doesn't surface (rare colour spaces, specific shading edge cases, non-standard interactive features) won't appear in the TIFF either. The TIFF is a faithful snapshot of what the viewer sample would display.
  • Background fill is a solid colour. BackgroundArgb paints a uniform brush; gradient or patterned backgrounds aren't exposed. Drop down to RenderPageAsync + your own composition if you need more.
  • RenderPageAsync returns full-colour Pbgra32. It bypasses the ColorMode down-conversion the writer would have done — that step is performed by the encoder, not the renderer. Apply your own conversion if you need a non-RGB single-page bitmap.

Targets

  • net8.0-windows

License

MIT.

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 113 6/6/2026
1.0.0 107 5/23/2026
0.2.0-preview 102 5/23/2026