mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-15 10:04:13 +02:00
Speed up opening .qetz projects with large pictures
A .qetz keeps each folio picture as a PNG file. On opening, join() put every picture back into the document as base64 text, and the folio then decoded that text again, twice. On a project with 20 pictures of 7 MB (140 MB of PNG, the shape of the project on PR #1462) that cost about 8 of the 12 seconds the open took: QDomDocument::createTextNode() on the base64 3.9 s DiagramImageItem::fromXml(), base64 decoded 3.9 s (2 x 1.9 s) the PNG decoding itself 0.3 s join() now takes an optional map. Given one, each picture stays a file: the <image> keeps its qetz-file attribute and the bytes go in the map. QETProject keeps the map for as long as the project is open, and Diagram::fromXml() hands a picture's bytes to the new DiagramImageItem::fromXml(element, picture). Kept, not cleared after the load, so a folio built later finds its pictures too; the bytes are shared with the PNG cache of the pictures built from them, so this costs almost no memory. readDocument() without a map, as the automatic numbering import uses it, still gives the whole document. fromXml() of a .qet picture also decodes its base64 once instead of twice: the first text node, which the PNG cache already used. e.text() also collects <image_base>'s text, but loadFromData() stops at the end of the first picture, so the picture shown is the same. Measured, same file, 3 runs each, offscreen: .qetz 11.8 s -> 3.8 s, peak memory 1034 MB -> 655 MB .qet 15.7 s -> 13.6 s Resaving either file with either binary gives the same bytes, a cropped and colour-keyed picture included, and every folio exports to the same PNG pixels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -155,13 +155,19 @@ bool QetContainer::isZip(const QByteArray &content)
|
||||
The project document held in @p content: unzipped and joined for a
|
||||
.qetz, parsed for a .qet.
|
||||
*/
|
||||
bool QetContainer::readDocument(const QByteArray &content, QDomDocument *document, QString *error)
|
||||
bool QetContainer::readDocument(const QByteArray &content, QDomDocument *document,
|
||||
QString *error, Pictures *pictures)
|
||||
{
|
||||
if (!isZip(content))
|
||||
return parse(content, document, error);
|
||||
QList<QetZip::Entry> entries;
|
||||
return QetZip::fromBytes(content, &entries, error)
|
||||
&& join(entries, document, error);
|
||||
&& join(entries, document, error, pictures);
|
||||
}
|
||||
|
||||
QString QetContainer::pictureFile(const QDomElement &image)
|
||||
{
|
||||
return image.attribute(ImageFileAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,8 +270,11 @@ QList<QetZip::Entry> QetContainer::split(const QDomDocument &project, const QStr
|
||||
Refused, with @p error set: not a .qetz, made for a later QElectroTech
|
||||
(the manifest's min-reader), or a part missing or unreadable. Entries
|
||||
nothing names are ignored, so a later format may add some.
|
||||
With @p pictures, the pictures stay out of the document: see the
|
||||
namespace.
|
||||
*/
|
||||
bool QetContainer::join(const QList<QetZip::Entry> &entries, QDomDocument *project, QString *error)
|
||||
bool QetContainer::join(const QList<QetZip::Entry> &entries, QDomDocument *project, QString *error,
|
||||
Pictures *pictures)
|
||||
{
|
||||
QHash<QString, QByteArray> files;
|
||||
for (const QetZip::Entry &entry : entries)
|
||||
@@ -310,7 +319,8 @@ bool QetContainer::join(const QList<QetZip::Entry> &entries, QDomDocument *proje
|
||||
part.parentNode().replaceChild(project->importNode(document.documentElement(), true), part);
|
||||
}
|
||||
|
||||
//Pictures back to base64, as the image's first child
|
||||
//Pictures back to base64, as the image's first child, or into
|
||||
//pictures
|
||||
const QDomNodeList images = project->elementsByTagName(QStringLiteral("image"));
|
||||
for (int i = 0 ; i < images.size() ; ++i)
|
||||
{
|
||||
@@ -321,6 +331,10 @@ bool QetContainer::join(const QList<QetZip::Entry> &entries, QDomDocument *proje
|
||||
setError(error, QStringLiteral("picture \"%1\" is missing").arg(file));
|
||||
return false;
|
||||
}
|
||||
if (pictures) {
|
||||
pictures->insert(file, files.value(file));
|
||||
continue;
|
||||
}
|
||||
image.removeAttribute(ImageFileAttribute);
|
||||
image.insertBefore(project->createTextNode(QString::fromLatin1(files.value(file).toBase64())),
|
||||
image.firstChild());
|
||||
|
||||
Reference in New Issue
Block a user