Exporting a chart in a scheduled report to a PDF file
When a scheduled report with a chart is exported to a PDF file, the chart is not automatically included in the PDF file. However, you can use the pyEmbedChartUsingPhantomJS HTML rule and the pyCallPhantomJS activity rule to implement a solution that can export the chart in a scheduled report to a PDF file.
This behavior is different from when you export reports from the Report Viewer. When you export a report with a chart from the Report Viewer, the chart is included in the PDF file. Including charts when you export a report is an effective way to visually communicate report details.
This solution uses PhantomJS. You can download PhantomJS from the following website: http://phantomjs.org/
Prerequisites
Before you begin:
- Comment out the code in the pyEmbedChartUsingPhantomJS HTML rule.
- Comment out all steps in the pyCallPhantomJS activity rule.
Process
1. Create a JavaScript file (for example, chartURL.js), and copy the following code into that file. Include a user ID and password in this file.
[*]
// Passing hard coded user id and password and passing URL and chartName dynamically
var page = require('webpage').create();
page.viewportSize = {
width: 2000,
height: 3000
};
page.settings.userName = ""; //username to be used to run the report
page.settings.password = ""; //password to be used to run the report
page.settings.clearMemoryCaches = true;
/*getting variables passed from activity*/
var reportURL = phantom.args[0];
var chartName = phantom.args[1];
var phantomLocation = phantom.args[2];
var chartPath=phantomLocation+chartName+".png";
phantom.clearCookies();
try{
page.open(reportURL, function() {
var waitNRun = function() {
console.log("In wait");
result = page.evaluate(function() {
var divs = document.getElementsByTagName('div');
var chartDiv;
for (var i = 0; i < divs.length; i++) {
if (divs[i].getAttribute('id') != null && divs[i].getAttribute('id').indexOf('ichartDiv') == 0) {
var reg = /^\d+$/;
if (reg.test(divs[i].getAttribute('id').split('ichartDiv')[1])) {
chartDiv = divs[i];
break;
}
} else if (divs[i].getAttribute('id') != null && divs[i].getAttribute('id').indexOf('staticChart') == 0) {
var reg = /^\d+$/;
if (reg.test(divs[i].getAttribute('id').split('staticChart')[1])) {
chartDiv = divs[i];
break;
}
}
}
var curtop = 0,
curleft = 0;
var chartDivForTop = chartDiv;
if (chartDivForTop.offsetParent) {
do {
curtop += chartDivForTop.offsetTop;
curleft += chartDivForTop.offsetLeft;
} while (chartDivForTop = chartDivForTop.offsetParent);
}
return [chartDiv.offsetHeight, chartDiv.offsetWidth, curtop, curleft];
});
try {
console.log('Crop brand new to : ' + result[0] + "x" + result[1] + "x" + result[2] + "x" + result[3]);
page.clipRect = {
top: result[2] + 10,
left: result[3],
width: result[1],
height: result[0] - 45
};
window.setTimeout(function() {
page.render(chartPath);
phantom.exit();
}, 20000);
} catch (err) {
console.log('exception');
phantom.exit(1);
}
}
setTimeout(waitNRun, 5000);
});
}catch(err){
console.log("error occured in js file");
}
2. Use the pyEmbedChartUsingPhantomJS HTML rule to call the activity to obtain the image byte stream and append the image byte stream to the PDF stream.
[*]
<%
HashStringMap keys = new HashStringMap();
keys.putString("pxObjClass", "Rule-Obj-Activity");
keys.putString("pyClassName", "Rule-Obj-Report-Definition");
keys.putString("pyActivityName", "pyCallPhantomJS");
ParameterPage paramsPage = new ParameterPage();
paramsPage.putString("InsHandle", tools.getPrimaryPage().getString(".pyReportDefinition.pzInsKey"));
ClipboardPage chartPage=tools.getPrimaryPage().getPage(".pyReportDefinition.pyUI.pyChart");
String ChartName=chartPage.getString(".pyGraphType")+chartPage.getString(".pySubType")+com.pegarules.generated.pega_rules_datetime.getCurrentTimeStampUnique().replace(".","").replace("GMT","");
ChartName = ChartName.trim();
paramsPage.putString("ChartName",ChartName);
tools.doActivity(keys , null, paramsPage);
String encodedImage = tools.getPrimaryPage().getString("encodedImage");
String imgTag = "<img src='data:image/png;base64,"+ encodedImage +"' />";
imgTag = imgTag.trim();
%>
<%
=imgTag
%>
3. Use the pyCallPhantomJS activity rule to invoke the PhantomJS WebKit, which calls the JavaScript file that you created (chartURL.js).
[*]
ClipboardPage cp=tools.findPage("pxRequestor"); /*Get the requestor page*/
if(cp!=null){
String reqContextURI= cp.getProperty(".pxReqContextURI").getStringValue()+"/PRServlet";
String reqPathInfoReal= cp.getProperty(".pxReqPathInfoReal").getStringValue();
String insHandle=tools.getParamValue("InsHandle");
insHandle=insHandle.replaceAll(" ","%20").replaceAll("#","%23");
reportURL=reqContextURI+reqPathInfoReal+"?pyActivity=%40baseclass.WBRun&InsHandle="+insHandle;
}else{
oLog.infoForced("requestor page is null");
}
[*]
Local.phantomPath=”"\\\\ shared_location \\phantom\\phantomjs"
Local.phantomLocation=”"\\\\ shared_location \\phantom\\"
Local. chartURL="\\\\ shared_location \\phantom\\chartURL.js"
[*]
try{
java.lang.Process process = java.lang.Runtime.getRuntime().exec(phantomPath+" "+chartURL+" "+reportURL+" "+tools.getParamValue("ChartName")+" "+phantomLocation);
process.waitFor();
}
catch(Exception e)
{
oLog.error("Exception occurred while calling phantom JS ",e);
}
[*]
try{
String chartPath = phantomLocation+tools.getParamValue("ChartName")+".png";
oLog.infoForced("chartPath=="+chartPath);
java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(new java.io.File(chartPath));
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
javax.imageio.ImageIO.write(image, "png", baos);
byte[] res=baos.toByteArray();
String encodedImage = com.sun.org.apache.xerces.internal.impl.dv.util.Base64.encode(baos.toByteArray());
oLog.infoForced("encodedImage=="+encodedImage);
tools.findPage("TmpExportResultsPage").putString("encodedImage",encodedImage);
} catch(Exception e) {
oLog.infoForced("In exception=="+e.getMessage());
}