From 345f86a2d8d69c6d3cbae314028902f090f39a43 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 13 May 2019 11:57:00 +1000 Subject: Avoid re-encoding embedded images when writing an ODF file If an embedded image is already encodeded as an png or jpg write the data as is instead of decoding to a QImage and re-encoding as a new image. Change-Id: I479ae1fddbf59900a500497dd1bdf7449c21f273 Reviewed-by: Lars Knoll --- src/gui/text/qtextodfwriter.cpp | 87 ++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 19 deletions(-) (limited to 'src/gui/text/qtextodfwriter.cpp') diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index 103e0a8222..1a96f7608f 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -43,6 +43,7 @@ #include "qtextodfwriter_p.h" +#include #include #include #include @@ -410,6 +411,29 @@ void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &bloc writer.writeEndElement(); // list-item } +static bool probeImageData(QIODevice *device, QImage *image, QString *mimeType, qreal *width, qreal *height) +{ + QImageReader reader(device); + const QByteArray format = reader.format().toLower(); + if (format == "png") { + *mimeType = QStringLiteral("image/png"); + } else if (format == "jpg") { + *mimeType = QStringLiteral("image/jpg"); + } else if (format == "svg") { + *mimeType = QStringLiteral("image/svg+xml"); + } else { + *image = reader.read(); + return false; + } + + const QSize size = reader.size(); + + *width = size.width(); + *height = size.height(); + + return true; +} + void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextFragment &fragment) const { writer.writeStartElement(drawNS, QString::fromLatin1("frame")); @@ -420,46 +444,71 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); writer.writeAttribute(drawNS, QString::fromLatin1("name"), imageFormat.name()); + QByteArray data; + QString mimeType; + qreal width = 0; + qreal height = 0; + QImage image; QString name = imageFormat.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); QUrl url = QUrl(name); - const QVariant data = m_document->resource(QTextDocument::ImageResource, url); - if (data.type() == QVariant::Image) { - image = qvariant_cast(data); - } else if (data.type() == QVariant::ByteArray) { - image.loadFromData(data.toByteArray()); - } - - if (image.isNull()) { - if (image.isNull()) { // try direct loading - name = imageFormat.name(); // remove qrc:/ prefix again - image.load(name); + const QVariant variant = m_document->resource(QTextDocument::ImageResource, url); + if (variant.type() == QVariant::Image) { + image = qvariant_cast(variant); + } else if (variant.type() == QVariant::ByteArray) { + data = variant.toByteArray(); + + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + probeImageData(&buffer, &image, &mimeType, &width, &height); + } else { + // try direct loading + QFile file(imageFormat.name()); + if (file.open(QIODevice::ReadOnly) && !probeImageData(&file, &image, &mimeType, &width, &height)) { + file.seek(0); + data = file.readAll(); } } if (! image.isNull()) { QBuffer imageBytes; - QString filename = m_strategy->createUniqueImageName(); + int imgQuality = imageFormat.quality(); if (imgQuality >= 100 || imgQuality < 0 || image.hasAlphaChannel()) { QImageWriter imageWriter(&imageBytes, "png"); imageWriter.write(image); - m_strategy->addFile(filename, QString::fromLatin1("image/png"), imageBytes.data()); + + data = imageBytes.data(); + mimeType = QStringLiteral("image/png"); } else { // Write images without alpha channel as jpg with quality set by QTextImageFormat QImageWriter imageWriter(&imageBytes, "jpg"); imageWriter.setQuality(imgQuality); imageWriter.write(image); - m_strategy->addFile(filename, QString::fromLatin1("image/jpg"), imageBytes.data()); + + data = imageBytes.data(); + mimeType = QStringLiteral("image/jpg"); } - // get the width/height from the format. - qreal width = imageFormat.hasProperty(QTextFormat::ImageWidth) - ? imageFormat.width() : image.width(); + + width = image.width(); + height = image.height(); + } + + if (!data.isEmpty()) { + if (imageFormat.hasProperty(QTextFormat::ImageWidth)) { + width = imageFormat.width(); + } + if (imageFormat.hasProperty(QTextFormat::ImageHeight)) { + height = imageFormat.height(); + } + + QString filename = m_strategy->createUniqueImageName(); + + m_strategy->addFile(filename, mimeType, data); + writer.writeAttribute(svgNS, QString::fromLatin1("width"), pixelToPoint(width)); - qreal height = imageFormat.hasProperty(QTextFormat::ImageHeight) - ? imageFormat.height() : image.height(); writer.writeAttribute(svgNS, QString::fromLatin1("height"), pixelToPoint(height)); writer.writeStartElement(drawNS, QString::fromLatin1("image")); writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), filename); -- cgit v1.2.3 From d661a22ae283c604e9e95eceeaf4e6b47e7e1753 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 13 May 2019 12:09:04 +1000 Subject: Write an anchor-type attribute when embedding images in an ODF document Without this some readers will fail to display the image or position the image at the start of a paragraph rather than inline. Change-Id: I2b9257e3193e5e68eb20112017a0c23be1d06cb0 Reviewed-by: Lars Knoll --- src/gui/text/qtextodfwriter.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/gui/text/qtextodfwriter.cpp') diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index 1a96f7608f..1906502c10 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -510,6 +510,7 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF writer.writeAttribute(svgNS, QString::fromLatin1("width"), pixelToPoint(width)); writer.writeAttribute(svgNS, QString::fromLatin1("height"), pixelToPoint(height)); + writer.writeAttribute(textNS, QStringLiteral("anchor-type"), QStringLiteral("as-char")); writer.writeStartElement(drawNS, QString::fromLatin1("image")); writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), filename); writer.writeEndElement(); // image -- cgit v1.2.3