def renderGeometry(self, symbol, geom, buffer=20):
        f = QgsFeature()
        f.setGeometry(geom)

        image = QImage(200, 200, QImage.Format_RGB32)

        painter = QPainter()
        ms = QgsMapSettings()
        extent = geom.get().boundingBox()
        # buffer extent by 10%
        if extent.width() > 0:
            extent = extent.buffered((extent.height() + extent.width()) / buffer)
        else:
            extent = extent.buffered(buffer / 2)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI
        context.expressionContext().setFeature(f)

        painter.begin(image)
        try:
            image.fill(QColor(0, 0, 0))
            symbol.startRender(context)
            symbol.renderFeature(f, context)
            symbol.stopRender(context)
        finally:
            painter.end()

        return image
Exemple #2
0
    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As Image'), '',
                                                           self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage("", self.tr("Successfully exported model as image to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
Exemple #3
0
    def exportAsImage(self):
        filename = unicode(QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Image'), '',
                                                       self.tr('PNG files (*.png *.PNG)')))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = QRectF(0, 0, 1, 1)
        for item in self.scene.items():
            totalRect = totalRect.united(item.sceneBoundingRect())
        totalRect.adjust(-10, -10, 10, 10)

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, totalRect, totalRect)
        painter.end()

        img.save(filename)
Exemple #4
0
    def testRenderMarkerLayerDisabled(self):
        """ test that rendering a marker symbol with disabled layer works"""
        layer = QgsSimpleMarkerSymbolLayer()
        layer.setEnabled(False)

        symbol = QgsMarkerSymbol()
        symbol.changeSymbolLayer(0, layer)

        image = QImage(200, 200, QImage.Format_RGB32)
        painter = QPainter()
        ms = QgsMapSettings()

        geom = QgsGeometry.fromWkt('Point (1 2)')
        f = QgsFeature()
        f.setGeometry(geom)

        extent = QgsRectangle(0, 0, 4, 4)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        image.fill(QColor(255, 255, 255))

        symbol.startRender(context)
        symbol.renderFeature(f, context)
        symbol.stopRender(context)
        painter.end()

        self.assertTrue(self.imageCheck('symbol_layer', 'symbollayer_disabled', image))
Exemple #5
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)
Exemple #6
0
    def testRenderLineLayerDisabled(self):
        """ test that rendering a line symbol with disabled layer works"""
        layer = QgsSimpleLineSymbolLayer()
        layer.setEnabled(False)

        symbol = QgsLineSymbol()
        symbol.changeSymbolLayer(0, layer)

        image = QImage(200, 200, QImage.Format_RGB32)
        painter = QPainter()
        ms = QgsMapSettings()

        geom = QgsGeometry.fromWkt('LineString (0 0,3 4,4 3)')
        f = QgsFeature()
        f.setGeometry(geom)

        extent = geom.constGet().boundingBox()
        # buffer extent by 10%
        extent = extent.buffered((extent.height() + extent.width()) / 20.0)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        image.fill(QColor(255, 255, 255))

        symbol.startRender(context)
        symbol.renderFeature(f, context)
        symbol.stopRender(context)
        painter.end()

        self.assertTrue(self.imageCheck('symbol_layer', 'symbollayer_disabled', image))
Exemple #7
0
    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As Image'), '',
                                                           self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage("", "Model was correctly exported as image", level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
    def testSimpleLineWithOffset(self):
        """ test that rendering a polygon with simple line symbol with offset results in closed line"""
        layer = QgsSimpleLineSymbolLayer()
        layer.setOffset(-1)

        symbol = QgsFillSymbol()
        symbol.changeSymbolLayer(0, layer)

        image = QImage(200, 200, QImage.Format_RGB32)
        painter = QPainter()
        ms = QgsMapSettings()

        geom = QgsGeometry.fromWkt('Polygon((0 0, 10 0, 10 10, 0 10, 0 0))')
        f = QgsFeature()
        f.setGeometry(geom)

        extent = geom.geometry().boundingBox()
        # buffer extent by 10%
        extent = extent.buffer((extent.height() + extent.width()) / 20.0)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        image.fill(QColor(255, 255, 255))

        symbol.startRender(context)
        symbol.renderFeature(f, context)
        symbol.stopRender(context)
        painter.end()

        self.assertTrue(self.imageCheck('symbol_layer', 'fill_simpleline_offset', image))
    def testFromQPainter(self):
        """ test QgsRenderContext.fromQPainter """

        # no painter
        c = QgsRenderContext.fromQPainter(None)
        self.assertFalse(c.painter())
        # assuming 88 dpi as fallback
        self.assertAlmostEqual(c.scaleFactor(), 88 / 25.4, 3)

        # no painter destination
        p = QPainter()
        c = QgsRenderContext.fromQPainter(p)
        self.assertEqual(c.painter(), p)
        self.assertEqual(c.testFlag(QgsRenderContext.Antialiasing), False)
        self.assertAlmostEqual(c.scaleFactor(), 88 / 25.4, 3)

        im = QImage(1000, 600, QImage.Format_RGB32)
        dots_per_m = 300 / 25.4 * 1000  # 300 dpi to dots per m
        im.setDotsPerMeterX(dots_per_m)
        im.setDotsPerMeterY(dots_per_m)
        p = QPainter(im)
        p.setRenderHint(QPainter.Antialiasing)
        c = QgsRenderContext.fromQPainter(p)
        self.assertEqual(c.painter(), p)
        self.assertEqual(c.testFlag(QgsRenderContext.Antialiasing), True)
        self.assertAlmostEqual(c.scaleFactor(), dots_per_m / 1000, 3)  # scaleFactor should be pixels/mm
def imageFromPath(path):
    if (path[:7] == 'http://' or path[:7] == 'file://'):
        #fetch remote image
        data = urllib2.urlopen(path).read()
        image = QImage()
        image.loadFromData(data)
    else:
        image = QImage(path)
    return image
Exemple #11
0
    def _get_composer_image(self, width, height, dpi):
        image = QImage(QSize(width, height),
                       self._TestMapSettings.outputImageFormat())
        image.fill(QColor(152, 219, 249).rgb())
        image.setDotsPerMeterX(dpi / 25.4 * 1000)
        image.setDotsPerMeterY(dpi / 25.4 * 1000)

        p = QPainter(image)
        p.setRenderHint(
            QPainter.Antialiasing,
            self._TestMapSettings.testFlag(QgsMapSettings.Antialiasing)
        )
        self._c.renderPage(p, 0)
        p.end()

        # image = self._c.printPageAsRaster(0)
        # """:type: QImage"""

        if image.isNull():
            return False, ''

        filepath = getTempfilePath('png')
        res = image.save(filepath, 'png')
        if not res:
            os.unlink(filepath)
            filepath = ''

        return res, filepath
    def __init__(self, parent, context, webPage, layerType):
        QObject.__init__(self, parent)

        debug("OpenlayersController.__init__", 3)
        self.context = context
        self.layerType = layerType

        self.img = QImage()

        self.page = webPage
        self.page.loadFinished.connect(self.pageLoaded)
        # initial size for map
        self.page.setViewportSize(QSize(1, 1))

        self.timerMapReady = QTimer()
        self.timerMapReady.setSingleShot(True)
        self.timerMapReady.setInterval(20)
        self.timerMapReady.timeout.connect(self.checkMapReady)

        self.timer = QTimer()
        self.timer.setInterval(100)
        self.timer.timeout.connect(self.checkMapUpdate)

        self.timerMax = QTimer()
        self.timerMax.setSingleShot(True)
        # TODO: different timeouts for map types
        self.timerMax.setInterval(2500)
        self.timerMax.timeout.connect(self.mapTimeout)
    def _svg_to_png(svg_file_path, rendered_file_path, width):
        svgr = QSvgRenderer(svg_file_path)

        height = width / svgr.viewBoxF().width() * svgr.viewBoxF().height()

        image = QImage(width, height, QImage.Format_ARGB32)
        image.fill(Qt.transparent)

        p = QPainter(image)
        p.setRenderHint(QPainter.Antialiasing, False)
        svgr.render(p)
        p.end()

        res = image.save(rendered_file_path, 'png')
        if not res:
            os.unlink(rendered_file_path)
    def image(self):
        width = (self.xmax - self.xmin + 1) * self.TILE_SIZE
        height = (self.ymax - self.ymin + 1) * self.TILE_SIZE
        image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
        p = QPainter(image)
        for tile in list(self.tiles.values()):
            if not tile.data:
                continue

            x = tile.x - self.xmin
            y = tile.y - self.ymin
            rect = QRect(x * self.TILE_SIZE, y * self.TILE_SIZE, self.TILE_SIZE, self.TILE_SIZE)

            timg = QImage()
            timg.loadFromData(tile.data)
            p.drawImage(rect, timg)
        return image
Exemple #15
0
    def testLayout(self, page=0, pixelDiff=0):
        if self.layout is None:
            myMessage = "Layout not valid"
            return False, myMessage

        # load expected image
        self.setControlName("expected_" + self.test_name)

        # get width/height, create image and render the composition to it
        outputImage = QImage(self.size, QImage.Format_RGB32)

        outputImage.setDotsPerMeterX(self.dots_per_meter)
        outputImage.setDotsPerMeterY(self.dots_per_meter)
        QgsMultiRenderChecker.drawBackground(outputImage)
        p = QPainter(outputImage)
        self.layout.exporter().renderPage(p, page)
        p.end()

        renderedFilePath = QDir.tempPath() + QDir.separator() + QFileInfo(self.test_name).baseName() + "_rendered.png"
        outputImage.save(renderedFilePath, "PNG")

        self.setRenderedImage(renderedFilePath)

        testResult = self.runTest(self.test_name, pixelDiff)

        return testResult, self.report()
Exemple #16
0
    def renderGeometry(self, geom):
        f = QgsFeature()
        f.setGeometry(geom)

        image = QImage(200, 200, QImage.Format_RGB32)

        painter = QPainter()
        ms = QgsMapSettings()
        extent = geom.get().boundingBox()
        # buffer extent by 10%
        if extent.width() > 0:
            extent = extent.buffered((extent.height() + extent.width()) / 20.0)
        else:
            extent = extent.buffered(10)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        try:
            image.fill(QColor(0, 0, 0))

            if geom.type() == QgsWkbTypes.PolygonGeometry:
                self.fill_symbol.startRender(context)
                self.fill_symbol.renderFeature(f, context)
                self.fill_symbol.stopRender(context)

            elif geom.type() == QgsWkbTypes.LineGeometry:
                self.line_symbol.startRender(context)
                self.line_symbol.renderFeature(f, context)
                self.line_symbol.stopRender(context)

            elif geom.type() == QgsWkbTypes.PointGeometry:
                self.marker_symbol.startRender(context)
                self.marker_symbol.renderFeature(f, context)
                self.marker_symbol.stopRender(context)
            else:
                self.fail("Unknown type: " + geom.type())
        finally:
            painter.end()

        return image
Exemple #17
0
    def testRenderPage(self):
        l = QgsLayout(QgsProject.instance())
        l.initializeDefaults()

        # add some items
        item1 = QgsLayoutItemShape(l)
        item1.attemptSetSceneRect(QRectF(10, 20, 100, 150))
        fill = QgsSimpleFillSymbolLayer()
        fill_symbol = QgsFillSymbol()
        fill_symbol.changeSymbolLayer(0, fill)
        fill.setColor(Qt.green)
        fill.setStrokeStyle(Qt.NoPen)
        item1.setSymbol(fill_symbol)
        l.addItem(item1)

        # get width/height, create image and render the composition to it
        size = QSize(1122, 794)
        output_image = QImage(size, QImage.Format_RGB32)

        output_image.setDotsPerMeterX(self.dots_per_meter)
        output_image.setDotsPerMeterY(self.dots_per_meter)
        QgsMultiRenderChecker.drawBackground(output_image)
        painter = QPainter(output_image)
        exporter = QgsLayoutExporter(l)

        # valid page
        exporter.renderPage(painter, 0)
        painter.end()

        rendered_file_path = os.path.join(self.basetestpath, 'test_renderpage.png')
        output_image.save(rendered_file_path, "PNG")
        self.assertTrue(self.checkImage('renderpage', 'renderpage', rendered_file_path))
Exemple #18
0
    def testRenderRegion(self):
        l = QgsLayout(QgsProject.instance())
        l.initializeDefaults()

        # add a guide, to ensure it is not included in export
        g1 = QgsLayoutGuide(Qt.Horizontal, QgsLayoutMeasurement(15, QgsUnitTypes.LayoutMillimeters), l.pageCollection().page(0))
        l.guides().addGuide(g1)

        # add some items
        item1 = QgsLayoutItemShape(l)
        item1.attemptSetSceneRect(QRectF(10, 20, 100, 150))
        fill = QgsSimpleFillSymbolLayer()
        fill_symbol = QgsFillSymbol()
        fill_symbol.changeSymbolLayer(0, fill)
        fill.setColor(Qt.green)
        fill.setStrokeStyle(Qt.NoPen)
        item1.setSymbol(fill_symbol)
        l.addItem(item1)

        # get width/height, create image and render the composition to it
        size = QSize(560, 509)
        output_image = QImage(size, QImage.Format_RGB32)

        output_image.setDotsPerMeterX(self.dots_per_meter)
        output_image.setDotsPerMeterY(self.dots_per_meter)
        QgsMultiRenderChecker.drawBackground(output_image)
        painter = QPainter(output_image)
        exporter = QgsLayoutExporter(l)

        exporter.renderRegion(painter, QRectF(5, 10, 110, 100))
        painter.end()

        rendered_file_path = os.path.join(self.basetestpath, 'test_renderregion.png')
        output_image.save(rendered_file_path, "PNG")
        self.assertTrue(self.checkImage('renderregion', 'renderregion', rendered_file_path))
def updateMask(control_image_path, rendered_image_path, mask_image_path):
    control_image = imageFromPath(control_image_path)
    if not control_image:
        error('Could not read control image {}'.format(control_image_path))

    rendered_image = imageFromPath(rendered_image_path)
    if not rendered_image:
        error('Could not read rendered image {}'.format(rendered_image_path))
    if not rendered_image.width() == control_image.width() or not rendered_image.height() == control_image.height():
        print ('Size mismatch - control image is {}x{}, rendered image is {}x{}'.format(control_image.width(),
                                                                                        control_image.height(),
                                                                                        rendered_image.width(),
                                                                                        rendered_image.height()))

    max_width = min(rendered_image.width(), control_image.width())
    max_height = min(rendered_image.height(), control_image.height())

    #read current mask, if it exist
    mask_image = imageFromPath(mask_image_path)
    if mask_image.isNull():
        print 'Mask image does not exist, creating {}'.format(mask_image_path)
        mask_image = QImage(control_image.width(), control_image.height(), QImage.Format_ARGB32)
        mask_image.fill(QColor(0, 0, 0))

    #loop through pixels in rendered image and compare
    mismatch_count = 0
    linebytes = max_width * 4
    for y in xrange(max_height):
        control_scanline = control_image.constScanLine(y).asstring(linebytes)
        rendered_scanline = rendered_image.constScanLine(y).asstring(linebytes)
        mask_scanline = mask_image.scanLine(y).asstring(linebytes)

        for x in xrange(max_width):
            currentTolerance = qRed(struct.unpack('I', mask_scanline[x * 4:x * 4 + 4])[0])

            if currentTolerance == 255:
                #ignore pixel
                continue

            expected_rgb = struct.unpack('I', control_scanline[x * 4:x * 4 + 4])[0]
            rendered_rgb = struct.unpack('I', rendered_scanline[x * 4:x * 4 + 4])[0]
            difference = colorDiff(expected_rgb, rendered_rgb)

            if difference > currentTolerance:
                #update mask image
                mask_image.setPixel(x, y, qRgb(difference, difference, difference))
                mismatch_count += 1

    if mismatch_count:
        #update mask
        mask_image.save(mask_image_path, "png")
        print 'Updated {} pixels in {}'.format(mismatch_count, mask_image_path)
    else:
        print 'No mismatches in {}'.format(mask_image_path)
    def getCachedImage(self, project, request, key):
        m = hashlib.md5()
        paramMap = request.parameters()
        urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
        m.update(urlParam.encode('utf8'))

        if not os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")):
            return QByteArray()

        img = QImage(m.hexdigest() + ".png")
        with open(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "rb") as f:
            statusOK = img.loadFromData(f.read())
            if not statusOK:
                print("Could not read or find the contents document. Error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr))
                return QByteArray()

        ba = QByteArray()
        buff = QBuffer(ba)
        buff.open(QIODevice.WriteOnly)
        img.save(buff, 'PNG')
        return ba
    def renderAnnotation(self, annotation, offset):
        image = QImage(600, 400, QImage.Format_RGB32)
        image.fill(QColor(0, 0, 0, 0))
        QgsRenderChecker.drawBackground(image)

        painter = QPainter()
        ms = QgsMapSettings()
        ms.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
        extent = QgsRectangle(0, 5, 40, 30)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        painter.translate(offset.x(), offset.y())
        annotation.render(context)
        painter.end()
        return image
Exemple #22
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
    def testSetCacheImages(self):
        cache = QgsMapRendererCache()
        # not set image
        im = cache.cacheImage('littlehands')
        self.assertTrue(im.isNull())
        self.assertFalse(cache.hasCacheImage('littlehands'))

        # set image
        im = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('littlehands', im)
        self.assertFalse(im.isNull())
        self.assertEqual(cache.cacheImage('littlehands'), im)
        self.assertTrue(cache.hasCacheImage('littlehands'))

        # test another not set image when cache has images
        self.assertTrue(cache.cacheImage('bad').isNull())
        self.assertFalse(cache.hasCacheImage('bad'))

        # clear cache image
        cache.clearCacheImage('not in cache')  # no crash!
        cache.clearCacheImage('littlehands')
        im = cache.cacheImage('littlehands')
        self.assertTrue(im.isNull())
        self.assertFalse(cache.hasCacheImage('littlehands'))

        # clear whole cache
        im = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('littlehands', im)
        self.assertFalse(im.isNull())
        self.assertTrue(cache.hasCacheImage('littlehands'))
        cache.clear()
        im = cache.cacheImage('littlehands')
        self.assertTrue(im.isNull())
        self.assertFalse(cache.hasCacheImage('littlehands'))
 def __signal_pbSaveImg_clicked(self, cheked):
     if type(self.__fileNameImg) == tuple:
         self.__fileNameImg = self.__fileNameImg[0]
     fileName = QFileDialog.getSaveFileName(self,
                                            QApplication.translate(
                                                "OpenLayersOverviewWidget",
                                                "Save image"),
                                            self.__fileNameImg,
                                            QApplication.translate(
                                                "OpenLayersOverviewWidget",
                                                "Image(*.jpg)"))
     if not fileName == '':
         self.__fileNameImg = fileName
     else:
         return
     img = QImage(self.webViewMap.page().mainFrame().contentsSize(),
                  QImage.Format_ARGB32_Premultiplied)
     imgPainter = QPainter()
     imgPainter.begin(img)
     self.webViewMap.page().mainFrame().render(imgPainter)
     imgPainter.end()
     img.save(fileName[0], "JPEG")
Exemple #25
0
def qt_svg_to_png_renderer(impact_report, component):
    """Render SVG into PNG.

    :param impact_report: ImpactReport contains data about the report that is
        going to be generated.
    :type impact_report: safe.report.impact_report.ImpactReport

    :param component: Contains the component metadata and context for
        rendering the output.
    :type component:
        safe.report.report_metadata.QgisComposerComponentsMetadata

    :return: Whatever type of output the component should be.

    .. versionadded:: 4.0
    """
    context = component.context
    filepath = context['filepath']
    width = component.extra_args['width']
    height = component.extra_args['height']
    image_format = QImage.Format_ARGB32
    qimage = QImage(width, height, image_format)
    qimage.fill(0x00000000)
    renderer = QSvgRenderer(filepath)
    painter = QPainter(qimage)
    renderer.render(painter)
    # Should call painter.end() so that QImage is not used
    painter.end()

    # in case output folder not specified
    if impact_report.output_folder is None:
        impact_report.output_folder = mkdtemp(dir=temp_dir())
    output_path = impact_report.component_absolute_output_path(
        component.key)

    qimage.save(output_path)

    component.output = output_path
    return component.output
Exemple #26
0
    def image(self):
        width = (self.xmax - self.xmin + 1) * self.TILE_SIZE
        height = (self.ymax - self.ymin + 1) * self.TILE_SIZE
        
        image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
        image.fill(Qt.transparent)
        p = QPainter(image)
        
        for tile in self.tiles.values():
            if not tile.data:
                continue

            x = tile.x - self.xmin
            y = tile.y - self.ymin
            rect = QRect(x * self.TILE_SIZE, y * self.TILE_SIZE, self.TILE_SIZE, self.TILE_SIZE)

            timg = QImage()
            res = timg.loadFromData(tile.data)
            if res:
                p.drawImage(rect, timg)

            if debug_mode:
                p.setPen(Qt.black)
                p.drawText(
                    rect,
                    Qt.AlignBottom | Qt.AlignRight,
                    # "x: %s, y:%s\nz: %s, data: %s" % (x, y, tile.zoom, tile.data.size())
                    "z: %s, data: %s" % (tile.zoom, tile.data.size())
                )
                if not res:
                    p.setPen(Qt.darkRed)
                    p.drawText(rect, Qt.AlignCenter, "Bad tile")

                p.setPen(Qt.black)
                p.drawRect(rect)

        return image
    def testSimpleLineWithCustomDashPattern(self):
        """ test that rendering a simple line symbol with custom dash pattern"""
        layer = QgsSimpleLineSymbolLayer(QColor(0, 0, 0))
        layer.setWidth(0.5)
        layer.setCustomDashVector([2, 5])
        layer.setUseCustomDashPattern(True)

        symbol = QgsLineSymbol()
        symbol.changeSymbolLayer(0, layer)

        image = QImage(200, 200, QImage.Format_RGB32)
        painter = QPainter()
        ms = QgsMapSettings()

        geom = QgsGeometry.fromWkt('LineString (0 0, 10 0, 10 10, 0 10, 0 0)')
        f = QgsFeature()
        f.setGeometry(geom)

        extent = geom.constGet().boundingBox()
        # buffer extent by 10%
        extent = extent.buffered((extent.height() + extent.width()) / 20.0)

        ms.setExtent(extent)
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI

        painter.begin(image)
        image.fill(QColor(255, 255, 255))

        symbol.startRender(context)
        symbol.renderFeature(f, context)
        symbol.stopRender(context)
        painter.end()

        self.assertTrue(self.imageCheck('symbol_layer_simpleline_customdashpattern', 'simpleline_customdashpattern', image))
Exemple #28
0
    def _get_composer_svg_image(self, width, height, dpi):
        # from qgscomposer.cpp, QgsComposer::on_mActionExportAsSVG_triggered,
        # near end of function
        svgpath = getTempfilePath('svg')
        temp_size = os.path.getsize(svgpath)

        svg_g = QSvgGenerator()
        # noinspection PyArgumentList
        svg_g.setTitle(QgsProject.instance().title())
        svg_g.setFileName(svgpath)
        svg_g.setSize(QSize(width, height))
        svg_g.setViewBox(QRect(0, 0, width, height))
        svg_g.setResolution(dpi)

        sp = QPainter(svg_g)
        self._c.renderPage(sp, 0)
        sp.end()

        if temp_size == os.path.getsize(svgpath):
            return False, ''

        image = QImage(width, height, self._TestMapSettings.outputImageFormat())
        image.fill(QColor(152, 219, 249).rgb())
        image.setDotsPerMeterX(dpi / 25.4 * 1000)
        image.setDotsPerMeterY(dpi / 25.4 * 1000)

        svgr = QSvgRenderer(svgpath)
        p = QPainter(image)
        p.setRenderHint(
            QPainter.Antialiasing,
            self._TestMapSettings.testFlag(QgsMapSettings.Antialiasing)
        )
        p.setRenderHint(QPainter.TextAntialiasing)
        svgr.render(p)
        p.end()

        filepath = getTempfilePath('png')
        res = image.save(filepath, 'png')
        if not res:
            os.unlink(filepath)
            filepath = ''
        # TODO: remove .svg file as well?

        return res, filepath
Exemple #29
0
 def __init__(self, canvas, filename, point):
     super().__init__(canvas)
     self._canvas = canvas
     self._filename = filename
     self._location = point
     self._image = QImage(self._filename)
Exemple #30
0
    def testPreviewColorRampHorizontalNoCheckboard(self):
        r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255))

        pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(200, 100), drawTransparentBackground=False)
        img = QImage(pix)
        self.assertTrue(self.imageCheck('color_ramp_no_check', 'color_ramp_no_check', img))
Exemple #31
0
class VideoWidgetSurface(QAbstractVideoSurface):

    def __init__(self, widget):
        ''' Constructor '''
        super().__init__()

        self.widget = widget
        self.imageFormat = QImage.Format_Invalid
        self.image = None

    def supportedPixelFormats(self, handleType=QAbstractVideoBuffer.NoHandle):
        ''' Available Frames Format '''
        formats = [QVideoFrame.PixelFormat()]
        if handleType == QAbstractVideoBuffer.NoHandle:
            for f in [QVideoFrame.Format_RGB32,
                      QVideoFrame.Format_ARGB32,
                      QVideoFrame.Format_ARGB32_Premultiplied,
                      QVideoFrame.Format_RGB565,
                      QVideoFrame.Format_RGB555
                      ]:
                formats.append(f)
        return formats

    def isFormatSupported(self, _format):
        ''' Check if is supported VideFrame format '''
        imageFormat = QVideoFrame.imageFormatFromPixelFormat(
            _format.pixelFormat())
        size = _format.frameSize()
        _bool = False
        if (imageFormat != QImage.Format_Invalid and not
            size.isEmpty() and
                _format.handleType() == QAbstractVideoBuffer.NoHandle):
            _bool = True
        return _bool

    def start(self, _format):
        ''' Start QAbstractVideoSurface '''
        imageFormat = QVideoFrame.imageFormatFromPixelFormat(
            _format.pixelFormat())
        size = _format.frameSize()
        if (imageFormat != QImage.Format_Invalid and not size.isEmpty()):
            self._sourceRect = _format.viewport()
            QAbstractVideoSurface.start(self, _format)
            self.imageFormat = imageFormat
            self.imageSize = size
            self.widget.updateGeometry()
            self.updateVideoRect()
            return True
        else:
            return False

    def stop(self):
        ''' Stop Video '''
        self._currentFrame = QVideoFrame()
        self._targetRect = QRect()
        QAbstractVideoSurface.stop(self)
        self.widget.update()

    def present(self, frame):
        ''' Present Frame '''
        if (self.surfaceFormat().pixelFormat() != frame.pixelFormat() or
                self.surfaceFormat().frameSize() != frame.size()):
            self.setError(QAbstractVideoSurface.IncorrectFormatError)
            # if is a hight quality frame is stopped and not call start function
            # self.stop()
            return False
        else:
            self._currentFrame = frame
            self.widget.update()
            return True

    def videoRect(self):
        ''' Get Video Rectangle '''
        return self._targetRect

    def sourceRect(self):
        ''' Get Source Rectangle '''
        return self._sourceRect

    def updateVideoRect(self):
        ''' Update video rectangle '''
        size = self.surfaceFormat().sizeHint()
        size.scale(self.widget.size().boundedTo(size), Qt.KeepAspectRatio)
        self._targetRect = QRect(QPoint(0, 0), size)
        self._targetRect.moveCenter(self.widget.rect().center())

    def paint(self, painter):
        ''' Paint Frame'''
        if (self._currentFrame.map(QAbstractVideoBuffer.ReadOnly)):
            oldTransform = painter.transform()
            painter.setTransform(oldTransform)

        self.image = QImage(self._currentFrame.bits(),
                            self._currentFrame.width(),
                            self._currentFrame.height(),
                            self._currentFrame.bytesPerLine(),
                            self.imageFormat
                            )

        if self.widget._filterSatate.grayColorFilter:
            self.image = filter.GrayFilter(self.image)

        if self.widget._filterSatate.MirroredHFilter:
            self.image = filter.MirrredFilter(self.image)

        if self.widget._filterSatate.monoFilter:
            self.image = filter.MonoFilter(self.image)

        if self.widget._filterSatate.invertColorFilter:
            self.image.invertPixels()

        # TODO : Test in other thread
        if self.widget._filterSatate.edgeDetectionFilter:
            try:
                self.image = filter.EdgeFilter(self.image)
            except Exception:
                None
        # TODO : Test in other thread
        if self.widget._filterSatate.contrastFilter:
            try:
                self.image = filter.AutoContrastFilter(self.image)
            except Exception:
                None

        # TODO : Test in other thread
        if self.widget._filterSatate.NDVI:
            try:
                self.image = filter.NDVIFilter(self.image)
            except Exception:
                None

        painter.drawImage(self._targetRect, self.image, self._sourceRect)
        self._currentFrame.unmap()
        return
Exemple #32
0
class CentroidDecorator(QgsMapCanvasItem):
    """
    Decorates centroids of features with population statistics
    """
    def __init__(self, canvas: QgsMapCanvas, electorate_layer: QgsVectorLayer,
                 meshblock_layer: QgsVectorLayer, task: str):
        """
        Constructor
        :param canvas: map canvas
        :param electorate_layer: electorates layer
        :param meshblock_layer: meshblocks layer
        :param task: current task
        """
        super().__init__(canvas)
        self.canvas = canvas
        self.electorate_layer = electorate_layer
        self.meshblock_layer = meshblock_layer
        self.task = task
        self.text_format = QgsTextFormat()
        # self.text_format.shadow().setEnabled(True)
        self.text_format.background().setEnabled(True)
        self.text_format.background().setSize(QSizeF(1, 0))
        self.text_format.background().setOffset(QPointF(0, -0.7))
        self.text_format.background().setRadii(QSizeF(1, 1))
        self.image = None

    def redraw(self):
        """
        Forces a redraw of the cached image
        """
        self.image = None

    def paint(self, painter, option, widget):  # pylint: disable=missing-docstring, unused-argument, too-many-locals
        if self.image is not None:
            painter.drawImage(0, 0, self.image)
            return

        image_size = self.canvas.mapSettings().outputSize()
        self.image = QImage(image_size.width(), image_size.height(),
                            QImage.Format_ARGB32)
        self.image.fill(0)
        image_painter = QPainter(self.image)
        render_context = QgsRenderContext.fromQPainter(image_painter)

        image_painter.setRenderHint(QPainter.Antialiasing, True)

        rect = self.canvas.mapSettings().visibleExtent()
        request = QgsFeatureRequest()
        request.setFilterRect(rect)
        request.setFilterExpression(
            QgsExpression.createFieldEqualityExpression('type', self.task))

        for f in self.electorate_layer.getFeatures(request):
            #    pole, dist = f.geometry().clipped(rect).poleOfInaccessibility(rect.width() / 30)
            pixel = self.toCanvasCoordinates(
                f.geometry().clipped(rect).centroid().asPoint())

            calc = QgsAggregateCalculator(self.meshblock_layer)
            calc.setFilter('staged_electorate={}'.format(f['electorate_id']))
            estimated_pop, ok = calc.calculate(QgsAggregateCalculator.Sum,
                                               'offline_pop_{}'.format(
                                                   self.task.lower()))  # pylint: disable=unused-variable

            text_string = [
                '{}'.format(f['name']), '{}'.format(int(estimated_pop))
            ]
            QgsTextRenderer().drawText(QPointF(pixel.x(), pixel.y()), 0,
                                       QgsTextRenderer.AlignCenter,
                                       text_string, render_context,
                                       self.text_format)

        image_painter.end()

        painter.drawImage(0, 0, self.image)
    def test_wms_getprint_maptheme(self):
        """Test templates green and red have 2 layers: red and green
            template red: follow map theme red
            template green: follow map theme green
            template blank: no map theme
        """

        project = self.project

        params = {
            "SERVICE": "WMS",
            "VERSION": "1.3.0",
            "REQUEST": "GetPrint",
            "TEMPLATE": "blank",
            "FORMAT": "png",
            "LAYERS": "",
            "map0:EXTENT": "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368",
            "map0:LAYERS": "red",
            "CRS": "EPSG:4326",
            "DPI": '72'
        }

        ######################################################
        # Template map theme tests, no HIGHLIGHT

        # blank template, specified layer is red
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # blank template, specified layer is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # red template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # green template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # green template, specified layer is red
        # This is a conflict situation: the green template map is set to follow green theme
        # but we tell the server to render the red layer, red is what we get.
        params["map0:LAYERS"] = "red"
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # Same situation as above but LAYERS is not map0 prefixed
        params["LAYERS"] = "red"
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # Same as above but we have a conflict situation: we pass both LAYERS
        # and map0:LAYERS, the second must prevail because it is more specific
        params["LAYERS"] = "red"
        params["map0:LAYERS"] = "green"
        params["TEMPLATE"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))
Exemple #34
0
    def setup_map(self):
        rendererContext = self.context

        # FIXME: self.mapSettings.outputDpi()
        self.outputDpi = rendererContext.painter().device().logicalDpiX()
        debug(" extent: %s" % rendererContext.extent().toString(), 3)
        debug(
            " center: %lf, %lf" % (rendererContext.extent().center().x(),
                                   rendererContext.extent().center().y()), 3)
        debug(
            " size: %d, %d" %
            (rendererContext.painter().viewport().size().width(),
             rendererContext.painter().viewport().size().height()), 3)
        debug(
            " logicalDpiX: %d" %
            rendererContext.painter().device().logicalDpiX(), 3)
        debug(" outputDpi: %lf" % self.outputDpi)
        debug(
            " mapUnitsPerPixel: %f" %
            rendererContext.mapToPixel().mapUnitsPerPixel(), 3)
        # debug(" rasterScaleFactor: %s" % str(rendererContext.
        #                                      rasterScaleFactor()), 3)
        # debug(" outputSize: %d, %d" % (self.iface.mapCanvas().mapRenderer().
        #                                outputSize().width(),
        #                                self.iface.mapCanvas().mapRenderer().
        #                                outputSize().height()), 3)
        # debug(" scale: %lf" % self.iface.mapCanvas().mapRenderer().scale(),
        #                                3)
        #
        # if (self.page.lastExtent == rendererContext.extent()
        #         and self.page.lastViewPortSize == rendererContext.painter().
        #         viewport().size()
        #         and self.page.lastLogicalDpi == rendererContext.painter().
        #         device().logicalDpiX()
        #         and self.page.lastOutputDpi == self.outputDpi
        #         and self.page.lastMapUnitsPerPixel == rendererContext.
        #         mapToPixel().mapUnitsPerPixel()):
        #     self.renderMap()
        #     self.finished.emit()
        #     return

        self.targetSize = rendererContext.painter().viewport().size()
        if rendererContext.painter().device().logicalDpiX() != int(
                self.outputDpi):
            # use screen dpi for printing
            sizeFact = self.outputDpi / 25.4 / rendererContext.mapToPixel(
            ).mapUnitsPerPixel()
            self.targetSize.setWidth(rendererContext.extent().width() *
                                     sizeFact)
            self.targetSize.setHeight(rendererContext.extent().height() *
                                      sizeFact)
        debug(
            " targetSize: %d, %d" %
            (self.targetSize.width(), self.targetSize.height()), 3)

        # find matching OL resolution
        qgisRes = rendererContext.extent().width() / self.targetSize.width()
        olRes = None
        for res in self.page.resolutions():
            if qgisRes >= res:
                olRes = res
                break
        if olRes is None:
            debug("No matching OL resolution found (QGIS resolution: %f)" %
                  qgisRes)
            self.emitErrorImage()
            return

        # adjust OpenLayers viewport to match QGIS extent
        olWidth = rendererContext.extent().width() / olRes
        olHeight = rendererContext.extent().height() / olRes
        debug(
            "    adjust viewport: %f -> %f: %f x %f" %
            (qgisRes, olRes, olWidth, olHeight), 3)
        olSize = QSize(int(olWidth), int(olHeight))
        self.page.setViewportSize(olSize)
        self.page.mainFrame().evaluateJavaScript("map.updateSize();")
        self.img = QImage(olSize, QImage.Format_ARGB32_Premultiplied)

        self.page.extent = rendererContext.extent()
        debug(
            "map.zoomToExtent (%f, %f, %f, %f)" %
            (self.page.extent.xMinimum(), self.page.extent.yMinimum(),
             self.page.extent.xMaximum(), self.page.extent.yMaximum()), 3)
        self.page.mainFrame().evaluateJavaScript(
            "map.zoomToExtent(new OpenLayers.Bounds(%f, %f, %f, %f), true);" %
            (self.page.extent.xMinimum(), self.page.extent.yMinimum(),
             self.page.extent.xMaximum(), self.page.extent.yMaximum()))
        olextent = self.page.mainFrame().evaluateJavaScript("map.getExtent();")
        debug("Resulting OL extent: %s" % olextent, 3)
        if olextent is None or not hasattr(olextent, '__getitem__'):
            debug("map.zoomToExtent failed")
            # map.setCenter and other operations throw "undefined[0]:
            # TypeError: 'null' is not an object" on first page load
            # We ignore that and render the initial map with wrong extents
            # self.emitErrorImage()
            # return
        else:
            reloffset = abs((self.page.extent.yMaximum() - olextent["top"]) /
                            self.page.extent.xMinimum())
            debug("relative offset yMaximum %f" % reloffset, 3)
            if reloffset > 0.1:
                debug("OL extent shift failure: %s" % reloffset)
                self.emitErrorImage()
                return
        self.mapFinished = False
        self.timer.start()
        self.timerMax.start()
    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)
Exemple #36
0
def toSpriteSheet(allSprites):
    if allSprites:
        height = spriteSize
        width = spriteSize * len(allSprites)
        img = QImage(width, height, QImage.Format_ARGB32)
        img.fill(QColor(Qt.transparent))
        img2x = QImage(width * 2, height * 2, QImage.Format_ARGB32)
        img2x.fill(QColor(Qt.transparent))
        painter = QPainter(img)
        painter.begin(img)
        painter2x = QPainter(img2x)
        painter2x.begin(img2x)
        spritesheet = {
            NO_ICON: {
                "width": 0,
                "height": 0,
                "x": 0,
                "y": 0,
                "pixelRatio": 1
            }
        }
        spritesheet2x = {
            NO_ICON: {
                "width": 0,
                "height": 0,
                "x": 0,
                "y": 0,
                "pixelRatio": 1
            }
        }
        x = 0
        for name, _sprites in allSprites.items():
            s = _sprites["image"]
            s2x = _sprites["image2x"]
            painter.drawImage(x, 0, s)
            painter2x.drawImage(x * 2, 0, s2x)
            spritesheet[name] = {
                "width": s.width(),
                "height": s.height(),
                "x": x,
                "y": 0,
                "pixelRatio": 1
            }
            spritesheet2x[name] = {
                "width": s2x.width(),
                "height": s2x.height(),
                "x": x * 2,
                "y": 0,
                "pixelRatio": 2
            }
            x += s.width()
        painter.end()
        painter2x.end()
        folder = "/Users/ddd/delme/"
        img.save(os.path.join(folder, "spriteSheet.png"))
        img2x.save(os.path.join(folder, "*****@*****.**"))
        with open(os.path.join(folder, "spriteSheet.json"), 'w') as f:
            json.dump(spritesheet, f)
        with open(os.path.join(folder, "*****@*****.**"), 'w') as f:
            json.dump(spritesheet2x, f)

        return {
            "img": img,
            "img2x": img2x,
            "json": json.dumps(spritesheet),
            "json2x": json.dumps(spritesheet2x)
        }

    return None
Exemple #37
0
    def testColorFromMimeData(self):
        data = QMimeData()
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertFalse(color.isValid())

        # color data
        data.setColorData(QColor(255, 0, 255))
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        # should be true regardless of the actual color's opacity -- a QColor object has innate knowledge of the alpha,
        # so our input color HAS an alpha of 255
        self.assertTrue(has_alpha)
        self.assertEqual(color.alpha(), 255)

        data.setColorData(QColor(255, 0, 255, 100))
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertEqual(color.alpha(), 100)
        self.assertTrue(has_alpha)

        # text data
        data = QMimeData()
        data.setText('#ff00ff')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        # should be False -- no alpha was specified
        self.assertFalse(has_alpha)
        self.assertEqual(color.alpha(), 255)

        data.setText('#ff00ff66')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertTrue(has_alpha)
        self.assertEqual(color.alpha(), 102)

        # "#" is optional
        data.setText('ff00ff66')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertTrue(has_alpha)
        self.assertEqual(color.alpha(), 102)

        data.setText('255,0,255')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertFalse(has_alpha)
        self.assertEqual(color.alpha(), 255)

        data.setText('255,0,255,0.5')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertTrue(has_alpha)
        self.assertEqual(color.alpha(), 128)

        data.setText('rgba(255,0,255,0.5)')
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertTrue(color.isValid())
        self.assertEqual(color.name(), '#ff00ff')
        self.assertTrue(has_alpha)
        self.assertEqual(color.alpha(), 128)

        # wrong data type
        data = QMimeData()
        data.setImageData(QImage())
        color, has_alpha = QgsSymbolLayerUtils.colorFromMimeData(data)
        self.assertFalse(color.isValid())
Exemple #38
0
    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
Exemple #39
0
def saveSpritesSheet(icons, folder):
    sprites = {}
    for iconPath, sl in icons.items():
        iconName = os.path.splitext(os.path.basename(iconPath))[0]
        sprites[iconName] = saveSymbolLayerSprite(sl)
    if sprites:
        height = max([s.height() for s, s2x in sprites.values()])
        width = sum([s.width() for s, s2x in sprites.values()])
        img = QImage(width, height, QImage.Format_ARGB32)
        img.fill(QColor(Qt.transparent))
        img2x = QImage(width * 2, height * 2, QImage.Format_ARGB32)
        img2x.fill(QColor(Qt.transparent))
        painter = QPainter(img)
        painter.begin(img)
        painter2x = QPainter(img2x)
        painter2x.begin(img2x)
        spritesheet = {
            NO_ICON: {
                "width": 0,
                "height": 0,
                "x": 0,
                "y": 0,
                "pixelRatio": 1
            }
        }
        spritesheet2x = {
            NO_ICON: {
                "width": 0,
                "height": 0,
                "x": 0,
                "y": 0,
                "pixelRatio": 1
            }
        }
        x = 0
        for name, _sprites in sprites.items():
            s, s2x = _sprites
            painter.drawImage(x, 0, s)
            painter2x.drawImage(x * 2, 0, s2x)
            spritesheet[name] = {
                "width": s.width(),
                "height": s.height(),
                "x": x,
                "y": 0,
                "pixelRatio": 1
            }
            spritesheet2x[name] = {
                "width": s2x.width(),
                "height": s2x.height(),
                "x": x * 2,
                "y": 0,
                "pixelRatio": 2
            }
            x += s.width()
        painter.end()
        painter2x.end()
        img.save(os.path.join(folder, "spriteSheet.png"))
        img2x.save(os.path.join(folder, "*****@*****.**"))
        with open(os.path.join(folder, "spriteSheet.json"), 'w') as f:
            json.dump(spritesheet, f)
        with open(os.path.join(folder, "*****@*****.**"), 'w') as f:
            json.dump(spritesheet2x, f)
Exemple #40
0
class PhotoViewer(QScrollArea):
    """
    Widget for viewing images by incorporating basic navigation options.
    """
    def __init__(self, parent=None, photo_path=""):
        QScrollArea.__init__(self, parent)
        self.setBackgroundRole(QPalette.Dark)

        self._printer = QPrinter()

        self._lbl_photo = QLabel()
        self._lbl_photo.setBackgroundRole(QPalette.Base)
        self._lbl_photo.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        self._lbl_photo.setScaledContents(True)

        self.setWidget(self._lbl_photo)

        self._photo_path = photo_path
        self._ph_image = None
        self._scale_factor = 1.0
        self._aspect_ratio = -1

        self._create_actions()

        if self._photo_path:
            self.load_document(self._photo_path)

    def _create_actions(self):
        """
        Create actions for basic image navigation.
        """
        self._zoom_in_act = QAction(
            QApplication.translate("PhotoViewer", "Zoom &In (25%)"), self)
        self._zoom_in_act.setShortcut(
            QApplication.translate("PhotoViewer", "Ctrl++"))
        self._zoom_in_act.setEnabled(False)
        self._zoom_in_act.triggered.connect(self.zoom_in)

        self._zoom_out_act = QAction(
            QApplication.translate("PhotoViewer", "Zoom &Out (25%)"), self)
        self._zoom_out_act.setShortcut(
            QApplication.translate("PhotoViewer", "Ctrl+-"))
        self._zoom_out_act.setEnabled(False)
        self._zoom_out_act.triggered.connect(self.zoom_out)

        self._normal_size_act = QAction(
            QApplication.translate("PhotoViewer", "&Normal Size"), self)
        self._normal_size_act.setShortcut(
            QApplication.translate("PhotoViewer", "Ctrl+S"))
        self._normal_size_act.setEnabled(False)
        self._normal_size_act.triggered.connect(self.normal_size)

        self._fit_to_window_act = QAction(
            QApplication.translate("PhotoViewer", "&Fit to Window"), self)
        self._fit_to_window_act.setShortcut(
            QApplication.translate("PhotoViewer", "Ctrl+F"))
        self._fit_to_window_act.setEnabled(False)
        self._fit_to_window_act.setCheckable(True)
        self._fit_to_window_act.triggered.connect(self.fit_to_window)

        self._print_act = QAction(
            QApplication.translate("PhotoViewer", "&Print"), self)
        self._print_act.setShortcut(
            QApplication.translate("PhotoViewer", "Ctrl+P"))
        self._print_act.setEnabled(False)
        self._print_act.triggered.connect(self.print_photo)

    def zoom_in(self):
        self.scale_photo(1.25)

    def zoom_out(self):
        self.scale_photo(0.8)

    def normal_size(self):
        self._lbl_photo.adjustSize()
        self._scale_factor = 1.0

    def fit_to_window(self):
        fit_to_win = self._fit_to_window_act.isChecked()
        self.setWidgetResizable(fit_to_win)

        if not fit_to_win:
            self.normal_size()

        self.update_actions()

    def print_photo(self):
        print_dialog = QPrintDialog(self._printer, self)

        if print_dialog.exec_() == QDialog.Accepted:
            painter = QPainter(self._printer)
            rect = painter.viewport()
            size = self._lbl_photo.pixmap().size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(),
                                size.height())
            painter.setWindow(self._lbl_photo.pixmap().rect())
            painter.drawPixmap(0, 0, self._lbl_photo.pixmap())

    def wheelEvent(self, event):
        """
        Zoom the image based on the mouse wheel rotation action.
        :param event: Event containing the wheel rotation info.
        :type event: QWheelEvent
        """
        degrees = event.delta() / 8
        num_steps = degrees / 15

        if num_steps < 0:
            abs_num_steps = abs(num_steps)
            zoom_factor = 1 + (abs_num_steps * 0.25)

        else:
            zoom_factor = 1 - (num_steps * 0.2)

        self.scale_photo(zoom_factor)

    def heightForWidth(self, width):
        if self._aspect_ratio != -1:
            return width / self._aspect_ratio

        else:
            return -1

    def resizeEvent(self, event):
        """
        Event for resizing the widget based on the pixmap's aspect ratio.
        :param event: Contains event parameters for the resize event.
        :type event: QResizeEvent
        """
        super(PhotoViewer, self).resizeEvent(event)

    def update_actions(self):
        self._zoom_out_act.setEnabled(not self._fit_to_window_act.isChecked())
        self._zoom_in_act.setEnabled(not self._fit_to_window_act.isChecked())
        self._normal_size_act.setEnabled(
            not self._fit_to_window_act.isChecked())

    def scale_photo(self, factor):
        """
        :param factor: Value by which the image will be increased/decreased in the view.
        :type factor: float
        """
        if not self._lbl_photo.pixmap().isNull():
            self._scale_factor *= factor
            self._lbl_photo.resize(self._scale_factor *
                                   self._lbl_photo.pixmap().size())

            self._adjust_scroll_bar(self.horizontalScrollBar(), factor)
            self._adjust_scroll_bar(self.verticalScrollBar(), factor)

            self._zoom_in_act.setEnabled(self._scale_factor < 3.0)
            self._zoom_out_act.setEnabled(self._scale_factor > 0.333)

    def _adjust_scroll_bar(self, scroll_bar, factor):
        scroll_bar.setValue(
            int(factor * scroll_bar.value() +
                ((factor - 1) * scroll_bar.pageStep() / 2)))

    def load_document(self, photo_path):
        if photo_path:
            self._ph_image = QImage(photo_path)

            if self._ph_image.isNull():
                return False

            self._photo_path = photo_path

            ph_pixmap = QPixmap.fromImage(self._ph_image)

            self._lbl_photo.setPixmap(ph_pixmap)
            self._scale_factor = 1.0

            self._aspect_ratio = ph_pixmap.width() / ph_pixmap.height()

            self._fit_to_window_act.setEnabled(True)
            self._print_act.setEnabled(True)
            self._fit_to_window_act.trigger()

            self.update_actions()
            return ph_pixmap

        return True

    def photo_location(self):
        """
        :returns: Absolute path of the photo in the central document repository.
        """
        return self._photo_path

    def set_actions(self, menu):
        """
        Add custom actions to the sub-window menu
        """
        menu.addSeparator()
        menu.addAction(self._zoom_in_act)
        menu.addAction(self._zoom_out_act)
        menu.addAction(self._normal_size_act)
        menu.addAction(self._fit_to_window_act)
        menu.addSeparator()
        menu.addAction(self._print_act)
Exemple #41
0
    def testPreviewColorRampHorizontal(self):
        r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255))

        pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(200, 100))
        img = QImage(pix)
        self.assertTrue(self.imageCheck('color_ramp_horizontal', 'color_ramp_horizontal', img))
    def test_atlas(self):
        """Test atlas"""

        qs = "?" + "&".join([
            "%s=%s" % i for i in list({
                'SERVICE': "WMS",
                'VERSION': "1.3.0",
                'REQUEST': "GetPrint",
                'CRS': 'EPSG:4326',
                'FORMAT': 'png',
                'LAYERS': 'multiple_pks',
                'DPI': 72,
                'TEMPLATE': "print1",
            }.items())
        ])

        req = QgsBufferServerRequest('http://my_server/' + qs +
                                     '&ATLAS_PK=1,2')
        res = QgsBufferServerResponse()

        self._server.handleRequest(req, res, self.test_project)
        self.assertEqual(res.statusCode(), 200)

        result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png')
        with open(result_path, 'wb+') as f:
            f.write(res.body())

        # A full red image is expected
        image = QImage(result_path)
        self.assertFalse(image.isGrayscale())
        color = image.pixelColor(100, 100)
        self.assertEqual(color.red(), 255)
        self.assertEqual(color.green(), 0)
        self.assertEqual(color.blue(), 0)

        # Forbid 1-1
        self._accesscontrol.active['layerFilterSubsetString'] = True
        self._check_exception(qs + '&ATLAS_PK=1,2',
                              "Atlas error: empty atlas.")

        self._accesscontrol.active['layerFilterSubsetString'] = False
        self._accesscontrol.active['layerFilterExpression'] = True
        self._check_exception(qs + '&ATLAS_PK=1,2',
                              "Atlas error: empty atlas.")

        # Remove all constraints
        self._clear_constraints()
        req = QgsBufferServerRequest('http://my_server/' + qs +
                                     '&ATLAS_PK=1,2')
        res = QgsBufferServerResponse()

        self._server.handleRequest(req, res, self.test_project)
        self.assertEqual(res.statusCode(), 200)

        result_path = os.path.join(self.temp_dir.path(), 'atlas_1_2.png')
        with open(result_path, 'wb+') as f:
            f.write(res.body())

        # A full red image is expected
        image = QImage(result_path)
        self.assertFalse(image.isGrayscale())
        color = image.pixelColor(100, 100)
        self.assertEqual(color.red(), 255)
        self.assertEqual(color.green(), 0)
        self.assertEqual(color.blue(), 0)
Exemple #43
0
class OpenlayersController(QObject):
    """
    Helper class that deals with QWebPage.
    The object lives in GUI thread, its request() slot is asynchronously called
    from worker thread.
    See https://github.com/wonder-sk/qgis-mtr-example-plugin for basic example
    1. Load Web Page with OpenLayers map
    2. Update OL map extend according to QGIS canvas extent
    """

    # signal that reports to the worker thread that the image is ready
    finished = pyqtSignal()

    def __init__(self, parent, context, webPage, layerType):
        QObject.__init__(self, parent)

        debug("OpenlayersController.__init__", 3)
        self.context = context
        self.layerType = layerType

        self.img = QImage()

        self.page = webPage
        self.page.loadFinished.connect(self.pageLoaded)
        # initial size for map
        self.page.setViewportSize(QSize(1, 1))

        self.timerMapReady = QTimer()
        self.timerMapReady.setSingleShot(True)
        self.timerMapReady.setInterval(20)
        self.timerMapReady.timeout.connect(self.checkMapReady)

        self.timer = QTimer()
        self.timer.setInterval(100)
        self.timer.timeout.connect(self.checkMapUpdate)

        self.timerMax = QTimer()
        self.timerMax.setSingleShot(True)
        # TODO: different timeouts for map types
        self.timerMax.setInterval(5000)
        self.timerMax.timeout.connect(self.mapTimeout)

    @pyqtSlot()
    def request(self):
        debug("[GUI THREAD] Processing request", 3)
        self.cancelled = False

        if not self.page.loaded:
            self.init_page()
        else:
            self.setup_map()

    def init_page(self):
        url = self.layerType.html_url()
        debug("page file: %s" % url)
        self.page.mainFrame().load(QUrl(url))
        # wait for page to finish loading
        debug("OpenlayersWorker waiting for page to load", 3)

    def pageLoaded(self):
        debug("[GUI THREAD] pageLoaded", 3)
        try:
            if self.cancelled:
                self.emitErrorImage()
                return
        except:
            # if you spam the addmap button in the overview then an error
            # appears where self.cancelled is not known/defined
            debug(
                "Exception raised while adding too many OpenlayersLayer at the same time",
                4)

        # wait until OpenLayers map is ready
        self.checkMapReady()

    def checkMapReady(self):
        debug("[GUI THREAD] checkMapReady", 3)
        if self.page.mainFrame().evaluateJavaScript("map != undefined"):
            # map ready
            self.page.loaded = True
            self.setup_map()
        else:
            # wait for map
            self.timerMapReady.start()

    def setup_map(self):
        rendererContext = self.context

        # FIXME: self.mapSettings.outputDpi()
        self.outputDpi = rendererContext.painter().device().logicalDpiX()
        debug(" extent: %s" % rendererContext.extent().toString(), 3)
        debug(
            " center: %lf, %lf" % (rendererContext.extent().center().x(),
                                   rendererContext.extent().center().y()), 3)
        debug(
            " size: %d, %d" %
            (rendererContext.painter().viewport().size().width(),
             rendererContext.painter().viewport().size().height()), 3)
        debug(
            " logicalDpiX: %d" %
            rendererContext.painter().device().logicalDpiX(), 3)
        debug(" outputDpi: %lf" % self.outputDpi)
        debug(
            " mapUnitsPerPixel: %f" %
            rendererContext.mapToPixel().mapUnitsPerPixel(), 3)
        # debug(" rasterScaleFactor: %s" % str(rendererContext.
        #                                      rasterScaleFactor()), 3)
        # debug(" outputSize: %d, %d" % (self.iface.mapCanvas().mapRenderer().
        #                                outputSize().width(),
        #                                self.iface.mapCanvas().mapRenderer().
        #                                outputSize().height()), 3)
        # debug(" scale: %lf" % self.iface.mapCanvas().mapRenderer().scale(),
        #                                3)
        #
        # if (self.page.lastExtent == rendererContext.extent()
        #         and self.page.lastViewPortSize == rendererContext.painter().
        #         viewport().size()
        #         and self.page.lastLogicalDpi == rendererContext.painter().
        #         device().logicalDpiX()
        #         and self.page.lastOutputDpi == self.outputDpi
        #         and self.page.lastMapUnitsPerPixel == rendererContext.
        #         mapToPixel().mapUnitsPerPixel()):
        #     self.renderMap()
        #     self.finished.emit()
        #     return

        self.targetSize = rendererContext.painter().viewport().size()
        if rendererContext.painter().device().logicalDpiX() != int(
                self.outputDpi):
            # use screen dpi for printing
            sizeFact = self.outputDpi / 25.4 / rendererContext.mapToPixel(
            ).mapUnitsPerPixel()
            self.targetSize.setWidth(rendererContext.extent().width() *
                                     sizeFact)
            self.targetSize.setHeight(rendererContext.extent().height() *
                                      sizeFact)
        debug(
            " targetSize: %d, %d" %
            (self.targetSize.width(), self.targetSize.height()), 3)

        # find matching OL resolution
        qgisRes = rendererContext.extent().width() / self.targetSize.width()
        olRes = None
        for res in self.page.resolutions():
            if qgisRes >= res:
                olRes = res
                break
        if olRes is None:
            debug("No matching OL resolution found (QGIS resolution: %f)" %
                  qgisRes)
            self.emitErrorImage()
            return

        # adjust OpenLayers viewport to match QGIS extent
        olWidth = rendererContext.extent().width() / olRes
        olHeight = rendererContext.extent().height() / olRes
        debug(
            "    adjust viewport: %f -> %f: %f x %f" %
            (qgisRes, olRes, olWidth, olHeight), 3)
        olSize = QSize(int(olWidth), int(olHeight))
        self.page.setViewportSize(olSize)
        self.page.mainFrame().evaluateJavaScript("map.updateSize();")
        self.img = QImage(olSize, QImage.Format_ARGB32_Premultiplied)

        self.page.extent = rendererContext.extent()
        debug(
            "map.zoomToExtent (%f, %f, %f, %f)" %
            (self.page.extent.xMinimum(), self.page.extent.yMinimum(),
             self.page.extent.xMaximum(), self.page.extent.yMaximum()), 3)
        self.page.mainFrame().evaluateJavaScript(
            "map.zoomToExtent(new OpenLayers.Bounds(%f, %f, %f, %f), true);" %
            (self.page.extent.xMinimum(), self.page.extent.yMinimum(),
             self.page.extent.xMaximum(), self.page.extent.yMaximum()))
        olextent = self.page.mainFrame().evaluateJavaScript("map.getExtent();")
        debug("Resulting OL extent: %s" % olextent, 3)
        if olextent is None or not hasattr(olextent, '__getitem__'):
            debug("map.zoomToExtent failed")
            # map.setCenter and other operations throw "undefined[0]:
            # TypeError: 'null' is not an object" on first page load
            # We ignore that and render the initial map with wrong extents
            # self.emitErrorImage()
            # return
        else:
            reloffset = abs((self.page.extent.yMaximum() - olextent["top"]) /
                            self.page.extent.xMinimum())
            debug("relative offset yMaximum %f" % reloffset, 3)
            if reloffset > 0.1:
                debug("OL extent shift failure: %s" % reloffset)
                self.emitErrorImage()
                return
        self.mapFinished = False
        self.timer.start()
        self.timerMax.start()

    def checkMapUpdate(self):
        if self.layerType.emitsLoadEnd:
            # wait for OpenLayers to finish loading
            try:
                loadEndOL = self.page.mainFrame().evaluateJavaScript("loadEnd")
                debug(
                    "waiting for loadEnd: renderingStopped=%r loadEndOL=%r" %
                    (self.context.renderingStopped(), loadEndOL), 4)
            except:
                # Multi threading problem when deleting multiple Openlayers layers
                debug(
                    "Exception raised while deleting multiple Openlayers layers",
                    4)
            if loadEndOL is not None:
                self.mapFinished = loadEndOL
            else:
                debug("OpenlayersLayer Warning: Could not get loadEnd")

        if self.mapFinished:
            self.timerMax.stop()
            self.timer.stop()

            self.renderMap()

            self.finished.emit()

    def renderMap(self):
        rendererContext = self.context
        if rendererContext.painter().device().logicalDpiX() != int(
                self.outputDpi):
            printScale = 25.4 / self.outputDpi  # OL DPI to printer pixels
            rendererContext.painter().scale(printScale, printScale)

        # render OpenLayers to image
        painter = QPainter(self.img)
        self.page.mainFrame().render(painter)
        painter.end()

        if self.img.size() != self.targetSize:
            targetWidth = self.targetSize.width()
            targetHeight = self.targetSize.height()
            # scale using QImage for better quality
            debug(
                "    scale image: %i x %i -> %i x %i" %
                (self.img.width(), self.img.height(), targetWidth,
                 targetHeight), 3)
            self.img = self.img.scaled(targetWidth, targetHeight,
                                       Qt.KeepAspectRatio,
                                       Qt.SmoothTransformation)

        # save current state
        self.page.lastExtent = rendererContext.extent()
        self.page.lastViewPortSize = rendererContext.painter().viewport().size(
        )
        self.page.lastLogicalDpi = rendererContext.painter().device(
        ).logicalDpiX()
        self.page.lastOutputDpi = self.outputDpi
        self.page.lastMapUnitsPerPixel = rendererContext.mapToPixel(
        ).mapUnitsPerPixel()

    def mapTimeout(self):
        debug("mapTimeout reached")
        self.timer.stop()
        # if not self.layerType.emitsLoadEnd:
        self.renderMap()
        self.finished.emit()

    def emitErrorImage(self):
        self.img = QImage()
        self.targetSize = self.img.size
        self.finished.emit()
Exemple #44
0
    def testRequestRepaintMultiple(self):
        """ test requesting repaint with multiple dependent layers """
        layer1 = QgsVectorLayer("Point?field=fldtxt:string", "layer1",
                                "memory")
        layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2",
                                "memory")
        QgsProject.instance().addMapLayers([layer1, layer2])
        self.assertTrue(layer1.isValid())
        self.assertTrue(layer2.isValid())

        # add image to cache - no dependent layers
        cache = QgsMapRendererCache()
        im1 = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('nolayer', im1)
        self.assertFalse(cache.cacheImage('nolayer').isNull())
        self.assertTrue(cache.hasCacheImage('nolayer'))

        # trigger repaint on layer
        layer1.triggerRepaint()
        layer1.triggerRepaint(
        )  # do this a couple of times - we don't want errors due to multiple disconnects, etc
        layer2.triggerRepaint()
        layer2.triggerRepaint()
        # cache image should still exist - it's not dependent on layers
        self.assertFalse(cache.cacheImage('nolayer').isNull())
        self.assertTrue(cache.hasCacheImage('nolayer'))

        # image depends on 1 layer
        im_l1 = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('im1', im_l1, [layer1])

        # image depends on 2 layers
        im_l1_l2 = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('im1_im2', im_l1_l2, [layer1, layer2])

        # image depends on 2nd layer alone
        im_l2 = QImage(200, 200, QImage.Format_RGB32)
        cache.setCacheImage('im2', im_l2, [layer2])

        self.assertFalse(cache.cacheImage('im1').isNull())
        self.assertTrue(cache.hasCacheImage('im1'))
        self.assertFalse(cache.cacheImage('im1_im2').isNull())
        self.assertTrue(cache.hasCacheImage('im1_im2'))
        self.assertFalse(cache.cacheImage('im2').isNull())
        self.assertTrue(cache.hasCacheImage('im2'))

        # trigger repaint layer 1 (check twice - don't want disconnect errors)
        for i in range(2):
            layer1.triggerRepaint()
            # should be cleared
            self.assertTrue(cache.cacheImage('im1').isNull())
            self.assertFalse(cache.hasCacheImage('im1'))
            self.assertTrue(cache.cacheImage('im1_im2').isNull())
            self.assertFalse(cache.hasCacheImage('im1_im2'))
            # should be retained
            self.assertTrue(cache.hasCacheImage('im2'))
            self.assertFalse(cache.cacheImage('im2').isNull())
            self.assertEqual(cache.cacheImage('im2'), im_l2)
            self.assertTrue(cache.hasCacheImage('nolayer'))
            self.assertFalse(cache.cacheImage('nolayer').isNull())
            self.assertEqual(cache.cacheImage('nolayer'), im1)

        # trigger repaint layer 2
        for i in range(2):
            layer2.triggerRepaint()
            # should be cleared
            self.assertFalse(cache.hasCacheImage('im1'))
            self.assertTrue(cache.cacheImage('im1').isNull())
            self.assertFalse(cache.hasCacheImage('im1_im2'))
            self.assertTrue(cache.cacheImage('im1_im2').isNull())
            self.assertFalse(cache.hasCacheImage('im2'))
            self.assertTrue(cache.cacheImage('im2').isNull())
            # should be retained
            self.assertTrue(cache.hasCacheImage('nolayer'))
            self.assertFalse(cache.cacheImage('nolayer').isNull())
            self.assertEqual(cache.cacheImage('nolayer'), im1)
Exemple #45
0
 def emitErrorImage(self):
     self.img = QImage()
     self.targetSize = self.img.size
     self.finished.emit()
Exemple #46
0
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 update_summary_sheet(self,lyr=None, force=None):
        '''
        Creates a summary sheet with thumbnail, layer metadata and online view link
        '''
        #create a layer snapshot and upload it to google drive

        if not lyr:
            lyr = self.lyr

        mapbox_style = self.service_sheet.sheet_cell('settings!A5')
        if not mapbox_style:
            logger("migrating mapbox style")
            self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr))
        
        if not force and not self.dirty and not self.restyled:
            return

        if self.restyled:
            self.service_sheet.set_style_qgis(self.layer_style_to_xml(self.lyr))
            self.service_sheet.set_style_sld(self.SLD_to_xml(self.lyr))
            self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr))
            self.saveMetadataState()
        
        canvas = QgsMapCanvas()
        canvas.resize(QSize(600,600))
        canvas.setCanvasColor(Qt.white)
        canvas.setExtent(lyr.extent())
        canvas.setLayers([lyr])
        canvas.refresh()
        canvas.update()
        settings = canvas.mapSettings()
        settings.setLayers([lyr])
        job = QgsMapRendererParallelJob(settings)
        job.start()
        job.waitForFinished()
        image = job.renderedImage()

        transparent_image = QImage(image.width(), image.height(), QImage.Format_ARGB32)
        transparent_image.fill(Qt.transparent)
        p = QPainter(transparent_image)
        mask = image.createMaskFromColor(QColor(255, 255, 255).rgb(), Qt.MaskInColor)
        p.setClipRegion(QRegion(QBitmap(QPixmap.fromImage(mask))))
        p.drawPixmap(0, 0, QPixmap.fromImage(image))
        p.end()

        tmp_path = os.path.join(self.parent.plugin_dir,self.service_sheet.name+".png")
        transparent_image.save(tmp_path,"PNG")
        image_istances = self.service_drive.list_files(mimeTypeFilter='image/png',filename=self.service_sheet.name+".png")
        for imagename, image_props in image_istances.items():
            self.service_drive.delete_file(image_props['id'])
        result = self.service_drive.upload_image(tmp_path)
        self.service_drive.add_permission(result['id'],'anyone','reader')
        webLink = result['webContentLink'] #'https://drive.google.com/uc?export=view&id='+result['id']
        logger("webLink:" + webLink)
        canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326))
        worldfile = QgsMapSettingsUtils.worldFileContent(settings)
        lonlat_min = self.transformToWGS84(QgsPointXY(canvas.extent().xMinimum(), canvas.extent().yMinimum()))
        lonlat_max = self.transformToWGS84(QgsPointXY(canvas.extent().xMaximum(), canvas.extent().yMaximum()))
        keymap_extent = [lonlat_min.x(),lonlat_min.y(),lonlat_max.x(),lonlat_max.y()]
        
        os.remove(tmp_path)
        #update layer metadata
        summary_id = self.service_sheet.add_sheet('summary', no_grid=True)
        appPropsUpdate = [
            ["keymap",webLink],
            ["worldfile",pack(worldfile)],
            ["keymap_extent", json.dumps(keymap_extent)]
        ]
        res = self.service_sheet.update_appProperties(self.spreadsheet_id,appPropsUpdate)
        
        self.saveMetadataState(metadata=self.get_layer_metadata())
        self.parent.public_db.setKey(self.spreadsheet_id, dict(self.get_layer_metadata()+appPropsUpdate),only_update=True)
        #merge cells to visualize snapshot and aaply image snapshot
        request_body = {
            'requests': [{
                'mergeCells': {
                    "range": {
                        "sheetId": summary_id,
                        "startRowIndex": 9,
                        "endRowIndex": 32,
                        "startColumnIndex": 0,
                        "endColumnIndex": 9,
                    },
                "mergeType": 'MERGE_ALL'
                }
            }]
        }
        self.service_sheet.service.spreadsheets().batchUpdate(spreadsheetId=self.spreadsheet_id, body=request_body).execute()
        self.service_sheet.set_sheet_cell('summary!A10','=IMAGE("%s",3)' % webLink)

        permissions = self.service_drive.file_property(self.spreadsheet_id,'permissions')
        for permission in permissions:
            if permission['type'] == 'anyone':
                public = True
                break
            else:
                public = False
        if public:
            update_range = 'summary!A9:B9'
            update_body = {
                "range": update_range,
                "values": [['public link', "https://enricofer.github.io/gdrive_provider/weblink/converter.html?spreadsheet_id="+self.spreadsheet_id]]
            }
            self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=update_range, body=update_body, valueInputOption='USER_ENTERED').execute()

        #hide worksheets except summary
        sheets = self.service_sheet.get_sheets()
        #self.service_sheet.toggle_sheet('summary', sheets['summary'], hidden=None)
        for sheet_name,sheet_id in sheets.items():
            if not sheet_name == 'summary':
                self.service_sheet.toggle_sheet(sheet_name, sheet_id, hidden=True)
Exemple #48
0
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)
Exemple #49
0
    def test_wms_getprint_maptheme(self):
        """Test project has 2 layer: red and green and three templates:
            red: follow map theme red
            green: follow map theme green
            blank: no map theme
        """

        tmp_dir = QTemporaryDir()
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_mapthemes.qgs'),
            os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs'))
        shutil.copyfile(
            os.path.join(unitTestDataPath('qgis_server'),
                         'test_project_mapthemes.gpkg'),
            os.path.join(tmp_dir.path(), 'test_project_mapthemes.gpkg'))

        project = QgsProject()
        self.assertTrue(
            project.read(
                os.path.join(tmp_dir.path(), 'test_project_mapthemes.qgs')))

        params = {
            "SERVICE": "WMS",
            "VERSION": "1.3",
            "REQUEST": "GetPrint",
            "TEMPLATE": "blank",
            "FORMAT": "png",
            "LAYERS": "",
            "map0:EXTENT":
            "44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368",
            "map0:LAYERS": "red",
            "CRS": "EPSG:4326",
            "DPI": '72'
        }

        polygon = 'POLYGON((7.09769689415099325 44.92867722467413216, 7.37818833364500737 44.92867722467413216, 7.37818833364500737 45.0714498943264914, 7.09769689415099325 45.0714498943264914, 7.09769689415099325 44.92867722467413216))'

        ######################################################
        # Template map theme tests, no HIGHLIGHT

        # blank template, specified layer is red
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # blank template, specified layer is green
        params["map0:LAYERS"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # red template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "red"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        # green template, no specified layers
        params["map0:LAYERS"] = ""
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertGreen(image.pixelColor(100, 100))

        # green template, specified layer is red
        # This is a conflict situation: the green template map is set to follow green theme
        # but we tell the server to render the red layer, red is what we get.
        params["map0:LAYERS"] = "red"
        params["TEMPLATE"] = "green"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertRed(image.pixelColor(100, 100))

        ######################################################
        # Start HIGHLIGHT tests

        params["TEMPLATE"] = "blank"
        params["map0:LAYERS"] = "red"
        params["map0:HIGHLIGHT_GEOM"] = polygon
        params[
            "map0:HIGHLIGHT_SYMBOL"] = r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>'

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight without layers
        params["TEMPLATE"] = "blank"
        params["map0:LAYERS"] = ""

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "green"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme, but add LAYERS (issue GH #34178)
        params["TEMPLATE"] = "green"
        params["LAYERS"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest(
            '?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))
    def test_wms_getprint_maptheme_highlight(self):
        """Test templates green and red have 2 layers: red and green
            template red: follow map theme red
            template green: follow map theme green
            template blank: no map theme
        """

        project = self.project

        params = {
            'SERVICE': 'WMS',
            'VERSION': '1.3.0',
            'REQUEST': 'GetPrint',
            'TEMPLATE': 'blank',
            'FORMAT': 'png',
            'LAYERS': '',
            'map0:EXTENT': '44.92867722467413216,7.097696894150993252,45.0714498943264914,7.378188333645007368',
            'map0:LAYERS': 'red',
            'CRS': 'EPSG:4326',
            'DPI': '72',
            'map0:HIGHLIGHT_GEOM': self.polygon,
            'map0:HIGHLIGHT_SYMBOL': r'<StyledLayerDescriptor><UserStyle><FeatureTypeStyle><Rule><PolygonSymbolizer><Fill><CssParameter name="fill">%230000FF</CssParameter></Fill></PolygonSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>'
        }

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight without layers
        params["TEMPLATE"] = "blank"
        params["map0:LAYERS"] = ""

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme (issue GH #34178)
        params["TEMPLATE"] = "green"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))

        # Test highlight on follow theme, but add LAYERS (issue GH #34178)
        params["TEMPLATE"] = "green"
        params["LAYERS"] = "red"

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        self._assertBlue(image.pixelColor(100, 100))
Exemple #51
0
    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()
Exemple #52
0
    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()
Exemple #53
0
    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())
Exemple #54
0
    def testPreviewColorRampVerticalFlipped(self):
        r = QgsGradientColorRamp(QColor(200, 0, 0, 200), QColor(0, 200, 0, 255))

        pix = QgsSymbolLayerUtils.colorRampPreviewPixmap(r, QSize(100, 200), direction=Qt.Vertical, flipDirection=True)
        img = QImage(pix)
        self.assertTrue(self.imageCheck('color_ramp_vertical_flipped', 'color_ramp_vertical_flipped', img))
Exemple #55
0
    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())
Exemple #56
0
    def testExportToImage(self):
        md = QgsProject.instance().metadata()
        md.setTitle('proj title')
        md.setAuthor('proj author')
        md.setCreationDateTime(
            QDateTime(QDate(2011, 5, 3), QTime(9, 4, 5), QTimeZone(36000)))
        md.setIdentifier('proj identifier')
        md.setAbstract('proj abstract')
        md.setKeywords({'kw': ['kw1', 'kw2'], 'KWx': ['kw3', 'kw4']})
        QgsProject.instance().setMetadata(md)
        l = QgsLayout(QgsProject.instance())
        l.initializeDefaults()

        # add a second page
        page2 = QgsLayoutItemPage(l)
        page2.setPageSize('A5')
        l.pageCollection().addPage(page2)

        # add some items
        item1 = QgsLayoutItemShape(l)
        item1.attemptSetSceneRect(QRectF(10, 20, 100, 150))
        fill = QgsSimpleFillSymbolLayer()
        fill_symbol = QgsFillSymbol()
        fill_symbol.changeSymbolLayer(0, fill)
        fill.setColor(Qt.green)
        fill.setStrokeStyle(Qt.NoPen)
        item1.setSymbol(fill_symbol)
        l.addItem(item1)

        item2 = QgsLayoutItemShape(l)
        item2.attemptSetSceneRect(QRectF(10, 20, 100, 150))
        item2.attemptMove(QgsLayoutPoint(10, 20), page=1)
        fill = QgsSimpleFillSymbolLayer()
        fill_symbol = QgsFillSymbol()
        fill_symbol.changeSymbolLayer(0, fill)
        fill.setColor(Qt.cyan)
        fill.setStrokeStyle(Qt.NoPen)
        item2.setSymbol(fill_symbol)
        l.addItem(item2)

        exporter = QgsLayoutExporter(l)
        # setup settings
        settings = QgsLayoutExporter.ImageExportSettings()
        settings.dpi = 80

        rendered_file_path = os.path.join(self.basetestpath,
                                          'test_exporttoimagedpi.png')
        self.assertEqual(exporter.exportToImage(rendered_file_path, settings),
                         QgsLayoutExporter.Success)

        self.assertTrue(
            self.checkImage('exporttoimagedpi_page1', 'exporttoimagedpi_page1',
                            rendered_file_path))
        page2_path = os.path.join(self.basetestpath,
                                  'test_exporttoimagedpi_2.png')
        self.assertTrue(
            self.checkImage('exporttoimagedpi_page2', 'exporttoimagedpi_page2',
                            page2_path))

        for f in (rendered_file_path, page2_path):
            d = gdal.Open(f)
            metadata = d.GetMetadata()
            self.assertEqual(metadata['Author'], 'proj author')
            self.assertEqual(metadata['Created'], '2011-05-03T09:04:05+10:00')
            self.assertEqual(metadata['Keywords'], 'KWx: kw3,kw4;kw: kw1,kw2')
            self.assertEqual(metadata['Subject'], 'proj abstract')
            self.assertEqual(metadata['Title'], 'proj title')

        # crop to contents
        settings.cropToContents = True
        settings.cropMargins = QgsMargins(10, 20, 30, 40)

        rendered_file_path = os.path.join(self.basetestpath,
                                          'test_exporttoimagecropped.png')
        self.assertEqual(exporter.exportToImage(rendered_file_path, settings),
                         QgsLayoutExporter.Success)

        self.assertTrue(
            self.checkImage('exporttoimagecropped_page1',
                            'exporttoimagecropped_page1', rendered_file_path))
        page2_path = os.path.join(self.basetestpath,
                                  'test_exporttoimagecropped_2.png')
        self.assertTrue(
            self.checkImage('exporttoimagecropped_page2',
                            'exporttoimagecropped_page2', page2_path))

        # specific pages
        settings.cropToContents = False
        settings.pages = [1]

        rendered_file_path = os.path.join(self.basetestpath,
                                          'test_exporttoimagepages.png')
        self.assertEqual(exporter.exportToImage(rendered_file_path, settings),
                         QgsLayoutExporter.Success)

        self.assertFalse(os.path.exists(rendered_file_path))
        page2_path = os.path.join(self.basetestpath,
                                  'test_exporttoimagepages_2.png')
        self.assertTrue(
            self.checkImage('exporttoimagedpi_page2', 'exporttoimagedpi_page2',
                            page2_path))

        # image size
        settings.imageSize = QSize(600, 851)
        rendered_file_path = os.path.join(self.basetestpath,
                                          'test_exporttoimagesize.png')
        self.assertEqual(exporter.exportToImage(rendered_file_path, settings),
                         QgsLayoutExporter.Success)
        self.assertFalse(os.path.exists(rendered_file_path))
        page2_path = os.path.join(self.basetestpath,
                                  'test_exporttoimagesize_2.png')
        self.assertTrue(
            self.checkImage('exporttoimagesize_page2',
                            'exporttoimagesize_page2', page2_path))

        # image size with incorrect aspect ratio
        # this can happen as a result of data defined page sizes
        settings.imageSize = QSize(851, 600)
        rendered_file_path = os.path.join(
            self.basetestpath, 'test_exporttoimagesizebadaspect.png')
        self.assertEqual(exporter.exportToImage(rendered_file_path, settings),
                         QgsLayoutExporter.Success)

        page2_path = os.path.join(self.basetestpath,
                                  'test_exporttoimagesizebadaspect_2.png')
        im = QImage(page2_path)
        self.assertTrue(
            self.checkImage('exporttoimagesize_badaspect',
                            'exporttoimagedpi_page2', page2_path),
            '{}x{}'.format(im.width(), im.height()))
    def test_wms_getprint_maptheme_multiple_maps(self):
        """Test template points has 4 layers: points_black, points_red, points_green, points_blue
            the template has two maps (from top to bottom) map1 and map0 using
            respectively the 4points-red and 4points-green map themes
        """

        project = self.project

        # No LAYERS specified
        params = {
            'SERVICE': 'WMS',
            'VERSION': '1.3.0',
            'REQUEST': 'GetPrint',
            'TEMPLATE': 'points',
            'FORMAT': 'png',
            'map0:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833',
            'CRS': 'EPSG:4326',
            'DPI': '72',
            'map1:EXTENT': '44.66151222233335716,6.71202136069002187,45.25042454764368927,7.83398711866607833'
        }

        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Expected: green and red
        # map1 (top map)
        self._assertRed(image.pixelColor(325, 184))  # RED
        self._assertWhite(image.pixelColor(474, 184))  # GREEN
        self._assertWhite(image.pixelColor(332, 262))  # BLUE
        self._assertWhite(image.pixelColor(485, 258))  # BLACK
        # map0 (bottom map)
        self._assertWhite(image.pixelColor(315, 461))  # RED
        self._assertGreen(image.pixelColor(475, 473))  # GREEN
        self._assertWhite(image.pixelColor(329, 553))  # BLUE
        self._assertWhite(image.pixelColor(481, 553))  # BLACK

        # Black LAYERS
        params["LAYERS"] = "points_black"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Expected black
        # map1 (top map)
        self._assertWhite(image.pixelColor(325, 184))  # RED
        self._assertWhite(image.pixelColor(474, 184))  # GREEN
        self._assertWhite(image.pixelColor(332, 262))  # BLUE
        self._assertBlack(image.pixelColor(485, 258))  # BLACK
        # map0 (bottom map)
        self._assertWhite(image.pixelColor(315, 461))  # RED
        self._assertWhite(image.pixelColor(475, 473))  # GREEN
        self._assertWhite(image.pixelColor(329, 553))  # BLUE
        self._assertBlack(image.pixelColor(481, 553))  # BLACK

        # Black map0:LAYERS
        del params["LAYERS"]
        params["map0:LAYERS"] = "points_black"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Expected black on map0, green on map1
        # map1 (top map)
        self._assertRed(image.pixelColor(325, 184))  # RED
        self._assertWhite(image.pixelColor(474, 184))  # GREEN
        self._assertWhite(image.pixelColor(332, 262))  # BLUE
        self._assertWhite(image.pixelColor(485, 258))  # BLACK
        #  map0 (bottom map)
        self._assertWhite(image.pixelColor(315, 461))  # RED
        self._assertWhite(image.pixelColor(475, 473))  # GREEN
        self._assertWhite(image.pixelColor(329, 553))  # BLUE
        self._assertBlack(image.pixelColor(481, 553))  # BLACK

        # Conflicting information: Black LAYERS and Green map0:LAYERS
        # The second gets precedence on map0 while LAYERS is applied to map1
        params["map0:LAYERS"] = "points_blue"
        params["LAYERS"] = "points_black"
        response = QgsBufferServerResponse()
        request = QgsBufferServerRequest('?' + '&'.join(["%s=%s" % i for i in params.items()]))
        self.server.handleRequest(request, response, project)

        image = QImage.fromData(response.body(), "PNG")
        # Expected green on map0, black on map1
        # map1 (top map)
        self._assertWhite(image.pixelColor(325, 184))  # RED
        self._assertWhite(image.pixelColor(474, 184))  # GREEN
        self._assertWhite(image.pixelColor(332, 262))  # BLUE
        self._assertBlack(image.pixelColor(485, 258))  # BLACK
        #  map0 (bottom map)
        self._assertWhite(image.pixelColor(315, 461))  # RED
        self._assertWhite(image.pixelColor(475, 473))  # GREEN
        self._assertBlue(image.pixelColor(329, 553))  # BLUE
        self._assertWhite(image.pixelColor(481, 553))  # BLACK
Exemple #58
0
    def testReprojectionErrorsWhileRendering(self):
        # WKT of a polygon which causes reprojection errors while rendering
        # (apologies for the ridiculously complex wkt, but I can't find a way to reproduce with simplifiction)
        wkt = 'MultiPolygon (((16.93392988400009358 42.77094147300012139, 16.88493899800005238 42.72939687700012712, ' \
              '16.80298912900011032 42.76349518400014915, 16.85816491000014139 42.78400299700011544, ' \
              '16.93392988400009358 42.77094147300012139)),((17.38200931100010393 42.79783763200002511, ' \
              '17.65894616000011297 42.74298737200008702, 17.74887129000009622 42.69456614800010641, ' \
              '17.32374108200008322 42.79083893400003547, 17.38200931100010393 42.79783763200002511)),' \
              '((16.768565300000148 42.97223541900014254, 17.03207441500009622 42.98261139500014849, ' \
              '17.13184655000009116 42.96954987200014386, 17.20020592500009116 42.92177969000012183, ' \
              '16.85141035200010151 42.90070221600008438, 16.65544681100004709 42.92625560099999404, ' \
              '16.70679772200014668 42.96954987200014386, 16.63168379000003938 42.98261139500014849, ' \
              '16.768565300000148 42.97223541900014254)),((17.05567467500011958 43.02895742400001211, ' \
              '17.24024498800011429 43.02277252800014651, 17.74146569100011561 42.83926015800001608, ' \
              '17.70736738400009358 42.88703034100014122, 17.65334906206413734 42.8909283361407887, ' \
              '17.70158573400010482 42.91950022500007833, 17.81175988700005064 42.909862570000044, ' \
              '17.85847538200005147 42.81697418200012351, 18.22413781700009849 42.62807098500009317, ' \
              '18.43735477700010961 42.55921213800017711, 18.4371480710000526 42.4934022020000981, ' \
              '18.49642988400009358 42.41632721600008438, 18.23894290500010129 42.55906810100005089, ' \
              '18.21753991000014139 42.6201032570001388, 18.07601972700010151 42.65131256700003348, ' \
              '18.0432235040000819 42.70205312700007028, 17.90162194100014403 42.75189850500014188, ' \
              '17.8928328790000819 42.79083893400003547, 17.72095787900005348 42.8262393250000315, ' \
              '17.7618921230000808 42.77871328300012976, 17.74870853000004445 42.77204010600017625, ' \
              '17.21387780000011958 42.98261139500014849, 17.04615319100011561 42.9950625670000619, ' \
              '17.00163821700004974 43.05149974200010377, 17.05567467500011958 43.02895742400001211)),' \
              '((16.19467207100007045 43.07440827000000638, 16.254893425000148 43.06854889500006323, ' \
              '16.08716881600014403 43.01146067900008063, 16.04883873800011429 43.06517161700004692, ' \
              '16.19467207100007045 43.07440827000000638)),((16.56275475400011032 43.22898997600010773, ' \
              '16.65951582100009887 43.21596914300012315, 16.72771243600001867 43.16461823100003414, ' \
              '17.19336998800014271 43.12726471600016964, 16.67017662900013875 43.12547435099999404, ' \
              '16.37159264400014536 43.19550202000006323, 16.49642988400006516 43.21808502800014651, ' \
              '16.58326256600014403 43.18866608300005794, 16.52051842500006273 43.22898997600010773, ' \
              '16.56275475400011032 43.22898997600010773)),((16.80681399800010922 43.34247467700005529, ' \
              '16.89234459700011826 43.31220123900006058, 16.84620201900008851 43.27338288000005662, ' \
              '16.62826582100012729 43.26373932500008834, 16.50074303500014139 43.28424713700003679, ' \
              '16.42188561300008587 43.31757233300011478, 16.40577233200011165 43.33270905200011214, ' \
              '16.45346113400009358 43.35317617400009738, 16.42628014400008851 43.39411041900011412, ' \
              '16.44703209700008983 43.39484284100014122, 16.80681399800010922 43.34247467700005529)),' \
              '((16.29818769600012729 43.40363190300011809, 16.30274498800008587 43.38727448100009099, ' \
              '16.39144941500012465 43.34638092700005529, 16.348643425000148 43.33869049700003018, ' \
              '16.20045006600014403 43.40704987200003018, 16.29818769600012729 43.40363190300011809)),' \
              '((16.33415774800010922 43.50153229400014254, 16.3752547540000819 43.49017975500008504, ' \
              '16.21143639400008851 43.49005768400009231, 16.26441491000014139 43.51288483300011478, ' \
              '16.33415774800010922 43.50153229400014254)),((15.67888431100004709 43.64801666900014254, ' \
              '15.74040774800010922 43.62750885600009099, 15.67204837300002396 43.63743724200010377, ' \
              '15.60377037900013875 43.67470937700007028, 15.67888431100004709 43.64801666900014254)),' \
              '((15.36736087300005238 43.79010651200015047, 15.39568118600007551 43.7724063170000619, ' \
              '15.22779381600014403 43.87445709800014981, 15.24073326900014536 43.88076406500009341, ' \
              '15.36736087300005238 43.79010651200015047)),((15.44271894600009887 43.89907461100013109, ' \
              '15.35865319100014403 43.91937897300014981, 15.26124108200011165 44.01105377800003282, ' \
              '15.38404381600008719 43.9701602230000077, 15.44271894600009887 43.89907461100013109)),' \
              '((15.22575931100010393 44.06622955900014915, 15.25440514400008851 44.01788971600014122, ' \
              '15.12183678500014139 44.09223053600005926, 15.06251061300008587 44.16193268400012073, ' \
              '15.22575931100010393 44.06622955900014915)),((14.83545983200014007 44.15102773600013109, ' \
              '14.85726972700010151 44.15204498900000374, 14.86915123800014271 44.14052969000006499, ' \
              '14.83521569100008719 44.14166901200009363, 14.81983483200014007 44.15302155199999845, ' \
              '14.82243899800005238 44.16868724200004692, 14.83545983200014007 44.15102773600013109)),' \
              '((14.98511803500011297 44.09096914300012315, 15.21680748800008587 43.91278717700008372, ' \
              '15.13331139400011693 43.92121002800003282, 15.19450931100004709 43.87262604400017096, ' \
              '15.10661868600007551 43.92544179900015422, 14.84961998800014271 44.17560455900014915, ' \
              '14.98511803500011297 44.09096914300012315)),((14.765961134000122 44.26504140800015819, ' \
              '14.74854576900014536 44.26166413000014188, 14.73959394600012729 44.28017812700015554, ' \
              '14.79167728000007287 44.27252838700003679, 14.765961134000122 44.26504140800015819)),' \
              '((14.66138756600011561 44.30866120000014519, 14.6407983730000808 44.31183502800003282, ' \
              '14.59506269600007045 44.34711334800006455, 14.643565300000148 44.32575104400011412, ' \
              '14.66138756600011561 44.30866120000014519)),((14.81120853000004445 44.35004303600000242, ' \
              '14.75619550900009358 44.36399974200004692, 14.76343834700008983 44.41535065300017493, ' \
              '14.80323326900008851 44.40550364800004957, 14.81120853000004445 44.35004303600000242)),' \
              '((14.27116946700002131 44.61253489800004957, 14.23259524800005238 44.62604401200012205, ' \
              '14.2657983730000808 44.67951080900003547, 14.28044681100007551 44.67755768400009231, ' \
              '14.27116946700002131 44.61253489800004957)),((14.84522545700008322 44.60053131700011875, ' \
              '14.93824303500014139 44.59414297100001079, 15.07553144600007045 44.48407623900006058, ' \
              '14.91114342500011958 44.54547760600014783, 15.04802493600004709 44.43943919500001982, ' \
              '15.09669030000009116 44.41518789300000947, 15.04151451900014536 44.47662995000008834, ' \
              '15.25440514400008851 44.34003327000000638, 15.165049675000148 44.36737702000006323, ' \
              '15.22022545700008322 44.3127302100001117, 15.13086998800008587 44.33258698100003414, ' \
              '15.17237389400014536 44.29913971600016964, 15.12875410200007309 44.31199778900018771, ' \
              '15.08920332100009887 44.37421295800000109, 15.11719811300014271 44.38719310099999404, ' \
              '15.04900149800010922 44.39468008000015686, 14.89747155000009116 44.49091217699999845, ' \
              '14.91863040500010129 44.50454336100013109, 14.87696373800011429 44.55975983300005794, ' \
              '14.73365319100008719 44.70319245000014519, 14.84522545700008322 44.60053131700011875)),' \
              '((14.41000410200010151 44.60097890800001608, 14.52662194100011561 44.50372955900012073, ' \
              '14.53435306100010393 44.48407623900006058, 14.42261803500008455 44.57387929900009738, ' \
              '14.36304772200014668 44.57343170800000109, 14.38257897200014668 44.60325755399999537, ' \
              '14.33578535200007309 44.71678294500010509, 14.39747155000009116 44.6856143250000315, ' \
              '14.41000410200010151 44.60097890800001608)),((14.75326582100007045 44.84585195500012844, ' \
              '14.74048912900011032 44.82050202000000638, 14.82243899800005238 44.77142975500005662, ' \
              '14.84961998800014271 44.70319245000014519, 14.65788821700004974 44.79877350500014188, ' \
              '14.7268172540000819 44.79877350500014188, 14.6858016290000819 44.8471540390000456, ' \
              '14.75326582100007045 44.84585195500012844)),((14.47103925900006516 44.95392487200003018, ' \
              '14.45191491000008455 44.79877350500014188, 14.47217858200011165 44.7079531920000619, ' \
              '14.53435306100010393 44.63426341400010244, 14.51335696700007816 44.618841864000089, ' \
              '14.42790774800005238 44.65656159100014122, 14.29420006600008719 44.9086367860001161, ' \
              '14.30152428500011297 44.94342682500014519, 14.38738040500004445 44.90900299700003018, ' \
              '14.39031009200004974 44.96039459800012139, 14.41138756600008719 44.95636627800014651, ' \
              '14.27849368600004709 45.1133487000000315, 14.29957116000014139 45.16233958499999801, ' \
              '14.35621178500014139 45.16925690300008966, 14.387705925000148 45.03904857000013351, ' \
              '14.47103925900006516 44.95392487200003018)),((14.56332441500012465 45.24974192900008063, ' \
              '14.62378991000011297 45.17548248900006058, 14.59742272200011826 45.16644928600005926, ' \
              '14.66529381600011561 45.16181061400011743, 14.66529381600011561 45.08734772300006455, ' \
              '14.74048912900011032 45.07306549700014386, 14.81495201900008851 44.97748444200009033, ' \
              '14.70639082100009887 44.9467227230000077, 14.62891686300014271 44.97817617400004053, ' \
              '14.62086022200008983 45.04559967700011214, 14.61695397200008983 45.02464427300007799, ' \
              '14.51050866000014139 45.03217194200011875, 14.43873131600014403 45.07050202000006323, ' \
              '14.4670516290000819 45.12409088700015047, 14.53012129000009622 45.13483307500014519, ' \
              '14.53435306100010393 45.23753489800002114, 14.56332441500012465 45.24974192900008063)),' \
              '((16.36947066200013978 46.54057118800012915, 16.63767134600004738 46.47447703100009164, ' \
              '16.75508020000012266 46.38187286400001597, 16.83765913900006694 46.38187286400001597, ' \
              '16.88923221800007468 46.29216257800014489, 17.05294315600005461 46.15346303300005104, ' \
              '17.20859257000006437 46.11656606000003933, 17.27587528500004055 46.01202463800002818, ' \
              '17.31680301900004793 45.99765859000002877, 17.29013798000011093 45.98463612900009423, ' \
              '17.40620324700006449 45.94365671800015605, 17.59110152100009827 45.93621531200012953, ' \
              '17.65652388500006964 45.84541982000014571, 17.80917606600013414 45.81441396100005647, ' \
              '17.85806197100004056 45.77172922800004073, 18.21121870900006456 45.78537180600012846, ' \
              '18.40438521300006869 45.74180857400001798, 18.57347049900010916 45.81668772400014689, ' \
              '18.6556360270001278 45.90758656800015558, 18.7755253500000947 45.88283355700004051, ' \
              '18.90130578600007993 45.93120269800006383, 18.87288374800004931 45.89523590100002082, ' \
              '18.90699019400011593 45.86795074500018643, 18.85531376100007606 45.85735707600009903, ' \
              '18.84497847500006174 45.8157058720000947, 18.96848514800012708 45.66873809800016204, ' \
              '18.90357954900008508 45.57308502200005762, 18.94171675700005153 45.53892689999999277, ' \
              '19.01809452300011571 45.56740061400002162, 19.10625451700005328 45.51164174500017623, ' \
              '19.00961958800010621 45.49867095900005154, 19.00300500400010151 45.45536611000007099, ' \
              '19.03742150900006891 45.42229319300010104, 18.97592655400006834 45.39495636000008005, ' \
              '19.09199182100007874 45.34999786400005917, 19.12475467900009107 45.29811472600006539, ' \
              '19.36308638500014467 45.24824696900010679, 19.40783817500010855 45.20313344400013023, ' \
              '19.39068160000005037 45.16933705700016333, 19.22593713300008744 45.16194732700016345, ' \
              '19.12186079900010327 45.195795390000157, 19.13767378700009658 45.14603098600004216, ' \
              '19.04486291500009543 45.13724599300006446, 19.08227665200013234 45.08494944300004192, ' \
              '19.0872375890000967 44.97710072800013847, 19.13167932100006396 44.95317454000003465, ' \
              '19.06667036900009293 44.90568389900012392, 18.99142948400006503 44.9149339800001286, ' \
              '19.01582076000008215 44.86563466400004074, 18.88962691200009658 44.86119049100013001, ' \
              '18.78338016700013213 44.91374542300012251, 18.79175174900009893 45.00154368100008639, ' \
              '18.73831831900008638 45.0159097290000858, 18.68405806500004473 45.08479441400000098, ' \
              '18.64871138500012648 45.06267689999999959, 18.61667199700013953 45.09766184500010411, ' \
              '18.54959598800010667 45.09476796500011631, 18.51703983500007666 45.05585561200003042, ' \
              '18.23788374800011525 45.15745147700012296, 18.15365116400005263 45.0975584930001645, ' \
              '18.00347945100011771 45.1493382780000303, 17.83573775200005684 45.0644338990000648, ' \
              '17.68473921700012852 45.1639627080000281, 17.48185754400009273 45.11440500900012296, ' \
              '17.49622359200009214 45.1416901650001563, 17.44775109900012922 45.13430043600014585, ' \
              '17.44330692500011537 45.16205068000009248, 17.38243208800008688 45.1396231090000839, ' \
              '17.26895064300006766 45.18954254200015441, 17.24548954300007608 45.15538442000017483, ' \
              '17.18709517400012032 45.14856313100001728, 17.0363033440001459 45.23047027600007652, ' \
              '17.00829471800011561 45.21615590500009318, 17.00829471800011561 45.24416453100009505, ' \
              '16.94731652900014751 45.23568959600000028, 16.9243721930001243 45.28452382500016427, ' \
              '16.81171757000004163 45.18122263700009, 16.52894413300009546 45.22225372400005483, ' \
              '16.38921106000003647 45.11683380099999852, 16.31624393700010955 45.00123362300008978, ' \
              '16.12152714000009723 45.09616322900008356, 16.02044803900011516 45.213933818000001, ' \
              '15.79234826700013627 45.18980092400012438, 15.76361617000014803 44.97555043600003444, ' \
              '15.7308533120001357 44.92723297200008403, 15.77343469200010873 44.84501576800015243, ' \
              '15.71607385200013596 44.80320953400008932, 15.72847619600008784 44.76910308800002269, ' \
              '15.80568078600006743 44.69665273000013883, 15.88877648900006534 44.72424794500012979, ' \
              '15.96897831200004703 44.63924021400013942, 16.02830285600006732 44.62471913700009907, ' \
              '16.04473596200011798 44.58937245700018082, 16.00608199000004106 44.54100331600012908, ' \
              '16.11646285000011858 44.52146962500013672, 16.15966434700004584 44.41610138000002905, ' \
              '16.13827030500004867 44.37760243800015303, 16.20286584400008678 44.35977406800010669, ' \
              '16.18756962000011868 44.28241444999999032, 16.21578495300011014 44.20815541600011045, ' \
              '16.32688928200008149 44.08237498000012522, 16.50103885900011846 43.99271637000008184, ' \
              '16.67859908100004418 43.8406843060001421, 16.71260217300007866 43.77151540100005889, ' \
              '17.03051558500007445 43.54847991900005866, 17.27050093600007585 43.46321380700000248, ' \
              '17.28993127500007176 43.3034302780000786, 17.44206669100009321 43.15243174300015028, ' \
              '17.6284119050001209 43.04657257100008394, 17.66272505700004558 42.96569895500012137, ' \
              '17.63450972400008254 42.950402731000068, 17.51563561300008587 42.95888906500012183, ' \
              '17.47087649800005238 43.01341380400010905, 17.50196373800014271 43.03099192900005221, ' \
              '17.43360436300014271 43.01740143400009231, 17.46021569100011561 43.03099192900005221, ' \
              '17.42611738400009358 43.06517161700004692, 17.4045516290000819 43.05149974200010377, ' \
              '17.31625410200012993 43.12726471600016964, 17.11394290500004445 43.21320221600008438, ' \
              '16.88062584700011826 43.40595123900006058, 16.62582441500009622 43.44904205900009231, ' \
              '16.52466881600011561 43.51080963700009363, 16.39144941500012465 43.51080963700009363, ' \
              '16.47339928500008455 43.5381533870001789, 16.43384850400013875 43.54975006700000506, ' \
              '16.11768639400008851 43.52448151200003679, 16.17237389400014536 43.4896914730000077, ' \
              '16.11312910200004467 43.47890859600009605, 15.95948326900011693 43.50397370000008834, ' \
              '15.987315300000148 43.54490794500010509, 15.92530358200011165 43.55857982000004824, ' \
              '15.91895592500009116 43.62872955900012073, 15.96631920700011165 43.64118073100003414, ' \
              '15.90479576900014536 43.64801666900014254, 15.95297285200010151 43.65086497599999404, ' \
              '15.95045006600008719 43.68854401200015047, 15.70630944100008719 43.76341380400005221, ' \
              '15.6174422540000819 43.82550690300017493, 15.66309655000009116 43.81297435099999404, ' \
              '15.67888431100004709 43.81928131700011875, 15.45508873800014271 43.92804596600014122, ' \
              '15.14454186300011429 44.19546133000015686, 15.15219160200012993 44.23529694200014717, ' \
              '15.11036217500011958 44.26434967700011214, 15.14063561300011429 44.28245677300013483, ' \
              '15.17660566500009622 44.24994538000005662, 15.20777428500008455 44.27277252800014651, ' \
              '15.19809004000012465 44.30166250200007028, 15.295258009000122 44.25067780199999845, ' \
              '15.30274498800008587 44.29913971600016964, 15.26124108200011165 44.33258698100003414, ' \
              '15.42448978000001603 44.26797109600006763, 15.52865644600009887 44.27179596600008438, ' \
              '15.30795332100009887 44.35439687700007028, 15.00733483200014007 44.56972890800012976, ' \
              '14.883799675000148 44.7236188820001388, 14.883799675000148 44.86147695500012844, 14.92164147200008983 ' \
              '44.95880768400009231, 14.85279381600011561 45.09365469000000815, 14.65788821700004974 ' \
              '45.19660065300017493, 14.57081139400008851 45.29364655200011214, 14.31153405000009116 ' \
              '45.34398021000005485, 14.23259524800005238 45.14935944200000506, 14.17937259200007816 ' \
              '45.13450755400005221, 14.19312584700008983 45.10561758000012844, 14.14389082100007045 ' \
              '45.05939362200003018, 14.151377800000148 44.97748444200009033, 14.06885826900014536 ' \
              '44.94953034100014122, 14.08383222700007309 44.9863955750000315, 14.04029381600014403 ' \
              '45.03896719000015025, 14.0756942070000548 44.98371002800003282, 14.02051842500011958 ' \
              '44.90110911700004692, 13.97266686300011429 44.90110911700004692, 13.99301191500009622 ' \
              '44.88129303600014453, 13.97266686300011429 44.82664622599999404, 14.00001061300008587 ' \
              '44.81305573100003414, 13.89014733200011165 44.83348216400010244, 13.91797936300014271 ' \
              '44.77826569200009033, 13.90316816500009622 44.77240631700014717, 13.89698326900011693 ' \
              '44.81305573100003414, 13.78711998800014271 44.87506745000008834, 13.84229576900008851 ' \
              '44.88812897300006455, 13.79460696700010658 44.89496491100008768, 13.77409915500007287 ' \
              '44.96381256700014717, 13.6232202480000808 45.07306549700014386, 13.61255944100014403 ' \
              '45.11786530199999845, 13.72624759200004974 45.13450755400005221, 13.5959578790000819 ' \
              '45.14541250200001343, 13.57545006600011561 45.26487864800007799, 13.60271243600001867 ' \
              '45.28534577000012007, 13.57545006600011561 45.30646393400006389, 13.60954837300005238 ' \
              '45.32013580900017757, 13.54127037900013875 45.34613678600005926, 13.50709069100014403 ' \
              '45.51190827000000638, 13.62901778100007277 45.45898346000016943, 13.75929406800014476 ' \
              '45.46316925100011019, 13.88900191200011136 45.42363678000005223, 13.98263960800005634 ' \
              '45.47531321200001742, 13.97189091000012695 45.5142255660000643, 14.09291711400010172 ' \
              '45.47391794800002174, 14.21869755100007637 45.49717234400004884, 14.37279667100006009 ' \
              '45.47784535800009564, 14.4689148350000778 45.52559438100014688, 14.49857710800012001 ' \
              '45.59618438800005435, 14.58094934100009255 45.66780792200010808, 14.66848921700008646 ' \
              '45.53396596300005683, 14.79716353300005949 45.46518463200006011, 14.88160282300009385 ' \
              '45.46978383400001178, 14.9226339110000481 45.51494903600017494, 15.13926151500010064 ' \
              '45.43004465799999991, 15.32519331800011742 45.45283396399999276, 15.36136682100004691 ' \
              '45.48203114900003641, 15.29666792800006192 45.52295888300012905, 15.2685559480001416 ' \
              '45.60166208900012919, 15.37376916500011248 45.64021270800010655, 15.25501672300006817 ' \
              '45.72346344000011698, 15.42906294700014769 45.77529490200011253, 15.45128381300008868 ' \
              '45.81513743100013869, 15.67607629400006886 45.84169911700014666, 15.65943648300003588 ' \
              '45.88882802400014782, 15.69798710100010908 46.0362092080000167, 15.58988000500005455 ' \
              '46.11351715100001059, 15.62284956800010605 46.19170359400006021, 16.01920780400010358 ' \
              '46.29882883700007312, 16.05961877400008575 46.33231516600015709, 16.0579651280001201 ' \
              '46.37753204400003426, 16.2756262620000598 46.37316538500006402, 16.23490523300009158 ' \
              '46.4933389280001137, 16.36947066200013978 46.54057118800012915))) '
        geom = QgsGeometry.fromWkt(wkt)
        f = QgsFeature()
        f.setGeometry(geom)

        image = QImage(200, 200, QImage.Format_RGB32)

        painter = QPainter()
        ms = QgsMapSettings()
        crs = QgsCoordinateReferenceSystem.fromProj4(
            '+proj=ortho +lat_0=36.5 +lon_0=-118.8 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs'
        )
        self.assertTrue(crs.isValid())
        ms.setDestinationCrs(crs)
        ms.setExtent(QgsRectangle(1374999.8, 3912610.7, 4724462.5, 6505499.6))
        ms.setOutputSize(image.size())
        context = QgsRenderContext.fromMapSettings(ms)
        context.setPainter(painter)
        context.setScaleFactor(96 / 25.4)  # 96 DPI
        ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('epsg:4326'),
                                    crs, QgsProject.instance())
        self.assertTrue(ct.isValid())
        context.setCoordinateTransform(ct)
        context.setExtent(
            ct.transformBoundingBox(ms.extent(),
                                    QgsCoordinateTransform.ReverseTransform))

        fill_symbol = QgsFillSymbol.createSimple({
            'color': '#ffffff',
            'outline_color': '#ffffff',
            'outline_width': '10'
        })

        painter.begin(image)
        try:
            image.fill(QColor(0, 0, 0))
            fill_symbol.startRender(context)
            fill_symbol.renderFeature(f, context)
            fill_symbol.stopRender(context)
        finally:
            painter.end()

        assert self.imageCheck('Reprojection errors polygon',
                               'reprojection_errors_polygon', image)

        #also test linestring
        linestring = QgsGeometry(geom.constGet().boundary())
        f.setGeometry(linestring)
        line_symbol = QgsLineSymbol.createSimple({
            'color': '#ffffff',
            'outline_width': '10'
        })

        image = QImage(200, 200, QImage.Format_RGB32)
        painter.begin(image)
        try:
            image.fill(QColor(0, 0, 0))
            line_symbol.startRender(context)
            line_symbol.renderFeature(f, context)
            line_symbol.stopRender(context)
        finally:
            painter.end()

        assert self.imageCheck('Reprojection errors linestring',
                               'reprojection_errors_linestring', image)
Exemple #59
0
    def testRenderWithTransform(self):
        layer = QgsAnnotationLayer(
            'test',
            QgsAnnotationLayer.LayerOptions(
                QgsProject.instance().transformContext()))
        self.assertTrue(layer.isValid())

        item = QgsAnnotationPolygonItem(
            QgsPolygon(
                QgsLineString([
                    QgsPoint(11.5, 13),
                    QgsPoint(12, 13),
                    QgsPoint(12, 13.5),
                    QgsPoint(11.5, 13)
                ])))
        item.setSymbol(
            QgsFillSymbol.createSimple({
                'color': '200,100,100',
                'outline_color': 'black',
                'outline_width': '2'
            }))
        item.setZIndex(1)
        layer.addItem(item)

        item = QgsAnnotationLineItem(
            QgsLineString(
                [QgsPoint(11, 13),
                 QgsPoint(12, 13),
                 QgsPoint(12, 15)]))
        item.setSymbol(
            QgsLineSymbol.createSimple({
                'color': '#ffff00',
                'line_width': '3'
            }))
        item.setZIndex(2)
        layer.addItem(item)

        item = QgsAnnotationMarkerItem(QgsPoint(12, 13))
        item.setSymbol(
            QgsMarkerSymbol.createSimple({
                'color': '100,200,200',
                'size': '6',
                'outline_color': 'black'
            }))
        item.setZIndex(3)
        layer.addItem(item)

        layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))

        settings = QgsMapSettings()
        settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
        settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518))
        settings.setOutputSize(QSize(300, 300))

        settings.setFlag(QgsMapSettings.Antialiasing, False)

        rc = QgsRenderContext.fromMapSettings(settings)
        rc.setCoordinateTransform(
            QgsCoordinateTransform(layer.crs(), settings.destinationCrs(),
                                   QgsProject.instance()))
        image = QImage(200, 200, QImage.Format_ARGB32)
        image.setDotsPerMeterX(96 / 25.4 * 1000)
        image.setDotsPerMeterY(96 / 25.4 * 1000)
        image.fill(QColor(255, 255, 255))
        painter = QPainter(image)
        rc.setPainter(painter)

        try:
            renderer = layer.createMapRenderer(rc)
            renderer.render()
        finally:
            painter.end()

        self.assertTrue(
            self.imageCheck('layer_render_transform', 'layer_render_transform',
                            image))
Exemple #60
0
    def __init__(self,
                 geoservice,
                 image_ba,
                 parent=None,
                 extent_renderer=None):
        QWidget.__init__(self, parent)

        self.extent_renderer = extent_renderer

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(5, 10, 5, 10)
        self.setLayout(self.layout)

        self.service_icon = QLabel(self)
        self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.service_icon.resize(24, 24)

        qimg = QImage.fromData(image_ba)
        pixmap = QPixmap.fromImage(qimg)
        self.service_icon.setPixmap(pixmap)
        self.layout.addWidget(self.service_icon)

        self.service_desc_layout = QGridLayout(self)
        self.service_desc_layout.setSpacing(0)
        self.layout.addLayout(self.service_desc_layout)

        self.service_name = QLabel(self)
        self.service_name.setTextFormat(Qt.RichText)
        self.service_name.setWordWrap(True)
        self.service_name.setText(u"   <strong> {} </strong>".format(
            geoservice.get('name', u"")))
        self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3)

        self.service_type = QLabel(self)
        self.service_type.setTextFormat(Qt.RichText)
        self.service_type.setWordWrap(True)
        self.service_type.setText(geoservice.get('type', u"").upper() + " ")
        self.service_desc_layout.addWidget(self.service_type, 1, 0)

        self.service_deteils = QLabel(self)
        self.service_deteils.setTextFormat(Qt.RichText)
        self.service_deteils.setWordWrap(True)
        self.service_deteils.setOpenExternalLinks(True)
        self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format(
            Client().geoservice_info_url(geoservice.get('id', u"")),
            self.tr('details')))
        self.service_desc_layout.addWidget(self.service_deteils, 1, 1)

        self.service_report = QLabel(self)
        self.service_report.setTextFormat(Qt.RichText)
        self.service_report.setWordWrap(True)
        self.service_report.setOpenExternalLinks(True)
        self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format(
            Client().geoservice_report_url(geoservice.get('id', u"")),
            self.tr('report a problem')))
        self.service_desc_layout.addWidget(self.service_report, 1, 2)
        self.service_desc_layout.setColumnStretch(2, 1)

        self.status_label = QLabel(self)
        self.status_label.setTextFormat(Qt.RichText)
        self.status_label.setText(u'\u2022')

        status = geoservice.get('cumulative_status', u'')
        if status == 'works':
            self.status_label.setStyleSheet("color: green; font-size: 30px")
        if status == 'failed':
            self.status_label.setStyleSheet("color: red; font-size: 30px")
        if status == 'problematic':
            self.status_label.setStyleSheet("color: yellow; font-size: 30px")
        self.layout.addWidget(self.status_label)

        self.addButton = QToolButton()
        self.addButton.setText(self.tr("Add"))
        self.addButton.clicked.connect(self.addToMap)
        self.layout.addWidget(self.addButton)

        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)

        self.geoservice = geoservice
        self.image_ba = image_ba