Repository navigation
swift-mapnik 2.1.0
A correctness and robustness release: 108 issues from a full audit, spanning silent rendering bugs, concurrency defects, and CI.
Fixed: silently wrong output
RenderOptions.scalewas ignored byrender(bounds:),renderToFileandrenderPNG256— @2x requests produced @1x images.RenderOptions.heightwas ignored by all tile and metatile rendering; every request produced a square image.renderPNG256ignoredskipFullyTransparentandformat.srs/layerSRStruncated projection strings at 255 characters.BoundingBox(parsing:)accepted malformed input —"1,2,foo,3,4"became(1,2,3,4)with the bad field silently dropped.- Datasource inspection rounded every double to 6 significant digits (~10 m at Web Mercator magnitudes).
- Antimeridian-crossing bounds expanded to the whole world in
TileSequence/MetatileSequence. renderTileon a non-Web-Mercator map rendered empty while the docs called it "valid".TilelistBuilder.tileCountcounted duplicates whiletilelistde-duplicated.
Fixed: crashes and data races
saveXML(explicitDefaults: true)segfaulted on mapnik 4.x (upstream memory corruption); now rejected with a clear error.MapnikPool.releaseallowed double release, handing the same non-thread-safeMapnikto two callers.WorkQueuewas permanently dead after any error (inFlightnever reset).MapnikConfig.initializepoisoned the process for nonexistent paths, and silently ignored custom paths after the first lazy init.- Layer accessors trapped on indices outside
Int32; public initializers usedpreconditionfor user input. - Datasource destruction was the one lifecycle path outside the documented serialization.
Fixed: configuration
- Linux plugin version comparison never parsed versions —
4.10sorted below4.2, so the wrong plugin directory could win. pkg-configprobing could deadlock on a full stderr pipe.
Breaking changes
renderMetatile is now a single entry point, and MetatileOptions is removed:
// before
try map.renderMetatile(origin: tile, metaSize: 4, options: .tile())
try map.renderMetatile(block, options: MetatileOptions(metaSize: 4, render: .tile()))
// after
try map.renderMetatile(try Metatile(origin: tile, metaSize: 4), options: .tile())
try map.renderMetatile(block, options: .tile())The block size now comes from Metatile.metaSize alone, so it cannot disagree with the options. Metatile.pixelSize(for:) replaces the MetatileOptions size helpers.
Also breaking: Metatile/TileSequence/MetatileSequence initializers are now throws; MapnikError gained a case and is Equatable; MapnikPoolError.exhausted carries a limit; TilelistBuilder.tileCount counts unique tiles.