def on_prepared_for_atlas(self, layout, item): # called for each atlas feature if not self.layer: return geom = QgsExpressionContextUtils.atlasScope(layout.atlas()).variable('atlas_geometry') if not geom: return masked_atlas_geometry = [geom] # no need to zoom, it has already been scaled by atlas self.layer = self.apply_mask_parameters(self.layer, self.parameters, dest_crs=self.layer.crs(), poly=masked_atlas_geometry, name=self.layer.name(), cleanup_and_zoom=False) # update maps QCoreApplication.processEvents() layout.refreshItems()
def on_prepared_for_atlas(self, layout): # called for each atlas feature if not self.layer: return geom = QgsExpressionContextUtils.atlasScope( layout.atlas()).variable("atlas_geometry") if not geom: return masked_atlas_geometry = [geom] # no need to zoom, it has already been scaled by atlas self.layer = self.apply_mask_parameters( self.layer, self.parameters, dest_crs=self.layer.crs(), poly=masked_atlas_geometry, name=self.layer.name(), cleanup_and_zoom=False, ) # update maps QCoreApplication.processEvents()
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_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 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