Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
76cfbe7
add deps
sharkAndshark Jan 16, 2026
910daf7
add helper method xyz_to_bbox_webmercator
sharkAndshark Jan 16, 2026
bad896b
copy and paste
sharkAndshark Jan 16, 2026
b176c6a
clippy
sharkAndshark Jan 16, 2026
409bf80
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Jan 16, 2026
bd1d631
use #[source] in error.rs
sharkAndshark Jan 16, 2026
91d7152
use const MAX_ZOOM instead of hard coded
sharkAndshark Jan 16, 2026
953c808
better naming
sharkAndshark Jan 16, 2026
bea536c
add auto_webmercator option
sharkAndshark Jan 16, 2026
1242e22
Removed auto_webmercator in favor of enforcing COG are always in EPSG…
Auspicus Jan 17, 2026
dae17e2
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Jan 17, 2026
21d6f72
Add check to ensure that the COG has 'ProjectedCRSGeoKey=EPSG:3857'
Auspicus Jan 17, 2026
3fafbf4
Compute bounds based on extent defined in file, set tileSize in TileJSON
Auspicus Jan 17, 2026
ac244b6
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Jan 17, 2026
5b5de81
clippy
Auspicus Jan 17, 2026
3d70ba1
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Jan 17, 2026
1953671
fmt
Auspicus Jan 17, 2026
48fe787
Add serde_json dep for unstable-cog
Auspicus Jan 17, 2026
33ad7be
chore: sort Cargo.toml
autofix-ci[bot] Jan 17, 2026
377fa1c
Set default limits on buffers used within tiff library
Auspicus Jan 22, 2026
bbdd90d
Single chunk per tile
Auspicus Jan 26, 2026
9be45c7
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Jan 26, 2026
1e9df20
fmt, determine bands per pixel from color_type
Auspicus Jan 26, 2026
bc32e49
Add fixtures representative of a COG with WebMercatorQuad tile matrix…
Auspicus Jan 27, 2026
52d233f
Remove unused xyz_to_bbox_webmercator
Auspicus Jan 27, 2026
eae5654
Update README.md
Auspicus Jan 27, 2026
57652a3
fmt, clippy, return 204 when failing to decode a tile within a valid …
Auspicus Jan 28, 2026
87ae379
Fix dependencies
Auspicus Jan 28, 2026
9565f69
clippy
Auspicus Jan 28, 2026
2c0b1b3
Support RGB and RGBA PNG result
Auspicus Jan 28, 2026
e1af76a
Merge branch 'main' into cog_web_5
Auspicus Jan 30, 2026
dec2168
Update image.rs
Auspicus Jan 31, 2026
9680c1c
Update image.rs
Auspicus Jan 31, 2026
12ef13e
Update image.rs
Auspicus Jan 31, 2026
74c180f
Remove unused clippy expect
Auspicus Feb 1, 2026
947b8e9
Add support for WEBP and ModernJPEG
Auspicus Feb 1, 2026
52be5db
chore(fmt): apply pre-commit formatting fixes
pre-commit-ci[bot] Feb 1, 2026
9fac114
Add more fixtures, add tests using fixtures
Auspicus Feb 1, 2026
1aed41b
Add format to TileJSON
Auspicus Feb 1, 2026
fb808e3
Make output_format parsing a bit more readable
Auspicus Feb 1, 2026
2ff3869
sort deps
nyurik Feb 9, 2026
f18ae44
Merge branch 'main' into cog_web_5
CommanderStorm Feb 9, 2026
c1f4df8
Merge branch 'main' into cog_web_5
CommanderStorm Feb 10, 2026
0c061ba
Apply suggestion from @CommanderStorm
CommanderStorm Feb 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion martin-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ postgres = [
"dep:serde_json",
"_tiles",
]
unstable-cog = ["dep:png", "dep:tiff", "_tiles"]
unstable-cog = [
"dep:png",
"dep:tiff",
"dep:image",
"dep:serde_json",
"_tiles",
]
unstable-rendering = ["styles", "dep:maplibre_native", "dep:image"]
fonts = [
"dep:bit-set",
Expand Down Expand Up @@ -67,6 +73,7 @@ bit-set = { workspace = true, optional = true }
dashmap = { workspace = true, optional = true }
deadpool-postgres = { workspace = true, optional = true }
futures = { workspace = true, optional = true }
image = { workspace = true, optional = true }
itertools = { workspace = true, optional = true }
martin-tile-utils.workspace = true
mbtiles = { workspace = true, optional = true }
Expand Down
45 changes: 27 additions & 18 deletions martin-core/src/tiles/cog/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
## COG Image Representation

* COG file is an image container representing a tile grid
* A COG may have multiple images, also called subfiles, each indexed with an Image File Directory number - [`IFD`](https://download.osgeo.org/libtiff/doc/TIFF6.pdf#[{"num":209,"gen":0},{"name":"FitB"}]#[{"num":76,"gen":0},{"name":"FitB"}]#[{"num":76,"gen":0},{"name":"FitB"}]])
* A COG may have multiple images, also called subfiles or overviews, each indexed with an Image File Directory number - [`IFD`](https://download.osgeo.org/libtiff/doc/TIFF6.pdf#[{"num":209,"gen":0},{"name":"FitB"}]#[{"num":76,"gen":0},{"name":"FitB"}]#[{"num":76,"gen":0},{"name":"FitB"}]])
* A COG must have at least one image.
* The first image (IFD=0) must be a full resolution image, e.g., the one with the highest resolution.
* [Each image may also have a mask](https://docs.ogc.org/is/21-026/21-026.html#_requirement_reduced_resolution_subfiles), which is also indexed with an IFD. The mask is used to [defines a transparency mask](https://www.verypdf.com/document/tiff6/pg_0036.htm). We do not support masks yet.
* While uncommon, COG tile grid might be different from the common ones like Web Mercator.
* [Each image may also have an accompanying mask](https://docs.ogc.org/is/21-026/21-026.html#_requirement_reduced_resolution_subfiles), which is also indexed with an IFD. The mask is used to [define a transparency mask](https://www.verypdf.com/document/tiff6/pg_0036.htm). We do not support masks yet.
* While uncommon, COG tile matrix set ([2D TMS](https://docs.ogc.org/is/17-083r4/17-083r4.html#tilematrixset-requirements-class)) might be different from the common `WebMercatorQuad`. We do not support any TMS other than Web Mercator yet.

### COG structure example
### COG IFD Structure

Here is an example of a tile grid for a COG file with five images and five masks.
Here is an example of a tile grid for a COG file with five images. See [wiki.openstreetmap.org](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale) for more information on resolution.

| ifd | image index | resolution | zoom |
| --- | ----------- | ---------- | ---- |
| 0 | 0 | 20 | 4 |
| 2 | 1 | 40 | 3 |
| 4 | 2 | 80 | 2 |
| 6 | 3 | 160 | 1 |
| 8 | 4 | 320 | 0 |
| ifd | `tile_size` | zoom | resolution (meters / px) |
| --- | ---------- | ---- | ------------------------ |
| 0 | 256 | 4 | 9783.94 |
| 1 | 256 | 3 | 19567.88 |
| 2 | 256 | 2 | 39135.76 |
| 3 | 256 | 1 | 78271.52 |
| 4 | 256 | 0 | 156543.03 |

### Tile grid code representation
### COG file requirements enforced by Martin

```rust, ignore
let images = vec![ image_0, image_1, image_2, image_3, image_4 ];
let minzoom = 0;
let zoom_of_image = image_count - 1 - idx_in_vec; # TODO: what is this?
let maxzoom = images.len() - 1;
Due to the flexibility of the COG, GEOTIFF and TIFF file formats and the assumptions of Martin, not all COG files will be compatible. The following are a few requirements that Martin has of the COG file, some of which are defined in the COG or TIFF spec, some are constraints imposed by assumptions of Martin. If your file conforms to these requirements, it's more likely to work with Martin:

* File MUST define the `ProjectedCRS` `GeoKey` with a value of 3857 (EPSG:3857)
* File MUST use PlanarConfiguration=1 aka. "Contiguous" or "Chunky"
* File MUST use Compression=1 "None", 5 "LZW", 7 "`ModernJPEG`", 8 "Deflate" or 50001 "WEBP" [See GDAL compression tag definitions](https://github.com/OSGeo/gdal/blob/c7d41bf263a1a3951546c5cfa66872fc05dfc8cc/frmts/gtiff/libtiff/tiff.h#L182-L219)
* File MUST use an 8-bit color depth
* File MUST use 3 (RGB) or 4 (RGBA) bands
* File MUST use tile blocks not strips (eg. `TileWidth`, `TileHeight` is defined, not `StripOffsets`, `StripByteCounts`, `RowsPerStrip`, etc.)
* File MUST use square tiles whose dimension is a power of 2 (eg. 256x256 or 512x512)

Using GDAL, you can create a COG file with 5 zoom levels which meets most of these requirements using:

```bash
gdal_translate original.tif compatible.tif -b 1 -b 2 -b 3 -of COG -co BIGTIFF=YES -co TILING_SCHEME=GoogleMapsCompatible -co ADD_ALPHA=YES -co OVERVIEWS=IGNORE_EXISTING -co COMPRESS=LZW -co OVERVIEW_COUNT=4 -co ALIGNED_LEVELS=5 -co NUM_THREADS=ALL_CPUS -co ZOOM_LEVEL_STRATEGY=LOWER -co BLOCKSIZE=512 -co SPARSE_OK=TRUE
```
8 changes: 8 additions & 0 deletions martin-core/src/tiles/cog/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ pub enum CogError {
#[error("The color type {0:?} and its bit depth of the tiff file {1} is not supported yet")]
NotSupportedColorTypeAndBitDepth(tiff::ColorType, PathBuf),

/// Unsupported compression.
#[error("The compression type {0:?} of the tiff file {1} is not supported yet")]
NotSupportedCompression(u16, PathBuf),

/// Striped TIFF format not supported.
#[error("Striped tiff file is not supported, the tiff file is {0}")]
NotSupportedChunkType(PathBuf),
Expand Down Expand Up @@ -86,4 +90,8 @@ pub enum CogError {
/// IO error.
#[error("IO error {0}: {1}")]
IoError(#[source] std::io::Error, PathBuf),

/// Images are not tiled consistently within the file.
#[error("The size of each tile is not consistent.")]
InconsistentTiling(PathBuf),
}
Loading
Loading