So, as I prepare to inflict PDF::Cairo on the world, I’ve been sensibilizing the documentation and adding example code. My latest effort was dusting off my 15-year-old Traveller sector map generator and cleaning up the hex-grid calculations to use my Box library and the regular-polygon method I recently added. Works great.
Then I had an idea for Yet Another Epicycle: tiling a large image
across multiple pages. I did this by hand in the original
script, splitting sector maps across 4 or 16 pages, but it would be
cool to render the entire sector once and then simply ‘cut out’ the
pieces I need for each page. It would also get rid of a lot of
special-case code for handling things that are partially outside of
the current page.
I tried it out by hand, and it worked great. I drew a big box on a recording surface that was 17x22, and replayed it four times onto 8.5x11 pages with different offsets. Not lightning fast, since you end up rendering the entire drawing N+1 times, but it worked.
For that very simple example.
Unfortunately, it looks like there’s internal state that doesn’t
get reset completely, so that when I integrated it into the
module and told it to make a really big hex grid, only the
first replay was 100% successful. The rest were incomplete (one
row/column of hexes, with no text labels). It didn’t matter what
order I replayed them in. Cairo apparently has scripting surfaces and proxy surfaces in recent
versions, but no one has updated the Perl module to expose those, and
I’m not sure they’d help (scripting surfaces are basically a debugging
tool that writes to disk and gets replayed with a standalone CLI tool). I still want to do it, so I may simply add a simple-minded recording
of my API calls and do a high-level replay. Even more overhead than
using a recording surface (especially for things like loading fonts
and images), but then I’ll know it can be replayed more than once. Meanwhile, the recording()/replay() methods work at least once, so I’m
leaving them in for now.
Wow, that was an easy fix. After walking away for a few hours, I went
back and added a single
cairo_surface_flush() right before each
set_source_surface() call. Renders perfectly, as many times as I
I just need to tweak the clipping regions a bit, to capture the
overlap between pages.
Performance is actually pretty good, now that I have something to measure: it took only 28% longer to generate the drawing and replay it four times on different pages. Output size was 146% larger than generating the same drawing on a single large sheet, but that’s a small price to pay for the convenience.
If I were really going to revive
sec2pdf (and I might, but not this
weekend!), what I’d do to get the most efficient output is use a
recording to draw all of the sector-wide elements (regional borders,
X-boat routes, etc) and replay them onto the individual pages, after
drawing each page’s grid but before adding text and system data. That
would significantly reduce the amount of wasted drawing outside each
page’s boundaries, and only repeat the elements that might appear on
Markdown formatting and simple HTML accepted.
Sometimes you have to double-click to enter text in the form (interaction between Isso and Bootstrap?). Tab is more reliable.