Generating Your Own PDFs - Some best practices

The JSAPI enables users to generate PDFs from their own custom HTML documents. Pulsar relies on several technologies in order to generate our PDFs offline. PDF generation is tricky business and requires a lot of effort to get working across all platforms.

Luckily, we’ve run into many of the issues ourselves and can provide some guidance to help you get your PDFs looking sharp.

https://github.com/luminixinc/PulsarForSalesforceAdvancedJSExamples

A Complete Example

We have developed a ready-to-use example of how a PDF might be generated and saved across all three platforms. The example is documented to explain what is going on at various stages and broken up using the Strategy Pattern to handle the differences between each platform.

Contained in the repository in the example-report folder is the example-report.pulsarapp which you can upload as a File to your Salesforce organization to see this in action while running the Pulsar for Salesforce App. Simply open the .pulsarapp from the Content Library.

The Complexity

Generating PDFs from HTML content is a complex procedure that is often achieved through online services or through the use of enterprise software. So please keep in mind that although this seems like it should be a simple task, comprehensive conversion from the browser while offline is not something to be taken for granted! For comprehensive notes on these differences, please explore the strategies and htmlFragments for each platform in the example-report.

When running on iOS Pulsar utilizes UIPrintPageRenderer to generate PDFs. While this is a very useful tool, it has a number of confusing nuances that are addressed in the iOS strategy in our example-report. Many of these relate to identifying the header and footer regions and calculating their height. Page numbers however are provided by default and located in the footer.

Windows follows the same general format as iOS but it utilizes IronPDF. Windows requires you to add your own page numbers in the HTML. IronPDF gives you access to handlebars type variables like:

{page} {total-pages} {url} {date} {time} {html-title} & {pdf-title}

For Android, Pulsar makes use of the native Chrome browser present in order to render PDFs. This is achieved in a completely different way and we recommend that you have different HTML templates for handling Android and iOS/Windows.

Additional Notes

Images and Canvas:

Using images, canvas elements and fonts will work in your custom HTML implementations, but it is possible to run into issues when attempting to generate PDF files, due to CORS rules or similar access restrictions imposed by the webview environment. Our recommendation is to convert each of these resources to a 'data URI' format with Base64 encoding.  

Canvas elements can be converted at runtime (prior to calling print/PDF APIs), using the convenient toDataURL() javascript API. For Images, the same thing can be done by drawing the image in a canvas element and using the toDataURL() API. Note: This particular method assumes a canvas element is available in your HTML page. Prior to generating the PDF or printing the HTML, we recommend removing the canvas from the DOM using jQuery or similar libraries, as we cannot guarantee the PDF engine will render canvas elements properly at this time.


Fonts:

Font files may require pre-deployment processing to avoid issues loading during PDF generation or printing. Embedding Fonts as base64 data urls works best, as this can be inlined or added directly to precompiled framework CSS for inclusion in your HTML/JS.

Note: On Windows, custom font files are sometimes needed to avoid issues with PDF rendering, as the PDF rendering engine environment only has access to a limited set of fonts, and these are not guaranteed to match the operating system installed fonts. In these cases, fonts can be included using @font-face CSS declarations and relative urls to your fonts, which should be included alongside your HTML/JS resources, for example:

@font-face { font-family: 'MyWebFont'; src: local(''), url('resources/myfont.woff2') format('woff2'), url('resources/myfont.woff') format('woff'), url('resources/myfont.ttf') format('truetype'), url('resources/myfont.svg') format('svg'); } body { font-family: 'MyWebFont', Fallback, sans-serif; }