Converting documents
Loading
| Class | Loaders |
|---|---|
PsDocument (PostScript and EPS) |
FromFile, FromBytes, FromStream, each with an overload that takes a CancellationToken |
XpsDocument |
FromFile, FromBytes, FromStream, each with a token overload |
The document type is the input format, so you choose between PsDocument and XpsDocument
yourself.
using XRay.PS;
using XRay.PS.PostScript;
using XRay.PS.Xps;
byte[] fromPs = PsDocument.FromFile("drawing.ps").ToPdf();
byte[] fromXps = XpsDocument.FromFile("report.xps").ToPdf(maxPages: 50);
// Straight into a stream, so a large PDF never exists as one array.
using var file = File.Create("drawing.pdf");
PsDocument.FromFile("drawing.ps").ToPdf(file, new PdfSaveOptions { JpegQuality = 75 }, token);
PdfSaveOptions:
| Option | Effect |
|---|---|
NoCompression |
Write content streams uncompressed, for inspection. |
AdditionalFontsFolder |
A folder of extra TrueType or OpenType fonts consulted before system fonts. |
JpegQuality |
Re-encode embedded raw 8-bit gray and RGB images as JPEG at this quality (1 to 100) when that is smaller than the deflated pixels. null passes images through unchanged. Masks, CMYK and already compressed images are never touched. |
MaskRasterizer |
XPS only: the rasteriser for opacity-masked content. The managed one when null; a SkiaRasterWriter for Skia. |
SuppressErrors, Warnings |
Recover from errors, see Limits and recovery. |
Limits |
Ceilings on a PostScript job. |
The PDF writer builds each object lazily and writes it in object-number order, keeping only the cross-reference offsets in memory. The render model itself stays in memory.
Images
using XRay.PS;
using XRay.PS.PostScript;
using XRay.PS.Xps;
var options = new ImageSaveOptions(ImageFormat.Png, dpi: 150) { OpaqueBackground = true };
byte[] firstPage = PsDocument.FromFile("drawing.ps").ToImage(options);
var xps = XpsDocument.FromFile("report.xps");
List<byte[]> pages = xps.ToImages(options);
// One stream per page, opened just before that page is written.
xps.ToImages(options, page => File.Create($"page{page + 1}.png"), maxPages: null, cancellationToken: token);
// The first page into a stream.
using var single = File.Create("first.png");
xps.ToImage(options, single, cancellationToken: token);
ToImage converts the first page; ToImages converts every page. For PostScript, the
ToImages(options, streamForPage, token) overload takes the page index from zero.
ImageSaveOptions:
| Option | Default | Effect |
|---|---|---|
Format |
Png |
Png, Jpeg, Bmp or Tiff. ImageSaveOptions.ParseFormat("jpg") parses a name. |
Dpi |
96 | Output resolution. |
OpaqueBackground |
false |
Paint a white background; PNG is transparent otherwise. |
PreserveFractionalPageSize |
false |
Keep fractional page sizes instead of snapping to whole pixels. |
JpegQuality |
null |
1 to 100; the writer's default when null (75 for the managed writer, 80 for the Skia writer). |
RasterWriter |
null |
A custom IRasterWriter; the managed renderer when null. |
AdditionalFontsFolder |
null |
Extra fonts folder. |
SuppressErrors, Warnings, Limits |
See Limits and recovery. Limits.MaxMemoryBytes also caps the page's pixel buffer, which is 4 GiB when no limits are set. |
PNG is encoded straight into the output stream. The JPEG, BMP and TIFF encoders need the whole image, so those formats are encoded in memory first and then written.
Fonts
Standard PostScript font names resolve to the bundled Liberation Serif and Dingbats fonts or to
fonts installed on the system. Set AdditionalFontsFolder on the save options to add a folder.
The render model
BuildRenderModel returns the page content both input kinds are converted into before they are
written, for code that wants to inspect it or write it somewhere else. PsDocument also takes
PsInterpreterLimits and a suppress-errors flag in an overload.
Building and editing documents
PsDocument.Create, AddPage, InsertPage, RemovePage, GetPage(i).Canvas and Save()
write PostScript or EPS; GetXmp, SetXmp and RemoveXmp handle XMP metadata.
XpsDocument.Create, AddPage, InsertPage, RemovePage, Save() and the print ticket methods
do the same for XPS. ImageToEps.Convert and ConvertFile wrap a raster image in EPS, with
overloads that write to a stream.
Skia raster output
The core raster renderer is managed. For PostScript and EPS it reproduces, pixel for pixel, the pure
Python renderer of the original library: identical on all 400 convertible inputs. The original's
default writer is Skia, though, and its output differs slightly from the managed one: anti-aliasing,
glyph rasterisation, gradients and image resampling. X-Ray.PS.Skia provides SkiaRasterWriter,
which draws the same render model with Skia and reproduces the original's default output.
using XRay.PS;
using XRay.PS.PostScript;
using XRay.PS.Skia;
using XRay.PS.Xps;
var options = new ImageSaveOptions(ImageFormat.Png, dpi: 150) { RasterWriter = new SkiaRasterWriter() };
byte[] png = PsDocument.FromFile("input.ps").ToImage(options);
var xps = XpsDocument.FromFile("input.xps");
List<byte[]> pages = xps.ToImages(options);
// XPS opacity masks are rasterized while building the PDF; Skia can do that too.
byte[] pdf = xps.ToPdf(new PdfSaveOptions { MaskRasterizer = new SkiaRasterWriter() });
Against the original's Skia output, the Skia writer was identical on 398 of 400 PostScript inputs (largest mean difference 0.005), and on XPS 74 of 85 pages were identical and 84 of 85 within 1% of pixels. The managed writer on XPS pages with images is further off, because the original needs Skia for XPS images. Use the Skia writer when XPS raster output matters.
PNG and JPEG are drawn with Skia. TIFF and BMP output, and documents whose images Skia cannot take safely (1-pixel images, CCITT data, samples other than 8 bits, full-page soft masks), fall back to the managed renderer. A writer instance keeps no state between calls and can be shared.
On Linux, also reference a SkiaSharp native asset package, for example
SkiaSharp.NativeAssets.Linux.NoDependencies.
Differences from the Python original
- JPEG XR images are not decoded.
- ICC-profile colours in XPS (
ContextColor) use the original's fallback formula. - Cancellation, stream outputs, interpreter limits, error suppression and JPEG re-encoding are additions with no counterpart in the original. Output is unchanged when they are not used.