Search code examples
htmlpdfzoomingbirtflying-saucer

Tell Flying Saucer or BIRT to scale the html to fit on a single pdf page


My application generates HTML reports. The users want the report to fit a single PDF page - doesn't matter how much zoom you need for it.

Currently they render the page in Internet Explorer 8, and manually define a custom zoom level at the Print Preview window, then they print the page to PDF. I need to perform this operation automatically. How to achieve this?

The reports are actually created by BIRT, so BIRT-based solution is fine, too. Using the BIRT zoom options scale the document to fit height, but it doesn't fit width (because it first renders the HTML then apply the zoom).

Now I'm trying to use Flying Saucer to convert to PDF the BIRT-generated HTML.

I've saw similar questions related to abcPDF (.NET) and CF8 (se below) but I need a Java-based solution, and I wasn't able to use the same techniques with Flying Saucer or BIRT.

Tell abcPdf to scale the html to fit on a single pdf page

scale PDF to single page


Solution

  • That's the solution I found, based on Flying Saucer / iText:

    // A4 paper size = 297x210 mm
    int PAGE_WIDTH = 2100;
    int PAGE_LENGTH = 2970;
    float MARGIN = 19.05f; // 0.75 inch
    
    int width = PAGE_WIDTH; 
    
    // Java2DRenderer.NO_HEIGHT = -1 (it's private)
    // if used the required height is computed
    Java2DRenderer renderer = new Java2DRenderer(dom, width, -1); 
    BufferedImage img = renderer.getImage();
    
    // Adjusts width based on required height
    int height = img.getHeight(); 
    width = (int) Math.round(height * PAGE_WIDTH / PAGE_LENGTH);
    
    // Render same document again, now with the right dimensions
    renderer = new Java2DRenderer(dom, width, height);
    img = renderer.getImage();
    
    com.lowagie.text.Document pdf = new com.lowagie.text.Document(PageSize.A4);
    pdf.setMargins(MARGIN,MARGIN,MARGIN,MARGIN); 
    PdfWriter.getInstance(pdf, new FileOutputStream(args[0]+".pdf"));
    pdf.open();
    com.lowagie.text.Image pdfImage = com.lowagie.text.Image.getInstance(img,Color.WHITE);
    Rectangle ps = pdf.getPageSize();
    pdfImage.scaleAbsolute(
        ps.getWidth()-pdf.leftMargin()-pdf.rightMargin(),
        ps.getHeight()-pdf.topMargin()-pdf.bottomMargin()
    );
    pdf.add(pdfImage);
    pdf.close();