feat(unstable-cog): Change tile path semantics for COG sources to match other sources, expose COG bounds, center and tileSize in TileJSON#2510
Conversation
auto_webmercator config optionauto_webmercator config option
auto_webmercator config option|
Great work! Some thoughts here:
yes and not.. Actually only works for the last zoom, eg, if the zoom range is 8 -20, we could only skip re-projecting at zoom 20 with that gdal option.
Yeah. For web-frinendly eanbled, it should be enforced.
It's a breaking change. Unfortunally our server rely on this feature with a local CRS(without a epsg code). It's pretty fast as no clipping and merging. Option1 Remove it. As Most user only use 3857. My company could keep our martin branch and someday contributing back upstream once martin figure out how to tell user the inner tilegrid of COG. I think Option 2 Keep it. And make web-friendly default. But We should keep the code as it's the most efficient way to serve tiles, no clipping and merging. And can serve any CRS. I perfer option1. It's the most easy way. Once #343 is resolved, we could add it back.
Is it true? |
|
From original PR description notes
I'm not sure why that would be the case if the internal tile blocks were aligned 1:1 with the WebMercator grid. Since a request for
I think to get this over the line and "stable-ish" we could aim for MVP that's fast but maybe doesn't support all the variations of COGs just yet. I will work on a full list of requirements for the COG file to work within the current system but it sounds like we're in alignment on:
I've gone with option 1 here. Keeping support will require extra complexity to the feature and it seems likely it will confuse users who want COGs to "just work".
It seems as though there was a change between v1.0.0 and v1.2.0 that made the fonts feature take a lot more memory on boot. It took about as much memory as my COG file so I thought it was that. Even when no fonts are loaded. Removing the pre-computed masks drops this significantly. I haven't dug in far enough to get to the bottom of it. I run martin without the fonts feature. TLDR; not sure how the tiff crate handles buffering, etc. yet but it doesn't seem to be the immediate culprit for this spike. |
We noticed an increase in this in the folliwing PR, but we apparently should have looke deeper into this, rahter than just accepting it. |
|
@CommanderStorm I have a proposal to help with the memory usage here: #2519 but I'm not sure if it gets it all the way across the line. I think there's more that could be done. |
@sharkAndshark I think I see what you mean. Let me try a few things out and report back. Ultimately it'd be a premature optimization to even try this without seeing how much the pixel by pixel copy costs. FWIW, where you've gotten it to feels pretty fast on my machine. Might not be necessary to go further :) |
|
@sharkAndshark I've found that using the following options with GDAL produces a COG that aligns at all generated zoom levels so that all tile requests have exactly 1 intersecting tile in the source file: The key options are I'm working on a commit to adjust the clipping and zoom level approximation to account for this. I will push that soon. It also appears that currently the only supported compression codecs are LZW, DEFLATE and NONE. Also, the
|
Good job! I would try this and inspect the inner layout of result file. If the aligning is from top down then there would be no different extents. But if the aligning is from full resolution to the last overview, there would be. So maybe gdal work from top to down when aligned levels count bigger than 1. |
|
One thing which you can decide (I am fine with both ways) is if we want to stabilise this feature and take it into the default compilation. The effect of this is that it makes breaking changes slower (since they require a SemVer-major bump), so if you think this needs some in the short-term future, we should not do that. |
From the GDAL docs it says:
So this will work but requires padding of the higher zooms to align them with the lower zooms, and you're right to be hesitant about that. This will generate a larger file than necessary for sure. I wonder if
Testing with this option on a small area, with SPARSE_OK=TRUE the file is ~4MB with 10 zoom levels. Without SPARSE_OK=TRUE the file is closer to 80MB. Both were using WEBP compression which likely makes this difference smaller than it would be with PNG, or JPEG. |
|
Amazingly, SPARSE_OK=TRUE actually kinda works in this MR. But you get an error logged for all the missing tiles. I'll see if we can rectify that. I generated an LZW compression COG and the difference was much greater between SPARSE_OK=TRUE/FALSE. Still around ~4MB with SPARSE_OK=TRUE but ~300MB with SPARSE_OK=FALSE.
|
|
@sharkAndshark do you mind casting another eye over this when you have some time? |
CommanderStorm
left a comment
There was a problem hiding this comment.
Nice work, looks good to me.
I have a few nits, nothing major
Obviously, I would like a review from @sharkAndshark if possible
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
Co-authored-by: Frank Elsinga <frank@elsinga.de>
|
Yeah I will review it these days @Auspicus would you mind update the description of this PR either? |
|
I managed to add in support for WEBP and JPEG without much fuss. It might be worth waiting to merge until upstream |
|
That is cool. Both ways are fine with me. |
|
I've created this discussion: #2540 to cover support for other projections than EPSG:3857. I think this will require a bit of consideration. |
## 🤖 New release
* `martin-tile-utils`: 0.6.9 -> 0.6.10 (✓ API compatible changes)
* `mbtiles`: 0.15.1 -> 0.15.2 (✓ API compatible changes)
* `martin-core`: 0.2.6 -> 0.3.0 (⚠ API breaking changes)
* `martin`: 1.3.0 -> 2.0.0
### ⚠ `martin-core` breaking changes
```text
--- failure enum_missing: pub enum removed or renamed ---
Description:
A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_missing.ron
Failed in:
enum martin_core::config::OptOneMany, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/cfg_containers.rs:29
enum martin_core::config::OptBoolObj, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/cfg_containers.rs:8
--- failure module_missing: pub module removed or renamed ---
Description:
A publicly-visible module cannot be imported by its prior path. A `pub use` may have been removed, or the module may have been renamed, removed, or made non-public.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/module_missing.ron
Failed in:
mod martin_core::config, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/mod.rs:1
mod martin_core::config::env, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/env.rs:1
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_missing.ron
Failed in:
struct martin_core::config::env::OsEnv, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/env.rs:53
struct martin_core::config::IdResolver, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/id_resolver.rs:10
struct martin_core::config::env::FauxEnv, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/env.rs:76
--- failure trait_missing: pub trait removed or renamed ---
Description:
A publicly-visible trait cannot be imported by its prior path. A `pub use` may have been removed, or the trait itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/trait_missing.ron
Failed in:
trait martin_core::config::env::Env, previously in file /tmp/.tmpiF3o7Z/martin-core/src/config/env.rs:20
```
<details><summary><i><b>Changelog</b></i></summary><p>
## `mbtiles`
<blockquote>
##
[0.15.2](mbtiles-v0.15.1...mbtiles-v0.15.2)
- 2026-02-11
### Other
- restrict `unused_trait_names` for trait imports
([#2542](#2542))
</blockquote>
## `martin-core`
<blockquote>
##
[0.3.0](martin-core-v0.2.6...martin-core-v0.3.0)
- 2026-02-11
### Added
- *(unstable-cog)* Change tile path semantics for COG sources to match
other sources, expose COG bounds, center and tileSize in TileJSON
([#2510](#2510))
### Other
- *(martin-core)* [**breaking**] remove the configration from the
martin-core crate
([#2521](#2521))
- restrict `unused_trait_names` for trait imports
([#2542](#2542))
</blockquote>
## `martin`
<blockquote>
##
[2.0.0](martin-v1.3.0...martin-v2.0.0)
- 2026-02-11
### Added
- *(srv)* Add HTTP 301 redirects for common URL mistakes
([#2528](#2528))
- *(unstable-cog)* Change tile path semantics for COG sources to match
other sources, expose COG bounds, center and tileSize in TileJSON
([#2510](#2510))
### Fixed
- logs not being integrated with the `path-prefix` correctly
([#2549](#2549))
- Make sure that `route-prefix` does not break the UI when using
trailing slash urls
([#2541](#2541))
### Other
- *(deps)* Bump the all-npm-version-updates group across 2 directories
with 7 updates ([#2553](#2553))
- Add test coverage for header handling in tilejson requests
([#2529](#2529))
- *(martin-core)* [**breaking**] remove the configration from the
martin-core crate
([#2521](#2521))
- *(deps)* autoupdate pre-commit
([#2545](#2545))
- restrict `unused_trait_names` for trait imports
([#2542](#2542))
- *(deps)* Bump the all-npm-version-updates group across 2 directories
with 12 updates ([#2533](#2533))
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>



This change tightens COG support and introduces breaking validation behavior: Martin now only accepts Cloud Optimized GeoTIFFs that are fully compatible with WebMercatorQuad. COGs must be tiled (no strips), use Chunky planar configuration, RGB/RGBA 8-bit imagery or YCbCr, and one of None/LZW/Deflate/ModernJPEG/WEBP compression methods, and must declare ProjectedCRSGeoKey = EPSG:3857. Zoom levels are derived from image resolution and tile size rather than IFD order, tile coordinates are computed in absolute WebMercator space (including non-zero tile origins), and all images must use a consistent tile size. TileJSON generation is updated to include accurate bounds, center, zoom range, and tileSize. As a result, previously accepted but ambiguous or non-WebMercator COGs may now fail to load.