从内存中的SVG内容创建QIcon

ult*_*lox 2 c++ plugins qt

我们如何创建QIcon在内存缓冲区中具有SVG图标内容的对象?

PS最初想创建QSvgIconEngine,但是它隐藏在插件层中,因此我无法显式创建它。我该如何从插件加载(考虑到该插件已加载)来完成呢?

The*_*ist 6

在这里和那里挖掘了一段时间之后,并研究了QIcon本身如何使用svg文件加载图标,这是我所学到的:

  • QIcon,当使用svg文件(或与此相关的任何其他图像类型)调用时,它addFile()随后调用,该调用仅使用文件扩展名(QFileInfo::suffix在Qt中调用)来确定将图像文件转换为图标的方法。

  • 该方法(从语义上讲)由QIconEngine实例确定

  • QIconEngine显然,我们(Qt开发人员)无法简单地访问每种图像类型的类;显然有一个插件系统要使用,并且在编译时不可用(至少不是简单的)

另一方面; QIcon如何工作?当从QIcon请求图标时,它使用传递给它的信息来确定要使用的引擎,并创建引擎的实例。然后,每当图标需要绘制某些内容时,它都会要求引擎绘制具有指定大小的图标。在函数上使用该大小,该函数QIconEngine::pixmap()创建具有所需大小的像素图,然后使用该方法QIconEngine::paint()在该像素图上绘画。

因此,给定这些信息,解决方案就是编写一个图标引擎,QIcon将使用该图标引擎来根据传递给它的大小生成图标。这样做的方法如下:

这是头文件SvgIconEngine.h

#ifndef SVGICONENGINE_H
#define SVGICONENGINE_H

#include <QIconEngine>
#include <QSvgRenderer>

class SVGIconEngine : public QIconEngine {

  QByteArray data;

public:
  explicit SVGIconEngine(const std::string &iconBuffer);
  void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode,
             QIcon::State state) override;
  QIconEngine *clone() const override;
  QPixmap pixmap(const QSize &size, QIcon::Mode mode,
                 QIcon::State state) override;
signals:

public slots:
};

#endif // SVGICONENGINE_H
Run Code Online (Sandbox Code Playgroud)

这是实现SvgIconEngine.cpp

#include "SvgIconEngine.h"
#include <QPainter>

SVGIconEngine::SVGIconEngine(const std::string &iconBuffer) {
  data = QByteArray::fromStdString(iconBuffer);
}

void SVGIconEngine::paint(QPainter *painter, const QRect &rect,
                          QIcon::Mode mode, QIcon::State state) {
  QSvgRenderer renderer(data);
  renderer.render(painter, rect);
}

QIconEngine *SVGIconEngine::clone() const { return new SVGIconEngine(*this); }

QPixmap SVGIconEngine::pixmap(const QSize &size, QIcon::Mode mode,
                              QIcon::State state) {
  // This function is necessary to create an EMPTY pixmap. It's called always
  // before paint()

  QImage img(size, QImage::Format_ARGB32);
  img.fill(qRgba(0, 0, 0, 0));
  QPixmap pix = QPixmap::fromImage(img, Qt::NoFormatConversion);
  {
    QPainter painter(&pix);
    QRect r(QPoint(0.0, 0.0), size);
    this->paint(&painter, r, mode, state);
  }
  return pix;
}
Run Code Online (Sandbox Code Playgroud)

注意:您必须重写clone(),因为它是一个抽象方法,并且必须重写pixmap(),因为没有它,您将没有一个空的像素图来绘制svg。

要使用此功能,只需执行以下操作:

std::string iconSvgData = GetTheSvgPlainData();
QIcon theIcon(new SVGIconEngine(iconSvgData));
//Use the icon!
Run Code Online (Sandbox Code Playgroud)

请注意,QIcon拥有引擎对象的所有权。它会在销毁时销毁。

玩得开心!


Ale*_*r V 0

我们如何创建在内存缓冲区中QIcon具有图标内容的对象?SVG

为此,所有必需的功能都是通过QSvgRenderer类的外部接口提供的。要构建该类型的渲染器,我们需要使用以下任一:

QSvgRenderer(const QByteArray &contents, QObject *parent = Q_NULLPTR);
QSvgRenderer(QXmlStreamReader *contents, QObject *parent = Q_NULLPTR);
Run Code Online (Sandbox Code Playgroud)

或者我们可以使用以下命令加载内容:

bool QSvgRenderer::load(const QByteArray &contents)
bool QSvgRenderer::load(QXmlStreamReader *contents)
Run Code Online (Sandbox Code Playgroud)

并创建实际的图标:

QIcon svg2Icon(const QByteArray& svgContent, QPainter::CompositionMode mode = 
   QPainter::CompositionMode_SourceOver)
{
    return QIcon(util::svg2Pixmap(svgContent, QSize(128, 128), mode));
}

QPixmap svg2Pixmap(const QByteArray& svgContent,
   const QSize& size,
   QPainter::CompositionMode mode)
{
    QSvgRenderer rr(svgContent);
    QImage image(size.width(), size.height(), QImage::Format_ARGB32);
    QPainter painter(&image);
    painter.setCompositionMode(mode);
    image.fill(Qt::transparent);
    rr.render(&painter);
    return QPixmap::fromImage(image);
}
Run Code Online (Sandbox Code Playgroud)

我们还可以使用其他合成模式,例如 QPainter::RasterOp_NotSourceOrDestination反转图标颜色。