- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-19-2020 08:25 AM
This is a brief guide to using the GeneralFormAPI Script Include to generate a PDF from an HTML source. There are a few utility classes for generating PDFs but ultimately they all end up in GeneralFormJava, which is a set of wrapper classes for iText 5.5.x. The limitations to what we can do with PDF are imposed by those wrapper classes.
Some things to consider:
- Only supports generating a PDF into a new attachment, so you will need a record to send the output to.
- A limited set of HTML and styling is supported.
- A single image can be used in the page header.
- A single image or plain text annotation can be used in the page footer.
- Images need to be in (?) png format and are supplied using a data URI (i.e. base64 encoded).
- You cannot use <hr> in your HTML: if you're using data from HTML fields make sure you filter out <hr> before passing to createPDF.
- I haven't tested SVG (see createPDF in GeneralFormAPI).
- Use HTML tables to achieve layout (but using width= will break)
- For more limitations see https://hi.service-now.com/kb_view.do?sysparm_article=KB0693303
The following is a complete example that should work when executed as a background script. Only do this in a sub-production instance!
(function() {
// grab a random RITM
var ritm = new GlideRecord('sc_req_item');
ritm.setLimit(1);
ritm.query();
ritm.next();
var filename = ritm.number + '.pdf';
gs.debug('Writing PDF to ' + ritm.number);
var table = ritm.getTableName();
var table_sys_id = ritm.getUniqueValue();
// create a new PDF generator
var formAPI = new global.GeneralFormAPI(filename, table, table_sys_id);
// grab a random image
var headerImage = null;
var att = new GlideRecord('sys_attachment');
att.addQuery('content_type', 'image/png');
att.addEncodedQuery('table_nameISNOTEMPTY');
att.query();
if (att.next()) {
headerImage = getAttachmentBase64(att);
}
var footer = 'Your footer message here';
// setDocument(header image, footer image, footer text, header alignment, footer alignment, paper size)
// alignment = "0" = left, "1" = centre, "2" = right. An invalid alignment will cause the image to not appear
formAPI.setDocument(headerImage, null, footer, '1', '1', 'a4');
// source HTML
// must be well-formed XML and not use <hr> (really)
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);
function getAttachmentBase64(attachmentGR) {
var base64ImageStr = GlideStringUtil.base64Encode(new GlideSysAttachment().getBytes(attachmentGR));
return "data:image/png;base64," + base64ImageStr + "";
};
})();
- 15,727 Views

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
That's a nifty little concept; thank you for sharing. Might be a useful way to generate forms on the fly where a customer still has "print, sign and file" as part of a process (with some work of course).
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Tim- this is great! thank you so much for sharing
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you Tim, this was helpful.
This was more or less what I was wanting to do, except for the random RITM and Header image used in the example. I modified slightly, and am going to use this in a UI action to place the PDF back onto the record where the UI action was initiated from. I could see where this could also be used on a Bus Rule or even a Scheduled Job depending on when you wanted to trigger the PDF.
I've got the base PDF created and attaching to the record I want via UI Action, now it's just a matter of finalizing the formatting/content within the body or pages. Having it on the UI Action allows for you to use 'current' and easily place data from within the record into the PDF which is also what I am looking to do.
Thanks again. I saw several other posts and reviewed the official ServiceNow documentation, but this example helped me really apply all that information. Good job.
Thanks,
Daniel
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Daniel,
We are doing similar practice and trying to use business rule or UI action to trigger the PDF and attach to the case record.
Would you please share how can we create the base PDF and attach to the record?
Thank you,
Godfrey
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Godfrey, I started by creating a UI Action for proof of concept and copying in the script above that Tim provided, then I modified as needed for our requirements. You should do the same to start with if you haven't already. Play around with the content section as well to learn the different configuration points.
For using in a UI Action, I modified the top section to query the current record, as opposed to the example above which is querying a random RITM record, as this is where I wanted the PDF to get attached. The variables 'filename', 'table' and 'target_sys_id' are then used as parameters in the PDF API call.
I also added a date stamp and suffix to the filename string, in case the UI action was run more than once it might help differentiate when it was created by just looking at the filename.
// get a glide record for current record
var gr = new GlideRecord('table_name_goes_here');
gr.addQuery('sys_id', current.sys_id);
gr.query();
gr.next();
//set filename
var filename = gs.now() + '_' + gr.number + '_filename_suffix_goes_here.pdf';
//get table and target record glide records
var table = gr.getTableName();
var target_sys_id = gr.getUniqueValue();
One other thing I ran into, was the greater than '>' and less than '<' characters in a string field. Because HTML tagging uses the < & > to create the formatting tags, this can cause a little havoc and potentially cause a PDF page not to generate.
There was a single < symbol that was coming across in one of our string fields that broke things (a comment field). I had to strip out the < from the string prior to using in the source HTML section, otherwise it was interpreted as a broken HTML tag. With the < in the string, our second PDF page was generating blank.
Good luck with it,
Daniel
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi Godfrey, I started by creating a UI Action for proof of concept and copying in the script above that Tim provided, then I modified as needed for our requirements. You should do the same to start with if you haven't already. Play around with the content section as well to learn the different configuration points.
For using in a UI Action, I modified the top section to query the current record, as opposed to the example above which is querying a random RITM record, as this is where I wanted the PDF to get attached. The variables 'filename', 'table' and 'target_sys_id' are then used as parameters in the PDF API call.
I also added a date stamp and suffix to the filename string, in case the UI action was run more than once it might help differentiate when it was created by just looking at the filename.
// get a glide record for current record
var gr = new GlideRecord('table_name_goes_here');
gr.addQuery('sys_id', current.sys_id);
gr.query();
gr.next();
//set filename
var filename = gs.now() + '_' + gr.number + '_filename_suffix_goes_here.pdf';
//get table and target record glide records
var table = gr.getTableName();
var target_sys_id = gr.getUniqueValue();
One other thing I ran into, was the greater than '>' and less than '<' characters in a string field. Because HTML tagging uses the < & > to create the formatting tags, this can cause a little havoc and potentially cause a PDF page not to generate.
There was a single < character that was coming across in one of our string fields that broke things (a comment field). I had to strip out the < from the string prior to using in the source HTML section, otherwise it was interpreted as a broken HTML tag. With the < in the string, our second PDF page was generating blank.
Good luck with it,
Daniel
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello,
I was looking for this and it worked for me,
Thank you very much!
Victor.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
is there any option to get the sys_id of the new attachment after the "formAPI.createPDF('', pages);" ??
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
So you would have to search the attachments table using the filename and record id you used. If you needed to be certain you got the right file, you could use a GUID as the filename.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi,
How can i dynamically add my fields values like you are using MY page or my second page i want to fetch it from form and then use it.
Thanks
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
var pages = [
{heading: '<h3 background-color:grey;>Application Form For Return Home Transportation Expanses</h3><br><br><table border="1"><tr><td>DATE</td><td>'+current.variables.date.getDisplayValue()+'</td><td>Name</td><td>'+u_name+'</td></tr><tr><td>Department</td><td>'+current.variables.reading.getDisplayValue()+'</td><td>GID</td><td>'+current.variables.gid.getDisplayValue()+'</td></tr></table><br><br><table border="1"><tr><td>Number of Application</td><td>YEAR(Prefecture)</td><td>Address</td><td>Route Name</td><td>station name</td></tr>'+ak()+'</table><br><br><table border="1"><tr><td>FullName</td><td>relationship</td><td>address</td><td>Route Name</td><td>station_name</td></tr>'+gk()+'</table><br><br><table border="1"><tr><td>Date</td><td>Trip</td><td>From</td><td>To</td><td>User</td><td>Transportation</td><td>Line</td><td>Receipts no.</td><td>Amount</td></tr>'+rk()+'</table>'}
];
hello Sir,
how can we add css inside this html tag. I used "background: grey" but not working
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello sir,
how can we add Css in the above code, i have try but not working
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Where the PDF saved ? i have run this script but i am not able to find out the pdf which is generated
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @DaSmith9
I have a similar requirement. I'm very new to the PDF generating thing in ServiceNow.
Can you please have a look at my requirement.
Requirement : Once a request is submitted through the portal, the form-level variables must be automatically populated in to a customized template and attach to the submitted request.
Suppose the form has three variables - Requested for, Company and Date. Once, these fields are filled and form is submitted, these variables should be populated in a custom pdf like below.
Dear (Requested for),
I'm working for (Company) till (Date)
It should automatically fill these details based on the request and get attached to post submission.
Is this feasible in Servicenow.
Please guide me on this.
Thank you in Advance.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
I have a similar requirement. I'm very new to the PDF generating thing in ServiceNow.
Can you please have a look at my requirement.
Requirement : Once a request is submitted through the portal, the form-level variables must be automatically populated in to a customized template and attach to the submitted request.
Suppose the form has three variables - Requested for, Company and Date. Once, these fields are filled and form is submitted, these variables should be populated in a custom pdf like below.
Dear (Requested for),
I'm working for (Company) till (Date)
It should automatically fill these details based on the request and get attached to post submission.
Is this feasible in ServiceNow.
Could you please guide me on this.
Thank you in Advance.