- Rust 100%
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
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
-
Create a QEMU virtual machine with a virtual serial port set up as a TCP server and install your preferred version of Windows.
-
Ensure XPS services package is present on the system by checking
optionalfeatures.exe, reboot if needed. -
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+.gpdcombo pointing to the built-inmxdwdrv(Microsoft XPS Document Writer) driver should be possible, but I was not able to make this work. -
Make sure xpslistener is running and that it is connected to the QEMU virtual serial port TCP server.
-
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-serialQEMU device, but I have not tested this. -
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.