-
Notifications
You must be signed in to change notification settings - Fork 180
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
WMS prototype working #572
WMS prototype working #572
Conversation
Wooot thank for the PR @mindless-bureaucrat 🙏 |
@mindless-bureaucrat I've got some change I'll push later today which will do:
Things to discuss:
|
I initially had WMS as an extension, however the behavior seems similar to the
At this time GetMap will pull the first layer specified (in the string-split list). I know in real WMS there's a way to pull and overlay multiple layers in a single call, however I think that is beyond the scope of just exposing a simple WMS protocol with this addition |
"image/jp2", | ||
"image/tiff; application=geotiff", | ||
] | ||
supported_version: List[str] = ["1.0.0", "1.1.0", "1.3.0"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now this is hardcoded, let's discuss later how users could change ☝️
}, | ||
}, | ||
openapi_extra={ | ||
"parameters": [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👇 with openapi_extra we add entries to the openapi.json schema (swagger docs) but this is just for display
😄 (the api will accept lower and upper case)
|
||
GetCapability will generate a WMS XML definition. | ||
|
||
GetMap is mostly copied from titiler.core.factory.TilerFactory.part.part | ||
""" | ||
processed_wms_params = process_wms_params(_request) | ||
print(processed_wms_params) | ||
req = {k.lower(): v for k, v in request.query_params.items()} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the middleware function and put everything here directly
with rasterio.Env(**env): | ||
with self.reader(src_path, **reader_params) as src_dst: | ||
image = src_dst.part( | ||
buffer=buffer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed buffer for now but we could add it back
if processed_wms_params.get('format'): | ||
imagetype = ImageType(MediaType(processed_wms_params['format'])._name_) | ||
else: | ||
imagetype = ImageType.jpeg if image.mask.all() else ImageType.png |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the auto
mode is not really part of the specification so I removed it
<DCPType> | ||
<HTTP> | ||
<Get onlineResource="{{ request_url }}" /> | ||
<Post onlineResource="{{ request_url }}" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't accept POST
request so I guess we should remove this
<Name>{{layer}}</Name> | ||
<Title>{{layer}}</Title> | ||
<Abstract>{{layers_dict[layer]['abstract']}}</Abstract> | ||
<SRS>{{" ".join(available_epsgs)}}</SRS> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have to repeat the list of SRS here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it's needed, but this is what I saw in all the auto-generated WMS XMLs from Geoserver and ESRI
# Build information for the whole service | ||
minx, miny, maxx, maxy = zip( | ||
*[layers_dict[layer]["bounds_wgs84"] for layer in layers_dict] | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to change the order here?
@mindless-bureaucrat the more I think about this, the more I feel uncomfortable adding a WMS endpoint in the tiler factories. Here is why:
I'm not quite sure we want to make a |
100% agree that WMS has seen better days. Unfortunately I (and likely others) am working in an environment with legacy web clients. This plugin/extension allows us to support modern clients (tile/rest based) along with dinosaurs on the same data definitions without having to run Geoserver (or similar WMS server) in addition to our beautiful TiTiler and FastAPI endpoints :) . Happy to have this functionality as a separate factory! Separate library would be second best. Docs-only... 😭. |
👍 ok then ToDo
|
so in parallel I've started #575, if it goes well I'll add a wmsExtension to the package with most of the code we added here. then we could use it as from fastapi import FastAPI
from titiler.core.factory import TilerFactory
from titiler.extensions import wmsExtension
app = FastAPI()
tiler = TilerFactory(
extensions=[
wmsExtension()
]
)
app.include_router(tiler.router) |
I've moved all the WMS related code to an extension. TODO:
|
@mindless-bureaucrat would you be able to review the code before we merge? 🙏 I'll take care of the documentation in another PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are a machine! Great looking tests and cleanup. Have a couple comments regarding using the mosaic method rather than .part, and a few WMS spec related things.
**dataset_params, | ||
) | ||
|
||
image, assets_used = mosaic_reader( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory we should only be passing a single layer in the layers
qs param, although I supposed this could work for a very simple mosaic method, absent MosaicJson. Is this the intended purpose rather than just getting the image out with .part() directly? How would this work with the MosaicTilerFactory if a user specified a custom backend?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so here we use simple mosaic, meaning you just need to pass multiple file name, there is no idea of mosaic json or mosaic backend.
How would this work with the MosaicTilerFactory if a user specified a custom backend?
It won't work for mosaic backend because they don't implement .part()
method (I might add it in titiler-pgstac)
72.22979795551834, | ||
-52.301598718454485, | ||
74.66298001264106, | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we implement the mosaic method in this PR as well, or wait until a future version? I have a working prototype in my local rats nest, happy to wait or push to a later date :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because mosaic backend do not implement part()
method, I'm not planing to add it
@mindless-bureaucrat I'm going to merge this PR, please if you have more comments feel free to raise them before we make the next release 🙏 |
This PR adds WMS functionality to the base
TilerFactory
at/wms
Notes:
process_wms_params
static method.layers
params. This behavior deviates from the standardurl
param as the primary COG input in the route./tiles
route, but usessrc_dst.part
with bbox rather than.tile
.preview