def testIteratorToPdfs(self): project, layout = self.prepareIteratorLayout() atlas = layout.atlas() atlas.setFilenameExpression("'test_exportiteratortopdf_' || \"NAME_1\"") # setup settings settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 80 settings.rasterizeWholeImage = False settings.forceVectorOutput = False result, error = QgsLayoutExporter.exportToPdfs(atlas, self.basetestpath + '/', settings) self.assertEqual(result, QgsLayoutExporter.Success, error) page1_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Basse-Normandie.pdf') rendered_page_1 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Basse-Normandie.png') pdfToPng(page1_path, rendered_page_1, dpi=80, page=1) self.assertTrue(self.checkImage('iteratortopdf1', 'iteratortoimage1', rendered_page_1, size_tolerance=2)) page2_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Bretagne.pdf') rendered_page_2 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Bretagne.png') pdfToPng(page2_path, rendered_page_2, dpi=80, page=1) self.assertTrue(self.checkImage('iteratortopdf2', 'iteratortoimage2', rendered_page_2, size_tolerance=2)) page3_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Centre.pdf') self.assertTrue(os.path.exists(page3_path)) page4_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_Pays de la Loire.pdf') self.assertTrue(os.path.exists(page4_path))
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ # get the parameter values base_project = self.parameterAsFile(parameters, self.BASE_PROJECT, context) layout_name = self.parameterAsString(parameters, self.LAYOUT_NAME, context) output = self.parameterAsFile(parameters, self.OUTPUT, context) # instantiation of the project project_instance = QgsProject() project_instance.read(base_project) # actual export of the PDF if layout_name: layout = project_instance.layoutManager().layoutByName(layout_name) else: layout = project_instance.layoutManager().layouts()[0] assert(layout is not None, "No layout found") export = QgsLayoutExporter(layout) export.exportToPdf(output, QgsLayoutExporter.PdfExportSettings()) # debug # project_instance.write(output_file+"debug.qgs") # done !! return {}
def __export(self): settings = QSettings() format = self.dialogui.comboBox_fileformat.itemData(self.dialogui.comboBox_fileformat.currentIndex()) filepath = QFileDialog.getSaveFileName( self.iface.mainWindow(), self.tr("Export Layout"), settings.value("/instantprint/lastfile", ""), format ) if not all(filepath): return # Ensure output filename has correct extension filename = os.path.splitext(filepath[0])[0] + "." + self.dialogui.comboBox_fileformat.currentText().lower() settings.setValue("/instantprint/lastfile", filepath[0]) if self.populateCompositionFz: self.populateCompositionFz(self.layoutView.composition()) success = False layout_name = self.dialogui.comboBox_layouts.currentText() layout_item = self.projectLayoutManager.layoutByName(layout_name) exporter = QgsLayoutExporter(layout_item) if filename[-3:].lower() == u"pdf": success = exporter.exportToPdf(filepath[0], QgsLayoutExporter.PdfExportSettings()) else: success = exporter.exportToImage(filepath[0], QgsLayoutExporter.ImageExportSettings()) if success != 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Export Failed"), self.tr("Failed to export the layout."))
def testIteratorToPdf(self): project, layout = self.prepareIteratorLayout() atlas = layout.atlas() # setup settings settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 80 settings.rasterizeWholeImage = False settings.forceVectorOutput = False pdf_path = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single.pdf') result, error = QgsLayoutExporter.exportToPdf(atlas, pdf_path, settings) self.assertEqual(result, QgsLayoutExporter.Success, error) rendered_page_1 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single1.png') pdfToPng(pdf_path, rendered_page_1, dpi=80, page=1) self.assertTrue(self.checkImage('iteratortopdfsingle1', 'iteratortoimage1', rendered_page_1, size_tolerance=2)) rendered_page_2 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single2.png') pdfToPng(pdf_path, rendered_page_2, dpi=80, page=2) self.assertTrue(self.checkImage('iteratortopdfsingle2', 'iteratortoimage2', rendered_page_2, size_tolerance=2)) rendered_page_3 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single3.png') pdfToPng(pdf_path, rendered_page_3, dpi=80, page=3) self.assertTrue(os.path.exists(rendered_page_3)) rendered_page_4 = os.path.join(self.basetestpath, 'test_exportiteratortopdf_single4.png') pdfToPng(pdf_path, rendered_page_4, dpi=80, page=4) self.assertTrue(os.path.exists(rendered_page_4))
def exportPdf(self, outputPath, feedback=None): exporter = QgsLayoutExporter(self.layout) result, error = exporter.exportToPdfs( self.layout.atlas(), outputPath, settings=QgsLayoutExporter.PdfExportSettings(), feedback=feedback) return result, error
def imprimirPlanol(self, x, y, escala, rotacion, projectePlanol, templateFile, fitxerSortida, tipusSortida): self.project.read(projectePlanol) template = QFile(templateFile) # Creem un document amb la plantilla doc = QDomDocument() doc.setContent(template, False) # Aquest layout no té res a veure amb els layaouts de PyQt. # Es una plantilla per el projecte. You must believe it. layout = QgsLayout(self.project) context = QgsReadWriteContext() [items, ok] = layout.loadFromTemplate(doc, context) if ok: refMap = layout.referenceMap() rect = refMap.extent() vector = QgsVector(x - rect.center().x(), y - rect.center().y()) rect += vector refMap.setExtent(rect) refMap.setScale(escala) refMap.setMapRotation(rotacion) #Depenent del tipus de sortida... exporter = QgsLayoutExporter(layout) image_settings = exporter.ImageExportSettings() image_settings.dpi = 60 # result = exporter.exportToImage('d:/dropbox/qpic/preview.png', image_settings) # imatge = QPixmap('d:/dropbox/qpic/preview.png') t = time.localtime() timestamp = time.strftime('%b-%d-%Y_%H%M%S', t) if tipusSortida == 'PDF': settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 60 settings.exportMetadata = False fitxerSortida = 'd:/dropbox/qpic/sortida_' + timestamp + '.PDF' result = exporter.exportToPdf(fitxerSortida, settings) print(fitxerSortida) if tipusSortida == 'PNG': settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 60 # fitxerSortida='sortida_'+timestamp+'.PNG' fitxerSortida = projectePlanol[0:-4] + '.png' result = exporter.exportToImage(fitxerSortida, settings)
def exportItemAsPdf(self, comptecommunal, suffix=None): """ Export one PDF file using the template composer filled with appropriate data for one "compte communal" """ temppath = None # print("export pour le cc %s" % comptecommunal) # Set configuration self.setComposerTemplates(comptecommunal) # Create the composition self.createComposition() if self.currentComposition: # Populate composition for all pages # print("numpage %s" % self.numPages) for i in range(self.numPages): j = i + 1 self.addPageContent(j) # Add map in first page if export parcelle if self.etype == 'parcelle' and self.print_parcelle_page: self.addParcelleMap() # Create the pdf output path from time import time temp = "releve_%s_%s_%s.pdf" % ( self.etype, comptecommunal.replace('+', 'plus').replace( '*', 'fois'), # .replace('¤', 'plus'), int(time() * 100)) # Create regexp to remove all non ascii chars import re r = re.compile(r"[^ -~]") temp = r.sub('', temp) # print temp temppath = os.path.join(self.targetDir, temp) temppath = os.path.normpath(temppath) # print("export temppath %s" % temppath) # Export as pdf exportersettings = QgsLayoutExporter.PdfExportSettings() exportersettings.dpi = 300 exportersettings.forceVectorOutput = True exportersettings.rasterizeWholeImage = False exporter = QgsLayoutExporter(self.currentComposition) exporter.exportToPdf(temppath, exportersettings) # Remove redline layer if self.redlineLayer: self.mProject.removeMapLayer(self.redlineLayer.id()) return temppath
def export_view(self): """ Export current view to PDF """ # Load template from file s = QSettings() f = s.value("cadastre/composerTemplateFile", '', type=str) if not os.path.exists(f): f = os.path.join(str(Path(__file__).resolve().parent), 'composers', 'paysage_a4.qpt') s.setValue("cadastre/composerTemplateFile", f) QApplication.setOverrideCursor(Qt.WaitCursor) template_content = None with open(f, 'rt', encoding="utf-8") as ff: template_content = ff.read() if not template_content: return d = QDomDocument() d.setContent(template_content) c = QgsPrintLayout(QgsProject.instance()) c.loadFromTemplate(d, QgsReadWriteContext()) # Set scale and extent cm = c.referenceMap() canvas = self.iface.mapCanvas() extent = canvas.extent() scale = canvas.scale() if extent: cm.zoomToExtent(extent) if scale: cm.setScale(scale) # Export tempDir = s.value("cadastre/tempDir", '%s' % tempfile.gettempdir(), type=str) self.targetDir = tempfile.mkdtemp('', 'cad_export_', tempDir) temp = int(time() * 100) temppath = os.path.join(tempDir, 'export_cadastre_%s.pdf' % temp) exporter = QgsLayoutExporter(c) exportersettings = QgsLayoutExporter.PdfExportSettings() exportersettings.dpi = 300 exportersettings.forceVectorOutput = True exportersettings.rasterizeWholeImage = False # rasterizeWholeImage = false exporter.exportToPdf(temppath, exportersettings) QApplication.restoreOverrideCursor() if os.path.exists(temppath): CadastreCommon.openFile(temppath)
def testExportToPdf(self): l = QgsLayout(QgsProject.instance()) l.initializeDefaults() # add a second page page2 = QgsLayoutItemPage(l) page2.setPageSize('A5') l.pageCollection().addPage(page2) # add some items item1 = QgsLayoutItemShape(l) item1.attemptSetSceneRect(QRectF(10, 20, 100, 150)) fill = QgsSimpleFillSymbolLayer() fill_symbol = QgsFillSymbol() fill_symbol.changeSymbolLayer(0, fill) fill.setColor(Qt.green) fill.setStrokeStyle(Qt.NoPen) item1.setSymbol(fill_symbol) l.addItem(item1) item2 = QgsLayoutItemShape(l) item2.attemptSetSceneRect(QRectF(10, 20, 100, 150)) item2.attemptMove(QgsLayoutPoint(10, 20), page=1) fill = QgsSimpleFillSymbolLayer() fill_symbol = QgsFillSymbol() fill_symbol.changeSymbolLayer(0, fill) fill.setColor(Qt.cyan) fill.setStrokeStyle(Qt.NoPen) item2.setSymbol(fill_symbol) l.addItem(item2) exporter = QgsLayoutExporter(l) # setup settings settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 80 settings.rasterizeWholeImage = False settings.forceVectorOutput = False pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdfdpi.pdf') self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.Success) self.assertTrue(os.path.exists(pdf_file_path)) rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi.png') dpi = 80 pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1) rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttopdfdpi2.png') pdfToPng(pdf_file_path, rendered_page_2, dpi=dpi, page=2) self.assertTrue(self.checkImage('exporttopdfdpi_page1', 'exporttopdfdpi_page1', rendered_page_1, size_tolerance=1)) self.assertTrue(self.checkImage('exporttopdfdpi_page2', 'exporttopdfdpi_page2', rendered_page_2, size_tolerance=1))
def test_print_layout(self): export_file = os.path.join(self.outdir, 'export.pdf') project = QgsProject.instance() project.read( os.path.join(os.path.dirname(os.path.realpath(__file__)), 'test_data/simple_polygons.qgz')) layout_manager = project.layoutManager() layout = layout_manager.layouts()[0] exporter = QgsLayoutExporter(layout) exporter.exportToPdf(export_file, exporter.PdfExportSettings()) self.assertTrue(os.path.isfile(export_file)) self.assertTrue(os.path.getsize(export_file) > 0)
def export_pdf(self, count_id, file_name): current_dir = os.path.dirname(os.path.abspath(__file__)) qpt_file_path = os.path.join(current_dir, os.pardir, 'qml', 'plan.qpt') self.layout = PlanCreator.create_layout_from_template(qpt_file_path) self.set_fields(count_id) # self.layers.select_and_zoom_on_section_of_count(count_id) canvas = iface.mapCanvas() map_item = self.layout.itemById('map') map_item.setExtent(canvas.extent()) exporter = QgsLayoutExporter(self.layout) exporter.exportToPdf(file_name, exporter.PdfExportSettings())
def export_map(project_path, layout_name, pdf_path, thumbnail_path=None): # Open project project_instance = QgsProject.instance() project_instance.setFileName(project_path) project_instance.read() # Open layout manager = QgsProject.instance().layoutManager() layout = manager.layoutByName(layout_name) # Export PDF exporter = QgsLayoutExporter(layout) exporter.exportToPdf(pdf_path, QgsLayoutExporter.PdfExportSettings()) if thumbnail_path: # Generate a thumbnail image image = exporter.renderPageToImage(0, dpi=50) image.save(thumbnail_path)
def export_pdf(composer_name, composer): # setup settings settings = QgsLayoutExporter.PdfExportSettings() export_path = os.path.join( tempfile.gettempdir(), '%s_%s.pdf' % (composer_name, uuid4()) ) result, error = QgsLayoutExporter.exportToPdf( composer, export_path, settings) if (result != QgsLayoutExporter.Success or not os.path.isfile(export_path)): QgsMessageLog.logMessage("atlasprint: export not generated {} " "Error: {}".format(export_path, error), 'atlasprint', Qgis.Critical) return None QgsMessageLog.logMessage("atlasprint: path generated %s" % export_path, 'atlasprint', Qgis.Success) return export_path
def exportMap(self, composition, debugMode): basename = self.mi + '_' + self.inom if self.mi else self.inom exporter = QgsLayoutExporter(composition) exportStatus = 0 if not debugMode: pdfFilePath = os.path.join(self.exportFolder, f'{basename}.pdf') pdfExporterSettings = QgsLayoutExporter.PdfExportSettings() pdfExporterSettings.rasterizeWholeImage = True pdfExporterSettings.simplifyGeometries = False pdfExporterSettings.appendGeoreference = True pdfExporterSettings.exportMetadata = False pdfExporterSettings.dpi = 400 exportStatus += exporter.exportToPdf(pdfFilePath, pdfExporterSettings) if self.dlgCfg.exportTiff: tiffFilePath = os.path.join(self.exportFolder, f'{basename}.tif') tiffExporterSettings = QgsLayoutExporter.ImageExportSettings() tiffExporterSettings.dpi = 400 statusTiff = exporter.exportToImage(tiffFilePath, tiffExporterSettings) exportStatus += statusTiff del exporter return not bool(exportStatus)
def overrideExportSettings(self, layout, extension): """Because GUI settings are not exposed in Python, we need to find and catch user selection See discussion at http://osgeo-org.1560.x6.nabble.com/Programmatically-export-layout-with-georeferenced-file-td5365462.html""" if extension == '.pdf': exportSettings = QgsLayoutExporter.PdfExportSettings() if layout.customProperty( 'dpi') and layout.customProperty('dpi') != -1: exportSettings.dpi = layout.customProperty('dpi') if layout.customProperty('forceVector') == True: exportSettings.forceVectorOutput = True if layout.customProperty('rasterize') == True: exportSettings.rasterizeWholeImage = True elif extension == '.svg': exportSettings = QgsLayoutExporter.SvgExportSettings() if layout.customProperty( 'dpi') and layout.customProperty('dpi') != -1: exportSettings.dpi = layout.customProperty('dpi') if layout.customProperty('forceVector') == True: exportSettings.forceVectorOutput = True if layout.customProperty('svgIncludeMetadata') == True: exportSettings.exportMetadata = True if layout.customProperty('svgGroupLayers') == True: exportSettings.exportAsLayers = True else: exportSettings = QgsLayoutExporter.ImageExportSettings() if layout.customProperty('exportWorldFile') == True: exportSettings.generateWorldFile = True if layout.customProperty('') == True: exportSettings.exportMetadata = True if layout.customProperty( 'dpi') and layout.customProperty('dpi') != -1: exportSettings.dpi = layout.customProperty('dpi') # if layout.customProperty('atlasRasterFormat') == True : exportSettings.xxxx = True # if layout.customProperty('imageAntialias') == True : exportSettings.xxxx = True return exportSettings
def print_layout(project, layout_name, feature_filter: str = None, scales=None, scale=None, **kwargs): """Generate a PDF for an atlas or a report. :param project: The QGIS project. :type project: QgsProject :param layout_name: Name of the layout of the atlas or report. :type layout_name: basestring :param feature_filter: QGIS Expression to use to select the feature. It can return many features, a multiple pages PDF will be returned. This is required to print atlas, not report :type feature_filter: basestring :param scale: A scale to force in the atlas context. Default to None. :type scale: int :param scales: A list of predefined list of scales to force in the atlas context. Default to None. :type scales: list :return: Path to the PDF. :rtype: basestring """ canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas) bridge.setCanvasLayers() manager = project.layoutManager() master_layout = manager.layoutByName(layout_name) settings = QgsLayoutExporter.PdfExportSettings() atlas = None atlas_layout = None report_layout = None logger = Logger() if not master_layout: raise AtlasPrintException('Layout `{}` not found'.format(layout_name)) if master_layout.layoutType() == QgsMasterLayoutInterface.PrintLayout: for _print_layout in manager.printLayouts(): if _print_layout.name() == layout_name: atlas_layout = _print_layout break atlas = atlas_layout.atlas() if not atlas.enabled(): raise AtlasPrintException('The layout is not enabled for an atlas') layer = atlas.coverageLayer() if feature_filter is None: raise AtlasPrintException( 'EXP_FILTER is mandatory to print an atlas layout') feature_filter = optimize_expression(layer, feature_filter) expression = QgsExpression(feature_filter) if expression.hasParserError(): raise AtlasPrintException( 'Expression is invalid, parser error: {}'.format( expression.parserErrorString())) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(project)) context.appendScope( QgsExpressionContextUtils.layoutScope(atlas_layout)) context.appendScope(QgsExpressionContextUtils.atlasScope(atlas)) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(context) if expression.hasEvalError(): raise AtlasPrintException( 'Expression is invalid, eval error: {}'.format( expression.evalErrorString())) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) if scale: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Fixed) atlas_layout.referenceMap().setScale(scale) if scales: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Predefined) if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = scales else: atlas_layout.reportContext().setPredefinedScales(scales) if not scales and atlas_layout.referenceMap().atlasScalingMode( ) == QgsLayoutItemMap.Predefined: if Qgis.QGIS_VERSION_INT >= 30900: use_project = project.useProjectScales() map_scales = project.mapScales() else: map_scales = project_scales(project) use_project = len(map_scales) == 0 if not use_project or len(map_scales) == 0: logger.info( 'Map scales not found in project, fetching predefined map scales in global config' ) map_scales = global_scales() if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = map_scales else: atlas_layout.reportContext().setPredefinedScales(map_scales) elif master_layout.layoutType() == QgsMasterLayoutInterface.Report: report_layout = master_layout else: raise AtlasPrintException('The layout is not supported by the plugin') for key, value in kwargs.items(): found = False if atlas_layout: item = atlas_layout.itemById(key.lower()) if isinstance(item, QgsLayoutItemLabel): item.setText(value) found = True logger.info( 'Additional parameters: {} found in layout {}, value {}'.format( key, found, value)) export_path = os.path.join(tempfile.gettempdir(), '{}_{}.pdf'.format(layout_name, uuid4())) result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout, export_path, settings) if result != QgsLayoutExporter.Success and not os.path.isfile(export_path): raise Exception('export not generated {} ({})'.format( export_path, error)) return export_path
def create_qgis_pdf_output( impact_report, output_path, layout, file_format, metadata): """Produce PDF output using QgsLayout. :param output_path: The output path. :type output_path: str :param layout: QGIS Layout object. :type layout: qgis.core.QgsPrintLayout :param qgis_composition_context: QGIS Composition context used by renderer. :type qgis_composition_context: safe.report.impact_report. QgsLayoutContext :param file_format: file format of map output, PDF or PNG. :type file_format: 'pdf', 'png' :param metadata: The component metadata. :type metadata: QgisComposerComponentsMetadata :return: Generated output path. :rtype: str """ # make sure directory is created dirname = os.path.dirname(output_path) if not os.path.exists(dirname): os.makedirs(dirname) qgis_composition_context = impact_report.qgis_composition_context aggregation_summary_layer = ( impact_report.impact_function.aggregation_summary) # process atlas generation print_atlas = setting('print_atlas_report', False, bool) if layout.atlas().enabled() and ( print_atlas and aggregation_summary_layer): output_path = atlas_renderer( layout, aggregation_summary_layer, output_path, file_format) # for QGIS layout only pdf and png output are available elif file_format == QgisComposerComponentsMetadata.OutputFormat.PDF: try: exporter = QgsLayoutExporter(layout) settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = metadata.page_dpi settings.rasterizeWholeImage = \ qgis_composition_context.save_as_raster # settings.forceVectorOutput = False # settings.exportMetadata = True # TODO: ABP: check that page size is set on the pages res = exporter.exportToPdf(output_path, settings) if res != QgsLayoutExporter.Success: LOGGER.error('Error exporting to {}'.format( exporter.errorFile())) return None except Exception as exc: LOGGER.error(exc) return None elif file_format == QgisComposerComponentsMetadata.OutputFormat.PNG: # TODO: implement PNG generation raise Exception('Not yet supported') return output_path
def saveAsPDF(self): fullpath, format = QFileDialog.getSaveFileName(self, '存储为pdf', '', '*.pdf') print(fullpath) exporter = QgsLayoutExporter(self.layout) exporter.exportToPdf(fullpath, QgsLayoutExporter.PdfExportSettings())
def print_atlas(project, layout_name, feature_filter, scales=None, scale=None): """Generate an atlas. :param project: The project to render as atlas. :type project: QgsProject :param layout_name: Name of the layout. :type layout_name: basestring :param feature_filter: QGIS Expression to use to select the feature. It can return many features, a multiple pages PDF will be returned. :type feature_filter: basestring :param scale: A scale to force in the atlas context. Default to None. :type scale: int :param scales: A list of predefined list of scales to force in the atlas context. Default to None. :type scales: list :return: Path to the PDF. :rtype: basestring """ canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas) bridge.setCanvasLayers() manager = project.layoutManager() master_layout = manager.layoutByName(layout_name) if not master_layout: raise AtlasPrintException('Layout not found') if master_layout.layoutType() != QgsMasterLayoutInterface.PrintLayout: raise AtlasPrintException('The layout is not a print layout') for l in manager.printLayouts(): if l.name() == layout_name: layout = l break else: raise AtlasPrintException('The layout is not found') atlas = layout.atlas() if not atlas.enabled(): raise AtlasPrintException('The layout is not enabled for an atlas') settings = QgsLayoutExporter.PdfExportSettings() if scale: layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Fixed) layout.referenceMap().setScale(scale) if scales: layout.referenceMap().setAtlasScalingMode(QgsLayoutItemMap.Predefined) if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = scales else: layout.reportContext().setPredefinedScales(scales) layer = atlas.coverageLayer() feature_filter = optimize_expression(layer, feature_filter) expression = QgsExpression(feature_filter) if expression.hasParserError(): raise AtlasPrintException( 'Expression is invalid, parser error: {}'.format( expression.parserErrorString())) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(project)) context.appendScope(QgsExpressionContextUtils.layoutScope(layout)) context.appendScope(QgsExpressionContextUtils.atlasScope(atlas)) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(context) if expression.hasEvalError(): raise AtlasPrintException( 'Expression is invalid, eval error: {}'.format( expression.evalErrorString())) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) if not scales and layout.referenceMap().atlasScalingMode( ) == QgsLayoutItemMap.Predefined: if Qgis.QGIS_VERSION_INT >= 30900: use_project = project.useProjectScales() map_scales = project.mapScales() else: map_scales = project_scales(project) use_project = len(map_scales) == 0 if not use_project or len(map_scales) == 0: QgsMessageLog.logMessage( 'Map scales not found in project, fetching predefined map scales in global config', 'atlasprint', Qgis.Info) map_scales = global_scales() if Qgis.QGIS_VERSION_INT >= 30900: settings.predefinedMapScales = map_scales else: layout.reportContext().setPredefinedScales(map_scales) export_path = os.path.join(tempfile.gettempdir(), '{}_{}.pdf'.format(layout_name, uuid4())) exporter = QgsLayoutExporter(layout) result = exporter.exportToPdf(atlas, export_path, settings) if result[0] != QgsLayoutExporter.Success and not os.path.isfile( export_path): raise Exception('export not generated {}'.format(export_path)) return export_path
def print_atlas(project_path, composer_name, predefined_scales, feature_filter, page_name_expression=None): if not feature_filter: QgsMessageLog.logMessage("atlasprint: NO feature_filter provided !", 'atlasprint', Qgis.Critical) return None # Get composer from project # in QGIS 2, we can't get composers without iface # so we reading project xml and extract composer # TODO Since QGIS 3.0, we should be able to use project layoutManager() # noinspection PyPep8Naming from xml.etree import ElementTree as ET composer_xml = None with open(project_path, 'r') as f: tree = ET.parse(f) for elem in tree.findall('.//Composer[@title="%s"]' % composer_name): composer_xml = ET.tostring( elem, encoding='utf8', method='xml' ) if not composer_xml: for elem in tree.findall('.//Layout[@name="%s"]' % composer_name): composer_xml = ET.tostring( elem, encoding='utf8', method='xml' ) if not composer_xml: QgsMessageLog.logMessage("atlasprint: Composer XML not parsed !", 'atlasprint', Qgis.Critical) return None document = QDomDocument() document.setContent(composer_xml) # Get canvas, map setting & instantiate composition canvas = QgsMapCanvas() project = QgsProject() project.read(project_path) bridge = QgsLayerTreeMapCanvasBridge( project.layerTreeRoot(), canvas ) bridge.setCanvasLayers() layout = QgsPrintLayout(project) # Load content from XML layout.loadFromTemplate( document, QgsReadWriteContext(), ) atlas = layout.atlas() atlas.setEnabled(True) atlas_map = layout.referenceMap() atlas_map.setAtlasDriven(True) atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Predefined) layout.reportContext().setPredefinedScales(predefined_scales) if page_name_expression: atlas.setPageNameExpression(page_name_expression) # Filter feature here to avoid QGIS looping through every feature when doing : composition.setAtlasMode(QgsComposition.ExportAtlas) coverage_layer = atlas.coverageLayer() # Filter by FID as QGIS cannot compile expressions with $id or other $ vars # which leads to bad performance for big dataset use_fid = None if '$id' in feature_filter: import re ids = list(map(int, re.findall(r'\d+', feature_filter))) if len(ids) > 0: use_fid = ids[0] if use_fid: qReq = QgsFeatureRequest().setFilterFid(use_fid) else: qReq = QgsFeatureRequest().setFilterExpression(feature_filter) # Change feature_filter in order to improve performance pks = coverage_layer.dataProvider().pkAttributeIndexes() if use_fid and len(pks) == 1: pk = coverage_layer.dataProvider().fields()[pks[0]].name() feature_filter = '"%s" IN (%s)' % (pk, use_fid) QgsMessageLog.logMessage("atlasprint: feature_filter changed into: %s" % feature_filter, 'atlasprint', Qgis.Info) qReq = QgsFeatureRequest().setFilterExpression(feature_filter) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) uid = uuid4() i = 0 # We use a single page for now. atlas.beginRender() atlas.seekTo(i) # setup settings settings = QgsLayoutExporter.PdfExportSettings() export_path = os.path.join( tempfile.gettempdir(), '%s_%s.pdf' % (atlas.nameForPage(i), uid) ) exporter = QgsLayoutExporter(layout) result = exporter.exportToPdf(export_path, settings) atlas.endRender() if result != QgsLayoutExporter.Success: QgsMessageLog.logMessage("atlasprint: export not generated %s" % export_path, 'atlasprint', Qgis.Critical) return None if not os.path.isfile(export_path): QgsMessageLog.logMessage("atlasprint: export not generated %s" % export_path, 'atlasprint', Qgis.Critical) return None QgsMessageLog.logMessage("atlasprint: path generated %s" % export_path, 'atlasprint', Qgis.Success) return export_path
def exportLayout(self, cView, folder, title): """Function that sets how to export files.""" currProject = QgsProject.instance() printer = QPrinter() painter = QPainter() exporter = QgsLayoutExporter(cView) # Set page progressbar maximum value self.dlg.pageBar.setValue(0) self.dlg.pageBar.setMaximum(11) # Do the export process if not os.path.exists(os.path.join(folder, title)): os.makedirs(os.path.join(folder, title)) exporter.exportToPdf(os.path.join(folder, title, title + '.pdf'), QgsLayoutExporter.PdfExportSettings()) exporter.exportToImage(os.path.join(folder, title, title + '.jpg'), QgsLayoutExporter.ImageExportSettings()) # read CSV file & load into list with open(os.path.join(self.plugin_dir, "input/metadata_items.csv"), 'r') as metadata_file: reader = csv.reader(metadata_file, delimiter=',') metadata_list = list(reader) settings = ET.Element("mapdoc") mapdata = ET.SubElement(settings, "mapdata") # output fixed QGIS variables to XML """ACTION?""" # output project variables listed in CSV to XML for x in metadata_list: ma_variable = str(x[0]) elem_name = str(x[1]) elem_name = elem_name.strip() ma_level = str(x[2]) ma_level = ma_level.strip() if (ma_level == 'project') and (elem_name != 'no_xml'): elem_value = str( QgsExpressionContextUtils.projectScope( currProject).variable(ma_variable)) ET.SubElement(mapdata, elem_name).text = elem_value if elem_value.strip(): QgsMessageLog.logMessage( ma_variable + ' exported as ' + elem_value, 'MapExport', Qgis.Info) else: msgBar.pushMessage( 'Warning: missing value for ' + ma_variable, 5) QgsMessageLog.logMessage( 'Warning: missing value for ' + ma_variable, 'MapExport') themes = ET.SubElement(mapdata, "themes") for theme in self.dlg.themeBox.findChildren(QCheckBox): if theme.isChecked(): ET.SubElement(themes, 'theme').text = theme.text() for layout in QgsProject.instance().layoutManager().printLayouts(): # Set values of internal variables if layout.name() == self.dlg.layoutSelect.currentText(): date_now = datetime.date.today().strftime("%B %d, %Y") ET.SubElement(mapdata, 'lastUpdated').text = date_now title = layout.name() ET.SubElement(mapdata, 'jpgfilename').text = layout.name() + '.jpg' ET.SubElement(mapdata, 'pdffilename').text = layout.name() + '.pdf' # Action: Which map is selected by this? item = layout.referenceMap() # item = layout.itemById('main') # Get the attr by name and call map_scale = getattr(item, 'scale')() ET.SubElement(mapdata, 'scale').text = str(round(map_scale)) map_extent = item.extent() map_xmin = map_extent.xMinimum() map_xmax = map_extent.xMaximum() map_ymin = map_extent.yMinimum() map_ymax = map_extent.yMaximum() QgsMessageLog.logMessage('Scale ' + str(map_xmin), 'MapExport', Qgis.Info) ET.SubElement(mapdata, 'xmin').text = str(round(map_xmin)) ET.SubElement(mapdata, 'xmax').text = str(round(map_xmax)) ET.SubElement(mapdata, 'ymin').text = str(round(map_ymin)) ET.SubElement(mapdata, 'ymax').text = str(round(map_ymax)) for x in metadata_list: ma_variable = str(x[0]) elem_name = str(x[1]) elem_name = elem_name.strip() ma_level = str(x[2]) ma_level = ma_level.strip() if ma_level == 'layout': elem_value = str( QgsExpressionContextUtils.layoutScope( layout).variable(ma_variable)) ET.SubElement(mapdata, elem_name).text = elem_value if elem_value.strip(): QgsMessageLog.logMessage( ma_variable + ' exported as ' + elem_value, 'MapExport', Qgis.Info) else: msgBar.pushMessage( 'Warning: missing value for ' + ma_variable, 5) QgsMessageLog.logMessage( 'Warning: missing value for ' + ma_variable, 'MapExport') tree = ET.ElementTree(settings) tree.write(os.path.join(folder, title, title + '.xml')) # Set the location and the file name of the zip zippath = os.path.join(folder, title) zf = zipfile.ZipFile( os.path.abspath(folder) + os.sep + title + ".zip", "w") for dirnames, folders, files in os.walk(os.path.join(folder, title)): # for root, dirs, files in os.walk(folder): for file in files: zf.write(os.path.join(os.path.join(folder, title), file), file) zf.close() self.pageProcessed()
def atlas_renderer(layout, coverage_layer, output_path, file_format): """Extract composition using atlas generation. :param layout: QGIS Print Layout object used for producing the report. :type layout: qgis.core.QgsPrintLayout :param coverage_layer: Coverage Layer used for atlas map. :type coverage_layer: QgsMapLayer :param output_path: The output path of the product. :type output_path: str :param file_format: File format of map output, 'pdf' or 'png'. :type file_format: str :return: Generated output path(s). :rtype: str, list """ # set the composer map to be atlas driven composer_map = layout_item( layout, 'impact-map', QgsLayoutItemMap) composer_map.setAtlasDriven(True) composer_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) # setup the atlas composition and composition atlas mode atlas_composition = layout.atlas() atlas_composition.setCoverageLayer(coverage_layer) atlas_on_single_file = layout.customProperty('singleFile', True) if file_format == QgisComposerComponentsMetadata.OutputFormat.PDF: if not atlas_composition.filenameExpression(): atlas_composition.setFilenameExpression( "'output_'||@atlas_featurenumber") output_directory = os.path.dirname(output_path) # we need to set the predefined scales for atlas project_scales = [] scales = QgsProject.instance().readListEntry( "Scales", "/ScalesList")[0] has_project_scales = QgsProject.instance().readBoolEntry( "Scales", "/useProjectScales")[0] if not has_project_scales or not scales: scales_string = str(general_setting("Map/scales", PROJECT_SCALES)) scales = scales_string.split(',') for scale in scales: parts = scale.split(':') if len(parts) == 2: project_scales.append(float(parts[1])) layout.reportContext().setPredefinedScales(project_scales) settings = QgsLayoutExporter.PdfExportSettings() LOGGER.info('Exporting Atlas') atlas_output = [] if atlas_on_single_file: res, error = QgsLayoutExporter.exportToPdf( atlas_composition, output_path, settings) atlas_output.append(output_path) else: res, error = QgsLayoutExporter.exportToPdfs( atlas_composition, output_directory, settings) if res != QgsLayoutExporter.Success: LOGGER.error(error) return atlas_output
def overrideExportSettings(self, layout, extension): """Because GUI settings are not exposed in Python, we need to find and catch user selection and override export settings values with what is actually active in the GUI. See discussion at http://osgeo-org.1560.x6.nabble.com/Programmatically-export-layout-with-georeferenced-file-td5365462.html """ if extension == '.pdf': # See QgsLayoutDesignerDialog::getPdfExportSettings # let's follow non-default values if set exportSettings = QgsLayoutExporter.PdfExportSettings() exportSettings.flags = layout.renderContext().flags() exportSettings.dpi = layoutDpi if layout.customProperty('rasterize') in ['true', True]: exportSettings.rasterizeWholeImage = True if layout.customProperty('forceVector') == 1: exportSettings.forceVectorOutput = True if layout.customProperty('pdfTextFormat') == 1: exportSettings.textRenderFormat = 1 if layout.customProperty('pdfOgcBestPracticeFormat') == 1: exportSettings.useIso32000ExtensionFormatGeoreferencing = False exportSettings.useOgcBestPracticeFormatGeoreferencing = True if layout.customProperty('pdfExportThemes'): exportSettings.exportThemes = layout.customProperty( 'pdfExportThemes') if layout.customProperty('pdfIncludeMetadata') == 0: exportSettings.exportMetadata = False if layout.customProperty('pdfSimplify') == 0: exportSettings.simplifyGeometries = False if layout.customProperty('pdfCreateGeoPdf') == 1: exportSettings.writeGeoPdf = True if layout.customProperty('pdfAppendGeoreference') == 0: exportSettings.appendGeoreference = False if layout.customProperty('pdfExportGeoPdfFeatures') == 0: exportSettings.includeGeoPdfFeatures = False elif extension == '.svg': # See QgsLayoutDesignerDialog::getSvgExportSettings exportSettings = QgsLayoutExporter.SvgExportSettings() exportSettings.flags = layout.renderContext().flags() exportSettings.dpi = layoutDpi if layout.customProperty('forceVector') == 1: exportSettings.forceVectorOutput = True if layout.customProperty('svgIncludeMetadata') == 0: exportSettings.exportMetadata = False if layout.customProperty('svgSimplify') == 0: exportSettings.simplifyGeometries = False if layout.customProperty('svgGroupLayers') in ['true', True]: exportSettings.exportAsLayers = True if layout.customProperty('svgTextFormat') == 1: exportSettings.textRenderFormat = 1 if layout.customProperty('svgCropToContents') in ['true', True]: exportSettings.cropToContents = True # Todo: add margin values when cropping to content #exportSettings.cropMargins = ???QgsMargins??? #if layout.customProperty('svgDisableRasterTiles') in ['true', True] : ??? # to fine tune with flags FlagDisableTiledRasterLayerRenders else: # see QgsLayoutDesignerDialog::getRasterExportSettings for settings exportSettings = QgsLayoutExporter.ImageExportSettings() exportSettings.flags = layout.renderContext().flags() exportSettings.dpi = layoutDpi if layout.customProperty('exportWorldFile') in ['true', True]: exportSettings.generateWorldFile = True if layout.customProperty('imageCropToContents') in ['true', True]: exportSettings.cropToContents = True # Todo: add margin values when cropping to content #exportSettings.cropMargins = ???QgsMargins??? # exportSettings.exportMetadata = False # what's the corresponding layout's property? # layout.customProperty('atlasRasterFormat') # overridden by extension # # if layout.customProperty('imageAntialias') in ['true', True] : ??? # to fine tune with flags FlagAntialiasing return exportSettings
def print_layout( project: QgsProject, layout_name: str, output_format: OutputFormat, feature_filter: str = None, scales: list = None, scale: int = None, **kwargs, ): """Generate a PDF for an atlas or a report. :param project: The QGIS project. :type project: QgsProject :param layout_name: Name of the layout of the atlas or report. :type layout_name: basestring :param feature_filter: QGIS Expression to use to select the feature. It can return many features, a multiple pages PDF will be returned. This is required to print atlas, not report :type feature_filter: basestring :param scale: A scale to force in the atlas context. Default to None. :type scale: int :param scales: A list of predefined list of scales to force in the atlas context. Default to None. :type scales: list :param output_format: The output format, default to PDF if not provided. :return: Path to the PDF. :rtype: basestring """ canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas) bridge.setCanvasLayers() manager = project.layoutManager() master_layout = manager.layoutByName(layout_name) if output_format == OutputFormat.Svg: settings = QgsLayoutExporter.SvgExportSettings() elif output_format in (OutputFormat.Png, OutputFormat.Jpeg): settings = QgsLayoutExporter.ImageExportSettings() else: # PDF by default settings = QgsLayoutExporter.PdfExportSettings() atlas = None atlas_layout = None report_layout = None logger = Logger() if not master_layout: raise AtlasPrintException("Layout `{}` not found".format(layout_name)) if master_layout.layoutType() == QgsMasterLayoutInterface.PrintLayout: for _print_layout in manager.printLayouts(): if _print_layout.name() == layout_name: atlas_layout = _print_layout break atlas = atlas_layout.atlas() if not atlas.enabled(): raise AtlasPrintException("The layout is not enabled for an atlas") layer = atlas.coverageLayer() if feature_filter is None: raise AtlasPrintException( "EXP_FILTER is mandatory to print an atlas layout") feature_filter = optimize_expression(layer, feature_filter) expression = QgsExpression(feature_filter) if expression.hasParserError(): raise AtlasPrintException( "Expression is invalid, parser error: {}".format( expression.parserErrorString())) context = QgsExpressionContext() context.appendScope(QgsExpressionContextUtils.globalScope()) context.appendScope(QgsExpressionContextUtils.projectScope(project)) context.appendScope( QgsExpressionContextUtils.layoutScope(atlas_layout)) context.appendScope(QgsExpressionContextUtils.atlasScope(atlas)) context.appendScope(QgsExpressionContextUtils.layerScope(layer)) expression.prepare(context) if expression.hasEvalError(): raise AtlasPrintException( "Expression is invalid, eval error: {}".format( expression.evalErrorString())) atlas.setFilterFeatures(True) atlas.setFilterExpression(feature_filter) atlas.updateFeatures() if scale: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Fixed) atlas_layout.referenceMap().setScale(scale) if scales: atlas_layout.referenceMap().setAtlasScalingMode( QgsLayoutItemMap.Predefined) settings.predefinedMapScales = scales if (not scales and atlas_layout.referenceMap().atlasScalingMode() == QgsLayoutItemMap.Predefined): use_project = project.useProjectScales() map_scales = project.mapScales() if not use_project or len(map_scales) == 0: logger.info( "Map scales not found in project, fetching predefined map scales in global config" ) map_scales = global_scales() settings.predefinedMapScales = map_scales elif master_layout.layoutType() == QgsMasterLayoutInterface.Report: report_layout = master_layout else: raise AtlasPrintException("The layout is not supported by the plugin") for key, value in kwargs.items(): found = False if atlas_layout: item = atlas_layout.itemById(key.lower()) if isinstance(item, QgsLayoutItemLabel): item.setText(value) found = True logger.info( 'Additional parameters "{key}" {found} in layout, value "{value}"'. format(key=key, found="found" if found else "not found", value=value)) file_name = "{}_{}.{}".format(clean_string(layout_name), uuid4(), output_format.name.lower()) export_path = Path(tempfile.gettempdir()).joinpath(file_name) Logger().info("Exporting the request in {} using {}".format( export_path, output_format.value)) if output_format in (OutputFormat.Png, OutputFormat.Jpeg): exporter = QgsLayoutExporter(atlas_layout or report_layout) result = exporter.exportToImage(str(export_path), settings) error = result_message(result) elif output_format in (OutputFormat.Svg, ): exporter = QgsLayoutExporter(atlas_layout or report_layout) result = exporter.exportToSvg(str(export_path), settings) error = result_message(result) else: # Default to PDF result, error = QgsLayoutExporter.exportToPdf(atlas or report_layout, str(export_path), settings) # Let's override error message _ = error error = result_message(result) if result != QgsLayoutExporter.Success: raise Exception("Export not generated in QGIS exporter {} : {}".format( export_path, error)) if not export_path.is_file(): logger.warning( "No error from QGIS Exporter, but the file does not exist.\n" "Message from QGIS exporter : {}\n" "File path : {}\n".format(error, export_path)) raise Exception( "Export OK from QGIS, but file not found on the file system : {}". format(export_path)) return export_path
def TOMsExportAtlas(self, printProposalObject): # TH (180608): Export function to deal with atlases settings = QSettings() format = self.dialogui.comboBox_fileformat.itemData(self.dialogui.comboBox_fileformat.currentIndex()) # TH (180608): Check to see whether or not the Composer is an Atlas currPrintLayout = self.layoutView currLayoutAtlas = currPrintLayout.atlas() success = False # https://gis.stackexchange.com/questions/77848/programmatically-load-composer-from-template-and-generate-atlas-using-pyqgis?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa self.TOMsSetAtlasValues(currPrintLayout) currRevisionDate = self.proposalsManager.date() # get the map tiles that are affected by the Proposal # self.getProposalTileList(currProposalID, currRevisionDate) proposalTileDictionaryForDate = printProposalObject.getProposalTileDictionaryForDate(currRevisionDate) """self.tileSet = set( proposalTileDictionaryForDate)""" # TODO: Change around use of tileSet - also might be good to have a current proposal as an object in proposalManager... # Now check which tiles to use self.tilesToPrint = self.TOMsChooseTiles(proposalTileDictionaryForDate) if len(self.tilesToPrint) == 0: return # get the output location dirName = QFileDialog.getExistingDirectory( self.iface.mainWindow(), self.tr("Export Composition"), settings.value("/instantprint/lastdir", ""), QFileDialog.ShowDirsOnly ) if not dirName: return settings.setValue("/instantprint/lastdir", dirName) tileIDList = "" firstTile = True for tile in self.tilesToPrint: if firstTile: tileIDList = str(tile.attribute("id")) firstTile = False else: tileIDList = tileIDList + ',' + str(tile.attribute("id")) currLayoutAtlas.setFilterFeatures(True) currLayoutAtlas.setFilterExpression(' "id" in ({tileList})'.format(tileList=tileIDList)) composerRevisionNr = currPrintLayout.itemById('revisionNr') composerEffectiveDate = currPrintLayout.itemById('effectiveDate') composerProposalStatus = currPrintLayout.itemById('proposalStatus') if composerProposalStatus is not None: composerProposalStatus.setText(self.proposalForPrintingStatusText) else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Missing label in Layout"), self.tr("Missing label 'proposalStatus'")) composerPrintTypeDetails = currPrintLayout.itemById('printTypeDetails') if composerPrintTypeDetails is not None: composerPrintTypeDetails.setText(self.proposalPrintTypeDetails) else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Missing label in Layout"), self.tr("Missing label 'printTypeDetails'")) # currProposalTitle, currProposalOpenDate = self.getProposalTitle(currProposalID) #printProposal = printProposalObject currProposalTitle = printProposalObject.getProposalTitle() currProposalOpenDate = printProposalObject.getProposalOpenDate() if printProposalObject.thisProposalNr == 0: currProposalTitle = "CurrentRestrictions_({date})".format( date=self.proposalsManager.date().toString('yyyyMMMdd')) TOMsMessageLog.logMessage("In TOMsExportAtlas. Now printing " + str(currLayoutAtlas.count()) + " items ....", level=Qgis.Info) currLayoutAtlas.setEnabled(True) currLayoutAtlas.updateFeatures() currLayoutAtlas.beginRender() altasFeatureFound = currLayoutAtlas.first() while altasFeatureFound: currTileNr = int(currLayoutAtlas.nameForPage(currLayoutAtlas.currentFeatureNumber())) currLayoutAtlas.refreshCurrentFeature() #tileWithDetails = self.tileFromTileSet(currTileNr) tileWithDetails = proposalTileDictionaryForDate[currTileNr] if tileWithDetails == None: TOMsMessageLog.logMessage("In TOMsExportAtlas. Tile with details not found ....", level=Qgis.Info) QMessageBox.warning(self.iface.mainWindow(), self.tr("Print Failed"), self.tr("Could not find details for " + str(currTileNr))) break TOMsMessageLog.logMessage("In TOMsExportAtlas. tile nr: " + str(currTileNr) + " RevisionNr: " + str( tileWithDetails["RevisionNr"]) + " RevisionDate: " + str(tileWithDetails["LastRevisionDate"]), level=Qgis.Info) if self.proposalForPrintingStatusText == "CONFIRMED": composerRevisionNr.setText(str(tileWithDetails["RevisionNr"])) composerEffectiveDate.setText( '{date}'.format(date=tileWithDetails["LastRevisionDate"].toString('dd-MMM-yyyy'))) else: composerRevisionNr.setText(str(tileWithDetails["RevisionNr"] + 1)) # For the Proposal, use the current view date composerEffectiveDate.setText( '{date}'.format(date=self.openDateForPrintProposal.toString('dd-MMM-yyyy'))) filename = currProposalTitle + "_" + str( currTileNr) + "." + self.dialogui.comboBox_fileformat.currentText().lower() outputFile = os.path.join(dirName, filename) exporter = QgsLayoutExporter(currLayoutAtlas.layout()) if self.dialogui.comboBox_fileformat.currentText().lower() == u"pdf": result = exporter.exportToPdf(outputFile, QgsLayoutExporter.PdfExportSettings()) # success = currLayoutAtlas.composition().exportAsPDF(outputFile) else: result = exporter.exportToImage(outputFile, 'png', QgsLayoutExporter.ImageExportSettings()) """image = currLayoutAtlas.composition().printPageAsRaster(0) if not image.isNull(): success = image.save(outputFile)""" if result != QgsLayoutExporter.Success: QMessageBox.warning(self.iface.mainWindow(), self.tr("Print Failed"), self.tr("Failed to print " + exporter.errorFile())) break altasFeatureFound = currLayoutAtlas.next() currLayoutAtlas.endRender() QMessageBox.information(self.iface.mainWindow(), "Information", ("Printing completed"))
def check_layout_export(self, control_name, expected_nb_raster, layers=None, dpiTarget=None): """ Generate a PDF layout export and control the output matches expected_filename """ # generate vector file layout = QgsLayout(QgsProject.instance()) page = QgsLayoutItemPage(layout) page.setPageSize(QgsLayoutSize(50, 33)) layout.pageCollection().addPage(page) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(1, 1, 48, 32)) map.setFrameEnabled(True) layout.addLayoutItem(map) map.setExtent(self.lines_layer.extent()) map.setLayers(layers if layers is not None else [self.points_layer, self.lines_layer, self.polys_layer]) settings = QgsLayoutExporter.PdfExportSettings() if dpiTarget is not None: settings.dpi = dpiTarget exporter = QgsLayoutExporter(layout) result_filename = getTempfilePath('pdf') exporter.exportToPdf(result_filename, settings) self.assertTrue(os.path.exists(result_filename)) # Generate a readable PDF file so we count raster in it result_txt = getTempfilePath("txt") subprocess.run([ "qpdf", "--qdf", "--object-streams=disable", result_filename, result_txt ]) self.assertTrue(os.path.exists(result_txt)) # expected_file = os.path.join(TEST_DATA_DIR, "control_images/selective_masking/pdf_exports/{}".format(expected_filename)) # self.assertTrue(os.path.exists(expected_file)) result = open(result_txt, 'rb') result_lines = [l.decode('iso-8859-1') for l in result.readlines()] result.close() nb_raster = len([l for l in result_lines if "/Subtype /Image" in l]) self.assertEqual(nb_raster, expected_nb_raster) # Generate an image from pdf to compare with expected control image # keep PDF DPI resolution (300) image_result_filename = getTempfilePath("png") subprocess.run([ "pdftoppm", result_filename, os.path.splitext(image_result_filename)[0], "-png", "-r", "300", "-singlefile" ]) self.checker.setControlName(control_name) self.checker.setRenderedImage(image_result_filename) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res)
def testExportToPdf(self): md = QgsProject.instance().metadata() md.setTitle('proj title') md.setAuthor('proj author') md.setCreationDateTime(QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000))) md.setIdentifier('proj identifier') md.setAbstract('proj abstract') md.setKeywords({'kw': ['kw1', 'kw2'], 'KWx': ['kw3', 'kw4']}) QgsProject.instance().setMetadata(md) l = QgsLayout(QgsProject.instance()) l.initializeDefaults() # add a second page page2 = QgsLayoutItemPage(l) page2.setPageSize('A5') l.pageCollection().addPage(page2) # add some items item1 = QgsLayoutItemShape(l) item1.attemptSetSceneRect(QRectF(10, 20, 100, 150)) fill = QgsSimpleFillSymbolLayer() fill_symbol = QgsFillSymbol() fill_symbol.changeSymbolLayer(0, fill) fill.setColor(Qt.green) fill.setStrokeStyle(Qt.NoPen) item1.setSymbol(fill_symbol) l.addItem(item1) item2 = QgsLayoutItemShape(l) item2.attemptSetSceneRect(QRectF(10, 20, 100, 150)) item2.attemptMove(QgsLayoutPoint(10, 20), page=1) fill = QgsSimpleFillSymbolLayer() fill_symbol = QgsFillSymbol() fill_symbol.changeSymbolLayer(0, fill) fill.setColor(Qt.cyan) fill.setStrokeStyle(Qt.NoPen) item2.setSymbol(fill_symbol) l.addItem(item2) exporter = QgsLayoutExporter(l) # setup settings settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 80 settings.rasterizeWholeImage = False settings.forceVectorOutput = False settings.exportMetadata = True pdf_file_path = os.path.join(self.basetestpath, 'test_exporttopdfdpi.pdf') self.assertEqual(exporter.exportToPdf(pdf_file_path, settings), QgsLayoutExporter.Success) self.assertTrue(os.path.exists(pdf_file_path)) rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi.png') dpi = 80 pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1) rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttopdfdpi2.png') pdfToPng(pdf_file_path, rendered_page_2, dpi=dpi, page=2) self.assertTrue(self.checkImage('exporttopdfdpi_page1', 'exporttopdfdpi_page1', rendered_page_1, size_tolerance=1)) self.assertTrue(self.checkImage('exporttopdfdpi_page2', 'exporttopdfdpi_page2', rendered_page_2, size_tolerance=1)) d = gdal.Open(pdf_file_path) metadata = d.GetMetadata() self.assertEqual(metadata['AUTHOR'], 'proj author') self.assertEqual(metadata['CREATION_DATE'], "D:20110503090405+10'0'") self.assertEqual(metadata['KEYWORDS'], 'KWx: kw3,kw4;kw: kw1,kw2') self.assertEqual(metadata['SUBJECT'], 'proj abstract') self.assertEqual(metadata['TITLE'], 'proj title')
def processAlgorithm(self, parameters, context, feedback): """This actually creates the print layout and exporting as .pdf document""" log = feedback.setProgressText input_title = self.parameterAsString(parameters, self.INPUT_TITLE, context) input_subtitle = self.parameterAsString(parameters, self.INPUT_SUBTITLE, context) input_credit_text = self.parameterAsString(parameters, self.INPUT_CREDIT_TEXT, context) output_pdf_path = self.parameterAsString(parameters, self.OUTPUT_PDF_PATH, context) log(f"Title: {input_title}") log(f"Subtitle: {input_subtitle}") log(f"Credit Text: {input_credit_text}") log(f"Output pdf path: {output_pdf_path}") #This creates a new print layout project = context.project() manager = project.layoutManager() layout = QgsPrintLayout(project) layoutName = 'EcoValuator Layout' #layoutName is going to be name of Title. Change this later layouts_list = manager.printLayouts() for layout in layouts_list: if layout.name() == layoutName: manager.removeLayout(layout) layout = QgsPrintLayout(project) layout.initializeDefaults() #create default map canvas layout.setName(layoutName) manager.addLayout(layout) #This adds a map item to the Print Layout map = QgsLayoutItemMap(layout) map.setRect(20, 20, 20, 20) #Set Extent canvas = iface.mapCanvas() map.setExtent(canvas.extent()) #sets map extent to current map canvas layout.addLayoutItem(map) #Move & Resize map.attemptMove(QgsLayoutPoint(5, 27, QgsUnitTypes.LayoutMillimeters)) map.attemptResize( QgsLayoutSize(218, 178, QgsUnitTypes.LayoutMillimeters)) #Gather visible layers in project layer tree and create a list of the map layer objects #Those which are not active (layers_to_remove) will subsequently remove from the legend model tree_layers = project.layerTreeRoot().children() active_layers = [ layer.name() for layer in tree_layers if layer.isVisible() ] layers_to_remove = [ layer for layer in project.mapLayers().values() if layer.name() not in active_layers ] #This adds a legend item to the Print Layout legend = QgsLayoutItemLegend(layout) layout.addLayoutItem(legend) legend.attemptMove( QgsLayoutPoint(219, 5, QgsUnitTypes.LayoutMillimeters)) #Get reference to existing legend model and root group then remove the unchecked layers legend.setAutoUpdateModel(False) #not sure if this line is required model = legend.model() group = model.rootGroup() for layer in layers_to_remove: group.removeLayer(layer) legend.adjustBoxSize() #This adds labels to the map title = QgsLayoutItemLabel(layout) title.setText(input_title) title.setFont(QFont("Arial", 28)) title.adjustSizeToText() layout.addLayoutItem(title) title.attemptMove(QgsLayoutPoint(10, 4, QgsUnitTypes.LayoutMillimeters)) subtitle = QgsLayoutItemLabel(layout) subtitle.setText(input_subtitle) subtitle.setFont(QFont("Arial", 17)) subtitle.adjustSizeToText() layout.addLayoutItem(subtitle) subtitle.attemptMove( QgsLayoutPoint(11, 20, QgsUnitTypes.LayoutMillimeters)) credit_text = QgsLayoutItemLabel(layout) credit_text.setText(input_credit_text) credit_text.setFont(QFont("Arial", 10)) credit_text.adjustSizeToText() layout.addLayoutItem(credit_text) credit_text.attemptMove( QgsLayoutPoint(219, 190, QgsUnitTypes.LayoutMillimeters)) #this creates credit text (line1) in bottom right corner of map layout giving credit to Key-Log Economics keylog_credits1 = QgsLayoutItemLabel(layout) keylog_credits1.setText("Created using EcoValuator Plugin") keylog_credits1.setFont(QFont("Arial", 10)) keylog_credits1.adjustSizeToText() layout.addLayoutItem(keylog_credits1) keylog_credits1.attemptMove( QgsLayoutPoint(219, 195, QgsUnitTypes.LayoutMillimeters)) #this creates credit text (line2) in bottom right corner of map layout giving credit to Key-Log Economics keylog_credits2 = QgsLayoutItemLabel(layout) keylog_credits2.setText("by Key-Log Economics") keylog_credits2.setFont(QFont("Arial", 10)) keylog_credits2.adjustSizeToText() layout.addLayoutItem(keylog_credits2) keylog_credits2.attemptMove( QgsLayoutPoint(219, 200, QgsUnitTypes.LayoutMillimeters)) #This exports a Print Layout as an image manager = QgsProject.instance().layoutManager( ) #this is a reference to the layout Manager, which contains a list of print layouts layout = manager.layoutByName( layoutName ) #this accesses a specific layout, by name (which is a string) exporter = QgsLayoutExporter( layout) #this creates a QgsLayoutExporter object exporter.exportToPdf(output_pdf_path, QgsLayoutExporter.PdfExportSettings()) log("Done!") result = { } #The processAlgorithm wants to return a dictionary. We don't actually need to do this so instead we return an empty one return result
def imprimirPlanol(self, x, y, escala, rotacion, midaPagina, templateFile, fitxerSortida, tipusSortida): tInicial = time.time() template = QFile(templateFile) doc = QDomDocument() doc.setContent(template, False) layout = QgsLayout(self.project) # page=QgsLayoutItemPage(layout) # page.setPageSize(midaPagina) # layout.pageCollection().addPage(page) # layout.initializeDefaults() # p=layout.pageCollection().pages()[0] # p.setPageSize(midaPagina) context = QgsReadWriteContext() [items, ok] = layout.loadFromTemplate(doc, context) # p=layout.pageCollection().pages()[0] # p.setPageSize(midaPagina) if ok: refMap = layout.referenceMap() titol = layout.itemById('idNomMapa') dataMapa = layout.itemById('idData') if self.leTitol.text() != '': titol.setText(self.leTitol.text()) #comentat pk peta else: titol.setText('') try: t = time.localtime() dataMapa.setText(strftime('%b-%d-%Y %H:%M', t)) except: pass rect = refMap.extent() vector = QgsVector(x - rect.center().x(), y - rect.center().y()) rect += vector refMap.setExtent(rect) refMap.setScale(escala) refMap.setMapRotation(rotacion) #Depenent del tipus de sortida... exporter = QgsLayoutExporter(layout) # image_settings = exporter.ImageExportSettings() # image_settings.dpi = 30 # result = exporter.exportToImage('d:/dropbox/qpic/preview.png', image_settings) # imatge = QPixmap('d:/dropbox/qpic/preview.png') # self.ui.lblImatgeResultat.setPixmap(imatge) if tipusSortida == 'PDF': settings = QgsLayoutExporter.PdfExportSettings() settings.dpi = 300 settings.exportMetadata = False # fitxerSortida='d:/sortida_'+timestamp+'.PDF' fitxerSortida += '.PDF' result = exporter.exportToPdf( fitxerSortida, settings) #Cal desar el resultat (???) print(fitxerSortida) if tipusSortida == 'PNG': settings = QgsLayoutExporter.ImageExportSettings() settings.dpi = 300 # fitxerSortida='d:/sortida_'+timestamp+'.PNG' fitxerSortida += '.PNG' result = exporter.exportToImage( fitxerSortida, settings) #Cal desar el resultat (???) #Obra el document si està marcat checkObrirResultat QDesktopServices().openUrl(QUrl(fitxerSortida)) segonsEmprats = round(time.time() - tInicial, 1) #??? layersTemporals = self.project.mapLayersByName( "Capa temporal d'impressió") estatDirtybit = self.parent.canvisPendents for layer in layersTemporals: self.project.removeMapLayer(layer.id()) self.parent.setDirtyBit(estatDirtybit)
def exportPDF(self, model, chart_path, gyf, exportDialog, area_id, groups, feature_gids, total): # Text from export dialog map_title = exportDialog.projectName.text() area_name = exportDialog.areaName.text() output_path = exportDialog.pdfPath.text() output_name = exportDialog.pdfName.text() author = exportDialog.author.text() gyf_version = model['Version'] #AP 2.0 date = datetime.datetime.today().strftime('%Y-%m-%d') # Get template path = os.path.dirname(os.path.realpath(__file__)) a = path.rfind('\\') template_file = open(path[:a] + "/template/qgyf_template1.qpt", encoding="utf-8") template_content = template_file.read() template_file.close() document = QDomDocument() proj = QgsProject.instance() document.setContent(template_content) composition = QgsLayout(proj) composition.loadFromTemplate(document, QgsReadWriteContext()) # Title title = sip.cast(composition.itemById("title"), QgsLayoutItemLabel) title.setText(map_title) title = sip.cast(composition.itemById("title1"), QgsLayoutItemLabel) title.setText(map_title) title = sip.cast(composition.itemById("title2"), QgsLayoutItemLabel) title.setText(map_title) # GYF value value = sip.cast(composition.itemById("gyf_value"), QgsLayoutItemLabel) value.setText('GYF ' + gyf) value = sip.cast(composition.itemById("gyf_value1"), QgsLayoutItemLabel) value.setText('GYF ' + gyf) value = sip.cast(composition.itemById("gyf_value2"), QgsLayoutItemLabel) value.setText('GYF ' + gyf) # GYF groups groups = sorted(list(set(groups))) groupList = sip.cast(composition.itemById("groups"), QgsLayoutItemLabel) text = '''<font face="tahoma" color="#238973"><h3>GYF Kategorier:</h3></font> <p style="font-family:tahoma; font-size:13.5; font-color:#4d4949; line-height:21px">''' for g in groups: text += g + '<br>' text = text + '</p>' groupList.setText(text) # Research Area area_id = area_id.id() research_area_lyr = proj.mapLayersByName('Beräkningsområde')[0] query = "id = " + str(area_id) research_area_lyr.setSubsetString(query) for feature in research_area_lyr.getFeatures(): s = feature['yta'] area_info = sip.cast(composition.itemById("area_info"), QgsLayoutItemLabel) items = [['Beräkningsyta: ', str(int(float(s)))], ['Ekoeffektiv yta: ', str(int(float(total)))]] text2 = "" for i in items: text2 += '<font face="tahoma" color="#238973"><b>'+ i[0] + \ '</b></font><p style="display:inline;font-family:tahoma; font-size:13.5; font-color:#4d4949; line-height:19px">''' + \ i[1] + ' m<sup>2</sup></p><br>' area_info.setText(text2) extent = research_area_lyr.extent() # Map main_map = sip.cast(composition.itemById("map"), QgsLayoutItemMap) main_map.zoomToExtent(extent) composition.itemById("map").refresh() main_map.setKeepLayerSet(True) main_map.setKeepLayerStyles(True) # Legend legend = sip.cast(composition.itemById("legend"), QgsLayoutItemLegend) legend.setLegendFilterByMapEnabled(True) # Remove background map from legend - have to be checked out #root = QgsLayerTree() #for lyr in iface.mapCanvas().layers(): # if lyr.type() == QgsMapLayer.VectorLayer: # root.addLayer(lyr) # legend.model().setRootGroup(root) legend.setAutoUpdateModel(False) # Table Grundytor & Kvaliteter root = proj.layerTreeRoot() content = [l.name() for l in root.children()] db_path = '{}\{}'.format( proj.readEntry("QGYF", "dataPath")[0], proj.readEntry("QGYF", 'activeDataBase')[0]) uri = QgsDataSourceUri() uri.setDatabase(db_path) #Table 2 - ground areas uri.setDataSource('', 'ground_areas', None) table2 = QgsVectorLayer(uri.uri(), 'ground_areas', 'spatialite') if 'ground_areas' not in content: proj.addMapLayer(table2, False) tableLayout2 = sip.cast(composition.itemById("table2"), QgsLayoutFrame) tableLayout2.refreshItemPosition() tableLayout2 = tableLayout2.multiFrame() tableLayout2.setVectorLayer(table2) tableLayout2.setDisplayedFields( ['ytgrupp', 'ytklass', 'faktor', 'yta', 'poang']) # label table_areas = sip.cast(composition.itemById("table_areas"), QgsLayoutItemLabel) table2_name = '<font face="tahoma" color="#238973"><b>' + model[ 'Klass_items'][0].title() + 'er</b></font>' table_areas.setText(table2_name) #h = tableLayout2.totalHeight() #Table 1 - qualities uri.setDataSource('', 'classification', None) table1 = QgsVectorLayer(uri.uri(), 'classification', 'spatialite') if 'classification' not in content: proj.addMapLayer(table1, False) tableLayout = sip.cast(composition.itemById("table"), QgsLayoutFrame) #position = tableLayout.positionAtReferencePoint(tableLayout.ReferencePoint()) #position.setX(position.x() + h) #tableLayout.setReferencePoint(position) tableLayout.refreshItemPosition() tableLayout = tableLayout.multiFrame() tableLayout.setVectorLayer(table1) tableLayout.setDisplayedFields([ 'id', 'geometri_typ', 'fil_namn', 'grupp', 'kvalitet', 'faktor', 'yta', 'poang' ]) # Filter feature_gids = "', '".join(i for i in feature_gids) query = "gid in ('" + feature_gids + "')" tableLayout.setFilterFeatures(True) tableLayout.setFeatureFilter(query) tableLayout.update() # label table_class = sip.cast(composition.itemById("table_class"), QgsLayoutItemLabel) table1_name = '<font face="tahoma" color="#238973"><b>' + model[ 'Klass_items'][1].title() + 'er</b></font>' table_class.setText(table1_name) # Diagram chart = sip.cast(composition.itemById("chart"), QgsLayoutItemPicture) chart.setPicturePath(chart_path) chart.refreshPicture() # Diagram chart2 = sip.cast(composition.itemById("chart2"), QgsLayoutItemPicture) if float(gyf) > 0.0: chart2.setPicturePath( proj.readEntry("QGYF", "dataPath")[0] + '\PieChart2.png') chart2.refreshPicture() # Metadata text = '<p style="font-family:tahoma; font-size:13.5; font-color:#4d4949; line-height:21px">Område: ' + \ area_name + '<br>Utförd av: ' + author + '<br>GYF version: ' + gyf_version + '<br>Datum: ' + date + '</p>' info = sip.cast(composition.itemById("info"), QgsLayoutItemLabel) info.setText(text) info = sip.cast(composition.itemById("info1"), QgsLayoutItemLabel) info.setText(text) # EXPORT! QgsLayoutExporter(composition).exportToPdf( output_path + '/' + output_name, QgsLayoutExporter.PdfExportSettings()) QMessageBox.information(ExportDialog(), 'Rapport', 'Din rapport har skapats! :)') # Reset map view research_area_lyr.setSubsetString('') proj.removeMapLayer(table1) proj.removeMapLayer(table2)