Skip to content

v2.1.0

Latest

Choose a tag to compare

@trasch trasch released this 02 Nov 22:15
1d2b3ee

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.scale was ignored by render(bounds:), renderToFile and renderPNG256 — @2x requests produced @1x images.
  • RenderOptions.height was ignored by all tile and metatile rendering; every request produced a square image.
  • renderPNG256 ignored skipFullyTransparent and format.
  • srs/layerSRS truncated 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.
  • renderTile on a non-Web-Mercator map rendered empty while the docs called it "valid".
  • TilelistBuilder.tileCount counted duplicates while tilelist de-duplicated.

Fixed: crashes and data races

  • saveXML(explicitDefaults: true) segfaulted on mapnik 4.x (upstream memory corruption); now rejected with a clear error.
  • MapnikPool.release allowed double release, handing the same non-thread-safe Mapnik to two callers.
  • WorkQueue was permanently dead after any error (inFlight never reset).
  • MapnikConfig.initialize poisoned the process for nonexistent paths, and silently ignored custom paths after the first lazy init.
  • Layer accessors trapped on indices outside Int32; public initializers used precondition for user input.
  • Datasource destruction was the one lifecycle path outside the documented serialization.

Fixed: configuration

  • Linux plugin version comparison never parsed versions — 4.10 sorted below 4.2, so the wrong plugin directory could win.
  • pkg-config probing 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.