Commit c19b1956 authored by Wescoeur's avatar Wescoeur

feat(App): use a custom svg parser

parent 24a83838
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
*/ */
#include <QFile> #include <QFile>
#include <QFileInfo>
#include <QImage> #include <QImage>
#include <QPainter> #include <QPainter>
#include <QSvgRenderer> #include <QSvgRenderer>
...@@ -29,6 +30,9 @@ ...@@ -29,6 +30,9 @@
#include "ImageProvider.hpp" #include "ImageProvider.hpp"
// Max image size in bytes. (100Kb)
#define MAX_IMAGE_SIZE 102400
// ============================================================================= // =============================================================================
const QString ImageProvider::PROVIDER_ID = "internal"; const QString ImageProvider::PROVIDER_ID = "internal";
...@@ -38,55 +42,139 @@ ImageProvider::ImageProvider () : QQuickImageProvider( ...@@ -38,55 +42,139 @@ ImageProvider::ImageProvider () : QQuickImageProvider(
QQmlImageProviderBase::ForceAsynchronousImageLoading QQmlImageProviderBase::ForceAsynchronousImageLoading
) {} ) {}
QImage ImageProvider::requestImage (const QString &id, QSize *, const QSize &) { // -----------------------------------------------------------------------------
const QString path = QStringLiteral(":/assets/images/%1").arg(id);
// 1. Read and update XML content. static QByteArray parseAttributes (QXmlStreamReader &reader) {
QFile file(path); // TODO: Check file size. QByteArray attributes;
if (!file.open(QIODevice::ReadOnly)) for (const auto &attribute : reader.attributes()) {
return QImage(); // Invalid file. const QByteArray prefix = attribute.prefix().toLatin1();
if (prefix.length() > 0) {
attributes.append(prefix);
attributes.append(":");
}
attributes.append(attribute.name().toLatin1());
attributes.append("=\"");
attributes.append(attribute.value().toLatin1());
attributes.append("\" ");
}
return attributes;
}
static QByteArray parseDeclarations (QXmlStreamReader &reader) {
QByteArray declarations;
for (const auto &declaration : reader.namespaceDeclarations()) {
const QByteArray prefix = declaration.prefix().toLatin1();
if (prefix.length() > 0) {
declarations.append("xmlns:");
declarations.append(prefix);
} else
declarations.append("xmlns");
declarations.append("=\"");
declarations.append(declaration.namespaceUri().toLatin1());
declarations.append("\" ");
}
return declarations;
}
static QByteArray parseStartDocument (QXmlStreamReader &reader) {
QByteArray startDocument = "<?xml version=\"";
startDocument.append(reader.documentVersion().toLatin1());
startDocument.append("\" encoding=\"");
startDocument.append(reader.documentEncoding().toLatin1());
startDocument.append("\"?>");
return startDocument;
}
static QByteArray parseStartElement (QXmlStreamReader &reader) {
QByteArray startElement = "<";
startElement.append(reader.name().toLatin1());
startElement.append(" ");
startElement.append(parseAttributes(reader));
startElement.append(" ");
startElement.append(parseDeclarations(reader));
startElement.append(">");
return startElement;
}
static QByteArray parseEndElement (QXmlStreamReader &reader) {
QByteArray endElement = "</";
endElement.append(reader.name().toLatin1());
endElement.append(">");
return endElement;
}
QString content; // -----------------------------------------------------------------------------
static QByteArray computeContent (QFile &file) {
QByteArray content;
QXmlStreamReader reader(&file); QXmlStreamReader reader(&file);
while (!reader.atEnd()) while (!reader.atEnd())
switch (reader.readNext()) { switch (reader.readNext()) {
case QXmlStreamReader::Comment: case QXmlStreamReader::Comment:
case QXmlStreamReader::DTD: case QXmlStreamReader::DTD:
case QXmlStreamReader::EndDocument: case QXmlStreamReader::EndDocument:
case QXmlStreamReader::EntityReference:
case QXmlStreamReader::Invalid: case QXmlStreamReader::Invalid:
case QXmlStreamReader::NoToken: case QXmlStreamReader::NoToken:
case QXmlStreamReader::ProcessingInstruction: case QXmlStreamReader::ProcessingInstruction:
case QXmlStreamReader::StartDocument:
break; break;
case QXmlStreamReader::StartElement: { case QXmlStreamReader::StartDocument:
QXmlStreamNamespaceDeclarations declarations = reader.namespaceDeclarations(); content.append(parseStartDocument(reader));
QXmlStreamAttributes attributes = reader.attributes(); break;
for (const auto &declaration : declarations) { case QXmlStreamReader::StartElement:
qDebug() << "toto" << declaration.namespaceUri() << declaration.prefix(); content.append(parseStartElement(reader));
} break;
} break; // TODO.
case QXmlStreamReader::EndElement: case QXmlStreamReader::EndElement:
content.append(QStringLiteral("</%1>").arg(reader.name().toString())); content.append(parseEndElement(reader));
break; break;
case QXmlStreamReader::Characters: case QXmlStreamReader::Characters:
content.append(reader.text()); content.append(reader.text().toLatin1());
break;
case QXmlStreamReader::EntityReference:
content.append(reader.name().toLatin1());
break; break;
} }
qDebug() << content; return reader.hasError() ? QByteArray() : content;
}
// -----------------------------------------------------------------------------
if (reader.hasError()) QImage ImageProvider::requestImage (const QString &id, QSize *, const QSize &) {
return QImage(); // Invalid file. const QString path = QStringLiteral(":/assets/images/%1").arg(id);
// 1. Read and update XML content.
QFile file(path);
if (QFileInfo(file).size() > MAX_IMAGE_SIZE) {
qWarning() << QStringLiteral("Unable to open large file: `%1`.").arg(path);
return QImage();
}
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << QStringLiteral("Unable to open file: `%1`.").arg(path);
return QImage();
}
const QByteArray content = computeContent(file);
if (!content.length()) {
qWarning() << QStringLiteral("Unable to parse file: `%1`.").arg(path);
return QImage();
}
// 2. Build svg renderer. // 2. Build svg renderer.
QSvgRenderer renderer(&reader); QSvgRenderer renderer(content);
if (!renderer.isValid()) if (!renderer.isValid()) {
return QImage(path); // Not a svg file. qWarning() << QStringLiteral("Invalid svg file: `%1`.").arg(path);
return QImage();
}
// 3. Create en empty image. // 3. Create en empty image.
const QRectF viewBox = renderer.viewBoxF(); const QRectF viewBox = renderer.viewBoxF();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment