large-image 1.27.1.dev40__tar.gz → 1.27.1.dev44__tar.gz
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.
- {large-image-1.27.1.dev40/large_image.egg-info → large-image-1.27.1.dev44}/PKG-INFO +1 -1
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/base.py +24 -19
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/geo.py +57 -38
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/jupyter.py +177 -159
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/stylefuncs.py +25 -14
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/tiledict.py +14 -10
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/utilities.py +126 -91
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44/large_image.egg-info}/PKG-INFO +1 -1
- large-image-1.27.1.dev44/large_image.egg-info/requires.txt +145 -0
- large-image-1.27.1.dev40/large_image.egg-info/requires.txt +0 -145
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/LICENSE +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/NOTICE +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/README.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/annotations.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/caching.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/conf.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/config_options.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/development.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/example_usage.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/girder_annotation_config_options.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/girder_config_options.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/image_conversion.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/index.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/large_image_examples.ipynb +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/make_docs.sh +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/multi_source_specification.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/notebooks.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/static/custom.css +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/tilesource_options.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/docs/upgrade.rst +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/__init__.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/cache_util/__init__.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/cache_util/base.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/cache_util/cache.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/cache_util/cachefactory.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/cache_util/memcache.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/config.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/constants.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/exceptions.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image/tilesource/__init__.py +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image.egg-info/SOURCES.txt +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image.egg-info/dependency_links.txt +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image.egg-info/not-zip-safe +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/large_image.egg-info/top_level.txt +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/setup.cfg +0 -0
- {large-image-1.27.1.dev40 → large-image-1.27.1.dev44}/setup.py +0 -0
|
@@ -56,8 +56,6 @@ class TileSource(IPyLeafletMixin):
|
|
|
56
56
|
nameMatches: Dict[str, SourcePriority] = {
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
geospatial = False
|
|
60
|
-
|
|
61
59
|
# When getting tiles for otherwise empty levels (missing powers of two), we
|
|
62
60
|
# composite the tile from higher resolution levels. This can use excessive
|
|
63
61
|
# memory if there are too many missing levels. For instance, if there are
|
|
@@ -203,6 +201,10 @@ class TileSource(IPyLeafletMixin):
|
|
|
203
201
|
def _repr_png_(self):
|
|
204
202
|
return self.getThumbnail(encoding='PNG')[0]
|
|
205
203
|
|
|
204
|
+
@property
|
|
205
|
+
def geospatial(self) -> bool:
|
|
206
|
+
return False
|
|
207
|
+
|
|
206
208
|
def _setStyle(self, style: Any) -> None:
|
|
207
209
|
"""
|
|
208
210
|
Check and set the specified style from a json string or a dictionary.
|
|
@@ -842,8 +844,9 @@ class TileSource(IPyLeafletMixin):
|
|
|
842
844
|
|
|
843
845
|
self.logger.debug(
|
|
844
846
|
'Fetching region of an image with a source size of %d x %d; '
|
|
845
|
-
'getting %d
|
|
846
|
-
regionWidth, regionHeight, (xmax - xmin) * (ymax - ymin)
|
|
847
|
+
'getting %d tile%s',
|
|
848
|
+
regionWidth, regionHeight, (xmax - xmin) * (ymax - ymin),
|
|
849
|
+
'' if (xmax - xmin) * (ymax - ymin) == 1 else 's')
|
|
847
850
|
|
|
848
851
|
# If tile is specified, return at most one tile
|
|
849
852
|
if iterInfo.get('tile_position') is not None:
|
|
@@ -1604,7 +1607,7 @@ class TileSource(IPyLeafletMixin):
|
|
|
1604
1607
|
tile = self._applyStyle(tile, getattr(self, 'style', None), x, y, z, frame)
|
|
1605
1608
|
if tile.shape[0] != self.tileHeight or tile.shape[1] != self.tileWidth:
|
|
1606
1609
|
extend = np.zeros(
|
|
1607
|
-
(self.tileHeight, self.tileWidth, tile.shape[2]),
|
|
1610
|
+
(self.tileHeight, self.tileWidth, tile.shape[2]), # type: ignore[misc]
|
|
1608
1611
|
dtype=tile.dtype)
|
|
1609
1612
|
extend[:min(self.tileHeight, tile.shape[0]),
|
|
1610
1613
|
:min(self.tileWidth, tile.shape[1])] = tile
|
|
@@ -1672,10 +1675,10 @@ class TileSource(IPyLeafletMixin):
|
|
|
1672
1675
|
sizeY - (maxY - self.tileHeight))
|
|
1673
1676
|
tile, mode = _imageToNumpy(tile)
|
|
1674
1677
|
if self.edge in (True, 'crop'):
|
|
1675
|
-
tile =
|
|
1678
|
+
tile = tile[:contentHeight, :contentWidth]
|
|
1676
1679
|
else:
|
|
1677
|
-
color = PIL.ImageColor.getcolor(self.edge,
|
|
1678
|
-
tile =
|
|
1680
|
+
color = PIL.ImageColor.getcolor(self.edge, mode)
|
|
1681
|
+
tile = tile.copy()
|
|
1679
1682
|
tile[:, contentWidth:] = color
|
|
1680
1683
|
tile[contentHeight:] = color
|
|
1681
1684
|
if isinstance(tile, np.ndarray) and numpyAllowed:
|
|
@@ -2207,7 +2210,7 @@ class TileSource(IPyLeafletMixin):
|
|
|
2207
2210
|
mode = None if TILE_FORMAT_NUMPY in format else iterInfo['mode']
|
|
2208
2211
|
outWidth = iterInfo['output']['width']
|
|
2209
2212
|
outHeight = iterInfo['output']['height']
|
|
2210
|
-
image: Optional[np.ndarray] = None
|
|
2213
|
+
image: Optional[Union[np.ndarray, PIL.Image.Image, ImageBytes, bytes]] = None
|
|
2211
2214
|
tiledimage = None
|
|
2212
2215
|
for tile in self._tileIterator(iterInfo):
|
|
2213
2216
|
# Add each tile to the image
|
|
@@ -2218,7 +2221,7 @@ class TileSource(IPyLeafletMixin):
|
|
|
2218
2221
|
tiledimage, subimage, x0, y0, regionWidth, regionHeight, tile, **kwargs)
|
|
2219
2222
|
else:
|
|
2220
2223
|
image = utilities._addSubimageToImage(
|
|
2221
|
-
image, subimage, x0, y0, regionWidth, regionHeight)
|
|
2224
|
+
cast(Optional[np.ndarray], image), subimage, x0, y0, regionWidth, regionHeight)
|
|
2222
2225
|
# Somehow discarding the tile here speeds things up.
|
|
2223
2226
|
del tile
|
|
2224
2227
|
del subimage
|
|
@@ -2230,7 +2233,7 @@ class TileSource(IPyLeafletMixin):
|
|
|
2230
2233
|
cast(Dict[str, Any], tiledimage), outWidth, outHeight, iterInfo, **kwargs)
|
|
2231
2234
|
if outWidth != regionWidth or outHeight != regionHeight:
|
|
2232
2235
|
dtype = cast(np.ndarray, image).dtype
|
|
2233
|
-
image = _imageToPIL(image, mode).resize(
|
|
2236
|
+
image = _imageToPIL(cast(np.ndarray, image), mode).resize(
|
|
2234
2237
|
(outWidth, outHeight),
|
|
2235
2238
|
getattr(PIL.Image, 'Resampling', PIL.Image).BICUBIC
|
|
2236
2239
|
if outWidth > regionWidth else
|
|
@@ -2241,8 +2244,8 @@ class TileSource(IPyLeafletMixin):
|
|
|
2241
2244
|
maxHeight = kwargs.get('output', {}).get('maxHeight')
|
|
2242
2245
|
if kwargs.get('fill') and maxWidth and maxHeight:
|
|
2243
2246
|
image = utilities._letterboxImage(
|
|
2244
|
-
_imageToPIL(image, mode), maxWidth, maxHeight, kwargs['fill'])
|
|
2245
|
-
return utilities._encodeImage(image, format=format, **kwargs)
|
|
2247
|
+
_imageToPIL(cast(np.ndarray, image), mode), maxWidth, maxHeight, kwargs['fill'])
|
|
2248
|
+
return utilities._encodeImage(cast(np.ndarray, image), format=format, **kwargs)
|
|
2246
2249
|
|
|
2247
2250
|
def _encodeTiledImage(
|
|
2248
2251
|
self, image: Dict[str, Any], outWidth: int, outHeight: int,
|
|
@@ -2435,14 +2438,16 @@ class TileSource(IPyLeafletMixin):
|
|
|
2435
2438
|
frame, idx, len(frameList), offsetX, offsetY)
|
|
2436
2439
|
if tiled:
|
|
2437
2440
|
tiledimage = utilities._addRegionTileToTiled(
|
|
2438
|
-
tiledimage, subimage, offsetX,
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
image
|
|
2441
|
+
tiledimage, cast(np.ndarray, subimage), offsetX,
|
|
2442
|
+
offsetY, outWidth, outHeight, tile, **kwargs)
|
|
2443
|
+
else:
|
|
2444
|
+
image = utilities._addSubimageToImage(
|
|
2445
|
+
image, cast(np.ndarray, subimage), offsetX, offsetY,
|
|
2446
|
+
outWidth, outHeight)
|
|
2442
2447
|
if tiled:
|
|
2443
2448
|
return self._encodeTiledImage(
|
|
2444
2449
|
cast(Dict[str, Any], tiledimage), outWidth, outHeight, iterInfo, **kwargs)
|
|
2445
|
-
return utilities._encodeImage(image, format=format, **kwargs)
|
|
2450
|
+
return utilities._encodeImage(cast(np.ndarray, image), format=format, **kwargs)
|
|
2446
2451
|
|
|
2447
2452
|
def getRegionAtAnotherScale(
|
|
2448
2453
|
self, sourceRegion: Dict[str, Any],
|
|
@@ -2851,7 +2856,7 @@ class TileSource(IPyLeafletMixin):
|
|
|
2851
2856
|
getattr(PIL.Image, 'Resampling', PIL.Image).BICUBIC
|
|
2852
2857
|
if width > imageWidth else
|
|
2853
2858
|
getattr(PIL.Image, 'Resampling', PIL.Image).LANCZOS)
|
|
2854
|
-
return utilities._encodeImage(image, **kwargs)
|
|
2859
|
+
return cast(Tuple[ImageBytes, str], utilities._encodeImage(image, **kwargs))
|
|
2855
2860
|
|
|
2856
2861
|
def getPixel(self, includeTileRecord: bool = False, **kwargs) -> JSONDict:
|
|
2857
2862
|
"""
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, cast
|
|
1
3
|
from urllib.parse import urlencode, urlparse
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from large_image.exceptions import TileSourceError
|
|
5
|
+
import numpy as np
|
|
6
|
+
import PIL.Image
|
|
6
7
|
|
|
8
|
+
from ..cache_util import CacheProperties, methodcache
|
|
9
|
+
from ..constants import SourcePriority, TileInputUnits
|
|
10
|
+
from ..exceptions import TileSourceError
|
|
7
11
|
from .base import FileTileSource
|
|
8
|
-
from .utilities import JSONDict, getPaletteColors
|
|
12
|
+
from .utilities import ImageBytes, JSONDict, getPaletteColors
|
|
9
13
|
|
|
10
14
|
try:
|
|
11
15
|
import pyproj
|
|
@@ -20,16 +24,16 @@ CacheProperties['tilesource']['itemExpectedSize'] = max(
|
|
|
20
24
|
100 * 1024 ** 2)
|
|
21
25
|
|
|
22
26
|
# Used to cache pixel size for projections
|
|
23
|
-
ProjUnitsAcrossLevel0 = {}
|
|
27
|
+
ProjUnitsAcrossLevel0: Dict[str, float] = {}
|
|
24
28
|
ProjUnitsAcrossLevel0_MaxSize = 100
|
|
25
29
|
|
|
26
30
|
InitPrefix = ''
|
|
27
31
|
NeededInitPrefix = '+init=' if has_pyproj and _pyproj_under_6 else InitPrefix
|
|
28
32
|
|
|
29
33
|
|
|
30
|
-
def make_vsi(url: str, **options):
|
|
34
|
+
def make_vsi(url: Union[str, pathlib.Path, Dict[Any, Any]], **options) -> str:
|
|
31
35
|
if str(url).startswith('s3://'):
|
|
32
|
-
s3_path = url.replace('s3://', '')
|
|
36
|
+
s3_path = str(url).replace('s3://', '')
|
|
33
37
|
vsi = f'/vsis3/{s3_path}'
|
|
34
38
|
else:
|
|
35
39
|
gdal_options = {
|
|
@@ -74,7 +78,14 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
74
78
|
'image/x-tiff': SourcePriority.LOW,
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
projection: Union[str, bytes]
|
|
82
|
+
projectionOrigin: Tuple[float, float]
|
|
83
|
+
sourceLevels: int
|
|
84
|
+
sourceSizeX: int
|
|
85
|
+
sourceSizeY: int
|
|
86
|
+
unitsAcrossLevel0: float
|
|
87
|
+
|
|
88
|
+
def _getDriver(self) -> str:
|
|
78
89
|
"""
|
|
79
90
|
Get the GDAL driver used to read this dataset.
|
|
80
91
|
|
|
@@ -82,20 +93,20 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
82
93
|
"""
|
|
83
94
|
raise NotImplementedError
|
|
84
95
|
|
|
85
|
-
def _convertProjectionUnits(self, *args, **kwargs):
|
|
96
|
+
def _convertProjectionUnits(self, *args, **kwargs) -> Tuple[float, float, float, float, str]:
|
|
86
97
|
raise NotImplementedError
|
|
87
98
|
|
|
88
|
-
def pixelToProjection(self, *args, **kwargs):
|
|
99
|
+
def pixelToProjection(self, *args, **kwargs) -> Tuple[float, float]:
|
|
89
100
|
raise NotImplementedError
|
|
90
101
|
|
|
91
|
-
def toNativePixelCoordinates(self, *args, **kwargs):
|
|
102
|
+
def toNativePixelCoordinates(self, *args, **kwargs) -> Tuple[float, float]:
|
|
92
103
|
raise NotImplementedError
|
|
93
104
|
|
|
94
|
-
def getBounds(self, *args, **kwargs):
|
|
105
|
+
def getBounds(self, *args, **kwargs) -> Dict[str, Any]:
|
|
95
106
|
raise NotImplementedError
|
|
96
107
|
|
|
97
108
|
@staticmethod
|
|
98
|
-
def isGeospatial(path):
|
|
109
|
+
def isGeospatial(path: Union[str, pathlib.Path]) -> bool:
|
|
99
110
|
"""
|
|
100
111
|
Check if a path is likely to be a geospatial file.
|
|
101
112
|
|
|
@@ -105,13 +116,13 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
105
116
|
raise NotImplementedError
|
|
106
117
|
|
|
107
118
|
@property
|
|
108
|
-
def geospatial(self):
|
|
119
|
+
def geospatial(self) -> bool:
|
|
109
120
|
"""
|
|
110
121
|
This is true if the source has geospatial information.
|
|
111
122
|
"""
|
|
112
123
|
return bool(self.projection)
|
|
113
124
|
|
|
114
|
-
def _getLargeImagePath(self):
|
|
125
|
+
def _getLargeImagePath(self) -> str:
|
|
115
126
|
"""Get GDAL-compatible image path.
|
|
116
127
|
|
|
117
128
|
This will cast the output to a string and can also handle URLs
|
|
@@ -122,7 +133,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
122
133
|
return make_vsi(self.largeImagePath)
|
|
123
134
|
return str(self.largeImagePath)
|
|
124
135
|
|
|
125
|
-
def _setStyle(self, style):
|
|
136
|
+
def _setStyle(self, style: Any) -> None:
|
|
126
137
|
"""
|
|
127
138
|
Check and set the specified style from a json string or a dictionary.
|
|
128
139
|
|
|
@@ -132,7 +143,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
132
143
|
if hasattr(self, '_getTileLock'):
|
|
133
144
|
self._setDefaultStyle()
|
|
134
145
|
|
|
135
|
-
def _styleBands(self):
|
|
146
|
+
def _styleBands(self) -> List[Dict[str, Any]]:
|
|
136
147
|
interpColorTable = {
|
|
137
148
|
'red': ['#000000', '#ff0000'],
|
|
138
149
|
'green': ['#000000', '#00ff00'],
|
|
@@ -178,7 +189,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
178
189
|
})
|
|
179
190
|
return style
|
|
180
191
|
|
|
181
|
-
def _setDefaultStyle(self):
|
|
192
|
+
def _setDefaultStyle(self) -> None:
|
|
182
193
|
"""If no style was specified, create a default style."""
|
|
183
194
|
self._bandNames = {}
|
|
184
195
|
for idx, band in self.getBandInformation().items():
|
|
@@ -224,16 +235,16 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
224
235
|
self._style = JSONDict({'bands': style})
|
|
225
236
|
|
|
226
237
|
@staticmethod
|
|
227
|
-
def getHexColors(palette):
|
|
238
|
+
def getHexColors(palette: Union[str, List[Union[str, float, Tuple[float, ...]]]]) -> List[str]:
|
|
228
239
|
"""
|
|
229
240
|
Returns list of hex colors for a given color palette
|
|
230
241
|
|
|
231
242
|
:returns: List of colors
|
|
232
243
|
"""
|
|
233
|
-
|
|
234
|
-
return ['#%02X%02X%02X%02X' % tuple(int(val) for val in clr) for clr in
|
|
244
|
+
pal = getPaletteColors(palette)
|
|
245
|
+
return ['#%02X%02X%02X%02X' % tuple(int(val) for val in clr) for clr in pal]
|
|
235
246
|
|
|
236
|
-
def getPixelSizeInMeters(self):
|
|
247
|
+
def getPixelSizeInMeters(self) -> Optional[float]:
|
|
237
248
|
"""
|
|
238
249
|
Get the approximate base pixel size in meters. This is calculated as
|
|
239
250
|
the average scale of the four edges in the WGS84 ellipsoid.
|
|
@@ -242,13 +253,13 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
242
253
|
"""
|
|
243
254
|
bounds = self.getBounds(NeededInitPrefix + 'epsg:4326')
|
|
244
255
|
if not bounds:
|
|
245
|
-
return
|
|
256
|
+
return None
|
|
246
257
|
if has_pyproj:
|
|
247
258
|
geod = pyproj.Geod(ellps='WGS84')
|
|
248
|
-
computer = geod.inv
|
|
259
|
+
computer = cast(Callable[[Any, Any, Any, Any], Tuple[Any, Any, float]], geod.inv)
|
|
249
260
|
else:
|
|
250
261
|
# Estimate based on great-cirlce distance
|
|
251
|
-
def computer(lon1, lat1, lon2, lat2):
|
|
262
|
+
def computer(lon1, lat1, lon2, lat2) -> Tuple[Any, Any, float]:
|
|
252
263
|
from math import acos, cos, radians, sin
|
|
253
264
|
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
|
|
254
265
|
return None, None, 6.378e+6 * (
|
|
@@ -264,7 +275,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
264
275
|
bounds['ul']['x'], bounds['ul']['y'])
|
|
265
276
|
return (s1 + s2 + s3 + s4) / (self.sourceSizeX * 2 + self.sourceSizeY * 2)
|
|
266
277
|
|
|
267
|
-
def getNativeMagnification(self):
|
|
278
|
+
def getNativeMagnification(self) -> Dict[str, Optional[float]]:
|
|
268
279
|
"""
|
|
269
280
|
Get the magnification at the base level.
|
|
270
281
|
|
|
@@ -277,7 +288,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
277
288
|
'mm_y': scale * 100 if scale else None,
|
|
278
289
|
}
|
|
279
290
|
|
|
280
|
-
def getTileCorners(self, z, x, y):
|
|
291
|
+
def getTileCorners(self, z: int, x: float, y: float) -> Tuple[float, float, float, float]:
|
|
281
292
|
"""
|
|
282
293
|
Returns bounds of a tile for a given x,y,z index.
|
|
283
294
|
|
|
@@ -307,7 +318,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
307
318
|
ymin, ymax = self.sourceSizeY - ymax, self.sourceSizeY - ymin
|
|
308
319
|
return xmin, ymin, xmax, ymax
|
|
309
320
|
|
|
310
|
-
def _bandNumber(self, band, exc=True):
|
|
321
|
+
def _bandNumber(self, band: Optional[Union[str, int]], exc: bool = True) -> Optional[int]:
|
|
311
322
|
"""Given a band number or interpretation name, return a validated band number.
|
|
312
323
|
|
|
313
324
|
:param band: either -1, a positive integer, or the name of a band interpretation
|
|
@@ -339,9 +350,13 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
339
350
|
|
|
340
351
|
return band
|
|
341
352
|
|
|
342
|
-
def _getRegionBounds(
|
|
343
|
-
|
|
344
|
-
|
|
353
|
+
def _getRegionBounds(
|
|
354
|
+
self, metadata: JSONDict, left: Optional[float] = None,
|
|
355
|
+
top: Optional[float] = None, right: Optional[float] = None,
|
|
356
|
+
bottom: Optional[float] = None, width: Optional[float] = None,
|
|
357
|
+
height: Optional[float] = None, units: Optional[str] = None,
|
|
358
|
+
desiredMagnification: Optional[Dict[str, Optional[float]]] = None,
|
|
359
|
+
cropToImage: bool = True, **kwargs) -> Tuple[float, float, float, float]:
|
|
345
360
|
"""
|
|
346
361
|
Given a set of arguments that can include left, right, top, bottom,
|
|
347
362
|
width, height, and units, generate actual pixel values for left, top,
|
|
@@ -385,7 +400,7 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
385
400
|
if top is None:
|
|
386
401
|
top = bounds['ymax'] if bottom is None or width is None else bottom - width
|
|
387
402
|
if bottom is None:
|
|
388
|
-
bottom = bounds['ymin'] if width is None else top + height
|
|
403
|
+
bottom = bounds['ymin'] if width is None else cast(float, top) + cast(float, height)
|
|
389
404
|
if not kwargs.get('unitsWH') or kwargs.get('unitsWH') == units:
|
|
390
405
|
width = height = None
|
|
391
406
|
# Convert to [-0.5, 0.5], [-0.5, 0.5] coordinate range
|
|
@@ -401,14 +416,18 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
401
416
|
top = max(0, min(yScale, (0.5 - top) * yScale))
|
|
402
417
|
bottom = max(0, min(yScale, (0.5 - bottom) * yScale))
|
|
403
418
|
# Ensure correct ordering
|
|
404
|
-
left, right = min(left, right), max(left, right)
|
|
405
|
-
top, bottom = min(top, bottom), max(top, bottom)
|
|
419
|
+
left, right = min(cast(float, left), cast(float, right)), max(left, cast(float, right))
|
|
420
|
+
top, bottom = min(cast(float, top), cast(float, bottom)), max(top, cast(float, bottom))
|
|
406
421
|
units = 'base_pixels'
|
|
407
422
|
return super()._getRegionBounds(
|
|
408
|
-
metadata, left, top, right, bottom, width, height, units,
|
|
423
|
+
metadata, left, top, right, bottom, width, height, units,
|
|
424
|
+
desiredMagnification, cropToImage, **kwargs)
|
|
409
425
|
|
|
410
426
|
@methodcache()
|
|
411
|
-
def getThumbnail(
|
|
427
|
+
def getThumbnail(
|
|
428
|
+
self, width: Optional[Union[str, int]] = None,
|
|
429
|
+
height: Optional[Union[str, int]] = None, **kwargs) -> Tuple[
|
|
430
|
+
Union[np.ndarray, PIL.Image.Image, ImageBytes, bytes, pathlib.Path], str]:
|
|
412
431
|
"""
|
|
413
432
|
Get a basic thumbnail from the current tile source. Aspect ratio is
|
|
414
433
|
preserved. If neither width nor height is given, a default value is
|
|
@@ -424,8 +443,8 @@ class GDALBaseFileTileSource(GeoBaseFileTileSource):
|
|
|
424
443
|
:returns: thumbData, thumbMime: the image data and the mime type.
|
|
425
444
|
"""
|
|
426
445
|
if self.projection:
|
|
427
|
-
if ((width is not None and width < 2) or
|
|
428
|
-
(height is not None and height < 2)):
|
|
446
|
+
if ((width is not None and float(width) < 2) or
|
|
447
|
+
(height is not None and float(height) < 2)):
|
|
429
448
|
msg = 'Invalid width or height. Minimum value is 2.'
|
|
430
449
|
raise ValueError(msg)
|
|
431
450
|
if width is None and height is None:
|