예제 #1
0
  def renderedImage(self, width, height, extent, transp_background=False, layerids=None):
    if QGis.QGIS_VERSION_INT < 20700:
      return self._renderedImage2(width, height, extent, transp_background, layerids)

    from qgis.core import QgsMapRendererCustomPainterJob
    antialias = True

    # render map image with QgsMapRendererCustomPainterJob
    settings = self.context.canvas.mapSettings()
    settings.setOutputSize(QSize(width, height))
    settings.setExtent(extent.unrotatedRect())
    settings.setRotation(extent.rotation())

    if layerids:
      settings.setLayers(layerids)

    if transp_background:
      settings.setBackgroundColor(QColor(Qt.transparent))
    #else:    #TODO: remove
      #settings.setBackgroundColor(self.context.canvas.canvasColor())
 
    image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
    painter = QPainter()
    painter.begin(image)
    if antialias:
      painter.setRenderHint(QPainter.Antialiasing)

    job = QgsMapRendererCustomPainterJob(settings, painter)
    job.start()
    job.waitForFinished()
    painter.end()

    return tools.base64image(image)
예제 #2
0
  def renderedImage(self, width, height, extent, transp_background=False, layerids=None):
    if QGis.QGIS_VERSION_INT < 20700:
      return self._renderedImage2(width, height, extent, transp_background, layerids)

    # render layers with QgsMapRendererCustomPainterJob
    from qgis.core import QgsMapRendererCustomPainterJob
    antialias = True
    settings = self.exportSettings.mapSettings

    # store old map settings
    old_outputSize = settings.outputSize()
    old_extent = settings.extent()
    old_rotation = settings.rotation()
    old_layerids = settings.layers()
    old_backgroundColor = settings.backgroundColor()

    # map settings
    settings.setOutputSize(QSize(width, height))
    settings.setExtent(extent.unrotatedRect())
    settings.setRotation(extent.rotation())

    if layerids is not None:
      settings.setLayers(layerids)

    if transp_background:
      settings.setBackgroundColor(QColor(Qt.transparent))
    #else:    #TODO: remove
      #settings.setBackgroundColor(self.exportSettings.canvas.canvasColor())

    has_pluginlayer = False
    for layerId in settings.layers():
      layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
      if layer and layer.type() == QgsMapLayer.PluginLayer:
        has_pluginlayer = True
        break

    # create an image
    image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
    painter = QPainter()
    painter.begin(image)
    if antialias:
      painter.setRenderHint(QPainter.Antialiasing)

    # rendering
    job = QgsMapRendererCustomPainterJob(settings, painter)
    if has_pluginlayer:
      job.renderSynchronously()   # use this method so that TileLayerPlugin layer is rendered correctly
    else:
      job.start()
      job.waitForFinished()
    painter.end()

    # restore map settings
    settings.setOutputSize(old_outputSize)
    settings.setExtent(old_extent)
    settings.setRotation(old_rotation)
    settings.setLayers(old_layerids)
    settings.setBackgroundColor(old_backgroundColor)

    return tools.base64image(image)
예제 #3
0
    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)
예제 #4
0
파일: TilesXYZ.py 프로젝트: manisandro/QGIS
    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)

        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
예제 #5
0
    def render(self, params):
        self.check_required_params(params)

        with change_directory(self.project_root):

            crs = QgsCoordinateReferenceSystem()
            crs.createFromSrid(params.get('srs'))

            img = QImage(
                QSize(*params.get('image_size')),
                QImage.Format_ARGB32_Premultiplied
            )
            dpm = 1 / 0.00028
            img.setDotsPerMeterX(dpm)
            img.setDotsPerMeterY(dpm)

            # set background color
            bgcolor = params.get('bgcolor')
            if params.get('transparent'):
                # fully transparent
                bgcolor.append(0)
            else:
                # fully opaque
                bgcolor.append(255)

            color = QColor(*bgcolor)
            img.fill(color)

            map_settings = QgsMapSettings()
            map_settings.setBackgroundColor(color)
            map_settings.setDestinationCrs(crs)
            map_settings.setCrsTransformEnabled(True)
            map_settings.setExtent(QgsRectangle(*params.get('bbox')))
            map_settings.setOutputDpi(img.logicalDpiX())
            map_settings.setOutputSize(img.size())
            map_settings.setMapUnits(crs.mapUnits())

            layers = params.get('layers')
            self.setTransparencies(layers, params.get('transparencies'))

            map_settings.setLayers(layers)

            p = QPainter()
            p.begin(img)

            job = QgsMapRendererCustomPainterJob(map_settings, p)
            job.start()
            job.waitForFinished()

            map_buffer = QBuffer()
            map_buffer.open(QIODevice.ReadWrite)

            if params.get('image_format') == 'jpeg':
                img.save(map_buffer, 'JPEG')
            elif params.get('image_format') == 'png8':
                png8 = img.convertToFormat(QImage.Format_Indexed8)
                png8.save(map_buffer, "PNG")
            else:
                img.save(map_buffer, 'PNG')

            # clean up
            p.end()
            map_buffer.close()
            return map_buffer.data()
예제 #6
0
파일: TilesXYZ.py 프로젝트: alexbruy/QGIS
    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()
예제 #7
0
    def renderer(self):
        qgis = QgsApplication([], False)
        qgis.setPrefixPath(self.settings.get('path'), True)
        qgis.setMaxThreads(1)
        qgis.initQgis()

        while True:
            try:
                fndata, srs, render_size, extended, \
                    target_box, result = self.queue.get()

                layer = QgsVectorLayer(fndata, 'layer', 'ogr')

                crs = QgsCoordinateReferenceSystem(srs.id)
                layer.setCrs(crs)

                settings = QgsMapSettings()
                settings.setLayers([layer.id()])
                settings.setFlag(QgsMapSettings.DrawLabeling)
                settings.setFlag(QgsMapSettings.Antialiasing)

                settings.setCrsTransformEnabled(True)
                settings.setDestinationCrs(crs)
                settings.setMapUnits(crs.mapUnits())
                settings.setOutputSize(QSize(*render_size))
                settings.setExtent(QgsRectangle(*extended))

                settings.setOutputImageFormat(QImage.Format_ARGB32)
                bgcolor = QColor.fromRgba(qRgba(255, 255, 255, 0))
                settings.setBackgroundColor(bgcolor)
                settings.setOutputDpi(96)

                QgsMapLayerRegistry.instance().addMapLayer(layer)
                settings.setLayers([layer.id()])

                # Создаем QImage руками чтобы можно было использовать
                # QgsMapRendererCustomPainterJob. Остальные не позволяют
                # обойти баг с рисованием поверх старого.
                img = QImage(settings.outputSize(), QImage.Format_ARGB32)

                # Эти костыли нужны для того, чтобы корректно рисовались
                # слои на прозрачном фоне, без этого получается каша.
                img.fill(QColor.fromRgba(qRgba(255, 255, 255, 255)))
                img.fill(QColor.fromRgba(qRgba(255, 255, 255, 0)))

                # DPI должно быть таким же как в settings, иначе ошибка. В QImage
                # разрешение указывается в точках на метр по каждой оси.
                dpm = settings.outputDpi() / 25.4 * 1000
                img.setDotsPerMeterX(dpm)
                img.setDotsPerMeterY(dpm)

                painter = QPainter(img)
                job = QgsMapRendererCustomPainterJob(settings, painter)
                job.renderSynchronously()
                painter.end()

                QgsMapLayerRegistry.instance().removeAllMapLayers()

                # Преобразование QImage в PIL
                ba = QByteArray()
                bf = QBuffer(ba)
                bf.open(QIODevice.WriteOnly)
                img.save(bf, 'PNG')
                bf.close()

                buf = StringIO()
                buf.write(bf.data())
                buf.seek(0)

                img = PIL.Image.open(buf)

                # Вырезаем нужный нам кусок изображения
                result.put(img.crop(target_box))

            except Exception as e:
                self.logger.error(e.message)

        qgis.exitQgis()
예제 #8
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")
예제 #9
0
 def create_job(settings):
     return QgsMapRendererCustomPainterJob(settings, p)
예제 #10
0
    def renderedImage(self,
                      width,
                      height,
                      extent,
                      transp_background=False,
                      layerids=None):
        if QGis.QGIS_VERSION_INT < 20700:
            return self._renderedImage2(width, height, extent,
                                        transp_background, layerids)

        # render layers with QgsMapRendererCustomPainterJob
        from qgis.core import QgsMapRendererCustomPainterJob
        antialias = True
        settings = self.exportSettings.mapSettings

        # store old map settings
        old_outputSize = settings.outputSize()
        old_extent = settings.extent()
        old_rotation = settings.rotation()
        old_layerids = settings.layers()
        old_backgroundColor = settings.backgroundColor()

        # map settings
        settings.setOutputSize(QSize(width, height))
        settings.setExtent(extent.unrotatedRect())
        settings.setRotation(extent.rotation())

        if layerids is not None:
            settings.setLayers(layerids)

        if transp_background:
            settings.setBackgroundColor(QColor(Qt.transparent))
        #else:    #TODO: remove
        #settings.setBackgroundColor(self.exportSettings.canvas.canvasColor())

        has_pluginlayer = False
        for layerId in settings.layers():
            layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
            if layer and layer.type() == QgsMapLayer.PluginLayer:
                has_pluginlayer = True
                break

        # create an image
        image = QImage(width, height, QImage.Format_ARGB32_Premultiplied)
        painter = QPainter()
        painter.begin(image)
        if antialias:
            painter.setRenderHint(QPainter.Antialiasing)

        # rendering
        job = QgsMapRendererCustomPainterJob(settings, painter)
        if has_pluginlayer:
            job.renderSynchronously(
            )  # use this method so that TileLayerPlugin layer is rendered correctly
        else:
            job.start()
            job.waitForFinished()
        painter.end()

        # restore map settings
        settings.setOutputSize(old_outputSize)
        settings.setExtent(old_extent)
        settings.setRotation(old_rotation)
        settings.setLayers(old_layerids)
        settings.setBackgroundColor(old_backgroundColor)

        return tools.base64image(image)
예제 #11
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)

        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