MapProxy 1.16.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mapproxy/__init__.py +0 -0
- mapproxy/cache/__init__.py +36 -0
- mapproxy/cache/azureblob.py +145 -0
- mapproxy/cache/base.py +111 -0
- mapproxy/cache/compact.py +664 -0
- mapproxy/cache/couchdb.py +295 -0
- mapproxy/cache/dummy.py +34 -0
- mapproxy/cache/file.py +185 -0
- mapproxy/cache/geopackage.py +609 -0
- mapproxy/cache/legend.py +83 -0
- mapproxy/cache/mbtiles.py +392 -0
- mapproxy/cache/meta.py +78 -0
- mapproxy/cache/path.py +250 -0
- mapproxy/cache/redis.py +88 -0
- mapproxy/cache/renderd.py +95 -0
- mapproxy/cache/riak.py +202 -0
- mapproxy/cache/s3.py +177 -0
- mapproxy/cache/tile.py +699 -0
- mapproxy/client/__init__.py +0 -0
- mapproxy/client/arcgis.py +79 -0
- mapproxy/client/cgi.py +139 -0
- mapproxy/client/http.py +315 -0
- mapproxy/client/log.py +33 -0
- mapproxy/client/tile.py +150 -0
- mapproxy/client/wms.py +254 -0
- mapproxy/compat/__init__.py +46 -0
- mapproxy/compat/image.py +79 -0
- mapproxy/compat/itertools.py +29 -0
- mapproxy/compat/modules.py +13 -0
- mapproxy/config/__init__.py +22 -0
- mapproxy/config/config.py +201 -0
- mapproxy/config/coverage.py +107 -0
- mapproxy/config/defaults.py +98 -0
- mapproxy/config/loader.py +2286 -0
- mapproxy/config/spec.py +644 -0
- mapproxy/config/validator.py +239 -0
- mapproxy/config_template/__init__.py +0 -0
- mapproxy/config_template/base_config/config.wsgi +10 -0
- mapproxy/config_template/base_config/full_example.yaml +593 -0
- mapproxy/config_template/base_config/full_seed_example.yaml +79 -0
- mapproxy/config_template/base_config/log.ini +35 -0
- mapproxy/config_template/base_config/mapproxy.yaml +60 -0
- mapproxy/config_template/base_config/seed.yaml +27 -0
- mapproxy/exception.py +142 -0
- mapproxy/featureinfo.py +252 -0
- mapproxy/grid.py +1170 -0
- mapproxy/image/__init__.py +536 -0
- mapproxy/image/fonts/DejaVuSans.ttf +0 -0
- mapproxy/image/fonts/DejaVuSansMono.ttf +0 -0
- mapproxy/image/fonts/LICENSE +99 -0
- mapproxy/image/fonts/__init__.py +0 -0
- mapproxy/image/mask.py +75 -0
- mapproxy/image/merge.py +316 -0
- mapproxy/image/message.py +347 -0
- mapproxy/image/opts.py +182 -0
- mapproxy/image/tile.py +167 -0
- mapproxy/image/transform.py +350 -0
- mapproxy/layer.py +470 -0
- mapproxy/multiapp.py +231 -0
- mapproxy/proj.py +302 -0
- mapproxy/request/__init__.py +18 -0
- mapproxy/request/arcgis.py +259 -0
- mapproxy/request/base.py +476 -0
- mapproxy/request/tile.py +128 -0
- mapproxy/request/wms/__init__.py +793 -0
- mapproxy/request/wms/exception.py +99 -0
- mapproxy/request/wmts.py +436 -0
- mapproxy/response.py +237 -0
- mapproxy/script/__init__.py +0 -0
- mapproxy/script/conf/__init__.py +0 -0
- mapproxy/script/conf/app.py +195 -0
- mapproxy/script/conf/caches.py +45 -0
- mapproxy/script/conf/layers.py +54 -0
- mapproxy/script/conf/seeds.py +37 -0
- mapproxy/script/conf/sources.py +86 -0
- mapproxy/script/conf/utils.py +143 -0
- mapproxy/script/defrag.py +184 -0
- mapproxy/script/export.py +333 -0
- mapproxy/script/grids.py +188 -0
- mapproxy/script/scales.py +126 -0
- mapproxy/script/util.py +406 -0
- mapproxy/script/wms_capabilities.py +152 -0
- mapproxy/seed/__init__.py +0 -0
- mapproxy/seed/cachelock.py +121 -0
- mapproxy/seed/cleanup.py +187 -0
- mapproxy/seed/config.py +469 -0
- mapproxy/seed/script.py +388 -0
- mapproxy/seed/seeder.py +538 -0
- mapproxy/seed/spec.py +64 -0
- mapproxy/seed/util.py +254 -0
- mapproxy/service/__init__.py +14 -0
- mapproxy/service/base.py +46 -0
- mapproxy/service/demo.py +356 -0
- mapproxy/service/kml.py +331 -0
- mapproxy/service/ows.py +38 -0
- mapproxy/service/template_helper.py +53 -0
- mapproxy/service/templates/demo/capabilities_demo.html +16 -0
- mapproxy/service/templates/demo/demo.html +181 -0
- mapproxy/service/templates/demo/openlayers-demo.cfg +16 -0
- mapproxy/service/templates/demo/static/img/blank.gif +0 -0
- mapproxy/service/templates/demo/static/img/east-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/north-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/south-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/west-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-minus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-plus-mini.png +0 -0
- mapproxy/service/templates/demo/static/img/zoom-world-mini.png +0 -0
- mapproxy/service/templates/demo/static/logo.png +0 -0
- mapproxy/service/templates/demo/static/ol.css +345 -0
- mapproxy/service/templates/demo/static/ol.js +4 -0
- mapproxy/service/templates/demo/static/proj4.min.js +1 -0
- mapproxy/service/templates/demo/static/proj4defs.js +1 -0
- mapproxy/service/templates/demo/static/site.css +137 -0
- mapproxy/service/templates/demo/static/theme/default/framedCloud.css +0 -0
- mapproxy/service/templates/demo/static/theme/default/google.css +17 -0
- mapproxy/service/templates/demo/static/theme/default/ie6-style.css +10 -0
- mapproxy/service/templates/demo/static/theme/default/style.css +482 -0
- mapproxy/service/templates/demo/static.html +34 -0
- mapproxy/service/templates/demo/tms_demo.html +103 -0
- mapproxy/service/templates/demo/wms_demo.html +140 -0
- mapproxy/service/templates/demo/wmts_demo.html +110 -0
- mapproxy/service/templates/tms_capabilities.xml +13 -0
- mapproxy/service/templates/tms_exception.xml +4 -0
- mapproxy/service/templates/tms_root_resource.xml +7 -0
- mapproxy/service/templates/tms_tilemap_capabilities.xml +14 -0
- mapproxy/service/templates/wms100capabilities.xml +112 -0
- mapproxy/service/templates/wms100exception.xml +4 -0
- mapproxy/service/templates/wms110capabilities.xml +152 -0
- mapproxy/service/templates/wms110exception.xml +5 -0
- mapproxy/service/templates/wms111capabilities.xml +183 -0
- mapproxy/service/templates/wms111exception.xml +5 -0
- mapproxy/service/templates/wms130capabilities.xml +326 -0
- mapproxy/service/templates/wms130exception.xml +8 -0
- mapproxy/service/templates/wmts100capabilities.xml +155 -0
- mapproxy/service/templates/wmts100exception.xml +9 -0
- mapproxy/service/tile.py +536 -0
- mapproxy/service/wms.py +851 -0
- mapproxy/service/wmts.py +381 -0
- mapproxy/source/__init__.py +75 -0
- mapproxy/source/arcgis.py +39 -0
- mapproxy/source/error.py +39 -0
- mapproxy/source/mapnik.py +259 -0
- mapproxy/source/tile.py +96 -0
- mapproxy/source/wms.py +270 -0
- mapproxy/srs.py +726 -0
- mapproxy/template.py +54 -0
- mapproxy/test/__init__.py +0 -0
- mapproxy/test/conftest.py +7 -0
- mapproxy/test/helper.py +247 -0
- mapproxy/test/http.py +494 -0
- mapproxy/test/image.py +210 -0
- mapproxy/test/mocker.py +2268 -0
- mapproxy/test/schemas/inspire/common/1.0/common.xsd +1461 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_bul.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_cze.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dan.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_dut.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_eng.xsd +155 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_est.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fin.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_fre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ger.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gle.xsd +109 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_gre.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_hun.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_ita.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lav.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_lit.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_mlt.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_pol.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_por.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_rum.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slo.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_slv.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_spa.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/enums/enum_swe.xsd +108 -0
- mapproxy/test/schemas/inspire/common/1.0/network.xsd +521 -0
- mapproxy/test/schemas/inspire/inspire_vs/1.0/inspire_vs.xsd +19 -0
- mapproxy/test/schemas/kml/2.2.0/ReadMe.txt +14 -0
- mapproxy/test/schemas/kml/2.2.0/atom-author-link.xsd +66 -0
- mapproxy/test/schemas/kml/2.2.0/ogckml22.xsd +1646 -0
- mapproxy/test/schemas/kml/2.2.0/xAL.xsd +1680 -0
- mapproxy/test/schemas/ows/1.1.0/ReadMe.txt +87 -0
- mapproxy/test/schemas/ows/1.1.0/ows19115subset.xsd +235 -0
- mapproxy/test/schemas/ows/1.1.0/owsAll.xsd +23 -0
- mapproxy/test/schemas/ows/1.1.0/owsCommon.xsd +157 -0
- mapproxy/test/schemas/ows/1.1.0/owsContents.xsd +86 -0
- mapproxy/test/schemas/ows/1.1.0/owsDataIdentification.xsd +127 -0
- mapproxy/test/schemas/ows/1.1.0/owsDomainType.xsd +279 -0
- mapproxy/test/schemas/ows/1.1.0/owsExceptionReport.xsd +76 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetCapabilities.xsd +112 -0
- mapproxy/test/schemas/ows/1.1.0/owsGetResourceByID.xsd +51 -0
- mapproxy/test/schemas/ows/1.1.0/owsInputOutputData.xsd +59 -0
- mapproxy/test/schemas/ows/1.1.0/owsManifest.xsd +125 -0
- mapproxy/test/schemas/ows/1.1.0/owsOperationsMetadata.xsd +140 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceIdentification.xsd +60 -0
- mapproxy/test/schemas/ows/1.1.0/owsServiceProvider.xsd +47 -0
- mapproxy/test/schemas/sld/1.1.0/sld_capabilities.xsd +27 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.dtd +353 -0
- mapproxy/test/schemas/wms/1.0.0/capabilities_1_0_0.xml +188 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.dtd +524 -0
- mapproxy/test/schemas/wms/1.0.7/capabilities_1_0_7.xml +260 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.dtd +273 -0
- mapproxy/test/schemas/wms/1.1.0/capabilities_1_1_0.xml +303 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.0/exception_1_1_0.xml +33 -0
- mapproxy/test/schemas/wms/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd +274 -0
- mapproxy/test/schemas/wms/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wms/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wms/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wms/1.3.0/ReadMe.txt +8 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xml +277 -0
- mapproxy/test/schemas/wms/1.3.0/capabilities_1_3_0.xsd +611 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xml +34 -0
- mapproxy/test/schemas/wms/1.3.0/exceptions_1_3_0.xsd +28 -0
- mapproxy/test/schemas/wmsc/1.1.1/OGC-exception.xsd +68 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_DescribeLayerResponse.dtd +22 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_MS_Capabilities.dtd +283 -0
- mapproxy/test/schemas/wmsc/1.1.1/WMS_exception_1_1_1.dtd +5 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.dtd +276 -0
- mapproxy/test/schemas/wmsc/1.1.1/capabilities_1_1_1.xml +303 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.dtd +6 -0
- mapproxy/test/schemas/wmsc/1.1.1/exception_1_1_1.xml +33 -0
- mapproxy/test/schemas/wmts/1.0/ReadMe.txt +32 -0
- mapproxy/test/schemas/wmts/1.0/wmts.xsd +28 -0
- mapproxy/test/schemas/wmts/1.0/wmtsAbstract.wsdl +151 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_request.xsd +38 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetCapabilities_response.xsd +564 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_request.xsd +57 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetFeatureInfo_response.xsd +72 -0
- mapproxy/test/schemas/wmts/1.0/wmtsGetTile_request.xsd +91 -0
- mapproxy/test/schemas/wmts/1.0/wmtsKVP.xsd +76 -0
- mapproxy/test/schemas/wmts/1.0/wmtsPayload_response.xsd +70 -0
- mapproxy/test/schemas/xlink/1.0.0/ReadMe.txt +6 -0
- mapproxy/test/schemas/xlink/1.0.0/xlinks.xsd +122 -0
- mapproxy/test/schemas/xml.xsd +287 -0
- mapproxy/test/system/__init__.py +98 -0
- mapproxy/test/system/fixture/arcgis.yaml +57 -0
- mapproxy/test/system/fixture/auth.yaml +70 -0
- mapproxy/test/system/fixture/cache.mbtiles +0 -0
- mapproxy/test/system/fixture/cache_azureblob.yaml +59 -0
- mapproxy/test/system/fixture/cache_band_merge.yaml +73 -0
- mapproxy/test/system/fixture/cache_bulk_meta_tiles.yaml +24 -0
- mapproxy/test/system/fixture/cache_data/dop_cache_EPSG3857/00/000/000/000/000/000/000.png +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_EPSG900913/01/000/000/000/000/000/001.jpeg +0 -0
- mapproxy/test/system/fixture/cache_data/wms_cache_transparent_EPSG900913/01/000/000/000/000/000/001.png +0 -0
- mapproxy/test/system/fixture/cache_geopackage.yaml +56 -0
- mapproxy/test/system/fixture/cache_grid_names.yaml +50 -0
- mapproxy/test/system/fixture/cache_mbtiles.yaml +28 -0
- mapproxy/test/system/fixture/cache_s3.yaml +58 -0
- mapproxy/test/system/fixture/cache_source.yaml +81 -0
- mapproxy/test/system/fixture/combined_sources.yaml +130 -0
- mapproxy/test/system/fixture/coverage.yaml +77 -0
- mapproxy/test/system/fixture/demo.yaml +135 -0
- mapproxy/test/system/fixture/dimension.yaml +59 -0
- mapproxy/test/system/fixture/disable_storage.yaml +25 -0
- mapproxy/test/system/fixture/empty_ogrdata.geojson +1 -0
- mapproxy/test/system/fixture/formats.yaml +72 -0
- mapproxy/test/system/fixture/inspire.yaml +101 -0
- mapproxy/test/system/fixture/inspire_full.yaml +124 -0
- mapproxy/test/system/fixture/kml_layer.yaml +66 -0
- mapproxy/test/system/fixture/layer.yaml +260 -0
- mapproxy/test/system/fixture/layergroups.yaml +57 -0
- mapproxy/test/system/fixture/layergroups_root.yaml +106 -0
- mapproxy/test/system/fixture/legendgraphic.yaml +93 -0
- mapproxy/test/system/fixture/mapnik_source.yaml +66 -0
- mapproxy/test/system/fixture/mapproxy_export.yaml +12 -0
- mapproxy/test/system/fixture/mapserver.yaml +23 -0
- mapproxy/test/system/fixture/minimal_cgi.py +16 -0
- mapproxy/test/system/fixture/mixed_mode.yaml +49 -0
- mapproxy/test/system/fixture/multi_cache_layers.yaml +100 -0
- mapproxy/test/system/fixture/multiapp1.yaml +20 -0
- mapproxy/test/system/fixture/multiapp2.yaml +19 -0
- mapproxy/test/system/fixture/renderd_client.yaml +55 -0
- mapproxy/test/system/fixture/scalehints.yaml +70 -0
- mapproxy/test/system/fixture/seed.yaml +94 -0
- mapproxy/test/system/fixture/seed_mapproxy.yaml +39 -0
- mapproxy/test/system/fixture/seed_old.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts.yaml +12 -0
- mapproxy/test/system/fixture/seed_timeouts_mapproxy.yaml +27 -0
- mapproxy/test/system/fixture/seedonly.yaml +51 -0
- mapproxy/test/system/fixture/sld.yaml +35 -0
- mapproxy/test/system/fixture/source_errors.yaml +84 -0
- mapproxy/test/system/fixture/source_errors_raise.yaml +82 -0
- mapproxy/test/system/fixture/tileservice_origin.yaml +26 -0
- mapproxy/test/system/fixture/tileservice_refresh.yaml +59 -0
- mapproxy/test/system/fixture/tilesource_minmax_res.yaml +22 -0
- mapproxy/test/system/fixture/util-conf-base-grids.yaml +5 -0
- mapproxy/test/system/fixture/util-conf-overwrite.yaml +13 -0
- mapproxy/test/system/fixture/util-conf-wms-111-cap.xml +90 -0
- mapproxy/test/system/fixture/util_grids.yaml +30 -0
- mapproxy/test/system/fixture/util_wms_capabilities111.xml +130 -0
- mapproxy/test/system/fixture/util_wms_capabilities130.xml +100 -0
- mapproxy/test/system/fixture/util_wms_capabilities_service_exception.xml +5 -0
- mapproxy/test/system/fixture/watermark.yaml +50 -0
- mapproxy/test/system/fixture/wms_srs_extent.yaml +39 -0
- mapproxy/test/system/fixture/wms_versions.yaml +38 -0
- mapproxy/test/system/fixture/wmts.yaml +134 -0
- mapproxy/test/system/fixture/wmts_dimensions.yaml +57 -0
- mapproxy/test/system/fixture/xslt_featureinfo.yaml +54 -0
- mapproxy/test/system/fixture/xslt_featureinfo_input.yaml +51 -0
- mapproxy/test/system/test_arcgis.py +156 -0
- mapproxy/test/system/test_auth.py +1134 -0
- mapproxy/test/system/test_behind_proxy.py +75 -0
- mapproxy/test/system/test_bulk_meta_tiles.py +106 -0
- mapproxy/test/system/test_cache_azureblob.py +127 -0
- mapproxy/test/system/test_cache_band_merge.py +103 -0
- mapproxy/test/system/test_cache_geopackage.py +144 -0
- mapproxy/test/system/test_cache_grid_names.py +89 -0
- mapproxy/test/system/test_cache_mbtiles.py +85 -0
- mapproxy/test/system/test_cache_s3.py +115 -0
- mapproxy/test/system/test_cache_source.py +146 -0
- mapproxy/test/system/test_combined_sources.py +335 -0
- mapproxy/test/system/test_coverage.py +140 -0
- mapproxy/test/system/test_decorate_img.py +214 -0
- mapproxy/test/system/test_demo.py +106 -0
- mapproxy/test/system/test_demo_with_extra_service.py +53 -0
- mapproxy/test/system/test_dimensions.py +278 -0
- mapproxy/test/system/test_disable_storage.py +42 -0
- mapproxy/test/system/test_formats.py +219 -0
- mapproxy/test/system/test_inspire_vs.py +173 -0
- mapproxy/test/system/test_kml.py +262 -0
- mapproxy/test/system/test_layergroups.py +160 -0
- mapproxy/test/system/test_legendgraphic.py +308 -0
- mapproxy/test/system/test_mapnik.py +161 -0
- mapproxy/test/system/test_mapserver.py +81 -0
- mapproxy/test/system/test_mixed_mode_format.py +195 -0
- mapproxy/test/system/test_multi_cache_layers.py +167 -0
- mapproxy/test/system/test_multiapp.py +92 -0
- mapproxy/test/system/test_refresh.py +207 -0
- mapproxy/test/system/test_renderd_client.py +304 -0
- mapproxy/test/system/test_response_headers.py +54 -0
- mapproxy/test/system/test_scalehints.py +140 -0
- mapproxy/test/system/test_seed.py +422 -0
- mapproxy/test/system/test_seed_only.py +93 -0
- mapproxy/test/system/test_sld.py +120 -0
- mapproxy/test/system/test_source_errors.py +377 -0
- mapproxy/test/system/test_tilesource_minmax_res.py +54 -0
- mapproxy/test/system/test_tms.py +276 -0
- mapproxy/test/system/test_tms_origin.py +46 -0
- mapproxy/test/system/test_util_conf.py +304 -0
- mapproxy/test/system/test_util_export.py +210 -0
- mapproxy/test/system/test_util_grids.py +88 -0
- mapproxy/test/system/test_util_wms_capabilities.py +182 -0
- mapproxy/test/system/test_watermark.py +91 -0
- mapproxy/test/system/test_wms.py +1611 -0
- mapproxy/test/system/test_wms_srs_extent.py +165 -0
- mapproxy/test/system/test_wms_version.py +85 -0
- mapproxy/test/system/test_wmsc.py +116 -0
- mapproxy/test/system/test_wmts.py +334 -0
- mapproxy/test/system/test_wmts_dimensions.py +206 -0
- mapproxy/test/system/test_wmts_restful.py +198 -0
- mapproxy/test/system/test_xslt_featureinfo.py +425 -0
- mapproxy/test/test_http_helper.py +219 -0
- mapproxy/test/unit/__init__.py +0 -0
- mapproxy/test/unit/epsg +2 -0
- mapproxy/test/unit/polygons/polygons.dbf +0 -0
- mapproxy/test/unit/polygons/polygons.shp +0 -0
- mapproxy/test/unit/polygons/polygons.shx +0 -0
- mapproxy/test/unit/test_async.py +245 -0
- mapproxy/test/unit/test_auth.py +419 -0
- mapproxy/test/unit/test_cache.py +1193 -0
- mapproxy/test/unit/test_cache_azureblob.py +94 -0
- mapproxy/test/unit/test_cache_compact.py +319 -0
- mapproxy/test/unit/test_cache_couchdb.py +114 -0
- mapproxy/test/unit/test_cache_geopackage.py +221 -0
- mapproxy/test/unit/test_cache_redis.py +67 -0
- mapproxy/test/unit/test_cache_riak.py +76 -0
- mapproxy/test/unit/test_cache_s3.py +84 -0
- mapproxy/test/unit/test_cache_tile.py +427 -0
- mapproxy/test/unit/test_client.py +479 -0
- mapproxy/test/unit/test_client_arcgis.py +73 -0
- mapproxy/test/unit/test_client_cgi.py +136 -0
- mapproxy/test/unit/test_collections.py +116 -0
- mapproxy/test/unit/test_concat_legends.py +37 -0
- mapproxy/test/unit/test_conf_loader.py +1061 -0
- mapproxy/test/unit/test_conf_validator.py +416 -0
- mapproxy/test/unit/test_config.py +117 -0
- mapproxy/test/unit/test_decorate_img.py +185 -0
- mapproxy/test/unit/test_exceptions.py +258 -0
- mapproxy/test/unit/test_featureinfo.py +291 -0
- mapproxy/test/unit/test_file_lock_load.py +49 -0
- mapproxy/test/unit/test_geom.py +503 -0
- mapproxy/test/unit/test_grid.py +1258 -0
- mapproxy/test/unit/test_image.py +1053 -0
- mapproxy/test/unit/test_image_mask.py +181 -0
- mapproxy/test/unit/test_image_messages.py +197 -0
- mapproxy/test/unit/test_image_options.py +160 -0
- mapproxy/test/unit/test_isodate.py +122 -0
- mapproxy/test/unit/test_multiapp.py +163 -0
- mapproxy/test/unit/test_ogr_reader.py +50 -0
- mapproxy/test/unit/test_request.py +745 -0
- mapproxy/test/unit/test_request_wmts.py +178 -0
- mapproxy/test/unit/test_response.py +79 -0
- mapproxy/test/unit/test_seed.py +365 -0
- mapproxy/test/unit/test_seed_cachelock.py +90 -0
- mapproxy/test/unit/test_srs.py +215 -0
- mapproxy/test/unit/test_tiled_source.py +122 -0
- mapproxy/test/unit/test_tilefilter.py +31 -0
- mapproxy/test/unit/test_times.py +25 -0
- mapproxy/test/unit/test_timeutils.py +50 -0
- mapproxy/test/unit/test_util_conf_utils.py +75 -0
- mapproxy/test/unit/test_utils.py +476 -0
- mapproxy/test/unit/test_wms_capabilities.py +44 -0
- mapproxy/test/unit/test_wms_layer.py +113 -0
- mapproxy/test/unit/test_yaml.py +69 -0
- mapproxy/tilefilter.py +59 -0
- mapproxy/util/__init__.py +0 -0
- mapproxy/util/async_.py +227 -0
- mapproxy/util/collections.py +132 -0
- mapproxy/util/coverage.py +329 -0
- mapproxy/util/escape.py +10 -0
- mapproxy/util/ext/__init__.py +14 -0
- mapproxy/util/ext/dictspec/__init__.py +1 -0
- mapproxy/util/ext/dictspec/spec.py +124 -0
- mapproxy/util/ext/dictspec/test/__init__.py +0 -0
- mapproxy/util/ext/dictspec/test/test_validator.py +274 -0
- mapproxy/util/ext/dictspec/validator.py +189 -0
- mapproxy/util/ext/local.py +196 -0
- mapproxy/util/ext/lockfile.py +138 -0
- mapproxy/util/ext/odict.py +330 -0
- mapproxy/util/ext/serving.py +508 -0
- mapproxy/util/ext/tempita/__init__.py +1174 -0
- mapproxy/util/ext/tempita/_looper.py +163 -0
- mapproxy/util/ext/tempita/compat3.py +46 -0
- mapproxy/util/ext/wmsparse/__init__.py +3 -0
- mapproxy/util/ext/wmsparse/duration.py +597 -0
- mapproxy/util/ext/wmsparse/parse.py +305 -0
- mapproxy/util/ext/wmsparse/test/__init__.py +0 -0
- mapproxy/util/ext/wmsparse/test/test_parse.py +162 -0
- mapproxy/util/ext/wmsparse/test/test_util.py +23 -0
- mapproxy/util/ext/wmsparse/test/wms-large-111.xml +2114 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-111.xml +90 -0
- mapproxy/util/ext/wmsparse/test/wms-omniscale-130.xml +120 -0
- mapproxy/util/ext/wmsparse/test/wms_nasa_cap.xml +386 -0
- mapproxy/util/ext/wmsparse/util.py +187 -0
- mapproxy/util/fs.py +156 -0
- mapproxy/util/geom.py +295 -0
- mapproxy/util/lib.py +115 -0
- mapproxy/util/lock.py +163 -0
- mapproxy/util/ogr.py +231 -0
- mapproxy/util/py.py +81 -0
- mapproxy/util/times.py +75 -0
- mapproxy/util/yaml.py +56 -0
- mapproxy/version.py +31 -0
- mapproxy/wsgiapp.py +164 -0
- mapproxy-1.16.1.dist-info/METADATA +151 -0
- mapproxy-1.16.1.dist-info/RECORD +458 -0
- mapproxy-1.16.1.dist-info/WHEEL +5 -0
- mapproxy-1.16.1.dist-info/entry_points.txt +3 -0
- mapproxy-1.16.1.dist-info/licenses/AUTHORS.txt +33 -0
- mapproxy-1.16.1.dist-info/licenses/COPYING.txt +60 -0
- mapproxy-1.16.1.dist-info/licenses/LICENSE.txt +202 -0
- mapproxy-1.16.1.dist-info/top_level.txt +1 -0
mapproxy/service/tile.py
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
# -:- encoding: utf-8 -:-
|
|
2
|
+
# This file is part of the MapProxy project.
|
|
3
|
+
# Copyright (C) 2010 Omniscale <http://omniscale.de>
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
from __future__ import division
|
|
18
|
+
|
|
19
|
+
import math
|
|
20
|
+
import time
|
|
21
|
+
|
|
22
|
+
from mapproxy.compat import iteritems, itervalues
|
|
23
|
+
from mapproxy.response import Response
|
|
24
|
+
from mapproxy.exception import RequestError
|
|
25
|
+
from mapproxy.service.base import Server
|
|
26
|
+
from mapproxy.request.tile import tile_request
|
|
27
|
+
from mapproxy.request.base import split_mime_type
|
|
28
|
+
from mapproxy.layer import map_extent_from_grid
|
|
29
|
+
from mapproxy.source import SourceError
|
|
30
|
+
from mapproxy.srs import SRS
|
|
31
|
+
from mapproxy.grid import default_bboxs
|
|
32
|
+
from mapproxy.image import BlankImageSource
|
|
33
|
+
from mapproxy.image.opts import ImageOptions
|
|
34
|
+
from mapproxy.image.mask import mask_image_source_from_coverage
|
|
35
|
+
from mapproxy.util.ext.odict import odict
|
|
36
|
+
from mapproxy.util.coverage import load_limited_to
|
|
37
|
+
|
|
38
|
+
import logging
|
|
39
|
+
log = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
from mapproxy.template import template_loader, bunch
|
|
43
|
+
get_template = template_loader(__name__, 'templates')
|
|
44
|
+
|
|
45
|
+
class TileServer(Server):
|
|
46
|
+
"""
|
|
47
|
+
A Tile Server. Supports strict TMS and non-TMS requests. The difference is the
|
|
48
|
+
support for profiles. The our internal tile cache starts with one tile at the
|
|
49
|
+
first level (like KML, etc.), but the global-geodetic and global-mercator
|
|
50
|
+
start with two and four tiles. The ``tile_request`` should set ``use_profiles``
|
|
51
|
+
accordingly (eg. False if first level is one tile)
|
|
52
|
+
"""
|
|
53
|
+
names = ('tiles', 'tms')
|
|
54
|
+
request_parser = staticmethod(tile_request)
|
|
55
|
+
request_methods = ('map', 'tms_capabilities, tms_root_resource')
|
|
56
|
+
template_file = 'tms_capabilities.xml'
|
|
57
|
+
layer_template_file = 'tms_tilemap_capabilities.xml'
|
|
58
|
+
root_resource_template_file = 'tms_root_resource.xml'
|
|
59
|
+
|
|
60
|
+
def __init__(self, layers, md, max_tile_age=None, use_dimension_layers=False, origin=None):
|
|
61
|
+
Server.__init__(self)
|
|
62
|
+
self.layers = layers
|
|
63
|
+
self.md = md
|
|
64
|
+
self.max_tile_age = max_tile_age
|
|
65
|
+
self.use_dimension_layers = use_dimension_layers
|
|
66
|
+
self.origin = origin
|
|
67
|
+
|
|
68
|
+
def map(self, tile_request):
|
|
69
|
+
"""
|
|
70
|
+
:return: the requested tile
|
|
71
|
+
:rtype: Response
|
|
72
|
+
"""
|
|
73
|
+
if self.origin and not tile_request.origin:
|
|
74
|
+
tile_request.origin = self.origin
|
|
75
|
+
layer, limit_to = self.layer(tile_request)
|
|
76
|
+
|
|
77
|
+
def decorate_img(image):
|
|
78
|
+
query_extent = (layer.grid.srs.srs_code,
|
|
79
|
+
layer.tile_bbox(tile_request, use_profiles=tile_request.use_profiles))
|
|
80
|
+
return self.decorate_img(image, 'tms', [layer.name], tile_request.http.environ, query_extent)
|
|
81
|
+
|
|
82
|
+
tile = layer.render(tile_request, use_profiles=tile_request.use_profiles, coverage=limit_to, decorate_img=decorate_img)
|
|
83
|
+
|
|
84
|
+
tile_format = getattr(tile, 'format', tile_request.format)
|
|
85
|
+
resp = Response(tile.as_buffer(), content_type='image/' + tile_format)
|
|
86
|
+
if tile.cacheable:
|
|
87
|
+
resp.cache_headers(tile.timestamp, etag_data=(tile.timestamp, tile.size),
|
|
88
|
+
max_age=self.max_tile_age)
|
|
89
|
+
else:
|
|
90
|
+
resp.cache_headers(no_cache=True)
|
|
91
|
+
resp.make_conditional(tile_request.http)
|
|
92
|
+
return resp
|
|
93
|
+
|
|
94
|
+
def _internal_layer(self, tile_request):
|
|
95
|
+
if '_layer_spec' in tile_request.dimensions:
|
|
96
|
+
name = tile_request.layer + '_' + tile_request.dimensions['_layer_spec']
|
|
97
|
+
else:
|
|
98
|
+
name = tile_request.layer
|
|
99
|
+
if name in self.layers:
|
|
100
|
+
return self.layers[name]
|
|
101
|
+
if name + '_EPSG900913' in self.layers:
|
|
102
|
+
return self.layers[name + '_EPSG900913']
|
|
103
|
+
if name + '_EPSG4326' in self.layers:
|
|
104
|
+
return self.layers[name + '_EPSG4326']
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
def _internal_dimension_layer(self, tile_request):
|
|
108
|
+
key = (tile_request.layer, tile_request.dimensions.get('_layer_spec'))
|
|
109
|
+
return self.layers.get(key)
|
|
110
|
+
|
|
111
|
+
def layer(self, tile_request):
|
|
112
|
+
if self.use_dimension_layers:
|
|
113
|
+
internal_layer = self._internal_dimension_layer(tile_request)
|
|
114
|
+
else:
|
|
115
|
+
internal_layer = self._internal_layer(tile_request)
|
|
116
|
+
if internal_layer is None:
|
|
117
|
+
raise RequestError('unknown layer: ' + tile_request.layer, request=tile_request)
|
|
118
|
+
|
|
119
|
+
limit_to = self.authorize_tile_layer(internal_layer, tile_request)
|
|
120
|
+
return internal_layer, limit_to
|
|
121
|
+
|
|
122
|
+
def authorize_tile_layer(self, tile_layer, request):
|
|
123
|
+
if 'mapproxy.authorize' in request.http.environ:
|
|
124
|
+
if request.tile:
|
|
125
|
+
query_extent = (tile_layer.grid.srs.srs_code,
|
|
126
|
+
tile_layer.tile_bbox(request, use_profiles=request.use_profiles))
|
|
127
|
+
else:
|
|
128
|
+
query_extent = None # for layer capabilities
|
|
129
|
+
result = request.http.environ['mapproxy.authorize']('tms', [tile_layer.name],
|
|
130
|
+
query_extent=query_extent, environ=request.http.environ)
|
|
131
|
+
if result['authorized'] == 'unauthenticated':
|
|
132
|
+
raise RequestError('unauthorized', status=401)
|
|
133
|
+
if result['authorized'] == 'full':
|
|
134
|
+
return
|
|
135
|
+
if result['authorized'] == 'partial':
|
|
136
|
+
if result['layers'].get(tile_layer.name, {}).get('tile', False) == True:
|
|
137
|
+
limited_to = result['layers'][tile_layer.name].get('limited_to')
|
|
138
|
+
if not limited_to:
|
|
139
|
+
limited_to = result.get('limited_to')
|
|
140
|
+
if limited_to:
|
|
141
|
+
return load_limited_to(limited_to)
|
|
142
|
+
else:
|
|
143
|
+
return None
|
|
144
|
+
raise RequestError('forbidden', status=403)
|
|
145
|
+
|
|
146
|
+
def authorized_tile_layers(self, env):
|
|
147
|
+
if 'mapproxy.authorize' in env:
|
|
148
|
+
result = env['mapproxy.authorize']('tms', [l for l in self.layers],
|
|
149
|
+
query_extent=None, environ=env)
|
|
150
|
+
if result['authorized'] == 'unauthenticated':
|
|
151
|
+
raise RequestError('unauthorized', status=401)
|
|
152
|
+
if result['authorized'] == 'full':
|
|
153
|
+
return self.layers
|
|
154
|
+
if result['authorized'] == 'none':
|
|
155
|
+
raise RequestError('forbidden', status=403)
|
|
156
|
+
allowed_layers = odict()
|
|
157
|
+
for layer in itervalues(self.layers):
|
|
158
|
+
if result['layers'].get(layer.name, {}).get('tile', False) == True:
|
|
159
|
+
allowed_layers[layer.name] = layer
|
|
160
|
+
return allowed_layers
|
|
161
|
+
else:
|
|
162
|
+
return self.layers
|
|
163
|
+
|
|
164
|
+
def tms_capabilities(self, tms_request):
|
|
165
|
+
"""
|
|
166
|
+
:return: the rendered tms capabilities
|
|
167
|
+
:rtype: Response
|
|
168
|
+
"""
|
|
169
|
+
service = self._service_md(tms_request)
|
|
170
|
+
if hasattr(tms_request, 'layer'):
|
|
171
|
+
layer, limit_to = self.layer(tms_request)
|
|
172
|
+
result = self._render_layer_template(layer, service)
|
|
173
|
+
else:
|
|
174
|
+
layers = self.authorized_tile_layers(tms_request.http.environ)
|
|
175
|
+
result = self._render_template(layers, service)
|
|
176
|
+
|
|
177
|
+
return Response(result, mimetype='text/xml')
|
|
178
|
+
|
|
179
|
+
def tms_root_resource(self, tms_request):
|
|
180
|
+
"""
|
|
181
|
+
:return: root resource with all available versions of the service
|
|
182
|
+
:rtype: Response
|
|
183
|
+
"""
|
|
184
|
+
service = self._service_md(tms_request)
|
|
185
|
+
result = self._render_root_resource_template(service)
|
|
186
|
+
return Response(result, mimetype='text/xml')
|
|
187
|
+
|
|
188
|
+
def _service_md(self, map_request):
|
|
189
|
+
md = dict(self.md)
|
|
190
|
+
md['url'] = map_request.http.base_url
|
|
191
|
+
return md
|
|
192
|
+
|
|
193
|
+
def _render_template(self, layers, service):
|
|
194
|
+
template = get_template(self.template_file)
|
|
195
|
+
return template.substitute(service=bunch(default='', **service), layers=layers)
|
|
196
|
+
|
|
197
|
+
def _render_layer_template(self, layer, service):
|
|
198
|
+
template = get_template(self.layer_template_file)
|
|
199
|
+
return template.substitute(service=bunch(default='', **service), layer=layer)
|
|
200
|
+
|
|
201
|
+
def _render_root_resource_template(self, service):
|
|
202
|
+
template = get_template(self.root_resource_template_file)
|
|
203
|
+
return template.substitute(service=bunch(default='', **service))
|
|
204
|
+
|
|
205
|
+
class TileLayer(object):
|
|
206
|
+
def __init__(self, name, title, md, tile_manager, info_sources=[], dimensions=None):
|
|
207
|
+
"""
|
|
208
|
+
:param md: the layer metadata
|
|
209
|
+
:param tile_manager: the layer tile manager
|
|
210
|
+
"""
|
|
211
|
+
self.name = name
|
|
212
|
+
self.title = title
|
|
213
|
+
self.md = md
|
|
214
|
+
self.tile_manager = tile_manager
|
|
215
|
+
self.info_sources = info_sources
|
|
216
|
+
self.dimensions = dimensions
|
|
217
|
+
self.grid = TileServiceGrid(tile_manager.grid)
|
|
218
|
+
self.extent = map_extent_from_grid(self.grid)
|
|
219
|
+
self._empty_tile = None
|
|
220
|
+
self._mixed_format = True if self.md.get('format', False) == 'mixed' else False
|
|
221
|
+
self.empty_response_as_png = True
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def bbox(self):
|
|
225
|
+
return self.grid.bbox
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def srs(self):
|
|
229
|
+
return self.grid.srs
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def format(self):
|
|
233
|
+
_mime_class, format, _options = split_mime_type(self.format_mime_type)
|
|
234
|
+
return format
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def queryable(self):
|
|
238
|
+
return bool(self.info_sources)
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def format_mime_type(self):
|
|
242
|
+
# force png format for capabilities & requests if mixed format
|
|
243
|
+
if self._mixed_format:
|
|
244
|
+
return 'image/png'
|
|
245
|
+
return self.md.get('format', 'image/png')
|
|
246
|
+
|
|
247
|
+
def _internal_tile_coord(self, tile_request, use_profiles=False):
|
|
248
|
+
tile_coord = self.grid.internal_tile_coord(tile_request.tile, use_profiles)
|
|
249
|
+
if tile_coord is None:
|
|
250
|
+
raise RequestError('The requested tile is outside the bounding box'
|
|
251
|
+
' of the tile map.', request=tile_request,
|
|
252
|
+
code='TileOutOfRange')
|
|
253
|
+
if tile_request.origin == 'nw' and self.grid.origin not in ('ul', 'nw'):
|
|
254
|
+
tile_coord = self.grid.flip_tile_coord(tile_coord)
|
|
255
|
+
elif tile_request.origin == 'sw' and self.grid.origin not in ('ll', 'sw', None):
|
|
256
|
+
tile_coord = self.grid.flip_tile_coord(tile_coord)
|
|
257
|
+
|
|
258
|
+
return tile_coord
|
|
259
|
+
|
|
260
|
+
def empty_response(self):
|
|
261
|
+
if self.empty_response_as_png:
|
|
262
|
+
format = 'png'
|
|
263
|
+
else:
|
|
264
|
+
format = self.format
|
|
265
|
+
if not self._empty_tile:
|
|
266
|
+
img = BlankImageSource(size=self.grid.tile_size,
|
|
267
|
+
image_opts=ImageOptions(format=format, transparent=True))
|
|
268
|
+
self._empty_tile = img.as_buffer().read()
|
|
269
|
+
return ImageResponse(self._empty_tile, format=format, timestamp=time.time())
|
|
270
|
+
|
|
271
|
+
def tile_bbox(self, tile_request, use_profiles=False, limit=False):
|
|
272
|
+
tile_coord = self._internal_tile_coord(tile_request, use_profiles=use_profiles)
|
|
273
|
+
return self.grid.tile_bbox(tile_coord, limit=limit)
|
|
274
|
+
|
|
275
|
+
def checked_dimensions(self, tile_request):
|
|
276
|
+
dimensions = {}
|
|
277
|
+
|
|
278
|
+
for dimension, values in iteritems(self.dimensions):
|
|
279
|
+
value = tile_request.dimensions.get(dimension)
|
|
280
|
+
if value in values:
|
|
281
|
+
dimensions[dimension] = value
|
|
282
|
+
elif not value or value == 'default':
|
|
283
|
+
dimensions[dimension] = values.default
|
|
284
|
+
else:
|
|
285
|
+
raise RequestError('invalid dimension value (%s=%s).'
|
|
286
|
+
% (dimension, value), request=tile_request,
|
|
287
|
+
code='InvalidParameterValue')
|
|
288
|
+
return dimensions
|
|
289
|
+
|
|
290
|
+
def render(self, tile_request, use_profiles=False, coverage=None, decorate_img=None):
|
|
291
|
+
if tile_request.format != self.format:
|
|
292
|
+
raise RequestError('invalid format (%s). this tile set only supports (%s)'
|
|
293
|
+
% (tile_request.format, self.format), request=tile_request,
|
|
294
|
+
code='InvalidParameterValue')
|
|
295
|
+
|
|
296
|
+
tile_coord = self._internal_tile_coord(tile_request, use_profiles=use_profiles)
|
|
297
|
+
|
|
298
|
+
coverage_intersects = False
|
|
299
|
+
if coverage:
|
|
300
|
+
tile_bbox = self.grid.tile_bbox(tile_coord)
|
|
301
|
+
if coverage.contains(tile_bbox, self.grid.srs):
|
|
302
|
+
pass
|
|
303
|
+
elif coverage.intersects(tile_bbox, self.grid.srs):
|
|
304
|
+
coverage_intersects = True
|
|
305
|
+
else:
|
|
306
|
+
return self.empty_response()
|
|
307
|
+
|
|
308
|
+
dimensions = self.checked_dimensions(tile_request)
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
with self.tile_manager.session():
|
|
312
|
+
tile = self.tile_manager.load_tile_coord(tile_coord,
|
|
313
|
+
dimensions=dimensions, with_metadata=True)
|
|
314
|
+
if tile.source is None:
|
|
315
|
+
return self.empty_response()
|
|
316
|
+
|
|
317
|
+
# Provide the wrapping WSGI app or filter the opportunity to process the
|
|
318
|
+
# image before it's wrapped up in a response
|
|
319
|
+
if decorate_img:
|
|
320
|
+
tile.source = decorate_img(tile.source)
|
|
321
|
+
|
|
322
|
+
if coverage_intersects:
|
|
323
|
+
if self.empty_response_as_png:
|
|
324
|
+
format = 'png'
|
|
325
|
+
image_opts = ImageOptions(transparent=True, format='png')
|
|
326
|
+
else:
|
|
327
|
+
format = self.format
|
|
328
|
+
image_opts = tile.source.image_opts
|
|
329
|
+
|
|
330
|
+
tile.source = mask_image_source_from_coverage(
|
|
331
|
+
tile.source, tile_bbox, self.grid.srs, coverage, image_opts)
|
|
332
|
+
|
|
333
|
+
return TileResponse(tile, format=format, image_opts=image_opts)
|
|
334
|
+
|
|
335
|
+
format = None if self._mixed_format else tile_request.format
|
|
336
|
+
return TileResponse(tile, format=format, image_opts=self.tile_manager.image_opts)
|
|
337
|
+
except SourceError as e:
|
|
338
|
+
raise RequestError(e.args[0], request=tile_request, internal=True)
|
|
339
|
+
|
|
340
|
+
def get_info(self, info_request):
|
|
341
|
+
if info_request.format != self.format:
|
|
342
|
+
raise RequestError('invalid format (%s). this tile set only supports (%s)'
|
|
343
|
+
% (info_request.format, self.format), request=info_request,
|
|
344
|
+
code='InvalidParameterValue')
|
|
345
|
+
|
|
346
|
+
tile_coord = self._internal_tile_coord(info_request)
|
|
347
|
+
|
|
348
|
+
coverage_intersects = False
|
|
349
|
+
if coverage:
|
|
350
|
+
tile_bbox = self.grid.tile_bbox(tile_coord)
|
|
351
|
+
if coverage.contains(tile_bbox, self.grid.srs):
|
|
352
|
+
pass
|
|
353
|
+
elif coverage.intersects(tile_bbox, self.grid.srs):
|
|
354
|
+
coverage_intersects = True
|
|
355
|
+
else:
|
|
356
|
+
return self.empty_response()
|
|
357
|
+
|
|
358
|
+
dimensions = self.checked_dimensions(info_request)
|
|
359
|
+
|
|
360
|
+
try:
|
|
361
|
+
with self.tile_manager.session():
|
|
362
|
+
tile = self.tile_manager.load_tile_coord(tile_coord,
|
|
363
|
+
dimensions=dimensions, with_metadata=True)
|
|
364
|
+
if tile.source is None:
|
|
365
|
+
return self.empty_response()
|
|
366
|
+
|
|
367
|
+
# Provide the wrapping WSGI app or filter the opportunity to process the
|
|
368
|
+
# image before it's wrapped up in a response
|
|
369
|
+
if decorate_img:
|
|
370
|
+
tile.source = decorate_img(tile.source)
|
|
371
|
+
|
|
372
|
+
if coverage_intersects:
|
|
373
|
+
if self.empty_response_as_png:
|
|
374
|
+
format = 'png'
|
|
375
|
+
image_opts = ImageOptions(transparent=True, format='png')
|
|
376
|
+
else:
|
|
377
|
+
format = self.format
|
|
378
|
+
image_opts = tile.source.image_opts
|
|
379
|
+
|
|
380
|
+
tile.source = mask_image_source_from_coverage(
|
|
381
|
+
tile.source, tile_bbox, self.grid.srs, coverage, image_opts)
|
|
382
|
+
|
|
383
|
+
return TileResponse(tile, format=format, image_opts=image_opts)
|
|
384
|
+
|
|
385
|
+
format = None if self._mixed_format else info_request.format
|
|
386
|
+
return TileResponse(tile, format=format, image_opts=self.tile_manager.image_opts)
|
|
387
|
+
except SourceError as e:
|
|
388
|
+
raise RequestError(e.args[0], request=info_request, internal=True)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class ImageResponse(object):
|
|
393
|
+
"""
|
|
394
|
+
Response from an image.
|
|
395
|
+
"""
|
|
396
|
+
def __init__(self, img, format, timestamp):
|
|
397
|
+
self.img = img
|
|
398
|
+
self.timestamp = timestamp
|
|
399
|
+
self.format = format
|
|
400
|
+
self.size = 0
|
|
401
|
+
self.cacheable = True
|
|
402
|
+
|
|
403
|
+
def as_buffer(self):
|
|
404
|
+
return self.img
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class TileResponse(object):
|
|
408
|
+
"""
|
|
409
|
+
Response from a Tile.
|
|
410
|
+
"""
|
|
411
|
+
def __init__(self, tile, format=None, timestamp=None, image_opts=None):
|
|
412
|
+
self.tile = tile
|
|
413
|
+
self.timestamp = tile.timestamp
|
|
414
|
+
self.size = tile.size
|
|
415
|
+
self.cacheable = tile.cacheable
|
|
416
|
+
self._buf = self.tile.source_buffer(format=format, image_opts=image_opts)
|
|
417
|
+
self.format = format or self._format_from_magic_bytes()
|
|
418
|
+
|
|
419
|
+
def as_buffer(self):
|
|
420
|
+
return self._buf
|
|
421
|
+
|
|
422
|
+
def _format_from_magic_bytes(self):
|
|
423
|
+
#read the 2 magic bytes from the buffer
|
|
424
|
+
magic_bytes = self._buf.read(2)
|
|
425
|
+
self._buf.seek(0)
|
|
426
|
+
if magic_bytes == b'\xFF\xD8':
|
|
427
|
+
return 'jpeg'
|
|
428
|
+
return 'png'
|
|
429
|
+
|
|
430
|
+
class TileServiceGrid(object):
|
|
431
|
+
"""
|
|
432
|
+
Wraps a `TileGrid` and adds some ``TileService`` specific methods.
|
|
433
|
+
"""
|
|
434
|
+
def __init__(self, grid):
|
|
435
|
+
self.grid = grid
|
|
436
|
+
self.profile = None
|
|
437
|
+
|
|
438
|
+
if self.grid.srs == SRS(900913) and self.grid.bbox == default_bboxs[SRS((900913))]:
|
|
439
|
+
self.profile = 'global-mercator'
|
|
440
|
+
self.srs_name = 'OSGEO:41001' # as required by TMS 1.0.0
|
|
441
|
+
self._skip_first_level = True
|
|
442
|
+
|
|
443
|
+
elif self.grid.srs == SRS(4326) and self.grid.bbox == default_bboxs[SRS((4326))]:
|
|
444
|
+
self.profile = 'global-geodetic'
|
|
445
|
+
self.srs_name = 'EPSG:4326'
|
|
446
|
+
self._skip_first_level = True
|
|
447
|
+
else:
|
|
448
|
+
self.profile = 'local'
|
|
449
|
+
self.srs_name = self.grid.srs.srs_code
|
|
450
|
+
self._skip_first_level = False
|
|
451
|
+
|
|
452
|
+
self._skip_odd_level = False
|
|
453
|
+
|
|
454
|
+
res_factor = self.grid.resolutions[0]/self.grid.resolutions[1]
|
|
455
|
+
if res_factor == math.sqrt(2):
|
|
456
|
+
self._skip_odd_level = True
|
|
457
|
+
|
|
458
|
+
def internal_level(self, level):
|
|
459
|
+
"""
|
|
460
|
+
:return: the internal level
|
|
461
|
+
"""
|
|
462
|
+
if self._skip_first_level:
|
|
463
|
+
level += 1
|
|
464
|
+
if self._skip_odd_level:
|
|
465
|
+
level += 1
|
|
466
|
+
if self._skip_odd_level:
|
|
467
|
+
level *= 2
|
|
468
|
+
return level
|
|
469
|
+
|
|
470
|
+
@property
|
|
471
|
+
def bbox(self):
|
|
472
|
+
"""
|
|
473
|
+
:return: the bbox of all tiles of the first level
|
|
474
|
+
"""
|
|
475
|
+
first_level = self.internal_level(0)
|
|
476
|
+
grid_size = self.grid.grid_sizes[first_level]
|
|
477
|
+
return self.grid._get_bbox([(0, 0, first_level),
|
|
478
|
+
(grid_size[0]-1, grid_size[1]-1, first_level)])
|
|
479
|
+
|
|
480
|
+
def __getattr__(self, key):
|
|
481
|
+
return getattr(self.grid, key)
|
|
482
|
+
|
|
483
|
+
@property
|
|
484
|
+
def tile_sets(self):
|
|
485
|
+
"""
|
|
486
|
+
Get all public tile sets for this layer.
|
|
487
|
+
:return: the order and resolution of each tile set
|
|
488
|
+
"""
|
|
489
|
+
tile_sets = []
|
|
490
|
+
num_levels = self.grid.levels
|
|
491
|
+
start = 0
|
|
492
|
+
step = 1
|
|
493
|
+
if self._skip_first_level:
|
|
494
|
+
if self._skip_odd_level:
|
|
495
|
+
start = 2
|
|
496
|
+
else:
|
|
497
|
+
start = 1
|
|
498
|
+
if self._skip_odd_level:
|
|
499
|
+
step = 2
|
|
500
|
+
for order, level in enumerate(range(start, num_levels, step)):
|
|
501
|
+
tile_sets.append((order, self.grid.resolutions[level]))
|
|
502
|
+
return tile_sets
|
|
503
|
+
|
|
504
|
+
def internal_tile_coord(self, tile_coord, use_profiles):
|
|
505
|
+
"""
|
|
506
|
+
Converts public tile coords to internal tile coords.
|
|
507
|
+
|
|
508
|
+
:param tile_coord: the public tile coord
|
|
509
|
+
:param use_profiles: True if the tile service supports global
|
|
510
|
+
profiles (see `mapproxy.core.server.TileServer`)
|
|
511
|
+
"""
|
|
512
|
+
x, y, z = tile_coord
|
|
513
|
+
if int(z) < 0:
|
|
514
|
+
return None
|
|
515
|
+
if use_profiles and self._skip_first_level:
|
|
516
|
+
z += 1
|
|
517
|
+
if self._skip_odd_level:
|
|
518
|
+
z *= 2
|
|
519
|
+
return self.grid.limit_tile((x, y, z))
|
|
520
|
+
|
|
521
|
+
def external_tile_coord(self, tile_coord, use_profiles):
|
|
522
|
+
"""
|
|
523
|
+
Converts internal tile coords to external tile coords.
|
|
524
|
+
|
|
525
|
+
:param tile_coord: the internal tile coord
|
|
526
|
+
:param use_profiles: True if the tile service supports global
|
|
527
|
+
profiles (see `mapproxy.core.server.TileServer`)
|
|
528
|
+
"""
|
|
529
|
+
x, y, z = tile_coord
|
|
530
|
+
if z < 0:
|
|
531
|
+
return None
|
|
532
|
+
if use_profiles and self._skip_first_level:
|
|
533
|
+
z -= 1
|
|
534
|
+
if self._skip_odd_level:
|
|
535
|
+
z //= 2
|
|
536
|
+
return (x, y, z)
|