Почему этот файл SVG пуст, когда генерируется QSvgGenerator из QGLWidget?
Я отображаю график данных с QwtPlot3D, используя Qt5. Графики отображаются в несколько раз подклассифицированном QGLWidget. Рассматриваемые графики выглядят примерно так:
Я использую следующий код для записи файлов, как указано в других источниках, путем рендеринга QGLWidget в QPainter, который принимает QSvgGenerator при вызове QPainter::begin
, Аналогичный процесс работает для записи растровых изображений, но файлы SVG кажутся пустыми (но они пишут).
Обратите внимание, что переменная currentPlot относится к классу Plot, который наследует SurfacePlot, который наследует Plot3D, который наследует QGLWidget.
void PlotWindow::writeCurrentPlotToSVG(const QString& directory,
const QString& filename)
{
QSvgGenerator generator;
QString ext = ".svg";
QString filepath = buildPath(directory, filename, ext);
generator.setFileName(filepath);
generator.setSize(currentPlot->size());
generator.setViewBox(currentPlot->rect());
generator.setTitle(currentPlot->title());
generator.setDescription("description");
QPainter painter;
painter.begin(&generator);
currentPlot->render(&painter);
painter.end();
}
Сгенерированный файл выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="225.778mm" height="169.333mm"
viewBox="0 0 640 480"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny">
<title>Plot_0</title>
<desc>description</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >
</g>
</svg>
Просмотр файла в Internet Explorer и Mozilla Firefox ничего не отображает. Я проверил правильность отображаемого прямоугольника и значений размера, передаваемых в генератор. На данный момент, я не уверен, что еще делать.
Заранее спасибо за помощь.
1 ответ
SVG выводит векторную графику, OpenGL выводит растровые данные в кадровый буфер, поэтому напрямую получить масштабируемую векторную графику из QGLWidget не представляется возможным. Я ожидал бы, что QSvgGenerator также получит контент OpenGL (по крайней мере, как растровое изображение), но, похоже, он этого не делает...
У меня была похожая проблема с отображением закадрового QGLWidget. Мой обходной путь - сначала render() для всего виджета (у вас не будет содержимого OpenGL), затем используйте отдельный FBO для визуализации QGLWidget, а затем нарисуйте изображение, полученное из этого FBO, поверх первого рендера.
Что-то в этом роде:
//find your QGL-sub-widget
qglWidget = ...
//render parent widget into the svg
QPainter painter(&svgGenerator);
widget->render(&painter);
//create/resize FBO. make the OpenGL context current, so the FBO is created in the correct context
qglChild->makeCurrent();
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setSamples(4);
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
fbo = new QOpenGLFramebufferObject(newWindowRect.size(), fboFormat);
//get the position and size of the QGLWidget within the widget
QRect newWindowRect = GetChildRectInParent(widget, qglChild);
//the position is reliably off by one pixel in x and y, so adjust it
newWindowRect.adjust(-1, -1, -1, -1);
//make the OpenGL context current, so the FBO is created in the correct context
qglChild->makeCurrent();
//bind FBO for rendering to it
fbo->bind();
//Painting to an FBO using OpenGL content in Qt is only possible with a QOpenGLPaintDevice
QOpenGLPaintDevice fboPaintDev(newWindowRect.size());
QPainter fboPainter(&fboPaintDev);
fboPainter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing);
//now render the QGraphicsView
qglChild->render(&fboPainter);
fboPainter.end();
fbo->release();
//grab image from FBO and paint it at the correct position in the pixmap we grabbed from the parent widget
QPixmap openGLPixmap = QPixmap::fromImage(fbo->toImage());
painter.drawPixmap(newWindowRect, openGLPixmap);
painter.end();
delete fbo;