Put a landscape folio on its standard sheet in --export-pdf

The PDF export sizes each page to its folio, and QPageSize rounds a size
within 3 pt of a standard sheet to the sheet. QPageSize knows the sheets
upright only (bar Ledger), so only portrait folios snapped: an A3 landscape
folio came out as a 1190 x 841 pt page, while an A3 portrait one was
842 x 1191, the sheet. A wide folio is now matched upright and turned.

tst_pdfpagesize exports a fixture with an A3 folio each way and checks both
pages are A3; it fails without the change (1190 x 841).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-02 22:53:13 +13:00
parent 808d6a3c5b
commit 797d502c0a
4 changed files with 171 additions and 5 deletions
+12 -5
View File
@@ -171,11 +171,18 @@ int exportPdf(QETProject &project, const QString &output,
for (Diagram *diagram : diagrams) {
const QRect r = diagramRect(diagram);
// Match the page to the diagram (in points: 1px @ 96dpi = 0.75pt).
const QPageSize page(QSizeF(r.width() * 72.0 / 96.0,
r.height() * 72.0 / 96.0),
QPageSize::Point);
writer.setPageSize(page);
writer.setPageMargins(QMarginsF(0, 0, 0, 0));
// QPageSize rounds a size within 3 pt of a standard sheet to the
// sheet, but knows the sheets upright only (bar Ledger), so a wide
// folio is matched upright and turned: otherwise an A3 landscape
// folio became a 1190 x 841 pt page while an A3 portrait one was
// 842 x 1191, the sheet.
QSizeF points(r.width() * 72.0 / 96.0, r.height() * 72.0 / 96.0);
const bool wide = points.width() > points.height();
if (wide) points.transpose();
writer.setPageLayout(QPageLayout(QPageSize(points, QPageSize::Point),
wide ? QPageLayout::Landscape
: QPageLayout::Portrait,
QMarginsF(0, 0, 0, 0)));
if (first) {
if (!painter.begin(&writer)) {
+12
View File
@@ -388,6 +388,18 @@ target_compile_definitions(tst_wiringlistexport PRIVATE
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\""
"QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"")
# --export-pdf puts an A3 folio on an A3 page whichever way it is turned:
# QPageSize matches standard sheets upright only, so a wide folio is matched
# upright and turned. fixtures/pdf_page_a3.qet has one folio each way.
add_executable(
tst_pdfpagesize
tst_pdfpagesize.cpp)
add_test(NAME tst_pdfpagesize COMMAND tst_pdfpagesize)
add_dependencies(tst_pdfpagesize qelectrotech)
target_link_libraries(tst_pdfpagesize PRIVATE Qt::Test Qt::Gui)
target_compile_definitions(tst_pdfpagesize PRIVATE
"QET_TEST_BINARY_PATH=\"$<TARGET_FILE:qelectrotech>\"")
# Hops where wires cross (issue #436): the geometry in wirehops.cpp, and
# through the real binary, that --resave keeps the project setting and
# adds nothing to a project without it.
+63
View File
@@ -0,0 +1,63 @@
<project title="pdf page size" uuid="{63126da6-a8f2-5840-8149-a23a51406a32}" version="0.200.1">
<properties>
<property name="saveddate" show="1">10/2/26</property>
<property name="saveddate-eu" show="1">02-10-2026</property>
<property name="saveddate-us" show="1">2026-10-02</property>
<property name="savedfilename" show="1">pdf_page_a3</property>
<property name="savedtime" show="1">22:39</property>
</properties>
<usage enabled="true" time_spent="0"/>
<newdiagrams>
<border cols="17" colsize="60" displaycols="true" displayrows="true" rows="8" rowsize="80"/>
<inset author="" auto_page_num="" date="null" displayAt="bottom" filename="" folio="" indexrev="" locmach="" plant="" title="" version=""/>
<conductors bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
<report label="%f-%l%c"/>
<xrefs>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="coil" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="commutator" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="plc" xrefpos="AlignBottom"/>
<xref delayprefix="" displayhas="cross" master_label="%f-%l%c" offset="0" powerprefix="" showallconfiguredslaves="false" showpowerctc="true" showterminalname="true" slave_label="(%f-%l%c)" slave_offset="0" snapto="label" switchprefix="" type="protection" xrefpos="AlignBottom"/>
</xrefs>
<conductors_autonums auto_break_conductors="false" current_autonum="" freeze_new_conductors="false"/>
<folio_autonums/>
<element_autonums current_autonum="" freeze_new_elements="false"/>
<guides/>
</newdiagrams>
<diagram author="" auto_page_num="" cols="27" colsize="58" date="null" displayAt="bottom" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="1070" indexrev="" locmach="" order="1" plant="" rows="14" rowsize="75" title="" uuid="{270fad7d-7d9f-4198-a0e1-dceb22c883cc}" version="0.200.1-dev">
<defaultconductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
</diagram>
<diagram author="" auto_page_num="" cols="20" colsize="55" date="null" displayAt="bottom" displaycols="true" displayrows="true" filename="" folio="" freezeNewConductor="false" freezeNewElement="false" height="1535" indexrev="" locmach="" order="2" plant="" rows="15" rowsize="101" title="" uuid="{9cf88404-d198-4690-90f7-647fb7940f68}" version="0.200.1-dev">
<defaultconductor bicolor="false" bus="" cable="" color2="#000000" condsize="1" conductor_color="" conductor_section="" dash-size="1" displaytext="1" formula="" function="" horizontal-alignment="AlignBottom" horizrotatetext="0" num="_" numsize="7" onetextperfolio="0" tension_protocol="" text_color="#000000" type="multi" vertical-alignment="AlignRight" vertirotatetext="270"/>
</diagram>
<collection>
<category name="import">
<names>
<name lang="ca">Elements importats</name>
<name lang="cs">Zavedené prvky</name>
<name lang="da">Importerede elementer</name>
<name lang="de">Importierte Elemente</name>
<name lang="el">Εισηγμένα στοιχεία</name>
<name lang="en">Imported elements</name>
<name lang="es">Elementos importados</name>
<name lang="fr">Éléments importés</name>
<name lang="hr">Uvezeni elementi</name>
<name lang="it">Elementi importati</name>
<name lang="ja">インバートされた要素</name>
<name lang="ko">전기 심볼 요소</name>
<name lang="ko_KR">전기 심볼 요소</name>
<name lang="nl">Elementen geïmporteerd</name>
<name lang="nl_BE">Elementen geïmporteerd</name>
<name lang="pl">Elementy importowane</name>
<name lang="pt">Elementos importados</name>
<name lang="pt_BR">Elementos importados</name>
<name lang="ro">Elemente importate</name>
<name lang="ru">Импортированные элементы</name>
<name lang="sl">Uvoženi elementi</name>
<name lang="sv">Importerade element</name>
<name lang="tr">İthal öğeler</name>
<name lang="uk">Імпортовані елементи</name>
<name lang="zh">导入元件</name>
</names>
</category>
</collection>
</project>
+84
View File
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QtTest>
#include <QDir>
#include <QFile>
#include <QPageSize>
#include <QProcess>
#include <QProcessEnvironment>
#include <QRegularExpression>
#include <QTemporaryDir>
// --export-pdf sizes each page to its folio, and QPageSize rounds a size
// within 3 pt of a standard sheet to the sheet. It knows the sheets upright
// only, so a wide folio used to miss: the fixture's A3 landscape folio
// (frame 1190.25 x 840.75 pt) came out 1190 x 841 pt while its A3 portrait
// folio came out 842 x 1191, the sheet. Both must land on A3.
class tst_pdfpagesize : public QObject
{
Q_OBJECT
QTemporaryDir m_dir;
// The MediaBox of each page, in page order. Qt writes one uncompressed
// "/MediaBox [0 0 w h]" per page object.
QList<QSizeF> exportPages(const QString &project)
{
const QString home = m_dir.filePath(QStringLiteral("home"));
const QString tmp = m_dir.filePath(QStringLiteral("tmp"));
const QString out = m_dir.filePath(QStringLiteral("out.pdf"));
QDir().mkpath(home);
QDir().mkpath(tmp);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen"));
env.insert(QStringLiteral("HOME"), home);
env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/.config"));
env.insert(QStringLiteral("XDG_DATA_HOME"), home + QStringLiteral("/.local/share"));
env.insert(QStringLiteral("TMPDIR"), tmp);
QProcess proc;
proc.setProcessEnvironment(env);
proc.start(QStringLiteral(QET_TEST_BINARY_PATH),
{QStringLiteral("--export-pdf"), project, out});
if (!proc.waitForFinished(60000) || proc.exitCode() != 0)
return {};
QFile file(out);
if (!file.open(QIODevice::ReadOnly))
return {};
const QString pdf = QString::fromLatin1(file.readAll());
static const QRegularExpression box(
QStringLiteral(R"(/MediaBox \[0 0 ([0-9.]+) ([0-9.]+)\])"));
QList<QSizeF> pages;
auto it = box.globalMatch(pdf);
while (it.hasNext()) {
const auto m = it.next();
pages << QSizeF(m.captured(1).toDouble(), m.captured(2).toDouble());
}
return pages;
}
private slots:
void initTestCase()
{
QVERIFY(m_dir.isValid());
QVERIFY(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)));
}
void a3BothWays()
{
const QString fixture = QFINDTESTDATA("fixtures/pdf_page_a3.qet");
QVERIFY2(!fixture.isEmpty(), "fixture project not found");
const QList<QSizeF> pages = exportPages(fixture);
QCOMPARE(pages.size(), 2);
// Qt writes the sheet's whole points: 842 x 1191 for A3.
const QSize a3 = QPageSize(QPageSize::A3).sizePoints();
QCOMPARE(pages.at(0), QSizeF(a3.height(), a3.width())); // landscape
QCOMPARE(pages.at(1), QSizeF(a3)); // portrait
}
};
QTEST_MAIN(tst_pdfpagesize)
#include "tst_pdfpagesize.moc"