【问题标题】:QSvgGenerator converts QSvgGraphicsItem to image when generating SvgQSvgGenerator 在生成 Svg 时将 QSvgGraphicsItem 转换为图像
【发布时间】:2019-09-23 12:41:14
【问题描述】:

我有一堆 SVG 文件,我已经将它们(作为 QGraphicsSvgItem)加载到 QGraphicsScene 中进行设计,一切正常,现在我想将场景保存到另一个输出 SVG 文件(包括所有 Svg 项目)中QSvgGenerator 使用下面的代码,但是当它导出 SVG 项目时,它会在输出文件中变成图像,并且它们的向量不再是可伸缩的。

如果这个 Qt 框架没有直接的解决方案,我期待 XML 操作方法。

QSvgGenerator generator;
generator.setFileName(savePath);
generator.setSize(QSize(static_cast<int>(currentScene->width()), static_cast<int>(currentScene->height())));
generator.setViewBox(currentScene->sceneRect());
generator.setTitle(tr("SVG Generated using SVG Generator"));
generator.setDescription(tr("an SVG drawing used by Software Package"));
QPainter painter;
painter.begin(&generator);
currentScene->clearSelection();
currentScene->render(&painter);
painter.end();

我期待一个输出 svg 文件,其中包含所包含的内部 SVG 项目的标签和节点(不将它们转换为图像数据)

现在它正在将内部 svg 项目转换为这些图像标签:

<image x="131" y="127" width="102" height="102" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...

更新 1 这个小应用程序将在图形场景中显示一个 svg 文件 (QGraphicsSvgItem),并将使用 QSvgGenerator 将场景导出到另一个输出 svg 文件中:

#include <QApplication>
#include <QtSvg>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // Creating and showing an svg icon in the graphical scene view
    QGraphicsSvgItem *item = new QGraphicsSvgItem(":The Pirate Bay Logo.svg");
    QGraphicsScene *scene = new QGraphicsScene;
    scene->setSceneRect(0, 0, 1000, 1000);
    QGraphicsView *view = new QGraphicsView(scene);

    scene->addItem(item);
    item->setPos(view->rect().center());

    view->show();

    // Saving the graphical scene to another svg output device file using QSvgGenerator
    QSvgGenerator generator;
    generator.setFileName("output.svg");
    generator.setSize(QSize(static_cast<int>(scene->width()), static_cast<int>(scene->height())));
    generator.setViewBox(scene->sceneRect());
    generator.setTitle("SVG Generated using SVG Generator");
    generator.setDescription("an SVG drawing used by Software Package");
    QPainter painter;
    painter.begin(&generator);
    scene->clearSelection();
    scene->render(&painter);
    painter.end();

    return a.exec();
}

但我得到的是一个 svg 文件,其中包含初始 svg 文件的非常低质量图像的转换损坏位。 我期望的是 QSvgGenerator 从源文件中获取初始 svg 元素(可能保存在场景中的 QGraphicsSvgItem 中)并将它们放入最后生成的文件中。

【问题讨论】:

  • 我删除了我的答案,因为我认为它是错误的。 QSvgGenerator 实际上应该或可以从 QPainter 编写矢量 SVG 文件(正如 Qt 示例所证明的那样)。因此,与图形视图、场景或所涉及的单个项目相关的事情肯定是发生了其他事情。如果您能提供一个更完整(但最小的:) 示例,我将有兴趣测试。
  • 谢谢,我已经编辑了我的问题并制作了一个小应用程序来重现这种情况。
  • 嗯,渲染的内容似乎很重要。使用您的示例,它甚至可以对我能找到的最简单的单色单路径 SVG 图标进行光栅化。如果我将 SVG 加载到 QIcon 并使用它来绘制,则相同。 OTOH,如果我使用QSvgWidget 加载图像,然后使用它渲染到QSvgRenderer,那么它会以矢量图形的形式出现!甚至是带有所有渐变的 PB 标志。此外,如果我将 SVG 加载到 QSvgRenderer 并使用它来渲染到生成器,它会输出矢量。所以这很奇怪,似乎与文档所声称的所有绘画都相同。
  • 好的,有道理...与小部件/图标/等如何绘制自身有关。 QIcon 使用位图绘画,这就是 SVG 生成器的输出。 QGraphicsItem 显然也是如此(因为它将自身缓存为像素图)。所以QSvgGenerator 在这里结束:code.woboq.org/qt5/qtsvg/src/svg/…QWidgets 和QSvgRenderer 直接将几何图形绘制到绘制设备(使用drawRectdrawText 等等)。
  • 刚刚想到了一些东西......而且它似乎有效!将QGraphicsItem::cacheMode 设置为QGraphicsItem::NoCache。因此,在您的示例中,我刚刚在创建QGraphicsSvgItem 的位置下方添加了item-&gt;setCacheMode(QGraphicsItem::NoCache);,现在它以矢量格式保存。基本上,这样做是强制每次都完成绘画,而不是缓存在位图中。请确认,我们可以将其添加为答案。

标签: c++ qt svg qtsvg


【解决方案1】:

事实证明,快速的答案是在将每个 QGraphicsItem 渲染为 SVG* 之前禁用缓存模式。

QGraphicsSvgItem *item = new QGraphicsSvgItem(":The Pirate Bay Logo.svg");
item->setCacheMode(QGraphicsItem::NoCache);

原因是当启用缓存模式时,图形项会将其绘画缓存在位图图像中(当然是光栅格式)。因此,当被要求在QSvgGenerator 设备上呈现自身时,它只会绘制缓存的位图。生成器正确编码为位图图像,而不是矢量。

这扩展到任何使用位图/QPixmap 来绘制或缓存自身的绘画。例如QSvgIconEngine(从 SVG 文件生成QIcons)将使用位图进行绘画(即使原始源是矢量)。因此,将 QIcon 渲染到 QSvgGenerator 会生成光栅图像。

* 我会考虑启用缓存,仅在渲染回 SVG 之前禁用它,然后再重新启用。您必须循环遍历所有场景项目,但在其余时间使用缓存获得的性能提升可能远远超过这一点。

【讨论】:

  • 我在使用普通 QGraphicsItems 时遇到了同样的问题。输出是位图的。我试图禁用缓存,但没有帮助。有什么想法吗?
  • @juzzlin 不确定您所说的“普通 QGraphicsItem”是什么意思,因为那是一个抽象类——具体来说,在子类的重写 paint() 方法中发生的事情是重要的部分。例如QGraphicsPixmapItem 只能输出位图,而QGraphicsRectItem 将始终以矢量格式输出。
  • 我的意思是我的问题与QGraphicsSvgItem 无关。我现在发现是我的阴影效果出于某种原因将所有内容都强制位图。禁用效果会产生正确的 SVG。此外,根据文档,默认情况下缓存模式为NoCache,因此显然它没有任何效果。
  • 确实,QGraphicsSvgItem 专门将默认缓存模式设置为DeviceCoordinateCache,而其他内置QGraphicsItem 子类上的NoCache
猜你喜欢
  • 2017-04-22
  • 1970-01-01
  • 2012-12-04
  • 1970-01-01
  • 2022-11-10
  • 2020-02-10
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多