Reducing our paper footprint is something most of us aim to do, even if sometimes we’re not that successful. It can save money, time, and not to mention, the odd tree or two. If we can keep our digital lives, digital and avoid printing, all the better, right?
But sometimes it’s hard. Either the application doesn’t have a document format that you need, or perhaps it doesn’t even save to a document format at all. Sometimes it’s hard to share with the people you need, or the device you want to view it on doesn’t even have a viewer for that file type.
With Windows 10, Microsoft has tried to help us all out a little with their new PDF Printer. This takes some of the pain out of going paperless by helping any app that prints, to save its content to PDF. This is a pretty good step forward as PDF is supported by most modern devices, it shares well without loss of fidelity, and its annotation support facilitates collaboration.
You still have to share that document around. Once you email it, you now have two copies, if you have more people in the loop, that’s potentially more copies. Wouldn’t it be great if your PDF was in the cloud, and you could share a URL instead?…
That’s where my research comes in. As a Technical Evangelist for the Mako SDK I’m always interested in how our SDK can help with real world problems. So for last few weeks I’ve been looking at how the our SDK may be able produce this workflow. The SDK actually comes with a few samples that I’ve been focusing on specifically; the PDF printer driver sample and the SVG (Scalable Vector Graphics) generator.
Using these samples and a couple of Microsoft technologies (ASP.net MVC and WebAPI 2), I managed to come up with the following architecture and solution.
What I like about the architecture is that it splits the website into two. One side a RESTful API, which allows us to upload a document and query / manipulate it, and the other is all about the presentation of that document.
The functionality is straight forward, but powerful. It all starts off with a printing application. This printing application uses the our new publish-to-web printer.
The printer driver for the printer is actually quite simple, all it does is collect the XPS spool data (which is usually sent onto a physical printer), convert it to PDF using the Mako SDK, then POST it to our RESTful API. This API then uses the Mako SDK again, to transform the PDF to SVG. It’s the SVG we use for presentation (more on why we use this, later). We store the original PDF along side the SVG. This will be the document that we work with. We could have used XPS instead, but PDF has better support for annotations. The PDF is always available to download too, if it is preferred.
Once the upload and conversion is complete, a response is returned to the driver, indicating the location of the new document. A snip of this JSON response is seen below:
In this case, we’re after the ViewUrl. This is the location of the ASP.net MVC controller which presents this particular document. The driver opens a new browser tab at the ViewUrl, showing the newly uploaded document. This URL can then be shared between any number of users.
By using the Mako SDK to produce SVG, rather than other traditional methods such as Mozilla’s PDF.js, we actually realise a few benefits.
Firstly, since we are dealing solely with vector content, we can hand off the rendering responsibility to the browser. SVG has been supported by browsers for a long time, and they are brilliant and rendering it efficiently and fast. So by using SVG, we let the browser do what they are good at and we avoid writing and optimising another renderer or relying on a third party implementation. Result!
Secondly, since we’re using vector content, we are also able to use the browser’s own native pinch and zoom gestures to zoom in on touch devices (tablets, phones). This is one area that PDF.js hasn’t quite caught up with. Since PDF.js renders into a canvas, the browser viewport and zoom levels need to be monitored and the canvas re-rendered each time a change is made. PDF.js is actually getting better over time in this area, but as someone who has worked with web apps that require fluid zoom support, I can tell you that it is non-trivial to implement and support zoom gestures cross-browser and cross-device and is consequently error prone.
The other area that we get immediate benefit from is the Mako SDK’s conversion path. This is perhaps less obvious until you start using it, but let me explain.
When we open a PDF in the Mako SDK, there is a lot of intelligence which joins up text, which may otherwise be broken. In PDFs, a lot of the time, textual content is broken up, sometimes even down to individual characters, or glyphs. By stitching these characters up into logical ‘runs’ of text, we improve the ability for the browser’s search and selection algorithms to correctly select and search for textual content. The alternative, PDF.js uses invisible text which is overlaid onto the rendered canvas. It’s actually quite a common technique amongst some PDF viewers, but it should be avoided if possible, as it can also be prone to errors.
So what would a shareable document workflow be, without the ability to add markup. Since our document is backed by a PDF, adding Ink annotations might be a good fit. Since we’re using SVG to present the document, it seems like a good idea to use SVG to represent our ink too. By using SVG, we allow the ink to re-render at high fidelity even when zoomed in. Again, the browser takes care of this for us.
After the ink has been added to the document, it’s a simple click to save the ink to the underlying PDF. Clicking the save icon sends a POST request containing our ink strokes to our API. The API then uses the Mako SDK to add an ink annotation to our underlying PDF. The affected SVG pages are then refreshed from the PDF. On downloading the PDF, you can see that it’s a first class PDF annotation. Great!
Of course, we could add a lot more annotations and modifications to this, and there is plenty more scope for improving the quality of ink. For example, we can add pressure sensitivity and smooth the ink using Bezier curves.
What’s that, you still want more? Ok..
So if you remember, I split the RESTful API apart from the views, which separates concerns nicely. This also makes it incredibly easy to add new views. If you don’t like how the document view looks, or if you want a different representation of the document, it becomes incredibly easy to change it. To see just how easy it is, I took the Turn.js library to create a view which turns our document into a booklet.
The great thing is that it took me literally less than an hour to do. (And I think it looks great!)
I’ve really had fun with this project, and I’m sure I’ll tweak and add to it in the future, but I’m really interested to hear what you think.
Do you work in a sector which might have an interesting take or requirement in this type of flow? Let’s talk!
Stevo · June 13, 2017 at 10:24 am
Excellent post. Fascinating stuff. The Mako SDK is clearly powerful.