16

How to add layers (vector or raster to an existing GeoPackage)?

While loading an existing layer of a GeoPackage is quite trivial:

from qgis.utils import iface

path = '/home/matteo/geopackage.gpkg|layername={}'.format('admin') iface.addVectorLayer(path, 'admin', 'ogr')

I couldn't find information about adding them via PyQGIS.

Taras
  • 32,823
  • 4
  • 66
  • 137
matteo
  • 3,304
  • 1
  • 23
  • 47

4 Answers4

14

You need to use QgsVectorFileWriter.writeAsVectorFormat. If you store one layer per GPKG file you just need:

QGIS 3:

# imports
from qgis.utils import iface
from qgis.core import QgsProject, QgsVectorFileWriter

get layer list by one of:

lyrs = iface.layerTreeView().selectedLayers() lyrs = QgsProject.instance().layerTreeRoot().children()

select layer

lyr = lyrs[0] _writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, r"C:\gisData\layer.gpkg")

QGIS 2:

# imports
from qgis.utils import iface
from qgis.core import QgsMapLayerRegistry, QgsVectorFileWriter

get layer list by one of:

lyrs = iface.mapCanvas().layers() # OR lyrs = QgsMapLayerRegistry.instance().mapLayers()

select layer

lyr = lyrs[0] _writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, r"C:\gisData\layer.gpkg")

If you want save more than one layer in GeoPackage file you should set additional options.

from qgis.core import QgsMapLayer, QgsVectorFileWriter

for lyr in filter(lambda l: l.type() == QgsMapLayer.VectorLayer, lyrs): options = QgsVectorFileWriter.SaveVectorOptions() options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer options.layerName = "_".join(lyr.name().split(' ')) _writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, gpkgPath, options) if _writer: print(lyr.name(), _writer)

PyQGIS should have similar interface for raster layers. In my opinion easiest way to find out is to install IPyConsole plugin and use PyQGIS API.

Taras
  • 32,823
  • 4
  • 66
  • 137
user19291
  • 405
  • 4
  • 11
  • 2
    QgsMapLayerRegistry is gone in QGIS 3, but writeAsVectorFormat should still be there. Sidenote, there is also the QgsVectorLayerExporter class available. – Matthias Kuhn Nov 02 '18 at 07:38
13

Write a layer to a GeoPackage

The easiest way to save a vector layer to GeoPackage is to use the "Save vector features to file" algorithm, available from QGIS 3.16 on.

import processing

params = {'INPUT': existing_layer, 'OUTPUT': '/tmp/new_gpkg.gpkg', 'LAYER_NAME': 'new_layer_name'} processing.run("native:savefeatures", params)

Note that you can pass additional GDAL/OGR options by passing DATASOURCE_OPTIONS and LAYER_OPTIONS parameters.

Warning: If you pass a path to an existing GeoPackage as OUTPUT parameter, this algorithm will replace your GeoPackage by a new one!!!

Adding an additional layer to an existing GeoPackage

Option 1

If you want to add a layer to an existing GeoPackage (and still preserve other existing layers!), you can use the GDAL's "Convert format" algorithm in this way:

import processing

params = {'INPUT': existing_layer, 'OPTIONS':'-update -nln my_new_layer_name', 'OUTPUT':'/tmp/existing_db.gpkg'} processing.run("gdal:convertformat", params)

Where -update indicates the existing GeoPackage shouldn't be overwritten but updated, and -nln (optional) indicates the layer name you want your existing_layer to have when created into the existing GeoPackage.

Option 2

You could also use the "Package layers" algorithm, which allows you to add several layers at once, in this way:

import processing

params = {'LAYERS': [layer1, layer2], 'OUTPUT': '/tmp/existing_db.gpkg', 'OVERWRITE': False, # Important! 'SAVE_STYLES': False, 'SAVE_METADATA': False, 'SELECTED_FEATURES_ONLY': False} processing.run("native:package", params)

Note: Set the rest of parameters as you like, but the OVERWRITE one should be set to False if you want to update the existing GeoPackage.

Taras
  • 32,823
  • 4
  • 66
  • 137
Germán Carrillo
  • 36,307
  • 5
  • 123
  • 178
  • This seems to be directly creating a new geopackage from an existing layer. Is there a way to add an existing layer to an existing geopackage? – WFL.GIS Aug 19 '21 at 01:30
  • Just try passing as OUTPUT an existing GeoPackage file path, as the answers also suggests. – Germán Carrillo Aug 19 '21 at 01:42
  • Yes, I used an existing gpkg as output and got an error message (it attempts to create a new gpkg with that name, and throws an error since it already exists). I was able to figure it out just now, though -- to add a new layer to an existing gpkg, "qgis:package" should be used instead. – WFL.GIS Aug 19 '21 at 02:00
  • 1
    You're actually right. I edited my answer to show a solution for your use case. – Germán Carrillo Aug 19 '21 at 02:40
7

I have investigated this code an create a script like it works very well for exporting raster layer to GeoPackage:

from osgeo import ogr
from qgis.core import QgsRasterLayer, QgsRasterFileWriter, QgsRasterPipe, QgsRasterProjector

ds = ogr.Open(self.projectGpkg, True) source = QgsRasterLayer(layerSource, 'rasterLayer', 'gdal')

if source.isValid(): provider = source.dataProvider() fw = QgsRasterFileWriter(self.projectGpkg) fw.setOutputFormat('gpkg') fw.setCreateOptions(["RASTER_TABLE=" + str(tableName), 'APPEND_SUBDATASET=YES'])

pipe = QgsRasterPipe()
if pipe.set(provider.clone()) is True:
    projector = QgsRasterProjector()
    projector.setCrs(provider.crs(), provider.crs())
    if pipe.insert(2, projector) is True:
        if fw.writeRaster(pipe, provider.xSize(), provider.ySize(), provider.extent(), provider.crs()) == 0:
            print("ok")
        else:
            print("error")

ds = None

For reading raster layer in GeoPackage:

from qgis.core import QgsRasterLayer

rlayer = QgsRasterLayer('GPKG:' + str(self.projectGpkg) + ':tableName', "layerName")

Taras
  • 32,823
  • 4
  • 66
  • 137
Mustafa Uçar
  • 1,581
  • 18
  • 29
1

For raster layers, use the GDAL's "Translate (convert format)" algorithm:

import processing

params = { 'COPY_SUBDATASETS' : False, 'DATA_TYPE' : 0, 'EXTRA' : '-co APPEND_SUBDATASET=YES -co RASTER_TABLE=name_of_layer', 'INPUT' : layer_to_add, 'NODATA' : None, 'OPTIONS' : '', 'OUTPUT' : 'existing.gpkg', 'TARGET_CRS' : None } processing.run("gdal:translate", params)

For vector layers see the answer from @GermánCarrillo.

Taras
  • 32,823
  • 4
  • 66
  • 137
Tom Brennan
  • 4,787
  • 6
  • 26