Пример #1
0
def renderMapToImage(mapsettings, parallel=False):
    """
    Render current map to an image, via multi-threaded renderer
    :param QgsMapSettings mapsettings:
    :param bool parallel: Do parallel or sequential render job
    :rtype: QImage
    """
    if parallel:
        job = QgsMapRendererParallelJob(mapsettings)
    else:
        job = QgsMapRendererSequentialJob(mapsettings)
    job.start()
    job.waitForFinished()

    return job.renderedImage()
Пример #2
0
    def setMap(self):
        def finished():
            self.swipe.setContent(job.renderedImage(),
                                  self.map_canvas.extent())

        if len(self.swipe.layers) == 0:
            return

        settings = QgsMapSettings(self.map_canvas.mapSettings())
        settings.setLayers(self.swipe.layers)

        job = QgsMapRendererParallelJob(settings)
        job.start()
        job.finished.connect(finished)
        job.waitForFinished()
Пример #3
0
 def getmap(self):
     if self.canvas:
         if QGis.QGIS_VERSION_INT > 20200:
             from qgis.core import QgsMapRendererParallelJob
             self.renderjob = QgsMapRendererParallelJob(
                 self.canvas.mapSettings())
             self.renderjob.finished.connect(self.rendermap)
             self.renderjob.start()
         else:
             pixmap = QPixmap(self.canvas.size())
             pixmap.fill(self.canvas.canvasColor())
             painter = QPainter(pixmap)
             renderer = self.canvas.mapRenderer()
             renderer.render(painter)
             del painter
             self.scribbleArea.addMap(pixmap)
    def _process(self):
        def finished():
            image = job.renderedImage()
            if bool(self.data['canvas'].property('retro')):
                image = image.scaled(image.width() / 3, image.height() / 3)
                image = image.convertToFormat(
                    QImage.Format_Indexed8,
                    Qt.OrderedDither | Qt.OrderedAlphaDither)
            image.save(self.data['filepath'], "TIFF", 100)  # 100: Uncompressed
            self._setParamsSendData(image)

        settings = QgsMapSettings(self.data['canvas'].mapSettings())
        settings.setBackgroundColor(QColor(Qt.transparent))

        settings.setLayers(self.data['layers'])
        job = QgsMapRendererParallelJob(settings)
        job.start()
        job.finished.connect(finished)
        job.waitForFinished()
    def writeLegendPng(self, layer, mapTitle, mapAttr, operation):
        mapTitle = UTILS.normalizeName(mapTitle)
        mapAttr = UTILS.normalizeName(mapAttr)
        legendFolder = self.getPathForMap(mapTitle, mapAttr, operation)

        # e.g. vlayer = iface.activeLayer()
        options = QgsMapSettings()
        options.setLayers([layer])
        options.setBackgroundColor(QColor(255, 128, 255))
        options.setOutputSize(QSize(60, 60))
        options.setExtent(layer.extent())
        qgisRenderJob = QgsMapRendererParallelJob(options)

        def savePng():
            img = qgisRenderJob.renderedImage()
            # save the image; e.g. img.save("/Users/myuser/render.png","png")
            img.save(os.path.join(legendFolder, "legend.png"), "png")

        qgisRenderJob.finished.connect(savePng)
        qgisRenderJob.start()
Пример #6
0
    def render_qgis_map(self):
        logging.info("Rendering QGIS map")
        # Gross. Fix me
        if not self.settings and project:
            self.settings = project.map_settings

        # TODO We should only get visible layers here but this will do for now
        self.settings.setLayers(QgsMapLayerRegistry.instance().mapLayers().keys())
        self.settings.setFlags(self.settings.flags() ^ QgsMapSettings.Antialiasing)
        logging.info(self.settings.flags())
        logging.info(self.settings.testFlag(QgsMapSettings.Antialiasing))
        height, width = self.mapwin.getmaxyx()
        logging.info("Setting output size to {}, {}".format(width, height))
        self.settings.setOutputSize(QSize(width, height))
        job = QgsMapRendererParallelJob(self.settings)
        job.start()
        job.waitForFinished()
        image = job.renderedImage()
        logging.info("Saving rendered image for checks...")
        image.save(r"F:\dev\qgis-term\render.jpg")
        return image
Пример #7
0
    def create_image(self, extent, width, height, canvas_name, output_dir):
        '''
        This method create an image

        :param extent: Extent
        :param width: Output image width
        :param height: Output image height
        :param canvas_name: Map name
        :param output_dir: Output directory for image
        '''

        if not extent:
            raise_exception('extent is empty')

        if not width:
            raise_exception('width is empty')

        if not height:
            raise_exception('height is empty')

        if not canvas_name:
            raise_exception('canvas name is empty')

        if not output_dir:
            raise_exception('output_dir is empty')

        file_name = '{0}/{1}.png'.format(output_dir, canvas_name)
        settings = QgsMapSettings()
        settings.setLayers(iface.mapCanvas().layers())
        settings.setBackgroundColor(QColor(255, 255, 255))
        settings.setOutputSize(QSize(width, height))
        settings.setExtent(extent)
        render = QgsMapRendererParallelJob(settings)
        render.start()
        render.waitForFinished()
        image = render.renderedImage()
        image.save(file_name, "png")

        return file_name
Пример #8
0
def write_image(destination_crs, extent, filepath, imagetype):
    """
    Save current QGIS canvas to image file.
    """
    settings = QgsMapSettings()  # build settings
    settings.setDestinationCrs(destination_crs)  # set output crs
    settings.setExtent(extent)  # in destination_crs
    layers = iface.mapCanvas().layers()  # get visible layers
    settings.setLayers(layers)

    w = 1920
    h = int((extent.yMaximum() - extent.yMinimum()) /
            (extent.xMaximum() - extent.xMinimum()) * w)
    settings.setOutputSize(QSize(w, h))
    settings.setOutputDpi(200)

    render = QgsMapRendererParallelJob(settings)
    render.start()
    render.waitForFinished()
    image = render.renderedImage()
    try:
        image.save(filepath, imagetype)
    except IOError:
        raise QgsProcessingException(f"Image not writable at <{filepath}>")
    def _start_job(self):

        map_settings = None

        if self._node_type:
            log.debug(f'Rendering image for node type: {self._node_type}')

        # Not sure why this needs to be a string comparison, instead of enum
        if f'{self._node_type}' == 'PlanetNodeType.DAILY_SCENE':

            if not self._item_type_ids:
                log.debug('No item type_id keys list object passed')
                return
            if LOG_VERBOSE:
                log.debug(f'item_type_ids:\n{self._item_type_ids}')

            if not self._extent_json:
                log.debug('Extent is invalid')
                return
            if LOG_VERBOSE:
                log.debug(f'extent_json:\n{self._extent_json}')

            if not self._api_key:
                log.debug('No API in passed')
                return

            if self._width <= 0 or self._height <= 0:
                log.debug('Invalid output width or height')
                return

            log.debug(f'Starting render map setup for {self._item_key}')

            # noinspection PyArgumentList
            # p = QgsProject.instance()

            data_src_uri = tile_service_data_src_uri(
                self._item_type_ids, self._api_key, tile_hash=self._tile_hash)
            log.debug(f'Render data_src_uri:\n'
                      f'{data_src_uri}')

            if not data_src_uri:
                log.debug('Invalid data source URI returned')
                return

            self._rlayer: QgsRasterLayer = \
                QgsRasterLayer(data_src_uri, self._item_key, "wms")

            if not self._rlayer.isValid():
                log.debug('Render layer is not valid')
                return

            # p.addMapLayer(rlayer, False)

            ext: QgsRectangle = \
                qgsgeometry_from_geojson(self._extent_json).boundingBox()

            if ext.isEmpty():
                log.debug('Extent bounding box is empty or null')
                return

            if ext.width() > ext.height():
                self._height = int(ext.height() / ext.width() * self._height)
            elif ext.height() > ext.width():
                self._width = int(ext.width() / ext.height() * self._width)

            # noinspection PyArgumentList
            transform = QgsCoordinateTransform(
                QgsCoordinateReferenceSystem('EPSG:4326'),
                QgsCoordinateReferenceSystem(self._dest_crs),
                QgsProject.instance())

            transform_extent = transform.transformBoundingBox(ext)

            if transform_extent.isEmpty():
                log.debug('Transformed extent bounding box is empty or null')
                return

            map_settings = QgsMapSettings()
            map_settings.setExtent(transform_extent)
            map_settings.setOutputSize(QSize(self._width, self._height))
            map_settings.setLayers([self._rlayer])

            log.debug(f'QgsMapSettings set for {self._item_key}')

        if map_settings is not None:

            self._job = QgsMapRendererParallelJob(map_settings)

            # noinspection PyUnresolvedReferences
            self._job.finished.connect(self._job_finished)

            self._has_job = True

            log.debug(f'Render job initialized for {self._item_key}')
        else:
            log.debug(f'No render job initialized for {self._item_key}')

        self._job.start()
Пример #10
0
    def test_render_via_job(self):
        """
        Test rendering an annotation layer via a map render job
        """
        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)
        i1_id = 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)
        i2_id = layer.addItem(item)

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

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

        settings = QgsMapSettings()
        settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
        settings.setExtent(QgsRectangle(10, 10, 18, 18))
        settings.setOutputSize(QSize(200, 200))
        settings.setLayers([layer])

        job = QgsMapRendererParallelJob(settings)
        job.start()
        job.waitForFinished()

        # check rendered item results
        item_results = job.takeRenderedItemResults()
        item_details = item_results.renderedItems()
        self.assertEqual(len(item_details), 3)
        self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3)
        self.assertCountEqual([i.itemId() for i in item_details],
                              [i1_id, i2_id, i3_id])
        self.assertCountEqual([
            i.itemId() for i in item_results.renderedAnnotationItemsInBounds(
                QgsRectangle(0, 0, 1, 1))
        ], [])
        self.assertCountEqual([
            i.itemId() for i in item_results.renderedAnnotationItemsInBounds(
                QgsRectangle(10, 10, 11, 18))
        ], [i2_id])
        self.assertCountEqual([
            i.itemId() for i in item_results.renderedAnnotationItemsInBounds(
                QgsRectangle(10, 10, 12, 18))
        ], [i1_id, i2_id, i3_id])

        # bounds should be in map crs
        self.assertEqual(
            [i.boundingBox() for i in item_details if i.itemId() == i1_id][0],
            QgsRectangle(11.5, 13, 12, 13.5))
        self.assertEqual(
            [i.boundingBox() for i in item_details if i.itemId() == i2_id][0],
            QgsRectangle(11, 13, 12, 15))
        self.assertEqual([
            i.boundingBox().toString(1) for i in item_details
            if i.itemId() == i3_id
        ][0], '11.5,12.5 : 12.5,13.5')
Пример #11
0
def write_image(
    feedback,
    tex_layer,
    tex_pixel_size,
    destination_crs,
    destination_extent,
    filepath,
    imagetype,
):
    """
    Save current QGIS canvas to image file.
    """

    feedback.pushInfo("Rendering texture image (timeout in 30s)...")
    project = QgsProject.instance()

    # Get extent size in meters
    d = QgsDistanceArea()
    d.setSourceCrs(
        crs=destination_crs, context=QgsProject.instance().transformContext()
    )
    p00, p10, p01 = (
        QgsPointXY(destination_extent.xMinimum(), destination_extent.yMinimum()),
        QgsPointXY(destination_extent.xMaximum(), destination_extent.yMinimum()),
        QgsPointXY(destination_extent.xMinimum(), destination_extent.yMaximum()),
    )
    wm = d.measureLine(p00, p10)  # euclidean dist, extent width in m
    hm = d.measureLine(p00, p01)  # euclidean dist, extent height in m

    # Image settings and texture layer choice
    settings = QgsMapSettings()  # build settings
    settings.setDestinationCrs(destination_crs)  # set output crs
    settings.setExtent(destination_extent)  # in destination_crs
    if tex_layer:
        layers = (tex_layer,)  # chosen texture layer
    else:
        canvas = iface.mapCanvas()
        layers = canvas.layers()  # get visible layers
    wpix = int(wm / tex_pixel_size)
    hpix = int(hm / tex_pixel_size)
    settings.setOutputSize(QSize(wpix, hpix))
    settings.setLayers(layers)
    feedback.pushInfo(
        f"Requested texture size: {wm:.2f}x{hm:.2f} m, {wpix}x{hpix} pixels."
    )

    # Render and save image
    render = QgsMapRendererParallelJob(settings)
    render.start()
    t0 = time.time()
    while render.isActive():
        dt = time.time() - t0
        QCoreApplication.processEvents()
        if feedback.isCanceled():
            render.cancelWithoutBlocking()
            return
        if dt >= 30.0:
            render.cancelWithoutBlocking()
            feedback.reportError("Render timed out, no texture saved.")
            return
    image = render.renderedImage()
    try:
        image.save(filepath, imagetype)
    except IOError:
        raise QgsProcessingException(
            f"Texture not writable to <{filepath}>, cannot proceed."
        )
    feedback.pushInfo(f"Texture saved in {dt:.2f} seconds.")
Пример #12
0
def write_texture(
    feedback,
    tex_layer,
    tex_extent,
    tex_pixel_size,
    utm_crs,  # destination_crs
    filepath,
    imagetype,
):
    """
    Crop and save texture to image file.
    """

    # Calc tex_extent size in meters (it is in utm)
    tex_extent_xm = tex_extent.xMaximum() - tex_extent.xMinimum()
    tex_extent_ym = tex_extent.yMaximum() - tex_extent.yMinimum()

    # Calc tex_extent size in pixels
    tex_extent_xpix = int(tex_extent_xm / tex_pixel_size)
    tex_extent_ypix = int(tex_extent_ym / tex_pixel_size)

    # Choose exporting layers
    if tex_layer:  # use user tex layer
        layers = (tex_layer,)
    else:  # no user tex layer, use map canvas
        canvas = iface.mapCanvas()
        layers = canvas.layers()

    # Image settings and texture layer choice
    settings = QgsMapSettings()  # build settings
    settings.setDestinationCrs(utm_crs)  # set output crs
    settings.setExtent(tex_extent)  # in utm_crs
    settings.setOutputSize(QSize(tex_extent_xpix, tex_extent_ypix))
    settings.setLayers(layers)

    feedback.pushInfo(
        f"Texture size: {tex_extent_xpix} x {tex_extent_ypix} pixels, {tex_extent_xm:.1f} x {tex_extent_ym:.1f} meters"
    )

    # Render and save image
    render = QgsMapRendererParallelJob(settings)
    render.start()
    t0 = time.time()
    while render.isActive():
        dt = time.time() - t0
        QCoreApplication.processEvents()
        if feedback.isCanceled():
            render.cancelWithoutBlocking()
            return
        if dt >= 30.0:
            render.cancelWithoutBlocking()
            feedback.reportError("Texture render timed out, no texture saved.")
            return
    image = render.renderedImage()
    try:
        image.save(filepath, imagetype)
    except IOError:
        raise QgsProcessingException(
            f"Texture not writable to <{filepath}>, cannot proceed."
        )
    feedback.pushInfo(f"Saved (in {dt:.2f} s): <{filepath}>")
Пример #13
0
 def update(self, *__args):
     settings = self.canvas.mapSettings()
     settings.setOutputSize(self.previewImage.size())
     self.renderjob = QgsMapRendererParallelJob(settings)
     self.renderjob.finished.connect(self._renderimage)
     self.renderjob.start()
Пример #14
0
    def make_coco_dataset(self):
        layers = QgsProject.instance().mapLayers().values()
        vectorlayers = [layer for layer in layers if layer.type() == VectorLayer]
        rasterLayers = [layer for layer in layers if layer.type() == RasterLayer]

        vectorlayer = vectorlayers[self.dlg.vectorlayerselector.currentIndex()]
        rasterlayer = rasterLayers[self.dlg.rasterlayerselector.currentIndex()]

        img_size = int(self.dlg.imagesizeselector.currentText())
        scale_realworld = int(self.dlg.zoomlevel.currentText())
        buffer_size = int(self.dlg.buffersize.text()) / 100
        target_dir = self.dlg.dirselectline.text()
        dataset_description = str(self.dlg.datasetdescription.text())
        contributor = str(self.dlg.creatorname.text())
        url = str(self.dlg.url.text())
        version = str(self.dlg.datasetversion.text())
        license = str(self.dlg.licenseselector.currentText())

        # to implement
        scale_to_fit = self.dlg.scaletofit.isChecked()
        use_fieldcategory = bool(self.dlg.usecategoryfields.isChecked())
        categoryfield = self.dlg.categoryfields.currentText()


        QgsMessageLog.logMessage(str(scale_to_fit), "cocotrainer", level=Qgis.Info)
        QgsMessageLog.logMessage(str(use_fieldcategory), "cocotrainer", level=Qgis.Info)

        # prepare directories
        os.makedirs(os.path.join(target_dir, "train"), exist_ok=True)
        os.makedirs(os.path.join(target_dir, "val"), exist_ok=True)

        QgsMessageLog.logMessage("====================================", "cocotrainer", level=Qgis.Info)

        # TODO:
        #  - use field categories

        features_iterator = vectorlayer.getFeatures(QgsFeatureRequest().setFilterExpression('$area > 1'))

        features = [feature for feature in features_iterator]
        QgsMessageLog.logMessage("vector layer: " + vectorlayer.name(), "cocotrainer", level=Qgis.Info)
        QgsMessageLog.logMessage("Filtered polygons smaller than 1m2 from data", "cocotrainer", level=Qgis.Info)
        QgsMessageLog.logMessage("features: " + str(len(list(features))), "cocotrainer", level=Qgis.Info)

        options = QgsMapSettings()
        options.setLayers([rasterlayer])
        options.setOutputSize(QSize(int(img_size), int(img_size)))

        QgsMessageLog.logMessage(str(scale_realworld), "cocotrainer", level=Qgis.Info)
        QgsMessageLog.logMessage(str(img_size), "cocotrainer", level=Qgis.Info)

        date = datetime.now()

        cat_dict = {}
        if use_fieldcategory:
            categories = []
            # uniqueprovider = rasterlayer.dataProvider()
            fields = vectorlayer.fields()
            id = fields.indexFromName(categoryfield)
            uniquevalues = vectorlayer.uniqueValues(id)
            for i, val in enumerate(uniquevalues):
                categories.append({"supercategory": "object", "id": i, "name": str(val)})
                cat_dict[str(val)] = i
        else:
            categories = [{"supercategory": "object", "id": 0, "name": "CATEGORYNAME"}]
            cat_dict["CATEGORYNAME"] = 0

        coco_annotation = {
            "info": {
                "description": dataset_description,
                "url": url,
                "version": version,
                "year": int(date.strftime("%Y")),
                "contributor": contributor,
                "date_created": date.strftime("%d/%m/%y")
            },
            "licenses": [self.license_dict[license]],
            "images": [],
            "annotations": [],
            "categories": categories,
            # < -- Not in Captionsannotations
            "segment_info": []  # < -- Only in Panoptic annotations
        }

        bboxes, polygons = {}, {}
        for i, feature in enumerate(features):
            polygons[i] = feature.geometry()
            bboxes[i] = feature.geometry().boundingBox()

        if use_fieldcategory:
            cats = {}
            for i, feature in enumerate(features):
                cats[i] = str(feature[categoryfield])

        image_id = 0
        annotation_id = 0

        for i, feature in enumerate(features):
            self.dlg.progressBar.setValue((i / len(polygons) * 100))
            QgsMessageLog.logMessage("something is happening", "cocotrainer", level=Qgis.Info)
            geoms = feature.geometry()
            bbox = geoms.boundingBox()

            if scale_to_fit:
                xmax = bbox.xMaximum()
                ymax = bbox.yMaximum()
                ymin = bbox.yMinimum()
                xmin = bbox.xMinimum()

                diffx = xmax - xmin
                diffy = ymax - ymin
                xmax = xmax + (buffer_size * diffx)
                xmin = xmin - (buffer_size * diffx)
                ymax = ymax + (buffer_size * diffy)
                ymin = ymin - (buffer_size * diffy)

            else:
                midpoint = bbox.center()
                QgsMessageLog.logMessage("trying to log centerpoint", "cocotrainer", level=Qgis.Info)
                QgsMessageLog.logMessage(str(midpoint.x()), "cocotrainer", level=Qgis.Info)
                QgsMessageLog.logMessage(str(midpoint.y()), "cocotrainer", level=Qgis.Info)
                xmin = midpoint.x() - scale_realworld / 2
                xmax = midpoint.x() + scale_realworld / 2
                ymin = midpoint.y() - scale_realworld / 2
                ymax = midpoint.y() + scale_realworld / 2

            extent = QgsRectangle(xmin, ymin, xmax, ymax)

            fileid = "{}_{}_{}".format(xmin, ymin, scale_realworld)

            image = {
                "license": 0,
                "file_name": fileid + ".png",
                "coco_url": None,
                "height": img_size,
                "width": img_size,
                "date_captured": date.strftime("%d/%m/%y"),
                "flickr_url": None,
                "id": image_id
            }

            coco_annotation["images"].append(image)

            for j, geo in bboxes.items():
                if extent.contains(geo) or extent.intersects(geo):
                    points = polygons[j].asMultiPolygon()
                    xs = np.array([p.x() - xmin for p in points[0][0]])
                    ys = np.array([(ymax - ymin) - (p.y() - ymin) for p in points[0][0]])

                    xs *= (img_size / scale_realworld)
                    xs = np.round(xs)
                    xs = xs.astype(np.int32)

                    ys *= (img_size / scale_realworld)
                    ys = np.round(ys)
                    ys = ys.astype(np.int32)

                    ys[ys < 0] = 0
                    xs[xs < 0] = 0

                    polygon = [[int(p[0]), int(p[1])] for p in zip(xs, ys)]
                    flat_list = [item for sublist in polygon for item in sublist]
                    QgsMessageLog.logMessage(str(flat_list), "cocotrainer", level=Qgis.Info)

                    pixelposbbox = [int(np.min(xs)), (int(np.min(ys))), geo.width() * (img_size / scale_realworld),
                                    geo.height() * (img_size / scale_realworld)]
                    pixelposbbox = [number if number > 0 else 0 for number in pixelposbbox]

                    QgsMessageLog.logMessage(str([geo.xMinimum(), geo.yMaximum(), geo.width(), geo.height()]),
                                             "cocotrainer", level=Qgis.Info)
                    QgsMessageLog.logMessage(str(pixelposbbox), "cocotrainer", level=Qgis.Info)

                    annotation = {
                        "segmentation": [flat_list],  # format is [x1,y1,x2,y2]
                        "area": polygons[j].area(),
                        "iscrowd": 0,
                        "image_id": image_id,
                        "bbox": pixelposbbox,  # format is [top left x position, top left y position, width, height]
                        "category_id": cat_dict[cats[j]],
                        "id": annotation_id
                    }
                    annotation_id += 1
                    coco_annotation["annotations"].append(annotation)

            options.setExtent(extent)
            render = QgsMapRendererParallelJob(options)

            def finished():
                QgsMessageLog.logMessage("saving image to disk", "cocotrainer", level=Qgis.Info)
                fname = os.path.join(target_dir, 'train', "{}.png".format(fileid))
                img = render.renderedImage()
                if not img.save(fname, "png"):
                    print("Error saving image")

            render.finished.connect(finished)
            render.start()
            render.waitForFinished()
            image_id += 1

        QgsMessageLog.logMessage(str(coco_annotation), "cocotrainer", level=Qgis.Info)

        with open(os.path.join(target_dir, "annotation.json"), "w") as outfile:
            json.dump(coco_annotation, outfile)

        self.dlg.progressBar.setValue(100)
        self.dlg.finished_label.setText("parsed {} features".format(len(list(features))))
def render_scene_to_image(item_keys: List[str],
                          extent_json: Union[str, dict],
                          api_key: str,
                          node: Optional[PlanetNode] = None,
                          width: int = 512,
                          height: int = 512) -> QImage:

    img = QImage()

    if not item_keys:
        log.debug('No item type_id keys list object passed')
        return img

    if not extent_json:
        log.debug('Extent is invalid')
        return img

    if node and node.node_type() != NodeT.DAILY_SCENE:
        log.debug('Item type is not a Daily Scene')
        return img

    if not api_key:
        log.debug('No API in passed')
        return img

    # p = QgsProject.instance()

    ext: QgsRectangle = \
        qgsgeometry_from_geojson(extent_json).boundingBox()

    if ext.width() > ext.height():
        height = int(ext.height() / ext.width() * height)
    elif ext.height() > ext.width():
        width = int(ext.width() / ext.height() * width)

    # noinspection PyArgumentList
    transform = QgsCoordinateTransform(
        QgsCoordinateReferenceSystem("EPSG:4326"),
        QgsCoordinateReferenceSystem("EPSG:3857"), QgsProject.instance())

    transform_extent = transform.transformBoundingBox(ext)

    data_src_uri = tile_service_data_src_uri(item_keys, api_key)
    log.debug(f'data_src_uri:\n' f'{data_src_uri}')

    rlayer = QgsRasterLayer(data_src_uri, "scene_layer", "wms")

    if not rlayer.isValid():
        log.debug('Layer is not valid')
        return img

    # p.addMapLayer(rlayer)

    settings = QgsMapSettings()
    settings.setExtent(transform_extent)
    settings.setOutputSize(QSize(width, height))
    settings.setLayers([rlayer])

    job = QgsMapRendererParallelJob(settings)
    job.start()

    # This blocks...
    # It should really be a QEventLoop or QTimer that checks for finished()
    # Any intermediate image can safely be pulled from renderedImage()
    job.waitForFinished()

    return job.renderedImage()
Пример #16
0
    def update_summary_sheet(self):
        '''
        Creates a summary sheet with thumbnail, layer metadata and online view link
        '''
        #create a layer snapshot and upload it to google drive
        mapbox_style = self.service_sheet.sheet_cell('settings!A5')
        if not mapbox_style:
            print "migrating mapbox style"
            self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr))
        if not self.dirty:
            return
        canvas = QgsMapCanvas()
        canvas.resize(QSize(300,300))
        canvas.setCanvasColor(Qt.white)
        canvas.setExtent(self.lyr.extent())
        canvas.setLayerSet([QgsMapCanvasLayer(self.lyr)])
        canvas.refresh()
        canvas.update()
        settings = canvas.mapSettings()
        settings.setLayers([self.lyr.id()])
        job = QgsMapRendererParallelJob(settings)
        job.start()
        job.waitForFinished()
        image = job.renderedImage()
        tmp_path = os.path.join(self.parent.plugin_dir,self.service_sheet.name+".png")
        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.iteritems():
            print imagename, image_props['id']
            self.service_drive.delete_file(image_props['id'])
        result = self.service_drive.upload_image(tmp_path)
        print "UPLOADED", result
        self.service_drive.add_permission(result['id'],'anyone','reader')
        webLink = 'https://drive.google.com/uc?export=view&id='+result['id']
        os.remove(tmp_path)
        print 'result',result,webLink

        #update layer metadata
        summary_id = self.service_sheet.add_sheet('summary', no_grid=True)
        self.service_sheet.erase_cells('summary')
        metadata = self.get_layer_metadata()
        range = 'summary!A1:B8'
        update_body = {
            "range": range,
            "values": metadata,
        }
        print "update", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=range, body=update_body, valueInputOption='USER_ENTERED').execute()

        #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'
                }
            }]
        }
        print "merge", self.service_sheet.service.spreadsheets().batchUpdate(spreadsheetId=self.spreadsheet_id, body=request_body).execute()
        print "image", 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:
            range = 'summary!A9:B9'
            update_body = {
                "range": range,
                "values": [['public link', "https://enricofer.github.io/GooGIS2CSV/converter.html?spreadsheet_id="+self.spreadsheet_id]]
            }
            print "update_public_link", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=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.iteritems():
            if not sheet_name == 'summary':
                print sheet_name, sheet_id
                self.service_sheet.toggle_sheet(sheet_name, sheet_id, hidden=True)
    def responseComplete(self):
        request = self.serverInterface().requestHandler()
        params = request.parameterMap()

        # SERVICE=RENDERGEOJSON -- we are taking over
        if params.get('SERVICE', '').upper() == 'RENDERGEOJSON':
            request.clear()
            try:
                # Parse parameters
                geojson = params.get('GEOJSON')
                if not geojson:
                    raise ParameterError('Parameter GEOJSON must be set.')

                style = params.get('STYLE')
                if not style:
                    raise ParameterError('Parameter STYLE must be set.')

                try:
                    width = int(params.get('WIDTH'))
                except TypeError:
                    raise ParameterError('Parameter WIDTH must be integer.')
                try:
                    height = int(params.get('HEIGHT'))
                except TypeError:
                    raise ParameterError('Parameter HEIGHT must be integer.')

                try:
                    dpi = int(params.get('DPI', 96))
                except TypeError:
                    raise ParameterError('Parameter DPI must be integer.')

                try:
                    minx, miny, maxx, maxy = params.get('BBOX').split(',')
                    bbox = QgsRectangle(float(minx), float(miny), float(maxx),
                                        float(maxy))
                except (ValueError, AttributeError):
                    raise ParameterError(
                        'Parameter BBOX must be specified in the form `min_x,min_y,max_x,max_y`.'
                    )

                url = geojson
                geojson_file_name = self._resolve_url(geojson)

                if '$type' in style:
                    polygon_style = self._resolve_url(
                        style.replace('$type', 'polygons'))
                    line_style = self._resolve_url(
                        style.replace('$type', 'lines'))
                    point_style = self._resolve_url(
                        style.replace('$type', 'points'))
                else:
                    polygon_style = self._resolve_url(style)
                    line_style = polygon_style
                    point_style = polygon_style

                polygon_layer = QgsVectorLayer(
                    geojson_file_name + '|geometrytype=Polygon', 'polygons',
                    'ogr')
                self._load_style(polygon_layer, polygon_style)
                line_layer = QgsVectorLayer(
                    geojson_file_name + '|geometrytype=Line', 'lines', 'ogr')
                self._load_style(line_layer, line_style)
                point_layer = QgsVectorLayer(
                    geojson_file_name + '|geometrytype=Point', 'points', 'ogr')
                self._load_style(point_layer, point_style)

                settings = QgsMapSettings()
                settings.setOutputSize(QSize(width, height))
                settings.setOutputDpi(dpi)
                settings.setExtent(bbox)
                settings.setLayers([polygon_layer, line_layer, point_layer])
                settings.setBackgroundColor(QColor(Qt.transparent))
                renderer = QgsMapRendererParallelJob(settings)

                event_loop = QEventLoop()
                renderer.finished.connect(event_loop.quit)
                renderer.start()

                event_loop.exec_()

                img = renderer.renderedImage()
                img.setDotsPerMeterX(dpi * 39.37)
                img.setDotsPerMeterY(dpi * 39.37)
                image_data = QByteArray()
                buf = QBuffer(image_data)
                buf.open(QIODevice.WriteOnly)
                img.save(buf, 'PNG')

                request.setResponseHeader('Content-type', 'image/png')
                request.appendBody(image_data)
            except ParameterError as e:
                QgsMessageLog.logMessage(
                    "RenderGeojson.responseComplete :: ParameterError")
                request.setResponseHeader('Content-type', 'text/plain')
                request.appendBody(str(e).encode('utf-8'))
            except:
                QgsMessageLog.logMessage(
                    "RenderGeojson.responseComplete :: Exception")
                QgsMessageLog.logMessage(
                    "RenderGeojson.responseComplete ::   {}".format(
                        traceback.format_exc()))
                request.setResponseHeader('Content-type', 'text/plain')
                request.appendBody(b'Unhandled error')
                request.appendBody(traceback.format_exc().encode('utf-8'))
Пример #18
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)