GeoConvert 0.1.4
See the version list below for details.
dotnet add package GeoConvert --version 0.1.4
NuGet\Install-Package GeoConvert -Version 0.1.4
<PackageReference Include="GeoConvert" Version="0.1.4" />
<PackageVersion Include="GeoConvert" Version="0.1.4" />
<PackageReference Include="GeoConvert" />
paket add GeoConvert --version 0.1.4
#r "nuget: GeoConvert, 0.1.4"
#:package GeoConvert@0.1.4
#addin nuget:?package=GeoConvert&version=0.1.4
#tool nuget:?package=GeoConvert&version=0.1.4
<img src="/src/icon.png" height="30px"> GeoConvert
Convert maps between geospatial formats, with no third-party dependencies — only the .NET base
class libraries (System.Text.Json, System.Xml, System.IO.Compression). It can also render a
bounding box to a PNG image. Ships as a library and a geoconvert command line tool.
Supported formats
All vector formats can be both read and written; PNG is a write-only raster export.
| Format | Extension(s) | Kind |
|---|---|---|
| GeoJSON | .geojson, .json |
JSON |
| TopoJSON | .topojson |
JSON (topology encoded) |
| Shapefile | .shp (+ .shx, .dbf, .prj) |
Binary |
| FlatGeobuf | .fgb |
Binary (FlatBuffers) |
| KML | .kml |
XML |
| KMZ | .kmz |
Zipped KML |
| GPX | .gpx |
XML |
| WKT | .wkt |
Text |
| WKB | .wkb |
Binary |
| CSV | .csv |
Text (WKT or lon/lat columns) |
| GeoParquet | .parquet, .geoparquet |
Binary (Apache Parquet) |
| PNG | .png |
Raster image (write-only) |
All coordinates are treated as WGS84 (EPSG:4326) longitude/latitude.
Library
Convert a file to another format (both formats inferred from their extensions):
<a id='snippet-Convert'></a>
// Formats are inferred from the file extensions.
GeoConverter.Convert("cities.geojson", "cities.kml");
GeoConverter.Convert("roads.shp", "roads.fgb");
<sup><a href='/src/Tests/Snippets.cs#L6-L10' title='Snippet source file'>snippet source</a> | <a href='#snippet-Convert' title='Start of snippet'>anchor</a></sup>
Read into the common feature model, then write a different format:
<a id='snippet-ReadModifyWrite'></a>
// Read any supported format into the common feature model.
var collection = GeoConverter.Read("roads.shp");
foreach (var feature in collection)
{
if (feature.Properties.TryGetValue("name", out var name))
{
Console.WriteLine(name);
}
}
// Write it back out as a different format.
GeoConverter.Write(collection, "roads.fgb");
<sup><a href='/src/Tests/Snippets.cs#L15-L29' title='Snippet source file'>snippet source</a> | <a href='#snippet-ReadModifyWrite' title='Start of snippet'>anchor</a></sup>
Build a collection in memory and serialize it:
<a id='snippet-BuildModel'></a>
var collection = new FeatureCollection
{
new Feature(
new Point(new(151.21, -33.87)),
new Dictionary<string, object?> { ["name"] = "Sydney" }),
};
var geoJson = GeoJson.WriteString(collection);
<sup><a href='/src/Tests/Snippets.cs#L34-L43' title='Snippet source file'>snippet source</a> | <a href='#snippet-BuildModel' title='Start of snippet'>anchor</a></sup>
Raster export (PNG)
Render a FeatureCollection to a PNG, clipped to a bounding box, with a software rasterizer and a
hand-written PNG encoder (no third-party dependencies):
<a id='snippet-RenderToPng'></a>
var collection = GeoConverter.Read("countries.geojson");
// Render a specific bounding box (min lon, min lat, max lon, max lat) to a PNG.
var options = new RenderOptions
{
Bounds = new Envelope(-10, 35, 30, 60),
Width = 1200,
Height = 900,
};
MapRenderer.RenderPng(collection, "europe.png", options);
<sup><a href='/src/Tests/Snippets.cs#L49-L61' title='Snippet source file'>snippet source</a> | <a href='#snippet-RenderToPng' title='Start of snippet'>anchor</a></sup>
RenderOptions controls the extent (Bounds), pixel Width/Height (height is derived from the
aspect ratio when left at 0), Padding, and the Background/Stroke/Fill colors. From the command
line, output a .png and pass --bbox and --size:
geoconvert world.geojson europe.png --bbox -10,35,30,60 --size 1200x900
Exampl generated png
All Australian suburbs
<img src="/src/Tests/PngTests.Render_RealMap.verified.png" height="1100px">
Command line
Installed as a .NET tool named
geoconvert:
geoconvert <input> <output> [--from <format>] [--to <format>]
Formats are detected from the file extensions; --from/--to override that. Examples:
geoconvert cities.geojson cities.kml
geoconvert roads.shp roads.fgb
geoconvert data.csv data.geojson --from csv
Run geoconvert --list to see the supported format names, or geoconvert --help for usage.
Model
Everything reads into and writes out of a FeatureCollection:
Feature— aGeometryplus a string-keyedPropertiesdictionary and an optionalId.Geometry—Point,LineString,Polygon,MultiPoint,MultiLineString,MultiPolygonorGeometryCollection, built fromPositionvalues (X = longitude, Y = latitude, optional Z and M).
Benchmarks
BenchmarkDotNet benchmarks live in src/Benchmarks and must run in
Release:
dotnet run -c Release --project src/Benchmarks -- --filter "*"
ConvertBenchmarks measures reading and writing a 500-polygon collection through each stream format;
RenderBenchmarks measures PNG rasterization. Add --job Dry for a quick smoke run.
Notes and limitations
- Shapefile holds a single geometry category per file; writing a collection that mixes points,
lines and polygons throws. This is mandated by the format, not a GeoConvert choice — the
.shpheader declares one shape type for the whole file, so a mixed collection has no valid encoding and the consumer must split it into one file per geometry type first. Output is 2D: the format does define Z and M variants, but GeoConvert drops those ordinates rather than emit them. A WGS84.prjis emitted. - FlatGeobuf is written without the optional packed R-tree spatial index
(
index_node_size = 0) and is 2D. The index is a query accelerator, not data: it lets a reader fetch features in a bounding box without scanning the whole file, but carries no information the feature records don't. So GeoConvert reads an indexed file by computing the index size and skipping past it — full-file conversion needs every feature anyway — and writes none, leaving output that is still valid FlatGeobuf (GDAL, QGIS and flatgeobuf.org read it fine) for the consumer to re-index on import if it wants spatial queries. Emitting one would mean hand-rolling a Hilbert R-tree to honour the no-dependency rule, which is real complexity for a benefit a conversion tool rarely needs. - GPX has no native area type: polygons are written as a track with one segment per ring, multi polygons flatten every ring into a single track, and geometry collections write each member geometry in turn. Reading a track with several segments yields a multi line string, so polygons do not survive a round trip as polygons.
- WKT and WKB carry geometry only — feature attributes are dropped on write.
- GeoParquet is written as a single row group with PLAIN-encoded, Snappy-compressed pages and a flat schema; geometry is stored as WKB (Z/M preserved) with the CRS defaulting to OGC:CRS84. The whole Parquet container is hand-rolled to honour the no-dependency rule, so the supported surface is a subset: on read it also handles GZIP/uncompressed pages, dictionary encoding and data page V2 (as written by GDAL, DuckDB and pyarrow). Zstd pages are read on .NET 11 builds (where Zstd is part of the BCL) and rejected with a clear error on earlier targets.
- PNG is a write-only raster export; reading a
.pngthrows. It needs an extent — when noBoundsis given, the full extent of the data is used. - Property values are scalars (
string,long,double,bool); nested JSON is flattened.
Icon
Pattern designed by Kim Sun Young from The Noun Project.
| 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 is compatible. 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 is compatible. 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. net11.0 is compatible. |
-
net10.0
- No dependencies.
-
net11.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on GeoConvert:
| Package | Downloads |
|---|---|
|
MapBundle
Core runtime for MapBundle. Loads bundled map data (borders, cities, waterways) that ships as FlatGeobuf in the MapBundle.World and MapBundle.[Region] packages. Data is derived from OpenStreetMap (© OpenStreetMap contributors, ODbL). |
|
|
GeoConvert.Skia
Optional SkiaSharp-backed PNG render backend for GeoConvert. Rasterizes the same projection, styling and labelling pipeline as the built-in renderer through Skia. Unlike GeoConvert itself, this package takes a third-party dependency (SkiaSharp). |
|
|
GeoConvert.ImageSharp
Optional SixLabors.ImageSharp-backed PNG render backend for GeoConvert. Rasterizes the same projection, styling and labelling pipeline as the built-in renderer through ImageSharp. Unlike GeoConvert itself, this package takes a third-party dependency (SixLabors.ImageSharp, under the Six Labors Split License). |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.1 | 96 | 6/8/2026 |
| 1.1.0 | 89 | 6/8/2026 |
| 1.0.1 | 2,829 | 6/6/2026 |
| 1.0.0 | 90 | 6/6/2026 |
| 0.12.0 | 93 | 6/5/2026 |
| 0.11.0 | 5,652 | 6/3/2026 |
| 0.10.1 | 2,883 | 6/3/2026 |
| 0.10.0 | 2,868 | 6/2/2026 |
| 0.9.1 | 2,887 | 6/2/2026 |
| 0.9.0 | 2,891 | 6/2/2026 |
| 0.8.2 | 2,874 | 6/2/2026 |
| 0.8.1 | 97 | 6/2/2026 |
| 0.8.0 | 94 | 6/1/2026 |
| 0.6.0 | 109 | 5/30/2026 |
| 0.5.1 | 115 | 5/28/2026 |
| 0.5.0 | 105 | 5/28/2026 |
| 0.4.0 | 103 | 5/28/2026 |
| 0.3.0 | 97 | 5/27/2026 |
| 0.2.0 | 90 | 5/27/2026 |
| 0.1.4 | 101 | 5/25/2026 |