diff --git a/sources/qetgraphicsitem/diagramimageitem.cpp b/sources/qetgraphicsitem/diagramimageitem.cpp index ed81b4619..843657b54 100644 --- a/sources/qetgraphicsitem/diagramimageitem.cpp +++ b/sources/qetgraphicsitem/diagramimageitem.cpp @@ -1686,7 +1686,12 @@ bool DiagramImageItem::fromXml(const QDomElement &e) // pivot), the same two-tier fallback QetShapeItem's own fromXml() // already uses for its identical element. m_transform.rotation = e.attribute("rotation").toDouble(); - m_transform.scaleX = e.attribute("size").toDouble(); + //A missing, unreadable, non-finite or zero size would scale the + //picture to nothing (and a resave wrote size="0" back): use 1, + //the size a picture is added with, as the branch does + bool size_ok = false; + const qreal size = e.attribute("size").toDouble(&size_ok); + m_transform.scaleX = (size_ok && qIsFinite(size) && size != 0) ? size : 1; m_transform.scaleY = m_transform.scaleX; m_transform.pivot = imageRect().center(); m_pivotIsCustom = false; diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt index fe45c2b4d..3572ed416 100644 --- a/tests/qttest/CMakeLists.txt +++ b/tests/qttest/CMakeLists.txt @@ -1037,6 +1037,19 @@ target_compile_definitions(tst_terminaluuids PRIVATE "QET_TEST_BINARY_PATH=\"$\"" "QET_EXAMPLES_DIR=\"${QET_DIR}/examples\"") +# A picture whose size attribute is missing, unreadable, "nan" or 0 is +# loaded at size 1, not 0: the real binary's --resave and --export-svg on +# fixtures/image_missing_size.qet. +add_executable( + tst_imagemissingsize + tst_imagemissingsize.cpp) +add_test(NAME tst_imagemissingsize COMMAND tst_imagemissingsize) +set_tests_properties(tst_imagemissingsize PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen") +add_dependencies(tst_imagemissingsize qelectrotech) +target_link_libraries(tst_imagemissingsize PRIVATE Qt::Test Qt::Xml) +target_compile_definitions(tst_imagemissingsize PRIVATE + "QET_TEST_BINARY_PATH=\"$\"") + # Sequential numbers saved the old way, as sequ_1/.../seqhf_1 attributes, # are all read: the real binary's --resave on # fixtures/legacy_sequential_attributes.qet, whose element and conductor diff --git a/tests/qttest/fixtures/image_missing_size.qet b/tests/qttest/fixtures/image_missing_size.qet new file mode 100644 index 000000000..af6933d73 --- /dev/null +++ b/tests/qttest/fixtures/image_missing_size.qet @@ -0,0 +1,45 @@ + + + 10/2/26 + 02-10-2026 + 2026-10-02 + image_missing_size + 18:39 + + + + + + + + + + + + + + + + + + + + + + + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAAFUlEQVR4nGM4ISdHNmIY1TyqmRACAJaAyyGTMvplAAAAAElFTkSuQmCC + + + + + + Imported elements + + + + diff --git a/tests/qttest/tst_imagemissingsize.cpp b/tests/qttest/tst_imagemissingsize.cpp new file mode 100644 index 000000000..0c1534498 --- /dev/null +++ b/tests/qttest/tst_imagemissingsize.cpp @@ -0,0 +1,108 @@ +/* + Copyright 2006-2026 The QElectroTech Team + This file is part of QElectroTech. + + QElectroTech is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + QElectroTech is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QElectroTech. If not, see . +*/ +#include +#include +#include +#include +#include + +/** + A picture on a folio (, without a child) whose size + attribute is missing, unreadable, "nan" or 0 is loaded at size 1. It + used to be loaded at size 0, so it was invisible, not exported, and a + resave wrote size="0" back. Runs the real binary's --resave and + --export-svg on fixtures/image_missing_size.qet: six 20x10 pictures, + one per size value, told apart by their y position. +*/ +class tst_imagemissingsize : public QObject +{ + Q_OBJECT + + QTemporaryDir m_dir; + QString m_fixture; + QDomDocument m_resaved; + + static bool runQet(const QStringList &arguments) + { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QStringLiteral("QT_QPA_PLATFORM"), QStringLiteral("offscreen")); + QProcess proc; + proc.setProcessEnvironment(env); + proc.start(QStringLiteral(QET_TEST_BINARY_PATH), arguments); + return proc.waitForFinished(60000) + && proc.exitStatus() == QProcess::NormalExit + && proc.exitCode() == 0; + } + +private slots: + void initTestCase() + { + QVERIFY2(QFile::exists(QStringLiteral(QET_TEST_BINARY_PATH)), "qelectrotech binary not found"); + QVERIFY(m_dir.isValid()); + m_fixture = QFINDTESTDATA("fixtures/image_missing_size.qet"); + QVERIFY2(!m_fixture.isEmpty(), "fixture project not found"); + const QString out = m_dir.filePath(QStringLiteral("resaved.qet")); + QVERIFY2(runQet({QStringLiteral("--resave"), m_fixture, out}), "--resave failed"); + QFile file(out); + QVERIFY(file.open(QIODevice::ReadOnly)); + QVERIFY(m_resaved.setContent(&file)); + } + + void savedSize_data() + { + QTest::addColumn("y"); + QTest::addColumn("size"); + QTest::newRow("missing") << "100" << "1"; + QTest::newRow("0") << "160" << "1"; + QTest::newRow("nan") << "220" << "1"; + QTest::newRow("not a number") << "280" << "1"; + // Usable sizes are kept, below and above 1. + QTest::newRow("0.5") << "340" << "0.5"; + QTest::newRow("2") << "400" << "2"; + } + + void savedSize() + { + QFETCH(QString, y); + QFETCH(QString, size); + const QDomNodeList list = m_resaved.elementsByTagName(QStringLiteral("image")); + QDomElement found; + for (int i = 0; i < list.size(); ++i) { + const QDomElement e = list.at(i).toElement(); + if (e.attribute(QStringLiteral("y")) == y) found = e; + } + QVERIFY2(!found.isNull(), "picture not found in the resaved project"); + QCOMPARE(found.attribute(QStringLiteral("size")), size); + } + + // All six pictures are drawn in the export. + void allPicturesAreExported() + { + const QString dir = m_dir.filePath(QStringLiteral("svg")); + QVERIFY(QDir().mkpath(dir)); + QVERIFY2(runQet({QStringLiteral("--export-svg"), m_fixture, dir}), "--export-svg failed"); + const QStringList files = QDir(dir).entryList({QStringLiteral("*.svg")}, QDir::Files); + QCOMPARE(files.size(), 1); + QFile svg(QDir(dir).filePath(files.first())); + QVERIFY(svg.open(QIODevice::ReadOnly)); + QCOMPARE(QString::fromUtf8(svg.readAll()).count(QStringLiteral("