I was recently helping a customer reconcile theory and practice with respect to our drawtomemory sample and their desire to render just a portion of a page instead of the entire page.
Shorn of the details, the theory is simple enough: You have an UpdateRect parameter for specifying which area of the page you want to render, a DestRect that represents the destination bitmap, and a matrix with which coordinates on the page can be translated to the destination bitmap via a matrix transformation. In theory, again, you can use your matrix to transform your UpdateRect to get your DestRect.
Actually, that is also true in practice, but figuring out your matrix gets a bit trickier when you are only interested in part of the page and…the page is rotated. And then, you have to consider our drawtomemory sample app which wasn’t designed to render anything less than the full page and thus had some assumptions that had to be backed out.
Let’s start with MainProc() in mainproc.cpp. The biggest changes were to take optional command-line parameters for the document, page number, and update rectangle values as I personally prefer to test by changing command-line parameters rather than by making code modifications and recompiling. But the most significant change was adding/requiring an explicit parameter for the UpdateRect:
To replicate the old behavior of rendering the entire page, you would need to explicitly pass in the page’s CropBox, which is still the default if no update rect values are specified on the command-line.
The DrawToMemory class declaration also changed a little bit:
Notably the SetPageRect method is now the SetDestRect method. The old SetPageRect method would take an ASFixedRect parameter and set pageRect to [0 0 rectWidth rectHeight]. The new SetDestRect effectively does the same thing in the first line of code, but then calculates another rectangle with the dimensions swapped and chooses between the two based on the page rotation to set the destRect. The pageRect class variable is now just going to be the page’s CropBox.
and GetImageRect() now returns destRect rather than pageRect.
The next big block of change is in the drawtomemory constructor:
Adobe PDF Library (APDFL) has this nifty little function called PDPageGetFlippedMatrix that returns a matrix for mapping page coordinates to a bitmap that takes into account page dimensions and page rotation. In the drawtomemory sample, we can use the matrix it returns as-is because we are rendering the entire page.
When we are rendering just a part of the page, we need to shift our little update rectangle into the destination rectangle, and we do that with a translation matrix. But what direction we shift, and how much, is going to depend on how the page is rotated.
Otherwise, the calls to PDPageDrawContentsToMemory() now explicitly pass in the UpdateRect parameter instead of setting it to NULL to have the page CropBox used by default. Instead of initializing the (RGB) buffer to white (0xffffff), I initialized it to medium gray (0x7f7f7f), which comes in handy in debugging while things are a bit Lost in Translation.
The full code is here.
Ready to try out APDFL? Start your free evaluation today!