mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-25 15:34:13 +01:00
Merge pull request #1317 from ispyisail/fix/pdf-trailer-startxref
Fix repeatable PDF changing with the output folder (#1178)
This commit is contained in:
+18
-35
@@ -194,6 +194,22 @@ void injectCrossRefLinks(QPdfEngine *engine, Diagram *diagram,
|
|||||||
engine->drawHyperlink(link.rect, link.url);
|
engine->drawHyperlink(link.rect, link.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The trailer dictionary of the xref table at \a xrefStart, from
|
||||||
|
/// "trailer" up to its startxref, which the caller writes again with the
|
||||||
|
/// new offset. Copying the old startxref too left a second one in the
|
||||||
|
/// file, with the size the file had before its links were rewritten, so
|
||||||
|
/// the bytes depended on the output path the links carry (#1178).
|
||||||
|
static QByteArray trailerDictionary(const QByteArray &data, int xrefStart)
|
||||||
|
{
|
||||||
|
const int start = data.indexOf("trailer", xrefStart);
|
||||||
|
if (start == -1)
|
||||||
|
return "trailer\n<<>>";
|
||||||
|
const int end = data.indexOf("startxref", start);
|
||||||
|
if (end == -1)
|
||||||
|
return "trailer\n<<>>";
|
||||||
|
return data.mid(start, end - start).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
void convertUriToGoTo(const QString &pdfPath)
|
void convertUriToGoTo(const QString &pdfPath)
|
||||||
{
|
{
|
||||||
// --- 1. Read raw bytes ---
|
// --- 1. Read raw bytes ---
|
||||||
@@ -383,19 +399,7 @@ void convertUriToGoTo(const QString &pdfPath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find trailer dict from the original xref section
|
const QByteArray trailer = trailerDictionary(data, xrefStart);
|
||||||
int trailerPos = data.indexOf("trailer", xrefStart);
|
|
||||||
int trailerEnd = -1;
|
|
||||||
if (trailerPos != -1) {
|
|
||||||
trailerEnd = data.indexOf("%%EOF", trailerPos);
|
|
||||||
if (trailerEnd != -1) trailerEnd += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray trailer;
|
|
||||||
if (trailerPos != -1 && trailerEnd != -1)
|
|
||||||
trailer = data.mid(trailerPos, trailerEnd - trailerPos);
|
|
||||||
else
|
|
||||||
trailer = "trailer\n<<>>\n%%EOF";
|
|
||||||
|
|
||||||
int newXrefOffset = body.size();
|
int newXrefOffset = body.size();
|
||||||
|
|
||||||
@@ -814,18 +818,7 @@ void convertComponentInfoAnnotations(const QString &pdfPath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy trailer and bump /Size to account for the new XObject
|
// Copy trailer and bump /Size to account for the new XObject
|
||||||
QByteArray trailer;
|
QByteArray trailer = trailerDictionary(data, xrefStart);
|
||||||
{
|
|
||||||
int tPos = data.indexOf("trailer", xrefStart);
|
|
||||||
if (tPos != -1) {
|
|
||||||
int tEnd = data.indexOf("%%EOF", tPos);
|
|
||||||
if (tEnd != -1) tEnd += 5;
|
|
||||||
if (tEnd != -1)
|
|
||||||
trailer = data.mid(tPos, tEnd - tPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (trailer.isEmpty())
|
|
||||||
trailer = "trailer\n<<>>\n%%EOF";
|
|
||||||
|
|
||||||
// Bump /Size: original was maxObjNum+1, now it's emptyXObjNum+1
|
// Bump /Size: original was maxObjNum+1, now it's emptyXObjNum+1
|
||||||
{
|
{
|
||||||
@@ -842,16 +835,6 @@ void convertComponentInfoAnnotations(const QString &pdfPath,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate startxref if present in copied trailer
|
|
||||||
{
|
|
||||||
int stPos = trailer.indexOf("\nstartxref\n");
|
|
||||||
if (stPos != -1)
|
|
||||||
trailer = trailer.left(stPos);
|
|
||||||
// Ensure trailer ends with %%EOF
|
|
||||||
if (!trailer.endsWith("%%EOF\n"))
|
|
||||||
trailer += "\n%%EOF\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
result.reserve(out.size() + xref.size() + trailer.size() + 64);
|
result.reserve(out.size() + xref.size() + trailer.size() + 64);
|
||||||
result += out;
|
result += out;
|
||||||
|
|||||||
@@ -22,12 +22,17 @@ class tst_pdfreproducible : public QObject
|
|||||||
QTemporaryDir m_dir;
|
QTemporaryDir m_dir;
|
||||||
int m_run = 0;
|
int m_run = 0;
|
||||||
|
|
||||||
QByteArray exportPdf(const QString &project, const QByteArray &epoch)
|
QByteArray exportPdf(const QString &project, const QByteArray &epoch,
|
||||||
|
const QString &folder = QString())
|
||||||
{
|
{
|
||||||
const int run = m_run++;
|
const int run = m_run++;
|
||||||
const QString home = m_dir.filePath(QStringLiteral("home%1").arg(run));
|
const QString home = m_dir.filePath(QStringLiteral("home%1").arg(run));
|
||||||
const QString tmp = m_dir.filePath(QStringLiteral("tmp%1").arg(run));
|
const QString tmp = m_dir.filePath(QStringLiteral("tmp%1").arg(run));
|
||||||
const QString out = m_dir.filePath(QStringLiteral("out%1.pdf").arg(run));
|
const QString out = folder.isEmpty()
|
||||||
|
? m_dir.filePath(QStringLiteral("out%1.pdf").arg(run))
|
||||||
|
: m_dir.filePath(folder + QStringLiteral("/same.pdf"));
|
||||||
|
if (!folder.isEmpty())
|
||||||
|
QDir().mkpath(m_dir.filePath(folder));
|
||||||
QDir().mkpath(home);
|
QDir().mkpath(home);
|
||||||
QDir().mkpath(tmp);
|
QDir().mkpath(tmp);
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
@@ -145,6 +150,23 @@ private slots:
|
|||||||
"the same drawing with new uuids gives a different PDF");
|
"the same drawing with new uuids gives a different PDF");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sameBytesInAnyFolder()
|
||||||
|
{
|
||||||
|
// #1178: the links carry the output path, and rewriting them left
|
||||||
|
// the old startxref in the file, with the size the file had before.
|
||||||
|
const QString project =
|
||||||
|
QStringLiteral(QET_EXAMPLES_DIR) + QStringLiteral("/iso_sfc_example.qet");
|
||||||
|
QVERIFY2(QFile::exists(project), "examples/iso_sfc_example.qet not found");
|
||||||
|
|
||||||
|
const QByteArray first = exportPdf(project, "1700000000", QStringLiteral("p"));
|
||||||
|
QVERIFY(!first.isEmpty());
|
||||||
|
QVERIFY(first.contains("/GoTo"));
|
||||||
|
QCOMPARE(first.count("startxref"), 1);
|
||||||
|
QVERIFY2(xrefMatches(first), "the xref table does not match the file");
|
||||||
|
QVERIFY2(exportPdf(project, "1700000000", QStringLiteral("longer-folder-name")) == first,
|
||||||
|
"the same project gives a different PDF in another folder");
|
||||||
|
}
|
||||||
|
|
||||||
void nowWithoutTheVariable()
|
void nowWithoutTheVariable()
|
||||||
{
|
{
|
||||||
const QString project =
|
const QString project =
|
||||||
|
|||||||
Reference in New Issue
Block a user