Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make tile service GoogleMaps-Compatible when the cog file is GoogleMapsCompatible #1637

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion martin/src/args/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,10 @@ mod tests {
let err = args.merge_into_config(&mut config, &env);
assert!(err.is_ok());
assert_yaml_snapshot!(config, @r#"
pmtiles: "../tests/fixtures/cog"
mbtiles: "../tests/fixtures/cog"
cog:
- "../tests/fixtures/cog/rgb_u8.tif"
- "../tests/fixtures/cog"
- "../tests/fixtures/cog/rgba_u8_nodata.tiff"
- "../tests/fixtures/cog/rgba_u8.tif"
"#);
Expand Down
3 changes: 3 additions & 0 deletions martin/src/cog/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ pub enum CogError {

#[error("Striped tiff file is not supported, the tiff file is {0}")]
NotSupportedChunkType(PathBuf),

#[error("Failed to parse GDAL metadata: {0}")]
GdalMetadataError(String),
}
93 changes: 89 additions & 4 deletions martin/src/cog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use crate::{
MartinResult, Source, TileData, UrlQuery,
};

use regex::Regex;

#[derive(Clone, Debug)]
pub struct CogSource {
id: String,
Expand All @@ -41,6 +43,8 @@ struct Meta {
zoom_and_ifd: HashMap<u8, usize>,
zoom_and_tile_across_down: HashMap<u8, (u32, u32)>,
nodata: Option<f64>,
google_compatible_max_zoom: Option<u8>,
google_compatible_min_zoom: Option<u8>,
}

#[async_trait]
Expand Down Expand Up @@ -75,9 +79,14 @@ impl Source for CogSource {
Decoder::new(tif_file).map_err(|e| CogError::InvalidTiffFile(e, self.path.clone()))?;
decoder = decoder.with_limits(tiff::decoder::Limits::unlimited());

let ifd = self.meta.zoom_and_ifd.get(&(xyz.z)).ok_or_else(|| {
let actual_zoom = if let Some(google_zoom) = self.meta.google_compatible_max_zoom {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should calculate the actual_x and actual_y either.

self.meta.max_zoom - google_zoom + xyz.z
} else {
xyz.z
};
let ifd = self.meta.zoom_and_ifd.get(&(actual_zoom)).ok_or_else(|| {
CogError::ZoomOutOfRange(
xyz.z,
actual_zoom,
self.path.clone(),
self.meta.min_zoom,
self.meta.max_zoom,
Expand Down Expand Up @@ -216,8 +225,8 @@ impl SourceConfigExtras for CogConfig {
let meta = get_meta(&path)?;
let tilejson = tilejson! {
tiles: vec![],
minzoom: meta.min_zoom,
maxzoom: meta.max_zoom
minzoom: meta.google_compatible_min_zoom.unwrap_or(meta.min_zoom),
maxzoom: meta.google_compatible_max_zoom.unwrap_or(meta.max_zoom),
};
Ok(Box::new(CogSource {
id,
Expand Down Expand Up @@ -287,6 +296,9 @@ fn get_meta(path: &PathBuf) -> Result<Meta, FileError> {
} else {
None
};

let (tiling_schema_name, zoom_level) = get_tilling_schema(&mut decoder).unwrap_or((None, None));

let images_ifd = get_images_ifd(&mut decoder);

let mut zoom_and_ifd: HashMap<u8, usize> = HashMap::new();
Expand Down Expand Up @@ -315,9 +327,21 @@ fn get_meta(path: &PathBuf) -> Result<Meta, FileError> {
.keys()
.max()
.ok_or_else(|| CogError::NoImagesFound(path.clone()))?;

let google_compatible_max_zoom =
if tiling_schema_name == Some("GoogleMapsCompatible".to_string()) {
zoom_level
} else {
None
};
let google_compatible_min_zoom =
google_compatible_max_zoom.map(|google_max_zoom| google_max_zoom - max_zoom + min_zoom);

Ok(Meta {
min_zoom: *min_zoom,
max_zoom: *max_zoom,
google_compatible_max_zoom,
google_compatible_min_zoom,
zoom_and_ifd,
zoom_and_tile_across_down,
nodata,
Expand Down Expand Up @@ -375,3 +399,64 @@ fn get_images_ifd(decoder: &mut Decoder<File>) -> Vec<usize> {
}
res
}

fn get_tilling_schema(
decoder: &mut Decoder<File>,
) -> Result<(Option<String>, Option<u8>), CogError> {
let gdal_metadata = decoder
.get_tag_ascii_string(Tag::Unknown(42112))
.map_err(|e| CogError::TagsNotFound(e, vec![42112], 0, PathBuf::new()))?;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just return None. It's normal a tiff file have no tag 42112


let mut tiling_schema_name = None;
let mut zoom_level = None;

let re_name = Regex::new(r#"<Item name="NAME" domain="TILING_SCHEME">([^<]+)</Item>"#).unwrap();
let re_zoom =
Regex::new(r#"<Item name="ZOOM_LEVEL" domain="TILING_SCHEME">([^<]+)</Item>"#).unwrap();

if let Some(caps) = re_name.captures(&gdal_metadata) {
tiling_schema_name = Some(caps[1].to_string());
}

if let Some(caps) = re_zoom.captures(&gdal_metadata) {
zoom_level = caps[1].parse().ok();
}

Ok((tiling_schema_name, zoom_level))
}

#[cfg(test)]
mod tests {
use rstest::rstest;

#[rstest]
#[case("../tests/fixtures/cog/google_compatible.tif", Some("GoogleMapsCompatible".to_string()), Some(14))]
#[case("../tests/fixtures/cog/rgba_u8_nodata.tiff", None, None)]
fn test_get_gdal_metadata(
#[case] path: &str,
#[case] expected_tiling_schema_name: Option<String>,
#[case] expected_zoom_level: Option<u8>,
) {
use std::{fs::File, path::PathBuf};

use tiff::decoder::Decoder;

use crate::cog::get_tilling_schema;

let path = PathBuf::from(path);
let tif_file = File::open(&path).expect("Failed to open test fixture file");
let mut decoder = Decoder::new(tif_file).expect("Failed to create decoder");

let (tiling_schema_name, zoom_level) =
get_tilling_schema(&mut decoder).expect("Failed to get GDAL metadata");

assert_eq!(
tiling_schema_name, expected_tiling_schema_name,
"TILING_SCHEME_NAME value should match the expected value"
);
assert_eq!(
zoom_level, expected_zoom_level,
"ZOOM_LEVEL value should match the expected value"
);
}
}
3 changes: 3 additions & 0 deletions tests/expected/auto/catalog_auto.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@
"description": "One of the example maps that comes with TileMill - a bright & colorful world map that blends retro and high-tech with its folded paper texture and interactive flag tooltips. ",
"name": "Geography Class"
},
"google_compatible": {
"content_type": "image/png"
},
"json": {
"content_type": "application/json",
"name": "Dummy json data"
Expand Down
8 changes: 8 additions & 0 deletions tests/expected/auto/google_compatible.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"maxzoom": 14,
"minzoom": 12,
"tilejson": "3.0.0",
"tiles": [
"http://localhost:3111/google_compatible/{z}/{x}/{y}"
]
}
1 change: 1 addition & 0 deletions tests/expected/auto/save_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ cog:
- tests/fixtures/pmtiles
- tests/fixtures/cog
sources:
google_compatible: tests/fixtures/cog/google_compatible.tif
rgb_u8: tests/fixtures/cog/rgb_u8.tif
rgba_u8: tests/fixtures/cog/rgba_u8.tif
rgba_u8_nodata: tests/fixtures/cog/rgba_u8_nodata.tiff
Expand Down
Binary file added tests/fixtures/cog/google_compatible.tif
Binary file not shown.
4 changes: 4 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ test_jsn rgba_u8_nodata rgba_u8_nodata
test_png rgba_u8_nodata_0_0_0 rgba_u8_nodata/0/0/0
test_png rgba_u8_nodata_1_0_0 rgba_u8_nodata/1/0/0

test_jsn google_compatible google_compatible
# test_png google_compatible_13_0_0 google_compatible/13/0/0
# test_png google_compatible_14_0_0 google_compatible/14/0/0

>&2 echo "***** Test server response for table source with empty SRID *****"
test_pbf points_empty_srid_0_0_0 points_empty_srid/0/0/0

Expand Down
Loading