IRI.Maptor.Ket.SqlitePersistence
2.8.11
dotnet add package IRI.Maptor.Ket.SqlitePersistence --version 2.8.11
NuGet\Install-Package IRI.Maptor.Ket.SqlitePersistence -Version 2.8.11
<PackageReference Include="IRI.Maptor.Ket.SqlitePersistence" Version="2.8.11" />
<PackageVersion Include="IRI.Maptor.Ket.SqlitePersistence" Version="2.8.11" />
<PackageReference Include="IRI.Maptor.Ket.SqlitePersistence" />
paket add IRI.Maptor.Ket.SqlitePersistence --version 2.8.11
#r "nuget: IRI.Maptor.Ket.SqlitePersistence, 2.8.11"
#:package IRI.Maptor.Ket.SqlitePersistence@2.8.11
#addin nuget:?package=IRI.Maptor.Ket.SqlitePersistence&version=2.8.11
#tool nuget:?package=IRI.Maptor.Ket.SqlitePersistence&version=2.8.11
IRI.Maptor.Ket.SqlitePersistence
SQLite-based geospatial format support for the Maptor library.
Overview
This package provides support for reading SQLite-based geospatial formats:
- MBTiles - Tile-based map storage format for offline mapping
- OGC GeoPackage - Universal geospatial data container (vector features and raster tiles)
Both formats are cross-platform compatible and work seamlessly with .NET 8, MAUI, and mobile platforms (Android, iOS, Windows, macOS).
Supported Formats
πΊοΈ MBTiles
MBTiles is a specification for storing tiled map data in SQLite databases for immediate use and for transfer. It's optimized for offline mapping applications.
Features:
- Raster tiles (PNG, JPEG, WebP)
- Vector tiles (PBF)
- Metadata support (name, description, bounds, attribution)
- TMS (Tile Map Service) coordinate scheme
- Efficient storage with SQLite compression
Specification: MBTiles Spec
π¦ GeoPackage (GPKG)
GeoPackage is an OGC standard for geospatial data exchange. It can store multiple types of data in a single file:
- Vector features (points, lines, polygons)
- Raster tiles and coverage data
- Attributes and metadata
- Multiple layers in a single file
Features:
- OGC standard format
- Cross-platform compatibility
- Rich metadata support
- Spatial indexing (R-Tree)
- Multiple coordinate reference systems
Specification: OGC GeoPackage
Installation
dotnet add package IRI.Maptor.Ket.SqlitePersistence
Usage Examples
MBTiles - Reading Tiles
using IRI.Maptor.Ket.SqlitePersistence.MbTiles;
using IRI.Maptor.Sta.Common.Primitives;
// Create and open MBTiles reader
using var reader = new MbTilesReader("path/to/map.mbtiles");
reader.Open();
// Get metadata
var metadata = reader.Metadata;
Console.WriteLine($"Name: {metadata?.Name}");
Console.WriteLine($"Format: {metadata?.Format}");
Console.WriteLine($"Zoom Range: {metadata?.MinZoom} - {metadata?.MaxZoom}");
Console.WriteLine($"Bounds: {metadata?.Bounds}");
// Get available zoom levels
var zoomLevels = reader.GetZoomLevels();
Console.WriteLine($"Available zooms: {string.Join(", ", zoomLevels)}");
// Get a specific tile (zoom, column, row in TMS scheme)
byte[]? tileData = reader.GetTile(zoom: 10, column: 512, row: 384);
if (tileData != null)
{
// Save tile to file or display
File.WriteAllBytes("tile.png", tileData);
}
// Get tile count
long totalTiles = reader.GetTileCount();
long tilesAtZoom10 = reader.GetTileCount(zoomLevel: 10);
// Get bounding box
BoundingBox? bbox = reader.GetBoundingBox();
MBTiles - Using Data Source
using IRI.Maptor.Ket.SqlitePersistence.MbTiles;
using IRI.Maptor.Sta.Common.Primitives;
// Create MBTiles data source (for use with map viewers)
using var dataSource = new MbTilesDataSource("path/to/map.mbtiles");
// Get tiles for a specific area and map scale
var boundingBox = new BoundingBox(
xMin: -74.01, yMin: 40.70, // New York City area
xMax: -73.99, yMax: 40.72
);
double mapScale = 10000; // Adjust based on your zoom level
var tiles = dataSource.GetTiles(boundingBox, mapScale);
Console.WriteLine($"Loaded {tiles.Count} tiles");
foreach (var tile in tiles)
{
Console.WriteLine($"Tile: {tile.ImageBytes.Length} bytes, Bounds: {tile.BoundingBox}");
}
// Get available zoom levels
var availableZooms = dataSource.GetAvailableZoomLevels();
// Get specific tile
byte[]? specificTile = dataSource.GetTile(zoom: 10, column: 512, row: 384);
GeoPackage - Reading Vector Features
using IRI.Maptor.Ket.SqlitePersistence.GeoPackage;
using IRI.Maptor.Sta.Common.Primitives;
// Create and open GeoPackage vector reader
using var reader = new GpkgVectorReader("path/to/data.gpkg");
reader.Open();
// Get all feature layers
var layers = reader.GetFeatureLayers();
foreach (var layer in layers)
{
Console.WriteLine($"Layer: {layer.TableName}");
Console.WriteLine($" Type: {layer.DataType}");
Console.WriteLine($" Description: {layer.Description}");
Console.WriteLine($" Bounds: ({layer.MinX}, {layer.MinY}) to ({layer.MaxX}, {layer.MaxY})");
}
// Get geometry column information
var geometryInfo = reader.GetGeometryColumnInfo("countries");
Console.WriteLine($"Geometry Column: {geometryInfo?.ColumnName}");
Console.WriteLine($"Geometry Type: {geometryInfo?.GeometryTypeName}");
Console.WriteLine($"SRID: {geometryInfo?.SrsId}");
// Read all features from a layer
var features = reader.ReadFeatures("countries");
Console.WriteLine($"Loaded {features.Count} features");
foreach (var feature in features)
{
Console.WriteLine($"Geometry Type: {feature.TheGeometry?.Type}");
// Access attributes
if (feature.Attributes != null)
{
foreach (var attr in feature.Attributes)
{
Console.WriteLine($" {attr.Key}: {attr.Value}");
}
}
}
// Read features within a bounding box
var bbox = new BoundingBox(-10, 35, 5, 45); // Approximate bounds for Western Europe
var filteredFeatures = reader.ReadFeatures("countries", bbox);
// Get feature count
long featureCount = reader.GetFeatureCount("countries");
// Get spatial reference systems
var srsList = reader.GetSpatialReferenceSystems();
GeoPackage - Using Vector Data Source
using IRI.Maptor.Ket.SqlitePersistence.GeoPackage;
using IRI.Maptor.Sta.Common.Primitives;
// Create GeoPackage vector data source
using var dataSource = new GeoPackageDataSource("path/to/data.gpkg", "countries");
// Get all features as FeatureSet
var featureSet = dataSource.GetAsFeatureSet(null);
Console.WriteLine($"Total features: {featureSet.Features.Count}");
Console.WriteLine($"SRID: {featureSet.Srid}");
// Get features within a bounding box
var bbox = new BoundingBox(-10, 35, 5, 45);
var filteredFeatureSet = dataSource.GetAsFeatureSet(bbox);
// Search features by text
var searchResults = dataSource.Search("Germany");
// Get layer metadata
var metadata = dataSource.LayerMetadata;
Console.WriteLine($"Layer: {metadata?.TableName}");
Console.WriteLine($"Description: {metadata?.Description}");
// Get geometry column info
var geomCol = dataSource.GeometryColumn;
Console.WriteLine($"Geometry: {geomCol?.GeometryTypeName}");
// Get feature count
long count = dataSource.GetFeatureCount();
GeoPackage - Reading Tile Layers
using IRI.Maptor.Ket.SqlitePersistence.GeoPackage;
// Create and open GeoPackage tile reader
using var reader = new GpkgTileReader("path/to/tiles.gpkg");
reader.Open();
// Get all tile layers
var tileLayers = reader.GetTileLayers();
foreach (var layer in tileLayers)
{
Console.WriteLine($"Tile Layer: {layer.TableName}");
Console.WriteLine($" Description: {layer.Description}");
}
// Get tile matrix set (pyramid information)
var tileMatrixSet = reader.GetTileMatrixSet("satellite_tiles");
Console.WriteLine($"SRS ID: {tileMatrixSet?.SrsId}");
Console.WriteLine($"Bounds: {tileMatrixSet?.MinX},{tileMatrixSet?.MinY} to {tileMatrixSet?.MaxX},{tileMatrixSet?.MaxY}");
// Get all zoom levels (tile matrices)
var matrices = reader.GetTileMatrices("satellite_tiles");
foreach (var matrix in matrices)
{
Console.WriteLine($"Zoom {matrix.ZoomLevel}: {matrix.MatrixWidth}x{matrix.MatrixHeight} tiles");
Console.WriteLine($" Tile size: {matrix.TileWidth}x{matrix.TileHeight} pixels");
}
// Get a specific tile
byte[]? tile = reader.GetTile("satellite_tiles", zoom: 10, column: 512, row: 384);
// Get available zoom levels
var zooms = reader.GetZoomLevels("satellite_tiles");
// Get tile count
long totalTiles = reader.GetTileCount("satellite_tiles");
long tilesAtZoom = reader.GetTileCount("satellite_tiles", zoomLevel: 10);
// Get zoom range
var (minZoom, maxZoom) = reader.GetZoomRange("satellite_tiles") ?? (0, 0);
GeoPackage - Using Tile Data Source
using IRI.Maptor.Ket.SqlitePersistence.GeoPackage;
using IRI.Maptor.Sta.Common.Primitives;
// Create GeoPackage tile data source
using var dataSource = new GeoPackageTileDataSource("path/to/tiles.gpkg", "satellite_tiles");
// Get tiles for a specific area and map scale
var bbox = new BoundingBox(-74.01, 40.70, -73.99, 40.72); // NYC
double mapScale = 10000;
var tiles = dataSource.GetTiles(bbox, mapScale);
Console.WriteLine($"Loaded {tiles.Count} tiles");
// Get available zoom levels
var zoomLevels = dataSource.GetAvailableZoomLevels();
// Get specific tile
byte[]? tile = dataSource.GetTile(zoom: 10, column: 512, row: 384);
// Get metadata
var metadata = dataSource.LayerMetadata;
var tileMatrixSet = dataSource.TileMatrixSet;
// Get zoom range
var zoomRange = dataSource.GetZoomRange();
Console.WriteLine($"Zoom range: {zoomRange?.minZoom} - {zoomRange?.maxZoom}");
Coordinate Systems
MBTiles
- Uses TMS (Tile Map Service) coordinate scheme
- Y-axis origin at bottom-left (row 0 is at the bottom)
- Tiles are typically in Web Mercator (EPSG:3857)
- Bounds are stored in WGS84 (EPSG:4326) format
GeoPackage
- Uses XYZ tile scheme for tiles (Y-axis origin at top-left)
- Supports multiple coordinate reference systems (CRS)
- Check
srs_idin metadata for the coordinate system - Common systems:
4326- WGS84 (Geographic)3857- Web Mercator900913- Google Web Mercator (legacy)
Converting Between Tile Schemes
// Converting from XYZ to TMS
int xyzY = 384;
int zoom = 10;
int maxTileIndex = (1 << zoom) - 1; // 2^zoom - 1
int tmsY = maxTileIndex - xyzY;
// Converting from TMS to XYZ
int tmsYValue = 639;
int xyzYValue = maxTileIndex - tmsYValue;
Async Operations
Both readers support async operations:
// MBTiles async
using var mbReader = new MbTilesReader("map.mbtiles");
await mbReader.OpenAsync();
byte[]? tile = await mbReader.GetTileAsync(10, 512, 384);
// GeoPackage async
using var gpReader = new GpkgVectorReader("data.gpkg");
await gpReader.OpenAsync();
using var tileReader = new GpkgTileReader("tiles.gpkg");
await tileReader.OpenAsync();
byte[]? gpTile = await tileReader.GetTileAsync("layer", 10, 512, 384);
Platform Support
β
.NET 8+
β
MAUI (Android, iOS, Windows, macOS)
β
Desktop (Windows, Linux, macOS)
β
Mobile (Android, iOS)
Dependencies
Microsoft.Data.Sqlite.Core- Modern SQLite ADO.NET providerSQLitePCLRaw.bundle_e_sqlite3- Native SQLite binaries for all platformsIRI.Maptor.Sta.Persistence- Maptor persistence abstractionsIRI.Maptor.Sta.Spatial- Maptor spatial types and algorithmsIRI.Maptor.Sta.Ogc- OGC standard implementations
Performance Tips
- Use spatial indexes: Both formats support spatial indexing (R-Tree) for fast queries
- Batch operations: When reading multiple tiles, consider parallel processing
- Connection pooling: Reuse readers/data sources instead of creating new ones
- Bounding box queries: Use bounding box filtering to limit data transfer
- Appropriate zoom levels: Request tiles at appropriate zoom levels for your map scale
Validation
// Validate MBTiles schema
using var mbReader = new MbTilesReader("map.mbtiles");
mbReader.Open();
bool isMbTilesValid = mbReader.ValidateSchema();
// Validate GeoPackage schema
using var gpReader = new GpkgVectorReader("data.gpkg");
gpReader.Open();
bool isGpkgValid = gpReader.ValidateSchema();
Error Handling
try
{
using var reader = new MbTilesReader("map.mbtiles");
reader.Open();
var tile = reader.GetTile(10, 512, 384);
if (tile == null)
{
Console.WriteLine("Tile not found");
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"File not found: {ex.Message}");
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Invalid operation: {ex.Message}");
}
catch (SqliteException ex)
{
Console.WriteLine($"SQLite error: {ex.Message}");
}
Best Practices
- Dispose properly: Always use
usingstatements or callDispose()to release resources - Check for null: Tiles and features may not exist, always check for null
- Validate files: Use
ValidateSchema()to ensure files are valid before processing - Handle exceptions: Wrap file operations in try-catch blocks
- Use async for UI apps: Use async methods in UI applications to avoid blocking
Contributing
Contributions are welcome! Please see the Maptor Contributing Guide.
License
This package is part of the Maptor library and is licensed under the MIT License.
Resources
Support
- π Documentation
- π Report Issues
- π¬ Discussions
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- IRI.Maptor.Sta.Common (>= 2.8.11)
- IRI.Maptor.Sta.Ogc (>= 2.8.11)
- IRI.Maptor.Sta.Persistence (>= 2.8.11)
- IRI.Maptor.Sta.Spatial (>= 2.8.11)
- Microsoft.Data.Sqlite.Core (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.8.11 | 385 | 11/19/2025 |
| 2.8.11-alpha | 376 | 11/19/2025 |
| 2.8.10 | 132 | 11/8/2025 |
| 2.8.10-alpha | 125 | 11/8/2025 |
| 2.8.9-alpha | 113 | 11/1/2025 |