protected static byte[] exportReportToPdf(JasperPrint jasperPrint)
throws JRException {
JRPdfExporter exporter = new JRPdfExporter();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"this.print({bUI: true,bSilent: false,bShrinkToFit: true});");
exporter.exportReport();
return baos.toByteArray();
}
We are using code like this to export a PDF document from a Jasper application.
The line
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"this.print({bUI: true,bSilent: false,bShrinkToFit: true});");
adds JavaScript to send the PDF document directly to the printer.
The expected behavior is that a print dialog will come up with a preview of the PDF document.
This works fine most of the time - except I am having problems about one out of every 5-6 times in Internet Explorer 8 and Firefox.
What happens is - the print preview dialog with the PDF document does not appear or it appears with a blank document in the preview window.
-I've tried a number of different JavaScripts (different params to this.print() via exporter.setParameter
-I've tried setting different response headers such as
response.setContentType("application/pdf");
response.setHeader("Content-disposition","inline; filename=\""
+ reportName
+ "\"");
response.setContentLength(baos.size());
these did not seem to help
This seems to be an IE and FF issue. Has anyone ever dealt with this problem? I need to get it to work across all browsers 100% of the time. Perhaps a different approach to accomplish the goal of sending the PDF document export directly to the printer? or a third party library that will work across browsers?
Maybe it isn't getting a chance to update the UI. The following code delays the print perhaps giving it the chance it needs. I didn't test as I don't have your environment.
exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT,
"app.setTimeOut('this.print({bUI: true,bSilent: false,bShrinkToFit: true});',200);")
Related
I have a report that is exported to XLSX and PDF. The code of both exporters is pretty similar at the same time encoding is lost during PDF export.
For instance, the following symbols are simply skipped in the end result: "Č", "ć". At the same time "ü", "ß" are printed correctly.
In XLSx exporter (working part) I use pretty simple code:
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
JRXlsxExporter xlsExporter = new JRXlsxExporter();
xlsExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
xlsExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
xlsExporter.exportReport();
return outputStream.toByteArray();
}
In case of PDF I use pretty the same code (doesn't work):
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
JRPdfExporter exporter = new JRPdfExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
exporter.exportReport();
return outputStream.toByteArray();
}
But it doesn't work. In both cases I pass the same instance of jasperPrint.
I tried playing around with PdfExporterConfiguration to set up some parameters, but unfortunately haven't found any encoding related configuration.
Q: What might cause the problem? Any idea how to fix it?
My suspision is that the problem comes from the fonts you are using. Are you sure both XLSX and PDF support the font you have set in your report? In the generated PDF you can check the used font by right-clicking and choosing document properties - there is a tab with fonts. Does the font in PDF support those symbols?
If I remember correctly sometimes when exporting to PDF the exporter will use some different font (if the one you wanted is not found/supported or something).
I use jasper reports version 6.2.1 with the following configuration:
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
JREmptyDataSource jasper = new JREmptyDataSource();
JasperPrint jasperPrint = jasperFillManager.fillReport(this.getClass().getClassLoader().getResource("/reports/tn2.jasper").getPath(), null, jasper);
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment" + "; filename=hehe.pdf");
ByteArrayOutputStream finalReport = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint,finalReport);
PrintWriter ouputStream = response.getWriter();
ouputStream.write(new String(finalReport.toByteArray()));
ouputStream.flush();
FacesContext.getCurrentInstance().responseComplete();
I do it from my JSF 2.x backing bean.
But I always get a blank page when try to export to stream. But if I do:
JasperExportManager.exportReportToPdfFile(jasperPrint,
"d://hehe.pdf");
it works ok, I see the content in the generated file. How to force it work with streams? I tried to close/flush streams in different configurations, use ARM, etc. No luck so far
This part is wrong.
ByteArrayOutputStream finalReport = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint,finalReport);
PrintWriter ouputStream = response.getWriter();
ouputStream.write(new String(finalReport.toByteArray()));
You're allocating a byte array in memory. Then you're exporting the report to it. Then you're converting the byte array to string (which is basically a character array). Then you're writing it to a character based writer. Basically, you've corrupted the binary content of the PDF file by converting all bytes to characters in a fairly inefficient and platform-dependent way. It's as if you're opening the PDF file in a text editor like Notepad and then saving it as a TXT file. Such a file is not anymore readable by a PDF reader.
You should just stream the bytes unmodified to the byte based output stream. Replace all of above by the below oneliner.
JasperExportManager.exportReportToPdfStream(jasperPrint, response.getOutputStream());
Unrelated to the concrete problem, since JSF 2.x, ExternalContext offers several delegate methods without the need to cast down to HttpServletResponse. See also How to provide a file download from a JSF backing bean? for a concrete example.
The solution is trivial:
FacesContext.getCurrentInstance().getExternalContext().responseReset();
And that's it!!
Thanks for your help.
I solved this by adding the next line:
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, new JREmptyDataSource());
I have an application that utilizes Jasper Reports 3.7.6, mainly for backwards-compatibility with the app's predecessor (i.e., the previous app was primarily used to generate sale certificates but the current app is mainly used to generate e-mails to convey the same information).
My QA person has just pointed out that the certificate-generation functionality only shows him a blank web page when run in his environment, and that is also the case for our development-build environment. But when I run the app on my local machine, I get the PDF file displayed as expected. Having not looked at this functionality in a while, and having never been that familiar with Jasper Reports (this was developed by another programmer who left the company years ago), I'm at a loss as to how to resolve what seems like an intermittent issue.
Here's the code that uses Jasper to generate the sales certificate:
// filePath verified as set to executable's directory
String fileName = filePath + "/Certificate.jasper";
String outFileName = "Certificate" + certObject.getSerial() + ".pdf";
HashMap hm = new HashMap();
try
{
if(certObject != null)
{
ArrayList<Certificate> certList = new ArrayList();
certList.add(certObject);
// Create the print object
JasperPrint print = JasperFillManager.fillReport(fileName, hm, new JRBeanCollectionDataSource( (ArrayList) certList , true));
// Create a PDF exporter
JRExporter exporter = new JRPdfExporter();
// Set the output file name in the HTTP response
response.setHeader("Content-disposition",
"attachment; filename=" + outFileName);
// Set the print object of the exporter, and set its
// output stream to be that of the HTTP response object
exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
ServletOutputStream outStream = response.getOutputStream();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outStream);
// Export the PDF file
exporter.exportReport();
}
} catch (JRException e)
{
e.printStackTrace();
System.out.println("JRException: "+e.toString());
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("IOException: "+ioe.toString());
}
I should also note that, if memory and subVersion logs serve, this functionality previously wrote the certificate PDF out to the executable's directory then opened that file in a browser window. I can't remember why I changed the functionality, except possibly for efficiency (i.e., not filling up that directory with lots of PDFs). Do I need to switch back to doing things that way? I really don't want to invest too much effort into what is not likely to be used much in the new application, so if anyone can give me a simple solution that will work consistently, I would be very appreciative.
Try changing your servlet to accept GET or change to Chrome.
I had the same trouble with IE, when the user clicks the generate PDF button IE makes a POST to the Java method, but right when the servlet responds with the PDF output, the Acrobat Plugin is loaded, which makes a second post but this time is a GET, and my controller didn't respond to GET submits.
I have an xml file already being created and rendered as a PDF sent over a servlet:
TraxInputHandler input = new TraxInputHandler(
new File(XML_LOCATION+xmlFile+".xml"),
new File(XSLT_LOCATION)
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
//driver is just `new Driver()`
synchronized (driver) {
driver.reset();
driver.setRenderer(Driver.RENDER_PDF);
driver.setOutputStream(out);
input.run(driver);
}
//response is HttpServletResponse
byte[] content = out.toByteArray();
response.setContentType("application/pdf");
response.setContentLength(content.length);
response.getOutputStream().write(content);
response.getOutputStream().flush();
This is all working perfectly fine.
However, I now have another PDF file that I need to include in the output. This is just a totally separate .pdf file that I was given. Is there any way that I can append this file either to the response, the driver, out, or anything else to include it in the response to the client? Will that even work? Or is there something else I need to do?
We also use FOP to generate some documents, and we accept uploaded documents, all of which we eventually combine into a single PDF.
You can't just send them sequentially out the stream, because the combined result needs a proper PDF file header, metadata, etc.
We use the iText library to combine the files, starting off with
PdfReader reader = new PdfReader(/*String*/fileName);
reader.consolidateNamedDestinations();
We later loop through adding pages from each pdf to the new combined destination pdf, adjusting the bookmark / page numbers as we go.
AFAIK, FOP doesn't provide this sort of functionality.
<%
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=\"" + "test.xls\"");
response.setHeader("Content-Transfer-Encoding", "binary");
response.setContentType("application/vnd.ms-excel");
InputStream is = new FileInputStream(realPath);
//OutputStream outStream = response.getOutputStream();
JasperPrint jasperPrint = JasperFillManager.fillReport(is,
parameters, new JRBeanCollectionDataSource(pdfList));
JRAbstractExporter exporter = new JExcelApiExporter();
exporter.setParameter(JExcelApiExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JExcelApiExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
exporter.setParameter(JExcelApiExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
exporter.setParameter(JExcelApiExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
exporter.setParameter(JExcelApiExporterParameter.OUTPUT_STREAM, out);
exporter.exportReport();
outStream.flush();
outStream.close();
out.clear();
out =pageContext.pushBody();
%>
we use the code above to generate an excel, and it works well in tomcat + windows, but after we upload to linux + weblogic server, the excel is corrupted. I use text editor to open the excel, I found it add several empty line in the excel, which caused the excel can not be open successfully, anyone can point me the right direction ? Why there are space ? How it comes ?
Thanks in advance !
I suspect that your use of pageContext.pushBody() may be the culprit.
pushBody is, as far as I know, meant for updating the output in the scope of a JSP tag.
When you are generating binary content such as an excel file, where you need to be absolutely sure that the intended bytes, and only the intended bytes reach the browser, you need to write those bytes, flush the output, and then make sure that nothing else gets written. By invoking pushBody(), you are making it so that more content can be written to the output, and any blank lines (and the carriage returns / line feeds between them) in the JSP page could be output.
All in all, I suggest that you just not do this in a JSP - do it in a Servlet instead.