shapekit 0.3.2 copy "shapekit: ^0.3.2" to clipboard
shapekit: ^0.3.2 copied to clipboard

Read and write ESRI Shapefiles and GeoPackage feature data in Dart, with streaming, typed geometries, and DBF attribute support.

shapekit #

A comprehensive Dart library for reading and writing ESRI Shapefiles, with GeoPackage support for feature data workflows.

pub package Buy Me A Coffee

Features #

  • Complete Shapefile Support - Read and write .shp, .shx, .dbf, and .prj files
  • 12 Geometry Types - Point, PointM, PointZ, Polyline, PolylineM, PolylineZ, Polygon, PolygonM, PolygonZ, MultiPoint, MultiPointM, MultiPointZ
  • GeoPackage Support - Read feature tables, inspect metadata, stream typed features, and write feature data
  • Streaming Shapefile Reads - Read large shapefiles incrementally with ShapefileStreamReader
  • Attribute Support - Full dBASE III+ (.dbf) file support for feature attributes
  • Projection Support - Read projection information from .prj files
  • Korean Text Support - CP949 encoding for Korean text in attributes
  • UTF-8 Support - Modern UTF-8 encoding support
  • Type-Safe - Strongly typed geometry classes with immutable data structures
  • Clean Architecture - Well-organized codebase following clean architecture principles

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  shapekit: ^0.3.2

Then run:

dart pub get

Quick Start #

Reading a Shapefile #

import 'package:shapekit/shapekit.dart';

void main() {
  final shapefile = Shapefile();

  try {
    shapefile.read('path/to/file.shp');
    print('Loaded ${shapefile.records.length} records');

    // Access geometry
    for (final record in shapefile.records) {
      if (record is Point) {
        print('Point: ${record.x}, ${record.y}');
      } else if (record is Polyline) {
        print('Polyline with ${record.numPoints} points');
      } else if (record is Polygon) {
        print('Polygon with ${record.numParts} parts');
      }
    }

    // Access attributes (if .dbf file exists)
    for (int i = 0; i < shapefile.attributeRecords.length; i++) {
      print('Record $i attributes: ${shapefile.attributeRecords[i]}');
    }

    // Access projection EPSG code (if .prj file exists)
    if (shapefile.epsgCode != null) {
      print('Projection EPSG: ${shapefile.epsgCode}');
    }
  } on ShapefileException catch (e) {
    print('Error reading shapefile: ${e.message}');
  }
}

Writing a Shapefile #

import 'package:shapekit/shapekit.dart';

void main() {
  final shapefile = Shapefile();

  // Create point records
  final records = [
    Point(126.9780, 37.5665), // Seoul
    Point(129.0756, 35.1796), // Busan
  ];

  // Create attribute fields
  final fields = [
    DbaseField.fieldC('NAME', 50),
    DbaseField.fieldN('POPULATION', 10),
  ];

  // Create attribute records
  final attributes = [
    ['Seoul', 9776000],
    ['Busan', 3413000],
  ];

  // Write shapefile
  shapefile.writeComplete(
    'cities.shp',
    ShapeType.shapePOINT,
    records,
    minX: 126.9780,
    minY: 35.1796,
    maxX: 129.0756,
    maxY: 37.5665,
    attributeFields: fields,
    attributeRecords: attributes,
  );

  print('Shapefile created successfully!');
}

Reading a GeoPackage #

import 'package:shapekit/shapekit.dart';

Future<void> main() async {
  final gpkg = GpkgReader.open('path/to/file.gpkg');

  try {
    final tables = gpkg.listFeatureTables();
    print('Feature tables: $tables');

    await for (final batch in gpkg.queryFeatures(
      table: tables.first,
      bounds: const Envelope(-180, -90, 180, 90),
      loadAttributes: true,
    )) {
      for (final feature in batch.features) {
        print('${feature.fid}: ${feature.geometry.type}');
      }
    }
  } finally {
    gpkg.close();
  }
}

Streaming a Shapefile #

import 'package:shapekit/shapekit.dart';

Future<void> main() async {
  final reader = ShapefileStreamReader.open('path/to/file.shp', isUtf8: true);

  await for (final feature in reader.features()) {
    print('Feature ${feature.index}: ${feature.geometry.type}');
  }
}

Supported Geometry Types #

Geometry Type Class Description
Point Point Single point (X, Y)
PointM PointM Point with measure value (X, Y, M)
PointZ PointZ Point with Z and M values (X, Y, Z, M)
Polyline Polyline Line or multi-line (parts, points)
PolylineM PolylineM Polyline with optional M values
PolylineZ PolylineZ Polyline with Z and optional M values
Polygon Polygon Polygon or multi-polygon (parts, points)
PolygonM PolygonM Polygon with optional M values
PolygonZ PolygonZ Polygon with Z and optional M values
MultiPoint MultiPoint Collection of points
MultiPointM MultiPointM MultiPoint with optional M values
MultiPointZ MultiPointZ MultiPoint with Z and optional M values
MultiPatch MultiPatch 3D surface ❌ not yet implemented

Text Encoding #

The library supports multiple text encodings for attribute data:

// UTF-8 encoding (default, recommended)
final shapefile = Shapefile(isUtf8: true);

// CP949 encoding (for Korean legacy data)
final shapefile = Shapefile(isCp949: true);

// ASCII encoding (when both flags are false)
final shapefile = Shapefile();

Attribute Field Types #

When working with dBASE attributes, use these field types:

// Character field (text)
DbaseField.fieldC('NAME', 50)  // name, max length

// Date field
DbaseField.fieldD('DATE')  // name only

// Logical field (boolean)
DbaseField.fieldL('ACTIVE')  // name only

// Numeric field (integer)
DbaseField.fieldN('COUNT', 10)  // name, total digits

// Numeric field (floating point)
DbaseField.fieldNF('AREA', 20, 8)  // name, total digits, decimal places

Limitations #

  • No MultiPatch support - MultiPatch geometry type is not yet implemented
  • No coordinate transformation - The library reads projection information but does not transform coordinates
  • Synchronous I/O - File operations are synchronous (blocking)

Error Handling #

The library uses typed exceptions for error handling:

try {
  final shapefile = Shapefile();
  shapefile.read('data.shp');
} on FileNotFoundException catch (e) {
  print('File not found: ${e.path}');
} on InvalidHeaderException catch (e) {
  print('Invalid shapefile header: ${e.message}');
} on CorruptedDataException catch (e) {
  print('Corrupted data: ${e.details}');
} on ShapefileException catch (e) {
  print('Shapefile error: $e');
}

Exception Types:

  • FileNotFoundException - File not found or cannot be accessed
  • InvalidHeaderException - Invalid file header
  • InvalidFormatException - Invalid file format
  • CorruptedDataException - Corrupted record data
  • UnsupportedTypeException - Unsupported geometry type
  • ShapefileIOException - File I/O error
  • GpkgException - GeoPackage read/write/query error

Support #

If you find this library helpful, consider supporting its development! ☕️

Buy Me A Coffee

Your support helps me:

  • 🐛 Fix bugs faster
  • ✨ Add new features and projections
  • 📚 Improve documentation
  • 🚀 Build more GIS tools for the community

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

References #

Acknowledgments #

This library is based on the shapefile-kr repository by @michael-kim-korea.

1
likes
150
points
184
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Read and write ESRI Shapefiles and GeoPackage feature data in Dart, with streaming, typed geometries, and DBF attribute support.

Repository (GitHub)
View/report issues

Topics

#shapefile #gis #geospatial #esri #mapping

Funding

Consider supporting this project:

www.buymeacoffee.com

License

ISC (license)

Dependencies

cp949_codec, meta, sqlite3

More

Packages that depend on shapekit