Highly cursed utility for printing to cropped SVG files from a QEMU Windows VM
Find a file
2026-03-13 00:44:03 +02:00
src Initial commit 2026-03-12 23:38:15 +02:00
.gitignore Initial commit 2026-03-12 23:38:15 +02:00
Cargo.lock Initial commit 2026-03-12 23:38:15 +02:00
Cargo.toml Initial commit 2026-03-12 23:38:15 +02:00
README.md Add a meaningful README 2026-03-13 00:44:03 +02:00

xpslistener

An experimental, crude daemon designed to convert XPS archives received through a TCP connection to SVG files with their viewBox cropped to content. This is most useful for "printing" from a Windows VM to SVG files that will be saved on the host filesystem (or any other location Gio supports). Once a print job arrives, a GTK 4 file save dialog will be opened to select the destination file.

Reasoning

As a university student, I have to prepare reports of the work I have done to show my understanding of the topics and document what exactly was done in order. To write high quality reports for subjects focused on the PSoC MCU family, I must be able to include "Top Design" sheets from PSoC Creator which are a graphical representation of peripheral device configuration.

Screenshots can work fine for such use cases, but vector images are much better - especially since that's the source format. Fortunately, PSoC Creator has good support for printing Top Design sheets. xpslistener fully automates the "print to SVG" pipeline, making the report writing workflow much faster and efficient for rapid adjustments.

Setup

  1. Create a QEMU virtual machine with a virtual serial port set up as a TCP server and install your preferred version of Windows.

  2. Ensure XPS services package is present on the system by checking optionalfeatures.exe, reboot if needed.

  3. Add a "printer" assigned to the virtual COM port. When asked for a driver, choose any printer model for which the native language is XPS. Using a custom .inf + .gpd combo pointing to the built-in mxdwdrv (Microsoft XPS Document Writer) driver should be possible, but I was not able to make this work.

  4. Make sure xpslistener is running and that it is connected to the QEMU virtual serial port TCP server.

  5. Use the printing functionality in your favorite application: select the newly added virtual printer, confirm printing and wait a few seconds for the virtual serial port transfer to complete. Better speeds may be achieved by using the virtio-serial QEMU device, but I have not tested this.

  6. Navigate using GTK 4 file save dialog to choose a directory and filename for the resulting SVG document. Once the file is saved, you may verify its contents using an image viewer or vector graphics editing software.

Architecture

As this is a "quick and dirty" project, all possible corners have been cut. The daemon contains both asynchronous and blocking code, error handling is mostly done with expect calls and the general code structure is poor.

The daemon connects to a TCP server (which can be started by e.g. QEMU) and listens for raw XPS archives. Once the connection becomes idle, xpslistener will attempt to find an "End Of Central Directory" record of the archive. If it is found, the archive is considered to be fully received.

The XPS archive is then saved to a temporary directory and converted with a subprocess call to the xpstosvg binary, which is part of libgxps. While GXPS provides GIR files that can be used to generate Rust bindings, avoiding the temporary file is not possible without changes to the library: instead of creating an input stream for the GFile, its path is accessed directly and passed to libarchive.

After xpstosvg does its job, the output file is fully read into memory as a string and passed to the SVG cropping subroutine. The operation consists of processing the document with usvg to determine the bounding box, then using xml to create an SVG document with modified <svg> element attributes.

Finally, processed document gets sent to the main thread which displays a file save dialog and writes SVG contents if the user picks a destination.