mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-06-16 10:23:14 +02:00
CLI: clickable cross-reference hyperlinks in PDF export
Wire the shared PdfLinks helper into the headless --export-pdf path so CLI-exported PDFs get the same internal cross-reference / folio-report navigation as the GUI print export. For each page, after rendering, the scene-to-page geometry is rebuilt from the QPdfWriter (96 dpi, zero margins, page sized to the diagram so the scale is ~1 with no centering) — deliberately NOT reusing the QPrinter-based mapping — and passed to PdfLinks::injectCrossRefLinks(). After the painter closes, PdfLinks::convertUriToGoTo() rewrites the URI annotations into native GoTo/FitR actions. Builds on the helper extracted in the previous commit; no change to the other CLI tools.
This commit is contained in:
@@ -23,12 +23,16 @@
|
|||||||
#include "dataBase/projectdatabase.h"
|
#include "dataBase/projectdatabase.h"
|
||||||
#include "diagram.h"
|
#include "diagram.h"
|
||||||
#include "diagramcontext.h"
|
#include "diagramcontext.h"
|
||||||
|
#include "pdf_links.h"
|
||||||
#include "qetgraphicsitem/conductor.h"
|
#include "qetgraphicsitem/conductor.h"
|
||||||
#include "qetgraphicsitem/element.h"
|
#include "qetgraphicsitem/element.h"
|
||||||
#include "qetgraphicsitem/terminal.h"
|
#include "qetgraphicsitem/terminal.h"
|
||||||
#include "qetproject.h"
|
#include "qetproject.h"
|
||||||
#include "wiringlistexport.h"
|
#include "wiringlistexport.h"
|
||||||
|
|
||||||
|
// Private Qt PDF engine for drawHyperlink() — see pdf_links / projectprintwindow.
|
||||||
|
#include <private/qpdf_p.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QDomDocument>
|
#include <QDomDocument>
|
||||||
@@ -37,6 +41,8 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QPageLayout>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPdfWriter>
|
#include <QPdfWriter>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
@@ -44,6 +50,7 @@
|
|||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
#include <QSvgGenerator>
|
#include <QSvgGenerator>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#include <QTransform>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -118,6 +125,12 @@ int exportPdf(QETProject &project, const QString &output)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Page numbers (1-based) for cross-reference hyperlink targets: each
|
||||||
|
// diagram is exactly one page in the CLI export (no tiling).
|
||||||
|
QMap<Diagram *, int> pageMap;
|
||||||
|
for (int i = 0; i < diagrams.size(); ++i)
|
||||||
|
pageMap.insert(diagrams.at(i), i + 1);
|
||||||
|
|
||||||
QPdfWriter writer(output);
|
QPdfWriter writer(output);
|
||||||
writer.setCreator("QElectroTech");
|
writer.setCreator("QElectroTech");
|
||||||
writer.setResolution(96);
|
writer.setResolution(96);
|
||||||
@@ -145,8 +158,50 @@ int exportPdf(QETProject &project, const QString &output)
|
|||||||
const QRectF target(0, 0,
|
const QRectF target(0, 0,
|
||||||
writer.width(), writer.height());
|
writer.width(), writer.height());
|
||||||
renderDiagram(diagram, painter, target);
|
renderDiagram(diagram, painter, target);
|
||||||
|
|
||||||
|
// Inject clickable cross-reference / folio-report hyperlinks for this
|
||||||
|
// page. The geometry is rebuilt from the QPdfWriter (not a QPrinter):
|
||||||
|
// render() anchors the diagram top-left with KeepAspectRatio, and the
|
||||||
|
// page is sized to the diagram so the scale is ~1.
|
||||||
|
if (auto *engine = dynamic_cast<QPdfEngine *>(painter.paintEngine())) {
|
||||||
|
const QRectF source(r);
|
||||||
|
const qreal s = qMin(target.width() / source.width(),
|
||||||
|
target.height() / source.height());
|
||||||
|
QTransform fit;
|
||||||
|
fit.translate(target.x(), target.y());
|
||||||
|
fit.scale(s, s);
|
||||||
|
fit.translate(-source.x(), -source.y());
|
||||||
|
|
||||||
|
// Device pixels -> PDF points, replicating the engine's page matrix
|
||||||
|
// (72/resolution scale + Y flip; zero margins -> no paint offset).
|
||||||
|
const qreal pt_scale = 72.0 / writer.resolution();
|
||||||
|
const qreal fullH_pt = writer.pageLayout().fullRectPoints().height();
|
||||||
|
const bool fullPageMode =
|
||||||
|
(writer.pageLayout().mode() == QPageLayout::FullPageMode);
|
||||||
|
const QRect paintPx =
|
||||||
|
writer.pageLayout().paintRectPixels(writer.resolution());
|
||||||
|
|
||||||
|
PdfLinks::PageGeometry geom;
|
||||||
|
geom.sceneToDevice = fit;
|
||||||
|
geom.target = target;
|
||||||
|
geom.pageBounds = QRectF(0, 0, target.width(), target.height());
|
||||||
|
geom.devToPdf = [=](const QPointF &d) -> QPointF {
|
||||||
|
qreal dx = d.x(), dy = d.y();
|
||||||
|
if (!fullPageMode) { dx += paintPx.left(); dy += paintPx.top(); }
|
||||||
|
return QPointF(pt_scale * dx, fullH_pt - pt_scale * dy);
|
||||||
|
};
|
||||||
|
geom.sourceRectOf = [](Diagram *dg) {
|
||||||
|
return QRectF(diagramRect(dg));
|
||||||
|
};
|
||||||
|
PdfLinks::injectCrossRefLinks(engine, diagram, geom, pageMap, output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
painter.end();
|
painter.end();
|
||||||
|
|
||||||
|
// Rewrite the URI link annotations into native internal GoTo actions, so
|
||||||
|
// the cross-references jump inside the document in any PDF viewer.
|
||||||
|
PdfLinks::convertUriToGoTo(output);
|
||||||
|
|
||||||
out << "Exported " << diagrams.size() << " page(s) -> " << output << "\n";
|
out << "Exported " << diagrams.size() << " page(s) -> " << output << "\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user