从内存中

时间:2017-03-30 18:08:58

标签: c++ qt plugins

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

P.S。最初想要创建QSvgIconEngine,但它隐藏在插件层上,我无法显式创建它。如何从插件加载(考虑到该插件已加载)?

3 个答案:

答案 0 :(得分:4)

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

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

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

  • 我们(Qt开发人员)显然无法轻易访问每种图像类型的
  • QIconEngine个类;显然有一个插件系统可供使用,它在编译时不可用(至少不是这样)

另一方面; 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

这是实施,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;
}

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

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

std::string iconSvgData = GetTheSvgPlainData();
QIcon theIcon(new SVGIconEngine(iconSvgData));
//Use the icon!

请注意,QIcon取得了引擎对象的所有权。当它被摧毁时它会毁掉它。

玩得开心!

答案 1 :(得分:0)

  

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

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

QSvgRenderer(const QByteArray &contents, QObject *parent = Q_NULLPTR);
QSvgRenderer(QXmlStreamReader *contents, QObject *parent = Q_NULLPTR);

或者我们只需加载内容:

bool QSvgRenderer::load(const QByteArray &contents)
bool QSvgRenderer::load(QXmlStreamReader *contents)

并创建实际图标:

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);
}

我们也可以使用其他合成模式,比方说, QPainter::RasterOp_NotSourceOrDestination反转图标颜色。

答案 2 :(得分:0)

我手头没有C ++,但转换起来应该很容易:

QtGui.QIcon(
  QtGui.QPixmap.fromImage(
    QtGui.QImage.fromData(
       b'<svg version="1.1" viewBox="0 0 32 32"'
       b' xmlns="http://www.w3.org/2000/svg">'
       b'<circle cx="16" cy="16" r="4.54237"/></svg>')))

此代码将创建带有黑圈的透明32 x 32像素图标。