Exemplo n.º 1
2
    def test_AddPALToVectorLayer(self):
        """Check if we can set a label field, verify that PAL is assigned
            and that output is rendered correctly"""
        # TODO: add UTM PAL-specific shps, with 4326 as on-the-fly cross-check
#        setCanvasCrs(26913)

        myShpFile = os.path.join(TEST_DATA_DIR, 'lines.shp')
        myVectorLayer = QgsVectorLayer(myShpFile, 'Lines', 'ogr')

        self._MapRegistry.addMapLayer(myVectorLayer)

        myLayers = QStringList()
        myLayers.append(myVectorLayer.id())
        self._MapRenderer.setLayerSet(myLayers)
        self._MapRenderer.setExtent(myVectorLayer.extent())
        self._Canvas.zoomToFullExtent()

        # check layer labeling is PAL with customProperty access
        # should not be activated on layer load
        myPalSet = myVectorLayer.customProperty( "labeling" ).toString()
        myMessage = '\nExpected: Empty QString\nGot: %s' % (str(myPalSet))
        assert str(myPalSet) == '', myMessage

        # simulate clicking checkbox, setting label field and clicking apply
        self._testFont.setPointSize(20)
        myPalLyr = QgsPalLayerSettings()

        myPalLyr.enabled = True
        myPalLyr.fieldName = 'Name'
        myPalLyr.placement = QgsPalLayerSettings.Line
        myPalLyr.placementFlags = QgsPalLayerSettings.AboveLine
        myPalLyr.xQuadOffset = 0
        myPalLyr.yQuadOffset = 0
        myPalLyr.xOffset = 0
        myPalLyr.yOffset = 0
        myPalLyr.angleOffset = 0
        myPalLyr.centroidWhole = False
        myPalLyr.textFont = self._testFont
        myPalLyr.textNamedStyle = QString("Medium")
        myPalLyr.textColor = Qt.black
        myPalLyr.textTransp = 0
        myPalLyr.previewBkgrdColor = Qt.white
        myPalLyr.priority = 5
        myPalLyr.obstacle = True
        myPalLyr.dist = 0
        myPalLyr.scaleMin = 0
        myPalLyr.scaleMax = 0
        myPalLyr.bufferSize = 1
        myPalLyr.bufferColor = Qt.white
        myPalLyr.bufferTransp = 0
        myPalLyr.bufferNoFill = False
        myPalLyr.bufferJoinStyle = Qt.RoundJoin
        myPalLyr.formatNumbers = False
        myPalLyr.decimals = 3
        myPalLyr.plusSign = False
        myPalLyr.labelPerPart = False
        myPalLyr.displayAll = True
        myPalLyr.mergeLines = False
        myPalLyr.minFeatureSize = 0.0
        myPalLyr.vectorScaleFactor = 1.0
        myPalLyr.rasterCompressFactor = 1.0
        myPalLyr.addDirectionSymbol = False
        myPalLyr.upsidedownLabels = QgsPalLayerSettings.Upright
        myPalLyr.fontSizeInMapUnits = False
        myPalLyr.bufferSizeInMapUnits = False
        myPalLyr.labelOffsetInMapUnits = True
        myPalLyr.distInMapUnits = False
        myPalLyr.wrapChar = ""
        myPalLyr.preserveRotation = True

        myPalLyr.writeToLayer(myVectorLayer)

        # check layer labeling is PAL with customProperty access
        myPalSet = myVectorLayer.customProperty( "labeling" ).toString()
        myMessage = '\nExpected: pal\nGot: %s' % (str(myPalSet))
        assert str(myPalSet) == 'pal', myMessage

        # check layer labeling is PAL via engine interface
        myMessage = '\nCould not get whether PAL enabled from labelingEngine'
        assert self._PalEngine.willUseLayer(myVectorLayer), myMessage

        #
        myChecker = QgsRenderChecker()
        myChecker.setControlName("expected_pal_aboveLineLabeling")
        myChecker.setMapRenderer(self._MapRenderer)

        myResult = myChecker.runTest("pal_aboveLineLabeling_python");
        myMessage = ('\nVector layer \'above line\' label engine '
                     'rendering test failed')
        assert myResult, myMessage

        # compare against a straight rendering/save as from QgsMapCanvasMap
        # unnecessary? works a bit different than QgsRenderChecker, though
#        myImage = os.path.join(unicode(QDir.tempPath()),
#                               'render_pal_aboveLineLabeling.png')
#        self._Map.render()
#        self._Canvas.saveAsImage(myImage)
#        myChecker.setRenderedImage(myImage)
#        myResult = myChecker.compareImages("pal_aboveLineLabeling_python")
#        myMessage = ('\nVector layer \'above line\' label engine '
#                     'comparison to QgsMapCanvasMap.render() test failed')
#        assert myResult, myMessage

        self._MapRegistry.removeMapLayer(myVectorLayer.id())
Exemplo n.º 2
0
    def renderCheck(self, mismatch=0, colortol=0, imgpath='', grpprefix=''):
        """Check rendered map canvas or existing image against control image

        :mismatch: number of pixels different from control, and still valid
        :colortol: maximum difference for each color component including alpha
        :imgpath: existing image; if present, skips rendering canvas
        :grpprefix: compare test image/rendering against different test group
        """
        if not grpprefix:
            grpprefix = self._TestGroupPrefix
        ctl_path = self.controlImagePath(grpprefix)
        if not os.path.exists(ctl_path):
            raise OSError('Missing control image: {0}'.format(ctl_path))
        chk = QgsRenderChecker()
        chk.setControlPathPrefix('expected_' + grpprefix)
        chk.setControlName(self._Test)
        chk.setColorTolerance(colortol)
        ms = self._MapSettings  # class settings
        if self._TestMapSettings is not None:
            ms = self._TestMapSettings  # per test settings
        chk.setMapSettings(ms)
        # noinspection PyUnusedLocal
        res = False
        if imgpath:
            res = chk.compareImages(self._Test, mismatch, str(imgpath))
        else:
            res = chk.runTest(self._Test, mismatch)
        if PALREPORT and not res:  # don't report ok checks
            testname = self._TestGroup + ' . ' + self._Test
            PALREPORTS[testname] = str(chk.report().toLocal8Bit())
        msg = '\nRender check failed for "{0}"'.format(self._Test)
        return res, msg
Exemplo n.º 3
0
    def runTestForLayer(self, layer, testname):
        tempdir = tempfile.mkdtemp()

        layer = QgsVectorLayer(layer, 'Layer', 'ogr')
        QgsProject.instance().addMapLayer(layer)
        self.iface.mapCanvas().setExtent(layer.extent())

        geom = next(layer.getFeatures()).geometry()

        highlight = QgsHighlight(self.iface.mapCanvas(), geom, layer)
        color = QColor(Qt.red)
        highlight.setColor(color)
        highlight.setWidth(2)
        color.setAlpha(50)
        highlight.setFillColor(color)
        highlight.show()

        image = QImage(QSize(400, 400), QImage.Format_ARGB32)
        image.fill(Qt.white)
        painter = QPainter()
        painter.begin(image)
        self.iface.mapCanvas().render(painter)
        painter.end()
        control_image = os.path.join(tempdir, 'highlight_{}.png'.format(testname))
        image.save(control_image)
        checker = QgsRenderChecker()
        checker.setControlPathPrefix("highlight")
        checker.setControlName("expected_highlight_{}".format(testname))
        checker.setRenderedImage(control_image)
        self.assertTrue(checker.compareImages("highlight_{}".format(testname)))
        shutil.rmtree(tempdir)
Exemplo n.º 4
0
    def testVectorBlending(self):
        """Test that blend modes work for vector layers."""

        #Add vector layers to map
        myLayers = []
        myLayers.append(self.mLineLayer.id())
        myLayers.append(self.mPolygonLayer.id())
        self.mapSettings.setLayers(myLayers)
        self.mapSettings.setExtent(self.mPointLayer.extent())

        #Set blending modes for both layers
        self.mLineLayer.setBlendMode(QPainter.CompositionMode_Difference)
        self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Difference)

        checker = QgsRenderChecker()
        checker.setControlName("expected_vector_blendmodes")
        checker.setMapSettings(self.mapSettings)

        myResult = checker.runTest("vector_blendmodes");
        myMessage = ('vector blending failed')
        assert myResult, myMessage

        #Reset layers
        self.mLineLayer.setBlendMode(QPainter.CompositionMode_SourceOver)
        self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_SourceOver)
Exemplo n.º 5
0
    def _img_diff(self, image, control_image, max_diff):
        temp_image = "/tmp/%s_result.png" % control_image
        with open(temp_image, "w") as f:
            f.write(image)

        control = QgsRenderChecker()
        control.setControlPathPrefix("qgis_server_accesscontrol")
        control.setControlName(control_image)
        control.setRenderedImage(temp_image)
        return control.compareImages(control_image), control.report()
 def renderCheck(self, mismatch=0):
     chk = QgsRenderChecker()
     chk.setControlPathPrefix('expected_' + self._TestGroupPrefix)
     chk.setControlName(self._Test)
     chk.setMapRenderer(self._MapRenderer)
     res = chk.runTest(self._Test, mismatch)
     if PALREPORT and not res:  # don't report ok checks
         testname = self._TestGroup + ' . ' + self._Test
         PALREPORTS[testname] = str(chk.report().toLocal8Bit())
     msg = '\nRender check failed for "{0}"'.format(self._Test)
     return res, msg
Exemplo n.º 7
0
    def _img_diff(self, image, control_image, max_diff, max_size_diff=QSize()):
        temp_image = path.join(tempfile.gettempdir(), "%s_result.png" % control_image)
        with open(temp_image, "w") as f:
            f.write(image)

        control = QgsRenderChecker()
        control.setControlPathPrefix("qgis_server_accesscontrol")
        control.setControlName(control_image)
        control.setRenderedImage(temp_image)
        if max_size_diff.isValid():
            control.setSizeTolerance(max_size_diff.width(), max_size_diff.height())
        return control.compareImages(control_image), control.report()
Exemplo n.º 8
0
 def imageCheck(self, name, reference_image, image):
     self.report += "<h2>Render {}</h2>\n".format(name)
     temp_dir = QDir.tempPath() + "/"
     file_name = temp_dir + "symbol_" + name + ".png"
     image.save(file_name, "PNG")
     checker = QgsRenderChecker()
     checker.setControlPathPrefix("symbolv2")
     checker.setControlName("expected_" + reference_image)
     checker.setRenderedImage(file_name)
     checker.setColorTolerance(2)
     result = checker.compareImages(name, 20)
     self.report += checker.report()
     print(self.report)
     return result
Exemplo n.º 9
0
    def test_getmap(self):
        test_name = 'qgis_local_server'
        success, img_path, url = MAPSERV.get_map(self.getmap_params())
        msg = '\nLocal server get_map failed'
        assert success, msg

        chk = QgsRenderChecker()
        chk.setControlName('expected_' + test_name)
        # chk.setMapRenderer(None)
        res = chk.compareImages(test_name, 0, img_path)
        if QGIS_TEST_REPORT and not res:  # don't report ok checks
            TESTREPORTS[test_name] = chk.report()
        msg = '\nRender check failed for "{0}"'.format(test_name)
        assert res, msg
Exemplo n.º 10
0
    def _pdf_diff(self, pdf, control_image, max_diff, max_size_diff=QSize(), dpi=96):

        temp_pdf = os.path.join(tempfile.gettempdir(), "%s_result.pdf" % control_image)

        with open(temp_pdf, "wb") as f:
            f.write(pdf)

        temp_image = os.path.join(tempfile.gettempdir(), "%s_result.png" % control_image)
        self._pdf_to_png(temp_pdf, temp_image, dpi=dpi, page=1)

        control = QgsRenderChecker()
        control.setControlPathPrefix("qgis_server")
        control.setControlName(control_image)
        control.setRenderedImage(temp_image)
        if max_size_diff.isValid():
            control.setSizeTolerance(max_size_diff.width(), max_size_diff.height())
        return control.compareImages(control_image, max_diff), control.report()
Exemplo n.º 11
0
 def renderCheck(self, mismatch=0):
     chk = QgsRenderChecker()
     chk.setControlPathPrefix('expected_' + self._TestGroupPrefix)
     chk.setControlName(self._Test)
     chk.setMapRenderer(self._MapRenderer)
     res = chk.runTest(self._Test, mismatch)
     if self._PalReportDir and not res:  # don't report ok checks
         testname = self._TestGroup + ' . ' + self._Test
         report = '<html>'
         report += '<head><title>{0}</title></head>'.format(testname)
         report += '<body>' + chk.report().toLocal8Bit() + '</body>'
         report += '</html>'
         f = QFile(os.path.join(self._PalReportDir, testname + '.html'))
         if f.open(QIODevice.ReadWrite | QIODevice.Truncate):
             f.write(report)
             f.close()
     msg = '\nRender check failed for "{0}"'.format(self._Test)
     return res, msg
Exemplo n.º 12
0
    def testRasterBlending(self):
        """Test that blend modes work for raster layers."""
        #Add raster layers to map
        myLayers = QStringList()
        myLayers.append(self.mRasterLayer1.id())
        myLayers.append(self.mRasterLayer2.id())
        self.mMapRenderer.setLayerSet(myLayers)
        self.mMapRenderer.setExtent(self.mRasterLayer1.extent())

        #Set blending mode for top layer
        self.mRasterLayer1.setBlendMode(QPainter.CompositionMode_Plus)
        checker = QgsRenderChecker()
        checker.setControlName("expected_raster_blendmodes")
        checker.setMapRenderer(self.mMapRenderer)

        myResult = checker.runTest("raster_blendmodes");
        myMessage = ('raster blending failed')
        assert myResult, myMessage
Exemplo n.º 13
0
    def _img_diff(self, image, control_image, max_diff, max_size_diff=QSize(), outputJpg=False):

        extFile = 'png'
        if outputJpg:
            extFile = 'jpg'

        temp_image = os.path.join(tempfile.gettempdir(), "%s_result.%s" % (control_image, extFile))

        with open(temp_image, "wb") as f:
            f.write(image)

        control = QgsRenderChecker()
        control.setControlPathPrefix("qgis_server_accesscontrol")
        control.setControlName(control_image)
        control.setRenderedImage(temp_image)
        if max_size_diff.isValid():
            control.setSizeTolerance(max_size_diff.width(), max_size_diff.height())
        return control.compareImages(control_image), control.report()
Exemplo n.º 14
0
    def testVectorLayerTransparency(self):
        """Test that layer transparency works for vector layers."""

        #Add vector layers to map
        myLayers = []
        myLayers.append(self.mLineLayer.id())
        myLayers.append(self.mPolygonLayer.id())
        self.mapSettings.setLayers(myLayers)
        self.mapSettings.setExtent(self.mPointLayer.extent())

        #Set feature blending for line layer
        self.mLineLayer.setLayerTransparency( 50 )

        checker = QgsRenderChecker()
        checker.setControlName("expected_vector_layertransparency")
        checker.setMapSettings(self.mapSettings)

        myResult = checker.runTest("vector_layertransparency");
        myMessage = ('vector layer transparency failed')
        assert myResult, myMessage
Exemplo n.º 15
0
    def imageCheck(self, name, reference_image, image):
        self.report += "<h2>Render {}</h2>\n".format(name)
        temp_dir = QDir.tempPath() + '/'
        file_name = temp_dir + 'svg_' + name + ".png"

        output_image = QImage(image.size(), QImage.Format_RGB32)
        QgsMultiRenderChecker.drawBackground(output_image)
        painter = QPainter(output_image)
        painter.drawImage(0, 0, image)
        painter.end()

        output_image.save(file_name, "PNG")
        checker = QgsRenderChecker()
        checker.setControlPathPrefix("svg_cache")
        checker.setControlName("expected_" + reference_image)
        checker.setRenderedImage(file_name)
        checker.setColorTolerance(2)
        result = checker.compareImages(name, 20)
        self.report += checker.report()
        print((self.report))
        return result
Exemplo n.º 16
0
    def testVectorBlending(self):
        """Test that blend modes work for vector layers."""

        #Add vector layers to map
        myLayers = QStringList()
        myLayers.append(self.mPointLayer.id())
        myLayers.append(self.mPolygonLayer.id())
        self.mMapRenderer.setLayerSet(myLayers)
        self.mMapRenderer.setExtent(self.mPointLayer.extent())

        #Set blending modes for both layers
        self.mPointLayer.setBlendMode(QPainter.CompositionMode_Overlay)
        self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Multiply)

        checker = QgsRenderChecker()
        checker.setControlName("expected_vector_blendmodes")
        checker.setMapRenderer(self.mMapRenderer)

        myResult = checker.runTest("vector_blendmodes");
        myMessage = ('vector blending failed')
        assert myResult, myMessage
Exemplo n.º 17
0
    def testVectorLayerTransparency(self):
        """Test that layer transparency works for vector layers."""

        #Add vector layers to map
        myLayers = QStringList()
        myLayers.append(self.mLineLayer.id())
        myLayers.append(self.mPolygonLayer.id())
        self.mMapRenderer.setLayerSet(myLayers)
        self.mMapRenderer.setExtent(self.mPointLayer.extent())
        self.mPolygonLayer.setBlendMode(QPainter.CompositionMode_Multiply)

        #Set feature blending for line layer
        self.mLineLayer.setLayerTransparency( 50 )

        checker = QgsRenderChecker()
        checker.setControlName("expected_vector_layertransparency")
        checker.setMapRenderer(self.mMapRenderer)

        myResult = checker.runTest("vector_layertransparency");
        myMessage = ('vector layer transparency failed')
        assert myResult, myMessage
Exemplo n.º 18
0
    def testPalettedBand(self):
        """ test paletted raster render band"""
        path = os.path.join(unitTestDataPath(),
                            'landsat_4326.tif')
        info = QFileInfo(path)
        base_name = info.baseName()
        layer = QgsRasterLayer(path, base_name)
        self.assertTrue(layer.isValid(), 'Raster not loaded: {}'.format(path))

        renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 2,
                                             [QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), 'class 2'),
                                              QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), 'class 1'),
                                              QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), 'class 1')])

        layer.setRenderer(renderer)
        ms = QgsMapSettings()
        ms.setLayers([layer])
        ms.setExtent(layer.extent())

        checker = QgsRenderChecker()
        checker.setControlName("expected_paletted_renderer_band2")
        checker.setMapSettings(ms)

        self.assertTrue(checker.runTest("expected_paletted_renderer_band2"), "Paletted rendering test failed")

        renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 3,
                                             [QgsPalettedRasterRenderer.Class(120, QColor(0, 255, 0), 'class 2'),
                                              QgsPalettedRasterRenderer.Class(123, QColor(255, 0, 0), 'class 1'),
                                              QgsPalettedRasterRenderer.Class(124, QColor(0, 0, 255), 'class 1')])

        layer.setRenderer(renderer)
        ms = QgsMapSettings()
        ms.setLayers([layer])
        ms.setExtent(layer.extent())

        checker = QgsRenderChecker()
        checker.setControlName("expected_paletted_renderer_band3")
        checker.setMapSettings(ms)

        self.assertTrue(checker.runTest("expected_paletted_renderer_band3"), "Paletted rendering test failed")
Exemplo n.º 19
0
    def testVectorFeatureBlending(self):
        """Test that feature blend modes work for vector layers."""

        #Add vector layers to map
        myLayers = []
        myLayers.append(self.mLineLayer.id())
        myLayers.append(self.mPolygonLayer.id())
        self.mMapRenderer.setLayerSet(myLayers)
        self.mMapRenderer.setExtent(self.mPointLayer.extent())

        #Set feature blending for line layer
        self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_Plus)

        checker = QgsRenderChecker()
        checker.setControlName("expected_vector_featureblendmodes")
        checker.setMapRenderer(self.mMapRenderer)

        myResult = checker.runTest("vector_featureblendmodes");
        myMessage = ('vector feature blending failed')
        assert myResult, myMessage

        #Reset layers
        self.mLineLayer.setFeatureBlendMode(QPainter.CompositionMode_SourceOver)
Exemplo n.º 20
0
    def renderCheck(self, mismatch=0, imgpath='', grpprefix=''):
        """Check rendered map canvas or existing image against control image

        mismatch: number of pixels different from control, and still valid check
        imgpath: existing image; if present, skips rendering canvas
        grpprefix: compare test image/rendering against different test group
        """
        if not grpprefix:
            grpprefix = self._TestGroupPrefix
        chk = QgsRenderChecker()
        chk.setControlPathPrefix('expected_' + grpprefix)
        chk.setControlName(self._Test)
        chk.setMapRenderer(self._MapRenderer)
        res = False
        if imgpath:
            res = chk.compareImages(self._Test, mismatch, str(imgpath))
        else:
            res = chk.runTest(self._Test, mismatch)
        if PALREPORT and not res:  # don't report ok checks
            testname = self._TestGroup + ' . ' + self._Test
            PALREPORTS[testname] = str(chk.report().toLocal8Bit())
        msg = '\nRender check failed for "{0}"'.format(self._Test)
        return res, msg
Exemplo n.º 21
0
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")
Exemplo n.º 22
0
    def test_AddPALToVectorLayer(self):
        """Check if we can set a label field, verify that PAL is assigned
            and that output is rendered correctly"""
        # TODO: add UTM PAL-specific shps, with 4326 as on-the-fly cross-check
        #        setCanvasCrs(26913)

        myShpFile = os.path.join(TEST_DATA_DIR, 'lines.shp')
        myVectorLayer = QgsVectorLayer(myShpFile, 'Lines', 'ogr')

        self._MapRegistry.addMapLayer(myVectorLayer)

        myLayers = QStringList()
        myLayers.append(myVectorLayer.id())
        self._MapRenderer.setLayerSet(myLayers)
        self._MapRenderer.setExtent(myVectorLayer.extent())
        self._Canvas.zoomToFullExtent()

        # check layer labeling is PAL with customProperty access
        # should not be activated on layer load
        myPalSet = myVectorLayer.customProperty("labeling").toString()
        myMessage = '\nExpected: Empty QString\nGot: %s' % (str(myPalSet))
        assert str(myPalSet) == '', myMessage

        # simulate clicking checkbox, setting label field and clicking apply
        self._testFont.setPointSize(20)
        myPalLyr = QgsPalLayerSettings()

        myPalLyr.enabled = True
        myPalLyr.fieldName = 'Name'
        myPalLyr.placement = QgsPalLayerSettings.Line
        myPalLyr.placementFlags = QgsPalLayerSettings.AboveLine
        myPalLyr.xQuadOffset = 0
        myPalLyr.yQuadOffset = 0
        myPalLyr.xOffset = 0
        myPalLyr.yOffset = 0
        myPalLyr.angleOffset = 0
        myPalLyr.centroidWhole = False
        myPalLyr.textFont = self._testFont
        myPalLyr.textNamedStyle = QString("Medium")
        myPalLyr.textColor = Qt.black
        myPalLyr.textTransp = 0
        myPalLyr.previewBkgrdColor = Qt.white
        myPalLyr.priority = 5
        myPalLyr.obstacle = True
        myPalLyr.dist = 0
        myPalLyr.scaleMin = 0
        myPalLyr.scaleMax = 0
        myPalLyr.bufferSize = 1
        myPalLyr.bufferColor = Qt.white
        myPalLyr.bufferTransp = 0
        myPalLyr.bufferNoFill = False
        myPalLyr.bufferJoinStyle = Qt.RoundJoin
        myPalLyr.formatNumbers = False
        myPalLyr.decimals = 3
        myPalLyr.plusSign = False
        myPalLyr.labelPerPart = False
        myPalLyr.displayAll = True
        myPalLyr.mergeLines = False
        myPalLyr.minFeatureSize = 0.0
        myPalLyr.vectorScaleFactor = 1.0
        myPalLyr.rasterCompressFactor = 1.0
        myPalLyr.addDirectionSymbol = False
        myPalLyr.upsidedownLabels = QgsPalLayerSettings.Upright
        myPalLyr.fontSizeInMapUnits = False
        myPalLyr.bufferSizeInMapUnits = False
        myPalLyr.labelOffsetInMapUnits = True
        myPalLyr.distInMapUnits = False
        myPalLyr.wrapChar = ""
        myPalLyr.preserveRotation = True

        myPalLyr.writeToLayer(myVectorLayer)

        # check layer labeling is PAL with customProperty access
        myPalSet = myVectorLayer.customProperty("labeling").toString()
        myMessage = '\nExpected: pal\nGot: %s' % (str(myPalSet))
        assert str(myPalSet) == 'pal', myMessage

        # check layer labeling is PAL via engine interface
        myMessage = '\nCould not get whether PAL enabled from labelingEngine'
        assert self._PalEngine.willUseLayer(myVectorLayer), myMessage

        #
        myChecker = QgsRenderChecker()
        myChecker.setControlName("expected_pal_aboveLineLabeling")
        myChecker.setMapRenderer(self._MapRenderer)

        myResult = myChecker.runTest("pal_aboveLineLabeling_python")
        myMessage = ('\nVector layer \'above line\' label engine '
                     'rendering test failed')
        assert myResult, myMessage

        # compare against a straight rendering/save as from QgsMapCanvasMap
        # unnecessary? works a bit different than QgsRenderChecker, though
        #        myImage = os.path.join(unicode(QDir.tempPath()),
        #                               'render_pal_aboveLineLabeling.png')
        #        self._Map.render()
        #        self._Canvas.saveAsImage(myImage)
        #        myChecker.setRenderedImage(myImage)
        #        myResult = myChecker.compareImages("pal_aboveLineLabeling_python")
        #        myMessage = ('\nVector layer \'above line\' label engine '
        #                     'comparison to QgsMapCanvasMap.render() test failed')
        #        assert myResult, myMessage

        self._MapRegistry.removeMapLayer(myVectorLayer.id())
Exemplo n.º 23
0
    def testTransparency(self):
        myPath = os.path.join(unitTestDataPath('raster'),
                              'band1_float32_noct_epsg4326.tif')
        myFileInfo = QFileInfo(myPath)
        myBaseName = myFileInfo.baseName()
        myRasterLayer = QgsRasterLayer(myPath, myBaseName)
        myMessage = 'Raster not loaded: %s' % myPath
        assert myRasterLayer.isValid(), myMessage

        renderer = QgsSingleBandGrayRenderer(myRasterLayer.dataProvider(), 1)
        myRasterLayer.setRenderer(renderer)
        myRasterLayer.setContrastEnhancementAlgorithm(
            QgsContrastEnhancement.StretchToMinimumMaximum,
            QgsRasterLayer.ContrastEnhancementMinMax)

        myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement()
        #print ("myContrastEnhancement.minimumValue = %.17g" %
        #       myContrastEnhancement.minimumValue())
        #print ("myContrastEnhancement.maximumValue = %.17g" %
        #        myContrastEnhancement.maximumValue())

        # Unfortunately the minimum/maximum values calculated in C++ and Python
        # are slightly different (e.g. 3.3999999521443642e+38 x
        # 3.3999999521444001e+38)
        # It is not clear where the precision is lost.
        # We set the same values as C++.
        myContrastEnhancement.setMinimumValue(-3.3319999287625854e+38)
        myContrastEnhancement.setMaximumValue(3.3999999521443642e+38)
        #myType = myRasterLayer.dataProvider().dataType(1);
        #myEnhancement = QgsContrastEnhancement(myType);



        myTransparentSingleValuePixelList = []
        rasterTransparency = QgsRasterTransparency()

        myTransparentPixel1 = \
            QgsRasterTransparency.TransparentSingleValuePixel()
        myTransparentPixel1.min = -2.5840000772112106e+38
        myTransparentPixel1.max = -1.0879999684602689e+38
        myTransparentPixel1.percentTransparent = 50
        myTransparentSingleValuePixelList.append(myTransparentPixel1)

        myTransparentPixel2 = \
            QgsRasterTransparency.TransparentSingleValuePixel()
        myTransparentPixel2.min = 1.359999960575336e+37
        myTransparentPixel2.max = 9.520000231087593e+37
        myTransparentPixel2.percentTransparent = 70
        myTransparentSingleValuePixelList.append(myTransparentPixel2)

        rasterTransparency.setTransparentSingleValuePixelList(
            myTransparentSingleValuePixelList)

        rasterRenderer = myRasterLayer.renderer()
        assert rasterRenderer

        rasterRenderer.setRasterTransparency(rasterTransparency)

        QgsMapLayerRegistry.instance().addMapLayers([ myRasterLayer, ])

        myMapRenderer = QgsMapRenderer()

        myLayers = QStringList()
        myLayers.append(myRasterLayer.id())
        myMapRenderer.setLayerSet(myLayers)
        myMapRenderer.setExtent(myRasterLayer.extent())

        myChecker = QgsRenderChecker()
        myChecker.setControlName("expected_raster_transparency")
        myChecker.setMapRenderer(myMapRenderer)

        myResultFlag = myChecker.runTest("raster_transparency_python");
        assert myResultFlag, "Raster transparency rendering test failed"
Exemplo n.º 24
0
    def testPaletted(self):
        """ test paletted raster renderer with raster with color table"""
        path = os.path.join(unitTestDataPath('raster'),
                            'with_color_table.tif')
        info = QFileInfo(path)
        base_name = info.baseName()
        layer = QgsRasterLayer(path, base_name)
        self.assertTrue(layer.isValid(), 'Raster not loaded: {}'.format(path))

        renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1,
                                             [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'),
                                              QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')])

        self.assertEqual(renderer.nColors(), 2)
        self.assertEqual(renderer.usesBands(), [1])

        # test labels
        self.assertEqual(renderer.label(1), 'class 2')
        self.assertEqual(renderer.label(3), 'class 1')
        self.assertFalse(renderer.label(101))

        # test legend symbology - should be sorted by value
        legend = renderer.legendSymbologyItems()
        self.assertEqual(legend[0][0], 'class 2')
        self.assertEqual(legend[1][0], 'class 1')
        self.assertEqual(legend[0][1].name(), '#00ff00')
        self.assertEqual(legend[1][1].name(), '#ff0000')

        # test retrieving classes
        classes = renderer.classes()
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'class 1')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')

        # test set label
        # bad index
        renderer.setLabel(1212, 'bad')
        renderer.setLabel(3, 'new class')
        self.assertEqual(renderer.label(3), 'new class')

        # color ramp
        r = QgsLimitedRandomColorRamp(5)
        renderer.setSourceColorRamp(r)
        self.assertEqual(renderer.sourceColorRamp().type(), 'random')
        self.assertEqual(renderer.sourceColorRamp().count(), 5)

        # clone
        new_renderer = renderer.clone()
        classes = new_renderer.classes()
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'new class')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')
        self.assertEqual(new_renderer.sourceColorRamp().type(), 'random')
        self.assertEqual(new_renderer.sourceColorRamp().count(), 5)

        # write to xml and read
        doc = QDomDocument('testdoc')
        elem = doc.createElement('qgis')
        renderer.writeXml(doc, elem)
        restored = QgsPalettedRasterRenderer.create(elem.firstChild().toElement(), layer.dataProvider())
        self.assertTrue(restored)
        self.assertEqual(restored.usesBands(), [1])
        classes = restored.classes()
        self.assertTrue(classes)
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'new class')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')
        self.assertEqual(restored.sourceColorRamp().type(), 'random')
        self.assertEqual(restored.sourceColorRamp().count(), 5)

        # render test
        layer.setRenderer(renderer)
        ms = QgsMapSettings()
        ms.setLayers([layer])
        ms.setExtent(layer.extent())

        checker = QgsRenderChecker()
        checker.setControlName("expected_paletted_renderer")
        checker.setMapSettings(ms)

        self.assertTrue(checker.runTest("expected_paletted_renderer"), "Paletted rendering test failed")
Exemplo n.º 25
0
    def testTransparency(self):
        myPath = os.path.join(unitTestDataPath('raster'),
                              'band1_float32_noct_epsg4326.tif')
        myFileInfo = QFileInfo(myPath)
        myBaseName = myFileInfo.baseName()
        myRasterLayer = QgsRasterLayer(myPath, myBaseName)
        myMessage = 'Raster not loaded: %s' % myPath
        assert myRasterLayer.isValid(), myMessage

        renderer = QgsSingleBandGrayRenderer(myRasterLayer.dataProvider(), 1)
        myRasterLayer.setRenderer(renderer)
        myRasterLayer.setContrastEnhancement(
            QgsContrastEnhancement.StretchToMinimumMaximum,
            QgsRasterMinMaxOrigin.MinMax)

        myContrastEnhancement = myRasterLayer.renderer().contrastEnhancement()
        # print ("myContrastEnhancement.minimumValue = %.17g" %
        #       myContrastEnhancement.minimumValue())
        # print ("myContrastEnhancement.maximumValue = %.17g" %
        #        myContrastEnhancement.maximumValue())

        # Unfortunately the minimum/maximum values calculated in C++ and Python
        # are slightly different (e.g. 3.3999999521443642e+38 x
        # 3.3999999521444001e+38)
        # It is not clear where the precision is lost.
        # We set the same values as C++.
        myContrastEnhancement.setMinimumValue(-3.3319999287625854e+38)
        myContrastEnhancement.setMaximumValue(3.3999999521443642e+38)
        #myType = myRasterLayer.dataProvider().dataType(1);
        #myEnhancement = QgsContrastEnhancement(myType);

        myTransparentSingleValuePixelList = []
        rasterTransparency = QgsRasterTransparency()

        myTransparentPixel1 = \
            QgsRasterTransparency.TransparentSingleValuePixel()
        myTransparentPixel1.min = -2.5840000772112106e+38
        myTransparentPixel1.max = -1.0879999684602689e+38
        myTransparentPixel1.percentTransparent = 50
        myTransparentSingleValuePixelList.append(myTransparentPixel1)

        myTransparentPixel2 = \
            QgsRasterTransparency.TransparentSingleValuePixel()
        myTransparentPixel2.min = 1.359999960575336e+37
        myTransparentPixel2.max = 9.520000231087593e+37
        myTransparentPixel2.percentTransparent = 70
        myTransparentSingleValuePixelList.append(myTransparentPixel2)

        rasterTransparency.setTransparentSingleValuePixelList(
            myTransparentSingleValuePixelList)

        rasterRenderer = myRasterLayer.renderer()
        assert rasterRenderer

        rasterRenderer.setRasterTransparency(rasterTransparency)

        QgsProject.instance().addMapLayers([
            myRasterLayer,
        ])

        myMapSettings = QgsMapSettings()
        myMapSettings.setLayers([myRasterLayer])
        myMapSettings.setExtent(myRasterLayer.extent())

        myChecker = QgsRenderChecker()
        myChecker.setControlName("expected_raster_transparency")
        myChecker.setMapSettings(myMapSettings)

        myResultFlag = myChecker.runTest("raster_transparency_python")
        assert myResultFlag, "Raster transparency rendering test failed"
Exemplo n.º 26
0
    def testPaletted(self):
        """ test paletted raster renderer with raster with color table"""
        path = os.path.join(unitTestDataPath('raster'),
                            'with_color_table.tif')
        info = QFileInfo(path)
        base_name = info.baseName()
        layer = QgsRasterLayer(path, base_name)
        self.assertTrue(layer.isValid(), 'Raster not loaded: {}'.format(path))

        renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1,
                                             [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'),
                                              QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')])

        self.assertEqual(renderer.nColors(), 2)
        self.assertEqual(renderer.usesBands(), [1])

        # test labels
        self.assertEqual(renderer.label(1), 'class 2')
        self.assertEqual(renderer.label(3), 'class 1')
        self.assertFalse(renderer.label(101))

        # test legend symbology - should be sorted by value
        legend = renderer.legendSymbologyItems()
        self.assertEqual(legend[0][0], 'class 2')
        self.assertEqual(legend[1][0], 'class 1')
        self.assertEqual(legend[0][1].name(), '#00ff00')
        self.assertEqual(legend[1][1].name(), '#ff0000')

        # test retrieving classes
        classes = renderer.classes()
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'class 1')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')

        # test set label
        # bad index
        renderer.setLabel(1212, 'bad')
        renderer.setLabel(3, 'new class')
        self.assertEqual(renderer.label(3), 'new class')

        # color ramp
        r = QgsLimitedRandomColorRamp(5)
        renderer.setSourceColorRamp(r)
        self.assertEqual(renderer.sourceColorRamp().type(), 'random')
        self.assertEqual(renderer.sourceColorRamp().count(), 5)

        # clone
        new_renderer = renderer.clone()
        classes = new_renderer.classes()
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'new class')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')
        self.assertEqual(new_renderer.sourceColorRamp().type(), 'random')
        self.assertEqual(new_renderer.sourceColorRamp().count(), 5)

        # write to xml and read
        doc = QDomDocument('testdoc')
        elem = doc.createElement('qgis')
        renderer.writeXml(doc, elem)
        restored = QgsPalettedRasterRenderer.create(elem.firstChild().toElement(), layer.dataProvider())
        self.assertTrue(restored)
        self.assertEqual(restored.usesBands(), [1])
        classes = restored.classes()
        self.assertTrue(classes)
        self.assertEqual(classes[0].value, 1)
        self.assertEqual(classes[1].value, 3)
        self.assertEqual(classes[0].label, 'class 2')
        self.assertEqual(classes[1].label, 'new class')
        self.assertEqual(classes[0].color.name(), '#00ff00')
        self.assertEqual(classes[1].color.name(), '#ff0000')
        self.assertEqual(restored.sourceColorRamp().type(), 'random')
        self.assertEqual(restored.sourceColorRamp().count(), 5)

        # render test
        layer.setRenderer(renderer)
        ms = QgsMapSettings()
        ms.setLayers([layer])
        ms.setExtent(layer.extent())

        checker = QgsRenderChecker()
        checker.setControlName("expected_paletted_renderer")
        checker.setMapSettings(ms)

        self.assertTrue(checker.runTest("expected_paletted_renderer"), "Paletted rendering test failed")