Help
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Callum Ridley1
Mega Guru

ServiceNow recently released a new plugin for the platform (Paris onwards) to enable better support for custom PDF generation using script. Unfortunately the only documentation on this new feature set you will find is in KB0866613, which does not go very far in explaining how to use the API. I'm sure ServiceNow will eventually document this, or even build some full featured platform functionality around it, but for now I hope this article will get you started.

The new API appears to be based on iText7, which is a major improvement over the old GeneralPDF that was based on iText5. The newer version of iText is much better at handling HTML conversion, and once you start to explore the feature set, there is quite a lot you can do with just plain HTML and CSS.

API Overview

At the time of writing this article, there are two known methods available on the API.

convertToPDFWithHeaderFooter

ParameterTypeDescription
htmlStringThe HTML content to convert to a PDF
targetTableStringThe table name to attach the generated PDF to
targetSysIdStringsys_id of the record to attach the generated PDF to
filenameStringThe file to to save the generated PDF as
pagePropertiesObjectJavascript object with properties used during PDF generation
fontSysIdStringsys_id of a font family record on the 'sys_pdf_generation_font_family' table

pageProperties

propertyTypeDescription
HeaderImageAttachmentIdStringsys_id of an attachment record
HeaderImageAlignmentStringOne of: 'LEFT', 'CENTER', 'RIGHT'
PageSizeStringOne of: 'LEGAL', 'LETTER', 'A4'
GeneratePageNumberStringOne of: 'true', 'false'
TopOrBottomMarginStringNumber as a string e.g. '72'
LeftOrRightMarginStringNumber as a string e.g. '36'

Example

var pageProperties = {
	HeaderImageAttachmentId: 'attachment_sys_id',
	HeaderImageAlignment: 'LEFT',
	PageSize: 'A4',
	GeneratePageNumber: 'true',
	TopOrBottomMargin: '72',
	LeftOrRightMargin: '36'
};

var html = '<h1>Hello World</h1>';

new sn_pdfgeneratorutils.PDFGenerationAPI().convertToPDFWithHeaderFooter(html, 'incident', 'incident_sys_id', 'My First PDF', pageProperties, 'font_family_sys_id');

convertToPDF

ParameterTypeDescription
htmlStringThe HTML content to convert to a PDF
targetTableStringThe table name to attach the generated PDF to
targetSysIdStringsys_id of the record to attach the generated PDF to
filenameStringThe file to to save the generated PDF as
fontSysIdStringsys_id of a font family record on the 'sys_pdf_generation_font_family' table

Example

var html = '<h1>Hello World</h1>';

new sn_pdfgeneratorutils.PDFGenerationAPI().convertToPDF(html, 'incident', 'incident_sys_id', 'My First PDF', 'font_family_sys_id');

On the face of it, it would appear as though the convertToPDFWithHeaderFooter is the more flexible of the two methods, however as you'll see below, we can actually control the entire document ourselves with HTML and CSS and just use the convertToPDF method.

CSS 3 Paged Media

The CSS 3 specification sets out functionality for paged media, for example printing. When it comes to PDF we can use the paged media rules to define how the document should be generated using the ServiceNow PDFGenerationAPI / iText7.

@page rule

The @page rule allows us to specify details about the pages we will be generating, including the margins, size, orientation, page numbering rules etc. 

Example

<style>
   @page {
      size: A4 landscape;
      margin-left: 1cm;
      margin-top: 3cm;
      margin-right: 1cm;
      margin-bottom: 3cm;

      @bottom-right {
        font-family: sans-serif;
        font-weight: bold;
        font-size: 1em;
        content: counter(page);
      }
   }
</style>
<h1>
   Hello World!
</h1>

Resulting PDF

 find_real_file.png

 

Headers and Footers

The creation of headers and footers is equally as easy. This uses a feature called 'Running elements'. At first they may not make much sense in how you define them, but see the below for an example.

<style>
   @page {
      size: A4 landscape;
      margin-left: 1cm;
      margin-top: 3cm;
      margin-right: 1cm;
      margin-bottom: 3cm;

      @top-center {
        font-family: sans-serif;
        font-weight: bold;
        font-size: 1em;
        content: element(runningPageHeader);
      }
   }
   
   #pageHeader {
      position: running(runningPageHeader)
   }
</style>

<div id="pageHeader">
   My Header!
</div>

<h1>
   Hello World!
</h1>

Resulting PDF

find_real_file.png

How this works

The div element with the id 'pageHeader' would normally be rendered in the position its included in the code on the page, however the style block of the code contains a CSS rule for the element #pageHeader, specifying position: running(runningPageHeader). This removes the element from the rendered page and adds it into a css variable, in our case the variable is called 'runningPageHeader'. Once the content is in the variable, we can use that same variable name to include it as content in the @top-center rule using content: element(runningPageHeader).

This can be a difficult concept to get your head around at first, and it can get more complicated when you want to include a page number in your custom HTML header content too. For example:

<style>
   @page {
      size: A4 landscape;
      margin-left: 1cm;
      margin-top: 3cm;
      margin-right: 1cm;
      margin-bottom: 3cm;

      @top-center {
        font-family: sans-serif;
        font-weight: bold;
        font-size: 1em;
        content: element(runningPageHeader);
      }
   }
   
   #pageHeader {
      position: running(runningPageHeader)
   }
   
   #currentPageNumber:before {
      content: counter(page)
   }
</style>

<div id="pageHeader">
   My Header! <span id="currentPageNumber"/>
</div>

<h1>
   Hello World!
</h1>

Resulting PDF

find_real_file.png

 

Images

Images are also possible with relative ease. You can use the usual img elements in your html, and even use absolute URLs to image content, be aware though that if the image is hosted on your ServiceNow instance, you need to make sure the image is publicly accessible. Attachments against records won't work unfortunately as the PDF generation API is not authenticated to your instance.

Example

<style>
   @page {
      size: A4 landscape;
      margin-left: 1cm;
      margin-top: 3cm;
      margin-right: 1cm;
      margin-bottom: 3cm;

      @top-center {
        font-family: sans-serif;
        font-weight: bold;
        font-size: 1em;
        content: element(runningPageHeader);
      }
   }
   
   #pageHeader {
      position: running(runningPageHeader)
   }
   
   #currentPageNumber:before {
      content: counter(page)
   }
</style>

<div id="pageHeader">
   My Header! <span id="currentPageNumber"/>
</div>

<h1>
   Hello World!
</h1>
<img src="URL_TO_IMAGE" width="100px"/>

Resulting PDF

find_real_file.png

 

Fonts

It is possible to add and use custom fonts into the PDFs that you generate. I've only tried this with TTF (TrueType) fonts, though it may work with other formats too. It's possible to add more than one font to a PDF, see the following example.

  1. Create a new Font Family [sys_pdf_generation_font_family] record
  2. fill in the name field with whatever you like, it doesn't make any difference to the process.
  3. Save the record
  4. Attach your font files to the record.

find_real_file.png

When using the API, the last parameter of both methods is the font family sys_id, you can only supply one sys_id to the method, which is why you add multiple fonts to the same Font Family record.

To use the font in your document, you simply specify the font-family CSS attribute in your CSS

Example

<style>
   @page {
      size: A4 landscape;
      margin-left: 1cm;
      margin-top: 3cm;
      margin-right: 1cm;
      margin-bottom: 3cm;

      @top-center {
        font-family: sans-serif;
        font-weight: bold;
        font-size: 1em;
        content: element(runningPageHeader);
      }
   }
   
   #pageHeader {
      position: running(runningPageHeader)
   }
   
   #currentPageNumber:before {
      content: counter(page)
   }
   
   .angry-birds-font {
      font-family: AngryBirds;
   }
   
   .flow-font {
      font-family: Flow;
   }
</style>

<div id="pageHeader">
   My Header! <span id="currentPageNumber"/>
</div>

<h1 class="flow-font">
   Hello World!
</h1>
<h1 class="angry-birds-font">
   Angry Birds
</h1>

Resulting PDF

find_real_file.png

Summary

Hopefully this article has helped you get to grips with the new PDFGenerationAPI. I have only scratched the surface of the CSS paged media rules, but a little Googling around should get you loads of information on how to use it.

Why not have a play with this on your developer instance and post some screenshots here to show everyone else what you've been able to achieve, I'd love to see some of what you've managed to create.

As always, if this content has helped you, please remember to mark it as helpful so that it can reach as many people as possible.

Callum

Comments
oleg7
Tera Contributor

Thanks for a great article! This is really helpful!

Good to know we can now get current page number by calling counter(page). 

Is there by any chance a way to get total number of pages? To build something like "page 2 of 5".

Callum Ridley1
Mega Guru

Yep absolutely, have a look at the documentation here https://www.w3.org/TR/css-page-3/#page-based-counters

TL;DR

counter(pages)

oleg7
Tera Contributor

Thanks! Got it!

What is the concept behind 'sys_pdf_generation_font_family' table? Do we need to attach fonts to the record? 

Slava Savitsky
Mega Sage

Great stuff! Thanks a lot for taking the time to explore this functionality and document your findings.

Just a small remark: The code example for convertToPDF is using a wrong method name (convertToPDFWithHeaderFooter). I thought you might want to correct it.

Callum Ridley1
Mega Guru

Good spot, thank you!

Updated 🙂

Callum Ridley1
Mega Guru

I have updated the article to include an example with custom fonts.

KLewis
Tera Guru

Great timing. I just started looking into how to append data to a preexisting PDF so this looks like it might be useful. Hopefully I can find a way to read in a current PDF and add to it. If not, i might have to go back to trying to get GeneralPDF to work.

KLewis
Tera Guru

@Callum Ridley Any idea on when/if more of the iText7 capabilities will be available?

 

Callum Ridley1
Mega Guru

@KLewis I very much doubt that ServiceNow will expose much of the actual iText Java API, instead opting to produce their own API as an abstraction over iText.

If you're wanting to fill in an existing PDF I guess you'll have to stick with what you've got. There may be more methods on the new API, but you'd have to guess at their names and how to use them as the properties/methods of the API Object are not enumerable via the usual for(prop in obj) method.

KLewis
Tera Guru

Thanks for the input. I'm relatively new to using Service Now so i'm curious as to why we couldn't reach out to them to get details on what methods are available for the API.

Callum Ridley1
Mega Guru
You could reach out to them on HI /Supoort, and you may get an answer. But they don't document everything available on the platform. Sometimes they don't intend for developers outside of ServiceNow to use some features.
Chris P_
Tera Expert

First off, thank you for this article, it was driving me crazy a few months ago that I couldn't find anything for this...

I've taken up the job of converting my existing PDF creations from iText5 to iText7, hoping that table-lines and other styling will get better now.

So taking your first example:
1) HeaderImageAttachmentId, I've got company logo images I want to add to the header, but these are obviously added to the db_image library, but this expects an attachment id? An attachment to what? to the targetTable+targetSysId? That doesn't make any sense...

2) f̶o̶n̶t̶_̶f̶a̶m̶i̶l̶y̶_̶s̶y̶s̶_̶i̶d̶,̶ ̶I̶'̶v̶e̶ ̶l̶o̶o̶k̶e̶d̶ ̶a̶t̶ ̶t̶h̶e̶ ̶s̶y̶s̶_̶p̶d̶f̶_̶g̶e̶n̶e̶r̶a̶t̶i̶o̶n̶_̶f̶o̶n̶t̶_̶f̶a̶m̶i̶l̶y̶ ̶t̶a̶b̶l̶e̶ ̶a̶n̶d̶ ̶t̶r̶i̶e̶d̶ ̶a̶d̶d̶i̶n̶g̶ ̶a̶ ̶l̶i̶n̶e̶ ̶w̶i̶t̶h̶ ̶'̶A̶r̶i̶a̶l̶'̶ ̶i̶n̶ ̶i̶t̶ ̶a̶n̶d̶ ̶u̶s̶i̶n̶g̶ ̶t̶h̶a̶t̶ ̶s̶y̶s̶_̶i̶d̶ ̶f̶o̶r̶ ̶t̶h̶e̶ ̶c̶o̶n̶v̶e̶r̶t̶T̶o̶P̶D̶F̶W̶i̶t̶h̶H̶e̶a̶d̶e̶r̶F̶o̶o̶t̶e̶r̶-̶f̶u̶n̶c̶t̶i̶o̶n̶,̶ ̶b̶u̶t̶ ̶t̶h̶a̶t̶ ̶d̶o̶e̶s̶n̶'̶t̶ ̶s̶e̶e̶m̶ ̶t̶o̶ ̶w̶o̶r̶k̶,̶ ̶s̶o̶ ̶h̶o̶w̶ ̶s̶h̶o̶u̶l̶d̶ ̶t̶h̶e̶ ̶r̶e̶c̶o̶r̶d̶ ̶b̶e̶ ̶f̶i̶l̶l̶e̶d̶?̶ <edit>Missed this in your post... weird... as it's such a good explanation!</edit>

Ok... after re-reading my post: I'm not attacking you or anything, I'm just lost at what to use here 🙂

Hopefully we can make this Article complete with everyone's questions and answers!

 

Ps, did get a fix script to create a <hello world> PDF using this new function, so there is hope!

Chris P_
Tera Expert
var pageProperties = {
	HeaderImageAttachmentId: '',
	HeaderImageAlignment: 'LEFT',
	PageSize: 'A4',
	GeneratePageNumber: 'true',
	TopOrBottomMargin: '72',
	LeftOrRightMargin: '36'
};

var html = '<style> @page { size: A4 portrait; margin-left: 1cm; margin-top: 3cm; margin-right: 1cm; margin-bottom: 3cm;' +
	'@bottom-right { font-family: Arial; font-weight: bold; font-size: 1em; content: counter(page); }' +
	'@top-center { font-family: Arial; font-size: 10pt; font-weight: bold; font-size: 1em; content: element(runningPageHeader); }' +
	'}' +
	'#pageHeader { position: running(runningPageHeader) }' +
	' .left-align { text-align: left; }' +
	' .right-align { text-align: right; }' +
	' .lined-table { border-collapse: collapse; border: 1px solid black; }' +
	' .lined-td { padding-left: 10px; border-collapse: collapse; border: 1px solid black; }' +
	' .font1 { font-family: Arial; }' +
	' .font2 { font-family: Flow; }' +
	' .font3 { font-family: Verdana; }' +
	' .font4 { font-family: AngryBirds; }' +
	'</style>' +
	'<div id="pageHeader">' + 
	'<table width="100%" cellspacing="0" cellpadding="0">' +
	'<tbody><tr>' +
	'<td width="50%" class="left-align"><img src="image-150.png" /></td>' +
	'<td width="50%" class="right-align"><img src="image2.jpg" /></td>' +
	'</tr><tr><td>Testing Font</td></tr></tbody></table>' +
	'</div>' + 
	'<table width="100%" class="lined-table">' +
	'<tbody><tr style="border-bottom:2px solid black;">' +
	'<td width="30%" class="lined-td font1"><b>First and last name</b><br /><b>participant</b></td>' +
	'<td width="15%" class="lined-td font2"><b>Reg. nr.</b><br /><b>participant</b></td>' +
	'<td width="15%" class="lined-td font3"><b>Birthdate</b><br /><b>participant</b></td>' +
	'<td width="10%" class="lined-td font4"><b>Comp.</b><br />&nbsp;</td>' +
	'<td width="30%" class="lined-td" style="font-family: arial;"><b>Signature participant</b><br/>USING A BLUE PEN</td>' +
	'</tr></tbody></table>' + 
	'<table width="100%" class="lined-table"><tbody>';

for (var i = 0; i < 7; i++) {
	html +=
		'<tr>' +
		'<td width="30%" class="lined-td">&nbsp;</td>' +
		'<td width="15%" class="lined-td">&nbsp;</td>' +
		'<td width="15%" class="lined-td">&nbsp;</td>' +
		'<td width="10%" class="lined-td">&nbsp;</td>' +
		'<td width="30%" class="lined-td">&nbsp;</td></tr>';
}
html += '</tbody></table>';

var target_table = 'target_table';
var target_id = 'target_id';
//sys_pdf_generation_font_family table is empty so last variable is empty
new sn_pdfgeneratorutils.PDFGenerationAPI().convertToPDFWithHeaderFooter(html, target_table, target_id, 'iText7 PDF 11', pageProperties, '');

So I was testing with this in a fix script and I'm thrilled to finally have proper control over table-lines again!

Though for some reason, no font-family seems to work... Everything is Times New Roman (and I loathe that font...)

find_real_file.png

Chris P_
Tera Expert

It would seem that over time with more testing things even out:

var pageProperties = {
	HeaderImageAttachmentId: '',
	HeaderImageAlignment: 'LEFT',
	PageSize: 'A4',
	GeneratePageNumber: 'false',
	TopOrBottomMargin: '72',
	LeftOrRightMargin: '36'
};

var css_text = '<style> @page { size: A4 portrait; margin-left: 1cm; margin-top: 3cm; margin-right: 1cm; margin-bottom: 3cm;' +
	'@top-center { font-family: Arial; font-size: 10pt; font-weight: bold; font-size: 1em; content: element(pageHeader); }' +
	'@bottom-left { font-family: Arial; font-size: 10pt; font-weight: bold; font-size: 1em; content: element(pageFooter); }' +
	'@bottom-right{ content: counter(page) " / " counter(pages); font-size:8pt; }' +
	'}' +
	' .pageHeader { position: running(pageHeader) }' +
	' .pageFooter { position: running(pageFooter) }' +
	' .left-align { text-align: left; }' +
	' .right-align { text-align: right; }' +
	' .lined-table { border-collapse: collapse; border: 1px solid black; }' +
	' .lined-td { padding-left: 10px; border-collapse: collapse; border: 1px solid black; }' +
	' .font1 { font-family: Arial; }' +
	' .font2 { font-family: arial; }' +
	' .font3 { font-family: Verdana; }' +
	' .font4 { font-family: Tahoma; }' +
	' .content { font-family: Verdana; }' +
	'</style>';

var header_text = '<div class="pageHeader">' + 
	'<table width="100%" cellspacing="0" cellpadding="0">' +
	'<tbody><tr>' +
	'<td width="50%" class="left-align"><img src="Print-logo-workorder.jpg" width="200px" /></td>' +
	//'<td width="50%"><img src="EngieLogo.jpg" align="left" /></td>' +
	'<td width="50%" class="right-align"><img src="Example.jpg" width="200px" /></td>' +
	'</tr></tbody></table>' +
	'</div>';

var footer_text = '<div class="pageFooter">' +
	'<table width="100%" style="font-size: 10pt; font-family: tahoma; position: relative;" cellspacing="0" cellpadding="0"><tbody><tr>'  +
				'<td style="font-family: tahoma;"><span style="font-size: 11pt; font-weight: bold;">Companyname<br />Department</span><br /><span style="font-size: 9pt; line-height: 12pt;">Addressline<br /> Telephonenumber</span><br /><span style="font-size: 9pt; font-weight: bold;">email@email.com - www.email.com</span><br /><span style="font-size: 7pt;">Legal line</span></td>' +
				'</tr></tbody></table>' +
	'</div>';

var body_text = '<div class="content">' +
	'<table width="100%" class="lined-table font1">' +
	'<tbody><tr style="border-bottom:2px solid black;">' +
	'<td width="30%" class="lined-td"><b>First and last name</b><br /><b>participant</b></td>' +
	'<td width="15%" class="lined-td"><b>Reg. nr.</b><br /><b>participant</b></td>' +
	'<td width="15%" class="lined-td"><b>Birthdate</b><br /><b>participant</b></td>' +
	'<td width="10%" class="lined-td"><b>Comp.</b><br />&nbsp;</td>' +
	'<td width="30%" class="lined-td" style="font-family: arial;"><b>Signature participant</b><br/>USING A BLUE PEN</td>' +
	'<table width="100%" class="lined-table"><tbody>';

for (var i = 0; i < 120; i++) {
	body_text +=
		'<tr>' +
		'<td width="30%" class="lined-td">&nbsp;</td>' +
		'<td width="15%" class="lined-td">&nbsp;</td>' +
		'<td width="15%" class="lined-td">&nbsp;</td>' +
		'<td width="10%" class="lined-td">&nbsp;</td>' +
		'<td width="30%" class="lined-td">&nbsp;</td></tr>';
}
body_text += '</tbody></table></div>';



var html = css_text+header_text+footer_text+body_text;
//gs.info(html);
var target_table = 'target_table';
var target_id = 'target_sys_id';
//dd06dbcc1b7ae8103cd411b1b24bcb56 is sys_id for sys_pdf_generation_font_family
new sn_pdfgeneratorutils.PDFGenerationAPI().convertToPDFWithHeaderFooter(html, target_table, target_id, 'iText7 PDF EN', pageProperties, 'dd06dbcc1b7ae8103cd411b1b24bcb56');

Resulting in:

find_real_file.png

So I'm quite satisfied with the headers, footers and CSS 🙂

Also since these images can be put into the header like this, it doesn't matter anymore that I don't know what HeaderImageAttachmentId should be!

Callum Ridley1
Mega Guru

Hi Chris,

Good work 🙂

The only thing to mention is that there is no need to use the convertToPDFWithHeaderFooter method as you are defining the page size and margins yourself using the @page rule in the CSS. Instead just use the convertToPDF method which I documented in the original article.

Callum

Chris P_
Tera Expert

Hi Callum,

Ah that is good to know, I tested it and works perfectly, so I'll be using that from now on!
I thought that the option with HeaderFooter would ensure those to things, but the CSS does this instead, perfect!

Chris

Andrew115
Tera Contributor

Hey, thanks a lot for this article, really helpful but i have a question:

Is it possible to create pages within the html string like

 

var html =" Page1 Content"+

"Some text on Page 1"+

//New Content should start on page 2

"Page2 Content"+

"Some text on Page 2";

 

 

In the old GeneralFormAPI there is something like that

var pages = [
	{heading: '<h1>My First PDF</h1><p>First page content</p>' },
	{heading: '<p color="red">Second page content</p>' },
	{heading: '<table border="1"><tr bgcolor="pink"><td>Pink rocks!</td><td align="center">Center</td></tr><tr><td colspan="2" align="center">Second row</td></tr></table>' },
	{heading: '<img src="' + getAttachmentBase64(att) + '"/>'}
];

gs.debug('Create the PDF!');

// createPDF(html, pages)
// if you don't want to use pages just supply the html argument
formAPI.createPDF('', pages);

 

Chris P_
Tera Expert

Hey Andrew,

That actually is possible, using PageBreak in your CSS:

.pageBreak { page-break-after : always; }
.pageBreakBefore { page-break-before : always; }

Then I added this to the body where I want the newpage:

<div class="pageBreak">

 

I use the pageBreakBefore in my header as well, so I can print multiple invitations to 1 pdf.

Andrew115
Tera Contributor

Thank you very much.

So simple and it works fine 😃

boz
Tera Expert

Hi, great content! 

The only thing I can't get to work is images in my header html. I'm using an image I've uploaded to system UI > Images and have made sure it's publicy accessible using an incognito browser.

I call my code that lives in a script include:

var styleHTML = '<style>'+
	'@page {' +
		'size: A4 portrait;' + 
		'margin-left: 1cm;' + 
		'margin-top: 1cm;' + 
		'margin-right: 1cm;' +
		'margin-bottom: 1cm;' +
		'@bottom-right { content: counter(page) " / " counter(pages); font-size:8pt; }' +
	'}' +
	'@page :first { ' +
		'size: A4 portrait;' +
		'margin-left: 1cm;' +
		'margin-top: 2cm;' +
		'margin-right: 1cm;' +
		'margin-bottom: 1cm;' +
		'@top-left {font-family: sans-serif; font-weight: bold; font-size: 1em; content: element(runningPageHeader);}' +
	'}' +
		
    ' #pageHeader { position: running(pageHeader) }' +
    ' </style>';
   
var headerHTML = '<div id="pageHeader">'+
	'<img src="Logo.png" width="250"/>'+
	'</div>';

var bodyHTML = '<div>'+
	'<h1>hello world</h1>'+
	'</div>';

var html = styleHTML + headerHTML + bodyHTML

var test = new sn_pdfgeneratorutils.PDFGenerationAPI().convertToPDF(html, 'table_name', 'record_sys_id', 'pdfFileName', '');

Have I missed something?

Cheers

 
 
Chris P_
Tera Expert

Seems legit code...
I haven''t used the @page :first before, so don't know if SN allows it...
Obviously the image name is case sensitive and I found that it wouldn't allow .JPG or .PNG but does allow .jpg and .png, so no uppercase extensions (no clue on why not though...)

I see you're not using a sys_pdf_generation_font_family - sys_id, perhaps having no fonts included has its effects as well?

Other that these I can't think of anything...

boz
Tera Expert

So after alot of testing, I got it to work by mistake. I added an extra value into the id property for the pageHeader element and for some bizarre reason the img element worked. I then just left a space in the id property's value instead and that was also acceptable.

<div id="pageHeader ">

Have no idea why, I thought it may have been because of the extra white space I had before the #pageHeader css

' #pageHeader { position: running(pageHeader) }' +

but still didn't work after i cleaned it up. Anyway, I'm happy to move on.

 
 
 
 
Chris P_
Tera Expert

Sometimes its just enough that things work!

Still very strange though...

Chris P_
Tera Expert

On this issue, finally needed this as well, so I added this to the CSS:

@bottom-right-corner { font-family: Arial; font-size: 10pt; content: counter(page) " / " counter(pages); }

Problem is, the pages counter has 1 page too many...

My document has 2 pages and it shows 1/3 and 2/3...

Ideas?

Marco Moro
Giga Guru

Official documentation available on ServiceNow API Documentation

PDFGenerationAPI API | ServiceNow Developers

D_ Barre
Tera Contributor

Is anyone aware of a way to add a Table of Contents to a generated PDF document?

Andrew115
Tera Contributor

hey, i've experimented a bit with this but haven't found a solution yet to dynamically map the links with page number
but you can build a dynamic overview with links without page numbers like this:
<a href="divId></a>
maybe it helps you a little bit otherwise i would also be very interested in a solution

D_ Barre
Tera Contributor

Ohh that's a really good idea, I didn't even think of that. I think that will have to be the best option for now. 

Vishwanath5
Tera Expert

how can i bring the page number to the bottom of the page .. for me its printing at the top of the page

users00024520
Tera Contributor

Sorry, is this code an include script? and is it called with a rule? please help, I need to create a pdf for a request article

Chris P_
Tera Expert

Hi Samuel,

This is all in an include script indeed, I mainly call this function from an UI-action, using a GlideAjax call.

Cheers,
Chris

Bob Loblaw
Kilo Guru

THANK YOU!! This has been a total life/job saver, much appreciated!

Chris P_
Tera Expert

If you review my posted code it says:

'@bottom-right{ content: counter(page) " / " counter(pages); font-size:8pt; }' +

This should be within your @page section in your CSS.

(ps: counter(pages) isn't working for me, but the counter is just fine)

 

Shakeel Shaik
Mega Sage
Mega Sage
Ashley Wise
Tera Explorer

Would you be able to provide an example of the UI action calling this? Do you use the standard GlideAjax calls?

Chris P_
Tera Expert

Hi Ashley, I didn't put any variables in the example so any standard call would do.

We actually don't use ajax to call it, since its called from a widget server script and from other script includes.

 

AlejandraEs
Tera Contributor

How can I put a background image or watermark that appears on all pages except the first?

Chris P_
Tera Expert

You need to create a different class on the first page, f.e.:

/* set background image per page */
.home-bg {
background: url(images/home-bg.jpg) no-repeat center center fixed;
}
.about-bg {
background: url(images/about.bg.jpg) no-repeat center center fixed;
}
.contact-bg {
background: url(images/contact-bg.jpg) no-repeat center center fixed;
}
For home page:
<html class="home-bg">

For about page:
<html class="about-bg">

For contact page:
<html class="contact-bg">

 

Gouriprasad
Kilo Contributor

My html contains some information in Thai language. The API works fine for English and even for Chinese. But for Thai the convertToPDF function fails.

 

Below is the result log.

{"message":null,"request_id":"3f3b858d1b99c910bf3b415de54bcb03","status":"failure"} 

AH6
Tera Contributor

Thank you for the article. When I convert my KB article using the sn_pdfgeneratorutils.PDFGenerationAPI API to PDF, the images in the KB article is missing. Any suggestions?

AH6
Tera Contributor

Issue is related to image not accessible without authentication. Any other suggestion? Cannot make the image public.

Paul Metzger1
Tera Explorer

How did you end up solving the Times New Romain issue?  We're having the same issue.

Scott38
Tera Contributor

If the image is on the attachment table you have to get the attachment and convert it to base 64 before adding it to the HTML. You may have to replace your image tag in the HTML as it will already be there. It might be tricky finding the correct image tag and replacing it but there is an XML API that you can use that turns XML into a JS object. You can loop through your object to find and replace anything that contains the IMG tag with a base 64 version of the image.

var gsa = new GlideSysAttachment();
var agr = gsa.getAttachments('kb_knowledge', 'KBA SysID');
while (agr.next()) {
html = html.replace(
'<img ...>',
'<img src="data:image/png;base64, ' + gsa.getContentBase64(agr) + '"/>'
);
}
Michael_Martin
Tera Contributor

Does somebody know if the fontSysId is still a thing?
In the official documentation they have only 5 parameters.

https://developer.servicenow.com/dev.do#!/reference/api/quebec/server/sn_pdfgeneratorutils-namespace/PDFGenerationAPIBothAPI#P-convertToPDFWithHdrFtr_S_S_S_S_O

I guess it would use otherwise just the themes system font? Where would be the best way to add a new systemwide font?

Mohamed13
Mega Explorer

Is anybody having trouble after the San Diego upgrade?

It seems like CSS 3 pages media are being ignored.

Any help?

Andrew115
Tera Contributor

Hey,

 

change the system property "com.snc.pdfgenerator.html2pdf.api.version" value to 1

 

Scott38
Tera Contributor

I logged a HI ticket and got this response:

Heard back from our DEV team and they have identified this as a defect (PRB1575866) caused by one of the enhancements in San Diego release. Please refer below as a temporary relief for the issue while they continue to work on the defect.

============
We started working on this defect and identified that this issue is caused by one of the enhancements in SanDiego. The customer can get a temporary relief for the issue by setting value of system property "com.snc.pdfgenerator.html2pdf.api.version" to 1. Though customer won't be able to use TOC tag which is introduced with San Diego. PRB ID for this defect is DEF0298967.
============

Mohamed13
Mega Explorer

Thank you both.

Could you please let us know when the defect is resolved?

Tushar Walveka2
Tera Guru

@Callum Ridley Any idea how can we add new pages using this API?
In the old GeneralPDF API we had multiple HTML Wrapper functions to make that happen.

I see there is Document API available, but again that provides the function to add texts but not the HTML content

Mohamed13
Mega Explorer

Any news about the defect?

Version history
Last update:
‎02-18-2021 02:03 AM
Updated by: