PDF output

Wt provides two classes for rendering to PDF:

PDF Images

The class WPdfImage is a paint device for rendering to PDF. It supports two main use-cases:

  • as any other paint device, it can be used to create a PDF output of the painting (which could e.g. be a chart or your own painted widget), or
  • it can be used to embed Wt-generated contents into a larger PDF document, e.g. to generate a report

A WPdfImage paint device is typically used in conjunction with a WPainter, which provides a high-level unified painting API.

The PDF is generated using The Haru Free PDF Library. This class is included in the library only if libharu was found during the build of the library.

The following example shows how to use a WPdfImage directly in conjunction with WPainter.

Example
source
#include <Wt/WPainter.h>
#include <Wt/WPdfImage.h>
#include <Wt/WPushButton.h>
#include <Wt/WResource.h>

using namespace Wt;

class SamplePdfResource : public Wt::WPdfImage
{
public:
    SamplePdfResource()
        : WPdfImage(400, 300)
    {
        suggestFileName("line.pdf");
        paint();
    }

private:
    void paint() {
        Wt::WPainter painter(this);

        Wt::WPen thickPen;
        thickPen.setWidth(5);
        painter.setPen(thickPen);
        painter.drawLine(50, 250, 150, 50);
        painter.drawLine(150, 50, 250, 50);

        painter.drawText(0, 0, 400, 300,
                         Wt::AlignmentFlag::Center | Wt::AlignmentFlag::Top,
                         "Hello, PDF");
    }
};

auto container = std::make_unique<Wt::WContainerWidget>();

auto pdf = std::make_shared<SamplePdfResource>();

Wt::WPushButton *button = container->addNew<Wt::WPushButton>("Create pdf");
button->setLink(Wt::WLink(pdf));

Another common use-case is to paint the contents of a WPaintedWidget, such as a chart, to a PDF :

source
#include <Wt/Chart/WCartesianChart.h>
#include <Wt/WPdfImage.h>

auto chart = std::make_unique<Chart::WCartesianChart>();

WPdfImage pdfImage("4cm", "3cm");
{
    WPainter p(&pdfImage);
    chart->paint(p);
}
std::ofstream f("chart.pdf", std::ios::out | std::ios::binary);
pdfImage.write(f);

When you want to embed a PDF image into a larger document, you need to use its constructor which passes an existing PDF document and page for it to paint on. This approach is used for example by the WPdfRenderer to render XHTML to multi-page PDF files.

Font information is embedded in the PDF. Fonts supported are native PostScript fonts (Base-14) (only ASCII-7), or true type fonts (Unicode). See addFontCollection() for more information on how fonts are located and matched to WFont descriptions.

The paint device has the following limitations:

  • Images (cf. WPainter::drawImage()) can only be included from local files, and only JPG or PNG images can be embedded.
  • Drop shadows are not supported.

Top

Rendering HTML to PDF

The class WPdfRenderer implements an XHTML to PDF renderer. It can be used to create multipage reports, without the need for programming tedious lay outing using a low-level drawing API.

The rendering engine supports only a subset of XHTML. See the documentation of WTextRenderer for more information.

Although the rendering class itself can render to any WPaintDevice (with font metrics), by far the most common use-case is to render to a PDF document using WPdfImage. Typically, you will want to adapt the pixel resolution By default it uses a pixel resolution of 72 DPI, which is a common default for printed documents, but differs from the default used by most browsers (which is 96 DPI and has nothing to do with the actual screen resolution). The resolution can be changed using setDpi() and has the effect of scaling down (or up) the rendering. This can be used in conjunction with setFontScale() to scale the font size differently than other content.

Example

Hello World!

This could be a big deal to your project, since this modest renderer does support many things commonly needed to render reports, such as:

Unordered lists:
  • with one ...
  • or more items
Ordered lists:
  1. it's a basic thing
  2. and they come in good use
That's a logo to look for, right there.

The renderer has fairly complete support for layout of floats (like images), including nested floats and their interactions with other inline and block contents.

There is obvious support for colors, different font sizes - big and small - and other fonts; including support for true type fonts.

You can attach an external style sheet, highlighting items that need special attention.

Reports typically contain tables, and these are also well supported; including multi-page ones, with automatic repetition of table headers.

FirstName LastName Company Address City County State
Essie Vaill Litronic Industries 14225 Hancock Dr Anchorage Anchorage AK
Cruz Roudabush Meridian Products 2202 S Central Ave Phoenix Maricopa AZ
Billie Tinnes D & M Plywood Inc 28 W 27th St New York New York NY
Zackary Mockus Metropolitan Elevator Co 286 State St Perth Amboy Middlesex NJ
Rosemarie Fifield Technology Services 3131 N Nimitz Hwy Honolulu Honolulu HI
Bernard Laboy Century 21 Keewaydin Prop 22661 S Frontage Rd Channahon Will IL
Sue Haakinson Kim Peacock Beringhause 9617 N Metro Pky W Phoenix Maricopa AZ
Valerie Pou Sea Port Record One Stop Inc 7475 Hamilton Blvd Trexlertown Lehigh PA
Lashawn Hasty Kpff Consulting Engineers 815 S Glendora Ave West Covina Los Angeles CA
Marianne Earman Albers Technologies Corp 6220 S Orange Blossom Trl Orlando Orange FL
Justina Dragaj Uchner, David D Esq 2552 Poplar Ave Memphis Shelby TN
Mandy Mcdonnell Southern Vermont Surveys 343 Bush St Se Salem Marion OR
Conrad Lanfear Kahler, Karen T Esq 49 Roche Way Youngstown Mahoning OH
Cyril Behen National Paper & Envelope Corp 1650 S Harbor Blvd Anaheim Orange CA
Shelley Groden Norton, Robert L Esq 110 Broadway St San Antonio Bexar TX
Rosalind Krenzke Waldein Manufacturing 7000 Bass Lake Rd Minneapolis Hennepin MN
Davis Brevard Transit Trading Corp 6715 Tippecanoe Rd Canfield Mahoning OH
Winnie Reich Pacific Seating Co 1535 Hawkins Blvd El Paso El Paso TX
Trudy Worlds Shapiro, Mark R Esq 24907 Tibbitts Avenue Valencia Los Angeles CA
Deshawn Inafuku Telair Div Of Teleflex Inc 3508 Leopard St Corpus Christi Nueces TX
Claudio Loose Audiotek Electronics 286 State St Perth Amboy Middlesex NJ
Sal Pindell Wrigley, Robert I Esq 1112 Se 1st St Evansville Vanderburgh IN
Cristina Sharper Tax Office 111 W 40th St New York New York NY
Cary Mccamey Williams Scotsman 100 E Broad St Columbus Franklin OH
Haley Rocheford Davis, Robert L Esq 6030 Greenwood Plaza Blvd Englewood Arapahoe CO
Dorothea Sweem Ehrmann, Rolfe F Esq 100 Thanet Circ Trenton Mercer NJ
Fannie Steese Chiapete, W Richard Esq 926 E ParkAve Tallahassee Leon FL
Allyson Gillispie De Friese Theo & Sons 1722 White Horse Mercerville R Trenton Mercer NJ
Roger Seid Yoshida, Gerald C Esq 3738 N Monroe St Tallahassee Leon FL
Dollie Daquino Jd Edwards & Co 1005 Congress Ave Austin Travis TX
Eva Seahorn Saunders Appraisal Inc 3 Northern Blvd Amherst Hillsborough NH
Mamie Mcintee Jacobs, Brian Realtor 2810 Jacobs Ave Eureka Humboldt CA
Lashonda Derouen Travel Agent Magazine 101 Royal St Alexandria Alexandria City VA
Jacklyn Emayo Super 8 Motel Temple 101 Us Highway 46 Fairfield Essex NJ

So, keep it in mind !

Create pdf
source
#include <Wt/WPushButton.h>
#include <Wt/WResource.h>
#include <Wt/Http/Request.h>
#include <Wt/Http/Response.h>
#include <Wt/Render/WPdfRenderer.h>
#include <Wt/WApplication.h>

#include <hpdf.h>
#include <hpdf_version.h>

namespace {
    void HPDF_STDCALL error_handler(HPDF_STATUS error_no,
                                    HPDF_STATUS detail_no,
                                    void *user_data) {
        auto pdfImage = static_cast<Wt::WPdfImage*>(user_data);
        pdfImage->errorHandler(error_no, detail_no);
    }
}

class ReportResource : public Wt::WResource
{
public:
    ReportResource()
        : WResource()
    {
        suggestFileName("report.pdf");
    }

    virtual ~ReportResource()
    {
        beingDeleted();
    }

    virtual void handleRequest(const Wt::Http::Request& request,
                               Wt::Http::Response& response)
    {
        response.setMimeType("application/pdf");

        HPDF_Doc pdf = HPDF_New(error_handler, 0);

        // Note: UTF-8 encoding (for TrueType fonts) is only available since libharu 2.3.0 !
        HPDF_UseUTFEncodings(pdf);

        renderReport(pdf);

        HPDF_SaveToStream(pdf);
        unsigned int size = HPDF_GetStreamSize(pdf);
        HPDF_BYTE *buf = new HPDF_BYTE[size];
        HPDF_ReadFromStream (pdf, buf, &size);
        HPDF_Free(pdf);
        response.out().write((char*)buf, size);
        delete[] buf;
    }

private:
    void renderReport(HPDF_Doc pdf) {
        renderPdf(Wt::WString::tr("report.example"), pdf);
    }

    void renderPdf(const Wt::WString& html, HPDF_Doc pdf)
    {
        HPDF_Page page = HPDF_AddPage(pdf);
        HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);

        Wt::Render::WPdfRenderer renderer(pdf, page);
        renderer.setMargin(2.54);
        renderer.setDpi(96);
        renderer.render(html);
    }
};

auto container = std::make_unique<Wt::WContainerWidget>();

Wt::WText *text = container->addNew<Wt::WText>(Wt::WString::tr("report.example"));
text->setStyleClass("reset");

Wt::WPushButton *button = container->addNew<Wt::WPushButton>("Create pdf");

auto pdf = std::make_shared<ReportResource>();
button->setLink(Wt::WLink(pdf));

Top