rastergdalqgispyqgisgeopackage

Exporting Vector and Raster Layers to GeoPackage (gpkg) with PyQGIS


How to export layers(shape-files and GTiff) from a list into one gpkg file?
It works for vector and raster layers separately, but only one type of layers is saved in the output.
I've realised what geopackage doesn't update while writing raster layer so I decided to create temp geopackage and after that update the self.output
You can see that below in my code:

def save_as_gpkg(self, layers: List[QgsVectorLayer]):
        for layer in layers:
            layer_name = layer.name()
            context = QgsProject.instance().transformContext()
            if layer.type() == QgsMapLayer.VectorLayer:
                options = QgsVectorFileWriter.SaveVectorOptions()
                options.layerName = layer_name
                options.fileEncoding = layer.dataProvider().encoding()
                options.driverName = "GPKG"
                if os.path.exists(self.output):
                    options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
                else:
                    options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile
                options.EditionCapability = 0
                res = QgsVectorFileWriter.writeAsVectorFormatV3(layer, 
                                                                self.output, 
                                                                context, 
                                                                options)
            elif layer.type() == QgsMapLayer.RasterLayer:
                if layer.isValid():
                    overwrite = [f"RASTER_TABLE={layer_name}", 
                                  "OVERWRITE=YES", 
                                  "APPEND_SUBDATASET=YES"]
                    if os.path.exists(self.output):
                        temp_gpkg = tempfile.NamedTemporaryFile(suffix='.gpkg', delete=False)
                        writer = QgsRasterFileWriter(temp_gpkg.name)
                        writer.setCreateOptions(overwrite)
                        pipe = QgsRasterPipe()
                        pipe.set(layer.dataProvider().clone())
                        res = writer.writeRaster(pipe, layer.width(), layer.height(),layer.extent(),
                                                 layer.crs(), context)
                        temp_gpkg.close()
                        raster_ds = gdal.Open(temp_gpkg.name)
                        raster_driver = gdal.GetDriverByName('GPKG')
                        new_raster_ds = raster_driver.Create(self.output, raster_ds.RasterXSize,
                                                                          raster_ds.RasterYSize,
                                                                          raster_ds.RasterCount,
                                                                         gdal.GDT_Float32)
                        geotransform = raster_ds.GetGeoTransform()
                        new_raster_ds.SetGeoTransform(geotransform)
                        for i in range(1, raster_ds.RasterCount + 1):
                            band = raster_ds.GetRasterBand(i)
                            data = band.ReadAsArray()
                            new_raster_ds.GetRasterBand(i).WriteArray(data)
                        new_raster_ds.FlushCache()

                    else:
                        writer = QgsRasterFileWriter(self.output)
                        writer.setCreateOptions(overwrite)
                        pipe = QgsRasterPipe()
                        pipe.set(layer.dataProvider().clone())
                        res = writer.writeRaster(pipe, layer.width(), layer.height(), layer.extent(), layer.crs(), context)

Interesting, what this string works correct:

QgsProject.instance().write(f"geopackage:{self.output}")

Solution

  • gdal.Translate(self.output, raster_dataset, format='GPKG',
                                           creationOptions=['APPEND_SUBDATASET=YES'])
    

    It works.