The catalog's /ViewerPreferences dictionary (ISO 32000-2 12.2, Table 147) tells a viewer how to open the file and what its print dialog
starts with. OnePDF reads and writes it; it never enforces it. Viewers treat every entry as a hint.
Happy path
using var doc = PdfDocument.Open("in.pdf", new PdfOpenOptions { AllowEditing = true }); doc.SetPrintPreferences(PdfPrintScaling.None, PdfDuplex.DuplexFlipLongEdge, copies: 2); doc.Save("out.pdf"); // or doc.SaveIncremental(stream)
For a new document, pass the same values through the writer:
var options = new PdfDocumentWriterOptions { ViewerPreferences = PdfViewerPreferences.ForPrint(PdfPrintScaling.None, PdfDuplex.Simplex, copies: 1), };
The typed model
PdfViewerPreferences has one nullable property per entry. Null means absent: it is not written, and when applied to an existing
document it leaves the existing entry alone.
| Property | Entry | Values |
|---|---|---|
PrintScaling | /PrintScaling | None, AppDefault |
Duplex | /Duplex | Simplex, DuplexFlipShortEdge, DuplexFlipLongEdge |
PrintPageRange | /PrintPageRange | list of PdfPrintPageRange(FirstPage, LastPage) |
NumCopies | /NumCopies | integer ≥ 1 |
PickTrayByPdfSize | /PickTrayByPDFSize | bool |
PrintArea, PrintClip, ViewArea, ViewClip | same names | PdfViewerBox: MediaBox, CropBox, BleedBox, TrimBox, ArtBox |
DisplayDocTitle, HideToolbar, HideMenubar, HideWindowUI, FitWindow, CenterWindow | same names | bool |
- Page ranges are one-based and inclusive, exactly as stored: Table 147 numbers the first page 1 and stores the ranges as a flat
array of integer pairs (
[1 1 3 3]is page 1 and page 3). This differs from the zero-baseddoc.Pagesindex on purpose, so a file dump matches what you wrote. Ranges must be ascending and must not overlap. PrintArea,PrintClip,ViewAreaandViewClipare deprecated in PDF 2.0. They are still read and written, and most viewers ignore them.doc.ViewerPreferencesreads the dictionary (null when the catalog has none);.Dictionaryon the result is the raw dictionary with every entry, including ones not modelled here. Editing never drops entries it doesn't know (/Direction,/Enforce, extensions).PdfDocumentWriterOptions.DisplayDocumentTitlestill works; an explicitViewerPreferences.DisplayDocTitlewins over it. The PDF/UA preparer setsDisplayDocTitlein the same dictionary and leaves the print entries alone.
Errors and leniency
- Writing (
SetViewerPreferences,SetPrintPreferences, the writer option):NumCopiesbelow 1, an empty, reversed, overlapping, descending or out-of-range page range (beyond the page count) or an undefined enum value throwsArgumentException, and nothing is changed. The writer reports it fromFinish, where the page count is known. - Reading: a value of the wrong type, an unknown name or a malformed range is left null and recorded as a warning in
doc.Diagnostics; nothing is thrown (underPdfOpenOptions.Stricta warning is an error, as everywhere). - Editing needs
PdfOpenOptions.AllowEditing; otherwise the setters throwInvalidOperationException.