Пример #1
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))
Пример #2
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))
Пример #3
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()
Пример #4
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)
Пример #5
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)
Пример #6
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)
Пример #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)
Пример #8
0
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)
Пример #9
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
Пример #10
0
    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
Пример #11
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 __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")
Пример #13
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
Пример #14
0
    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)
Пример #15
0
    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)
Пример #16
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
Пример #17
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
Пример #18
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)
Пример #19
0
    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)
Пример #20
0
    def test_different_dpi_target_vector(self):
        """Test rendering a raster layer with vector output and a target dpi
        Used when layout previewing
        """

        # modify labeling settings
        label_settings = self.polys_layer.labeling().settings()
        fmt = label_settings.format()
        # enable a mask
        fmt.mask().setEnabled(True)
        fmt.mask().setSize(4.0)
        # and mask other symbol layers underneath
        fmt.mask().setMaskedSymbolLayers([
            # the black part of roads
            QgsSymbolLayerReference(self.lines_layer.id(),
                                    QgsSymbolLayerId("", 0))
        ])

        label_settings.setFormat(fmt)
        self.polys_layer.labeling().setSettings(label_settings)

        self.map_settings.setLayers(
            [self.lines_layer, self.polys_layer, self.raster_layer])
        self.map_settings.setOutputDpi(81)
        self.map_settings.setDpiTarget(300)
        self.map_settings.setFlag(Qgis.MapSettingsFlag.ForceVectorOutput, True)

        image = QImage(self.map_settings.deviceOutputSize(),
                       self.map_settings.outputImageFormat())
        image.setDevicePixelRatio(self.map_settings.devicePixelRatio())
        image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() /
                                   25.4))
        image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() /
                                   25.4))
        image.fill(Qt.transparent)
        pImg = QPainter()
        pImg.begin(image)
        job = QgsMapRendererCustomPainterJob(self.map_settings, pImg)
        job.start()
        job.waitForFinished()
        pImg.end()
        tmp = getTempfilePath('png')
        image.save(tmp)

        control_name = "different_dpi_target_vector"
        self.checker.setControlName(control_name)
        self.checker.setRenderedImage(tmp)
        res = self.checker.compareImages(control_name)
        self.report += self.checker.report()
        self.assertTrue(res)

        # Same test with high dpi
        self.map_settings.setDevicePixelRatio(2)
        image = QImage(self.map_settings.deviceOutputSize(),
                       self.map_settings.outputImageFormat())
        image.setDevicePixelRatio(self.map_settings.devicePixelRatio())
        image.setDotsPerMeterX(int(1000 * self.map_settings.outputDpi() /
                                   25.4))
        image.setDotsPerMeterY(int(1000 * self.map_settings.outputDpi() /
                                   25.4))
        image.fill(Qt.transparent)
        pImg = QPainter()
        pImg.begin(image)
        job = QgsMapRendererCustomPainterJob(self.map_settings, pImg)
        job.start()
        job.waitForFinished()
        pImg.end()
        tmp = getTempfilePath('png')
        image.save(tmp)

        control_name = "different_dpi_target_vector_hdpi"
        self.checker.setControlName(control_name)
        self.checker.setRenderedImage(tmp)
        res = self.checker.compareImages(control_name)
        self.report += self.checker.report()
        self.assertTrue(res)
Пример #21
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)
Пример #22
0
    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)
Пример #23
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
Пример #24
0
class TileSet():
    """
    A set of tiles
    """
    def __init__(self, map_theme, layer, extent, tile_size, mupp, output,
                 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

        # TODO: Check if file exists and update instead?
        driver = self.getDriverForFile(output)

        if not driver:
            raise GeoAlgorithmExecutionException(
                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

        self.dataset = driver.Create(output, xsize, ysize, 3)  # 3 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_RGB32)

        self.settings = QgsMapSettings()
        self.settings.setCrsTransformEnabled(True)
        self.settings.setOutputDpi(self.image.logicalDpiX())
        self.settings.setOutputImageFormat(QImage.Format_RGB32)
        self.settings.setDestinationCrs(crs)
        self.settings.setOutputSize(self.image.size())
        self.settings.setMapUnits(crs.mapUnits())
        self.settings.setFlag(QgsMapSettings.Antialiasing, True)
        self.settings.setFlag(QgsMapSettings.RenderMapTile, True)

        if QgsProject.instance().visibilityPresetCollection().hasPreset(
                map_theme):
            self.settings.setLayers(QgsProject.instance(
            ).visibilityPresetCollection().presetVisibleLayers(map_theme))
            self.settings.setLayerStyleOverrides(QgsProject.instance(
            ).visibilityPresetCollection().presetStyleOverrides(map_theme))
        elif layer:
            self.settings.setLayers([layer])
        else:
            self.settings.setLayers(map_settings.layers())

    def render(self, progress):
        for x in range(self.x_tile_count):
            for y in range(self.y_tile_count):
                cur_tile = x * self.y_tile_count + y
                num_tiles = self.x_tile_count * self.y_tile_count
                progress.setPercentage(cur_tile * 100 / num_tiles)
                self.renderTile(x, y)

    def renderTile(self, x, y):
        """
        Render one tile

        :param x: The x index of the current tile
        :param y: The y index of the current tile
        """
        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))
        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)

        for i in range(osgeo.gdal.GetDriverCount()):
            driver = osgeo.gdal.GetDriver(i)
            if driver.GetMetadataItem('DMD_EXTENSION') == extension[1:]:
                return driver
Пример #25
0
class TileSet():
    """
    A set of tiles
    """
    def __init__(self, map_theme, layer, extent, tile_size, mupp, output,
                 make_trans, map_settings, project):
        """
        :param map_theme:
        :param extent:
        :param layer:
        :param tile_size:
        :param mupp:
        :param output:
        :param map_settings: Map canvas map settings used for some fallback
        values and CRS
        """

        self.extent = extent
        self.mupp = mupp
        self.tile_size = tile_size

        driver = self.getDriverForFile(output)

        if not driver:
            raise QgsProcessingException(
                u'Could not load GDAL driver for file {}'.format(output))

        crs = map_settings.destinationCrs()

        self.x_tile_count = math.ceil(extent.width() / mupp / tile_size)
        self.y_tile_count = math.ceil(extent.height() / mupp / tile_size)

        xsize = self.x_tile_count * tile_size
        ysize = self.y_tile_count * tile_size

        if make_trans:
            no_bands = 4
        else:
            no_bands = 3

        self.dataset = driver.Create(output, xsize, ysize, no_bands)
        self.dataset.SetProjection(str(crs.toWkt()))
        self.dataset.SetGeoTransform(
            [extent.xMinimum(), mupp, 0,
             extent.yMaximum(), 0, -mupp])

        self.image = QImage(QSize(tile_size, tile_size), QImage.Format_ARGB32)

        self.settings = QgsMapSettings()
        self.settings.setOutputDpi(self.image.logicalDpiX())
        self.settings.setOutputImageFormat(QImage.Format_ARGB32)
        self.settings.setDestinationCrs(crs)
        self.settings.setOutputSize(self.image.size())
        self.settings.setFlag(QgsMapSettings.Antialiasing, True)
        self.settings.setFlag(QgsMapSettings.RenderMapTile, True)
        self.settings.setFlag(QgsMapSettings.UseAdvancedEffects, True)

        r = project.readNumEntry('Gui', '/CanvasColorRedPart', 255)[0]
        g = project.readNumEntry('Gui', '/CanvasColorGreenPart', 255)[0]
        b = project.readNumEntry('Gui', '/CanvasColorBluePart', 255)[0]
        if make_trans:
            self.bgColor = QColor(r, g, b, 0)
        else:
            self.bgColor = QColor(r, g, b)
        self.settings.setBackgroundColor(self.bgColor)

        if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme):
            self.settings.setLayers(QgsProject.instance().mapThemeCollection().
                                    mapThemeVisibleLayers(map_theme))
            self.settings.setLayerStyleOverrides(QgsProject.instance(
            ).mapThemeCollection().mapThemeStyleOverrides(map_theme))
        elif layer:
            self.settings.setLayers([layer])
        else:
            self.settings.setLayers(map_settings.layers())

    def render(self, feedback, make_trans):
        for x in range(self.x_tile_count):
            for y in range(self.y_tile_count):
                if feedback.isCanceled():
                    return
                cur_tile = x * self.y_tile_count + y
                num_tiles = self.x_tile_count * self.y_tile_count
                self.renderTile(x, y, feedback, make_trans)

                feedback.setProgress(int((cur_tile / num_tiles) * 100))

    def renderTile(self, x, y, feedback, make_trans):
        """
        Render one tile
        :param x: The x index of the current tile
        :param y: The y index of the current tile
        """

        if make_trans:
            self.image.fill(self.bgColor.rgba())
        else:
            self.image.fill(self.bgColor.rgb())

        painter = QPainter(self.image)

        self.settings.setExtent(
            QgsRectangle(
                self.extent.xMinimum() + x * self.mupp * self.tile_size,
                self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size,
                self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size,
                self.extent.yMaximum() - y * self.mupp * self.tile_size))

        job = QgsMapRendererCustomPainterJob(self.settings, painter)
        job.renderSynchronously()
        painter.end()

        # Needs not to be deleted or Windows will kill it too early...
        tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
        try:
            self.image.save(tmpfile.name)

            src_ds = osgeo.gdal.Open(tmpfile.name)

            self.dataset.WriteRaster(
                x * self.tile_size, y * self.tile_size, self.tile_size,
                self.tile_size,
                src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size))
        except Exception as e:
            feedback.reportError(str(e))
        finally:
            del src_ds
            tmpfile.close()
            os.unlink(tmpfile.name)

    def getDriverForFile(self, filename):
        """
        Get the GDAL driver for a filename, based on its extension. (.gpkg,
        .mbtiles...)
        """
        _, extension = os.path.splitext(filename)

        # If no extension is set, use .tif as default
        if extension == '':
            extension = '.tif'

        driver_name = QgsRasterFileWriter.driverForExtension(extension[1:])
        return osgeo.gdal.GetDriverByName(driver_name)
Пример #26
0
    def printMap(self,taxon):
        # copy style from grid layer to output layer
        outstyle = tempfile.gettempdir() + os.sep + "output.qml"
        getLayerFromId(self.GRID_LAYER).saveNamedStyle(outstyle)
        self.TAXON_GRID_LAYER.loadNamedStyle(outstyle)

        # create layer set
        baseLayer = getLayerFromId(self.BASE_LAYER)
        if self.TAXON_GRID_LAYER.crs() != baseLayer.crs():
            QMessageBox.information(self.dlg,"Distribution Map Generator",
                "All layers must have the same projection.")
            raise QgsCsException("All layers must have the same projection.")
        baseCrs = baseLayer.crs()
        if self.SECONDARY_LAYER != "None":
            secondaryLayer = getLayerFromId(self.SECONDARY_LAYER)
            if secondaryLayer.crs() != baseLayer.crs():
                QMessageBox.information(self.dlg,"Distribution Map Generator",
                    "All layers must have the same projection.")
                raise QgsCsException("All layers must have the same projection.")
        else:
            secondaryLayer = None
        if self.SURFACE_LAYER != "None":
            surfaceLayer = getLayerFromId(self.SURFACE_LAYER)
            if surfaceLayer.crs() != baseLayer.crs():
                QMessageBox.information(self.dlg,"Distribution Map Generator",
                    "All layers must have the same projection.")
                raise QgsCsException("All layers must have the same projection.")
        else:
            surfaceLayer = None

        lst = []
        lst.append(self.TAXON_GRID_LAYER)
        if self.SURFACE_LAYER != "None":
            lst.append(surfaceLayer)
        if self.SECONDARY_LAYER != "None":
            lst.append(secondaryLayer)
        lst.append(baseLayer)

        ms = QgsMapSettings()
        ms.setLayers(lst)
        ms.setBackgroundColor(self.BACKGROUND_COLOUR)

        # set extent (xmin,ymin,xmax,ymax)
        rect = QgsRectangle(self.X_MIN,self.Y_MIN,self.X_MAX,self.Y_MAX)
        ms.setExtent(rect)

        # set output size
        outputSize = QSize(self.OUT_WIDTH,self.OUT_HEIGHT)
        ms.setOutputSize(outputSize)

        # create painter
        p = QPainter()
        p.setRenderHint(QPainter.Antialiasing)

        # create image (dimensions 325x299)
        img = QImage(outputSize, QImage.Format_ARGB32_Premultiplied)
        p.begin(img)

        # do the rendering
        r = QgsMapRendererCustomPainterJob(ms, p)

        r.start()
        r.waitForFinished()
        p.end()

        # save image
        outdir = self.OUT_DIR
        img.save(outdir+os.sep+str(str(taxon))+".png","png")