Showing posts with label pdf-generation. Show all posts
Showing posts with label pdf-generation. Show all posts

Monday, 25 April 2011

Create PDF and RTF reports using Jasper API

Using Japer, you can create reports in various formats like CSV file, HTML file, PDF file, RTF file, Excel file, XML file etc. First of all, the report needs to be designed using a report designer. I was using the open source report designing tool called, iReport. You can produce a report using the data from a database, parameters, variable expressions etc. If you are generating the report from a custom class file (DAO), include it in the class path of iReport. Using the iReport designing tool, you’ll be able to create a report as a JRXML/XML file; compile the report creating a new file with extension, .jasper called as ‘Jasper file’. We will be using this Jasper file in our java code.
Download the Jasper API with all its dependent jar’s and invoke the report using the API. Here is a sample to generate PDF and RTF reports. Generating other formats are very similar to this. Here I am using a custom datasource inplemented from JRDataSource for generating the reports. Since I was writing a web service to generate reports, I wasn’t rendering the report but returning the report in byte array. The client progran would use the FileOutputStream to render the report from byte array or could directly feed the byte array to the OutputStream of the HttpServletResponse.

public byte[] buildRtfResume(final String ssnNumber) {
ResumeEngineImpl.log.debug("Building RTF Resume for " + ssnNumber);
byte[] rtfResume = null;
try {
final Applicant applicant = this.getApplicantBySsn(ssnNumber);
final JasperPrint jasperPrint = this.renderCV(applicant);
final JRRtfExporter rtfExporter = new JRRtfExporter();
final ByteArrayOutputStream rtfStream = new ByteArrayOutputStream();
rtfExporter.setParameter(JRExporterParameter.JASPER_PRINT,jasperPrint);
rtfExporter.setParameter(JRExporterParameter.OUTPUT_STREAM,rtfStream);
rtfExporter.exportReport();
rtfResume = rtfStream.toByteArray();
} catch (final JRException e) {
ResumeEngineImpl.log.error(e.getMessage(), e);
} catch (final RuntimeException e) {
ResumeEngineImpl.log.error(e.getMessage(), e);
}
return rtfResume;
}

public byte[] buildPdfResume(final String ssnNumber) {
ResumeEngineImpl.log.debug("Building PDF Resume for " + ssnNumber);
byte[] pdfResume = null;
try {
final Applicant applicant = this.getApplicantBySsn(ssnNumber);
final JasperPrint jasperPrint = this.renderCV(applicant);
pdfResume = JasperExportManager.exportReportToPdf(jasperPrint);
} catch (final JRException e) {
ResumeEngineImpl.log.error(e.getMessage(), e);
} catch (final RuntimeException e) {
ResumeEngineImpl.log.error(e.getMessage(), e);
}
return pdfResume;
}

JasperPrint object represents the output, which can be viewed, printed or exported to many different formats.JasperFillManager class is used for report filling process. It takes three arguments to fill a report; Compiled report design, Parameters and Datasources.

public JasperPrint renderCV(Applicant applicant){
..........
..........
final JasperReport jasperReport = (JasperReport) JRLoader.loadObject(this.getClass().getClassLoader().getResourceAsStream("jerry/jacob/reports/resume.jasper"));
final JasperReport empHistSubReport = (JasperReport) JRLoader.loadObject(this.getClass().getClassLoader().getResourceAsStream("jerry/jacob/reports/EmploymentSubReport.jasper"));
final JasperReport edHistSubReport = (JasperReport) JRLoader.loadObject(this.getClass().getClassLoader().getResourceAsStream("jerry/jacob/reports/EducationSubReport.jasper"));
.........
final EmpHistDataSource empHistDataSource = new EmpHistDataSource(empHists);
final EducationHistDataSource edHistDataSource = new EducationHistDataSource(eduHists);
.........
final Map parameters = new HashMap();
// add sub reports to map
parameters.put("EmploymentSubReport", empHistSubReport);
parameters.put("EducationSubReport", edHistSubReport);
// add data sources to map
parameters.put("EmploymentDataSource", empHistDataSource);
parameters.put("EducationDataSource", edHistDataSource);
return JasperFillManager.fillReport(jasperReport, parameters,applicantDataSource);
}

Getting the word document:
public byte[] buildDocResume(final String ssnNumber) {

final String sourceMethod = "buildDocResume";
ResumeEngineImpl.log.entering(ResumeEngineImpl.sourceClass,
sourceMethod, ssnNumber);
byte[] docResume = null;
try {
final Seeker seeker = this.getSeekerBySsn(ssnNumber);
final JasperPrint jasperPrint = this.renderResume(seeker);

final JRDocxExporter docExporter = new JRDocxExporter();
final ByteArrayOutputStream docStream = new ByteArrayOutputStream();
docExporter.setParameter(JRDocxExporterParameter.JASPER_PRINT,
jasperPrint);
docExporter.setParameter(JRDocxExporterParameter.OUTPUT_STREAM,
docStream);
docExporter.setParameter(JRDocxExporterParameter.FLEXIBLE_ROW_HEIGHT, Boolean.TRUE);
docExporter.exportReport();
docResume = docStream.toByteArray();
} catch (final JRException e) {
ResumeEngineImpl.log.logp(Level.WARNING,
ResumeEngineImpl.sourceClass, sourceMethod,
"Exception caught:", e);
} catch (final RuntimeException e) {
ResumeEngineImpl.log.logp(Level.WARNING,
ResumeEngineImpl.sourceClass, sourceMethod,
"Exception caught:", e);
}

return docResume;
}

Tip: The generated word document will be formatted using several nested tables. If the property, JRDocxExporterParameter.FLEXIBLE_ROW_HEIGHT, is set to false, the table rows do not increase in height automatically and the user has to enlarge them manually in word.

Wednesday, 13 April 2011

PDF Generation with Big Faceless Report Generator

Big Faceless Report Generator is a commercial Java API for generating PDF files from XML input. The report generator is built on the Big Faceless Java PDF library. It has a very easy to use API, but the one thing that I like most about it is, for it is more than a bargain for the price you pay for it. It easily out performs the open source PDF generators (iText and XSL FOP) and also has a lot of intersting features.

  • HTML-style Tables - auto-sized nested tables with full control over padding, margins and borders
  • Support for CSS2 Style sheets
  • Create inline graphs and charts with XML, direct from the database
  • Includes a servlet and a servlet filter for simple generation of PDF's from XML or JSP pages.
  • Auto pagination of content with page headers and footers
  • Familiar HTML syntax - <a>, <ul>, <p>, <table>, <td> and so on - simpler and faster than FOP
  • Unicode support, Encryption, TrueType fonts, Barcodes and more
  • Load existing PDF documents as templates
  • Digitally sign documents
  • Create and edit interactive Forms, or "AcroForms"
The following is an example of how to use the Report generation library to create PDF files using an XML for input Data, and an XSL as a template. Follow these steps to implement the example
  1. Download Big Faceless Report generator from here. You only have to include the bforeport.jar file in your classpath.
  2. Create the input XML file as shown below:

    <?xml version="1.0" encoding="UTF-8"?>
    <Org>
    <Employee>
    <firstName>Asif</firstName>
    <lastName>Mandvi</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>James</firstName>
    <lastName>Baker</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Jon</firstName>
    <lastName>Stewart</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Stephen</firstName>
    <lastName>Colbert</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Samantha</firstName>
    <lastName>Bee</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    <Employee>
    <firstName>Jon</firstName>
    <lastName>Oliver</lastName>
    <dateOfBirth>1/1/1900</dateOfBirth>
    </Employee>
    </Org>

  3. Create the template for the PDF(XSL) as shown below.

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" />
    <xsl:preserve-space elements="true" />
    <xsl:template match="Org">
    <pdf>
    <body>
    <table font-size="12pt" width="700px">
    <tr font-weight="bold">
    <td>First Name</td>
    <td>Last Name</td>
    <td>Date of Birth</td>
    </tr>
    <xsl:for-each select="/Org/Employee">
    <tr>
    <td>
    <xsl:value-of select="firstName" />
    </td>
    <td>
    <xsl:value-of select="lastName" />
    </td>
    <td>
    <xsl:value-of select="dateOfBirth" />
    </td>
    </tr>
    </xsl:for-each>
    </table>
    </body>
    </pdf>
    </xsl:template>
    </xsl:stylesheet>
  4. Transform the XML to the format required by the report generator: The XML file cannot be used as input to the report generator directly. It has to be first transformed into the required format. That is reason for using the XSL.

    public class ConvertXML {
    public void renderReport() {
    try {
    TransformerFactory factory = TransformerFactory.newInstance();
    StreamSource stylesheet = new StreamSource(new FileInputStream("c:\\pdf\\test.xsl"));
    Transformer transformer = factory.newTransformer(stylesheet);
    Source src = new StreamSource(new FileInputStream("c:\\pdf\\test.xml"));
    Result res = new StreamResult(new FileOutputStream("c:\\pdf\\intermediate.xml"));
    transformer.transform(src, res);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
  5. The following code can be used to generate the final PDF: The PDFGenerator first uses the ConvertXML to transform the input to the report generator input format (intermediate.xml), and then invokes the report generator.

    public class PDFGenerator {
    public void createPDF(String xmlfile, OutputStream out) {
    ReportParser parser;
    try {
    parser = ReportParser.getInstance();
    InputSource src = new InputSource(new FileInputStream(xmlfile));
    PDF pdf = (PDF) parser.parse(src);
    pdf.render(out);
    out.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    public static void main(String args[]) {
    PDFGenerator gen = new PDFGenerator();
    OutputStream os = null;
    try {
    ConvertXML cx = new ConvertXML();
    cx.renderReport();
    os = new FileOutputStream("c:\\pdf\\test.pdf");
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    gen.createPDF("C:\\pdf\\intermediate.xml", os);
    }
    }



Setting attributes of PDF using itext

While you generate a PDF, you may want to set its different attribute like: author name, title, file description etc. iText jar can help you to set different attributes of a PDF file. Document object provide different methods to add various attributes to a PDF file.

document.addAuthor("Vaani");
document.addCreationDate();
document.addCreator("iText library");
document.addTitle("Hello World PDF");

Generate PDF as Output Stream in HTTP request using itext

Sometime we may want to add the PDF generation functionality to a web application, where user on clicking some link or button is served with PDF output. Hence the PDF should be generated on fly and sent to client browser.
Consider following simple action class for Struts which uses this mechanism to generate a dummy PDF and sent the output to browser.

import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.lowagie.text.Document;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;


public class PdfHelloWorldAction extends Action{

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {

Document document = new Document();
try{
response.setContentType("application/pdf");
PdfWriter.getInstance(document, response.getOutputStream());
document.open();
document.add(new Paragraph("Hello vaani"));
document.add(new Paragraph(new Date().toString()));
}catch(Exception e){
e.printStackTrace();
}
document.close();
return null;

}
}

Notice that, we have passed response.getOutputStream() object to getInstance() method. Thus the output generated by iText will be sent directly to the response. Also don’t forget to set the content type of the response to application/pdf.

PDF Generation in Java using iText JAR

Generating PDF files in today’s enterprise applications is quite common. Doing this with Java is not an easy task as Java does not gives default api’s to handle PDF files. No worries, iText jar is for you.
iText is a free Java-PDF library that allows you to generate PDF files on the fly (dynamically). iText is an ideal library for developers looking to enhance web- and other applications with dynamic PDF document generation and/or manipulation. iText is not an end-user tool. Typically you won’t use it on your Desktop as you would use Acrobat or any other PDF application. Rather, you’ll build iText into your own applications so that you can automate the PDF creation and manipulation process.

iText (Java-PDF Library) can be used to:

  1. Serve PDF to a browser
  2. Generate dynamic documents from XML files or databases
  3. Use PDF’s many interactive features
  4. Add bookmarks, page numbers, watermarks, etc.
  5. Split, concatenate, and manipulate PDF pages
  6. Automate filling out of PDF forms
  7. Add digital signatures to a PDF file

Technical Requirements to use iText

You should have JDK 1.4 or later to integrate iText PDF generation in your application.

Getting iText

Download iText jar from its home page http://www.lowagie.com/iText/download.html
iText core: iText-2.1.5.jar

Generate simple PDF in Java using free Java-PDF library

It is very easy to generate a simple PDF file in Java using iText. All you have to do is to put itext.jar in your class path and paste following code in GeneratePDF.java class and compile and execute it. After you execute this, a file Test.pdf will be created in C: drive (If you are using Linux, you may want to have /usr/test.pdf as path).

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Date;

import com.lowagie.text.Document;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;

//Now in some class write this function
public static void generatePDF () {
try {
OutputStream file = new FileOutputStream(new File("C:\\Test.pdf"));

Document document = new Document();
PdfWriter.getInstance(document, file);
document.open();
document.add(new Paragraph("Hello Kiran"));
document.add(new Paragraph(new Date().toString()));

document.close();
file.close();

} catch (Exception e) {

e.printStackTrace();
}
}

In above code snippet we have created Document object which represents our PDF document. Also, by supplying OutputStream object to getInstance() method sends the output to OutputStream. Thus in our case we have created a output file and sent output to it.