Skip to content

Commit 952e6fb

Browse files
authored
Merge pull request #3931 from nirvn/processing_modeler_picture
[FEATURE] Export processing models as PDF/SVG
2 parents a05096d + f54476c commit 952e6fb

12 files changed

Lines changed: 185 additions & 117 deletions

File tree

-323 Bytes
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Loading
-510 Bytes
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 1 deletion
Loading
Lines changed: 1 addition & 1 deletion
Loading
Lines changed: 1 addition & 62 deletions
Loading
Lines changed: 1 addition & 1 deletion
Loading

‎python/plugins/processing/modeler/ModelerDialog.py‎

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
import os
3232

3333
from qgis.PyQt import uic
34-
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QSettings, QByteArray, QSize, pyqtSignal
34+
from qgis.PyQt.QtCore import Qt, QRectF, QMimeData, QPoint, QPointF, QSettings, QByteArray, QSize, QSizeF, pyqtSignal
3535
from qgis.PyQt.QtWidgets import QGraphicsView, QTreeWidget, QMessageBox, QFileDialog, QTreeWidgetItem, QSizePolicy, QMainWindow
3636
from qgis.PyQt.QtGui import QIcon, QImage, QPainter
37+
from qgis.PyQt.QtSvg import QSvgGenerator
38+
from qgis.PyQt.QtPrintSupport import QPrinter
3739
from qgis.core import QgsApplication
3840
from qgis.gui import QgsMessageBar
3941
from processing.core.ProcessingConfig import ProcessingConfig
@@ -213,6 +215,8 @@ def _mimeDataAlgorithm(items):
213215
self.mActionSave.triggered.connect(self.save)
214216
self.mActionSaveAs.triggered.connect(self.saveAs)
215217
self.mActionExportImage.triggered.connect(self.exportAsImage)
218+
self.mActionExportPdf.triggered.connect(self.exportAsPdf)
219+
self.mActionExportSvg.triggered.connect(self.exportAsSvg)
216220
self.mActionExportPython.triggered.connect(self.exportAsPython)
217221
self.mActionEditHelp.triggered.connect(self.editHelp)
218222
self.mActionRun.triggered.connect(self.runModel)
@@ -287,6 +291,7 @@ def saveAs(self):
287291
self.saveModel(True)
288292

289293
def exportAsImage(self):
294+
self.repaintModel(controls=False)
290295
filename, fileFilter = QFileDialog.getSaveFileName(self,
291296
self.tr('Save Model As Image'), '',
292297
self.tr('PNG files (*.png *.PNG)'))
@@ -296,23 +301,79 @@ def exportAsImage(self):
296301
if not filename.lower().endswith('.png'):
297302
filename += '.png'
298303

299-
totalRect = QRectF(0, 0, 1, 1)
300-
for item in list(self.scene.items()):
301-
totalRect = totalRect.united(item.sceneBoundingRect())
304+
totalRect = self.scene.itemsBoundingRect()
302305
totalRect.adjust(-10, -10, 10, 10)
306+
imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())
303307

304308
img = QImage(totalRect.width(), totalRect.height(),
305309
QImage.Format_ARGB32_Premultiplied)
306310
img.fill(Qt.white)
307311
painter = QPainter()
308312
painter.setRenderHint(QPainter.Antialiasing)
309313
painter.begin(img)
310-
self.scene.render(painter, totalRect, totalRect)
314+
self.scene.render(painter, imgRect, totalRect)
311315
painter.end()
312316

313317
img.save(filename)
314318

315319
self.bar.pushMessage("", "Model was correctly exported as image", level=QgsMessageBar.SUCCESS, duration=5)
320+
self.repaintModel(controls=True)
321+
322+
def exportAsPdf(self):
323+
self.repaintModel(controls=False)
324+
filename, fileFilter = QFileDialog.getSaveFileName(self,
325+
self.tr('Save Model As PDF'), '',
326+
self.tr('SVG files (*.pdf *.PDF)'))
327+
if not filename:
328+
return
329+
330+
if not filename.lower().endswith('.pdf'):
331+
filename += '.pdf'
332+
333+
totalRect = self.scene.itemsBoundingRect()
334+
totalRect.adjust(-10, -10, 10, 10)
335+
printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())
336+
337+
printer = QPrinter()
338+
printer.setOutputFormat(QPrinter.PdfFormat)
339+
printer.setOutputFileName(filename)
340+
printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel)
341+
printer.setFullPage(True)
342+
343+
painter = QPainter(printer)
344+
self.scene.render(painter, printerRect, totalRect)
345+
painter.end()
346+
347+
self.bar.pushMessage("", "Model was correctly exported as PDF", level=QgsMessageBar.SUCCESS, duration=5)
348+
self.repaintModel(controls=True)
349+
350+
def exportAsSvg(self):
351+
self.repaintModel(controls=False)
352+
filename, fileFilter = QFileDialog.getSaveFileName(self,
353+
self.tr('Save Model As SVG'), '',
354+
self.tr('SVG files (*.svg *.SVG)'))
355+
if not filename:
356+
return
357+
358+
if not filename.lower().endswith('.svg'):
359+
filename += '.svg'
360+
361+
totalRect = self.scene.itemsBoundingRect()
362+
totalRect.adjust(-10, -10, 10, 10)
363+
svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())
364+
365+
svg = QSvgGenerator()
366+
svg.setFileName(filename)
367+
svg.setSize(QSize(totalRect.width(), totalRect.height()))
368+
svg.setViewBox(svgRect)
369+
svg.setTitle(self.alg.name)
370+
371+
painter = QPainter(svg)
372+
self.scene.render(painter, svgRect, totalRect)
373+
painter.end()
374+
375+
self.bar.pushMessage("", "Model was correctly exported as SVG", level=QgsMessageBar.SUCCESS, duration=5)
376+
self.repaintModel(controls=True)
316377

317378
def exportAsPython(self):
318379
filename, filter = QFileDialog.getSaveFileName(self,
@@ -399,11 +460,11 @@ def openModel(self):
399460
self.tr('The selected model could not be loaded.\n'
400461
'See the log for more information.'))
401462

402-
def repaintModel(self):
463+
def repaintModel(self, controls=True):
403464
self.scene = ModelerScene()
404465
self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
405466
ModelerAlgorithm.CANVAS_SIZE))
406-
self.scene.paintModel(self.alg)
467+
self.scene.paintModel(self.alg, controls)
407468
self.view.setScene(self.scene)
408469

409470
def addInput(self):

0 commit comments

Comments
 (0)