dsvg imageformats plugin sans dtk dependency
This commit is contained in:
parent
383edf5627
commit
fbe90c3485
|
@ -1,8 +1,10 @@
|
|||
project (pimageformats)
|
||||
project(pimageformats)
|
||||
|
||||
cmake_minimum_required (VERSION 3.9.5)
|
||||
cmake_minimum_required(VERSION 3.9.5)
|
||||
|
||||
include (GNUInstallDirs)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
option(BUILD_EXPERIMENTAL_PLUGINS "Enable the build of imageformats plugin(s) that might not working" ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
@ -10,5 +12,8 @@ set(QT_MINIMUM_VERSION "5.10")
|
|||
|
||||
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Gui)
|
||||
|
||||
add_subdirectory(vendor/libsai)
|
||||
if(BUILD_EXPERIMENTAL_PLUGINS)
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/vendor/libsai)
|
||||
endif()
|
||||
|
||||
add_subdirectory(imageformats)
|
||||
|
|
|
@ -1,17 +1,4 @@
|
|||
set (plugin pimg_sai)
|
||||
|
||||
set (PLUGIN_SOURCES
|
||||
sai_p.h
|
||||
sai.cpp
|
||||
)
|
||||
|
||||
# {{{ KCM style
|
||||
set(CMAKE_SHARED_MODULE_PREFIX "")
|
||||
unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
# }}}
|
||||
|
||||
add_library(${plugin} MODULE ${PLUGIN_SOURCES})
|
||||
set_property(TARGET ${plugin} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "sai.json")
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats")
|
||||
target_link_libraries(${plugin} Qt5::Gui sai)
|
||||
if(BUILD_EXPERIMENTAL_PLUGINS)
|
||||
add_subdirectory(sai)
|
||||
endif()
|
||||
add_subdirectory(svg)
|
||||
|
|
17
imageformats/sai/CMakeLists.txt
Normal file
17
imageformats/sai/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
set (plugin pimg_sai)
|
||||
|
||||
set (PLUGIN_SOURCES
|
||||
sai_p.h
|
||||
sai.cpp
|
||||
)
|
||||
|
||||
# {{{ KCM style
|
||||
set(CMAKE_SHARED_MODULE_PREFIX "")
|
||||
unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
# }}}
|
||||
|
||||
add_library(${plugin} MODULE ${PLUGIN_SOURCES})
|
||||
set_property(TARGET ${plugin} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "sai.json")
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats")
|
||||
target_link_libraries(${plugin} Qt5::Gui sai)
|
26
imageformats/svg/CMakeLists.txt
Normal file
26
imageformats/svg/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
set (plugin pimg_svg)
|
||||
|
||||
set (PLUGIN_SOURCES
|
||||
main.cpp
|
||||
svg_p.h
|
||||
svg.cpp
|
||||
# since dtkgui still cannot compile under platforms other than Linux...
|
||||
dsvgrenderer.h
|
||||
dsvgrenderer.cpp
|
||||
)
|
||||
|
||||
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Svg)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(rsvg REQUIRED librsvg-2.0 IMPORTED_TARGET)
|
||||
|
||||
# {{{ KCM style
|
||||
set(CMAKE_SHARED_MODULE_PREFIX "")
|
||||
unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
# }}}
|
||||
|
||||
add_library(${plugin} MODULE ${PLUGIN_SOURCES})
|
||||
set_property(TARGET ${plugin} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "svg.json")
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/imageformats")
|
||||
target_link_libraries(${plugin} Qt5::Gui Qt5::Svg PkgConfig::rsvg)
|
280
imageformats/svg/dsvgrenderer.cpp
Normal file
280
imageformats/svg/dsvgrenderer.cpp
Normal file
|
@ -0,0 +1,280 @@
|
|||
// SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DTK_DISABLE_LIBRSVG
|
||||
#include <librsvg/rsvg.h>
|
||||
#else
|
||||
#include <QSvgRenderer>
|
||||
#endif
|
||||
|
||||
#include "dsvgrenderer.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QGuiApplication>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
class DSvgRendererPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
explicit DSvgRendererPrivate(DSvgRenderer *qq);
|
||||
|
||||
QImage getImage(const QSize &size, const QString &elementId) const;
|
||||
|
||||
RsvgHandle *handle = nullptr;
|
||||
QSize defaultSize;
|
||||
mutable QRectF viewBox;
|
||||
};
|
||||
|
||||
DSvgRendererPrivate::DSvgRendererPrivate(DSvgRenderer *qq)
|
||||
: QObject(qq) // qq ==> DObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QImage DSvgRendererPrivate::getImage(const QSize &size, const QString &elementId) const
|
||||
{
|
||||
QImage image(size, QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
image.fill(Qt::transparent);
|
||||
|
||||
cairo_surface_t *surface = cairo_image_surface_create_for_data(image.bits(), CAIRO_FORMAT_ARGB32, image.width(), image.height(), image.bytesPerLine());
|
||||
cairo_t *cairo = cairo_create(surface);
|
||||
cairo_scale(cairo, image.width() / viewBox.width(), image.height() / viewBox.height());
|
||||
cairo_translate(cairo, -viewBox.x(), -viewBox.y());
|
||||
|
||||
if (elementId.isEmpty())
|
||||
rsvg_handle_render_cairo(handle, cairo);
|
||||
else
|
||||
rsvg_handle_render_cairo_sub(handle, cairo, elementId.toUtf8().constData());
|
||||
|
||||
cairo_destroy(cairo);
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class Dtk::Gui::DSvgRenderer
|
||||
\inmodule dtkgui
|
||||
\brief 提供了将SVG文件的内容绘制到绘制设备上的方法.
|
||||
|
||||
SVG图形可以在构造 DSvgRenderer 时加载,也可以稍后使用load()函数加载。
|
||||
因为渲染是使用 QPainter 执行的,所以可以在 QPaintDevice 的任何子类上渲染SVG图形。
|
||||
如果加载了有效文件,则无论是在构造时还是以后某个时间,isValid()都将返回true;否则将返回false。
|
||||
DSvgRenderer提供render()插槽,用于使用给定的 QPainter 渲染当前文档或动画文档的当前帧
|
||||
\note 使用 DSvgRenderer 需要 librsvg库
|
||||
*/
|
||||
|
||||
DSvgRenderer::DSvgRenderer(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
DSvgRenderer::DSvgRenderer(const QString &filename, QObject *parent)
|
||||
: DSvgRenderer(parent)
|
||||
{
|
||||
load(filename);
|
||||
}
|
||||
|
||||
DSvgRenderer::DSvgRenderer(const QByteArray &contents, QObject *parent)
|
||||
: DSvgRenderer(parent)
|
||||
{
|
||||
load(contents);
|
||||
}
|
||||
|
||||
DSvgRenderer::~DSvgRenderer()
|
||||
{
|
||||
Q_D(DSvgRenderer);
|
||||
|
||||
if (d->handle) {
|
||||
Q_ASSERT(isValid());
|
||||
g_object_unref(d->handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool DSvgRenderer::isValid() const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
return d->handle;
|
||||
}
|
||||
|
||||
QSize DSvgRenderer::defaultSize() const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
return d->defaultSize;
|
||||
}
|
||||
|
||||
QRect DSvgRenderer::viewBox() const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
return d->handle ? d->viewBox.toRect() : QRect();
|
||||
}
|
||||
|
||||
QRectF DSvgRenderer::viewBoxF() const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
return d->handle ? d->viewBox : QRectF();
|
||||
}
|
||||
|
||||
void DSvgRenderer::setViewBox(const QRect &viewbox)
|
||||
{
|
||||
setViewBox(QRectF(viewbox));
|
||||
}
|
||||
|
||||
void DSvgRenderer::setViewBox(const QRectF &viewbox)
|
||||
{
|
||||
Q_D(DSvgRenderer);
|
||||
if (d->handle)
|
||||
d->viewBox = viewbox;
|
||||
}
|
||||
|
||||
QRectF DSvgRenderer::boundsOnElement(const QString &id) const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
if (!d->handle)
|
||||
return QRectF();
|
||||
|
||||
const QByteArray &id_data = id.toUtf8();
|
||||
|
||||
RsvgDimensionData dimension_data;
|
||||
|
||||
if (!rsvg_handle_get_dimensions_sub(d->handle, &dimension_data, id_data.constData()))
|
||||
return QRectF();
|
||||
|
||||
RsvgPositionData pos_data;
|
||||
|
||||
if (!rsvg_handle_get_position_sub(d->handle, &pos_data, id_data.constData()))
|
||||
return QRectF();
|
||||
|
||||
return QRectF(pos_data.x, pos_data.y, dimension_data.width, dimension_data.height);
|
||||
}
|
||||
|
||||
bool DSvgRenderer::elementExists(const QString &id) const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
if (!d->handle)
|
||||
return false;
|
||||
|
||||
return rsvg_handle_has_sub(d->handle, id.toUtf8().constData());
|
||||
}
|
||||
|
||||
QImage DSvgRenderer::toImage(const QSize sz, const QString &elementId) const
|
||||
{
|
||||
Q_D(const DSvgRenderer);
|
||||
|
||||
return d->getImage(sz, elementId);
|
||||
}
|
||||
|
||||
static QByteArray updateXmlAttribute(const QString &contents)
|
||||
{
|
||||
QByteArray data;
|
||||
QXmlStreamWriter writer(&data);
|
||||
QXmlStreamReader reader(contents);
|
||||
while(reader.readNext() != QXmlStreamReader::Invalid && !reader.atEnd()) {
|
||||
if (reader.tokenType() != QXmlStreamReader::StartElement ||
|
||||
!reader.attributes().hasAttribute("href")) {
|
||||
writer.writeCurrentToken(reader);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &nd : reader.namespaceDeclarations())
|
||||
writer.writeNamespace(nd.namespaceUri().toString(), nd.prefix().toString());
|
||||
|
||||
writer.writeStartElement(reader.namespaceUri().toString(), reader.name().toString());
|
||||
|
||||
for (const auto &attr : reader.attributes()) {
|
||||
if (attr.name() == "href") {
|
||||
writer.writeAttribute("xlink:href", attr.value().toString());
|
||||
continue;
|
||||
}
|
||||
writer.writeAttribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static QByteArray format(const QByteArray &contents)
|
||||
{
|
||||
QXmlStreamReader reader(contents);
|
||||
while (reader.readNextStartElement()) {
|
||||
if (reader.attributes().hasAttribute("href"))
|
||||
return updateXmlAttribute(contents);
|
||||
}
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
bool DSvgRenderer::load(const QString &filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
// TODO: if `href` attribute is adapted after librsvg upgrade revert me
|
||||
return load(format(file.readAll()));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DSvgRenderer::load(const QByteArray &contents)
|
||||
{
|
||||
Q_D(DSvgRenderer);qDebug() << "drsvg load()";
|
||||
|
||||
if (d->handle) {
|
||||
g_object_unref(d->handle);
|
||||
d->handle = nullptr;
|
||||
}
|
||||
|
||||
GError *error = nullptr;
|
||||
d->handle = rsvg_handle_new_from_data((const guint8*)contents.constData(), contents.length(), &error);
|
||||
|
||||
if (error) {
|
||||
qWarning("DSvgRenderer::load: %s", error->message);
|
||||
g_error_free(error);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RsvgDimensionData rsvg_data;
|
||||
|
||||
rsvg_handle_get_dimensions(d->handle, &rsvg_data);
|
||||
|
||||
d->defaultSize.setWidth(rsvg_data.width);
|
||||
d->defaultSize.setHeight(rsvg_data.height);
|
||||
d->viewBox = QRectF(QPointF(0, 0), d->defaultSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DSvgRenderer::render(QPainter *p)
|
||||
{
|
||||
render(p, QString(), QRectF());
|
||||
}
|
||||
|
||||
void DSvgRenderer::render(QPainter *p, const QRectF &bounds)
|
||||
{
|
||||
render(p, QString(), bounds);
|
||||
}
|
||||
|
||||
void DSvgRenderer::render(QPainter *p, const QString &elementId, const QRectF &bounds)
|
||||
{
|
||||
Q_D(DSvgRenderer);
|
||||
if (!d->handle)
|
||||
return;
|
||||
|
||||
p->save();
|
||||
|
||||
const QImage image = d->getImage(QSize(p->device()->width(), p->device()->height()), elementId);
|
||||
|
||||
if (bounds.isEmpty())
|
||||
p->drawImage(0, 0, image);
|
||||
else
|
||||
p->drawImage(bounds, image);
|
||||
|
||||
p->restore();
|
||||
}
|
||||
|
52
imageformats/svg/dsvgrenderer.h
Normal file
52
imageformats/svg/dsvgrenderer.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DSVGRENDERER_H
|
||||
#define DSVGRENDERER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QRectF>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPainter;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DSvgRendererPrivate;
|
||||
class DSvgRenderer : public QObject
|
||||
{
|
||||
Q_PROPERTY(QRectF viewBox READ viewBoxF WRITE setViewBox)
|
||||
public:
|
||||
explicit DSvgRenderer(QObject *parent = Q_NULLPTR);
|
||||
DSvgRenderer(const QString &filename, QObject *parent = Q_NULLPTR);
|
||||
DSvgRenderer(const QByteArray &contents, QObject *parent = Q_NULLPTR);
|
||||
~DSvgRenderer();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
QSize defaultSize() const;
|
||||
|
||||
QRect viewBox() const;
|
||||
QRectF viewBoxF() const;
|
||||
void setViewBox(const QRect &viewbox);
|
||||
void setViewBox(const QRectF &viewbox);
|
||||
|
||||
QRectF boundsOnElement(const QString &id) const;
|
||||
bool elementExists(const QString &id) const;
|
||||
|
||||
QImage toImage(const QSize sz, const QString &elementId = QString()) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
bool load(const QString &filename);
|
||||
bool load(const QByteArray &contents);
|
||||
void render(QPainter *p);
|
||||
void render(QPainter *p, const QRectF &bounds);
|
||||
|
||||
void render(QPainter *p, const QString &elementId,
|
||||
const QRectF &bounds = QRectF());
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(DSvgRenderer)
|
||||
};
|
||||
|
||||
#endif // DSVGRENDERER_H
|
53
imageformats/svg/main.cpp
Normal file
53
imageformats/svg/main.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
#include <qimageiohandler.h>
|
||||
#include <qstringlist.h>
|
||||
|
||||
#include "svg_p.h"
|
||||
|
||||
#include <qiodevice.h>
|
||||
#include <qbytearray.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSvgPlugin : public QImageIOPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "svg.json")
|
||||
|
||||
public:
|
||||
QStringList keys() const;
|
||||
Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
|
||||
QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
|
||||
};
|
||||
|
||||
QStringList QSvgPlugin::keys() const
|
||||
{
|
||||
return QStringList() << QLatin1String("svg") << QLatin1String("svgz");
|
||||
}
|
||||
|
||||
QImageIOPlugin::Capabilities QSvgPlugin::capabilities(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
if (format == "svg" || format == "svgz")
|
||||
return Capabilities(CanRead);
|
||||
if (!format.isEmpty())
|
||||
return 0;
|
||||
|
||||
Capabilities cap;
|
||||
if (device->isReadable() && QSvgIOHandler::canRead(device))
|
||||
cap |= CanRead;
|
||||
return cap;
|
||||
}
|
||||
|
||||
QImageIOHandler *QSvgPlugin::create(QIODevice *device, const QByteArray &format) const
|
||||
{
|
||||
QSvgIOHandler *hand = new QSvgIOHandler();
|
||||
hand->setDevice(device);
|
||||
hand->setFormat(format);
|
||||
return hand;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "main.moc"
|
234
imageformats/svg/svg.cpp
Normal file
234
imageformats/svg/svg.cpp
Normal file
|
@ -0,0 +1,234 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
#include "svg_p.h"
|
||||
|
||||
#ifndef QT_NO_SVGRENDERER
|
||||
|
||||
#include "qimage.h"
|
||||
#include "qpixmap.h"
|
||||
#include "qpainter.h"
|
||||
#include "qvariant.h"
|
||||
#include "qbuffer.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
#include "dsvgrenderer.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QSvgIOHandlerPrivate
|
||||
{
|
||||
public:
|
||||
QSvgIOHandlerPrivate(QSvgIOHandler *qq)
|
||||
: q(qq), loaded(false), readDone(false), backColor(Qt::transparent)
|
||||
{}
|
||||
|
||||
bool load(QIODevice *device);
|
||||
|
||||
QSvgIOHandler *q;
|
||||
DSvgRenderer r;
|
||||
QSize defaultSize;
|
||||
QRect clipRect;
|
||||
QSize scaledSize;
|
||||
QRect scaledClipRect;
|
||||
bool loaded;
|
||||
bool readDone;
|
||||
QColor backColor;
|
||||
};
|
||||
|
||||
bool QSvgIOHandlerPrivate::load(QIODevice *device)
|
||||
{qDebug() << "load() started";
|
||||
if (!device)
|
||||
return false;
|
||||
qDebug() << "device not null";
|
||||
if (loaded)
|
||||
return true;
|
||||
if (q->format().isEmpty())
|
||||
q->canRead();
|
||||
qDebug() << "can read to set format";
|
||||
// # The SVG renderer doesn't handle trailing, unrelated data, so we must
|
||||
// assume that all available data in the device is to be read.
|
||||
bool res = false;
|
||||
QBuffer *buf = qobject_cast<QBuffer *>(device);
|
||||
if (buf) {
|
||||
const QByteArray &ba = buf->data();
|
||||
res = r.load(QByteArray::fromRawData(ba.constData() + buf->pos(), ba.size() - buf->pos()));
|
||||
buf->seek(ba.size());
|
||||
} else if (q->format() == "svgz") {
|
||||
res = r.load(device->readAll());
|
||||
} else {
|
||||
res = r.load(device->readAll());
|
||||
}
|
||||
|
||||
if (res) {
|
||||
defaultSize = QSize(r.viewBox().width(), r.viewBox().height());
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
|
||||
QSvgIOHandler::QSvgIOHandler()
|
||||
: d(new QSvgIOHandlerPrivate(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
QSvgIOHandler::~QSvgIOHandler()
|
||||
{
|
||||
// delete d;
|
||||
}
|
||||
|
||||
|
||||
bool QSvgIOHandler::canRead() const
|
||||
{
|
||||
if (!device())
|
||||
return false;
|
||||
if (d->loaded && !d->readDone)
|
||||
return true; // Will happen if we have been asked for the size
|
||||
|
||||
QByteArray buf = device()->peek(8);
|
||||
if (buf.startsWith("\x1f\x8b")) {
|
||||
setFormat("svgz");
|
||||
return true;
|
||||
} else if (buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--")) {
|
||||
setFormat("svg");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QByteArray QSvgIOHandler::name() const
|
||||
{
|
||||
return "svg";
|
||||
}
|
||||
|
||||
|
||||
bool QSvgIOHandler::read(QImage *image)
|
||||
{qDebug() << "started";
|
||||
if (d->readDone || d->load(device())) {qDebug() << "loaded";
|
||||
bool xform = (d->clipRect.isValid() || d->scaledSize.isValid() || d->scaledClipRect.isValid());
|
||||
QSize finalSize = d->defaultSize;
|
||||
QRectF bounds;
|
||||
if (xform && !d->defaultSize.isEmpty()) {qDebug() << "defaultSize not empty";
|
||||
bounds = QRectF(QPointF(0,0), QSizeF(d->defaultSize));
|
||||
QPoint tr1, tr2;
|
||||
QSizeF sc(1, 1);
|
||||
if (d->clipRect.isValid()) {
|
||||
tr1 = -d->clipRect.topLeft();
|
||||
finalSize = d->clipRect.size();
|
||||
}
|
||||
if (d->scaledSize.isValid()) {
|
||||
sc = QSizeF(qreal(d->scaledSize.width()) / finalSize.width(),
|
||||
qreal(d->scaledSize.height()) / finalSize.height());
|
||||
finalSize = d->scaledSize;
|
||||
}
|
||||
if (d->scaledClipRect.isValid()) {
|
||||
tr2 = -d->scaledClipRect.topLeft();
|
||||
finalSize = d->scaledClipRect.size();
|
||||
}
|
||||
QTransform t;
|
||||
t.translate(tr2.x(), tr2.y());
|
||||
t.scale(sc.width(), sc.height());
|
||||
t.translate(tr1.x(), tr1.y());
|
||||
bounds = t.mapRect(bounds);
|
||||
}
|
||||
if (!finalSize.isEmpty()) {qDebug() << "finalSize not empty";
|
||||
if (bounds.isEmpty() && d->backColor.alpha() == 0) {
|
||||
*image = d->r.toImage(finalSize);
|
||||
} else {
|
||||
*image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied);
|
||||
image->fill(d->backColor.rgba());
|
||||
QPainter p(image);
|
||||
p.setRenderHints(QPainter::SmoothPixmapTransform);
|
||||
d->r.render(&p, bounds);
|
||||
p.end();
|
||||
}
|
||||
}qDebug() << "readDone";
|
||||
d->readDone = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
QVariant QSvgIOHandler::option(ImageOption option) const
|
||||
{
|
||||
switch(option) {
|
||||
case ImageFormat:
|
||||
return QImage::Format_ARGB32_Premultiplied;
|
||||
break;
|
||||
case Size:
|
||||
d->load(device());
|
||||
return d->defaultSize;
|
||||
break;
|
||||
case ClipRect:
|
||||
return d->clipRect;
|
||||
break;
|
||||
case ScaledSize:
|
||||
return d->scaledSize;
|
||||
break;
|
||||
case ScaledClipRect:
|
||||
return d->scaledClipRect;
|
||||
break;
|
||||
case BackgroundColor:
|
||||
return d->backColor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
void QSvgIOHandler::setOption(ImageOption option, const QVariant & value)
|
||||
{
|
||||
switch(option) {
|
||||
case ClipRect:
|
||||
d->clipRect = value.toRect();
|
||||
break;
|
||||
case ScaledSize:
|
||||
d->scaledSize = value.toSize();
|
||||
break;
|
||||
case ScaledClipRect:
|
||||
d->scaledClipRect = value.toRect();
|
||||
break;
|
||||
case BackgroundColor:
|
||||
d->backColor = value.value<QColor>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool QSvgIOHandler::supportsOption(ImageOption option) const
|
||||
{
|
||||
switch(option)
|
||||
{
|
||||
case ImageFormat:
|
||||
case Size:
|
||||
case ClipRect:
|
||||
case ScaledSize:
|
||||
case ScaledClipRect:
|
||||
case BackgroundColor:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool QSvgIOHandler::canRead(QIODevice *device)
|
||||
{
|
||||
QByteArray buf = device->peek(8);
|
||||
return buf.startsWith("\x1f\x8b") || buf.contains("<?xml") || buf.contains("<svg") || buf.contains("<!--");
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_SVGRENDERER
|
4
imageformats/svg/svg.json
Normal file
4
imageformats/svg/svg.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"Keys": [ "svg", "svgz" ],
|
||||
"MimeTypes": [ "image/svg+xml" ]
|
||||
}
|
35
imageformats/svg/svg_p.h
Normal file
35
imageformats/svg/svg_p.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
#ifndef QSVGIOHANDLER_H
|
||||
#define QSVGIOHANDLER_H
|
||||
|
||||
#include <QImageIOHandler>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QImage;
|
||||
class QByteArray;
|
||||
class QIODevice;
|
||||
class QVariant;
|
||||
|
||||
class QSvgIOHandlerPrivate;
|
||||
class QSvgIOHandler : public QImageIOHandler
|
||||
{
|
||||
public:
|
||||
QSvgIOHandler();
|
||||
~QSvgIOHandler();
|
||||
virtual bool canRead() const;
|
||||
virtual QByteArray name() const;
|
||||
virtual bool read(QImage *image);
|
||||
static bool canRead(QIODevice *device);
|
||||
virtual QVariant option(ImageOption option) const;
|
||||
virtual void setOption(ImageOption option, const QVariant & value);
|
||||
virtual bool supportsOption(ImageOption option) const;
|
||||
|
||||
private:
|
||||
QSvgIOHandlerPrivate *d;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSVGIOHANDLER_H
|
Loading…
Reference in New Issue
Block a user