JetsonPDF.PdfToTiffConverter
1.1.0
dotnet add package JetsonPDF.PdfToTiffConverter --version 1.1.0
NuGet\Install-Package JetsonPDF.PdfToTiffConverter -Version 1.1.0
<PackageReference Include="JetsonPDF.PdfToTiffConverter" Version="1.1.0" />
<PackageVersion Include="JetsonPDF.PdfToTiffConverter" Version="1.1.0" />
<PackageReference Include="JetsonPDF.PdfToTiffConverter" />
paket add JetsonPDF.PdfToTiffConverter --version 1.1.0
#r "nuget: JetsonPDF.PdfToTiffConverter, 1.1.0"
#:package JetsonPDF.PdfToTiffConverter@1.1.0
#addin nuget:?package=JetsonPDF.PdfToTiffConverter&version=1.1.0
#tool nuget:?package=JetsonPDF.PdfToTiffConverter&version=1.1.0
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
- Quick start
- Entry points
- PdfToTiffOptions
- Compression and color matrices
- Multi-page strategies
- Page filtering
- Progress reporting
- STA threading
- See also
- Limitations
- Targets
- License
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:
- Read. The PDF is parsed by
JetsonPDF.Readerinto aReadDocument. - Convert. Each
ReadPagebecomes a XAMLCanvasviaJetsonPDF.Wpf.PdfToXamlConverter(the same converter the WPF viewer sample uses). - Layout.
XamlReader.Parsematerialises the canvas; it's wrapped in aBorderso a solid background paints below the content (defaults to opaque white so transparent regions aren't black), thenMeasure/Arrangeruns at the page's MediaBox in DIPs. - Rasterise. A
RenderTargetBitmapat the requested DPI captures the tree into aPbgra32BitmapSource. - Encode. RGBA bytes flow into
JetsonPDF.Tiff.TiffWriter.Encode, producing a multi-frame TIFF inColor,Grayscale, orBlackAndWhiteperPdfToTiffOptions.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 throughstring.Format(CultureInfo.InvariantCulture, pattern, pageNumber). Example:"page-{0:D3}.tif"producespage-001.tif,page-002.tif, … - Otherwise,
-p001,-p002, … is inserted immediately before the extension. Example:"out.tif"producesout-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 alo-hirange (7-9). Inclusive on both ends. - Descending ranges (
9-7) throwFormatException. - 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 boundProgressBardoesn'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, andTiffImage(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. SamePdfToTiffOptions/TiffConversionProgresssurface, but rasterises withhtml2canvasinstead of WPF. No STA requirement, but limited to what the browser canvas can render.JetsonPDF.Wpf—PdfToXamlConverter(the layout pipeline this converter delegates to) andPdfToXamlOptions(the value passed throughPdfToTiffOptions.XamlOptions).JetsonPDF.Reader—Reader.Loadand theReadDocument/ReadPagetypes the stream-basedConvertAsyncexpects.
Limitations
- Windows-only. The converter targets
net8.0-windowsand 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
TiffWriterdoesn't ship encoders for these yet; passing them viaCompressionthrowsNotSupportedException. The reader can decode all of them, so round-tripping a CCITT-encoded TIFF through read → re-encode currently requires pickingDeflateorPackBitsfor the second pass. UseBlackAndWhite+PackBitsfor the closest approximation of a CCITT-G4 fax workflow. - PDF fidelity matches the WPF viewer. Anything the WPF
PdfToXamlConverterdoesn'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.
BackgroundArgbpaints a uniform brush; gradient or patterned backgrounds aren't exposed. Drop down toRenderPageAsync+ your own composition if you need more. RenderPageAsyncreturns full-colourPbgra32. It bypasses theColorModedown-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 | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 is compatible. net9.0-windows was computed. net10.0-windows was computed. |
-
net8.0-windows7.0
- JetsonPDF.Common (>= 1.1.0)
- JetsonPDF.Reader (>= 1.1.0)
- JetsonPDF.Tiff (>= 1.1.0)
- JetsonPDF.Wpf (>= 1.1.0)
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 |