|
@@ -78,9 +78,9 @@ PdfConverterPrivate::PdfConverterPrivate(PdfGlobal & s, PdfConverter & o) :
|
|
|
settings(s), pageLoader(s.load),
|
|
|
out(o), printer(0), painter(0)
|
|
|
#ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
|
|
|
- , hfLoader(s.load), tocLoader1(s.load), tocLoader2(s.load)
|
|
|
+ , measuringHFLoader(s.load), hfLoader(s.load), tocLoader1(s.load), tocLoader2(s.load)
|
|
|
, tocLoader(&tocLoader1), tocLoaderOld(&tocLoader2)
|
|
|
- , outline(0)
|
|
|
+ , outline(0), currentHeader(0), currentFooter(0)
|
|
|
#endif
|
|
|
{
|
|
|
|
|
@@ -102,12 +102,17 @@ PdfConverterPrivate::PdfConverterPrivate(PdfGlobal & s, PdfConverter & o) :
|
|
|
connect(&pageLoader, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
|
|
|
|
|
|
#ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
|
|
|
- connect(&hfLoader, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
|
|
|
+ connect(&measuringHFLoader, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
|
|
|
+ connect(&measuringHFLoader, SIGNAL(loadFinished(bool)), this, SLOT(measuringHeadersLoaded(bool)));
|
|
|
+ connect(&measuringHFLoader, SIGNAL(error(QString)), this, SLOT(forwardError(QString)));
|
|
|
+ connect(&measuringHFLoader, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
|
|
|
+
|
|
|
+ connect(&hfLoader, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
|
|
|
connect(&hfLoader, SIGNAL(loadFinished(bool)), this, SLOT(headersLoaded(bool)));
|
|
|
connect(&hfLoader, SIGNAL(error(QString)), this, SLOT(forwardError(QString)));
|
|
|
connect(&hfLoader, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
|
|
|
|
|
|
- connect(&tocLoader1, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
|
|
|
+ connect(&tocLoader1, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
|
|
|
connect(&tocLoader1, SIGNAL(loadFinished(bool)), this, SLOT(tocLoaded(bool)));
|
|
|
connect(&tocLoader1, SIGNAL(error(QString)), this, SLOT(forwardError(QString)));
|
|
|
connect(&tocLoader1, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
|
|
@@ -137,22 +142,49 @@ void PdfConverterPrivate::beginConvert() {
|
|
|
return;
|
|
|
}
|
|
|
#endif
|
|
|
+ bool headerHeightsCalcNeeded = false;
|
|
|
|
|
|
for (QList<PageObject>::iterator i=objects.begin(); i != objects.end(); ++i) {
|
|
|
PageObject & o=*i;
|
|
|
settings::PdfObject & s = o.settings;
|
|
|
|
|
|
- if (!s.header.htmlUrl.isEmpty() && looksLikeHtmlAndNotAUrl(s.header.htmlUrl)) {
|
|
|
- emit out.error("--header-html should be a URL and not a string containing HTML code.");
|
|
|
- fail();
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!s.footer.htmlUrl.isEmpty() && looksLikeHtmlAndNotAUrl(s.footer.htmlUrl)) {
|
|
|
- emit out.error("--footer-html should be a URL and not a string containing HTML code.");
|
|
|
- fail();
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (!s.header.htmlUrl.isEmpty() ) {
|
|
|
+ if (looksLikeHtmlAndNotAUrl(s.header.htmlUrl)) {
|
|
|
+ emit out.error("--header-html should be a URL and not a string containing HTML code.");
|
|
|
+ fail();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // we should auto calculate header if top margin is not specified
|
|
|
+ if (settings.margin.top.first == -1) {
|
|
|
+ headerHeightsCalcNeeded = true;
|
|
|
+ o.measuringHeader = &measuringHFLoader.addResource(
|
|
|
+ MultiPageLoader::guessUrlFromString(s.header.htmlUrl), s.load)->page;
|
|
|
+ } else {
|
|
|
+ // or just set static values
|
|
|
+ // add spacing to prevent moving header out of page
|
|
|
+ o.headerReserveHeight = settings.margin.top.first + s.header.spacing;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!s.footer.htmlUrl.isEmpty()) {
|
|
|
+ if (looksLikeHtmlAndNotAUrl(s.footer.htmlUrl)) {
|
|
|
+ emit out.error("--footer-html should be a URL and not a string containing HTML code.");
|
|
|
+ fail();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (settings.margin.bottom.first == -1) {
|
|
|
+ // we should auto calculate footer if top margin is not specified
|
|
|
+ headerHeightsCalcNeeded = true;
|
|
|
+ o.measuringFooter = &measuringHFLoader.addResource(
|
|
|
+ MultiPageLoader::guessUrlFromString(s.footer.htmlUrl), s.load)->page;
|
|
|
+ } else {
|
|
|
+ // or just set static values
|
|
|
+ // add spacing to prevent moving footer out of page
|
|
|
+ o.footerReserveHeight = settings.margin.bottom.first + s.footer.spacing;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (!s.isTableOfContent) {
|
|
|
o.loaderObject = pageLoader.addResource(s.page, s.load, &o.data);
|
|
@@ -162,13 +194,64 @@ void PdfConverterPrivate::beginConvert() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
emit out.phaseChanged();
|
|
|
loadProgress(0);
|
|
|
|
|
|
- pageLoader.load();
|
|
|
+ if (headerHeightsCalcNeeded) {
|
|
|
+ // preload header/footer to check their heights
|
|
|
+ measuringHFLoader.load();
|
|
|
+ } else {
|
|
|
+ // set defaults if top or bottom mergin is not specified
|
|
|
+ if (settings.margin.top.first == -1) {
|
|
|
+ settings.margin.top.first = 10;
|
|
|
+ }
|
|
|
+ if (settings.margin.bottom.first == -1) {
|
|
|
+ settings.margin.bottom.first = 10;
|
|
|
+ }
|
|
|
+
|
|
|
+ pageLoader.load();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// calculates header/footer height
|
|
|
+// returns millimeters
|
|
|
+qreal PdfConverterPrivate::calculateHeaderHeight(PageObject & object, QWebPage & header) {
|
|
|
+ typedef QPair<QWebElement, QString> p_t;
|
|
|
+ settings::PdfObject & s = object.settings;
|
|
|
+ QPainter * testPainter = new QPainter();
|
|
|
+ QPrinter * testPrinter = createPrinter();
|
|
|
+
|
|
|
+ QWebPrinter wp(header.mainFrame(), testPrinter, *testPainter);
|
|
|
+ qreal height = wp.elementLocation(header.mainFrame()->findFirstElement("body")).second.height();
|
|
|
+
|
|
|
+ delete testPainter;
|
|
|
+ delete testPrinter;
|
|
|
+
|
|
|
+ return (height / PdfConverter::millimeterToPointMultiplier);
|
|
|
}
|
|
|
|
|
|
+QPrinter * PdfConverterPrivate::createPrinter() {
|
|
|
+ QPrinter * printer = new QPrinter(settings.resolution);
|
|
|
+ if (settings.dpi != -1) printer->setResolution(settings.dpi);
|
|
|
+ //Tell the printer object to print the file <out>
|
|
|
+
|
|
|
+ printer->setOutputFormat(
|
|
|
+ (settings.outputFormat == "ps" || (settings.outputFormat == "" && settings.out.endsWith(".ps", Qt::CaseInsensitive)))?
|
|
|
+ QPrinter::PostScriptFormat : QPrinter::PdfFormat
|
|
|
+ );
|
|
|
+ printer->setOutputFileName(lout);
|
|
|
+
|
|
|
+ if ((settings.size.height.first != -1) && (settings.size.width.first != -1)) {
|
|
|
+ printer->setPaperSize(QSizeF(settings.size.width.first,settings.size.height.first + 100), settings.size.height.second);
|
|
|
+ } else {
|
|
|
+ printer->setPaperSize(settings.size.pageSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ printer->setOrientation(settings.orientation);
|
|
|
+ printer->setColorMode(settings.colorMode);
|
|
|
+
|
|
|
+ return printer;
|
|
|
+}
|
|
|
|
|
|
void PdfConverterPrivate::preprocessPage(PageObject & obj) {
|
|
|
currentObject++;
|
|
@@ -239,10 +322,10 @@ void PdfConverterPrivate::pagesLoaded(bool ok) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- //Setup margins and papersize
|
|
|
- printer->setPageMargins(settings.margin.left.first, settings.margin.top.first,
|
|
|
- settings.margin.right.first, settings.margin.bottom.first,
|
|
|
- settings.margin.left.second);
|
|
|
+ //Setup margins and papersize
|
|
|
+ printer->setPageMargins(settings.margin.left.first, objects[0].headerReserveHeight,
|
|
|
+ settings.margin.right.first, objects[0].footerReserveHeight,
|
|
|
+ settings.margin.left.second);
|
|
|
|
|
|
if ((settings.size.height.first != -1) && (settings.size.width.first != -1)) {
|
|
|
printer->setPaperSize(QSizeF(settings.size.width.first,settings.size.height.first), settings.size.height.second);
|
|
@@ -440,6 +523,9 @@ void PdfConverterPrivate::fillParms(QHash<QString, QString> & parms, int page, c
|
|
|
void PdfConverterPrivate::endPage(PageObject & object, bool hasHeaderFooter, int objectPage, int pageNumber) {
|
|
|
typedef QPair<QWebElement, QString> p_t;
|
|
|
settings::PdfObject & s = object.settings;
|
|
|
+ // save margin values
|
|
|
+ qreal leftMargin, topMargin, rightMargin, bottomMargin;
|
|
|
+ printer->getPageMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin, settings.margin.left.second);
|
|
|
if (hasHeaderFooter) {
|
|
|
QHash<QString, QString> parms;
|
|
|
fillParms(parms, pageNumber, object);
|
|
@@ -487,6 +573,8 @@ void PdfConverterPrivate::endPage(PageObject & object, bool hasHeaderFooter, int
|
|
|
painter->save();
|
|
|
painter->resetTransform();
|
|
|
double spacing = s.header.spacing * printer->height() / printer->heightMM();
|
|
|
+ // clear vertical margins for proper header rendering
|
|
|
+ printer->setPageMargins(leftMargin, 0, rightMargin, 0, settings.margin.left.second);
|
|
|
painter->translate(0, -spacing);
|
|
|
QWebPrinter wp(header->mainFrame(), printer, *painter);
|
|
|
painter->translate(0,-wp.elementLocation(header->mainFrame()->findFirstElement("body")).second.height());
|
|
@@ -503,8 +591,9 @@ void PdfConverterPrivate::endPage(PageObject & object, bool hasHeaderFooter, int
|
|
|
painter->addHyperlink(r, QUrl(p.second));
|
|
|
}
|
|
|
wp.spoolPage(1);
|
|
|
+ // restore margins
|
|
|
+ printer->setPageMargins(leftMargin, topMargin, rightMargin, bottomMargin, settings.margin.left.second);
|
|
|
painter->restore();
|
|
|
-
|
|
|
}
|
|
|
|
|
|
if (currentFooter) {
|
|
@@ -513,6 +602,9 @@ void PdfConverterPrivate::endPage(PageObject & object, bool hasHeaderFooter, int
|
|
|
painter->resetTransform();
|
|
|
double spacing = s.footer.spacing * printer->height() / printer->heightMM();
|
|
|
painter->translate(0, printer->height()+ spacing);
|
|
|
+ // clear vertical margins for proper header rendering
|
|
|
+ printer->setPageMargins(leftMargin, 0, rightMargin, 0, settings.margin.left.second);
|
|
|
+
|
|
|
QWebPrinter wp(footer->mainFrame(), printer, *painter);
|
|
|
|
|
|
QVector<p_t> local;
|
|
@@ -528,6 +620,8 @@ void PdfConverterPrivate::endPage(PageObject & object, bool hasHeaderFooter, int
|
|
|
painter->addHyperlink(r, QUrl(p.second));
|
|
|
}
|
|
|
wp.spoolPage(1);
|
|
|
+ // restore margins
|
|
|
+ printer->setPageMargins(leftMargin, topMargin, rightMargin, bottomMargin, settings.margin.left.second);
|
|
|
painter->restore();
|
|
|
}
|
|
|
|
|
@@ -597,6 +691,32 @@ void PdfConverterPrivate::tocLoaded(bool ok) {
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+void PdfConverterPrivate::measuringHeadersLoaded(bool ok) {
|
|
|
+#ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
|
|
|
+ if (errorCode == 0) errorCode = measuringHFLoader.httpErrorCode();
|
|
|
+#endif
|
|
|
+ if (!ok) {
|
|
|
+ fail();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int d=0; d < objects.size(); ++d) {
|
|
|
+ PageObject & obj = objects[d];
|
|
|
+ if (obj.measuringHeader) {
|
|
|
+ // add spacing to prevent moving header out of page
|
|
|
+ obj.headerReserveHeight = calculateHeaderHeight(obj, *obj.measuringHeader) + obj.settings.header.spacing;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (obj.measuringFooter) {
|
|
|
+ // add spacing to prevent moving footer out of page
|
|
|
+ obj.footerReserveHeight = calculateHeaderHeight(obj, *obj.measuringFooter) + obj.settings.header.spacing;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pageLoader.load();
|
|
|
+}
|
|
|
+
|
|
|
void PdfConverterPrivate::headersLoaded(bool ok) {
|
|
|
#ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
|
|
|
if (errorCode == 0) errorCode = hfLoader.httpErrorCode();
|