TODO request – PDF rendering – fit to page width ability – the solution.
Added by Michael Shestero about 9 years ago
First of all I am to say here thank you for Wt developers. Wt is the very useful and good library, in fact one of the best of open-source ones.
I use it particularly to export my reports to PDF. The reports are simple tables. Wt still contains some great difficulties, perhaps even bugs with Cyrillic output there but finally I've overcome it.
A few time later I discovered the problem. If my report table is relatively big (not too big, just it have more than 5 columns and several pages high) it eventually doesn't fit the page width. In this case the left part of the table are cut or anyway cannot be seen by user.
I found no way in Wt how to bound maximal table width in HTML for Wt. I'm not sure if it's possible, but even if yes there are sometimes not possible to render the HTML table into area with requested size in pixel.
Here is my post about this: http://redmine.webtoolkit.eu/boards/2/topics/11033
I saw the code of WTextRenderer and WPdfRenderer classes and discover, that Wt catches this situation but just produce warning "contents too wide for page...". There are but no possibilities to intercept and to fix this in the outer caller's code.
Meanwhile the solution is ease. The only thing you need is to make the method WtextRenderer::render to return the scale ratio you need to narrow the page, that is the first original maxX value divided to the final maxX value.
More detailed I make the following:
1) add to WTextRenderer double field called wfactor.
2) The class constructor initializes it to 1.
3) In WTextRenderer::render store original maxX:
double maxX = textWidth(currentPs.page);
const double maxX0= maxX; // my
4) At the middle of the method calculates ratio value. The if-block is used in order to call the method second time from the external code:
const double f = (maxX0?1.001:maxX0/maxX); // my
if ( wfactor1 && f<1 )
{
LOG_WARN("Skipping page(s) generation");
endPage(device_); // ? page "#0" already started
return f;
}
for (int page = 0; page <= currentPs.page; ++page) {
...
5) At the end of the method return f instead of useless(??) currentPs.y:
return f; // originally: return currentPs.y; // my
} catch (Wt::rapidxml::parse_error& e) {
throw e;
}
Now we can detect the too-wide exports (if the method return value <1) and even can value how wide are they!
Next changing allow to narrow the page in for the proper ratio:
6) In the WPdfRenderer::startPage use wfactor (2 places):
HPDF_Page_Concat (page*, 72.0f/dpi**wfactor, 0, 0, 72.0f/dpi_, 0, 0); // my
deviceTransform.scale(72.0f/dpi**wfactor, 72.0f/dpi*); // my
7) Also in WPdfRenderer::endPage(WPaintDevice *device):
HPDF_Page_Concat (page_, dpi_/72.0f*wfactor, 0, 0, dpi_/72.0f, 0, 0); // my
8) Finally. Here is a new external application code which performs the export:
try {
double factor = renderer.render( html );
if (factor<1) // too wide! Do corrections
{
factor*=0.99; // extra 1%
renderer.set_wfactor(factor); // OR: renderer.wfactor=wfactor;
// renderer.setFontScale(factor);
factor = renderer.render( html ); // second try
}
}
catch (exception& e)
// #include <boost/property_tree/detail/rapidxml.hpp>
// boost::property_tree::detail::rapidxml::parse_error& e)
// e.what(), e.where()
{
...
That's works! And it isn't too complicated.
I am sure this ability are needed by many over users who do PDF render using Wt.