def createImageParams(): def finished(): def addParams(): def getJsonImages(): vmap = {} for l in self.paramProcess['layerImages']: vmap[ l.name() ] = l.source() return json.dumps( vmap ) e = self.paramProcess['canvas'].extent() imgWidth, imgHeight = image.width(), image.height() resX, resY = e.width() / imgWidth, e.height() / imgHeight self.paramProcess['json_images'] = getJsonImages() self.paramProcess['crs_map'] = self.paramProcess['canvas'].mapSettings().destinationCrs().authid() self.paramProcess['extent_map'] = e.asWktCoordinates() # xMin, yMin, xMax, yMax self.paramProcess['res'] = { 'X': resX, 'Y': resY } image = job.renderedImage() if bool( self.paramProcess['canvas'].property('retro') ): image = image.scaled( image.width() / 3, image.height() / 3 ) image = image.convertToFormat( QImage.Format_Indexed8, Qt.OrderedDither | Qt.OrderedAlphaDither ) image.save( self.paramProcess['pathfileImage'], "TIFF", 100 ) # 100: Uncompressed addParams() settings = QgsMapSettings( self.paramProcess['canvas'].mapSettings() ) settings.setBackgroundColor( QColor( Qt.transparent ) ) layers = self.paramProcess['layerImages'] if 'layerPolygon' in self.paramProcess: layers = [ self.paramProcess['layerPolygon'] ] + layers settings.setLayers( layers ) job = QgsMapRendererParallelJob( settings ) job.start() job.finished.connect( finished) job.waitForFinished()
def loadProject(filename): # clear the map layer registry QgsMapLayerRegistry.instance().removeAllMapLayers() assert os.path.exists(filename), "project file does not exist: " + filename # load the project QgsProject.instance().read(QFileInfo(filename)) assert QgsMapLayerRegistry.instance().mapLayers(), "no layers in map layer registry" doc = QDomDocument() with open(filename) as f: doc.setContent(f.read()) # map settings mapSettings = QgsMapSettings() mapSettings.readXML(doc.elementsByTagName("mapcanvas").at(0)) # visible layers layerIds = [] nodes = doc.elementsByTagName("legendlayer") for i in range(nodes.count()): elem = nodes.at(i).toElement().elementsByTagName("legendlayerfile").at(0).toElement() if elem.attribute("visible") == "1": layerIds.append(elem.attribute("layerid")) mapSettings.setLayers(layerIds) # canvas color red = int(doc.elementsByTagName("CanvasColorRedPart").at(0).toElement().text()) green = int(doc.elementsByTagName("CanvasColorGreenPart").at(0).toElement().text()) blue = int(doc.elementsByTagName("CanvasColorBluePart").at(0).toElement().text()) mapSettings.setBackgroundColor(QColor(red, green, blue)) return mapSettings
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" crs.createFromSrid(4326) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) return ms
def cloneMapSettings(self, oms): """ :param QgsMapSettings oms: Other QgsMapSettings :rtype: QgsMapSettings """ ms = QgsMapSettings() ms.setBackgroundColor(oms.backgroundColor()) ms.setOutputSize(oms.outputSize()) ms.setOutputDpi(oms.outputDpi()) ms.setFlags(oms.flags()) ms.setDestinationCrs(oms.destinationCrs()) ms.setExtent(oms.extent()) ms.setOutputImageFormat(oms.outputImageFormat()) ms.setLabelingEngineSettings(oms.labelingEngineSettings()) ms.setLayers(oms.layers()) return ms
def cloneMapSettings(self, oms): """ :param oms: QgsMapSettings :rtype: QgsMapSettings """ ms = QgsMapSettings() ms.setBackgroundColor(oms.backgroundColor()) ms.setOutputSize(oms.outputSize()) ms.setOutputDpi(oms.outputDpi()) ms.setFlags(oms.flags()) ms.setDestinationCrs(oms.destinationCrs()) ms.setCrsTransformEnabled(oms.hasCrsTransformEnabled()) ms.setMapUnits(oms.mapUnits()) ms.setExtent(oms.extent()) ms.setLayers(oms.layers()) return ms
def savePng(self, box, name, path, size=1024): options = QgsMapSettings() # layers = QgsProject.instance().mapLayers().values() layers = [iface.activeLayer()] options.setDestinationCrs( QgsCoordinateReferenceSystem(self.export_epsg)) options.setLayers(layers) options.setBackgroundColor(QColor(255, 255, 255)) options.setOutputSize(QSize(size, size)) options.setExtent(box) # options.setFlag(options.Antialiasing, True) render = QgsMapRendererSequentialJob(options) render.start() render.waitForFinished() img = render.renderedImage() img.save(path + "/" + name + ".png", "png")
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) ms.setExtent(cls.aoiExtent()) return ms
def save_layer_image(filename, layer, extent): h = int(extent.height() / extent.width() * WIDTH) img = QImage(QSize(WIDTH, h), QImage.Format_A2BGR30_Premultiplied) color = QColor(255, 255, 255, 255) img.fill(color.rgba()) p = QPainter() p.begin(img) p.setRenderHint(QPainter.Antialiasing) ms = QgsMapSettings() ms.setBackgroundColor(color) ms.setLayers([layer]) ms.setExtent(extent) ms.setOutputSize(img.size()) render = QgsMapRendererCustomPainterJob(ms, p) render.start() render.waitForFinished() p.end() img.save(filename)
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing) ms.setDestinationCrs(crs) ms.setCrsTransformEnabled(False) ms.setMapUnits(crs.mapUnits()) # meters ms.setExtent(cls.aoiExtent()) return ms
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing) ms.setDestinationCrs(crs) ms.setCrsTransformEnabled(False) ms.setMapUnits(crs.mapUnits()) # meters ms.setExtent(cls.aoiExtent()) return ms
def cloneMapSettings(self, oms): """ :param QgsMapSettings oms: Other QgsMapSettings :rtype: QgsMapSettings """ ms = QgsMapSettings() ms.setBackgroundColor(oms.backgroundColor()) ms.setOutputSize(oms.outputSize()) ms.setOutputDpi(oms.outputDpi()) ms.setFlags(oms.flags()) ms.setDestinationCrs(oms.destinationCrs()) ms.setCrsTransformEnabled(oms.hasCrsTransformEnabled()) ms.setMapUnits(oms.mapUnits()) ms.setExtent(oms.extent()) ms.setOutputImageFormat(oms.outputImageFormat()) ms.setLayers(oms.layers()) return ms
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) ms.setExtent(cls.aoiExtent()) return ms
def _process(self): def finished(): image = job.renderedImage() if bool(self.data['canvas'].property('retro')): image = image.scaled(image.width() / 3, image.height() / 3) image = image.convertToFormat( QImage.Format_Indexed8, Qt.OrderedDither | Qt.OrderedAlphaDither) image.save(self.data['filepath'], "TIFF", 100) # 100: Uncompressed self._setParamsSendData(image) settings = QgsMapSettings(self.data['canvas'].mapSettings()) settings.setBackgroundColor(QColor(Qt.transparent)) settings.setLayers(self.data['layers']) job = QgsMapRendererParallelJob(settings) job.start() job.finished.connect(finished) job.waitForFinished()
def _saveLayerThumbnail(layer): filename = tempFileInSubFolder("thumbnail.png") img = QImage(QSize(800, 800), QImage.Format_A2BGR30_Premultiplied) color = QColor(255, 255, 255, 255) img.fill(color.rgba()) p = QPainter() p.begin(img) p.setRenderHint(QPainter.Antialiasing) ms = QgsMapSettings() ms.setBackgroundColor(color) ms.setLayers([layer]) ms.setExtent(layer.extent()) ms.setOutputSize(img.size()) render = QgsMapRendererCustomPainterJob(ms, p) render.start() render.waitForFinished() p.end() img.save(filename) return filename
def writeLegendPng(self, layer, mapTitle, mapAttr, operation): mapTitle = UTILS.normalizeName(mapTitle) mapAttr = UTILS.normalizeName(mapAttr) legendFolder = self.getPathForMap(mapTitle, mapAttr, operation) # e.g. vlayer = iface.activeLayer() options = QgsMapSettings() options.setLayers([layer]) options.setBackgroundColor(QColor(255, 128, 255)) options.setOutputSize(QSize(60, 60)) options.setExtent(layer.extent()) qgisRenderJob = QgsMapRendererParallelJob(options) def savePng(): img = qgisRenderJob.renderedImage() # save the image; e.g. img.save("/Users/myuser/render.png","png") img.save(os.path.join(legendFolder, "legend.png"), "png") qgisRenderJob.finished.connect(savePng) qgisRenderJob.start()
def create_image(self, extent, width, height, canvas_name, output_dir): ''' This method create an image :param extent: Extent :param width: Output image width :param height: Output image height :param canvas_name: Map name :param output_dir: Output directory for image ''' if not extent: raise_exception('extent is empty') if not width: raise_exception('width is empty') if not height: raise_exception('height is empty') if not canvas_name: raise_exception('canvas name is empty') if not output_dir: raise_exception('output_dir is empty') file_name = '{0}/{1}.png'.format(output_dir, canvas_name) settings = QgsMapSettings() settings.setLayers(iface.mapCanvas().layers()) settings.setBackgroundColor(QColor(255, 255, 255)) settings.setOutputSize(QSize(width, height)) settings.setExtent(extent) render = QgsMapRendererParallelJob(settings) render.start() render.waitForFinished() image = render.renderedImage() image.save(file_name, "png") return file_name
def loadProject(filename): # clear the map layer registry QgsMapLayerRegistry.instance().removeAllMapLayers() assert os.path.exists(filename), "project file does not exist: " + filename # load the project QgsProject.instance().read(QFileInfo(filename)) assert QgsMapLayerRegistry.instance().mapLayers( ), "no layers in map layer registry" doc = QDomDocument() with open(filename) as f: doc.setContent(f.read()) # map settings mapSettings = QgsMapSettings() mapSettings.readXML(doc.elementsByTagName("mapcanvas").at(0)) # visible layers layerIds = [] nodes = doc.elementsByTagName("legendlayer") for i in range(nodes.count()): elem = nodes.at(i).toElement().elementsByTagName("legendlayerfile").at( 0).toElement() if elem.attribute("visible") == "1": layerIds.append(elem.attribute("layerid")) mapSettings.setLayers(layerIds) # canvas color red = int( doc.elementsByTagName("CanvasColorRedPart").at(0).toElement().text()) green = int( doc.elementsByTagName("CanvasColorGreenPart").at(0).toElement().text()) blue = int( doc.elementsByTagName("CanvasColorBluePart").at(0).toElement().text()) mapSettings.setBackgroundColor(QColor(red, green, blue)) return mapSettings
class TestSelectiveMasking(unittest.TestCase): def setUp(self): self.checker = QgsRenderChecker() self.checker.setControlPathPrefix("selective_masking") self.report = "<h1>Python Selective Masking Tests</h1>\n" self.map_settings = QgsMapSettings() crs = QgsCoordinateReferenceSystem('epsg:4326') extent = QgsRectangle(-123.0, 22.7, -76.4, 46.9) self.map_settings.setBackgroundColor(QColor(152, 219, 249)) self.map_settings.setOutputSize(QSize(420, 280)) self.map_settings.setOutputDpi(72) self.map_settings.setFlag(QgsMapSettings.Antialiasing, True) self.map_settings.setFlag(QgsMapSettings.UseAdvancedEffects, False) self.map_settings.setDestinationCrs(crs) self.map_settings.setExtent(extent) # load a predefined QGIS project self.assertTrue(QgsProject.instance().read( os.path.join(unitTestDataPath(), "selective_masking.qgs"))) self.points_layer = QgsProject.instance().mapLayersByName('points')[0] self.lines_layer = QgsProject.instance().mapLayersByName('lines')[0] # line layer with subsymbols self.lines_layer2 = QgsProject.instance().mapLayersByName('lines2')[0] # line layer with labels self.lines_with_labels = QgsProject.instance().mapLayersByName( 'lines_with_labels')[0] self.polys_layer = QgsProject.instance().mapLayersByName('polys')[0] # polygon layer with a rule based labeling self.polys_layer2 = QgsProject.instance().mapLayersByName('polys2')[0] self.raster_layer = QgsProject.instance().mapLayersByName( 'raster_layer')[0] # try to fix the font for where labels are defined # in order to have more stable image comparison tests for layer in [ self.polys_layer, self.lines_with_labels, self.polys_layer2 ]: for provider in layer.labeling().subProviders(): settings = layer.labeling().settings(provider) font = getTestFont() font.setPointSize(32) fmt = settings.format() fmt.setFont(font) fmt.setNamedStyle('Roman') fmt.setSize(32) fmt.setSizeUnit(QgsUnitTypes.RenderPoints) settings.setFormat(fmt) if (layer.geometryType == QgsWkbTypes.PolygonGeometry): settings.placement = QgsPalLayerSettings.OverPoint layer.labeling().setSettings(settings, provider) # order layers for rendering self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer]) def tearDown(self): report_file_path = "%s/qgistest.html" % QDir.tempPath() with open(report_file_path, 'a') as report_file: report_file.write(self.report) def check_renderings(self, map_settings, control_name): """Test a rendering with different configurations: - parallel rendering, no cache - sequential rendering, no cache - parallel rendering, with cache (rendered two times) - sequential rendering, with cache (rendered two times) """ for do_parallel in [False, True]: for use_cache in [False, True]: print("=== parallel", do_parallel, "cache", use_cache) tmp = getTempfilePath('png') cache = None if use_cache: cache = QgsMapRendererCache() # render a first time to fill the cache renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img, t = renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img.save(tmp) print("Image rendered in {}".format(tmp)) self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) suffix = ("_parallel" if do_parallel else "_sequential") + ( "_cache" if use_cache else "_nocache") res = self.checker.compareImages(control_name + suffix) self.report += self.checker.report() self.assertTrue(res) print("=== Rendering took {}s".format(float(t) / 1000.0)) 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 test_save_restore_references(self): """ Test saving and restoring symbol layer references """ # simple ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) # complex ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference( self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference( self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference( self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference( self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) # complex ids, v2 mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference( self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference( self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference( self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference( self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) def test_label_mask(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask") def test_multiple_label_masks_different_sets(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # polygons QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers( [self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_different_sets") # restore map settings self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer]) def test_multiple_label_masks_same_set(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers( [self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_same_set") # restore map settings self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_subsymbol(self): # new map settings with a line symbology that has sub symbols self.map_settings.setLayers( [self.points_layer, self.lines_layer2, self.polys_layer]) # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # mask only vertical segments of "roads" QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0])), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_subsymbol") # restore original map settings self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_dd(self): """ test label mask with data defined properties """ label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() fmt.mask().setEnabled(False) fmt.mask().setSize(1.0) fmt.mask().setOpacity(0.42) # mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) # overwrite with data-defined properties fmt.dataDefinedProperties().setProperty( QgsPalLayerSettings.MaskEnabled, QgsProperty.fromExpression('1')) fmt.dataDefinedProperties().setProperty( QgsPalLayerSettings.MaskBufferSize, QgsProperty.fromExpression('4.0')) fmt.dataDefinedProperties().setProperty( QgsPalLayerSettings.MaskOpacity, QgsProperty.fromExpression('100.0')) context = QgsRenderContext() fmt.updateDataDefinedProperties(context) self.assertEqual(fmt.mask().enabled(), True) self.assertEqual(fmt.mask().size(), 4.0) self.assertEqual(fmt.mask().opacity(), 1.0) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "label_mask") def test_label_mask_rule_labeling(self): # new map settings with a rule based labeling self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer2]) # modify labeling settings of one rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() == 'Tadam': break label_settings = child.settings() label_settings.priority = 3 fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) child.setSettings(label_settings) # modify labeling settings of another rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() != 'Tadam': break label_settings = child.settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the polygons QgsSymbolLayerReference(self.polys_layer2.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) child.setSettings(label_settings) self.check_renderings(self.map_settings, "rule_label_mask") # restore map settings self.map_settings.setLayers( [self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_symbol_levels(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # enable symbol levels self.lines_layer.renderer().setUsingSymbolLevels(True) self.check_renderings(self.map_settings, "label_mask_symbol_levels") def test_symbol_layer_mask(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "sl_mask") def test_multiple_masks_same_symbol_layer(self): """Test multiple masks that occlude the same symbol layer""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_same_sl") def test_multiple_masks_different_symbol_layers_same_layer(self): """Test multiple masks that occlude different symbol layers of the same layer. The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl") def test_multiple_masks_different_symbol_layers_same_layer2(self): """Test multiple masks that occlude different symbol layers of the same layer - 2nd possible order The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl2") def test_mask_symbollayer_preview(self): # # Masks should be visible in previews # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) p.insertSymbolLayer(0, mask_layer) for control_name, render_function in [ ("as_image", lambda: p.asImage(QSize(64, 64)).save(tmp)), ("as_big_preview", lambda: p.bigSymbolPreviewImage().save(tmp)), ("sl_preview", lambda: QgsSymbolLayerUtils.symbolLayerPreviewIcon( mask_layer, QgsUnitTypes.RenderPixels, QSize(64, 64)).pixmap( QSize(64, 64)).save(tmp)) ]: tmp = getTempfilePath('png') render_function() self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name, 90) self.report += self.checker.report() self.assertTrue(res) def test_mask_with_effect(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '12'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add an outer glow effect to the mask layer blur = QgsOuterGlowEffect.create({ "enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) mask_layer.setPaintEffect(blur) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "mask_with_effect") def test_label_mask_with_effect(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({ "enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_with_effect") # test that force vector output has no impact on the result self.map_settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True) self.check_renderings(self.map_settings, "label_mask_with_effect") def test_different_dpi_target(self): """Test with raster layer and a target dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.map_settings.setLayers( [self.lines_layer, self.polys_layer, self.raster_layer]) self.map_settings.setDpiTarget(300) self.check_renderings(self.map_settings, "different_dpi_target") # test with high dpi screen self.map_settings.setDevicePixelRatio(2) self.check_renderings(self.map_settings, "different_dpi_target_hdpi") def test_layout_export(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.font().setPointSize(4) fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_layout_export("layout_export", 0) def test_layout_export_w_effects(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.font().setPointSize(4) fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({ "enabled": "1", "blur_level": "3.445", "blur_unit": "MM", "opacity": "1", "spread": "0.06", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) # 4 rasters : Image and its mask for masked point and lines layer self.check_layout_export("layout_export_w_effects", 4) def test_layout_export_marker_masking(self): """Test mask effects in a layout export with a marker symbol masking""" p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_layout_export("layout_export_marker_masking", 0) def test_layout_export_marker_masking_w_effects(self): """Test mask effects in a layout export with a marker symbol masking""" p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({ "enabled": "1", "blur_level": "3.445", "blur_unit": "MM", "opacity": "1", "spread": "0.06", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) # TODO try to set the mask effect on p the marker symbol -> result should be the same mask_layer.setPaintEffect(blur) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # 2 rasters : Image and its mask for masked lines layer self.check_layout_export("layout_export_marker_masking_w_effects", 2) def test_layout_export_w_raster(self): """Test layout export with raster beneath the masked area""" # just decrease the yellow line so we see the raster on masked area self.lines_layer.renderer().symbol().symbolLayers()[1].setWidth(0.5) # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.font().setPointSize(4) fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) # 1 raster : the raster layer self.check_layout_export( "layout_export_w_raster", 1, [self.lines_layer, self.polys_layer, self.raster_layer]) def test_layout_export_w_force_raster_render(self): """ Test layout export with a marker symbol masking forced to be render as raster We expect the lines to be masked and the whole output needs to be vector except the marker layer forced as raster """ p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.points_layer.renderer().setForceRasterRender(True) # 2 rasters : Image and its mask for the points layer self.check_layout_export("layout_export_force_raster_render", 2, [self.points_layer, self.lines_layer]) def test_layout_export_marker_masking_w_transparency(self): """Test layout export with a marker symbol masking which has an opacity lower than 1""" p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) circle_symbol.setOpacity(0.5) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # 2 rasters (mask + image) because opacity force rasterization of the masked line layers self.check_layout_export("layout_export_marker_masking_w_transparency", 2) def test_layout_export_text_masking_w_transparency(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.font().setPointSize(4) fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) fmt.mask().setOpacity(0.5) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) # 4 rasters (mask+image per masked layer) because opacity force rasterization # of the masked line and point layers self.check_layout_export("layout_export_text_masking_w_transparency", 4) def test_different_dpi_target_vector(self): """Test rendering a raster layer with vector output and a target dpi Used when layout previewing """ # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.map_settings.setLayers( [self.lines_layer, self.polys_layer, self.raster_layer]) self.map_settings.setOutputDpi(81) self.map_settings.setDpiTarget(300) self.map_settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True) image = QImage(self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat()) image.setDevicePixelRatio(self.map_settings.devicePixelRatio()) image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() / 25.4)) image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() / 25.4)) image.fill(Qt.transparent) pImg = QPainter() pImg.begin(image) job = QgsMapRendererCustomPainterJob(self.map_settings, pImg) job.start() job.waitForFinished() pImg.end() tmp = getTempfilePath('png') image.save(tmp) control_name = "different_dpi_target_vector" self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res) # Same test with high dpi self.map_settings.setDevicePixelRatio(2) image = QImage(self.map_settings.deviceOutputSize(), self.map_settings.outputImageFormat()) image.setDevicePixelRatio(self.map_settings.devicePixelRatio()) image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() / 25.4)) image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() / 25.4)) image.fill(Qt.transparent) pImg = QPainter() pImg.begin(image) job = QgsMapRendererCustomPainterJob(self.map_settings, pImg) job.start() job.waitForFinished() pImg.end() tmp = getTempfilePath('png') image.save(tmp) control_name = "different_dpi_target_vector_hdpi" self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res) def test_layout_export_2_sources_masking(self): """Test masking with 2 different sources""" # mask with points layer circles... p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "3"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '6'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # ...and with text label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() fmt.font().setPointSize(4) fmt.mask().setEnabled(True) fmt.mask().setSize(1.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_layout_export("layout_export_2_sources_masking", 0)
class TileSet(): """ A set of tiles """ def __init__(self, map_theme, layer, extent, tile_size, mupp, output, make_trans, map_settings, project): """ :param map_theme: :param extent: :param layer: :param tile_size: :param mupp: :param output: :param map_settings: Map canvas map settings used for some fallback values and CRS """ self.extent = extent self.mupp = mupp self.tile_size = tile_size driver = self.getDriverForFile(output) if not driver: raise QgsProcessingException( u'Could not load GDAL driver for file {}'.format(output)) crs = map_settings.destinationCrs() self.x_tile_count = math.ceil(extent.width() / mupp / tile_size) self.y_tile_count = math.ceil(extent.height() / mupp / tile_size) xsize = self.x_tile_count * tile_size ysize = self.y_tile_count * tile_size if make_trans: no_bands = 4 else: no_bands = 3 self.dataset = driver.Create(output, xsize, ysize, no_bands) self.dataset.SetProjection(str(crs.toWkt())) self.dataset.SetGeoTransform( [extent.xMinimum(), mupp, 0, extent.yMaximum(), 0, -mupp]) self.image = QImage(QSize(tile_size, tile_size), QImage.Format_ARGB32) self.settings = QgsMapSettings() self.settings.setOutputDpi(self.image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_ARGB32) self.settings.setDestinationCrs(crs) self.settings.setOutputSize(self.image.size()) self.settings.setFlag(QgsMapSettings.Antialiasing, True) self.settings.setFlag(QgsMapSettings.RenderMapTile, True) self.settings.setFlag(QgsMapSettings.UseAdvancedEffects, True) r = project.readNumEntry('Gui', '/CanvasColorRedPart', 255)[0] g = project.readNumEntry('Gui', '/CanvasColorGreenPart', 255)[0] b = project.readNumEntry('Gui', '/CanvasColorBluePart', 255)[0] if make_trans: self.bgColor = QColor(r, g, b, 0) else: self.bgColor = QColor(r, g, b) self.settings.setBackgroundColor(self.bgColor) if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme): self.settings.setLayers(QgsProject.instance().mapThemeCollection(). mapThemeVisibleLayers(map_theme)) self.settings.setLayerStyleOverrides(QgsProject.instance( ).mapThemeCollection().mapThemeStyleOverrides(map_theme)) elif layer: self.settings.setLayers([layer]) else: self.settings.setLayers(map_settings.layers()) def render(self, feedback, make_trans): for x in range(self.x_tile_count): for y in range(self.y_tile_count): if feedback.isCanceled(): return cur_tile = x * self.y_tile_count + y num_tiles = self.x_tile_count * self.y_tile_count self.renderTile(x, y, feedback, make_trans) feedback.setProgress(int((cur_tile / num_tiles) * 100)) def renderTile(self, x, y, feedback, make_trans): """ Render one tile :param x: The x index of the current tile :param y: The y index of the current tile """ if make_trans: self.image.fill(self.bgColor.rgba()) else: self.image.fill(self.bgColor.rgb()) painter = QPainter(self.image) self.settings.setExtent( QgsRectangle( self.extent.xMinimum() + x * self.mupp * self.tile_size, self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size, self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size, self.extent.yMaximum() - y * self.mupp * self.tile_size)) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() # Needs not to be deleted or Windows will kill it too early... tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False) try: self.image.save(tmpfile.name) src_ds = osgeo.gdal.Open(tmpfile.name) self.dataset.WriteRaster( x * self.tile_size, y * self.tile_size, self.tile_size, self.tile_size, src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size)) except Exception as e: feedback.reportError(str(e)) finally: del src_ds tmpfile.close() os.unlink(tmpfile.name) def getDriverForFile(self, filename): """ Get the GDAL driver for a filename, based on its extension. (.gpkg, .mbtiles...) """ _, extension = os.path.splitext(filename) # If no extension is set, use .tif as default if extension == '': extension = '.tif' driver_name = QgsRasterFileWriter.driverForExtension(extension[1:]) return osgeo.gdal.GetDriverByName(driver_name)
def printMap(self,taxon): # copy style from grid layer to output layer outstyle = tempfile.gettempdir() + os.sep + "output.qml" getLayerFromId(self.GRID_LAYER).saveNamedStyle(outstyle) self.TAXON_GRID_LAYER.loadNamedStyle(outstyle) # create layer set baseLayer = getLayerFromId(self.BASE_LAYER) if self.TAXON_GRID_LAYER.crs() != baseLayer.crs(): QMessageBox.information(self.dlg,"Distribution Map Generator", "All layers must have the same projection.") raise QgsCsException("All layers must have the same projection.") baseCrs = baseLayer.crs() if self.SECONDARY_LAYER != "None": secondaryLayer = getLayerFromId(self.SECONDARY_LAYER) if secondaryLayer.crs() != baseLayer.crs(): QMessageBox.information(self.dlg,"Distribution Map Generator", "All layers must have the same projection.") raise QgsCsException("All layers must have the same projection.") else: secondaryLayer = None if self.SURFACE_LAYER != "None": surfaceLayer = getLayerFromId(self.SURFACE_LAYER) if surfaceLayer.crs() != baseLayer.crs(): QMessageBox.information(self.dlg,"Distribution Map Generator", "All layers must have the same projection.") raise QgsCsException("All layers must have the same projection.") else: surfaceLayer = None lst = [] lst.append(self.TAXON_GRID_LAYER) if self.SURFACE_LAYER != "None": lst.append(surfaceLayer) if self.SECONDARY_LAYER != "None": lst.append(secondaryLayer) lst.append(baseLayer) ms = QgsMapSettings() ms.setLayers(lst) ms.setBackgroundColor(self.BACKGROUND_COLOUR) # set extent (xmin,ymin,xmax,ymax) rect = QgsRectangle(self.X_MIN,self.Y_MIN,self.X_MAX,self.Y_MAX) ms.setExtent(rect) # set output size outputSize = QSize(self.OUT_WIDTH,self.OUT_HEIGHT) ms.setOutputSize(outputSize) # create painter p = QPainter() p.setRenderHint(QPainter.Antialiasing) # create image (dimensions 325x299) img = QImage(outputSize, QImage.Format_ARGB32_Premultiplied) p.begin(img) # do the rendering r = QgsMapRendererCustomPainterJob(ms, p) r.start() r.waitForFinished() p.end() # save image outdir = self.OUT_DIR img.save(outdir+os.sep+str(str(taxon))+".png","png")
class TileSet(): """ A set of tiles """ def __init__(self, map_theme, layer, extent, tile_size, mupp, output, make_trans, map_settings): """ :param map_theme: :param extent: :param layer: :param tile_size: :param mupp: :param output: :param map_settings: Map canvas map settings used for some fallback values and CRS """ self.extent = extent self.mupp = mupp self.tile_size = tile_size driver = self.getDriverForFile(output) if not driver: raise QgsProcessingException( u'Could not load GDAL driver for file {}'.format(output)) crs = map_settings.destinationCrs() self.x_tile_count = math.ceil(extent.width() / mupp / tile_size) self.y_tile_count = math.ceil(extent.height() / mupp / tile_size) xsize = self.x_tile_count * tile_size ysize = self.y_tile_count * tile_size if make_trans: no_bands = 4 else: no_bands = 3 self.dataset = driver.Create(output, xsize, ysize, no_bands) self.dataset.SetProjection(str(crs.toWkt())) self.dataset.SetGeoTransform( [extent.xMinimum(), mupp, 0, extent.yMaximum(), 0, -mupp]) self.image = QImage(QSize(tile_size, tile_size), QImage.Format_ARGB32) self.settings = QgsMapSettings() self.settings.setOutputDpi(self.image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_ARGB32) self.settings.setDestinationCrs(crs) self.settings.setOutputSize(self.image.size()) self.settings.setFlag(QgsMapSettings.Antialiasing, True) self.settings.setFlag(QgsMapSettings.RenderMapTile, True) self.settings.setFlag(QgsMapSettings.UseAdvancedEffects, True) if make_trans: self.settings.setBackgroundColor(QColor(255, 255, 255, 0)) else: self.settings.setBackgroundColor(QColor(255, 255, 255)) if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme): self.settings.setLayers( QgsProject.instance().mapThemeCollection( ).mapThemeVisibleLayers( map_theme)) self.settings.setLayerStyleOverrides( QgsProject.instance().mapThemeCollection( ).mapThemeStyleOverrides( map_theme)) elif layer: self.settings.setLayers([layer]) else: self.settings.setLayers(map_settings.layers()) def render(self, feedback, make_trans): for x in range(self.x_tile_count): for y in range(self.y_tile_count): if feedback.isCanceled(): return cur_tile = x * self.y_tile_count + y num_tiles = self.x_tile_count * self.y_tile_count self.renderTile(x, y, feedback, make_trans) feedback.setProgress(int((cur_tile / num_tiles) * 100)) def renderTile(self, x, y, feedback, make_trans): """ Render one tile :param x: The x index of the current tile :param y: The y index of the current tile """ if make_trans: background_color = QColor(255, 255, 255, 0) self.image.fill(background_color.rgba()) else: background_color = QColor(255, 255, 255) self.image.fill(background_color.rgb()) painter = QPainter(self.image) self.settings.setExtent(QgsRectangle( self.extent.xMinimum() + x * self.mupp * self.tile_size, self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size, self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size, self.extent.yMaximum() - y * self.mupp * self.tile_size)) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() # Needs not to be deleted or Windows will kill it too early... tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False) try: self.image.save(tmpfile.name) src_ds = osgeo.gdal.Open(tmpfile.name) self.dataset.WriteRaster(x * self.tile_size, y * self.tile_size, self.tile_size, self.tile_size, src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size)) except Exception as e: feedback.reportError(str(e)) finally: del src_ds tmpfile.close() os.unlink(tmpfile.name) def getDriverForFile(self, filename): """ Get the GDAL driver for a filename, based on its extension. (.gpkg, .mbtiles...) """ _, extension = os.path.splitext(filename) # If no extension is set, use .tif as default if extension == '': extension = '.tif' driver_name = QgsRasterFileWriter.driverForExtension(extension[1:]) return osgeo.gdal.GetDriverByName(driver_name)
def cvt_vtr(self): QSWATMOD_path_dict = self.dirs_and_paths() selectedVector = self.dlg.comboBox_vector_lyrs.currentText() layer = QgsProject.instance().mapLayersByName(str(selectedVector))[0] # Find .dis file and read number of rows, cols, x spacing, and y spacing (not allowed to change) for filename in glob.glob(str(QSWATMOD_path_dict['SMfolder']) + "/*.dis"): with open(filename, "r") as f: data = [] for line in f.readlines(): if not line.startswith("#"): data.append(line.replace('\n', '').split()) nrow = int(data[0][1]) ncol = int(data[0][2]) delr = float(data[2][1]) # is the cell width along rows (y spacing) delc = float( data[3][1]) # is the cell width along columns (x spacing). # get extent ext = layer.extent() xmin = ext.xMinimum() xmax = ext.xMaximum() ymin = ext.yMinimum() ymax = ext.yMaximum() extent = "{a},{b},{c},{d}".format(a=xmin, b=xmax, c=ymin, d=ymax) fdnames = [ field.name() for field in layer.dataProvider().fields() if not (field.name() == 'fid' or field.name() == 'id' or field.name() == 'xmin' or field.name() == 'xmax' or field.name() == 'ymin' or field.name() == 'ymax' or field.name() == 'grid_id' or field.name() == 'row' or field.name() == 'col' or field.name() == 'elev_mf') ] # Create swatmf_results tree inside root = QgsProject.instance().layerTreeRoot() if root.findGroup("swatmf_results"): swatmf_results = root.findGroup("swatmf_results") else: swatmf_results = root.insertGroup(0, "swatmf_results") if root.findGroup(selectedVector): rastergroup = root.findGroup(selectedVector) else: rastergroup = swatmf_results.insertGroup(0, selectedVector) per = 0 self.dlg.progressBar_cvt_vtr.setValue(0) for fdnam in fdnames: QCoreApplication.processEvents() nodata = float(self.dlg.lineEdit_nodata.text()) mincolor = self.dlg.mColorButton_min_rmap.color().name() maxcolor = self.dlg.mColorButton_max_rmap.color().name() name = fdnam name_ext = "{}.tif".format(name) output_dir = QSWATMOD_path_dict['SMshps'] # create folder for each layer output rasterpath = os.path.join(output_dir, selectedVector) if not os.path.exists(rasterpath): os.makedirs(rasterpath) output_raster = os.path.join(rasterpath, name_ext) params = { 'INPUT': layer, 'FIELD': fdnam, 'UNITS': 1, 'WIDTH': delc, 'HEIGHT': delr, 'EXTENT': extent, 'NODATA': nodata, 'DATA_TYPE': 5, #Float32 'OUTPUT': output_raster } processing.run("gdal:rasterize", params) rasterlayer = QgsRasterLayer(output_raster, '{0} ({1})'.format(fdnam, selectedVector)) QgsProject.instance().addMapLayer(rasterlayer, False) rastergroup.insertChildNode(0, QgsLayerTreeLayer(rasterlayer)) stats = rasterlayer.dataProvider().bandStatistics( 1, QgsRasterBandStats.All) rmin = stats.minimumValue rmax = stats.maximumValue fnc = QgsColorRampShader() lst = [ QgsColorRampShader.ColorRampItem(rmin, QColor(mincolor)), QgsColorRampShader.ColorRampItem(rmax, QColor(maxcolor)) ] fnc.setColorRampItemList(lst) fnc.setColorRampType(QgsColorRampShader.Interpolated) shader = QgsRasterShader() shader.setRasterShaderFunction(fnc) renderer = QgsSingleBandPseudoColorRenderer(rasterlayer.dataProvider(), 1, shader) rasterlayer.setRenderer(renderer) rasterlayer.triggerRepaint() # create image img = QImage(QSize(800, 800), QImage.Format_ARGB32_Premultiplied) # set background color # bcolor = QColor(255, 255, 255, 255) bcolor = QColor(255, 255, 255, 0) img.fill(bcolor.rgba()) # create painter p = QPainter() p.begin(img) p.setRenderHint(QPainter.Antialiasing) # create map settings ms = QgsMapSettings() ms.setBackgroundColor(bcolor) # set layers to render flayer = QgsProject.instance().mapLayersByName(rasterlayer.name()) ms.setLayers([flayer[0]]) # set extent rect = QgsRectangle(ms.fullExtent()) rect.scale(1.1) ms.setExtent(rect) # set ouptut size ms.setOutputSize(img.size()) # setup qgis map renderer render = QgsMapRendererCustomPainterJob(ms, p) render.start() render.waitForFinished() # get timestamp p.drawImage(QPoint(), img) pen = QPen(Qt.red) pen.setWidth(2) p.setPen(pen) font = QFont() font.setFamily('Times') # font.setBold(True) font.setPointSize(18) p.setFont(font) # p.setBackground(QColor('sea green')) doesn't work p.drawText(QRect(0, 0, 800, 800), Qt.AlignRight | Qt.AlignBottom, fdnam) p.end() # save the image img.save(os.path.join(rasterpath, '{:03d}_{}.jpg'.format(per, fdnam))) # Update progress bar per += 1 progress = round((per / len(fdnames)) * 100) self.dlg.progressBar_cvt_vtr.setValue(progress) QCoreApplication.processEvents() self.dlg.raise_() duration = self.dlg.doubleSpinBox_ani_r_time.value() # filepaths fp_in = os.path.join(rasterpath, '*.jpg') fp_out = os.path.join(rasterpath, '{}.gif'.format(selectedVector)) # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif fimg, *fimgs = [Image.open(f) for f in sorted(glob.glob(fp_in))] fimg.save(fp=fp_out, format='GIF', append_images=fimgs, save_all=True, duration=duration * 1000, loop=0, transparency=0) msgBox = QMessageBox() msgBox.setWindowIcon(QtGui.QIcon(':/QSWATMOD2/pics/sm_icon.png')) msgBox.setWindowTitle("Coverted!") msgBox.setText( "Fields from {} were converted successfully!".format(selectedVector)) msgBox.exec_() questionBox = QMessageBox() questionBox.setWindowIcon(QtGui.QIcon(':/QSWATMOD2/pics/sm_icon.png')) reply = QMessageBox.question(questionBox, 'Open?', 'Do you want to open the animated gif file?', QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: os.startfile(os.path.join(rasterpath, '{}.gif'.format(selectedVector)))
def responseComplete(self): request = self.serverInterface().requestHandler() params = request.parameterMap() # SERVICE=RENDERGEOJSON -- we are taking over if params.get('SERVICE', '').upper() == 'RENDERGEOJSON': request.clear() try: # Parse parameters geojson = params.get('GEOJSON') if not geojson: raise ParameterError('Parameter GEOJSON must be set.') style = params.get('STYLE') if not style: raise ParameterError('Parameter STYLE must be set.') try: width = int(params.get('WIDTH')) except TypeError: raise ParameterError('Parameter WIDTH must be integer.') try: height = int(params.get('HEIGHT')) except TypeError: raise ParameterError('Parameter HEIGHT must be integer.') try: dpi = int(params.get('DPI', 96)) except TypeError: raise ParameterError('Parameter DPI must be integer.') try: minx, miny, maxx, maxy = params.get('BBOX').split(',') bbox = QgsRectangle(float(minx), float(miny), float(maxx), float(maxy)) except (ValueError, AttributeError): raise ParameterError( 'Parameter BBOX must be specified in the form `min_x,min_y,max_x,max_y`.' ) url = geojson geojson_file_name = self._resolve_url(geojson) if '$type' in style: polygon_style = self._resolve_url( style.replace('$type', 'polygons')) line_style = self._resolve_url( style.replace('$type', 'lines')) point_style = self._resolve_url( style.replace('$type', 'points')) else: polygon_style = self._resolve_url(style) line_style = polygon_style point_style = polygon_style polygon_layer = QgsVectorLayer( geojson_file_name + '|geometrytype=Polygon', 'polygons', 'ogr') self._load_style(polygon_layer, polygon_style) line_layer = QgsVectorLayer( geojson_file_name + '|geometrytype=Line', 'lines', 'ogr') self._load_style(line_layer, line_style) point_layer = QgsVectorLayer( geojson_file_name + '|geometrytype=Point', 'points', 'ogr') self._load_style(point_layer, point_style) settings = QgsMapSettings() settings.setOutputSize(QSize(width, height)) settings.setOutputDpi(dpi) settings.setExtent(bbox) settings.setLayers([polygon_layer, line_layer, point_layer]) settings.setBackgroundColor(QColor(Qt.transparent)) renderer = QgsMapRendererParallelJob(settings) event_loop = QEventLoop() renderer.finished.connect(event_loop.quit) renderer.start() event_loop.exec_() img = renderer.renderedImage() img.setDotsPerMeterX(dpi * 39.37) img.setDotsPerMeterY(dpi * 39.37) image_data = QByteArray() buf = QBuffer(image_data) buf.open(QIODevice.WriteOnly) img.save(buf, 'PNG') request.setResponseHeader('Content-type', 'image/png') request.appendBody(image_data) except ParameterError as e: QgsMessageLog.logMessage( "RenderGeojson.responseComplete :: ParameterError") request.setResponseHeader('Content-type', 'text/plain') request.appendBody(str(e).encode('utf-8')) except: QgsMessageLog.logMessage( "RenderGeojson.responseComplete :: Exception") QgsMessageLog.logMessage( "RenderGeojson.responseComplete :: {}".format( traceback.format_exc())) request.setResponseHeader('Content-type', 'text/plain') request.appendBody(b'Unhandled error') request.appendBody(traceback.format_exc().encode('utf-8'))
class TestSelectiveMasking(unittest.TestCase): def setUp(self): self.checker = QgsRenderChecker() self.checker.setControlPathPrefix("selective_masking") self.report = "<h1>Python Selective Masking Tests</h1>\n" self.map_settings = QgsMapSettings() crs = QgsCoordinateReferenceSystem('epsg:4326') extent = QgsRectangle(-123.0, 22.7, -76.4, 46.9) self.map_settings.setBackgroundColor(QColor(152, 219, 249)) self.map_settings.setOutputSize(QSize(420, 280)) self.map_settings.setOutputDpi(72) self.map_settings.setFlag(QgsMapSettings.Antialiasing, True) self.map_settings.setFlag(QgsMapSettings.UseAdvancedEffects, False) self.map_settings.setDestinationCrs(crs) self.map_settings.setExtent(extent) # load a predefined QGIS project self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking.qgs"))) self.points_layer = QgsProject.instance().mapLayersByName('points')[0] self.lines_layer = QgsProject.instance().mapLayersByName('lines')[0] # line layer with subsymbols self.lines_layer2 = QgsProject.instance().mapLayersByName('lines2')[0] # line layer with labels self.lines_with_labels = QgsProject.instance().mapLayersByName('lines_with_labels')[0] self.polys_layer = QgsProject.instance().mapLayersByName('polys')[0] # polygon layer with a rule based labeling self.polys_layer2 = QgsProject.instance().mapLayersByName('polys2')[0] self.raster_layer = QgsProject.instance().mapLayersByName('raster_layer')[0] # try to fix the font for where labels are defined # in order to have more stable image comparison tests for layer in [self.polys_layer, self.lines_with_labels, self.polys_layer2]: for provider in layer.labeling().subProviders(): settings = layer.labeling().settings(provider) font = getTestFont() font.setPointSize(32) fmt = settings.format() fmt.setFont(font) fmt.setNamedStyle('Roman') fmt.setSize(32) fmt.setSizeUnit(QgsUnitTypes.RenderPoints) settings.setFormat(fmt) if (layer.geometryType == QgsWkbTypes.PolygonGeometry): settings.placement = QgsPalLayerSettings.OverPoint layer.labeling().setSettings(settings, provider) # order layers for rendering self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def tearDown(self): report_file_path = "%s/qgistest.html" % QDir.tempPath() with open(report_file_path, 'a') as report_file: report_file.write(self.report) def check_renderings(self, map_settings, control_name): """Test a rendering with different configurations: - parallel rendering, no cache - sequential rendering, no cache - parallel rendering, with cache (rendered two times) - sequential rendering, with cache (rendered two times) """ for do_parallel in [False, True]: for use_cache in [False, True]: print("=== parallel", do_parallel, "cache", use_cache) tmp = getTempfilePath('png') cache = None if use_cache: cache = QgsMapRendererCache() # render a first time to fill the cache renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img, t = renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img.save(tmp) print("Image rendered in {}".format(tmp)) self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) suffix = "_parallel" if do_parallel else "_sequential" res = self.checker.compareImages(control_name + suffix) self.report += self.checker.report() self.assertTrue(res) print("=== Rendering took {}s".format(float(t) / 1000.0)) def test_save_restore_references(self): """ Test saving and restoring symbol layer references """ # simple ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) # complex ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) # complex ids, v2 mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) def test_label_mask(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask") def test_multiple_label_masks_different_sets(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # polygons QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_different_sets") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_multiple_label_masks_same_set(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_same_set") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_subsymbol(self): # new map settings with a line symbology that has sub symbols self.map_settings.setLayers([self.points_layer, self.lines_layer2, self.polys_layer]) # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # mask only vertical segments of "roads" QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0])), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_subsymbol") # restore original map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_dd(self): """ test label mask with data defined properties """ label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() fmt.mask().setEnabled(False) fmt.mask().setSize(1.0) fmt.mask().setOpacity(0.42) # mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # overwrite with data-defined properties fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskEnabled, QgsProperty.fromExpression('1')) fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskBufferSize, QgsProperty.fromExpression('4.0')) fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskOpacity, QgsProperty.fromExpression('100.0')) context = QgsRenderContext() fmt.updateDataDefinedProperties(context) self.assertEqual(fmt.mask().enabled(), True) self.assertEqual(fmt.mask().size(), 4.0) self.assertEqual(fmt.mask().opacity(), 1.0) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "label_mask") def test_label_mask_rule_labeling(self): # new map settings with a rule based labeling self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer2]) # modify labeling settings of one rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() == 'Tadam': break label_settings = child.settings() label_settings.priority = 3 fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) child.setSettings(label_settings) # modify labeling settings of another rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() != 'Tadam': break label_settings = child.settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the polygons QgsSymbolLayerReference(self.polys_layer2.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) child.setSettings(label_settings) self.check_renderings(self.map_settings, "rule_label_mask") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_symbol_levels(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # enable symbol levels self.lines_layer.renderer().setUsingSymbolLevels(True) self.check_renderings(self.map_settings, "label_mask_symbol_levels") def test_symbol_layer_mask(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "sl_mask") def test_multiple_masks_same_symbol_layer(self): """Test multiple masks that occlude the same symbol layer""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_same_sl") def test_multiple_masks_different_symbol_layers_same_layer(self): """Test multiple masks that occlude different symbol layers of the same layer. The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl") def test_multiple_masks_different_symbol_layers_same_layer2(self): """Test multiple masks that occlude different symbol layers of the same layer - 2nd possible order The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl2") def test_mask_symbollayer_preview(self): # # Masks should be visible in previews # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) p.insertSymbolLayer(0, mask_layer) for control_name, render_function in [ ("as_image", lambda: p.asImage(QSize(64, 64)).save(tmp)), ("as_big_preview", lambda: p.bigSymbolPreviewImage().save(tmp)), ("sl_preview", lambda: QgsSymbolLayerUtils.symbolLayerPreviewIcon(mask_layer, QgsUnitTypes.RenderPixels, QSize(64, 64)).pixmap(QSize(64, 64)).save(tmp)) ]: tmp = getTempfilePath('png') render_function() self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name, 90) self.report += self.checker.report() self.assertTrue(res) def test_mask_with_effect(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '12'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add an outer glow effect to the mask layer blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) mask_layer.setPaintEffect(blur) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "mask_with_effect") def test_label_mask_with_effect(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_with_effect") def test_layout_exports(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) 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([self.points_layer, self.lines_layer, self.polys_layer]) image = QImage(591, 591, QImage.Format_RGB32) image.setDotsPerMeterX(int(300 / 25.3 * 1000)) image.setDotsPerMeterY(int(300 / 25.3 * 1000)) image.fill(0) p = QPainter(image) exporter = QgsLayoutExporter(layout) exporter.renderPage(p, 0) p.end() tmp = getTempfilePath('png') image.save(tmp) control_name = "layout_export" self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res) def test_different_dpi_target(self): """Test with raster layer and a target dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.map_settings.setLayers([self.lines_layer, self.polys_layer, self.raster_layer]) self.map_settings.setDpiTarget(300) self.check_renderings(self.map_settings, "different_dpi_target")
print('crs authid: %s' % layer.crs().authid()) print('extent: %s' % layer.sourceExtent().toString()) QgsProject.instance().addMapLayer(layer) image = QImage(QSize(600, 400), QImage.Format_ARGB32_Premultiplied) image.fill(QColor(255, 255, 128).rgb()) painter = QPainter(image) settings = QgsMapSettings() settings.setOutputDpi(image.logicalDpiX()) settings.setOutputImageFormat(QImage.Format_ARGB32) settings.setDestinationCrs(layer.crs()) settings.setOutputSize(image.size()) settings.setFlag(QgsMapSettings.Antialiasing, True) settings.setFlag(QgsMapSettings.RenderMapTile, True) settings.setFlag(QgsMapSettings.UseAdvancedEffects, True) settings.setBackgroundColor(QColor(255, 255, 255, 0)) settings.setLayers([layer]) settings.setExtent(layer.extent()) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() output_path = os.environ.get('QGIS_DJANGO_PROVIDER_TEST_OUTPUT', '/tmp/qgis-django-provider-test.png') image.save(output_path, 'png')
def renderer(self): qgis = QgsApplication([], False) qgis.setPrefixPath(self.settings.get('path'), True) qgis.setMaxThreads(1) qgis.initQgis() while True: try: fndata, srs, render_size, extended, \ target_box, result = self.queue.get() layer = QgsVectorLayer(fndata, 'layer', 'ogr') crs = QgsCoordinateReferenceSystem(srs.id) layer.setCrs(crs) settings = QgsMapSettings() settings.setLayers([layer.id()]) settings.setFlag(QgsMapSettings.DrawLabeling) settings.setFlag(QgsMapSettings.Antialiasing) settings.setCrsTransformEnabled(True) settings.setDestinationCrs(crs) settings.setMapUnits(crs.mapUnits()) settings.setOutputSize(QSize(*render_size)) settings.setExtent(QgsRectangle(*extended)) settings.setOutputImageFormat(QImage.Format_ARGB32) bgcolor = QColor.fromRgba(qRgba(255, 255, 255, 0)) settings.setBackgroundColor(bgcolor) settings.setOutputDpi(96) QgsMapLayerRegistry.instance().addMapLayer(layer) settings.setLayers([layer.id()]) # Создаем QImage руками чтобы можно было использовать # QgsMapRendererCustomPainterJob. Остальные не позволяют # обойти баг с рисованием поверх старого. img = QImage(settings.outputSize(), QImage.Format_ARGB32) # Эти костыли нужны для того, чтобы корректно рисовались # слои на прозрачном фоне, без этого получается каша. img.fill(QColor.fromRgba(qRgba(255, 255, 255, 255))) img.fill(QColor.fromRgba(qRgba(255, 255, 255, 0))) # DPI должно быть таким же как в settings, иначе ошибка. В QImage # разрешение указывается в точках на метр по каждой оси. dpm = settings.outputDpi() / 25.4 * 1000 img.setDotsPerMeterX(dpm) img.setDotsPerMeterY(dpm) painter = QPainter(img) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() QgsMapLayerRegistry.instance().removeAllMapLayers() # Преобразование QImage в PIL ba = QByteArray() bf = QBuffer(ba) bf.open(QIODevice.WriteOnly) img.save(bf, 'PNG') bf.close() buf = StringIO() buf.write(bf.data()) buf.seek(0) img = PIL.Image.open(buf) # Вырезаем нужный нам кусок изображения result.put(img.crop(target_box)) except Exception as e: self.logger.error(e.message) qgis.exitQgis()
def GDX_Publisher(self): # print ("GDX_Publisher -------------------------------\n") tumpdir = unicode( QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() ) + "/python/plugins/gearthview3/_WebServer" # print (tumpdir) adesso = str(datetime.datetime.now()) adesso = adesso.replace(" ", "_") adesso = adesso.replace(":", "_") adesso = adesso.replace(".", "_") # print ("adesso: <%s>\n" %(adesso)) # HERE IT DELETES THE OLD IMAGE ------------------------------------ # (if you comment these, images still remain ... :) for filename in glob.glob(str(tumpdir + '/*.png')): os.remove(str(filename)) for filename in glob.glob(str(tumpdir + '/*.pngw')): os.remove(str(filename)) # ------------------------------------------------------------------ mapCanvas = self.iface.mapCanvas() text = mapCanvas.extent().toString() text1 = text.replace(",", " ") text2 = text1.replace(" : ", ",") # print ("extent: <%s>\n" %(text2)) layer = mapCanvas.currentLayer() # print ("Layer: <%s>\n" %(layer.name() )) extent = mapCanvas.extent() crsSrc = mapCanvas.mapSettings().destinationCrs() crsDest = QgsCoordinateReferenceSystem(4326) try: transform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance()) except: transform = QgsCoordinateTransform(crsSrc, crsDest) projectedExtent = transform.transformBoundingBox(extent) x1 = projectedExtent.xMinimum() y1 = projectedExtent.yMinimum() x2 = projectedExtent.xMaximum() y2 = projectedExtent.yMinimum() x3 = projectedExtent.xMaximum() y3 = projectedExtent.yMaximum() x4 = projectedExtent.xMinimum() y4 = projectedExtent.yMaximum() xc = (x1 + x3) / 2. yc = (y1 + y3) / 2. out_folder = tumpdir # create output image and initialize it mapRect = mapCanvas.extent() width = mapCanvas.width() height = mapCanvas.height() srs = mapCanvas.mapSettings().destinationCrs() # print (width, height) # MINORU # canvas = mapCanvas ## image = QImage(size.width(), size.height(), QImage.Format_ARGB32_Premultiplied) # image = QImage(QSize(math.ceil(width), math.ceil(height)), QImage.Format_ARGB32) # image.fill(Qt.transparent) ## image.fill(QColor(0)) # painter = QPainter() # painter.setRenderHint(QPainter.Antialiasing, True) # painter.setRenderHint(QPainter.TextAntialiasing, True) # painter.setRenderHint(QPainter.SmoothPixmapTransform, True) ## painter.setRenderHint(QPainter.transparent, True) # ## brush = QtGui.QBrush() ## brush.setColor(QtGui.QColor(0)) ## painter.setBackground(self, 0) # # painter.begin(image) # canvas.render(painter) # painter.end() # MINORU # MINORU2 # settings = self.exportSettings.mapSettings settings = QgsMapSettings() # extent = settings.extent() extent = mapCanvas.extent() # store old map settings # old_outputSize = settings.outputSize() # old_extent = settings.extent() # old_rotation = settings.rotation() # old_layers = settings.layers() # old_backgroundColor = settings.backgroundColor() # map settings settings.setOutputSize(QSize(width, height)) # settings.setExtent(extent.unrotatedRect()) # settings.setRotation(extent.rotation()) # if layerids: # settings.setLayers(tools.getLayersByLayerIds(layerids)) # if transp_background: settings.setBackgroundColor(QColor(Qt.transparent)) has_pluginlayer = False for layer in settings.layers(): if layer and layer.type() == QgsMapLayer.PluginLayer: has_pluginlayer = True break # create an image image = QImage(width, height, QImage.Format_ARGB32_Premultiplied) painter = QPainter() painter.begin(image) # if antialias: # painter.setRenderHint(QPainter.Antialiasing) # rendering job = QgsMapRendererCustomPainterJob(settings, painter) if has_pluginlayer: job.renderSynchronously( ) # use this method so that TileLayerPlugin layer is rendered correctly else: job.start() job.waitForFinished() painter.end() # restore map settings # settings.setOutputSize(old_outputSize) # settings.setExtent(old_extent) # settings.setRotation(old_rotation) # settings.setLayers(old_layers) # settings.setBackgroundColor(old_backgroundColor) # MINORU2 kml = codecs.open(out_folder + '/doc.kml', 'w', encoding='utf-8') kml.write('<?xml version="1.0" encoding="UTF-8"?>\n') kml.write( '<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">\n' ) kml.write(' <Document>\n') kml.write(' <name>QGisView</name>\n') kml.write(' <Snippet maxLines="0"></Snippet>\n') # loc = (" <description><![CDATA[https://map.what3words.com/%.7lf,%.7lf]]></description>\n") %(yc, xc) # kml.write(loc) kml.write(' <open>1</open>\n') kml.write(' <Style id="sh_style">\n') kml.write(' <PolyStyle>\n') kml.write(' <color>7fff8080</color>\n') kml.write(' </PolyStyle>\n') kml.write(' </Style>\n') kml.write(' <StyleMap id="msn_style">\n') kml.write(' <Pair>\n') kml.write(' <key>normal</key>\n') kml.write(' <styleUrl>#sn_style</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' <Pair>\n') kml.write(' <key>highlight</key>\n') kml.write(' <styleUrl>#sh_style</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' </StyleMap>\n') kml.write(' <Style id="sn_style">\n') kml.write(' <PolyStyle>\n') kml.write(' <color>00ff8080</color>\n') kml.write(' <fill>0</fill>\n') kml.write(' </PolyStyle>\n') kml.write(' </Style>\n') kml.write(' <Style id="sh_ylw-pushpin">\n') kml.write(' <IconStyle>\n') kml.write(' <scale>1.2</scale>\n') kml.write(' </IconStyle>\n') kml.write(' <PolyStyle>\n') kml.write(' <fill>0</fill>\n') kml.write(' </PolyStyle>\n') kml.write(' </Style>\n') kml.write(' <Style id="sn_ylw-pushpin">\n') kml.write(' <PolyStyle>\n') kml.write(' <fill>0</fill>\n') kml.write(' </PolyStyle>\n') kml.write(' </Style>\n') kml.write(' <StyleMap id="msn_ylw-pushpin">\n') kml.write(' <Pair>\n') kml.write(' <key>normal</key>\n') kml.write(' <styleUrl>#sn_ylw-pushpin</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' <Pair>\n') kml.write(' <key>highlight</key>\n') kml.write(' <styleUrl>#sh_ylw-pushpin</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' </StyleMap>\n') kml.write(' <StyleMap id="msn_style">\n') kml.write(' <Pair>\n') kml.write(' <key>normal</key>\n') kml.write(' <styleUrl>#sn_style</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' <Pair>\n') kml.write(' <key>highlight</key>\n') kml.write(' <styleUrl>#sh_style</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' </StyleMap>\n') kml.write(' <Style id="hl">\n') kml.write(' <IconStyle>\n') kml.write(' <scale>0.7</scale>\n') kml.write(' <Icon>\n') kml.write( ' <href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle_highlight.png</href>\n' ) kml.write(' </Icon>\n') kml.write(' </IconStyle>\n') kml.write(' <LabelStyle>\n') kml.write(' <scale>0.7</scale>\n') kml.write(' </LabelStyle>\n') kml.write(' <ListStyle>\n') kml.write(' </ListStyle>\n') kml.write(' </Style>\n') kml.write(' <Style id="default">\n') kml.write(' <IconStyle>\n') kml.write(' <scale>0.7</scale>\n') kml.write(' <Icon>\n') kml.write( ' <href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>\n' ) kml.write(' </Icon>\n') kml.write(' </IconStyle>\n') kml.write(' <LabelStyle>\n') kml.write(' <scale>0.7</scale>\n') kml.write(' </LabelStyle>\n') kml.write(' <ListStyle>\n') kml.write(' </ListStyle>\n') kml.write(' </Style>\n') kml.write(' <StyleMap id="default0">\n') kml.write(' <Pair>\n') kml.write(' <key>normal</key>\n') kml.write(' <styleUrl>#default</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' <Pair>\n') kml.write(' <key>highlight</key>\n') kml.write(' <styleUrl>#hl</styleUrl>\n') kml.write(' </Pair>\n') kml.write(' </StyleMap>\n') rotazio = 0.0 rotazio = -(mapCanvas.rotation()) kml.write(' <Folder>\n') xc = (x1 + x3) / 2. yc = (y1 + y3) / 2. dx = (x3 - x1) * 75000. #100000. kml.write(' <open>1</open>\n') kml.write(' <NetworkLink>\n') kml.write(' <name>QGIS_link</name>\n') kml.write(' <visibility>1</visibility>\n') kml.write(' <open>1</open>\n') kml.write(' <Link>\n') kml.write(' <href>QGIS_link.kmz</href>\n') kml.write(' </Link>\n') kml.write(' </NetworkLink>\n') kml.write(' <LookAt>\n') stringazza = (" <longitude>%lf</longitude>\n") % (xc) kml.write(stringazza) stringazza = (" <latitude>%lf</latitude>\n") % (yc) kml.write(stringazza) kml.write(' <altitude>0</altitude>\n') stringazza = (" <heading>%lf</heading>\n") % (rotazio) kml.write(stringazza) kml.write(' <tilt>0</tilt>\n') stringazza = (" <range>%lf</range>\n") % (dx) kml.write(stringazza) kml.write(' <gx:altitudeMode>relativeToGround</gx:altitudeMode>\n') kml.write(' </LookAt>\n') kml.write(' <GroundOverlay>\n') kml.write(' <name>QGisView</name>\n') kml.write(' <Icon>\n') xN = projectedExtent.xMinimum() yN = projectedExtent.yMinimum() nomePNG = ("QGisView_%lf_%lf_%s") % (xN, yN, adesso) stringazza = (" <href>%s.png</href>\n") % (nomePNG) kml.write(stringazza) kml.write(' <viewBoundScale>1.0</viewBoundScale>\n') kml.write(' </Icon>\n') kml.write(' <gx:LatLonQuad>\n') kml.write(' <coordinates>\n') stringazza = ("%.7lf,%.7lf,0 %.7lf,%.7lf,0 %.7lf,%.7lf,0 %.7lf,%.7lf,0\n" ) % (x1, y1, x2, y2, x3, y3, x4, y4) kml.write(stringazza) kml.write(' </coordinates>\n') kml.write(' </gx:LatLonQuad>\n') kml.write(' </GroundOverlay>\n') #Export tfw-file xScale = (projectedExtent.xMaximum() - projectedExtent.xMinimum()) / image.width() yScale = (projectedExtent.yMaximum() - projectedExtent.yMinimum()) / image.height() f = open(out_folder + "/" + nomePNG + ".pngw", 'w') f.write(str(xScale) + '\n') f.write(str(0) + '\n') f.write(str(0) + '\n') f.write('-' + str(yScale) + '\n') f.write(str(projectedExtent.xMinimum()) + '\n') f.write(str(projectedExtent.yMaximum()) + '\n') f.write(str(projectedExtent.xMaximum()) + '\n') f.write(str(projectedExtent.yMinimum())) f.close() input_file = out_folder + "/" + nomePNG + ".png" #Save the image image.save(input_file, "png") nomeLay = "gearthview" # foo default name # Adesso scrivo il vettoriale # Prendo il sistema di riferimento del Layer selezionato ------------------ curLayer = mapCanvas.currentLayer() iface = qgis.utils.iface selectedLayers = iface.layerTreeView().selectedLayers() if (not selectedLayers): # print ("selectedLayers is Empty") selectedLayers = [] selectedLayers.append(curLayer) for layer in selectedLayers: if layer: if layer.type() == layer.VectorLayer: name = layer.source() nomeLayer = layer.name() nomeLay = nomeLayer.replace(" ", "_") # print(layer.name()) kml.write(' <Folder>\n') stringazza = (' <name>%s</name>\n') % (nomeLay) kml.write(stringazza) crsSrc = layer.crs() crsDest = QgsCoordinateReferenceSystem(4326) # Wgs84LLH xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance()) #---------------------------------------------------------------------------- # Trasformo la finestra video in coordinate layer, # per estrarre solo gli elementi visibili #---------------------------------------------------------------------------- # mapCanvas = iface.mapCanvas() boundBox = mapCanvas.extent() xMin = float(boundBox.xMinimum()) yMin = float(boundBox.yMinimum()) xMax = float(boundBox.xMaximum()) yMax = float(boundBox.yMaximum()) crs2 = mapCanvas.mapSettings().destinationCrs() crsSrc2 = QgsCoordinateReferenceSystem(crs2.authid()) crsDest2 = QgsCoordinateReferenceSystem(layer.crs()) xform2 = QgsCoordinateTransform(crsSrc2, crsDest2, QgsProject.instance()) pt0 = xform2.transform(QgsPointXY(xMin, yMin)) pt1 = xform2.transform(QgsPointXY(xMax, yMax)) rect = QgsRectangle(pt0, pt1) # print ("pt0x: <%s>" %(str(pt0.x())) ) # print ("pt0y: <%s>" %(str(pt0.y())) ) # print ("pt1x: <%s>" %(str(pt1.x())) ) # print ("pt1y: <%s>" %(str(pt1.y())) ) rq = QgsFeatureRequest(rect) iter = layer.getFeatures(rq) for feat in iter: nele = feat.id() # fetch geometry geom = feat.geometry() # show some information about the feature # print (("GeomType: %d") %(geom.type())) if geom.type() == 0: elem = geom.asPoint() x1 = elem.x() y1 = elem.y() # pt1 = xform.transform(QgsPoint(x1, y1)) kml.write(' <Placemark>\n') stringazza = (' <name>%s</name>\n') % (nele) kml.write(stringazza) kml.write(' <styleUrl>#default0</styleUrl>\n') # DESCRIPTION DATA----------- kml.write(' <Snippet maxLines="0"></Snippet>\n') kml.write(' <description><![CDATA[\n') kml.write('<html><body><table border="1">\n') kml.write( '<tr><th>Field Name</th><th>Field Value</th></tr>\n' ) # Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ('<tr><td>%s</td><td>%s</td></tr>\n' ) % (f.name(), feat[iii]) kml.write(stringazza) kml.write('</table></body></html>\n') kml.write(']]></description>\n') # EXTENDED DATA ------------- stringazza = ( ' <ExtendedData><SchemaData schemaUrl="#%s">\n' ) % (nomeLay) kml.write(stringazza) ## Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ( ' <SimpleData name="%s">%s</SimpleData>\n' ) % (f.name(), feat[iii]) if (stringazza.find('<SimpleData name="descrip') == -1): kml.write(stringazza) kml.write(' </SchemaData></ExtendedData>\n') # EXTENDED DATA ------------- wkt = layer.crs().toWkt() source = osr.SpatialReference() source.ImportFromWkt(wkt) target = osr.SpatialReference() target.ImportFromEPSG(4326) transform = osr.CoordinateTransformation( source, target) testo = geom.asWkt() # print (testo) testo = testo.replace("PointZ (", "Point (") testo = testo.replace("PointZM (", "Point (") testo = testo.replace(" 0,", ",") testo = testo.replace(" 0)", ")") geometra = ogr.CreateGeometryFromWkt(testo) geometra.Transform(transform) testoKML = geometra.ExportToKML() kml.write(testoKML) kml.write(' </Placemark>\n') elif geom.type() == 1: elem = geom.asPolyline() kml.write(' <Placemark>\n') stringazza = (' <name>%s</name>\n') % (nele) kml.write(stringazza) kml.write(' <styleUrl>#default0</styleUrl>\n') # DESCRIPTION DATA----------- kml.write(' <Snippet maxLines="0"></Snippet>\n') kml.write(' <description><![CDATA[\n') kml.write('<html><body><table border="1">\n') kml.write( '<tr><th>Field Name</th><th>Field Value</th></tr>\n' ) # Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ('<tr><td>%s</td><td>%s</td></tr>\n' ) % (f.name(), feat[iii]) kml.write(stringazza) kml.write('</table></body></html>\n') kml.write(']]></description>\n') # EXTENDED DATA ------------- stringazza = ( ' <ExtendedData><SchemaData schemaUrl="#%s">\n' ) % (nomeLay) kml.write(stringazza) ## Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ( ' <SimpleData name="%s">%s</SimpleData>\n' ) % (f.name(), feat[iii]) if (stringazza.find('<SimpleData name="descrip') == -1): kml.write(stringazza) kml.write(' </SchemaData></ExtendedData>\n') # EXTENDED DATA ------------- wkt = layer.crs().toWkt() source = osr.SpatialReference() source.ImportFromWkt(wkt) target = osr.SpatialReference() target.ImportFromEPSG(4326) transform = osr.CoordinateTransformation( source, target) testo = geom.asWkt() # print (testo) testo = testo.replace("LineStringZ (", "LineString (") testo = testo.replace("LineStringZM (", "LineString (") testo = testo.replace(" 0,", ",") testo = testo.replace(" 0)", ")") geometra = ogr.CreateGeometryFromWkt(testo) geometra.Transform(transform) testoKML = geometra.ExportToKML() kml.write(testoKML) kml.write(' </Placemark>\n') elif geom.type() == 2: kml.write(' <Placemark>\n') stringazza = (' <name>%s</name>\n') % (nele) kml.write(stringazza) kml.write(' <styleUrl>#msn_style</styleUrl>\n') # DESCRIPTION DATA----------- kml.write(' <Snippet maxLines="0"></Snippet>\n') kml.write(' <description><![CDATA[\n') kml.write('<html><body><table border="1">\n') kml.write( '<tr><th>Field Name</th><th>Field Value</th></tr>\n' ) # Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ('<tr><td>%s</td><td>%s</td></tr>\n' ) % (f.name(), feat[iii]) kml.write(stringazza) kml.write('</table></body></html>\n') kml.write(']]></description>\n') # EXTENDED DATA ------------- stringazza = ( ' <ExtendedData><SchemaData schemaUrl="#%s">\n' ) % (nomeLay) kml.write(stringazza) ## Prendo il contenuto dei campi ------------- fff = feat.fields() num = fff.count() iii = -1 for f in layer.fields(): iii = iii + 1 stringazza = ( ' <SimpleData name="%s">%s</SimpleData>\n' ) % (f.name(), feat[iii]) if (stringazza.find('<SimpleData name="descrip') == -1): kml.write(stringazza) kml.write(' </SchemaData></ExtendedData>\n') # EXTENDED DATA ------------- testo = geom.asWkt() # print (testo) wkt = layer.crs().toWkt() source = osr.SpatialReference() source.ImportFromWkt(wkt) target = osr.SpatialReference() target.ImportFromEPSG(4326) transform = osr.CoordinateTransformation( source, target) testo = testo.replace("PolygonZ (", "Polygon (") testo = testo.replace("PolygonZM (", "Polygon (") testo = testo.replace(" 0,", ",") testo = testo.replace(" 0)", ")") geometra = ogr.CreateGeometryFromWkt(testo) geometra.Transform(transform) testoKML = geometra.ExportToKML() testoKML = testoKML.replace( "<Polygon>", "<Polygon><altitudeMode>relativeToGround</altitudeMode>" ) kml.write(testoKML) kml.write(' </Placemark>\n') kml.write(' </Folder>\n') kml.write('</Folder>\n') kml.write('</Document>\n') kml.write('</kml>\n') kml.close() if platform.system() == "Windows": os.startfile(out_folder + '/doc.kml') if platform.system() == "Darwin": os.system("open " + str(out_folder + '/doc.kml')) if platform.system() == "Linux": os.system("xdg-open " + str(out_folder + '/doc.kml'))
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException(self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException(self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results
def render(self, params): self.check_required_params(params) with change_directory(self.project_root): crs = QgsCoordinateReferenceSystem() crs.createFromSrid(params.get('srs')) img = QImage( QSize(*params.get('image_size')), QImage.Format_ARGB32_Premultiplied ) dpm = 1 / 0.00028 img.setDotsPerMeterX(dpm) img.setDotsPerMeterY(dpm) # set background color bgcolor = params.get('bgcolor') if params.get('transparent'): # fully transparent bgcolor.append(0) else: # fully opaque bgcolor.append(255) color = QColor(*bgcolor) img.fill(color) map_settings = QgsMapSettings() map_settings.setBackgroundColor(color) map_settings.setDestinationCrs(crs) map_settings.setCrsTransformEnabled(True) map_settings.setExtent(QgsRectangle(*params.get('bbox'))) map_settings.setOutputDpi(img.logicalDpiX()) map_settings.setOutputSize(img.size()) map_settings.setMapUnits(crs.mapUnits()) layers = params.get('layers') self.setTransparencies(layers, params.get('transparencies')) map_settings.setLayers(layers) p = QPainter() p.begin(img) job = QgsMapRendererCustomPainterJob(map_settings, p) job.start() job.waitForFinished() map_buffer = QBuffer() map_buffer.open(QIODevice.ReadWrite) if params.get('image_format') == 'jpeg': img.save(map_buffer, 'JPEG') elif params.get('image_format') == 'png8': png8 = img.convertToFormat(QImage.Format_Indexed8) png8.save(map_buffer, "PNG") else: img.save(map_buffer, 'PNG') # clean up p.end() map_buffer.close() return map_buffer.data()
def generate(self, writer, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) self.min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) self.max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) self.tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if self.tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) self.wgs_extent = src_to_wgs.transformBoundingBox(extent) self.wgs_extent = [self.wgs_extent.xMinimum(), self.wgs_extent.yMinimum(), self.wgs_extent.xMaximum(), self.wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(self.min_zoom, self.max_zoom + 1): metatiles = get_metatiles(self.wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': self.tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height, 'min_zoom': self.min_zoom, 'max_zoom': self.max_zoom, 'extent': self.wgs_extent, } writer.set_parameters(tile_params) for zoom in range(self.min_zoom, self.max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): if feedback.isCanceled(): break size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) if hasattr(settings, 'setLabelBoundaryGeometry'): label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.write_tile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close()
class TestQgsBlendModes(unittest.TestCase): def __init__(self, methodName): """Run once on class initialization.""" unittest.TestCase.__init__(self, methodName) self.iface = get_iface() # initialize class MapRegistry, Canvas, MapRenderer, Map and PAL self.mMapRegistry = QgsProject.instance() # create point layer myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') self.mPointLayer = QgsVectorLayer(myShpFile, 'Points', 'ogr') self.mMapRegistry.addMapLayer(self.mPointLayer) self.mSimplifyMethod = QgsVectorSimplifyMethod() self.mSimplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod.NoSimplification) # create polygon layer myShpFile = os.path.join(TEST_DATA_DIR, 'polys.shp') self.mPolygonLayer = QgsVectorLayer(myShpFile, 'Polygons', 'ogr') self.mPolygonLayer.setSimplifyMethod(self.mSimplifyMethod) self.mMapRegistry.addMapLayer(self.mPolygonLayer) # create line layer myShpFile = os.path.join(TEST_DATA_DIR, 'lines.shp') self.mLineLayer = QgsVectorLayer(myShpFile, 'Lines', 'ogr') self.mLineLayer.setSimplifyMethod(self.mSimplifyMethod) self.mMapRegistry.addMapLayer(self.mLineLayer) # create two raster layers myRasterFile = os.path.join(TEST_DATA_DIR, 'rgb256x256.png') self.mRasterLayer1 = QgsRasterLayer(myRasterFile, "raster1") self.mRasterLayer2 = QgsRasterLayer(myRasterFile, "raster2") myMultiBandRenderer1 = QgsMultiBandColorRenderer( self.mRasterLayer1.dataProvider(), 1, 2, 3) self.mRasterLayer1.setRenderer(myMultiBandRenderer1) self.mMapRegistry.addMapLayer(self.mRasterLayer1) myMultiBandRenderer2 = QgsMultiBandColorRenderer( self.mRasterLayer2.dataProvider(), 1, 2, 3) self.mRasterLayer2.setRenderer(myMultiBandRenderer2) self.mMapRegistry.addMapLayer(self.mRasterLayer2) # to match blend modes test comparisons background self.mapSettings = QgsMapSettings() self.mapSettings.setLayers([self.mRasterLayer1, self.mRasterLayer2]) self.mapSettings.setBackgroundColor(QColor(152, 219, 249)) self.mapSettings.setOutputSize(QSize(400, 400)) self.mapSettings.setOutputDpi(96) self.extent = QgsRectangle(-118.8888888888887720, 22.8002070393376783, -83.3333333333331581, 46.8719806763287536) def testVectorBlending(self): """Test that blend modes work for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set blending modes for both layers self.mLineLayer.setBlendMode(QPainter.CompositionMode_Difference) self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Difference) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_blendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_blendmodes", 20) myMessage = ('vector blending failed') assert myResult, myMessage # Reset layers self.mLineLayer.setBlendMode(QPainter.CompositionMode_SourceOver) self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_SourceOver) def testVectorFeatureBlending(self): """Test that feature blend modes work for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set feature blending for line layer self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_Plus) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_featureblendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_featureblendmodes", 20) myMessage = ('vector feature blending failed') assert myResult, myMessage # Reset layers self.mLineLayer.setFeatureBlendMode( QPainter.CompositionMode_SourceOver) def testVectorLayerOpacity(self): """Test that layer opacity works for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set feature blending for line layer self.mLineLayer.setOpacity(0.5) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_layertransparency") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_layertransparency", 20) myMessage = ('vector layer transparency failed') assert myResult, myMessage def testRasterBlending(self): """Test that blend modes work for raster layers.""" # Add raster layers to map myLayers = [self.mRasterLayer1, self.mRasterLayer2] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.mRasterLayer1.extent()) # Set blending mode for top layer self.mRasterLayer1.setBlendMode(QPainter.CompositionMode_Difference) checker = QgsMultiRenderChecker() checker.setControlName("expected_raster_blendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) checker.setColorTolerance(1) myResult = checker.runTest("raster_blendmodes", 20) myMessage = ('raster blending failed') assert myResult, myMessage
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException(self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException(self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results
class TestQgsBlendModes(unittest.TestCase): def __init__(self, methodName): """Run once on class initialization.""" unittest.TestCase.__init__(self, methodName) self.iface = get_iface() # initialize class MapRegistry, Canvas, MapRenderer, Map and PAL self.mMapRegistry = QgsProject.instance() # create point layer myShpFile = os.path.join(TEST_DATA_DIR, 'points.shp') self.mPointLayer = QgsVectorLayer(myShpFile, 'Points', 'ogr') self.mMapRegistry.addMapLayer(self.mPointLayer) self.mSimplifyMethod = QgsVectorSimplifyMethod() self.mSimplifyMethod.setSimplifyHints(QgsVectorSimplifyMethod.NoSimplification) # create polygon layer myShpFile = os.path.join(TEST_DATA_DIR, 'polys.shp') self.mPolygonLayer = QgsVectorLayer(myShpFile, 'Polygons', 'ogr') self.mPolygonLayer.setSimplifyMethod(self.mSimplifyMethod) self.mMapRegistry.addMapLayer(self.mPolygonLayer) # create line layer myShpFile = os.path.join(TEST_DATA_DIR, 'lines.shp') self.mLineLayer = QgsVectorLayer(myShpFile, 'Lines', 'ogr') self.mLineLayer.setSimplifyMethod(self.mSimplifyMethod) self.mMapRegistry.addMapLayer(self.mLineLayer) # create two raster layers myRasterFile = os.path.join(TEST_DATA_DIR, 'rgb256x256.png') self.mRasterLayer1 = QgsRasterLayer(myRasterFile, "raster1") self.mRasterLayer2 = QgsRasterLayer(myRasterFile, "raster2") myMultiBandRenderer1 = QgsMultiBandColorRenderer(self.mRasterLayer1.dataProvider(), 1, 2, 3) self.mRasterLayer1.setRenderer(myMultiBandRenderer1) self.mMapRegistry.addMapLayer(self.mRasterLayer1) myMultiBandRenderer2 = QgsMultiBandColorRenderer(self.mRasterLayer2.dataProvider(), 1, 2, 3) self.mRasterLayer2.setRenderer(myMultiBandRenderer2) self.mMapRegistry.addMapLayer(self.mRasterLayer2) # to match blend modes test comparisons background self.mapSettings = QgsMapSettings() self.mapSettings.setLayers([self.mRasterLayer1, self.mRasterLayer2]) self.mapSettings.setBackgroundColor(QColor(152, 219, 249)) self.mapSettings.setOutputSize(QSize(400, 400)) self.mapSettings.setOutputDpi(96) self.extent = QgsRectangle(-118.8888888888887720, 22.8002070393376783, -83.3333333333331581, 46.8719806763287536) def testVectorBlending(self): """Test that blend modes work for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set blending modes for both layers self.mLineLayer.setBlendMode(QPainter.CompositionMode_Difference) self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Difference) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_blendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_blendmodes", 20) myMessage = ('vector blending failed') assert myResult, myMessage # Reset layers self.mLineLayer.setBlendMode(QPainter.CompositionMode_SourceOver) self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_SourceOver) def testVectorFeatureBlending(self): """Test that feature blend modes work for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set feature blending for line layer self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_Plus) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_featureblendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_featureblendmodes", 20) myMessage = ('vector feature blending failed') assert myResult, myMessage # Reset layers self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_SourceOver) def testVectorLayerTransparency(self): """Test that layer transparency works for vector layers.""" # Add vector layers to map myLayers = [self.mLineLayer, self.mPolygonLayer] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.extent) # Set feature blending for line layer self.mLineLayer.setLayerTransparency(50) checker = QgsMultiRenderChecker() checker.setControlName("expected_vector_layertransparency") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) myResult = checker.runTest("vector_layertransparency", 20) myMessage = ('vector layer transparency failed') assert myResult, myMessage def testRasterBlending(self): """Test that blend modes work for raster layers.""" # Add raster layers to map myLayers = [self.mRasterLayer1, self.mRasterLayer2] self.mapSettings.setLayers(myLayers) self.mapSettings.setExtent(self.mRasterLayer1.extent()) # Set blending mode for top layer self.mRasterLayer1.setBlendMode(QPainter.CompositionMode_Difference) checker = QgsMultiRenderChecker() checker.setControlName("expected_raster_blendmodes") checker.setMapSettings(self.mapSettings) checker.setColorTolerance(1) checker.setColorTolerance(1) myResult = checker.runTest("raster_blendmodes", 20) myMessage = ('raster blending failed') assert myResult, myMessage
def generate(self, writer, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) self.min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) self.max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) color = self.parameterAsColor(parameters, self.BACKGROUND_COLOR, context) self.tile_format = self.formats[self.parameterAsEnum( parameters, self.TILE_FORMAT, context)] quality = self.parameterAsInt(parameters, self.QUALITY, context) self.metatilesize = self.parameterAsInt(parameters, self.METATILESIZE, context) try: tile_width = self.parameterAsInt(parameters, self.TILE_WIDTH, context) tile_height = self.parameterAsInt(parameters, self.TILE_HEIGHT, context) except AttributeError: tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if self.tile_format == 'PNG': settings.setBackgroundColor(color) # disable partial labels (they would be cut at the edge of tiles) labeling_engine_settings = settings.labelingEngineSettings() labeling_engine_settings.setFlag( QgsLabelingEngineSettings.UsePartialCandidates, False) settings.setLabelingEngineSettings(labeling_engine_settings) self.wgs_extent = src_to_wgs.transformBoundingBox(extent) self.wgs_extent = [ self.wgs_extent.xMinimum(), self.wgs_extent.yMinimum(), self.wgs_extent.xMaximum(), self.wgs_extent.yMaximum() ] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(self.min_zoom, self.max_zoom + 1): metatiles = get_metatiles(self.wgs_extent, zoom, self.metatilesize) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': self.tile_format, 'quality': quality, 'width': tile_width, 'height': tile_height, 'min_zoom': self.min_zoom, 'max_zoom': self.max_zoom, 'extent': self.wgs_extent, } writer.set_parameters(tile_params) for zoom in range(self.min_zoom, self.max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): if feedback.isCanceled(): break size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(color) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.write_tile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close()