Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +4 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/__main__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/freeze.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/testing.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/typing.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/v2.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/v3.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/__init__.py +16 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/extensions.py +1919 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/plugins.py +784 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__init__.py +16 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/legacy_plugin_wrapper.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/request.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/findlib.py +161 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/format.py +856 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/imopen.py +303 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/legacy_plugin_wrapper.py +322 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/request.py +752 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/v3_plugin_api.py +367 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/__init__.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_bsdf.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_dicom.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_freeimage.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_swf.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/feisem.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/fits.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/freeimage.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/gdal.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/lytro.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/npz.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/opencv.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow_info.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow_legacy.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillowmulti.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/simpleitk.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/swf.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/tifffile.cpython-38.pyc +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/_dicom.py +925 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/_tifffile.py +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/example.py +148 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/gdal.py +71 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/npz.py +85 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/resources/images/realshort.mp4 +0 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/patches.cpython-38.pyc +3 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf +3 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralBolIta.ttf +3 -0
- my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralItalic.ttf +3 -0
.gitattributes
CHANGED
|
@@ -375,3 +375,7 @@ my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/pkg_resourc
|
|
| 375 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/backend_bases.cpython-38.pyc filter=lfs diff=lfs merge=lfs -text
|
| 376 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/lxml/objectify.cpython-38-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 377 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/figure.cpython-38.pyc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 375 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/backend_bases.cpython-38.pyc filter=lfs diff=lfs merge=lfs -text
|
| 376 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/lxml/objectify.cpython-38-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 377 |
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/figure.cpython-38.pyc filter=lfs diff=lfs merge=lfs -text
|
| 378 |
+
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/patches.cpython-38.pyc filter=lfs diff=lfs merge=lfs -text
|
| 379 |
+
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralBolIta.ttf filter=lfs diff=lfs merge=lfs -text
|
| 380 |
+
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralItalic.ttf filter=lfs diff=lfs merge=lfs -text
|
| 381 |
+
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf filter=lfs diff=lfs merge=lfs -text
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (2.66 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/__main__.cpython-38.pyc
ADDED
|
Binary file (4.19 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/freeze.cpython-38.pyc
ADDED
|
Binary file (476 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/testing.cpython-38.pyc
ADDED
|
Binary file (1.51 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/typing.cpython-38.pyc
ADDED
|
Binary file (479 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/v2.cpython-38.pyc
ADDED
|
Binary file (15.5 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/__pycache__/v3.cpython-38.pyc
ADDED
|
Binary file (9.77 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .extensions import (
|
| 2 |
+
extension_list,
|
| 3 |
+
known_extensions,
|
| 4 |
+
FileExtension,
|
| 5 |
+
video_extensions,
|
| 6 |
+
)
|
| 7 |
+
from .plugins import known_plugins, PluginConfig
|
| 8 |
+
|
| 9 |
+
__all__ = [
|
| 10 |
+
"known_plugins",
|
| 11 |
+
"PluginConfig",
|
| 12 |
+
"extension_list",
|
| 13 |
+
"known_extensions",
|
| 14 |
+
"FileExtension",
|
| 15 |
+
"video_extensions",
|
| 16 |
+
]
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/extensions.py
ADDED
|
@@ -0,0 +1,1919 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
A set of objects representing each file extension recognized by ImageIO. If an
|
| 3 |
+
extension is not listed here it is still supported, as long as there exists a
|
| 4 |
+
supporting backend.
|
| 5 |
+
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class FileExtension:
|
| 10 |
+
"""File Extension Metadata
|
| 11 |
+
|
| 12 |
+
This class holds information about a image file format associated with a
|
| 13 |
+
given extension. This information is used to track plugins that are known to
|
| 14 |
+
be able to handle a particular format. It also contains additional
|
| 15 |
+
information about a format, which is used when creating the supported format
|
| 16 |
+
docs.
|
| 17 |
+
|
| 18 |
+
Plugins known to be able to handle this format are ordered by a ``priority``
|
| 19 |
+
list. This list is used to determine the ideal plugin to use when choosing a
|
| 20 |
+
plugin based on file extension.
|
| 21 |
+
|
| 22 |
+
Parameters
|
| 23 |
+
----------
|
| 24 |
+
extension : str
|
| 25 |
+
The name of the extension including the initial dot, e.g. ".png".
|
| 26 |
+
priority : List
|
| 27 |
+
A list of plugin names (entries in config.known_plugins) that can handle
|
| 28 |
+
this format. The position of a plugin expresses a preference, e.g.
|
| 29 |
+
["plugin1", "plugin2"] indicates that, if available, plugin1 should be
|
| 30 |
+
preferred over plugin2 when handling a request related to this format.
|
| 31 |
+
name : str
|
| 32 |
+
The full name of the format.
|
| 33 |
+
description : str
|
| 34 |
+
A description of the format.
|
| 35 |
+
external_link : str
|
| 36 |
+
A link to further information about the format. Typically, the format's
|
| 37 |
+
specification.
|
| 38 |
+
|
| 39 |
+
Examples
|
| 40 |
+
--------
|
| 41 |
+
>>> FileExtension(
|
| 42 |
+
name="Bitmap",
|
| 43 |
+
extension=".bmp",
|
| 44 |
+
priority=["pillow", "BMP-PIL", "BMP-FI", "ITK"],
|
| 45 |
+
external_link="https://en.wikipedia.org/wiki/BMP_file_format",
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
"""
|
| 49 |
+
|
| 50 |
+
def __init__(
|
| 51 |
+
self, *, extension, priority, name=None, description=None, external_link=None
|
| 52 |
+
):
|
| 53 |
+
self.extension = extension
|
| 54 |
+
self.priority = priority
|
| 55 |
+
self.name = name
|
| 56 |
+
self.description = description
|
| 57 |
+
self.external_link = external_link
|
| 58 |
+
self.default_priority = priority.copy()
|
| 59 |
+
|
| 60 |
+
def reset(self):
|
| 61 |
+
self.priority = self.default_priority.copy()
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
extension_list = [
|
| 65 |
+
FileExtension(
|
| 66 |
+
name="Hasselblad raw",
|
| 67 |
+
extension=".3fr",
|
| 68 |
+
priority=["RAW-FI"],
|
| 69 |
+
),
|
| 70 |
+
FileExtension(
|
| 71 |
+
name="Sony alpha",
|
| 72 |
+
extension=".arw",
|
| 73 |
+
priority=["RAW-FI"],
|
| 74 |
+
),
|
| 75 |
+
FileExtension(
|
| 76 |
+
name="Animated Portable Network Graphics",
|
| 77 |
+
external_link="https://en.wikipedia.org/wiki/APNG",
|
| 78 |
+
extension=".apng",
|
| 79 |
+
priority=["pillow", "pyav"],
|
| 80 |
+
),
|
| 81 |
+
FileExtension(
|
| 82 |
+
name="Audio Video Interleave",
|
| 83 |
+
extension=".avi",
|
| 84 |
+
priority=["FFMPEG"],
|
| 85 |
+
),
|
| 86 |
+
FileExtension(
|
| 87 |
+
name="Casio raw format",
|
| 88 |
+
extension=".bay",
|
| 89 |
+
priority=["RAW-FI"],
|
| 90 |
+
),
|
| 91 |
+
FileExtension(
|
| 92 |
+
extension=".blp",
|
| 93 |
+
priority=["pillow"],
|
| 94 |
+
),
|
| 95 |
+
FileExtension(
|
| 96 |
+
name="Bitmap",
|
| 97 |
+
extension=".bmp",
|
| 98 |
+
priority=["pillow", "BMP-PIL", "BMP-FI", "ITK", "pyav", "opencv"],
|
| 99 |
+
external_link="https://en.wikipedia.org/wiki/BMP_file_format",
|
| 100 |
+
),
|
| 101 |
+
FileExtension(
|
| 102 |
+
name="Device-Independent Bitmap",
|
| 103 |
+
extension=".dip",
|
| 104 |
+
priority=["opencv"],
|
| 105 |
+
external_link="https://en.wikipedia.org/wiki/BMP_file_format",
|
| 106 |
+
),
|
| 107 |
+
FileExtension(
|
| 108 |
+
name="Re-Volt mipmap",
|
| 109 |
+
extension=".bmq",
|
| 110 |
+
priority=["RAW-FI"],
|
| 111 |
+
),
|
| 112 |
+
FileExtension(
|
| 113 |
+
name="Binary Structured Data Format",
|
| 114 |
+
extension=".bsdf",
|
| 115 |
+
priority=["BSDF"],
|
| 116 |
+
external_link="http://bsdf.io/",
|
| 117 |
+
),
|
| 118 |
+
FileExtension(
|
| 119 |
+
name="Binary Universal Form for the Representation of meteorological data",
|
| 120 |
+
extension=".bufr",
|
| 121 |
+
priority=["pillow", "BUFR-PIL"],
|
| 122 |
+
),
|
| 123 |
+
FileExtension(
|
| 124 |
+
name="Silicon Graphics Image",
|
| 125 |
+
extension=".bw",
|
| 126 |
+
priority=["pillow", "SGI-PIL", "SGI-FI"],
|
| 127 |
+
),
|
| 128 |
+
FileExtension(
|
| 129 |
+
name="Scirra Construct",
|
| 130 |
+
extension=".cap",
|
| 131 |
+
priority=["RAW-FI"],
|
| 132 |
+
),
|
| 133 |
+
FileExtension(
|
| 134 |
+
name="AMETEK High Speed Camera Format",
|
| 135 |
+
extension=".cine",
|
| 136 |
+
priority=["RAW-FI"],
|
| 137 |
+
external_link="https://phantomhighspeed-knowledge.secure.force.com/servlet/fileField?id=0BE1N000000kD2i#:~:text=Cine%20is%20a%20video%20file,camera%20model%20and%20image%20resolution",
|
| 138 |
+
),
|
| 139 |
+
FileExtension(extension=".cr2", priority=["RAW-FI"]),
|
| 140 |
+
FileExtension(
|
| 141 |
+
extension=".crw",
|
| 142 |
+
priority=["RAW-FI"],
|
| 143 |
+
),
|
| 144 |
+
FileExtension(
|
| 145 |
+
extension=".cs1",
|
| 146 |
+
priority=["RAW-FI"],
|
| 147 |
+
),
|
| 148 |
+
FileExtension(
|
| 149 |
+
name="Computerized Tomography",
|
| 150 |
+
extension=".ct",
|
| 151 |
+
priority=["DICOM"],
|
| 152 |
+
),
|
| 153 |
+
FileExtension(
|
| 154 |
+
name="Windows Cursor Icons",
|
| 155 |
+
extension=".cur",
|
| 156 |
+
priority=["pillow", "CUR-PIL"],
|
| 157 |
+
),
|
| 158 |
+
FileExtension(
|
| 159 |
+
name="Dr. Halo",
|
| 160 |
+
extension=".cut",
|
| 161 |
+
priority=["CUT-FI"],
|
| 162 |
+
),
|
| 163 |
+
FileExtension(
|
| 164 |
+
extension=".dc2",
|
| 165 |
+
priority=["RAW-FI"],
|
| 166 |
+
),
|
| 167 |
+
FileExtension(
|
| 168 |
+
name="DICOM file format",
|
| 169 |
+
extension=".dcm",
|
| 170 |
+
priority=["DICOM", "ITK"],
|
| 171 |
+
),
|
| 172 |
+
FileExtension(
|
| 173 |
+
extension=".dcr",
|
| 174 |
+
priority=["RAW-FI"],
|
| 175 |
+
),
|
| 176 |
+
FileExtension(
|
| 177 |
+
name="Intel DCX",
|
| 178 |
+
extension=".dcx",
|
| 179 |
+
priority=["pillow", "DCX-PIL"],
|
| 180 |
+
),
|
| 181 |
+
FileExtension(
|
| 182 |
+
name="DirectX Texture Container",
|
| 183 |
+
extension=".dds",
|
| 184 |
+
priority=["pillow", "DDS-FI", "DDS-PIL"],
|
| 185 |
+
),
|
| 186 |
+
FileExtension(
|
| 187 |
+
name="Windows Bitmap",
|
| 188 |
+
extension=".dib",
|
| 189 |
+
priority=["pillow", "DIB-PIL"],
|
| 190 |
+
),
|
| 191 |
+
FileExtension(
|
| 192 |
+
name="DICOM file format",
|
| 193 |
+
extension=".dicom",
|
| 194 |
+
priority=["ITK"],
|
| 195 |
+
),
|
| 196 |
+
FileExtension(
|
| 197 |
+
extension=".dng",
|
| 198 |
+
priority=["RAW-FI"],
|
| 199 |
+
),
|
| 200 |
+
FileExtension(
|
| 201 |
+
extension=".drf",
|
| 202 |
+
priority=["RAW-FI"],
|
| 203 |
+
),
|
| 204 |
+
FileExtension(
|
| 205 |
+
extension=".dsc",
|
| 206 |
+
priority=["RAW-FI"],
|
| 207 |
+
),
|
| 208 |
+
FileExtension(
|
| 209 |
+
name="Enhanced Compression Wavelet",
|
| 210 |
+
extension=".ecw",
|
| 211 |
+
priority=["GDAL"],
|
| 212 |
+
),
|
| 213 |
+
FileExtension(
|
| 214 |
+
name="Windows Metafile",
|
| 215 |
+
extension=".emf",
|
| 216 |
+
priority=["pillow", "WMF-PIL"],
|
| 217 |
+
),
|
| 218 |
+
FileExtension(
|
| 219 |
+
name="Encapsulated Postscript",
|
| 220 |
+
extension=".eps",
|
| 221 |
+
priority=["pillow", "EPS-PIL"],
|
| 222 |
+
),
|
| 223 |
+
FileExtension(
|
| 224 |
+
extension=".erf",
|
| 225 |
+
priority=["RAW-FI"],
|
| 226 |
+
),
|
| 227 |
+
FileExtension(
|
| 228 |
+
name="ILM OpenEXR",
|
| 229 |
+
extension=".exr",
|
| 230 |
+
priority=["EXR-FI", "pyav", "opencv"],
|
| 231 |
+
),
|
| 232 |
+
FileExtension(
|
| 233 |
+
extension=".fff",
|
| 234 |
+
priority=["RAW-FI"],
|
| 235 |
+
),
|
| 236 |
+
FileExtension(
|
| 237 |
+
name="Flexible Image Transport System File",
|
| 238 |
+
extension=".fit",
|
| 239 |
+
priority=["pillow", "FITS-PIL", "FITS"],
|
| 240 |
+
),
|
| 241 |
+
FileExtension(
|
| 242 |
+
name="Flexible Image Transport System File",
|
| 243 |
+
extension=".fits",
|
| 244 |
+
priority=["pillow", "FITS-PIL", "FITS", "pyav"],
|
| 245 |
+
),
|
| 246 |
+
FileExtension(
|
| 247 |
+
name="Autodesk FLC Animation",
|
| 248 |
+
extension=".flc",
|
| 249 |
+
priority=["pillow", "FLI-PIL"],
|
| 250 |
+
),
|
| 251 |
+
FileExtension(
|
| 252 |
+
name="Autodesk FLI Animation",
|
| 253 |
+
extension=".fli",
|
| 254 |
+
priority=["pillow", "FLI-PIL"],
|
| 255 |
+
),
|
| 256 |
+
FileExtension(
|
| 257 |
+
name="Kodak FlashPix",
|
| 258 |
+
extension=".fpx",
|
| 259 |
+
priority=["pillow", "FPX-PIL"],
|
| 260 |
+
),
|
| 261 |
+
FileExtension(
|
| 262 |
+
name="Independence War 2: Edge Of Chaos Texture Format",
|
| 263 |
+
extension=".ftc",
|
| 264 |
+
priority=["pillow", "FTEX-PIL"],
|
| 265 |
+
),
|
| 266 |
+
FileExtension(
|
| 267 |
+
name="Flexible Image Transport System File",
|
| 268 |
+
extension=".fts",
|
| 269 |
+
priority=["FITS"],
|
| 270 |
+
),
|
| 271 |
+
FileExtension(
|
| 272 |
+
name="Independence War 2: Edge Of Chaos Texture Format",
|
| 273 |
+
extension=".ftu",
|
| 274 |
+
priority=["pillow", "FTEX-PIL"],
|
| 275 |
+
),
|
| 276 |
+
FileExtension(
|
| 277 |
+
name="Flexible Image Transport System File",
|
| 278 |
+
extension=".fz",
|
| 279 |
+
priority=["FITS"],
|
| 280 |
+
),
|
| 281 |
+
FileExtension(
|
| 282 |
+
name="Raw fax format CCITT G.3",
|
| 283 |
+
extension=".g3",
|
| 284 |
+
priority=["G3-FI"],
|
| 285 |
+
),
|
| 286 |
+
FileExtension(
|
| 287 |
+
name="GIMP brush file",
|
| 288 |
+
extension=".gbr",
|
| 289 |
+
priority=["pillow", "GBR-PIL"],
|
| 290 |
+
),
|
| 291 |
+
FileExtension(
|
| 292 |
+
name="Grassroots DICOM",
|
| 293 |
+
extension=".gdcm",
|
| 294 |
+
priority=["ITK"],
|
| 295 |
+
),
|
| 296 |
+
FileExtension(
|
| 297 |
+
name="Graphics Interchange Format",
|
| 298 |
+
extension=".gif",
|
| 299 |
+
priority=["pillow", "GIF-PIL", "pyav"],
|
| 300 |
+
),
|
| 301 |
+
FileExtension(
|
| 302 |
+
name="UMDS GIPL",
|
| 303 |
+
extension=".gipl",
|
| 304 |
+
priority=["ITK"],
|
| 305 |
+
),
|
| 306 |
+
FileExtension(
|
| 307 |
+
name="gridded meteorological data",
|
| 308 |
+
extension=".grib",
|
| 309 |
+
priority=["pillow", "GRIB-PIL"],
|
| 310 |
+
),
|
| 311 |
+
FileExtension(
|
| 312 |
+
name="Hierarchical Data Format 5",
|
| 313 |
+
extension=".h5",
|
| 314 |
+
priority=["pillow", "HDF5-PIL"],
|
| 315 |
+
),
|
| 316 |
+
FileExtension(
|
| 317 |
+
name="Hierarchical Data Format 5",
|
| 318 |
+
extension=".hdf",
|
| 319 |
+
priority=["pillow", "HDF5-PIL"],
|
| 320 |
+
),
|
| 321 |
+
FileExtension(
|
| 322 |
+
name="Hierarchical Data Format 5",
|
| 323 |
+
extension=".hdf5",
|
| 324 |
+
priority=["ITK"],
|
| 325 |
+
),
|
| 326 |
+
FileExtension(
|
| 327 |
+
name="JPEG Extended Range",
|
| 328 |
+
extension=".hdp",
|
| 329 |
+
priority=["JPEG-XR-FI"],
|
| 330 |
+
),
|
| 331 |
+
FileExtension(
|
| 332 |
+
name="High Dynamic Range Image",
|
| 333 |
+
extension=".hdr",
|
| 334 |
+
priority=["HDR-FI", "ITK", "opencv"],
|
| 335 |
+
),
|
| 336 |
+
FileExtension(
|
| 337 |
+
extension=".ia",
|
| 338 |
+
priority=["RAW-FI"],
|
| 339 |
+
),
|
| 340 |
+
FileExtension(
|
| 341 |
+
extension=".icb",
|
| 342 |
+
priority=["pillow"],
|
| 343 |
+
),
|
| 344 |
+
FileExtension(
|
| 345 |
+
name="Mac OS Icon File",
|
| 346 |
+
extension=".icns",
|
| 347 |
+
priority=["pillow", "ICNS-PIL"],
|
| 348 |
+
),
|
| 349 |
+
FileExtension(
|
| 350 |
+
name="Windows Icon File",
|
| 351 |
+
extension=".ico",
|
| 352 |
+
priority=["pillow", "ICO-FI", "ICO-PIL", "pyav"],
|
| 353 |
+
),
|
| 354 |
+
FileExtension(
|
| 355 |
+
name="ILBM Interleaved Bitmap",
|
| 356 |
+
extension=".iff",
|
| 357 |
+
priority=["IFF-FI"],
|
| 358 |
+
),
|
| 359 |
+
FileExtension(
|
| 360 |
+
name="IPTC/NAA",
|
| 361 |
+
extension=".iim",
|
| 362 |
+
priority=["pillow", "IPTC-PIL"],
|
| 363 |
+
),
|
| 364 |
+
FileExtension(
|
| 365 |
+
extension=".iiq",
|
| 366 |
+
priority=["RAW-FI"],
|
| 367 |
+
),
|
| 368 |
+
FileExtension(
|
| 369 |
+
name="IFUNC Image Memory",
|
| 370 |
+
extension=".im",
|
| 371 |
+
priority=["pillow", "IM-PIL"],
|
| 372 |
+
),
|
| 373 |
+
FileExtension(
|
| 374 |
+
extension=".img",
|
| 375 |
+
priority=["ITK", "GDAL"],
|
| 376 |
+
),
|
| 377 |
+
FileExtension(
|
| 378 |
+
extension=".img.gz",
|
| 379 |
+
priority=["ITK"],
|
| 380 |
+
),
|
| 381 |
+
FileExtension(
|
| 382 |
+
name="IM Tools",
|
| 383 |
+
extension=".IMT",
|
| 384 |
+
priority=["pillow", "IMT-PIL"],
|
| 385 |
+
),
|
| 386 |
+
FileExtension(
|
| 387 |
+
name="Image Processing Lab",
|
| 388 |
+
extension=".ipl",
|
| 389 |
+
priority=["ITK"],
|
| 390 |
+
),
|
| 391 |
+
FileExtension(
|
| 392 |
+
name="JPEG 2000",
|
| 393 |
+
extension=".j2c",
|
| 394 |
+
priority=["pillow", "J2K-FI", "JPEG2000-PIL", "pyav"],
|
| 395 |
+
),
|
| 396 |
+
FileExtension(
|
| 397 |
+
name="JPEG 2000",
|
| 398 |
+
extension=".j2k",
|
| 399 |
+
priority=["pillow", "J2K-FI", "JPEG2000-PIL", "pyav"],
|
| 400 |
+
),
|
| 401 |
+
FileExtension(
|
| 402 |
+
name="JPEG",
|
| 403 |
+
extension=".jfif",
|
| 404 |
+
priority=["pillow", "JPEG-PIL"],
|
| 405 |
+
),
|
| 406 |
+
FileExtension(
|
| 407 |
+
name="JPEG",
|
| 408 |
+
extension=".jif",
|
| 409 |
+
priority=["JPEG-FI"],
|
| 410 |
+
),
|
| 411 |
+
FileExtension(
|
| 412 |
+
name="JPEG Network Graphics",
|
| 413 |
+
extension=".jng",
|
| 414 |
+
priority=["JNG-FI"],
|
| 415 |
+
),
|
| 416 |
+
FileExtension(
|
| 417 |
+
name="JPEG 2000",
|
| 418 |
+
extension=".jp2",
|
| 419 |
+
priority=["pillow", "JP2-FI", "JPEG2000-PIL", "pyav", "opencv"],
|
| 420 |
+
),
|
| 421 |
+
FileExtension(
|
| 422 |
+
name="JPEG 2000",
|
| 423 |
+
extension=".jpc",
|
| 424 |
+
priority=["pillow", "JPEG2000-PIL"],
|
| 425 |
+
),
|
| 426 |
+
FileExtension(
|
| 427 |
+
name="JPEG",
|
| 428 |
+
extension=".jpe",
|
| 429 |
+
priority=["pillow", "JPEG-FI", "JPEG-PIL", "opencv"],
|
| 430 |
+
),
|
| 431 |
+
FileExtension(
|
| 432 |
+
name="Joint Photographic Experts Group",
|
| 433 |
+
extension=".jpeg",
|
| 434 |
+
priority=["pillow", "JPEG-PIL", "JPEG-FI", "ITK", "GDAL", "pyav", "opencv"],
|
| 435 |
+
),
|
| 436 |
+
FileExtension(
|
| 437 |
+
name="JPEG 2000",
|
| 438 |
+
extension=".jpf",
|
| 439 |
+
priority=["pillow", "JPEG2000-PIL"],
|
| 440 |
+
),
|
| 441 |
+
FileExtension(
|
| 442 |
+
name="Joint Photographic Experts Group",
|
| 443 |
+
extension=".jpg",
|
| 444 |
+
priority=["pillow", "JPEG-PIL", "JPEG-FI", "ITK", "GDAL", "pyav", "opencv"],
|
| 445 |
+
),
|
| 446 |
+
FileExtension(
|
| 447 |
+
name="JPEG 2000",
|
| 448 |
+
extension=".jpx",
|
| 449 |
+
priority=["pillow", "JPEG2000-PIL"],
|
| 450 |
+
),
|
| 451 |
+
FileExtension(
|
| 452 |
+
name="JPEG Extended Range",
|
| 453 |
+
extension=".jxr",
|
| 454 |
+
priority=["JPEG-XR-FI"],
|
| 455 |
+
),
|
| 456 |
+
FileExtension(
|
| 457 |
+
extension=".k25",
|
| 458 |
+
priority=["RAW-FI"],
|
| 459 |
+
),
|
| 460 |
+
FileExtension(
|
| 461 |
+
extension=".kc2",
|
| 462 |
+
priority=["RAW-FI"],
|
| 463 |
+
),
|
| 464 |
+
FileExtension(
|
| 465 |
+
extension=".kdc",
|
| 466 |
+
priority=["RAW-FI"],
|
| 467 |
+
),
|
| 468 |
+
FileExtension(
|
| 469 |
+
name="C64 Koala Graphics",
|
| 470 |
+
extension=".koa",
|
| 471 |
+
priority=["KOALA-FI"],
|
| 472 |
+
),
|
| 473 |
+
FileExtension(
|
| 474 |
+
name="ILBM Interleaved Bitmap",
|
| 475 |
+
extension=".lbm",
|
| 476 |
+
priority=["IFF-FI"],
|
| 477 |
+
),
|
| 478 |
+
FileExtension(
|
| 479 |
+
name="Lytro F01",
|
| 480 |
+
extension=".lfp",
|
| 481 |
+
priority=["LYTRO-LFP"],
|
| 482 |
+
),
|
| 483 |
+
FileExtension(
|
| 484 |
+
name="Lytro Illum",
|
| 485 |
+
extension=".lfr",
|
| 486 |
+
priority=["LYTRO-LFR"],
|
| 487 |
+
),
|
| 488 |
+
FileExtension(
|
| 489 |
+
name="ZEISS LSM",
|
| 490 |
+
extension=".lsm",
|
| 491 |
+
priority=["ITK", "TIFF"],
|
| 492 |
+
),
|
| 493 |
+
FileExtension(
|
| 494 |
+
name="McIdas area file",
|
| 495 |
+
extension=".MCIDAS",
|
| 496 |
+
priority=["pillow", "MCIDAS-PIL"],
|
| 497 |
+
external_link="https://www.ssec.wisc.edu/mcidas/doc/prog_man/2003print/progman2003-formats.html",
|
| 498 |
+
),
|
| 499 |
+
FileExtension(
|
| 500 |
+
extension=".mdc",
|
| 501 |
+
priority=["RAW-FI"],
|
| 502 |
+
),
|
| 503 |
+
FileExtension(
|
| 504 |
+
extension=".mef",
|
| 505 |
+
priority=["RAW-FI"],
|
| 506 |
+
),
|
| 507 |
+
FileExtension(
|
| 508 |
+
name="FreeSurfer File Format",
|
| 509 |
+
extension=".mgh",
|
| 510 |
+
priority=["ITK"],
|
| 511 |
+
),
|
| 512 |
+
FileExtension(
|
| 513 |
+
name="ITK MetaImage",
|
| 514 |
+
extension=".mha",
|
| 515 |
+
priority=["ITK"],
|
| 516 |
+
),
|
| 517 |
+
FileExtension(
|
| 518 |
+
name="ITK MetaImage Header",
|
| 519 |
+
extension=".mhd",
|
| 520 |
+
priority=["ITK"],
|
| 521 |
+
),
|
| 522 |
+
FileExtension(
|
| 523 |
+
name="Microsoft Image Composer",
|
| 524 |
+
extension=".mic",
|
| 525 |
+
priority=["pillow", "MIC-PIL"],
|
| 526 |
+
),
|
| 527 |
+
FileExtension(
|
| 528 |
+
name="Matroska Multimedia Container",
|
| 529 |
+
extension=".mkv",
|
| 530 |
+
priority=["FFMPEG", "pyav"],
|
| 531 |
+
),
|
| 532 |
+
FileExtension(
|
| 533 |
+
name="Medical Imaging NetCDF",
|
| 534 |
+
extension=".mnc",
|
| 535 |
+
priority=["ITK"],
|
| 536 |
+
),
|
| 537 |
+
FileExtension(
|
| 538 |
+
name="Medical Imaging NetCDF 2",
|
| 539 |
+
extension=".mnc2",
|
| 540 |
+
priority=["ITK"],
|
| 541 |
+
),
|
| 542 |
+
FileExtension(
|
| 543 |
+
name="Leaf Raw Image Format",
|
| 544 |
+
extension=".mos",
|
| 545 |
+
priority=["RAW-FI"],
|
| 546 |
+
),
|
| 547 |
+
FileExtension(
|
| 548 |
+
name="QuickTime File Format",
|
| 549 |
+
extension=".mov",
|
| 550 |
+
priority=["FFMPEG", "pyav"],
|
| 551 |
+
),
|
| 552 |
+
FileExtension(
|
| 553 |
+
name="MPEG-4 Part 14",
|
| 554 |
+
extension=".mp4",
|
| 555 |
+
priority=["FFMPEG", "pyav"],
|
| 556 |
+
),
|
| 557 |
+
FileExtension(
|
| 558 |
+
name="MPEG-1 Moving Picture Experts Group",
|
| 559 |
+
extension=".mpeg",
|
| 560 |
+
priority=["FFMPEG", "pyav"],
|
| 561 |
+
),
|
| 562 |
+
FileExtension(
|
| 563 |
+
name="Moving Picture Experts Group",
|
| 564 |
+
extension=".mpg",
|
| 565 |
+
priority=["pillow", "FFMPEG", "pyav"],
|
| 566 |
+
),
|
| 567 |
+
FileExtension(
|
| 568 |
+
name="JPEG Multi-Picture Format",
|
| 569 |
+
extension=".mpo",
|
| 570 |
+
priority=["pillow", "MPO-PIL"],
|
| 571 |
+
),
|
| 572 |
+
FileExtension(
|
| 573 |
+
name="Magnetic resonance imaging",
|
| 574 |
+
extension=".mri",
|
| 575 |
+
priority=["DICOM"],
|
| 576 |
+
),
|
| 577 |
+
FileExtension(
|
| 578 |
+
extension=".mrw",
|
| 579 |
+
priority=["RAW-FI"],
|
| 580 |
+
),
|
| 581 |
+
FileExtension(
|
| 582 |
+
name="Windows Paint",
|
| 583 |
+
extension=".msp",
|
| 584 |
+
priority=["pillow", "MSP-PIL"],
|
| 585 |
+
),
|
| 586 |
+
FileExtension(
|
| 587 |
+
extension=".nef",
|
| 588 |
+
priority=["RAW-FI"],
|
| 589 |
+
),
|
| 590 |
+
FileExtension(
|
| 591 |
+
extension=".nhdr",
|
| 592 |
+
priority=["ITK"],
|
| 593 |
+
),
|
| 594 |
+
FileExtension(
|
| 595 |
+
extension=".nia",
|
| 596 |
+
priority=["ITK"],
|
| 597 |
+
),
|
| 598 |
+
FileExtension(
|
| 599 |
+
extension=".nii",
|
| 600 |
+
priority=["ITK"],
|
| 601 |
+
),
|
| 602 |
+
FileExtension(
|
| 603 |
+
name="nii.gz",
|
| 604 |
+
extension=".nii.gz",
|
| 605 |
+
priority=["ITK"],
|
| 606 |
+
),
|
| 607 |
+
FileExtension(
|
| 608 |
+
name="Numpy Array",
|
| 609 |
+
extension=".npz",
|
| 610 |
+
priority=["NPZ"],
|
| 611 |
+
),
|
| 612 |
+
FileExtension(
|
| 613 |
+
extension=".nrrd",
|
| 614 |
+
priority=["ITK"],
|
| 615 |
+
),
|
| 616 |
+
FileExtension(
|
| 617 |
+
extension=".nrw",
|
| 618 |
+
priority=["RAW-FI"],
|
| 619 |
+
),
|
| 620 |
+
FileExtension(
|
| 621 |
+
extension=".orf",
|
| 622 |
+
priority=["RAW-FI"],
|
| 623 |
+
),
|
| 624 |
+
FileExtension(
|
| 625 |
+
extension=".palm",
|
| 626 |
+
priority=["pillow"],
|
| 627 |
+
),
|
| 628 |
+
FileExtension(
|
| 629 |
+
name="Portable Bitmap",
|
| 630 |
+
extension=".pbm",
|
| 631 |
+
priority=["PGM-FI", "PGMRAW-FI", "pyav", "opencv"],
|
| 632 |
+
),
|
| 633 |
+
FileExtension(
|
| 634 |
+
name="Kodak PhotoCD",
|
| 635 |
+
extension=".pcd",
|
| 636 |
+
priority=["pillow", "PCD-FI", "PCD-PIL"],
|
| 637 |
+
),
|
| 638 |
+
FileExtension(
|
| 639 |
+
name="Macintosh PICT",
|
| 640 |
+
extension=".pct",
|
| 641 |
+
priority=["PICT-FI"],
|
| 642 |
+
),
|
| 643 |
+
FileExtension(
|
| 644 |
+
name="Zsoft Paintbrush",
|
| 645 |
+
extension=".PCX",
|
| 646 |
+
priority=["pillow", "PCX-FI", "PCX-PIL"],
|
| 647 |
+
),
|
| 648 |
+
FileExtension(
|
| 649 |
+
extension=".pdf",
|
| 650 |
+
priority=["pillow"],
|
| 651 |
+
),
|
| 652 |
+
FileExtension(
|
| 653 |
+
extension=".pef",
|
| 654 |
+
priority=["RAW-FI"],
|
| 655 |
+
),
|
| 656 |
+
FileExtension(
|
| 657 |
+
extension=".pfm",
|
| 658 |
+
priority=["PFM-FI", "pyav", "opencv"],
|
| 659 |
+
),
|
| 660 |
+
FileExtension(
|
| 661 |
+
name="Portable Greymap",
|
| 662 |
+
extension=".pgm",
|
| 663 |
+
priority=["pillow", "PGM-FI", "PGMRAW-FI", "pyav", "opencv"],
|
| 664 |
+
),
|
| 665 |
+
FileExtension(
|
| 666 |
+
name="Macintosh PICT",
|
| 667 |
+
extension=".pic",
|
| 668 |
+
priority=["PICT-FI", "ITK", "opencv"],
|
| 669 |
+
),
|
| 670 |
+
FileExtension(
|
| 671 |
+
name="Macintosh PICT",
|
| 672 |
+
extension=".pict",
|
| 673 |
+
priority=["PICT-FI"],
|
| 674 |
+
),
|
| 675 |
+
FileExtension(
|
| 676 |
+
name="Portable Network Graphics",
|
| 677 |
+
extension=".png",
|
| 678 |
+
priority=["pillow", "PNG-PIL", "PNG-FI", "ITK", "pyav", "opencv"],
|
| 679 |
+
),
|
| 680 |
+
FileExtension(
|
| 681 |
+
name="Portable Image Format",
|
| 682 |
+
extension=".pnm",
|
| 683 |
+
priority=["pillow", "opencv"],
|
| 684 |
+
),
|
| 685 |
+
FileExtension(
|
| 686 |
+
name="Pbmplus image",
|
| 687 |
+
extension=".ppm",
|
| 688 |
+
priority=["pillow", "PPM-PIL", "pyav"],
|
| 689 |
+
),
|
| 690 |
+
FileExtension(
|
| 691 |
+
name="Pbmplus image",
|
| 692 |
+
extension=".pbm",
|
| 693 |
+
priority=["pillow", "PPM-PIL", "PPM-FI"],
|
| 694 |
+
),
|
| 695 |
+
FileExtension(
|
| 696 |
+
name="Portable image format",
|
| 697 |
+
extension=".pxm",
|
| 698 |
+
priority=["opencv"],
|
| 699 |
+
),
|
| 700 |
+
FileExtension(
|
| 701 |
+
name="Portable Pixelmap (ASCII)",
|
| 702 |
+
extension=".ppm",
|
| 703 |
+
priority=["PPM-FI", "opencv"],
|
| 704 |
+
),
|
| 705 |
+
FileExtension(
|
| 706 |
+
name="Portable Pixelmap (Raw)",
|
| 707 |
+
extension=".ppm",
|
| 708 |
+
priority=["PPMRAW-FI"],
|
| 709 |
+
),
|
| 710 |
+
FileExtension(
|
| 711 |
+
name="Ghostscript",
|
| 712 |
+
extension=".ps",
|
| 713 |
+
priority=["pillow", "EPS-PIL"],
|
| 714 |
+
),
|
| 715 |
+
FileExtension(
|
| 716 |
+
name="Adope Photoshop 2.5 and 3.0",
|
| 717 |
+
extension=".psd",
|
| 718 |
+
priority=["pillow", "PSD-PIL", "PSD-FI"],
|
| 719 |
+
),
|
| 720 |
+
FileExtension(
|
| 721 |
+
extension=".ptx",
|
| 722 |
+
priority=["RAW-FI"],
|
| 723 |
+
),
|
| 724 |
+
FileExtension(
|
| 725 |
+
extension=".pxn",
|
| 726 |
+
priority=["RAW-FI"],
|
| 727 |
+
),
|
| 728 |
+
FileExtension(
|
| 729 |
+
name="PIXAR raster image",
|
| 730 |
+
extension=".pxr",
|
| 731 |
+
priority=["pillow", "PIXAR-PIL"],
|
| 732 |
+
),
|
| 733 |
+
FileExtension(
|
| 734 |
+
extension=".qtk",
|
| 735 |
+
priority=["RAW-FI"],
|
| 736 |
+
),
|
| 737 |
+
FileExtension(
|
| 738 |
+
extension=".raf",
|
| 739 |
+
priority=["RAW-FI"],
|
| 740 |
+
),
|
| 741 |
+
FileExtension(
|
| 742 |
+
name="Sun Raster File",
|
| 743 |
+
extension=".ras",
|
| 744 |
+
priority=["pillow", "SUN-PIL", "RAS-FI", "pyav", "opencv"],
|
| 745 |
+
),
|
| 746 |
+
FileExtension(
|
| 747 |
+
name="Sun Raster File",
|
| 748 |
+
extension=".sr",
|
| 749 |
+
priority=["opencv"],
|
| 750 |
+
),
|
| 751 |
+
FileExtension(
|
| 752 |
+
extension=".raw",
|
| 753 |
+
priority=["RAW-FI", "LYTRO-ILLUM-RAW", "LYTRO-F01-RAW"],
|
| 754 |
+
),
|
| 755 |
+
FileExtension(
|
| 756 |
+
extension=".rdc",
|
| 757 |
+
priority=["RAW-FI"],
|
| 758 |
+
),
|
| 759 |
+
FileExtension(
|
| 760 |
+
name="Silicon Graphics Image",
|
| 761 |
+
extension=".rgb",
|
| 762 |
+
priority=["pillow", "SGI-PIL"],
|
| 763 |
+
),
|
| 764 |
+
FileExtension(
|
| 765 |
+
name="Silicon Graphics Image",
|
| 766 |
+
extension=".rgba",
|
| 767 |
+
priority=["pillow", "SGI-PIL"],
|
| 768 |
+
),
|
| 769 |
+
FileExtension(
|
| 770 |
+
extension=".rw2",
|
| 771 |
+
priority=["RAW-FI"],
|
| 772 |
+
),
|
| 773 |
+
FileExtension(
|
| 774 |
+
extension=".rwl",
|
| 775 |
+
priority=["RAW-FI"],
|
| 776 |
+
),
|
| 777 |
+
FileExtension(
|
| 778 |
+
extension=".rwz",
|
| 779 |
+
priority=["RAW-FI"],
|
| 780 |
+
),
|
| 781 |
+
FileExtension(
|
| 782 |
+
name="Silicon Graphics Image",
|
| 783 |
+
extension=".sgi",
|
| 784 |
+
priority=["pillow", "SGI-PIL", "pyav"],
|
| 785 |
+
),
|
| 786 |
+
FileExtension(
|
| 787 |
+
name="SPE File Format",
|
| 788 |
+
extension=".spe",
|
| 789 |
+
priority=["SPE"],
|
| 790 |
+
),
|
| 791 |
+
FileExtension(
|
| 792 |
+
extension=".SPIDER",
|
| 793 |
+
priority=["pillow", "SPIDER-PIL"],
|
| 794 |
+
),
|
| 795 |
+
FileExtension(
|
| 796 |
+
extension=".sr2",
|
| 797 |
+
priority=["RAW-FI"],
|
| 798 |
+
),
|
| 799 |
+
FileExtension(
|
| 800 |
+
extension=".srf",
|
| 801 |
+
priority=["RAW-FI"],
|
| 802 |
+
),
|
| 803 |
+
FileExtension(
|
| 804 |
+
extension=".srw",
|
| 805 |
+
priority=["RAW-FI"],
|
| 806 |
+
),
|
| 807 |
+
FileExtension(
|
| 808 |
+
extension=".sti",
|
| 809 |
+
priority=["RAW-FI"],
|
| 810 |
+
),
|
| 811 |
+
FileExtension(
|
| 812 |
+
extension=".stk",
|
| 813 |
+
priority=["TIFF"],
|
| 814 |
+
),
|
| 815 |
+
FileExtension(
|
| 816 |
+
name="ShockWave Flash",
|
| 817 |
+
extension=".swf",
|
| 818 |
+
priority=["SWF", "pyav"],
|
| 819 |
+
),
|
| 820 |
+
FileExtension(
|
| 821 |
+
name="Truevision TGA",
|
| 822 |
+
extension=".targa",
|
| 823 |
+
priority=["pillow", "TARGA-FI"],
|
| 824 |
+
),
|
| 825 |
+
FileExtension(
|
| 826 |
+
name="Truevision TGA",
|
| 827 |
+
extension=".tga",
|
| 828 |
+
priority=["pillow", "TGA-PIL", "TARGA-FI", "pyav"],
|
| 829 |
+
),
|
| 830 |
+
FileExtension(
|
| 831 |
+
name="Tagged Image File",
|
| 832 |
+
extension=".tif",
|
| 833 |
+
priority=[
|
| 834 |
+
"TIFF",
|
| 835 |
+
"pillow",
|
| 836 |
+
"TIFF-PIL",
|
| 837 |
+
"TIFF-FI",
|
| 838 |
+
"FEI",
|
| 839 |
+
"ITK",
|
| 840 |
+
"GDAL",
|
| 841 |
+
"pyav",
|
| 842 |
+
"opencv",
|
| 843 |
+
],
|
| 844 |
+
),
|
| 845 |
+
FileExtension(
|
| 846 |
+
name="Tagged Image File Format",
|
| 847 |
+
extension=".tiff",
|
| 848 |
+
priority=[
|
| 849 |
+
"TIFF",
|
| 850 |
+
"pillow",
|
| 851 |
+
"TIFF-PIL",
|
| 852 |
+
"TIFF-FI",
|
| 853 |
+
"FEI",
|
| 854 |
+
"ITK",
|
| 855 |
+
"GDAL",
|
| 856 |
+
"pyav",
|
| 857 |
+
"opencv",
|
| 858 |
+
],
|
| 859 |
+
),
|
| 860 |
+
FileExtension(
|
| 861 |
+
extension=".vda",
|
| 862 |
+
priority=["pillow"],
|
| 863 |
+
),
|
| 864 |
+
FileExtension(
|
| 865 |
+
extension=".vst",
|
| 866 |
+
priority=["pillow"],
|
| 867 |
+
),
|
| 868 |
+
FileExtension(
|
| 869 |
+
extension=".vtk",
|
| 870 |
+
priority=["ITK"],
|
| 871 |
+
),
|
| 872 |
+
FileExtension(
|
| 873 |
+
name="Wireless Bitmap",
|
| 874 |
+
extension=".wap",
|
| 875 |
+
priority=["WBMP-FI"],
|
| 876 |
+
),
|
| 877 |
+
FileExtension(
|
| 878 |
+
name="Wireless Bitmap",
|
| 879 |
+
extension=".wbm",
|
| 880 |
+
priority=["WBMP-FI"],
|
| 881 |
+
),
|
| 882 |
+
FileExtension(
|
| 883 |
+
name="Wireless Bitmap",
|
| 884 |
+
extension=".wbmp",
|
| 885 |
+
priority=["WBMP-FI"],
|
| 886 |
+
),
|
| 887 |
+
FileExtension(
|
| 888 |
+
name="JPEG Extended Range",
|
| 889 |
+
extension=".wdp",
|
| 890 |
+
priority=["JPEG-XR-FI"],
|
| 891 |
+
),
|
| 892 |
+
FileExtension(
|
| 893 |
+
name="Matroska",
|
| 894 |
+
extension=".webm",
|
| 895 |
+
priority=["FFMPEG", "pyav"],
|
| 896 |
+
),
|
| 897 |
+
FileExtension(
|
| 898 |
+
name="Google WebP",
|
| 899 |
+
extension=".webp",
|
| 900 |
+
priority=["pillow", "WEBP-FI", "pyav", "opencv"],
|
| 901 |
+
),
|
| 902 |
+
FileExtension(
|
| 903 |
+
name="Windows Meta File",
|
| 904 |
+
extension=".wmf",
|
| 905 |
+
priority=["pillow", "WMF-PIL"],
|
| 906 |
+
),
|
| 907 |
+
FileExtension(
|
| 908 |
+
name="Windows Media Video",
|
| 909 |
+
extension=".wmv",
|
| 910 |
+
priority=["FFMPEG"],
|
| 911 |
+
),
|
| 912 |
+
FileExtension(
|
| 913 |
+
name="X11 Bitmap",
|
| 914 |
+
extension=".xbm",
|
| 915 |
+
priority=["pillow", "XBM-PIL", "XBM-FI", "pyav"],
|
| 916 |
+
),
|
| 917 |
+
FileExtension(
|
| 918 |
+
name="X11 Pixel Map",
|
| 919 |
+
extension=".xpm",
|
| 920 |
+
priority=["pillow", "XPM-PIL", "XPM-FI"],
|
| 921 |
+
),
|
| 922 |
+
FileExtension(
|
| 923 |
+
name="Thumbnail Image",
|
| 924 |
+
extension=".XVTHUMB",
|
| 925 |
+
priority=["pillow", "XVTHUMB-PIL"],
|
| 926 |
+
),
|
| 927 |
+
FileExtension(
|
| 928 |
+
extension=".dpx",
|
| 929 |
+
priority=["pyav"],
|
| 930 |
+
),
|
| 931 |
+
FileExtension(
|
| 932 |
+
extension=".im1",
|
| 933 |
+
priority=["pyav"],
|
| 934 |
+
),
|
| 935 |
+
FileExtension(
|
| 936 |
+
extension=".im24",
|
| 937 |
+
priority=["pyav"],
|
| 938 |
+
),
|
| 939 |
+
FileExtension(
|
| 940 |
+
extension=".im8",
|
| 941 |
+
priority=["pyav"],
|
| 942 |
+
),
|
| 943 |
+
FileExtension(
|
| 944 |
+
extension=".jls",
|
| 945 |
+
priority=["pyav"],
|
| 946 |
+
),
|
| 947 |
+
FileExtension(
|
| 948 |
+
extension=".ljpg",
|
| 949 |
+
priority=["pyav"],
|
| 950 |
+
),
|
| 951 |
+
FileExtension(
|
| 952 |
+
extension=".pam",
|
| 953 |
+
priority=["pyav"],
|
| 954 |
+
),
|
| 955 |
+
FileExtension(
|
| 956 |
+
extension=".pcx",
|
| 957 |
+
priority=["pyav"],
|
| 958 |
+
),
|
| 959 |
+
FileExtension(
|
| 960 |
+
extension=".pgmyuv",
|
| 961 |
+
priority=["pyav"],
|
| 962 |
+
),
|
| 963 |
+
FileExtension(
|
| 964 |
+
extension=".pix",
|
| 965 |
+
priority=["pyav"],
|
| 966 |
+
),
|
| 967 |
+
FileExtension(
|
| 968 |
+
extension=".ppm",
|
| 969 |
+
priority=["pyav"],
|
| 970 |
+
),
|
| 971 |
+
FileExtension(
|
| 972 |
+
extension=".rs",
|
| 973 |
+
priority=["pyav"],
|
| 974 |
+
),
|
| 975 |
+
FileExtension(
|
| 976 |
+
extension=".sun",
|
| 977 |
+
priority=["pyav"],
|
| 978 |
+
),
|
| 979 |
+
FileExtension(
|
| 980 |
+
extension=".sunras",
|
| 981 |
+
priority=["pyav"],
|
| 982 |
+
),
|
| 983 |
+
FileExtension(
|
| 984 |
+
extension=".xface",
|
| 985 |
+
priority=["pyav"],
|
| 986 |
+
),
|
| 987 |
+
FileExtension(
|
| 988 |
+
extension=".xwd",
|
| 989 |
+
priority=["pyav"],
|
| 990 |
+
),
|
| 991 |
+
FileExtension(
|
| 992 |
+
extension=".y",
|
| 993 |
+
priority=["pyav"],
|
| 994 |
+
),
|
| 995 |
+
FileExtension(
|
| 996 |
+
name="3GP (3GPP file format)",
|
| 997 |
+
extension=".3g2",
|
| 998 |
+
priority=["pyav"],
|
| 999 |
+
),
|
| 1000 |
+
FileExtension(
|
| 1001 |
+
name="3GP (3GPP file format)",
|
| 1002 |
+
extension=".3gp",
|
| 1003 |
+
priority=["pyav"],
|
| 1004 |
+
),
|
| 1005 |
+
FileExtension(
|
| 1006 |
+
name="3GP (3GPP file format)",
|
| 1007 |
+
extension=".f4v",
|
| 1008 |
+
priority=["pyav"],
|
| 1009 |
+
),
|
| 1010 |
+
FileExtension(
|
| 1011 |
+
name="3GP (3GPP file format)",
|
| 1012 |
+
extension=".ism",
|
| 1013 |
+
priority=["pyav"],
|
| 1014 |
+
),
|
| 1015 |
+
FileExtension(
|
| 1016 |
+
name="3GP (3GPP file format)",
|
| 1017 |
+
extension=".isma",
|
| 1018 |
+
priority=["pyav"],
|
| 1019 |
+
),
|
| 1020 |
+
FileExtension(
|
| 1021 |
+
name="3GP (3GPP file format)",
|
| 1022 |
+
extension=".ismv",
|
| 1023 |
+
priority=["pyav"],
|
| 1024 |
+
),
|
| 1025 |
+
FileExtension(
|
| 1026 |
+
name="3GP (3GPP file format)",
|
| 1027 |
+
extension=".m4a",
|
| 1028 |
+
priority=["pyav"],
|
| 1029 |
+
),
|
| 1030 |
+
FileExtension(
|
| 1031 |
+
name="3GP (3GPP file format)",
|
| 1032 |
+
extension=".m4b",
|
| 1033 |
+
priority=["pyav"],
|
| 1034 |
+
),
|
| 1035 |
+
FileExtension(
|
| 1036 |
+
name="3GP (3GPP file format)",
|
| 1037 |
+
extension=".mj2",
|
| 1038 |
+
priority=["pyav"],
|
| 1039 |
+
),
|
| 1040 |
+
FileExtension(
|
| 1041 |
+
name="3GP (3GPP file format)",
|
| 1042 |
+
extension=".psp",
|
| 1043 |
+
priority=["pyav"],
|
| 1044 |
+
),
|
| 1045 |
+
FileExtension(
|
| 1046 |
+
name="3GP2 (3GPP2 file format)",
|
| 1047 |
+
extension=".3g2",
|
| 1048 |
+
priority=["pyav"],
|
| 1049 |
+
),
|
| 1050 |
+
FileExtension(
|
| 1051 |
+
name="3GP2 (3GPP2 file format)",
|
| 1052 |
+
extension=".3gp",
|
| 1053 |
+
priority=["pyav"],
|
| 1054 |
+
),
|
| 1055 |
+
FileExtension(
|
| 1056 |
+
name="3GP2 (3GPP2 file format)",
|
| 1057 |
+
extension=".f4v",
|
| 1058 |
+
priority=["pyav"],
|
| 1059 |
+
),
|
| 1060 |
+
FileExtension(
|
| 1061 |
+
name="3GP2 (3GPP2 file format)",
|
| 1062 |
+
extension=".ism",
|
| 1063 |
+
priority=["pyav"],
|
| 1064 |
+
),
|
| 1065 |
+
FileExtension(
|
| 1066 |
+
name="3GP2 (3GPP2 file format)",
|
| 1067 |
+
extension=".isma",
|
| 1068 |
+
priority=["pyav"],
|
| 1069 |
+
),
|
| 1070 |
+
FileExtension(
|
| 1071 |
+
name="3GP2 (3GPP2 file format)",
|
| 1072 |
+
extension=".ismv",
|
| 1073 |
+
priority=["pyav"],
|
| 1074 |
+
),
|
| 1075 |
+
FileExtension(
|
| 1076 |
+
name="3GP2 (3GPP2 file format)",
|
| 1077 |
+
extension=".m4a",
|
| 1078 |
+
priority=["pyav"],
|
| 1079 |
+
),
|
| 1080 |
+
FileExtension(
|
| 1081 |
+
name="3GP2 (3GPP2 file format)",
|
| 1082 |
+
extension=".m4b",
|
| 1083 |
+
priority=["pyav"],
|
| 1084 |
+
),
|
| 1085 |
+
FileExtension(
|
| 1086 |
+
name="3GP2 (3GPP2 file format)",
|
| 1087 |
+
extension=".mj2",
|
| 1088 |
+
priority=["pyav"],
|
| 1089 |
+
),
|
| 1090 |
+
FileExtension(
|
| 1091 |
+
name="3GP2 (3GPP2 file format)",
|
| 1092 |
+
extension=".psp",
|
| 1093 |
+
priority=["pyav"],
|
| 1094 |
+
),
|
| 1095 |
+
FileExtension(
|
| 1096 |
+
name="3GPP AMR",
|
| 1097 |
+
extension=".amr",
|
| 1098 |
+
priority=["pyav"],
|
| 1099 |
+
),
|
| 1100 |
+
FileExtension(
|
| 1101 |
+
name="a64 - video for Commodore 64",
|
| 1102 |
+
extension=".A64",
|
| 1103 |
+
priority=["pyav"],
|
| 1104 |
+
),
|
| 1105 |
+
FileExtension(
|
| 1106 |
+
name="a64 - video for Commodore 64",
|
| 1107 |
+
extension=".a64",
|
| 1108 |
+
priority=["pyav"],
|
| 1109 |
+
),
|
| 1110 |
+
FileExtension(
|
| 1111 |
+
name="Adobe Filmstrip",
|
| 1112 |
+
extension=".flm",
|
| 1113 |
+
priority=["pyav"],
|
| 1114 |
+
),
|
| 1115 |
+
FileExtension(
|
| 1116 |
+
name="AMV",
|
| 1117 |
+
extension=".amv",
|
| 1118 |
+
priority=["pyav"],
|
| 1119 |
+
),
|
| 1120 |
+
FileExtension(
|
| 1121 |
+
name="ASF (Advanced / Active Streaming Format)",
|
| 1122 |
+
extension=".asf",
|
| 1123 |
+
priority=["pyav"],
|
| 1124 |
+
),
|
| 1125 |
+
FileExtension(
|
| 1126 |
+
name="ASF (Advanced / Active Streaming Format)",
|
| 1127 |
+
extension=".asf",
|
| 1128 |
+
priority=["pyav"],
|
| 1129 |
+
),
|
| 1130 |
+
FileExtension(
|
| 1131 |
+
name="ASF (Advanced / Active Streaming Format)",
|
| 1132 |
+
extension=".wmv",
|
| 1133 |
+
priority=["pyav"],
|
| 1134 |
+
),
|
| 1135 |
+
FileExtension(
|
| 1136 |
+
name="ASF (Advanced / Active Streaming Format)",
|
| 1137 |
+
extension=".wmv",
|
| 1138 |
+
priority=["pyav"],
|
| 1139 |
+
),
|
| 1140 |
+
FileExtension(
|
| 1141 |
+
name="AV1 Annex B",
|
| 1142 |
+
extension=".obu",
|
| 1143 |
+
priority=["pyav"],
|
| 1144 |
+
),
|
| 1145 |
+
FileExtension(
|
| 1146 |
+
name="AV1 low overhead OBU",
|
| 1147 |
+
extension=".obu",
|
| 1148 |
+
priority=["pyav"],
|
| 1149 |
+
),
|
| 1150 |
+
FileExtension(
|
| 1151 |
+
name="AVI (Audio Video Interleaved)",
|
| 1152 |
+
extension=".avi",
|
| 1153 |
+
priority=["pyav"],
|
| 1154 |
+
),
|
| 1155 |
+
FileExtension(
|
| 1156 |
+
name="AVR (Audio Visual Research)",
|
| 1157 |
+
extension=".avr",
|
| 1158 |
+
priority=["pyav"],
|
| 1159 |
+
),
|
| 1160 |
+
FileExtension(
|
| 1161 |
+
name="Beam Software SIFF",
|
| 1162 |
+
extension=".vb",
|
| 1163 |
+
priority=["pyav"],
|
| 1164 |
+
),
|
| 1165 |
+
FileExtension(
|
| 1166 |
+
name="CD Graphics",
|
| 1167 |
+
extension=".cdg",
|
| 1168 |
+
priority=["pyav"],
|
| 1169 |
+
),
|
| 1170 |
+
FileExtension(
|
| 1171 |
+
name="Commodore CDXL video",
|
| 1172 |
+
extension=".cdxl",
|
| 1173 |
+
priority=["pyav"],
|
| 1174 |
+
),
|
| 1175 |
+
FileExtension(
|
| 1176 |
+
name="Commodore CDXL video",
|
| 1177 |
+
extension=".xl",
|
| 1178 |
+
priority=["pyav"],
|
| 1179 |
+
),
|
| 1180 |
+
FileExtension(
|
| 1181 |
+
name="DASH Muxer",
|
| 1182 |
+
extension=".mpd",
|
| 1183 |
+
priority=["pyav"],
|
| 1184 |
+
),
|
| 1185 |
+
FileExtension(
|
| 1186 |
+
name="Digital Pictures SGA",
|
| 1187 |
+
extension=".sga",
|
| 1188 |
+
priority=["pyav"],
|
| 1189 |
+
),
|
| 1190 |
+
FileExtension(
|
| 1191 |
+
name="Discworld II BMV",
|
| 1192 |
+
extension=".bmv",
|
| 1193 |
+
priority=["pyav"],
|
| 1194 |
+
),
|
| 1195 |
+
FileExtension(
|
| 1196 |
+
name="DV (Digital Video)",
|
| 1197 |
+
extension=".dif",
|
| 1198 |
+
priority=["pyav"],
|
| 1199 |
+
),
|
| 1200 |
+
FileExtension(
|
| 1201 |
+
name="DV (Digital Video)",
|
| 1202 |
+
extension=".dv",
|
| 1203 |
+
priority=["pyav"],
|
| 1204 |
+
),
|
| 1205 |
+
FileExtension(
|
| 1206 |
+
name="F4V Adobe Flash Video",
|
| 1207 |
+
extension=".f4v",
|
| 1208 |
+
priority=["pyav"],
|
| 1209 |
+
),
|
| 1210 |
+
FileExtension(
|
| 1211 |
+
name="FLV (Flash Video)",
|
| 1212 |
+
extension=".flv",
|
| 1213 |
+
priority=["pyav"],
|
| 1214 |
+
),
|
| 1215 |
+
FileExtension(
|
| 1216 |
+
name="GXF (General eXchange Format)",
|
| 1217 |
+
extension=".gxf",
|
| 1218 |
+
priority=["pyav"],
|
| 1219 |
+
),
|
| 1220 |
+
FileExtension(
|
| 1221 |
+
name="iCE Draw File",
|
| 1222 |
+
extension=".idf",
|
| 1223 |
+
priority=["pyav"],
|
| 1224 |
+
),
|
| 1225 |
+
FileExtension(
|
| 1226 |
+
name="IFV CCTV DVR",
|
| 1227 |
+
extension=".ifv",
|
| 1228 |
+
priority=["pyav"],
|
| 1229 |
+
),
|
| 1230 |
+
FileExtension(
|
| 1231 |
+
name="iPod H.264 MP4 (MPEG-4 Part 14)",
|
| 1232 |
+
extension=".m4a",
|
| 1233 |
+
priority=["pyav"],
|
| 1234 |
+
),
|
| 1235 |
+
FileExtension(
|
| 1236 |
+
name="iPod H.264 MP4 (MPEG-4 Part 14)",
|
| 1237 |
+
extension=".m4b",
|
| 1238 |
+
priority=["pyav"],
|
| 1239 |
+
),
|
| 1240 |
+
FileExtension(
|
| 1241 |
+
name="iPod H.264 MP4 (MPEG-4 Part 14)",
|
| 1242 |
+
extension=".m4v",
|
| 1243 |
+
priority=["pyav"],
|
| 1244 |
+
),
|
| 1245 |
+
FileExtension(
|
| 1246 |
+
name="IVR (Internet Video Recording)",
|
| 1247 |
+
extension=".ivr",
|
| 1248 |
+
priority=["pyav"],
|
| 1249 |
+
),
|
| 1250 |
+
FileExtension(
|
| 1251 |
+
name="Konami PS2 SVAG",
|
| 1252 |
+
extension=".svag",
|
| 1253 |
+
priority=["pyav"],
|
| 1254 |
+
),
|
| 1255 |
+
FileExtension(
|
| 1256 |
+
name="KUX (YouKu)",
|
| 1257 |
+
extension=".kux",
|
| 1258 |
+
priority=["pyav"],
|
| 1259 |
+
),
|
| 1260 |
+
FileExtension(
|
| 1261 |
+
name="live RTMP FLV (Flash Video)",
|
| 1262 |
+
extension=".flv",
|
| 1263 |
+
priority=["pyav"],
|
| 1264 |
+
),
|
| 1265 |
+
FileExtension(
|
| 1266 |
+
name="Loki SDL MJPEG",
|
| 1267 |
+
extension=".mjpg",
|
| 1268 |
+
priority=["pyav"],
|
| 1269 |
+
),
|
| 1270 |
+
FileExtension(
|
| 1271 |
+
name="LVF",
|
| 1272 |
+
extension=".lvf",
|
| 1273 |
+
priority=["pyav"],
|
| 1274 |
+
),
|
| 1275 |
+
FileExtension(
|
| 1276 |
+
name="Matroska / WebM",
|
| 1277 |
+
extension=".mk3d",
|
| 1278 |
+
priority=["pyav"],
|
| 1279 |
+
),
|
| 1280 |
+
FileExtension(
|
| 1281 |
+
name="Matroska / WebM",
|
| 1282 |
+
extension=".mka",
|
| 1283 |
+
priority=["pyav"],
|
| 1284 |
+
),
|
| 1285 |
+
FileExtension(
|
| 1286 |
+
name="Matroska / WebM",
|
| 1287 |
+
extension=".mks",
|
| 1288 |
+
priority=["pyav"],
|
| 1289 |
+
),
|
| 1290 |
+
FileExtension(
|
| 1291 |
+
name="Microsoft XMV",
|
| 1292 |
+
extension=".xmv",
|
| 1293 |
+
priority=["pyav"],
|
| 1294 |
+
),
|
| 1295 |
+
FileExtension(
|
| 1296 |
+
name="MIME multipart JPEG",
|
| 1297 |
+
extension=".mjpg",
|
| 1298 |
+
priority=["pyav"],
|
| 1299 |
+
),
|
| 1300 |
+
FileExtension(
|
| 1301 |
+
name="MobiClip MODS",
|
| 1302 |
+
extension=".mods",
|
| 1303 |
+
priority=["pyav"],
|
| 1304 |
+
),
|
| 1305 |
+
FileExtension(
|
| 1306 |
+
name="MobiClip MOFLEX",
|
| 1307 |
+
extension=".moflex",
|
| 1308 |
+
priority=["pyav"],
|
| 1309 |
+
),
|
| 1310 |
+
FileExtension(
|
| 1311 |
+
name="Motion Pixels MVI",
|
| 1312 |
+
extension=".mvi",
|
| 1313 |
+
priority=["pyav"],
|
| 1314 |
+
),
|
| 1315 |
+
FileExtension(
|
| 1316 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1317 |
+
extension=".3g2",
|
| 1318 |
+
priority=["pyav"],
|
| 1319 |
+
),
|
| 1320 |
+
FileExtension(
|
| 1321 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1322 |
+
extension=".3gp",
|
| 1323 |
+
priority=["pyav"],
|
| 1324 |
+
),
|
| 1325 |
+
FileExtension(
|
| 1326 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1327 |
+
extension=".f4v",
|
| 1328 |
+
priority=["pyav"],
|
| 1329 |
+
),
|
| 1330 |
+
FileExtension(
|
| 1331 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1332 |
+
extension=".ism",
|
| 1333 |
+
priority=["pyav"],
|
| 1334 |
+
),
|
| 1335 |
+
FileExtension(
|
| 1336 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1337 |
+
extension=".isma",
|
| 1338 |
+
priority=["pyav"],
|
| 1339 |
+
),
|
| 1340 |
+
FileExtension(
|
| 1341 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1342 |
+
extension=".ismv",
|
| 1343 |
+
priority=["pyav"],
|
| 1344 |
+
),
|
| 1345 |
+
FileExtension(
|
| 1346 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1347 |
+
extension=".m4a",
|
| 1348 |
+
priority=["pyav"],
|
| 1349 |
+
),
|
| 1350 |
+
FileExtension(
|
| 1351 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1352 |
+
extension=".m4b",
|
| 1353 |
+
priority=["pyav"],
|
| 1354 |
+
),
|
| 1355 |
+
FileExtension(
|
| 1356 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1357 |
+
extension=".mj2",
|
| 1358 |
+
priority=["pyav"],
|
| 1359 |
+
),
|
| 1360 |
+
FileExtension(
|
| 1361 |
+
name="MP4 (MPEG-4 Part 14)",
|
| 1362 |
+
extension=".psp",
|
| 1363 |
+
priority=["pyav"],
|
| 1364 |
+
),
|
| 1365 |
+
FileExtension(
|
| 1366 |
+
name="MPEG-2 PS (DVD VOB)",
|
| 1367 |
+
extension=".dvd",
|
| 1368 |
+
priority=["pyav"],
|
| 1369 |
+
),
|
| 1370 |
+
FileExtension(
|
| 1371 |
+
name="MPEG-2 PS (SVCD)",
|
| 1372 |
+
extension=".vob",
|
| 1373 |
+
priority=["pyav"],
|
| 1374 |
+
),
|
| 1375 |
+
FileExtension(
|
| 1376 |
+
name="MPEG-2 PS (VOB)",
|
| 1377 |
+
extension=".vob",
|
| 1378 |
+
priority=["pyav"],
|
| 1379 |
+
),
|
| 1380 |
+
FileExtension(
|
| 1381 |
+
name="MPEG-TS (MPEG-2 Transport Stream)",
|
| 1382 |
+
extension=".m2t",
|
| 1383 |
+
priority=["pyav"],
|
| 1384 |
+
),
|
| 1385 |
+
FileExtension(
|
| 1386 |
+
name="MPEG-TS (MPEG-2 Transport Stream)",
|
| 1387 |
+
extension=".m2ts",
|
| 1388 |
+
priority=["pyav"],
|
| 1389 |
+
),
|
| 1390 |
+
FileExtension(
|
| 1391 |
+
name="MPEG-TS (MPEG-2 Transport Stream)",
|
| 1392 |
+
extension=".mts",
|
| 1393 |
+
priority=["pyav"],
|
| 1394 |
+
),
|
| 1395 |
+
FileExtension(
|
| 1396 |
+
name="MPEG-TS (MPEG-2 Transport Stream)",
|
| 1397 |
+
extension=".ts",
|
| 1398 |
+
priority=["pyav"],
|
| 1399 |
+
),
|
| 1400 |
+
FileExtension(
|
| 1401 |
+
name="Musepack",
|
| 1402 |
+
extension=".mpc",
|
| 1403 |
+
priority=["pyav"],
|
| 1404 |
+
),
|
| 1405 |
+
FileExtension(
|
| 1406 |
+
name="MXF (Material eXchange Format) Operational Pattern Atom",
|
| 1407 |
+
extension=".mxf",
|
| 1408 |
+
priority=["pyav"],
|
| 1409 |
+
),
|
| 1410 |
+
FileExtension(
|
| 1411 |
+
name="MXF (Material eXchange Format)",
|
| 1412 |
+
extension=".mxf",
|
| 1413 |
+
priority=["pyav"],
|
| 1414 |
+
),
|
| 1415 |
+
FileExtension(
|
| 1416 |
+
name="MxPEG clip",
|
| 1417 |
+
extension=".mxg",
|
| 1418 |
+
priority=["pyav"],
|
| 1419 |
+
),
|
| 1420 |
+
FileExtension(
|
| 1421 |
+
name="NC camera feed",
|
| 1422 |
+
extension=".v",
|
| 1423 |
+
priority=["pyav"],
|
| 1424 |
+
),
|
| 1425 |
+
FileExtension(
|
| 1426 |
+
name="NUT",
|
| 1427 |
+
extension=".nut",
|
| 1428 |
+
priority=["pyav"],
|
| 1429 |
+
),
|
| 1430 |
+
FileExtension(
|
| 1431 |
+
name="Ogg Video",
|
| 1432 |
+
extension=".ogv",
|
| 1433 |
+
priority=["pyav"],
|
| 1434 |
+
),
|
| 1435 |
+
FileExtension(
|
| 1436 |
+
name="Ogg",
|
| 1437 |
+
extension=".ogg",
|
| 1438 |
+
priority=["pyav"],
|
| 1439 |
+
),
|
| 1440 |
+
FileExtension(
|
| 1441 |
+
name="On2 IVF",
|
| 1442 |
+
extension=".ivf",
|
| 1443 |
+
priority=["pyav"],
|
| 1444 |
+
),
|
| 1445 |
+
FileExtension(
|
| 1446 |
+
name="PSP MP4 (MPEG-4 Part 14)",
|
| 1447 |
+
extension=".psp",
|
| 1448 |
+
priority=["pyav"],
|
| 1449 |
+
),
|
| 1450 |
+
FileExtension(
|
| 1451 |
+
name="Psygnosis YOP",
|
| 1452 |
+
extension=".yop",
|
| 1453 |
+
priority=["pyav"],
|
| 1454 |
+
),
|
| 1455 |
+
FileExtension(
|
| 1456 |
+
name="QuickTime / MOV",
|
| 1457 |
+
extension=".3g2",
|
| 1458 |
+
priority=["pyav"],
|
| 1459 |
+
),
|
| 1460 |
+
FileExtension(
|
| 1461 |
+
name="QuickTime / MOV",
|
| 1462 |
+
extension=".3gp",
|
| 1463 |
+
priority=["pyav"],
|
| 1464 |
+
),
|
| 1465 |
+
FileExtension(
|
| 1466 |
+
name="QuickTime / MOV",
|
| 1467 |
+
extension=".f4v",
|
| 1468 |
+
priority=["pyav"],
|
| 1469 |
+
),
|
| 1470 |
+
FileExtension(
|
| 1471 |
+
name="QuickTime / MOV",
|
| 1472 |
+
extension=".ism",
|
| 1473 |
+
priority=["pyav"],
|
| 1474 |
+
),
|
| 1475 |
+
FileExtension(
|
| 1476 |
+
name="QuickTime / MOV",
|
| 1477 |
+
extension=".isma",
|
| 1478 |
+
priority=["pyav"],
|
| 1479 |
+
),
|
| 1480 |
+
FileExtension(
|
| 1481 |
+
name="QuickTime / MOV",
|
| 1482 |
+
extension=".ismv",
|
| 1483 |
+
priority=["pyav"],
|
| 1484 |
+
),
|
| 1485 |
+
FileExtension(
|
| 1486 |
+
name="QuickTime / MOV",
|
| 1487 |
+
extension=".m4a",
|
| 1488 |
+
priority=["pyav"],
|
| 1489 |
+
),
|
| 1490 |
+
FileExtension(
|
| 1491 |
+
name="QuickTime / MOV",
|
| 1492 |
+
extension=".m4b",
|
| 1493 |
+
priority=["pyav"],
|
| 1494 |
+
),
|
| 1495 |
+
FileExtension(
|
| 1496 |
+
name="QuickTime / MOV",
|
| 1497 |
+
extension=".mj2",
|
| 1498 |
+
priority=["pyav"],
|
| 1499 |
+
),
|
| 1500 |
+
FileExtension(
|
| 1501 |
+
name="QuickTime / MOV",
|
| 1502 |
+
extension=".psp",
|
| 1503 |
+
priority=["pyav"],
|
| 1504 |
+
),
|
| 1505 |
+
FileExtension(
|
| 1506 |
+
name="raw AVS2-P2/IEEE1857.4 video",
|
| 1507 |
+
extension=".avs",
|
| 1508 |
+
priority=["pyav"],
|
| 1509 |
+
),
|
| 1510 |
+
FileExtension(
|
| 1511 |
+
name="raw AVS2-P2/IEEE1857.4 video",
|
| 1512 |
+
extension=".avs2",
|
| 1513 |
+
priority=["pyav"],
|
| 1514 |
+
),
|
| 1515 |
+
FileExtension(
|
| 1516 |
+
name="raw AVS3-P2/IEEE1857.10",
|
| 1517 |
+
extension=".avs3",
|
| 1518 |
+
priority=["pyav"],
|
| 1519 |
+
),
|
| 1520 |
+
FileExtension(
|
| 1521 |
+
name="raw Chinese AVS (Audio Video Standard) video",
|
| 1522 |
+
extension=".cavs",
|
| 1523 |
+
priority=["pyav"],
|
| 1524 |
+
),
|
| 1525 |
+
FileExtension(
|
| 1526 |
+
name="raw Dirac",
|
| 1527 |
+
extension=".drc",
|
| 1528 |
+
priority=["pyav"],
|
| 1529 |
+
),
|
| 1530 |
+
FileExtension(
|
| 1531 |
+
name="raw Dirac",
|
| 1532 |
+
extension=".vc2",
|
| 1533 |
+
priority=["pyav"],
|
| 1534 |
+
),
|
| 1535 |
+
FileExtension(
|
| 1536 |
+
name="raw DNxHD (SMPTE VC-3)",
|
| 1537 |
+
extension=".dnxhd",
|
| 1538 |
+
priority=["pyav"],
|
| 1539 |
+
),
|
| 1540 |
+
FileExtension(
|
| 1541 |
+
name="raw DNxHD (SMPTE VC-3)",
|
| 1542 |
+
extension=".dnxhr",
|
| 1543 |
+
priority=["pyav"],
|
| 1544 |
+
),
|
| 1545 |
+
FileExtension(
|
| 1546 |
+
name="raw GSM",
|
| 1547 |
+
extension=".gsm",
|
| 1548 |
+
priority=["pyav"],
|
| 1549 |
+
),
|
| 1550 |
+
FileExtension(
|
| 1551 |
+
name="raw H.261",
|
| 1552 |
+
extension=".h261",
|
| 1553 |
+
priority=["pyav"],
|
| 1554 |
+
),
|
| 1555 |
+
FileExtension(
|
| 1556 |
+
name="raw H.263",
|
| 1557 |
+
extension=".h263",
|
| 1558 |
+
priority=["pyav"],
|
| 1559 |
+
),
|
| 1560 |
+
FileExtension(
|
| 1561 |
+
name="raw H.264 video",
|
| 1562 |
+
extension=".264",
|
| 1563 |
+
priority=["pyav"],
|
| 1564 |
+
),
|
| 1565 |
+
FileExtension(
|
| 1566 |
+
name="raw H.264 video",
|
| 1567 |
+
extension=".avc",
|
| 1568 |
+
priority=["pyav"],
|
| 1569 |
+
),
|
| 1570 |
+
FileExtension(
|
| 1571 |
+
name="raw H.264 video",
|
| 1572 |
+
extension=".h264",
|
| 1573 |
+
priority=["pyav"],
|
| 1574 |
+
),
|
| 1575 |
+
FileExtension(
|
| 1576 |
+
name="raw H.264 video",
|
| 1577 |
+
extension=".h26l",
|
| 1578 |
+
priority=["pyav"],
|
| 1579 |
+
),
|
| 1580 |
+
FileExtension(
|
| 1581 |
+
name="raw HEVC video",
|
| 1582 |
+
extension=".265",
|
| 1583 |
+
priority=["pyav"],
|
| 1584 |
+
),
|
| 1585 |
+
FileExtension(
|
| 1586 |
+
name="raw HEVC video",
|
| 1587 |
+
extension=".h265",
|
| 1588 |
+
priority=["pyav"],
|
| 1589 |
+
),
|
| 1590 |
+
FileExtension(
|
| 1591 |
+
name="raw HEVC video",
|
| 1592 |
+
extension=".hevc",
|
| 1593 |
+
priority=["pyav"],
|
| 1594 |
+
),
|
| 1595 |
+
FileExtension(
|
| 1596 |
+
name="raw id RoQ",
|
| 1597 |
+
extension=".roq",
|
| 1598 |
+
priority=["pyav"],
|
| 1599 |
+
),
|
| 1600 |
+
FileExtension(
|
| 1601 |
+
name="raw Ingenient MJPEG",
|
| 1602 |
+
extension=".cgi",
|
| 1603 |
+
priority=["pyav"],
|
| 1604 |
+
),
|
| 1605 |
+
FileExtension(
|
| 1606 |
+
name="raw IPU Video",
|
| 1607 |
+
extension=".ipu",
|
| 1608 |
+
priority=["pyav"],
|
| 1609 |
+
),
|
| 1610 |
+
FileExtension(
|
| 1611 |
+
name="raw MJPEG 2000 video",
|
| 1612 |
+
extension=".j2k",
|
| 1613 |
+
priority=["pyav"],
|
| 1614 |
+
),
|
| 1615 |
+
FileExtension(
|
| 1616 |
+
name="raw MJPEG video",
|
| 1617 |
+
extension=".mjpeg",
|
| 1618 |
+
priority=["pyav"],
|
| 1619 |
+
),
|
| 1620 |
+
FileExtension(
|
| 1621 |
+
name="raw MJPEG video",
|
| 1622 |
+
extension=".mjpg",
|
| 1623 |
+
priority=["pyav"],
|
| 1624 |
+
),
|
| 1625 |
+
FileExtension(
|
| 1626 |
+
name="raw MJPEG video",
|
| 1627 |
+
extension=".mpo",
|
| 1628 |
+
priority=["pyav"],
|
| 1629 |
+
),
|
| 1630 |
+
FileExtension(
|
| 1631 |
+
name="raw MPEG-1 video",
|
| 1632 |
+
extension=".m1v",
|
| 1633 |
+
priority=["pyav"],
|
| 1634 |
+
),
|
| 1635 |
+
FileExtension(
|
| 1636 |
+
name="raw MPEG-1 video",
|
| 1637 |
+
extension=".mpeg",
|
| 1638 |
+
priority=["pyav"],
|
| 1639 |
+
),
|
| 1640 |
+
FileExtension(
|
| 1641 |
+
name="raw MPEG-1 video",
|
| 1642 |
+
extension=".mpg",
|
| 1643 |
+
priority=["pyav"],
|
| 1644 |
+
),
|
| 1645 |
+
FileExtension(
|
| 1646 |
+
name="raw MPEG-2 video",
|
| 1647 |
+
extension=".m2v",
|
| 1648 |
+
priority=["pyav"],
|
| 1649 |
+
),
|
| 1650 |
+
FileExtension(
|
| 1651 |
+
name="raw MPEG-4 video",
|
| 1652 |
+
extension=".m4v",
|
| 1653 |
+
priority=["pyav"],
|
| 1654 |
+
),
|
| 1655 |
+
FileExtension(
|
| 1656 |
+
name="raw VC-1 video",
|
| 1657 |
+
extension=".vc1",
|
| 1658 |
+
priority=["pyav"],
|
| 1659 |
+
),
|
| 1660 |
+
FileExtension(
|
| 1661 |
+
name="raw video",
|
| 1662 |
+
extension=".cif",
|
| 1663 |
+
priority=["pyav"],
|
| 1664 |
+
),
|
| 1665 |
+
FileExtension(
|
| 1666 |
+
name="raw video",
|
| 1667 |
+
extension=".qcif",
|
| 1668 |
+
priority=["pyav"],
|
| 1669 |
+
),
|
| 1670 |
+
FileExtension(
|
| 1671 |
+
name="raw video",
|
| 1672 |
+
extension=".rgb",
|
| 1673 |
+
priority=["pyav"],
|
| 1674 |
+
),
|
| 1675 |
+
FileExtension(
|
| 1676 |
+
name="raw video",
|
| 1677 |
+
extension=".yuv",
|
| 1678 |
+
priority=["pyav"],
|
| 1679 |
+
),
|
| 1680 |
+
FileExtension(
|
| 1681 |
+
name="RealMedia",
|
| 1682 |
+
extension=".rm",
|
| 1683 |
+
priority=["pyav"],
|
| 1684 |
+
),
|
| 1685 |
+
FileExtension(
|
| 1686 |
+
name="SDR2",
|
| 1687 |
+
extension=".sdr2",
|
| 1688 |
+
priority=["pyav"],
|
| 1689 |
+
),
|
| 1690 |
+
FileExtension(
|
| 1691 |
+
name="Sega FILM / CPK",
|
| 1692 |
+
extension=".cpk",
|
| 1693 |
+
priority=["pyav"],
|
| 1694 |
+
),
|
| 1695 |
+
FileExtension(
|
| 1696 |
+
name="SER (Simple uncompressed video format for astronomical capturing)",
|
| 1697 |
+
extension=".ser",
|
| 1698 |
+
priority=["pyav"],
|
| 1699 |
+
),
|
| 1700 |
+
FileExtension(
|
| 1701 |
+
name="Simbiosis Interactive IMX",
|
| 1702 |
+
extension=".imx",
|
| 1703 |
+
priority=["pyav"],
|
| 1704 |
+
),
|
| 1705 |
+
FileExtension(
|
| 1706 |
+
name="Square SVS",
|
| 1707 |
+
extension=".svs",
|
| 1708 |
+
priority=["pyav"],
|
| 1709 |
+
),
|
| 1710 |
+
FileExtension(
|
| 1711 |
+
name="TiVo TY Stream",
|
| 1712 |
+
extension=".ty",
|
| 1713 |
+
priority=["pyav"],
|
| 1714 |
+
),
|
| 1715 |
+
FileExtension(
|
| 1716 |
+
name="TiVo TY Stream",
|
| 1717 |
+
extension=".ty+",
|
| 1718 |
+
priority=["pyav"],
|
| 1719 |
+
),
|
| 1720 |
+
FileExtension(
|
| 1721 |
+
name="Uncompressed 4:2:2 10-bit",
|
| 1722 |
+
extension=".v210",
|
| 1723 |
+
priority=["pyav"],
|
| 1724 |
+
),
|
| 1725 |
+
FileExtension(
|
| 1726 |
+
name="Uncompressed 4:2:2 10-bit",
|
| 1727 |
+
extension=".yuv10",
|
| 1728 |
+
priority=["pyav"],
|
| 1729 |
+
),
|
| 1730 |
+
FileExtension(
|
| 1731 |
+
name="VC-1 test bitstream",
|
| 1732 |
+
extension=".rcv",
|
| 1733 |
+
priority=["pyav"],
|
| 1734 |
+
),
|
| 1735 |
+
FileExtension(
|
| 1736 |
+
name="Video CCTV DAT",
|
| 1737 |
+
extension=".dat",
|
| 1738 |
+
priority=["pyav"],
|
| 1739 |
+
),
|
| 1740 |
+
FileExtension(
|
| 1741 |
+
name="Video DAV",
|
| 1742 |
+
extension=".dav",
|
| 1743 |
+
priority=["pyav"],
|
| 1744 |
+
),
|
| 1745 |
+
FileExtension(
|
| 1746 |
+
name="Vivo",
|
| 1747 |
+
extension=".viv",
|
| 1748 |
+
priority=["pyav"],
|
| 1749 |
+
),
|
| 1750 |
+
FileExtension(
|
| 1751 |
+
name="WebM Chunk Muxer",
|
| 1752 |
+
extension=".chk",
|
| 1753 |
+
priority=["pyav"],
|
| 1754 |
+
),
|
| 1755 |
+
FileExtension(
|
| 1756 |
+
name="WebM",
|
| 1757 |
+
extension=".mk3d",
|
| 1758 |
+
priority=["pyav"],
|
| 1759 |
+
),
|
| 1760 |
+
FileExtension(
|
| 1761 |
+
name="WebM",
|
| 1762 |
+
extension=".mka",
|
| 1763 |
+
priority=["pyav"],
|
| 1764 |
+
),
|
| 1765 |
+
FileExtension(
|
| 1766 |
+
name="WebM",
|
| 1767 |
+
extension=".mks",
|
| 1768 |
+
priority=["pyav"],
|
| 1769 |
+
),
|
| 1770 |
+
FileExtension(
|
| 1771 |
+
name="Windows Television (WTV)",
|
| 1772 |
+
extension=".wtv",
|
| 1773 |
+
priority=["pyav"],
|
| 1774 |
+
),
|
| 1775 |
+
FileExtension(
|
| 1776 |
+
name="Xilam DERF",
|
| 1777 |
+
extension=".adp",
|
| 1778 |
+
priority=["pyav"],
|
| 1779 |
+
),
|
| 1780 |
+
FileExtension(
|
| 1781 |
+
name="YUV4MPEG pipe",
|
| 1782 |
+
extension=".y4m",
|
| 1783 |
+
priority=["pyav"],
|
| 1784 |
+
),
|
| 1785 |
+
]
|
| 1786 |
+
extension_list.sort(key=lambda x: x.extension)
|
| 1787 |
+
|
| 1788 |
+
|
| 1789 |
+
known_extensions = dict()
|
| 1790 |
+
for ext in extension_list:
|
| 1791 |
+
if ext.extension not in known_extensions:
|
| 1792 |
+
known_extensions[ext.extension] = list()
|
| 1793 |
+
known_extensions[ext.extension].append(ext)
|
| 1794 |
+
|
| 1795 |
+
extension_list = [ext for ext_list in known_extensions.values() for ext in ext_list]
|
| 1796 |
+
|
| 1797 |
+
_video_extension_strings = [
|
| 1798 |
+
".264",
|
| 1799 |
+
".265",
|
| 1800 |
+
".3g2",
|
| 1801 |
+
".3gp",
|
| 1802 |
+
".a64",
|
| 1803 |
+
".A64",
|
| 1804 |
+
".adp",
|
| 1805 |
+
".amr",
|
| 1806 |
+
".amv",
|
| 1807 |
+
".asf",
|
| 1808 |
+
".avc",
|
| 1809 |
+
".avi",
|
| 1810 |
+
".avr",
|
| 1811 |
+
".avs",
|
| 1812 |
+
".avs2",
|
| 1813 |
+
".avs3",
|
| 1814 |
+
".bmv",
|
| 1815 |
+
".cavs",
|
| 1816 |
+
".cdg",
|
| 1817 |
+
".cdxl",
|
| 1818 |
+
".cgi",
|
| 1819 |
+
".chk",
|
| 1820 |
+
".cif",
|
| 1821 |
+
".cpk",
|
| 1822 |
+
".dat",
|
| 1823 |
+
".dav",
|
| 1824 |
+
".dif",
|
| 1825 |
+
".dnxhd",
|
| 1826 |
+
".dnxhr",
|
| 1827 |
+
".drc",
|
| 1828 |
+
".dv",
|
| 1829 |
+
".dvd",
|
| 1830 |
+
".f4v",
|
| 1831 |
+
".flm",
|
| 1832 |
+
".flv",
|
| 1833 |
+
".gsm",
|
| 1834 |
+
".gxf",
|
| 1835 |
+
".h261",
|
| 1836 |
+
".h263",
|
| 1837 |
+
".h264",
|
| 1838 |
+
".h265",
|
| 1839 |
+
".h26l",
|
| 1840 |
+
".hevc",
|
| 1841 |
+
".idf",
|
| 1842 |
+
".ifv",
|
| 1843 |
+
".imx",
|
| 1844 |
+
".ipu",
|
| 1845 |
+
".ism",
|
| 1846 |
+
".isma",
|
| 1847 |
+
".ismv",
|
| 1848 |
+
".ivf",
|
| 1849 |
+
".ivr",
|
| 1850 |
+
".j2k",
|
| 1851 |
+
".kux",
|
| 1852 |
+
".lvf",
|
| 1853 |
+
".m1v",
|
| 1854 |
+
".m2t",
|
| 1855 |
+
".m2ts",
|
| 1856 |
+
".m2v",
|
| 1857 |
+
".m4a",
|
| 1858 |
+
".m4b",
|
| 1859 |
+
".m4v",
|
| 1860 |
+
".mj2",
|
| 1861 |
+
".mjpeg",
|
| 1862 |
+
".mjpg",
|
| 1863 |
+
".mk3d",
|
| 1864 |
+
".mka",
|
| 1865 |
+
".mks",
|
| 1866 |
+
".mkv",
|
| 1867 |
+
".mods",
|
| 1868 |
+
".moflex",
|
| 1869 |
+
".mov",
|
| 1870 |
+
".mp4",
|
| 1871 |
+
".mpc",
|
| 1872 |
+
".mpd",
|
| 1873 |
+
".mpeg",
|
| 1874 |
+
".mpg",
|
| 1875 |
+
".mpo",
|
| 1876 |
+
".mts",
|
| 1877 |
+
".mvi",
|
| 1878 |
+
".mxf",
|
| 1879 |
+
".mxg",
|
| 1880 |
+
".nut",
|
| 1881 |
+
".obu",
|
| 1882 |
+
".ogg",
|
| 1883 |
+
".ogv",
|
| 1884 |
+
".psp",
|
| 1885 |
+
".qcif",
|
| 1886 |
+
".rcv",
|
| 1887 |
+
".rgb",
|
| 1888 |
+
".rm",
|
| 1889 |
+
".roq",
|
| 1890 |
+
".sdr2",
|
| 1891 |
+
".ser",
|
| 1892 |
+
".sga",
|
| 1893 |
+
".svag",
|
| 1894 |
+
".svs",
|
| 1895 |
+
".ts",
|
| 1896 |
+
".ty",
|
| 1897 |
+
".ty+",
|
| 1898 |
+
".v",
|
| 1899 |
+
".v210",
|
| 1900 |
+
".vb",
|
| 1901 |
+
".vc1",
|
| 1902 |
+
".vc2",
|
| 1903 |
+
".viv",
|
| 1904 |
+
".vob",
|
| 1905 |
+
".webm",
|
| 1906 |
+
".wmv",
|
| 1907 |
+
".wtv",
|
| 1908 |
+
".xl",
|
| 1909 |
+
".xmv",
|
| 1910 |
+
".y4m",
|
| 1911 |
+
".yop",
|
| 1912 |
+
".yuv",
|
| 1913 |
+
".yuv10",
|
| 1914 |
+
]
|
| 1915 |
+
video_extensions = list()
|
| 1916 |
+
for ext_string in _video_extension_strings:
|
| 1917 |
+
formats = known_extensions[ext_string]
|
| 1918 |
+
video_extensions.append(formats[0])
|
| 1919 |
+
video_extensions.sort(key=lambda x: x.extension)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/config/plugins.py
ADDED
|
@@ -0,0 +1,784 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import importlib
|
| 2 |
+
|
| 3 |
+
from ..core.legacy_plugin_wrapper import LegacyPlugin
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class PluginConfig:
|
| 7 |
+
"""Plugin Configuration Metadata
|
| 8 |
+
|
| 9 |
+
This class holds the information needed to lazy-import plugins.
|
| 10 |
+
|
| 11 |
+
Parameters
|
| 12 |
+
----------
|
| 13 |
+
name : str
|
| 14 |
+
The name of the plugin.
|
| 15 |
+
class_name : str
|
| 16 |
+
The name of the plugin class inside the plugin module.
|
| 17 |
+
module_name : str
|
| 18 |
+
The name of the module/package from which to import the plugin.
|
| 19 |
+
is_legacy : bool
|
| 20 |
+
If True, this plugin is a v2 plugin and will be wrapped in a
|
| 21 |
+
LegacyPlugin. Default: False.
|
| 22 |
+
package_name : str
|
| 23 |
+
If the given module name points to a relative module, then the package
|
| 24 |
+
name determines the package it is relative to.
|
| 25 |
+
install_name : str
|
| 26 |
+
The name of the optional dependency that can be used to install this
|
| 27 |
+
plugin if it is missing.
|
| 28 |
+
legacy_args : Dict
|
| 29 |
+
A dictionary of kwargs to pass to the v2 plugin (Format) upon construction.
|
| 30 |
+
|
| 31 |
+
Examples
|
| 32 |
+
--------
|
| 33 |
+
>>> PluginConfig(
|
| 34 |
+
name="TIFF",
|
| 35 |
+
class_name="TiffFormat",
|
| 36 |
+
module_name="imageio.plugins.tifffile",
|
| 37 |
+
is_legacy=True,
|
| 38 |
+
install_name="tifffile",
|
| 39 |
+
legacy_args={
|
| 40 |
+
"description": "TIFF format",
|
| 41 |
+
"extensions": ".tif .tiff .stk .lsm",
|
| 42 |
+
"modes": "iIvV",
|
| 43 |
+
},
|
| 44 |
+
)
|
| 45 |
+
>>> PluginConfig(
|
| 46 |
+
name="pillow",
|
| 47 |
+
class_name="PillowPlugin",
|
| 48 |
+
module_name="imageio.plugins.pillow"
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
def __init__(
|
| 54 |
+
self,
|
| 55 |
+
name,
|
| 56 |
+
class_name,
|
| 57 |
+
module_name,
|
| 58 |
+
*,
|
| 59 |
+
is_legacy=False,
|
| 60 |
+
package_name=None,
|
| 61 |
+
install_name=None,
|
| 62 |
+
legacy_args=None,
|
| 63 |
+
):
|
| 64 |
+
legacy_args = legacy_args or dict()
|
| 65 |
+
|
| 66 |
+
self.name = name
|
| 67 |
+
self.class_name = class_name
|
| 68 |
+
self.module_name = module_name
|
| 69 |
+
self.package_name = package_name
|
| 70 |
+
|
| 71 |
+
self.is_legacy = is_legacy
|
| 72 |
+
self.install_name = install_name or self.name
|
| 73 |
+
self.legacy_args = {"name": name, "description": "A legacy plugin"}
|
| 74 |
+
self.legacy_args.update(legacy_args)
|
| 75 |
+
|
| 76 |
+
@property
|
| 77 |
+
def format(self):
|
| 78 |
+
"""For backwards compatibility with FormatManager
|
| 79 |
+
|
| 80 |
+
Delete when migrating to v3
|
| 81 |
+
"""
|
| 82 |
+
if not self.is_legacy:
|
| 83 |
+
raise RuntimeError("Can only get format for legacy plugins.")
|
| 84 |
+
|
| 85 |
+
module = importlib.import_module(self.module_name, self.package_name)
|
| 86 |
+
clazz = getattr(module, self.class_name)
|
| 87 |
+
return clazz(**self.legacy_args)
|
| 88 |
+
|
| 89 |
+
@property
|
| 90 |
+
def plugin_class(self):
|
| 91 |
+
"""Get the plugin class (import if needed)
|
| 92 |
+
|
| 93 |
+
Returns
|
| 94 |
+
-------
|
| 95 |
+
plugin_class : Any
|
| 96 |
+
The class that can be used to instantiate plugins.
|
| 97 |
+
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
module = importlib.import_module(self.module_name, self.package_name)
|
| 101 |
+
clazz = getattr(module, self.class_name)
|
| 102 |
+
|
| 103 |
+
if self.is_legacy:
|
| 104 |
+
legacy_plugin = clazz(**self.legacy_args)
|
| 105 |
+
|
| 106 |
+
def partial_legacy_plugin(request):
|
| 107 |
+
return LegacyPlugin(request, legacy_plugin)
|
| 108 |
+
|
| 109 |
+
clazz = partial_legacy_plugin
|
| 110 |
+
|
| 111 |
+
return clazz
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
known_plugins = dict()
|
| 115 |
+
known_plugins["pillow"] = PluginConfig(
|
| 116 |
+
name="pillow", class_name="PillowPlugin", module_name="imageio.plugins.pillow"
|
| 117 |
+
)
|
| 118 |
+
known_plugins["pyav"] = PluginConfig(
|
| 119 |
+
name="pyav", class_name="PyAVPlugin", module_name="imageio.plugins.pyav"
|
| 120 |
+
)
|
| 121 |
+
known_plugins["opencv"] = PluginConfig(
|
| 122 |
+
name="opencv", class_name="OpenCVPlugin", module_name="imageio.plugins.opencv"
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
# Legacy plugins
|
| 126 |
+
# ==============
|
| 127 |
+
#
|
| 128 |
+
# Which are partly registered by format, partly by plugin, and partly by a mix
|
| 129 |
+
# of both. We keep the naming here for backwards compatibility.
|
| 130 |
+
# In v3 this should become a single entry per plugin named after the plugin
|
| 131 |
+
# We can choose extension-specific priority in ``config.extensions``.
|
| 132 |
+
#
|
| 133 |
+
# Note: Since python 3.7 order of insertion determines the order of dict().keys()
|
| 134 |
+
# This means that the order here determines the order by which plugins are
|
| 135 |
+
# checked during the full fallback search. We don't advertise this downstream,
|
| 136 |
+
# but it could be a useful thing to keep in mind to choose a sensible default
|
| 137 |
+
# search order.
|
| 138 |
+
|
| 139 |
+
known_plugins["TIFF"] = PluginConfig(
|
| 140 |
+
name="TIFF",
|
| 141 |
+
class_name="TiffFormat",
|
| 142 |
+
module_name="imageio.plugins.tifffile",
|
| 143 |
+
is_legacy=True,
|
| 144 |
+
install_name="tifffile",
|
| 145 |
+
legacy_args={
|
| 146 |
+
"description": "TIFF format",
|
| 147 |
+
"extensions": ".tif .tiff .stk .lsm",
|
| 148 |
+
"modes": "iIvV",
|
| 149 |
+
},
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
# PILLOW plugin formats (legacy)
|
| 153 |
+
PILLOW_FORMATS = [
|
| 154 |
+
("BMP", "Windows Bitmap", ".bmp", "PillowFormat"),
|
| 155 |
+
("BUFR", "BUFR", ".bufr", "PillowFormat"),
|
| 156 |
+
("CUR", "Windows Cursor", ".cur", "PillowFormat"),
|
| 157 |
+
("DCX", "Intel DCX", ".dcx", "PillowFormat"),
|
| 158 |
+
("DDS", "DirectDraw Surface", ".dds", "PillowFormat"),
|
| 159 |
+
("DIB", "Windows Bitmap", "", "PillowFormat"),
|
| 160 |
+
("EPS", "Encapsulated Postscript", ".ps .eps", "PillowFormat"),
|
| 161 |
+
("FITS", "FITS", ".fit .fits", "PillowFormat"),
|
| 162 |
+
("FLI", "Autodesk FLI/FLC Animation", ".fli .flc", "PillowFormat"),
|
| 163 |
+
("FPX", "FlashPix", ".fpx", "PillowFormat"),
|
| 164 |
+
("FTEX", "Texture File Format (IW2:EOC)", ".ftc .ftu", "PillowFormat"),
|
| 165 |
+
("GBR", "GIMP brush file", ".gbr", "PillowFormat"),
|
| 166 |
+
("GIF", "Compuserve GIF", ".gif", "GIFFormat"),
|
| 167 |
+
("GRIB", "GRIB", ".grib", "PillowFormat"),
|
| 168 |
+
("HDF5", "HDF5", ".h5 .hdf", "PillowFormat"),
|
| 169 |
+
("ICNS", "Mac OS icns resource", ".icns", "PillowFormat"),
|
| 170 |
+
("ICO", "Windows Icon", ".ico", "PillowFormat"),
|
| 171 |
+
("IM", "IFUNC Image Memory", ".im", "PillowFormat"),
|
| 172 |
+
("IMT", "IM Tools", "", "PillowFormat"),
|
| 173 |
+
("IPTC", "IPTC/NAA", ".iim", "PillowFormat"),
|
| 174 |
+
("JPEG", "JPEG (ISO 10918)", ".jfif .jpe .jpg .jpeg", "JPEGFormat"),
|
| 175 |
+
(
|
| 176 |
+
"JPEG2000",
|
| 177 |
+
"JPEG 2000 (ISO 15444)",
|
| 178 |
+
".jp2 .j2k .jpc .jpf .jpx .j2c",
|
| 179 |
+
"JPEG2000Format",
|
| 180 |
+
),
|
| 181 |
+
("MCIDAS", "McIdas area file", "", "PillowFormat"),
|
| 182 |
+
("MIC", "Microsoft Image Composer", ".mic", "PillowFormat"),
|
| 183 |
+
# skipped in legacy pillow
|
| 184 |
+
# ("MPEG", "MPEG", ".mpg .mpeg", "PillowFormat"),
|
| 185 |
+
("MPO", "MPO (CIPA DC-007)", ".mpo", "PillowFormat"),
|
| 186 |
+
("MSP", "Windows Paint", ".msp", "PillowFormat"),
|
| 187 |
+
("PCD", "Kodak PhotoCD", ".pcd", "PillowFormat"),
|
| 188 |
+
("PCX", "Paintbrush", ".pcx", "PillowFormat"),
|
| 189 |
+
("PIXAR", "PIXAR raster image", ".pxr", "PillowFormat"),
|
| 190 |
+
("PNG", "Portable network graphics", ".png", "PNGFormat"),
|
| 191 |
+
("PPM", "Pbmplus image", ".pbm .pgm .ppm", "PillowFormat"),
|
| 192 |
+
("PSD", "Adobe Photoshop", ".psd", "PillowFormat"),
|
| 193 |
+
("SGI", "SGI Image File Format", ".bw .rgb .rgba .sgi", "PillowFormat"),
|
| 194 |
+
("SPIDER", "Spider 2D image", "", "PillowFormat"),
|
| 195 |
+
("SUN", "Sun Raster File", ".ras", "PillowFormat"),
|
| 196 |
+
("TGA", "Targa", ".tga", "PillowFormat"),
|
| 197 |
+
("TIFF", "Adobe TIFF", ".tif .tiff", "TIFFFormat"),
|
| 198 |
+
("WMF", "Windows Metafile", ".wmf .emf", "PillowFormat"),
|
| 199 |
+
("XBM", "X11 Bitmap", ".xbm", "PillowFormat"),
|
| 200 |
+
("XPM", "X11 Pixel Map", ".xpm", "PillowFormat"),
|
| 201 |
+
("XVTHUMB", "XV thumbnail image", "", "PillowFormat"),
|
| 202 |
+
]
|
| 203 |
+
for id, summary, ext, class_name in PILLOW_FORMATS:
|
| 204 |
+
config = PluginConfig(
|
| 205 |
+
name=id.upper() + "-PIL",
|
| 206 |
+
class_name=class_name,
|
| 207 |
+
module_name="imageio.plugins.pillow_legacy",
|
| 208 |
+
is_legacy=True,
|
| 209 |
+
install_name="pillow",
|
| 210 |
+
legacy_args={
|
| 211 |
+
"description": summary + " via Pillow",
|
| 212 |
+
"extensions": ext,
|
| 213 |
+
"modes": "iI" if class_name == "GIFFormat" else "i",
|
| 214 |
+
"plugin_id": id,
|
| 215 |
+
},
|
| 216 |
+
)
|
| 217 |
+
known_plugins[config.name] = config
|
| 218 |
+
|
| 219 |
+
known_plugins["FFMPEG"] = PluginConfig(
|
| 220 |
+
name="FFMPEG",
|
| 221 |
+
class_name="FfmpegFormat",
|
| 222 |
+
module_name="imageio.plugins.ffmpeg",
|
| 223 |
+
is_legacy=True,
|
| 224 |
+
install_name="ffmpeg",
|
| 225 |
+
legacy_args={
|
| 226 |
+
"description": "Many video formats and cameras (via ffmpeg)",
|
| 227 |
+
"extensions": ".mov .avi .mpg .mpeg .mp4 .mkv .webm .wmv",
|
| 228 |
+
"modes": "I",
|
| 229 |
+
},
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
known_plugins["BSDF"] = PluginConfig(
|
| 233 |
+
name="BSDF",
|
| 234 |
+
class_name="BsdfFormat",
|
| 235 |
+
module_name="imageio.plugins.bsdf",
|
| 236 |
+
is_legacy=True,
|
| 237 |
+
install_name="bsdf",
|
| 238 |
+
legacy_args={
|
| 239 |
+
"description": "Format based on the Binary Structured Data Format",
|
| 240 |
+
"extensions": ".bsdf",
|
| 241 |
+
"modes": "iIvV",
|
| 242 |
+
},
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
known_plugins["DICOM"] = PluginConfig(
|
| 246 |
+
name="DICOM",
|
| 247 |
+
class_name="DicomFormat",
|
| 248 |
+
module_name="imageio.plugins.dicom",
|
| 249 |
+
is_legacy=True,
|
| 250 |
+
install_name="dicom",
|
| 251 |
+
legacy_args={
|
| 252 |
+
"description": "Digital Imaging and Communications in Medicine",
|
| 253 |
+
"extensions": ".dcm .ct .mri",
|
| 254 |
+
"modes": "iIvV",
|
| 255 |
+
},
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
known_plugins["FEI"] = PluginConfig(
|
| 259 |
+
name="FEI",
|
| 260 |
+
class_name="FEISEMFormat",
|
| 261 |
+
module_name="imageio.plugins.feisem",
|
| 262 |
+
is_legacy=True,
|
| 263 |
+
install_name="feisem",
|
| 264 |
+
legacy_args={
|
| 265 |
+
"description": "FEI-SEM TIFF format",
|
| 266 |
+
"extensions": [".tif", ".tiff"],
|
| 267 |
+
"modes": "iv",
|
| 268 |
+
},
|
| 269 |
+
)
|
| 270 |
+
|
| 271 |
+
known_plugins["FITS"] = PluginConfig(
|
| 272 |
+
name="FITS",
|
| 273 |
+
class_name="FitsFormat",
|
| 274 |
+
module_name="imageio.plugins.fits",
|
| 275 |
+
is_legacy=True,
|
| 276 |
+
install_name="fits",
|
| 277 |
+
legacy_args={
|
| 278 |
+
"description": "Flexible Image Transport System (FITS) format",
|
| 279 |
+
"extensions": ".fits .fit .fts .fz",
|
| 280 |
+
"modes": "iIvV",
|
| 281 |
+
},
|
| 282 |
+
)
|
| 283 |
+
|
| 284 |
+
known_plugins["GDAL"] = PluginConfig(
|
| 285 |
+
name="GDAL",
|
| 286 |
+
class_name="GdalFormat",
|
| 287 |
+
module_name="imageio.plugins.gdal",
|
| 288 |
+
is_legacy=True,
|
| 289 |
+
install_name="gdal",
|
| 290 |
+
legacy_args={
|
| 291 |
+
"description": "Geospatial Data Abstraction Library",
|
| 292 |
+
"extensions": ".tiff .tif .img .ecw .jpg .jpeg",
|
| 293 |
+
"modes": "iIvV",
|
| 294 |
+
},
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
known_plugins["ITK"] = PluginConfig(
|
| 298 |
+
name="ITK",
|
| 299 |
+
class_name="ItkFormat",
|
| 300 |
+
module_name="imageio.plugins.simpleitk",
|
| 301 |
+
is_legacy=True,
|
| 302 |
+
install_name="simpleitk",
|
| 303 |
+
legacy_args={
|
| 304 |
+
"description": "Insight Segmentation and Registration Toolkit (ITK) format",
|
| 305 |
+
"extensions": " ".join(
|
| 306 |
+
(
|
| 307 |
+
".gipl",
|
| 308 |
+
".ipl",
|
| 309 |
+
".mha",
|
| 310 |
+
".mhd",
|
| 311 |
+
".nhdr",
|
| 312 |
+
".nia",
|
| 313 |
+
".hdr",
|
| 314 |
+
".nrrd",
|
| 315 |
+
".nii",
|
| 316 |
+
".nii.gz",
|
| 317 |
+
".img",
|
| 318 |
+
".img.gz",
|
| 319 |
+
".vtk",
|
| 320 |
+
".hdf5",
|
| 321 |
+
".lsm",
|
| 322 |
+
".mnc",
|
| 323 |
+
".mnc2",
|
| 324 |
+
".mgh",
|
| 325 |
+
".mnc",
|
| 326 |
+
".pic",
|
| 327 |
+
".bmp",
|
| 328 |
+
".jpeg",
|
| 329 |
+
".jpg",
|
| 330 |
+
".png",
|
| 331 |
+
".tiff",
|
| 332 |
+
".tif",
|
| 333 |
+
".dicom",
|
| 334 |
+
".dcm",
|
| 335 |
+
".gdcm",
|
| 336 |
+
)
|
| 337 |
+
),
|
| 338 |
+
"modes": "iIvV",
|
| 339 |
+
},
|
| 340 |
+
)
|
| 341 |
+
|
| 342 |
+
known_plugins["NPZ"] = PluginConfig(
|
| 343 |
+
name="NPZ",
|
| 344 |
+
class_name="NpzFormat",
|
| 345 |
+
module_name="imageio.plugins.npz",
|
| 346 |
+
is_legacy=True,
|
| 347 |
+
install_name="numpy",
|
| 348 |
+
legacy_args={
|
| 349 |
+
"description": "Numpy's compressed array format",
|
| 350 |
+
"extensions": ".npz",
|
| 351 |
+
"modes": "iIvV",
|
| 352 |
+
},
|
| 353 |
+
)
|
| 354 |
+
|
| 355 |
+
known_plugins["SPE"] = PluginConfig(
|
| 356 |
+
name="SPE",
|
| 357 |
+
class_name="SpeFormat",
|
| 358 |
+
module_name="imageio.plugins.spe",
|
| 359 |
+
is_legacy=True,
|
| 360 |
+
install_name="spe",
|
| 361 |
+
legacy_args={
|
| 362 |
+
"description": "SPE file format",
|
| 363 |
+
"extensions": ".spe",
|
| 364 |
+
"modes": "iIvV",
|
| 365 |
+
},
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
known_plugins["SWF"] = PluginConfig(
|
| 369 |
+
name="SWF",
|
| 370 |
+
class_name="SWFFormat",
|
| 371 |
+
module_name="imageio.plugins.swf",
|
| 372 |
+
is_legacy=True,
|
| 373 |
+
install_name="swf",
|
| 374 |
+
legacy_args={
|
| 375 |
+
"description": "Shockwave flash",
|
| 376 |
+
"extensions": ".swf",
|
| 377 |
+
"modes": "I",
|
| 378 |
+
},
|
| 379 |
+
)
|
| 380 |
+
|
| 381 |
+
known_plugins["SCREENGRAB"] = PluginConfig(
|
| 382 |
+
name="SCREENGRAB",
|
| 383 |
+
class_name="ScreenGrabFormat",
|
| 384 |
+
module_name="imageio.plugins.grab",
|
| 385 |
+
is_legacy=True,
|
| 386 |
+
install_name="pillow",
|
| 387 |
+
legacy_args={
|
| 388 |
+
"description": "Grab screenshots (Windows and OS X only)",
|
| 389 |
+
"extensions": [],
|
| 390 |
+
"modes": "i",
|
| 391 |
+
},
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
+
known_plugins["CLIPBOARDGRAB"] = PluginConfig(
|
| 395 |
+
name="CLIPBOARDGRAB",
|
| 396 |
+
class_name="ClipboardGrabFormat",
|
| 397 |
+
module_name="imageio.plugins.grab",
|
| 398 |
+
is_legacy=True,
|
| 399 |
+
install_name="pillow",
|
| 400 |
+
legacy_args={
|
| 401 |
+
"description": "Grab from clipboard (Windows only)",
|
| 402 |
+
"extensions": [],
|
| 403 |
+
"modes": "i",
|
| 404 |
+
},
|
| 405 |
+
)
|
| 406 |
+
|
| 407 |
+
# LYTRO plugin (legacy)
|
| 408 |
+
lytro_formats = [
|
| 409 |
+
("lytro-lfr", "Lytro Illum lfr image file", ".lfr", "i", "LytroLfrFormat"),
|
| 410 |
+
(
|
| 411 |
+
"lytro-illum-raw",
|
| 412 |
+
"Lytro Illum raw image file",
|
| 413 |
+
".raw",
|
| 414 |
+
"i",
|
| 415 |
+
"LytroIllumRawFormat",
|
| 416 |
+
),
|
| 417 |
+
("lytro-lfp", "Lytro F01 lfp image file", ".lfp", "i", "LytroLfpFormat"),
|
| 418 |
+
("lytro-f01-raw", "Lytro F01 raw image file", ".raw", "i", "LytroF01RawFormat"),
|
| 419 |
+
]
|
| 420 |
+
for name, des, ext, mode, class_name in lytro_formats:
|
| 421 |
+
config = PluginConfig(
|
| 422 |
+
name=name.upper(),
|
| 423 |
+
class_name=class_name,
|
| 424 |
+
module_name="imageio.plugins.lytro",
|
| 425 |
+
is_legacy=True,
|
| 426 |
+
install_name="lytro",
|
| 427 |
+
legacy_args={
|
| 428 |
+
"description": des,
|
| 429 |
+
"extensions": ext,
|
| 430 |
+
"modes": mode,
|
| 431 |
+
},
|
| 432 |
+
)
|
| 433 |
+
known_plugins[config.name] = config
|
| 434 |
+
|
| 435 |
+
# FreeImage plugin (legacy)
|
| 436 |
+
FREEIMAGE_FORMATS = [
|
| 437 |
+
(
|
| 438 |
+
"BMP",
|
| 439 |
+
0,
|
| 440 |
+
"Windows or OS/2 Bitmap",
|
| 441 |
+
".bmp",
|
| 442 |
+
"i",
|
| 443 |
+
"FreeimageBmpFormat",
|
| 444 |
+
"imageio.plugins.freeimage",
|
| 445 |
+
),
|
| 446 |
+
(
|
| 447 |
+
"CUT",
|
| 448 |
+
21,
|
| 449 |
+
"Dr. Halo",
|
| 450 |
+
".cut",
|
| 451 |
+
"i",
|
| 452 |
+
"FreeimageFormat",
|
| 453 |
+
"imageio.plugins.freeimage",
|
| 454 |
+
),
|
| 455 |
+
(
|
| 456 |
+
"DDS",
|
| 457 |
+
24,
|
| 458 |
+
"DirectX Surface",
|
| 459 |
+
".dds",
|
| 460 |
+
"i",
|
| 461 |
+
"FreeimageFormat",
|
| 462 |
+
"imageio.plugins.freeimage",
|
| 463 |
+
),
|
| 464 |
+
(
|
| 465 |
+
"EXR",
|
| 466 |
+
29,
|
| 467 |
+
"ILM OpenEXR",
|
| 468 |
+
".exr",
|
| 469 |
+
"i",
|
| 470 |
+
"FreeimageFormat",
|
| 471 |
+
"imageio.plugins.freeimage",
|
| 472 |
+
),
|
| 473 |
+
(
|
| 474 |
+
"G3",
|
| 475 |
+
27,
|
| 476 |
+
"Raw fax format CCITT G.3",
|
| 477 |
+
".g3",
|
| 478 |
+
"i",
|
| 479 |
+
"FreeimageFormat",
|
| 480 |
+
"imageio.plugins.freeimage",
|
| 481 |
+
),
|
| 482 |
+
(
|
| 483 |
+
"GIF",
|
| 484 |
+
25,
|
| 485 |
+
"Static and animated gif (FreeImage)",
|
| 486 |
+
".gif",
|
| 487 |
+
"iI",
|
| 488 |
+
"GifFormat",
|
| 489 |
+
"imageio.plugins.freeimagemulti",
|
| 490 |
+
),
|
| 491 |
+
(
|
| 492 |
+
"HDR",
|
| 493 |
+
26,
|
| 494 |
+
"High Dynamic Range Image",
|
| 495 |
+
".hdr",
|
| 496 |
+
"i",
|
| 497 |
+
"FreeimageFormat",
|
| 498 |
+
"imageio.plugins.freeimage",
|
| 499 |
+
),
|
| 500 |
+
(
|
| 501 |
+
"ICO",
|
| 502 |
+
1,
|
| 503 |
+
"Windows Icon",
|
| 504 |
+
".ico",
|
| 505 |
+
"iI",
|
| 506 |
+
"IcoFormat",
|
| 507 |
+
"imageio.plugins.freeimagemulti",
|
| 508 |
+
),
|
| 509 |
+
(
|
| 510 |
+
"IFF",
|
| 511 |
+
5,
|
| 512 |
+
"IFF Interleaved Bitmap",
|
| 513 |
+
".iff .lbm",
|
| 514 |
+
"i",
|
| 515 |
+
"FreeimageFormat",
|
| 516 |
+
"imageio.plugins.freeimage",
|
| 517 |
+
),
|
| 518 |
+
(
|
| 519 |
+
"J2K",
|
| 520 |
+
30,
|
| 521 |
+
"JPEG-2000 codestream",
|
| 522 |
+
".j2k .j2c",
|
| 523 |
+
"i",
|
| 524 |
+
"FreeimageFormat",
|
| 525 |
+
"imageio.plugins.freeimage",
|
| 526 |
+
),
|
| 527 |
+
(
|
| 528 |
+
"JNG",
|
| 529 |
+
3,
|
| 530 |
+
"JPEG Network Graphics",
|
| 531 |
+
".jng",
|
| 532 |
+
"i",
|
| 533 |
+
"FreeimageFormat",
|
| 534 |
+
"imageio.plugins.freeimage",
|
| 535 |
+
),
|
| 536 |
+
(
|
| 537 |
+
"JP2",
|
| 538 |
+
31,
|
| 539 |
+
"JPEG-2000 File Format",
|
| 540 |
+
".jp2",
|
| 541 |
+
"i",
|
| 542 |
+
"FreeimageFormat",
|
| 543 |
+
"imageio.plugins.freeimage",
|
| 544 |
+
),
|
| 545 |
+
(
|
| 546 |
+
"JPEG",
|
| 547 |
+
2,
|
| 548 |
+
"JPEG - JFIF Compliant",
|
| 549 |
+
".jpg .jif .jpeg .jpe",
|
| 550 |
+
"i",
|
| 551 |
+
"FreeimageJpegFormat",
|
| 552 |
+
"imageio.plugins.freeimage",
|
| 553 |
+
),
|
| 554 |
+
(
|
| 555 |
+
"JPEG-XR",
|
| 556 |
+
36,
|
| 557 |
+
"JPEG XR image format",
|
| 558 |
+
".jxr .wdp .hdp",
|
| 559 |
+
"i",
|
| 560 |
+
"FreeimageFormat",
|
| 561 |
+
"imageio.plugins.freeimage",
|
| 562 |
+
),
|
| 563 |
+
(
|
| 564 |
+
"KOALA",
|
| 565 |
+
4,
|
| 566 |
+
"C64 Koala Graphics",
|
| 567 |
+
".koa",
|
| 568 |
+
"i",
|
| 569 |
+
"FreeimageFormat",
|
| 570 |
+
"imageio.plugins.freeimage",
|
| 571 |
+
),
|
| 572 |
+
# not registered in legacy pillow
|
| 573 |
+
# ("MNG", 6, "Multiple-image Network Graphics", ".mng", "i", "FreeimageFormat", "imageio.plugins.freeimage"),
|
| 574 |
+
(
|
| 575 |
+
"PBM",
|
| 576 |
+
7,
|
| 577 |
+
"Portable Bitmap (ASCII)",
|
| 578 |
+
".pbm",
|
| 579 |
+
"i",
|
| 580 |
+
"FreeimageFormat",
|
| 581 |
+
"imageio.plugins.freeimage",
|
| 582 |
+
),
|
| 583 |
+
(
|
| 584 |
+
"PBMRAW",
|
| 585 |
+
8,
|
| 586 |
+
"Portable Bitmap (RAW)",
|
| 587 |
+
".pbm",
|
| 588 |
+
"i",
|
| 589 |
+
"FreeimageFormat",
|
| 590 |
+
"imageio.plugins.freeimage",
|
| 591 |
+
),
|
| 592 |
+
(
|
| 593 |
+
"PCD",
|
| 594 |
+
9,
|
| 595 |
+
"Kodak PhotoCD",
|
| 596 |
+
".pcd",
|
| 597 |
+
"i",
|
| 598 |
+
"FreeimageFormat",
|
| 599 |
+
"imageio.plugins.freeimage",
|
| 600 |
+
),
|
| 601 |
+
(
|
| 602 |
+
"PCX",
|
| 603 |
+
10,
|
| 604 |
+
"Zsoft Paintbrush",
|
| 605 |
+
".pcx",
|
| 606 |
+
"i",
|
| 607 |
+
"FreeimageFormat",
|
| 608 |
+
"imageio.plugins.freeimage",
|
| 609 |
+
),
|
| 610 |
+
(
|
| 611 |
+
"PFM",
|
| 612 |
+
32,
|
| 613 |
+
"Portable floatmap",
|
| 614 |
+
".pfm",
|
| 615 |
+
"i",
|
| 616 |
+
"FreeimageFormat",
|
| 617 |
+
"imageio.plugins.freeimage",
|
| 618 |
+
),
|
| 619 |
+
(
|
| 620 |
+
"PGM",
|
| 621 |
+
11,
|
| 622 |
+
"Portable Greymap (ASCII)",
|
| 623 |
+
".pgm",
|
| 624 |
+
"i",
|
| 625 |
+
"FreeimageFormat",
|
| 626 |
+
"imageio.plugins.freeimage",
|
| 627 |
+
),
|
| 628 |
+
(
|
| 629 |
+
"PGMRAW",
|
| 630 |
+
12,
|
| 631 |
+
"Portable Greymap (RAW)",
|
| 632 |
+
".pgm",
|
| 633 |
+
"i",
|
| 634 |
+
"FreeimageFormat",
|
| 635 |
+
"imageio.plugins.freeimage",
|
| 636 |
+
),
|
| 637 |
+
(
|
| 638 |
+
"PICT",
|
| 639 |
+
33,
|
| 640 |
+
"Macintosh PICT",
|
| 641 |
+
".pct .pict .pic",
|
| 642 |
+
"i",
|
| 643 |
+
"FreeimageFormat",
|
| 644 |
+
"imageio.plugins.freeimage",
|
| 645 |
+
),
|
| 646 |
+
(
|
| 647 |
+
"PNG",
|
| 648 |
+
13,
|
| 649 |
+
"Portable Network Graphics",
|
| 650 |
+
".png",
|
| 651 |
+
"i",
|
| 652 |
+
"FreeimagePngFormat",
|
| 653 |
+
"imageio.plugins.freeimage",
|
| 654 |
+
),
|
| 655 |
+
(
|
| 656 |
+
"PPM",
|
| 657 |
+
14,
|
| 658 |
+
"Portable Pixelmap (ASCII)",
|
| 659 |
+
".ppm",
|
| 660 |
+
"i",
|
| 661 |
+
"FreeimagePnmFormat",
|
| 662 |
+
"imageio.plugins.freeimage",
|
| 663 |
+
),
|
| 664 |
+
(
|
| 665 |
+
"PPMRAW",
|
| 666 |
+
15,
|
| 667 |
+
"Portable Pixelmap (RAW)",
|
| 668 |
+
".ppm",
|
| 669 |
+
"i",
|
| 670 |
+
"FreeimagePnmFormat",
|
| 671 |
+
"imageio.plugins.freeimage",
|
| 672 |
+
),
|
| 673 |
+
(
|
| 674 |
+
"PSD",
|
| 675 |
+
20,
|
| 676 |
+
"Adobe Photoshop",
|
| 677 |
+
".psd",
|
| 678 |
+
"i",
|
| 679 |
+
"FreeimageFormat",
|
| 680 |
+
"imageio.plugins.freeimage",
|
| 681 |
+
),
|
| 682 |
+
(
|
| 683 |
+
"RAS",
|
| 684 |
+
16,
|
| 685 |
+
"Sun Raster Image",
|
| 686 |
+
".ras",
|
| 687 |
+
"i",
|
| 688 |
+
"FreeimageFormat",
|
| 689 |
+
"imageio.plugins.freeimage",
|
| 690 |
+
),
|
| 691 |
+
(
|
| 692 |
+
"RAW",
|
| 693 |
+
34,
|
| 694 |
+
"RAW camera image",
|
| 695 |
+
".3fr .arw .bay .bmq .cap .cine .cr2 .crw .cs1 .dc2 "
|
| 696 |
+
".dcr .drf .dsc .dng .erf .fff .ia .iiq .k25 .kc2 .kdc .mdc .mef .mos .mrw .nef .nrw .orf "
|
| 697 |
+
".pef .ptx .pxn .qtk .raf .raw .rdc .rw2 .rwl .rwz .sr2 .srf .srw .sti",
|
| 698 |
+
"i",
|
| 699 |
+
"FreeimageFormat",
|
| 700 |
+
"imageio.plugins.freeimage",
|
| 701 |
+
),
|
| 702 |
+
(
|
| 703 |
+
"SGI",
|
| 704 |
+
28,
|
| 705 |
+
"SGI Image Format",
|
| 706 |
+
".sgi .rgb .rgba .bw",
|
| 707 |
+
"i",
|
| 708 |
+
"FreeimageFormat",
|
| 709 |
+
"imageio.plugins.freeimage",
|
| 710 |
+
),
|
| 711 |
+
(
|
| 712 |
+
"TARGA",
|
| 713 |
+
17,
|
| 714 |
+
"Truevision Targa",
|
| 715 |
+
".tga .targa",
|
| 716 |
+
"i",
|
| 717 |
+
"FreeimageFormat",
|
| 718 |
+
"imageio.plugins.freeimage",
|
| 719 |
+
),
|
| 720 |
+
(
|
| 721 |
+
"TIFF",
|
| 722 |
+
18,
|
| 723 |
+
"Tagged Image File Format",
|
| 724 |
+
".tif .tiff",
|
| 725 |
+
"i",
|
| 726 |
+
"FreeimageFormat",
|
| 727 |
+
"imageio.plugins.freeimage",
|
| 728 |
+
),
|
| 729 |
+
(
|
| 730 |
+
"WBMP",
|
| 731 |
+
19,
|
| 732 |
+
"Wireless Bitmap",
|
| 733 |
+
".wap .wbmp .wbm",
|
| 734 |
+
"i",
|
| 735 |
+
"FreeimageFormat",
|
| 736 |
+
"imageio.plugins.freeimage",
|
| 737 |
+
),
|
| 738 |
+
(
|
| 739 |
+
"WebP",
|
| 740 |
+
35,
|
| 741 |
+
"Google WebP image format",
|
| 742 |
+
".webp",
|
| 743 |
+
"i",
|
| 744 |
+
"FreeimageFormat",
|
| 745 |
+
"imageio.plugins.freeimage",
|
| 746 |
+
),
|
| 747 |
+
(
|
| 748 |
+
"XBM",
|
| 749 |
+
22,
|
| 750 |
+
"X11 Bitmap Format",
|
| 751 |
+
".xbm",
|
| 752 |
+
"i",
|
| 753 |
+
"FreeimageFormat",
|
| 754 |
+
"imageio.plugins.freeimage",
|
| 755 |
+
),
|
| 756 |
+
(
|
| 757 |
+
"XPM",
|
| 758 |
+
23,
|
| 759 |
+
"X11 Pixmap Format",
|
| 760 |
+
".xpm",
|
| 761 |
+
"i",
|
| 762 |
+
"FreeimageFormat",
|
| 763 |
+
"imageio.plugins.freeimage",
|
| 764 |
+
),
|
| 765 |
+
]
|
| 766 |
+
for name, i, des, ext, mode, class_name, module_name in FREEIMAGE_FORMATS:
|
| 767 |
+
config = PluginConfig(
|
| 768 |
+
name=name.upper() + "-FI",
|
| 769 |
+
class_name=class_name,
|
| 770 |
+
module_name=module_name,
|
| 771 |
+
is_legacy=True,
|
| 772 |
+
install_name="freeimage",
|
| 773 |
+
legacy_args={
|
| 774 |
+
"description": des,
|
| 775 |
+
"extensions": ext,
|
| 776 |
+
"modes": mode,
|
| 777 |
+
"fif": i,
|
| 778 |
+
},
|
| 779 |
+
)
|
| 780 |
+
known_plugins[config.name] = config
|
| 781 |
+
|
| 782 |
+
# exists for backwards compatibility with FormatManager
|
| 783 |
+
# delete in V3
|
| 784 |
+
_original_order = [x for x, config in known_plugins.items() if config.is_legacy]
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
| 3 |
+
|
| 4 |
+
""" This subpackage provides the core functionality of imageio
|
| 5 |
+
(everything but the plugins).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
# flake8: noqa
|
| 9 |
+
|
| 10 |
+
from .util import Image, Array, Dict, asarray, image_as_uint, urlopen
|
| 11 |
+
from .util import BaseProgressIndicator, StdoutProgressIndicator, IS_PYPY
|
| 12 |
+
from .util import get_platform, appdata_dir, resource_dirs, has_module
|
| 13 |
+
from .findlib import load_lib
|
| 14 |
+
from .fetching import get_remote_file, InternetNotAllowedError, NeedDownloadError
|
| 15 |
+
from .request import Request, read_n_bytes, RETURN_BYTES
|
| 16 |
+
from .format import Format, FormatManager
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (890 Bytes). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/legacy_plugin_wrapper.cpython-38.pyc
ADDED
|
Binary file (9.67 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/__pycache__/request.cpython-38.pyc
ADDED
|
Binary file (19.8 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/findlib.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# Copyright (c) 2015-1018, imageio contributors
|
| 3 |
+
# Copyright (C) 2013, Zach Pincus, Almar Klein and others
|
| 4 |
+
|
| 5 |
+
""" This module contains generic code to find and load a dynamic library.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import os
|
| 9 |
+
import sys
|
| 10 |
+
import ctypes
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
LOCALDIR = os.path.abspath(os.path.dirname(__file__))
|
| 14 |
+
|
| 15 |
+
# Flag that can be patched / set to True to disable loading non-system libs
|
| 16 |
+
SYSTEM_LIBS_ONLY = False
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def looks_lib(fname):
|
| 20 |
+
"""Returns True if the given filename looks like a dynamic library.
|
| 21 |
+
Based on extension, but cross-platform and more flexible.
|
| 22 |
+
"""
|
| 23 |
+
fname = fname.lower()
|
| 24 |
+
if sys.platform.startswith("win"):
|
| 25 |
+
return fname.endswith(".dll")
|
| 26 |
+
elif sys.platform.startswith("darwin"):
|
| 27 |
+
return fname.endswith(".dylib")
|
| 28 |
+
else:
|
| 29 |
+
return fname.endswith(".so") or ".so." in fname
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def generate_candidate_libs(lib_names, lib_dirs=None):
|
| 33 |
+
"""Generate a list of candidate filenames of what might be the dynamic
|
| 34 |
+
library corresponding with the given list of names.
|
| 35 |
+
Returns (lib_dirs, lib_paths)
|
| 36 |
+
"""
|
| 37 |
+
lib_dirs = lib_dirs or []
|
| 38 |
+
|
| 39 |
+
# Get system dirs to search
|
| 40 |
+
sys_lib_dirs = [
|
| 41 |
+
"/lib",
|
| 42 |
+
"/usr/lib",
|
| 43 |
+
"/usr/lib/x86_64-linux-gnu",
|
| 44 |
+
"/usr/lib/aarch64-linux-gnu",
|
| 45 |
+
"/usr/local/lib",
|
| 46 |
+
"/opt/local/lib",
|
| 47 |
+
]
|
| 48 |
+
|
| 49 |
+
# Get Python dirs to search (shared if for Pyzo)
|
| 50 |
+
py_sub_dirs = ["bin", "lib", "DLLs", "Library/bin", "shared"]
|
| 51 |
+
py_lib_dirs = [os.path.join(sys.prefix, d) for d in py_sub_dirs]
|
| 52 |
+
if hasattr(sys, "base_prefix"):
|
| 53 |
+
py_lib_dirs += [os.path.join(sys.base_prefix, d) for d in py_sub_dirs]
|
| 54 |
+
|
| 55 |
+
# Get user dirs to search (i.e. HOME)
|
| 56 |
+
home_dir = os.path.expanduser("~")
|
| 57 |
+
user_lib_dirs = [os.path.join(home_dir, d) for d in ["lib"]]
|
| 58 |
+
|
| 59 |
+
# Select only the dirs for which a directory exists, and remove duplicates
|
| 60 |
+
potential_lib_dirs = lib_dirs + sys_lib_dirs + py_lib_dirs + user_lib_dirs
|
| 61 |
+
lib_dirs = []
|
| 62 |
+
for ld in potential_lib_dirs:
|
| 63 |
+
if os.path.isdir(ld) and ld not in lib_dirs:
|
| 64 |
+
lib_dirs.append(ld)
|
| 65 |
+
|
| 66 |
+
# Now attempt to find libraries of that name in the given directory
|
| 67 |
+
# (case-insensitive)
|
| 68 |
+
lib_paths = []
|
| 69 |
+
for lib_dir in lib_dirs:
|
| 70 |
+
# Get files, prefer short names, last version
|
| 71 |
+
files = os.listdir(lib_dir)
|
| 72 |
+
files = reversed(sorted(files))
|
| 73 |
+
files = sorted(files, key=len)
|
| 74 |
+
for lib_name in lib_names:
|
| 75 |
+
# Test all filenames for name and ext
|
| 76 |
+
for fname in files:
|
| 77 |
+
if fname.lower().startswith(lib_name) and looks_lib(fname):
|
| 78 |
+
lib_paths.append(os.path.join(lib_dir, fname))
|
| 79 |
+
|
| 80 |
+
# Return (only the items which are files)
|
| 81 |
+
lib_paths = [lp for lp in lib_paths if os.path.isfile(lp)]
|
| 82 |
+
return lib_dirs, lib_paths
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def load_lib(exact_lib_names, lib_names, lib_dirs=None):
|
| 86 |
+
"""load_lib(exact_lib_names, lib_names, lib_dirs=None)
|
| 87 |
+
|
| 88 |
+
Load a dynamic library.
|
| 89 |
+
|
| 90 |
+
This function first tries to load the library from the given exact
|
| 91 |
+
names. When that fails, it tries to find the library in common
|
| 92 |
+
locations. It searches for files that start with one of the names
|
| 93 |
+
given in lib_names (case insensitive). The search is performed in
|
| 94 |
+
the given lib_dirs and a set of common library dirs.
|
| 95 |
+
|
| 96 |
+
Returns ``(ctypes_library, library_path)``
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
# Checks
|
| 100 |
+
assert isinstance(exact_lib_names, list)
|
| 101 |
+
assert isinstance(lib_names, list)
|
| 102 |
+
if lib_dirs is not None:
|
| 103 |
+
assert isinstance(lib_dirs, list)
|
| 104 |
+
exact_lib_names = [n for n in exact_lib_names if n]
|
| 105 |
+
lib_names = [n for n in lib_names if n]
|
| 106 |
+
|
| 107 |
+
# Get reference name (for better messages)
|
| 108 |
+
if lib_names:
|
| 109 |
+
the_lib_name = lib_names[0]
|
| 110 |
+
elif exact_lib_names:
|
| 111 |
+
the_lib_name = exact_lib_names[0]
|
| 112 |
+
else:
|
| 113 |
+
raise ValueError("No library name given.")
|
| 114 |
+
|
| 115 |
+
# Collect filenames of potential libraries
|
| 116 |
+
# First try a few bare library names that ctypes might be able to find
|
| 117 |
+
# in the default locations for each platform.
|
| 118 |
+
if SYSTEM_LIBS_ONLY:
|
| 119 |
+
lib_dirs, lib_paths = [], []
|
| 120 |
+
else:
|
| 121 |
+
lib_dirs, lib_paths = generate_candidate_libs(lib_names, lib_dirs)
|
| 122 |
+
lib_paths = exact_lib_names + lib_paths
|
| 123 |
+
|
| 124 |
+
# Select loader
|
| 125 |
+
if sys.platform.startswith("win"):
|
| 126 |
+
loader = ctypes.windll
|
| 127 |
+
else:
|
| 128 |
+
loader = ctypes.cdll
|
| 129 |
+
|
| 130 |
+
# Try to load until success
|
| 131 |
+
the_lib = None
|
| 132 |
+
errors = []
|
| 133 |
+
for fname in lib_paths:
|
| 134 |
+
try:
|
| 135 |
+
the_lib = loader.LoadLibrary(fname)
|
| 136 |
+
break
|
| 137 |
+
except Exception as err:
|
| 138 |
+
# Don't record errors when it couldn't load the library from an
|
| 139 |
+
# exact name -- this fails often, and doesn't provide any useful
|
| 140 |
+
# debugging information anyway, beyond "couldn't find library..."
|
| 141 |
+
if fname not in exact_lib_names:
|
| 142 |
+
errors.append((fname, err))
|
| 143 |
+
|
| 144 |
+
# No success ...
|
| 145 |
+
if the_lib is None:
|
| 146 |
+
if errors:
|
| 147 |
+
# No library loaded, and load-errors reported for some
|
| 148 |
+
# candidate libs
|
| 149 |
+
err_txt = ["%s:\n%s" % (lib, str(e)) for lib, e in errors]
|
| 150 |
+
msg = (
|
| 151 |
+
"One or more %s libraries were found, but "
|
| 152 |
+
+ "could not be loaded due to the following errors:\n%s"
|
| 153 |
+
)
|
| 154 |
+
raise OSError(msg % (the_lib_name, "\n\n".join(err_txt)))
|
| 155 |
+
else:
|
| 156 |
+
# No errors, because no potential libraries found at all!
|
| 157 |
+
msg = "Could not find a %s library in any of:\n%s"
|
| 158 |
+
raise OSError(msg % (the_lib_name, "\n".join(lib_dirs)))
|
| 159 |
+
|
| 160 |
+
# Done
|
| 161 |
+
return the_lib, fname
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/format.py
ADDED
|
@@ -0,0 +1,856 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
.. note::
|
| 7 |
+
imageio is under construction, some details with regard to the
|
| 8 |
+
Reader and Writer classes may change.
|
| 9 |
+
|
| 10 |
+
These are the main classes of imageio. They expose an interface for
|
| 11 |
+
advanced users and plugin developers. A brief overview:
|
| 12 |
+
|
| 13 |
+
* imageio.FormatManager - for keeping track of registered formats.
|
| 14 |
+
* imageio.Format - representation of a file format reader/writer
|
| 15 |
+
* imageio.Format.Reader - object used during the reading of a file.
|
| 16 |
+
* imageio.Format.Writer - object used during saving a file.
|
| 17 |
+
* imageio.Request - used to store the filename and other info.
|
| 18 |
+
|
| 19 |
+
Plugins need to implement a Format class and register
|
| 20 |
+
a format object using ``imageio.formats.add_format()``.
|
| 21 |
+
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
# todo: do we even use the known extensions?
|
| 25 |
+
|
| 26 |
+
# Some notes:
|
| 27 |
+
#
|
| 28 |
+
# The classes in this module use the Request object to pass filename and
|
| 29 |
+
# related info around. This request object is instantiated in
|
| 30 |
+
# imageio.get_reader and imageio.get_writer.
|
| 31 |
+
|
| 32 |
+
import sys
|
| 33 |
+
import warnings
|
| 34 |
+
|
| 35 |
+
import numpy as np
|
| 36 |
+
from pathlib import Path
|
| 37 |
+
|
| 38 |
+
from . import Array, asarray
|
| 39 |
+
from .request import ImageMode
|
| 40 |
+
from ..config import known_plugins, known_extensions, PluginConfig, FileExtension
|
| 41 |
+
from ..config.plugins import _original_order
|
| 42 |
+
from .imopen import imopen
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
# survived for backwards compatibility
|
| 46 |
+
# I don't know if external plugin code depends on it existing
|
| 47 |
+
# We no longer do
|
| 48 |
+
MODENAMES = ImageMode
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def _get_config(plugin):
|
| 52 |
+
"""Old Plugin resolution logic.
|
| 53 |
+
|
| 54 |
+
Remove once we remove the old format manager.
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
extension_name = None
|
| 58 |
+
|
| 59 |
+
if Path(plugin).suffix.lower() in known_extensions:
|
| 60 |
+
extension_name = Path(plugin).suffix.lower()
|
| 61 |
+
elif plugin in known_plugins:
|
| 62 |
+
pass
|
| 63 |
+
elif plugin.lower() in known_extensions:
|
| 64 |
+
extension_name = plugin.lower()
|
| 65 |
+
elif "." + plugin.lower() in known_extensions:
|
| 66 |
+
extension_name = "." + plugin.lower()
|
| 67 |
+
else:
|
| 68 |
+
raise IndexError(f"No format known by name `{plugin}`.")
|
| 69 |
+
|
| 70 |
+
if extension_name is not None:
|
| 71 |
+
for plugin_name in [
|
| 72 |
+
x
|
| 73 |
+
for file_extension in known_extensions[extension_name]
|
| 74 |
+
for x in file_extension.priority
|
| 75 |
+
]:
|
| 76 |
+
if known_plugins[plugin_name].is_legacy:
|
| 77 |
+
plugin = plugin_name
|
| 78 |
+
break
|
| 79 |
+
|
| 80 |
+
return known_plugins[plugin]
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class Format(object):
|
| 84 |
+
"""Represents an implementation to read/write a particular file format
|
| 85 |
+
|
| 86 |
+
A format instance is responsible for 1) providing information about
|
| 87 |
+
a format; 2) determining whether a certain file can be read/written
|
| 88 |
+
with this format; 3) providing a reader/writer class.
|
| 89 |
+
|
| 90 |
+
Generally, imageio will select the right format and use that to
|
| 91 |
+
read/write an image. A format can also be explicitly chosen in all
|
| 92 |
+
read/write functions. Use ``print(format)``, or ``help(format_name)``
|
| 93 |
+
to see its documentation.
|
| 94 |
+
|
| 95 |
+
To implement a specific format, one should create a subclass of
|
| 96 |
+
Format and the Format.Reader and Format.Writer classes. See
|
| 97 |
+
:class:`imageio.plugins` for details.
|
| 98 |
+
|
| 99 |
+
Parameters
|
| 100 |
+
----------
|
| 101 |
+
name : str
|
| 102 |
+
A short name of this format. Users can select a format using its name.
|
| 103 |
+
description : str
|
| 104 |
+
A one-line description of the format.
|
| 105 |
+
extensions : str | list | None
|
| 106 |
+
List of filename extensions that this format supports. If a
|
| 107 |
+
string is passed it should be space or comma separated. The
|
| 108 |
+
extensions are used in the documentation and to allow users to
|
| 109 |
+
select a format by file extension. It is not used to determine
|
| 110 |
+
what format to use for reading/saving a file.
|
| 111 |
+
modes : str
|
| 112 |
+
A string containing the modes that this format can handle ('iIvV'),
|
| 113 |
+
“i” for an image, “I” for multiple images, “v” for a volume,
|
| 114 |
+
“V” for multiple volumes.
|
| 115 |
+
This attribute is used in the documentation and to select the
|
| 116 |
+
formats when reading/saving a file.
|
| 117 |
+
"""
|
| 118 |
+
|
| 119 |
+
def __init__(self, name, description, extensions=None, modes=None):
|
| 120 |
+
"""Initialize the Plugin.
|
| 121 |
+
|
| 122 |
+
Parameters
|
| 123 |
+
----------
|
| 124 |
+
name : str
|
| 125 |
+
A short name of this format. Users can select a format using its name.
|
| 126 |
+
description : str
|
| 127 |
+
A one-line description of the format.
|
| 128 |
+
extensions : str | list | None
|
| 129 |
+
List of filename extensions that this format supports. If a
|
| 130 |
+
string is passed it should be space or comma separated. The
|
| 131 |
+
extensions are used in the documentation and to allow users to
|
| 132 |
+
select a format by file extension. It is not used to determine
|
| 133 |
+
what format to use for reading/saving a file.
|
| 134 |
+
modes : str
|
| 135 |
+
A string containing the modes that this format can handle ('iIvV'),
|
| 136 |
+
“i” for an image, “I” for multiple images, “v” for a volume,
|
| 137 |
+
“V” for multiple volumes.
|
| 138 |
+
This attribute is used in the documentation and to select the
|
| 139 |
+
formats when reading/saving a file.
|
| 140 |
+
"""
|
| 141 |
+
|
| 142 |
+
# Store name and description
|
| 143 |
+
self._name = name.upper()
|
| 144 |
+
self._description = description
|
| 145 |
+
|
| 146 |
+
# Store extensions, do some effort to normalize them.
|
| 147 |
+
# They are stored as a list of lowercase strings without leading dots.
|
| 148 |
+
if extensions is None:
|
| 149 |
+
extensions = []
|
| 150 |
+
elif isinstance(extensions, str):
|
| 151 |
+
extensions = extensions.replace(",", " ").split(" ")
|
| 152 |
+
#
|
| 153 |
+
if isinstance(extensions, (tuple, list)):
|
| 154 |
+
self._extensions = tuple(
|
| 155 |
+
["." + e.strip(".").lower() for e in extensions if e]
|
| 156 |
+
)
|
| 157 |
+
else:
|
| 158 |
+
raise ValueError("Invalid value for extensions given.")
|
| 159 |
+
|
| 160 |
+
# Store mode
|
| 161 |
+
self._modes = modes or ""
|
| 162 |
+
if not isinstance(self._modes, str):
|
| 163 |
+
raise ValueError("Invalid value for modes given.")
|
| 164 |
+
for m in self._modes:
|
| 165 |
+
if m not in "iIvV?":
|
| 166 |
+
raise ValueError("Invalid value for mode given.")
|
| 167 |
+
|
| 168 |
+
def __repr__(self):
|
| 169 |
+
# Short description
|
| 170 |
+
return "<Format %s - %s>" % (self.name, self.description)
|
| 171 |
+
|
| 172 |
+
def __str__(self):
|
| 173 |
+
return self.doc
|
| 174 |
+
|
| 175 |
+
@property
|
| 176 |
+
def doc(self):
|
| 177 |
+
"""The documentation for this format (name + description + docstring)."""
|
| 178 |
+
# Our docsring is assumed to be indented by four spaces. The
|
| 179 |
+
# first line needs special attention.
|
| 180 |
+
return "%s - %s\n\n %s\n" % (
|
| 181 |
+
self.name,
|
| 182 |
+
self.description,
|
| 183 |
+
self.__doc__.strip(),
|
| 184 |
+
)
|
| 185 |
+
|
| 186 |
+
@property
|
| 187 |
+
def name(self):
|
| 188 |
+
"""The name of this format."""
|
| 189 |
+
return self._name
|
| 190 |
+
|
| 191 |
+
@property
|
| 192 |
+
def description(self):
|
| 193 |
+
"""A short description of this format."""
|
| 194 |
+
return self._description
|
| 195 |
+
|
| 196 |
+
@property
|
| 197 |
+
def extensions(self):
|
| 198 |
+
"""A list of file extensions supported by this plugin.
|
| 199 |
+
These are all lowercase with a leading dot.
|
| 200 |
+
"""
|
| 201 |
+
return self._extensions
|
| 202 |
+
|
| 203 |
+
@property
|
| 204 |
+
def modes(self):
|
| 205 |
+
"""A string specifying the modes that this format can handle."""
|
| 206 |
+
return self._modes
|
| 207 |
+
|
| 208 |
+
def get_reader(self, request):
|
| 209 |
+
"""get_reader(request)
|
| 210 |
+
|
| 211 |
+
Return a reader object that can be used to read data and info
|
| 212 |
+
from the given file. Users are encouraged to use
|
| 213 |
+
imageio.get_reader() instead.
|
| 214 |
+
"""
|
| 215 |
+
select_mode = request.mode[1] if request.mode[1] in "iIvV" else ""
|
| 216 |
+
if select_mode not in self.modes:
|
| 217 |
+
raise RuntimeError(
|
| 218 |
+
f"Format {self.name} cannot read in {request.mode.image_mode} mode"
|
| 219 |
+
)
|
| 220 |
+
return self.Reader(self, request)
|
| 221 |
+
|
| 222 |
+
def get_writer(self, request):
|
| 223 |
+
"""get_writer(request)
|
| 224 |
+
|
| 225 |
+
Return a writer object that can be used to write data and info
|
| 226 |
+
to the given file. Users are encouraged to use
|
| 227 |
+
imageio.get_writer() instead.
|
| 228 |
+
"""
|
| 229 |
+
select_mode = request.mode[1] if request.mode[1] in "iIvV" else ""
|
| 230 |
+
if select_mode not in self.modes:
|
| 231 |
+
raise RuntimeError(
|
| 232 |
+
f"Format {self.name} cannot write in {request.mode.image_mode} mode"
|
| 233 |
+
)
|
| 234 |
+
return self.Writer(self, request)
|
| 235 |
+
|
| 236 |
+
def can_read(self, request):
|
| 237 |
+
"""can_read(request)
|
| 238 |
+
|
| 239 |
+
Get whether this format can read data from the specified uri.
|
| 240 |
+
"""
|
| 241 |
+
return self._can_read(request)
|
| 242 |
+
|
| 243 |
+
def can_write(self, request):
|
| 244 |
+
"""can_write(request)
|
| 245 |
+
|
| 246 |
+
Get whether this format can write data to the speciefed uri.
|
| 247 |
+
"""
|
| 248 |
+
return self._can_write(request)
|
| 249 |
+
|
| 250 |
+
def _can_read(self, request): # pragma: no cover
|
| 251 |
+
"""Check if Plugin can read from ImageResource.
|
| 252 |
+
|
| 253 |
+
This method is called when the format manager is searching for a format
|
| 254 |
+
to read a certain image. Return True if this format can do it.
|
| 255 |
+
|
| 256 |
+
The format manager is aware of the extensions and the modes that each
|
| 257 |
+
format can handle. It will first ask all formats that *seem* to be able
|
| 258 |
+
to read it whether they can. If none can, it will ask the remaining
|
| 259 |
+
formats if they can: the extension might be missing, and this allows
|
| 260 |
+
formats to provide functionality for certain extensions, while giving
|
| 261 |
+
preference to other plugins.
|
| 262 |
+
|
| 263 |
+
If a format says it can, it should live up to it. The format would
|
| 264 |
+
ideally check the request.firstbytes and look for a header of some kind.
|
| 265 |
+
|
| 266 |
+
Parameters
|
| 267 |
+
----------
|
| 268 |
+
request : Request
|
| 269 |
+
A request that can be used to access the ImageResource and obtain
|
| 270 |
+
metadata about it.
|
| 271 |
+
|
| 272 |
+
Returns
|
| 273 |
+
-------
|
| 274 |
+
can_read : bool
|
| 275 |
+
True if the plugin can read from the ImageResource, False otherwise.
|
| 276 |
+
|
| 277 |
+
"""
|
| 278 |
+
return None # Plugins must implement this
|
| 279 |
+
|
| 280 |
+
def _can_write(self, request): # pragma: no cover
|
| 281 |
+
"""Check if Plugin can write to ImageResource.
|
| 282 |
+
|
| 283 |
+
Parameters
|
| 284 |
+
----------
|
| 285 |
+
request : Request
|
| 286 |
+
A request that can be used to access the ImageResource and obtain
|
| 287 |
+
metadata about it.
|
| 288 |
+
|
| 289 |
+
Returns
|
| 290 |
+
-------
|
| 291 |
+
can_read : bool
|
| 292 |
+
True if the plugin can write to the ImageResource, False otherwise.
|
| 293 |
+
|
| 294 |
+
"""
|
| 295 |
+
return None # Plugins must implement this
|
| 296 |
+
|
| 297 |
+
# -----
|
| 298 |
+
|
| 299 |
+
class _BaseReaderWriter(object):
|
| 300 |
+
"""Base class for the Reader and Writer class to implement common
|
| 301 |
+
functionality. It implements a similar approach for opening/closing
|
| 302 |
+
and context management as Python's file objects.
|
| 303 |
+
"""
|
| 304 |
+
|
| 305 |
+
def __init__(self, format, request):
|
| 306 |
+
self.__closed = False
|
| 307 |
+
self._BaseReaderWriter_last_index = -1
|
| 308 |
+
self._format = format
|
| 309 |
+
self._request = request
|
| 310 |
+
# Open the reader/writer
|
| 311 |
+
self._open(**self.request.kwargs.copy())
|
| 312 |
+
|
| 313 |
+
@property
|
| 314 |
+
def format(self):
|
| 315 |
+
"""The :class:`.Format` object corresponding to the current
|
| 316 |
+
read/write operation.
|
| 317 |
+
"""
|
| 318 |
+
return self._format
|
| 319 |
+
|
| 320 |
+
@property
|
| 321 |
+
def request(self):
|
| 322 |
+
"""The :class:`.Request` object corresponding to the
|
| 323 |
+
current read/write operation.
|
| 324 |
+
"""
|
| 325 |
+
return self._request
|
| 326 |
+
|
| 327 |
+
def __enter__(self):
|
| 328 |
+
self._checkClosed()
|
| 329 |
+
return self
|
| 330 |
+
|
| 331 |
+
def __exit__(self, type, value, traceback):
|
| 332 |
+
if value is None:
|
| 333 |
+
# Otherwise error in close hide the real error.
|
| 334 |
+
self.close()
|
| 335 |
+
|
| 336 |
+
def __del__(self):
|
| 337 |
+
try:
|
| 338 |
+
self.close()
|
| 339 |
+
except Exception: # pragma: no cover
|
| 340 |
+
pass # Supress noise when called during interpreter shutdown
|
| 341 |
+
|
| 342 |
+
def close(self):
|
| 343 |
+
"""Flush and close the reader/writer.
|
| 344 |
+
This method has no effect if it is already closed.
|
| 345 |
+
"""
|
| 346 |
+
if self.__closed:
|
| 347 |
+
return
|
| 348 |
+
self.__closed = True
|
| 349 |
+
self._close()
|
| 350 |
+
# Process results and clean request object
|
| 351 |
+
self.request.finish()
|
| 352 |
+
|
| 353 |
+
@property
|
| 354 |
+
def closed(self):
|
| 355 |
+
"""Whether the reader/writer is closed."""
|
| 356 |
+
return self.__closed
|
| 357 |
+
|
| 358 |
+
def _checkClosed(self, msg=None):
|
| 359 |
+
"""Internal: raise an ValueError if reader/writer is closed"""
|
| 360 |
+
if self.closed:
|
| 361 |
+
what = self.__class__.__name__
|
| 362 |
+
msg = msg or ("I/O operation on closed %s." % what)
|
| 363 |
+
raise RuntimeError(msg)
|
| 364 |
+
|
| 365 |
+
# To implement
|
| 366 |
+
|
| 367 |
+
def _open(self, **kwargs):
|
| 368 |
+
"""_open(**kwargs)
|
| 369 |
+
|
| 370 |
+
Plugins should probably implement this.
|
| 371 |
+
|
| 372 |
+
It is called when reader/writer is created. Here the
|
| 373 |
+
plugin can do its initialization. The given keyword arguments
|
| 374 |
+
are those that were given by the user at imageio.read() or
|
| 375 |
+
imageio.write().
|
| 376 |
+
"""
|
| 377 |
+
raise NotImplementedError()
|
| 378 |
+
|
| 379 |
+
def _close(self):
|
| 380 |
+
"""_close()
|
| 381 |
+
|
| 382 |
+
Plugins should probably implement this.
|
| 383 |
+
|
| 384 |
+
It is called when the reader/writer is closed. Here the plugin
|
| 385 |
+
can do a cleanup, flush, etc.
|
| 386 |
+
|
| 387 |
+
"""
|
| 388 |
+
raise NotImplementedError()
|
| 389 |
+
|
| 390 |
+
# -----
|
| 391 |
+
|
| 392 |
+
class Reader(_BaseReaderWriter):
|
| 393 |
+
"""
|
| 394 |
+
The purpose of a reader object is to read data from an image
|
| 395 |
+
resource, and should be obtained by calling :func:`.get_reader`.
|
| 396 |
+
|
| 397 |
+
A reader can be used as an iterator to read multiple images,
|
| 398 |
+
and (if the format permits) only reads data from the file when
|
| 399 |
+
new data is requested (i.e. streaming). A reader can also be
|
| 400 |
+
used as a context manager so that it is automatically closed.
|
| 401 |
+
|
| 402 |
+
Plugins implement Reader's for different formats. Though rare,
|
| 403 |
+
plugins may provide additional functionality (beyond what is
|
| 404 |
+
provided by the base reader class).
|
| 405 |
+
"""
|
| 406 |
+
|
| 407 |
+
def get_length(self):
|
| 408 |
+
"""get_length()
|
| 409 |
+
|
| 410 |
+
Get the number of images in the file. (Note: you can also
|
| 411 |
+
use ``len(reader_object)``.)
|
| 412 |
+
|
| 413 |
+
The result can be:
|
| 414 |
+
* 0 for files that only have meta data
|
| 415 |
+
* 1 for singleton images (e.g. in PNG, JPEG, etc.)
|
| 416 |
+
* N for image series
|
| 417 |
+
* inf for streams (series of unknown length)
|
| 418 |
+
"""
|
| 419 |
+
return self._get_length()
|
| 420 |
+
|
| 421 |
+
def get_data(self, index, **kwargs):
|
| 422 |
+
"""get_data(index, **kwargs)
|
| 423 |
+
|
| 424 |
+
Read image data from the file, using the image index. The
|
| 425 |
+
returned image has a 'meta' attribute with the meta data.
|
| 426 |
+
Raises IndexError if the index is out of range.
|
| 427 |
+
|
| 428 |
+
Some formats may support additional keyword arguments. These are
|
| 429 |
+
listed in the documentation of those formats.
|
| 430 |
+
"""
|
| 431 |
+
self._checkClosed()
|
| 432 |
+
self._BaseReaderWriter_last_index = index
|
| 433 |
+
try:
|
| 434 |
+
im, meta = self._get_data(index, **kwargs)
|
| 435 |
+
except StopIteration:
|
| 436 |
+
raise IndexError(index)
|
| 437 |
+
return Array(im, meta) # Array tests im and meta
|
| 438 |
+
|
| 439 |
+
def get_next_data(self, **kwargs):
|
| 440 |
+
"""get_next_data(**kwargs)
|
| 441 |
+
|
| 442 |
+
Read the next image from the series.
|
| 443 |
+
|
| 444 |
+
Some formats may support additional keyword arguments. These are
|
| 445 |
+
listed in the documentation of those formats.
|
| 446 |
+
"""
|
| 447 |
+
return self.get_data(self._BaseReaderWriter_last_index + 1, **kwargs)
|
| 448 |
+
|
| 449 |
+
def set_image_index(self, index, **kwargs):
|
| 450 |
+
"""set_image_index(index)
|
| 451 |
+
|
| 452 |
+
Set the internal pointer such that the next call to
|
| 453 |
+
get_next_data() returns the image specified by the index
|
| 454 |
+
"""
|
| 455 |
+
self._checkClosed()
|
| 456 |
+
n = self.get_length()
|
| 457 |
+
self._BaseReaderWriter_last_index = min(max(index - 1, -1), n)
|
| 458 |
+
|
| 459 |
+
def get_meta_data(self, index=None):
|
| 460 |
+
"""get_meta_data(index=None)
|
| 461 |
+
|
| 462 |
+
Read meta data from the file. using the image index. If the
|
| 463 |
+
index is omitted or None, return the file's (global) meta data.
|
| 464 |
+
|
| 465 |
+
Note that ``get_data`` also provides the meta data for the returned
|
| 466 |
+
image as an atrribute of that image.
|
| 467 |
+
|
| 468 |
+
The meta data is a dict, which shape depends on the format.
|
| 469 |
+
E.g. for JPEG, the dict maps group names to subdicts and each
|
| 470 |
+
group is a dict with name-value pairs. The groups represent
|
| 471 |
+
the different metadata formats (EXIF, XMP, etc.).
|
| 472 |
+
"""
|
| 473 |
+
self._checkClosed()
|
| 474 |
+
meta = self._get_meta_data(index)
|
| 475 |
+
if not isinstance(meta, dict):
|
| 476 |
+
raise ValueError(
|
| 477 |
+
"Meta data must be a dict, not %r" % meta.__class__.__name__
|
| 478 |
+
)
|
| 479 |
+
return meta
|
| 480 |
+
|
| 481 |
+
def iter_data(self):
|
| 482 |
+
"""iter_data()
|
| 483 |
+
|
| 484 |
+
Iterate over all images in the series. (Note: you can also
|
| 485 |
+
iterate over the reader object.)
|
| 486 |
+
|
| 487 |
+
"""
|
| 488 |
+
self._checkClosed()
|
| 489 |
+
n = self.get_length()
|
| 490 |
+
i = 0
|
| 491 |
+
while i < n:
|
| 492 |
+
try:
|
| 493 |
+
im, meta = self._get_data(i)
|
| 494 |
+
except StopIteration:
|
| 495 |
+
return
|
| 496 |
+
except IndexError:
|
| 497 |
+
if n == float("inf"):
|
| 498 |
+
return
|
| 499 |
+
raise
|
| 500 |
+
yield Array(im, meta)
|
| 501 |
+
i += 1
|
| 502 |
+
|
| 503 |
+
# Compatibility
|
| 504 |
+
|
| 505 |
+
def __iter__(self):
|
| 506 |
+
return self.iter_data()
|
| 507 |
+
|
| 508 |
+
def __len__(self):
|
| 509 |
+
n = self.get_length()
|
| 510 |
+
if n == float("inf"):
|
| 511 |
+
n = sys.maxsize
|
| 512 |
+
return n
|
| 513 |
+
|
| 514 |
+
# To implement
|
| 515 |
+
|
| 516 |
+
def _get_length(self):
|
| 517 |
+
"""_get_length()
|
| 518 |
+
|
| 519 |
+
Plugins must implement this.
|
| 520 |
+
|
| 521 |
+
The retured scalar specifies the number of images in the series.
|
| 522 |
+
See Reader.get_length for more information.
|
| 523 |
+
"""
|
| 524 |
+
raise NotImplementedError()
|
| 525 |
+
|
| 526 |
+
def _get_data(self, index):
|
| 527 |
+
"""_get_data()
|
| 528 |
+
|
| 529 |
+
Plugins must implement this, but may raise an IndexError in
|
| 530 |
+
case the plugin does not support random access.
|
| 531 |
+
|
| 532 |
+
It should return the image and meta data: (ndarray, dict).
|
| 533 |
+
"""
|
| 534 |
+
raise NotImplementedError()
|
| 535 |
+
|
| 536 |
+
def _get_meta_data(self, index):
|
| 537 |
+
"""_get_meta_data(index)
|
| 538 |
+
|
| 539 |
+
Plugins must implement this.
|
| 540 |
+
|
| 541 |
+
It should return the meta data as a dict, corresponding to the
|
| 542 |
+
given index, or to the file's (global) meta data if index is
|
| 543 |
+
None.
|
| 544 |
+
"""
|
| 545 |
+
raise NotImplementedError()
|
| 546 |
+
|
| 547 |
+
# -----
|
| 548 |
+
|
| 549 |
+
class Writer(_BaseReaderWriter):
|
| 550 |
+
"""
|
| 551 |
+
The purpose of a writer object is to write data to an image
|
| 552 |
+
resource, and should be obtained by calling :func:`.get_writer`.
|
| 553 |
+
|
| 554 |
+
A writer will (if the format permits) write data to the file
|
| 555 |
+
as soon as new data is provided (i.e. streaming). A writer can
|
| 556 |
+
also be used as a context manager so that it is automatically
|
| 557 |
+
closed.
|
| 558 |
+
|
| 559 |
+
Plugins implement Writer's for different formats. Though rare,
|
| 560 |
+
plugins may provide additional functionality (beyond what is
|
| 561 |
+
provided by the base writer class).
|
| 562 |
+
"""
|
| 563 |
+
|
| 564 |
+
def append_data(self, im, meta=None):
|
| 565 |
+
"""append_data(im, meta={})
|
| 566 |
+
|
| 567 |
+
Append an image (and meta data) to the file. The final meta
|
| 568 |
+
data that is used consists of the meta data on the given
|
| 569 |
+
image (if applicable), updated with the given meta data.
|
| 570 |
+
"""
|
| 571 |
+
self._checkClosed()
|
| 572 |
+
# Check image data
|
| 573 |
+
if not isinstance(im, np.ndarray):
|
| 574 |
+
raise ValueError("append_data requires ndarray as first arg")
|
| 575 |
+
# Get total meta dict
|
| 576 |
+
total_meta = {}
|
| 577 |
+
if hasattr(im, "meta") and isinstance(im.meta, dict):
|
| 578 |
+
total_meta.update(im.meta)
|
| 579 |
+
if meta is None:
|
| 580 |
+
pass
|
| 581 |
+
elif not isinstance(meta, dict):
|
| 582 |
+
raise ValueError("Meta must be a dict.")
|
| 583 |
+
else:
|
| 584 |
+
total_meta.update(meta)
|
| 585 |
+
|
| 586 |
+
# Decouple meta info
|
| 587 |
+
im = asarray(im)
|
| 588 |
+
# Call
|
| 589 |
+
return self._append_data(im, total_meta)
|
| 590 |
+
|
| 591 |
+
def set_meta_data(self, meta):
|
| 592 |
+
"""set_meta_data(meta)
|
| 593 |
+
|
| 594 |
+
Sets the file's (global) meta data. The meta data is a dict which
|
| 595 |
+
shape depends on the format. E.g. for JPEG the dict maps
|
| 596 |
+
group names to subdicts, and each group is a dict with
|
| 597 |
+
name-value pairs. The groups represents the different
|
| 598 |
+
metadata formats (EXIF, XMP, etc.).
|
| 599 |
+
|
| 600 |
+
Note that some meta formats may not be supported for
|
| 601 |
+
writing, and individual fields may be ignored without
|
| 602 |
+
warning if they are invalid.
|
| 603 |
+
"""
|
| 604 |
+
self._checkClosed()
|
| 605 |
+
if not isinstance(meta, dict):
|
| 606 |
+
raise ValueError("Meta must be a dict.")
|
| 607 |
+
else:
|
| 608 |
+
return self._set_meta_data(meta)
|
| 609 |
+
|
| 610 |
+
# To implement
|
| 611 |
+
|
| 612 |
+
def _append_data(self, im, meta):
|
| 613 |
+
# Plugins must implement this
|
| 614 |
+
raise NotImplementedError()
|
| 615 |
+
|
| 616 |
+
def _set_meta_data(self, meta):
|
| 617 |
+
# Plugins must implement this
|
| 618 |
+
raise NotImplementedError()
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
class FormatManager(object):
|
| 622 |
+
"""
|
| 623 |
+
The FormatManager is a singleton plugin factory.
|
| 624 |
+
|
| 625 |
+
The format manager supports getting a format object using indexing (by
|
| 626 |
+
format name or extension). When used as an iterator, this object
|
| 627 |
+
yields all registered format objects.
|
| 628 |
+
|
| 629 |
+
See also :func:`.help`.
|
| 630 |
+
"""
|
| 631 |
+
|
| 632 |
+
@property
|
| 633 |
+
def _formats(self):
|
| 634 |
+
return [x for x in known_plugins.values() if x.is_legacy]
|
| 635 |
+
|
| 636 |
+
def __repr__(self):
|
| 637 |
+
return f"<imageio.FormatManager with {len(self._formats)} registered formats>"
|
| 638 |
+
|
| 639 |
+
def __iter__(self):
|
| 640 |
+
return iter(x.format for x in self._formats)
|
| 641 |
+
|
| 642 |
+
def __len__(self):
|
| 643 |
+
return len(self._formats)
|
| 644 |
+
|
| 645 |
+
def __str__(self):
|
| 646 |
+
ss = []
|
| 647 |
+
for config in self._formats:
|
| 648 |
+
ext = config.legacy_args["extensions"]
|
| 649 |
+
desc = config.legacy_args["description"]
|
| 650 |
+
s = f"{config.name} - {desc} [{ext}]"
|
| 651 |
+
ss.append(s)
|
| 652 |
+
return "\n".join(ss)
|
| 653 |
+
|
| 654 |
+
def __getitem__(self, name):
|
| 655 |
+
warnings.warn(
|
| 656 |
+
"The usage of `FormatManager` is deprecated and it will be "
|
| 657 |
+
"removed in Imageio v3. Use `iio.imopen` instead.",
|
| 658 |
+
DeprecationWarning,
|
| 659 |
+
stacklevel=2,
|
| 660 |
+
)
|
| 661 |
+
|
| 662 |
+
if not isinstance(name, str):
|
| 663 |
+
raise ValueError(
|
| 664 |
+
"Looking up a format should be done by name or by extension."
|
| 665 |
+
)
|
| 666 |
+
|
| 667 |
+
if name == "":
|
| 668 |
+
raise ValueError("No format matches the empty string.")
|
| 669 |
+
|
| 670 |
+
# Test if name is existing file
|
| 671 |
+
if Path(name).is_file():
|
| 672 |
+
# legacy compatibility - why test reading here??
|
| 673 |
+
try:
|
| 674 |
+
return imopen(name, "r", legacy_mode=True)._format
|
| 675 |
+
except ValueError:
|
| 676 |
+
# no plugin can read the file
|
| 677 |
+
pass
|
| 678 |
+
|
| 679 |
+
config = _get_config(name.upper())
|
| 680 |
+
|
| 681 |
+
try:
|
| 682 |
+
return config.format
|
| 683 |
+
except ImportError:
|
| 684 |
+
raise ImportError(
|
| 685 |
+
f"The `{config.name}` format is not installed. "
|
| 686 |
+
f"Use `pip install imageio[{config.install_name}]` to install it."
|
| 687 |
+
)
|
| 688 |
+
|
| 689 |
+
def sort(self, *names):
|
| 690 |
+
"""sort(name1, name2, name3, ...)
|
| 691 |
+
|
| 692 |
+
Sort the formats based on zero or more given names; a format with
|
| 693 |
+
a name that matches one of the given names will take precedence
|
| 694 |
+
over other formats. A match means an equal name, or ending with
|
| 695 |
+
that name (though the former counts higher). Case insensitive.
|
| 696 |
+
|
| 697 |
+
Format preference will match the order of the given names: using
|
| 698 |
+
``sort('TIFF', '-FI', '-PIL')`` would prefer the FreeImage formats
|
| 699 |
+
over the Pillow formats, but prefer TIFF even more. Each time
|
| 700 |
+
this is called, the starting point is the default format order,
|
| 701 |
+
and calling ``sort()`` with no arguments will reset the order.
|
| 702 |
+
|
| 703 |
+
Be aware that using the function can affect the behavior of
|
| 704 |
+
other code that makes use of imageio.
|
| 705 |
+
|
| 706 |
+
Also see the ``IMAGEIO_FORMAT_ORDER`` environment variable.
|
| 707 |
+
"""
|
| 708 |
+
|
| 709 |
+
warnings.warn(
|
| 710 |
+
"`FormatManager` is deprecated and it will be removed in ImageIO v3."
|
| 711 |
+
" Migrating `FormatManager.sort` depends on your use-case:\n"
|
| 712 |
+
"\t- modify `iio.config.known_plugins` to specify the search order for "
|
| 713 |
+
"unrecognized formats.\n"
|
| 714 |
+
"\t- modify `iio.config.known_extensions[<extension>].priority`"
|
| 715 |
+
" to control a specific extension.",
|
| 716 |
+
DeprecationWarning,
|
| 717 |
+
stacklevel=2,
|
| 718 |
+
)
|
| 719 |
+
|
| 720 |
+
# Check and sanitize imput
|
| 721 |
+
for name in names:
|
| 722 |
+
if not isinstance(name, str):
|
| 723 |
+
raise TypeError("formats.sort() accepts only string names.")
|
| 724 |
+
if any(c in name for c in ".,"):
|
| 725 |
+
raise ValueError(
|
| 726 |
+
"Names given to formats.sort() should not "
|
| 727 |
+
"contain dots `.` or commas `,`."
|
| 728 |
+
)
|
| 729 |
+
|
| 730 |
+
should_reset = len(names) == 0
|
| 731 |
+
if should_reset:
|
| 732 |
+
names = _original_order
|
| 733 |
+
|
| 734 |
+
sane_names = [name.strip().upper() for name in names if name != ""]
|
| 735 |
+
|
| 736 |
+
# enforce order for every extension that uses it
|
| 737 |
+
flat_extensions = [
|
| 738 |
+
ext for ext_list in known_extensions.values() for ext in ext_list
|
| 739 |
+
]
|
| 740 |
+
for extension in flat_extensions:
|
| 741 |
+
if should_reset:
|
| 742 |
+
extension.reset()
|
| 743 |
+
continue
|
| 744 |
+
|
| 745 |
+
for name in reversed(sane_names):
|
| 746 |
+
for plugin in [x for x in extension.default_priority]:
|
| 747 |
+
if plugin.endswith(name):
|
| 748 |
+
extension.priority.remove(plugin)
|
| 749 |
+
extension.priority.insert(0, plugin)
|
| 750 |
+
|
| 751 |
+
old_order = known_plugins.copy()
|
| 752 |
+
known_plugins.clear()
|
| 753 |
+
|
| 754 |
+
for name in sane_names:
|
| 755 |
+
plugin = old_order.pop(name, None)
|
| 756 |
+
if plugin is not None:
|
| 757 |
+
known_plugins[name] = plugin
|
| 758 |
+
|
| 759 |
+
known_plugins.update(old_order)
|
| 760 |
+
|
| 761 |
+
def add_format(self, iio_format, overwrite=False):
|
| 762 |
+
"""add_format(format, overwrite=False)
|
| 763 |
+
|
| 764 |
+
Register a format, so that imageio can use it. If a format with the
|
| 765 |
+
same name already exists, an error is raised, unless overwrite is True,
|
| 766 |
+
in which case the current format is replaced.
|
| 767 |
+
"""
|
| 768 |
+
|
| 769 |
+
warnings.warn(
|
| 770 |
+
"`FormatManager` is deprecated and it will be removed in ImageIO v3."
|
| 771 |
+
"To migrate `FormatManager.add_format` add the plugin directly to "
|
| 772 |
+
"`iio.config.known_plugins`.",
|
| 773 |
+
DeprecationWarning,
|
| 774 |
+
stacklevel=2,
|
| 775 |
+
)
|
| 776 |
+
|
| 777 |
+
if not isinstance(iio_format, Format):
|
| 778 |
+
raise ValueError("add_format needs argument to be a Format object")
|
| 779 |
+
elif not overwrite and iio_format.name in self.get_format_names():
|
| 780 |
+
raise ValueError(
|
| 781 |
+
f"A Format named {iio_format.name} is already registered, use"
|
| 782 |
+
" `overwrite=True` to replace."
|
| 783 |
+
)
|
| 784 |
+
|
| 785 |
+
config = PluginConfig(
|
| 786 |
+
name=iio_format.name.upper(),
|
| 787 |
+
class_name=iio_format.__class__.__name__,
|
| 788 |
+
module_name=iio_format.__class__.__module__,
|
| 789 |
+
is_legacy=True,
|
| 790 |
+
install_name="unknown",
|
| 791 |
+
legacy_args={
|
| 792 |
+
"name": iio_format.name,
|
| 793 |
+
"description": iio_format.description,
|
| 794 |
+
"extensions": " ".join(iio_format.extensions),
|
| 795 |
+
"modes": iio_format.modes,
|
| 796 |
+
},
|
| 797 |
+
)
|
| 798 |
+
|
| 799 |
+
known_plugins[config.name] = config
|
| 800 |
+
|
| 801 |
+
for extension in iio_format.extensions:
|
| 802 |
+
# be conservative and always treat it as a unique file format
|
| 803 |
+
ext = FileExtension(
|
| 804 |
+
extension=extension,
|
| 805 |
+
priority=[config.name],
|
| 806 |
+
name="Unique Format",
|
| 807 |
+
description="A format inserted at runtime."
|
| 808 |
+
f" It is being read by the `{config.name}` plugin.",
|
| 809 |
+
)
|
| 810 |
+
known_extensions.setdefault(extension, list()).append(ext)
|
| 811 |
+
|
| 812 |
+
def search_read_format(self, request):
|
| 813 |
+
"""search_read_format(request)
|
| 814 |
+
|
| 815 |
+
Search a format that can read a file according to the given request.
|
| 816 |
+
Returns None if no appropriate format was found. (used internally)
|
| 817 |
+
"""
|
| 818 |
+
|
| 819 |
+
try:
|
| 820 |
+
# in legacy_mode imopen returns a LegacyPlugin
|
| 821 |
+
return imopen(request, request.mode.io_mode, legacy_mode=True)._format
|
| 822 |
+
except ValueError:
|
| 823 |
+
# no plugin can read this request
|
| 824 |
+
# but the legacy API doesn't raise
|
| 825 |
+
return None
|
| 826 |
+
|
| 827 |
+
def search_write_format(self, request):
|
| 828 |
+
"""search_write_format(request)
|
| 829 |
+
|
| 830 |
+
Search a format that can write a file according to the given request.
|
| 831 |
+
Returns None if no appropriate format was found. (used internally)
|
| 832 |
+
"""
|
| 833 |
+
|
| 834 |
+
try:
|
| 835 |
+
# in legacy_mode imopen returns a LegacyPlugin
|
| 836 |
+
return imopen(request, request.mode.io_mode, legacy_mode=True)._format
|
| 837 |
+
except ValueError:
|
| 838 |
+
# no plugin can write this request
|
| 839 |
+
# but the legacy API doesn't raise
|
| 840 |
+
return None
|
| 841 |
+
|
| 842 |
+
def get_format_names(self):
|
| 843 |
+
"""Get the names of all registered formats."""
|
| 844 |
+
|
| 845 |
+
warnings.warn(
|
| 846 |
+
"`FormatManager` is deprecated and it will be removed in ImageIO v3."
|
| 847 |
+
"To migrate `FormatManager.get_format_names` use `iio.config.known_plugins.keys()` instead.",
|
| 848 |
+
DeprecationWarning,
|
| 849 |
+
stacklevel=2,
|
| 850 |
+
)
|
| 851 |
+
|
| 852 |
+
return [f.name for f in self._formats]
|
| 853 |
+
|
| 854 |
+
def show(self):
|
| 855 |
+
"""Show a nicely formatted list of available formats"""
|
| 856 |
+
print(self)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/imopen.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import warnings
|
| 3 |
+
|
| 4 |
+
from ..config import known_plugins
|
| 5 |
+
from ..config.extensions import known_extensions
|
| 6 |
+
from .request import (
|
| 7 |
+
SPECIAL_READ_URIS,
|
| 8 |
+
URI_FILENAME,
|
| 9 |
+
InitializationError,
|
| 10 |
+
IOMode,
|
| 11 |
+
Request,
|
| 12 |
+
)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def imopen(
|
| 16 |
+
uri,
|
| 17 |
+
io_mode,
|
| 18 |
+
*,
|
| 19 |
+
plugin=None,
|
| 20 |
+
extension=None,
|
| 21 |
+
format_hint=None,
|
| 22 |
+
legacy_mode=False,
|
| 23 |
+
**kwargs,
|
| 24 |
+
):
|
| 25 |
+
"""Open an ImageResource.
|
| 26 |
+
|
| 27 |
+
.. warning::
|
| 28 |
+
This warning is for pypy users. If you are not using a context manager,
|
| 29 |
+
remember to deconstruct the returned plugin to avoid leaking the file
|
| 30 |
+
handle to an unclosed file.
|
| 31 |
+
|
| 32 |
+
Parameters
|
| 33 |
+
----------
|
| 34 |
+
uri : str or pathlib.Path or bytes or file or Request
|
| 35 |
+
The :doc:`ImageResource <../../user_guide/requests>` to load the
|
| 36 |
+
image from.
|
| 37 |
+
io_mode : str
|
| 38 |
+
The mode in which the file is opened. Possible values are::
|
| 39 |
+
|
| 40 |
+
``r`` - open the file for reading
|
| 41 |
+
``w`` - open the file for writing
|
| 42 |
+
|
| 43 |
+
Depreciated since v2.9:
|
| 44 |
+
A second character can be added to give the reader a hint on what
|
| 45 |
+
the user expects. This will be ignored by new plugins and will
|
| 46 |
+
only have an effect on legacy plugins. Possible values are::
|
| 47 |
+
|
| 48 |
+
``i`` for a single image,
|
| 49 |
+
``I`` for multiple images,
|
| 50 |
+
``v`` for a single volume,
|
| 51 |
+
``V`` for multiple volumes,
|
| 52 |
+
``?`` for don't care (default)
|
| 53 |
+
|
| 54 |
+
plugin : str, Plugin, or None
|
| 55 |
+
The plugin to use. If set to None (default) imopen will perform a
|
| 56 |
+
search for a matching plugin. If not None, this takes priority over
|
| 57 |
+
the provided format hint.
|
| 58 |
+
extension : str
|
| 59 |
+
If not None, treat the provided ImageResource as if it had the given
|
| 60 |
+
extension. This affects the order in which backends are considered, and
|
| 61 |
+
when writing this may also influence the format used when encoding.
|
| 62 |
+
format_hint : str
|
| 63 |
+
A format hint to help optimize plugin selection given as the format's
|
| 64 |
+
extension, e.g. ".png". This can speed up the selection process for
|
| 65 |
+
ImageResources that don't have an explicit extension, e.g. streams, or
|
| 66 |
+
for ImageResources where the extension does not match the resource's
|
| 67 |
+
content. If the ImageResource lacks an explicit extension, it will be
|
| 68 |
+
set to this format.
|
| 69 |
+
legacy_mode : bool
|
| 70 |
+
If true (default) use the v2 behavior when searching for a suitable
|
| 71 |
+
plugin. This will ignore v3 plugins and will check ``plugin``
|
| 72 |
+
against known extensions if no plugin with the given name can be found.
|
| 73 |
+
**kwargs : Any
|
| 74 |
+
Additional keyword arguments will be passed to the plugin upon
|
| 75 |
+
construction.
|
| 76 |
+
|
| 77 |
+
Notes
|
| 78 |
+
-----
|
| 79 |
+
Registered plugins are controlled via the ``known_plugins`` dict in
|
| 80 |
+
``imageio.config``.
|
| 81 |
+
|
| 82 |
+
Passing a ``Request`` as the uri is only supported if ``legacy_mode``
|
| 83 |
+
is ``True``. In this case ``io_mode`` is ignored.
|
| 84 |
+
|
| 85 |
+
Using the kwarg ``format_hint`` does not enforce the given format. It merely
|
| 86 |
+
provides a `hint` to the selection process and plugin. The selection
|
| 87 |
+
processes uses this hint for optimization; however, a plugin's decision how
|
| 88 |
+
to read a ImageResource will - typically - still be based on the content of
|
| 89 |
+
the resource.
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
Examples
|
| 93 |
+
--------
|
| 94 |
+
|
| 95 |
+
>>> import imageio.v3 as iio
|
| 96 |
+
>>> with iio.imopen("/path/to/image.png", "r") as file:
|
| 97 |
+
>>> im = file.read()
|
| 98 |
+
|
| 99 |
+
>>> with iio.imopen("/path/to/output.jpg", "w") as file:
|
| 100 |
+
>>> file.write(im)
|
| 101 |
+
|
| 102 |
+
"""
|
| 103 |
+
|
| 104 |
+
if isinstance(uri, Request) and legacy_mode:
|
| 105 |
+
warnings.warn(
|
| 106 |
+
"`iio.core.Request` is a low-level object and using it"
|
| 107 |
+
" directly as input to `imopen` is discouraged. This will raise"
|
| 108 |
+
" an exception in ImageIO v3.",
|
| 109 |
+
DeprecationWarning,
|
| 110 |
+
stacklevel=2,
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
request = uri
|
| 114 |
+
uri = request.raw_uri
|
| 115 |
+
io_mode = request.mode.io_mode
|
| 116 |
+
request.format_hint = format_hint
|
| 117 |
+
else:
|
| 118 |
+
request = Request(uri, io_mode, format_hint=format_hint, extension=extension)
|
| 119 |
+
|
| 120 |
+
source = "<bytes>" if isinstance(uri, bytes) else uri
|
| 121 |
+
|
| 122 |
+
# fast-path based on plugin
|
| 123 |
+
# (except in legacy mode)
|
| 124 |
+
if plugin is not None:
|
| 125 |
+
if isinstance(plugin, str):
|
| 126 |
+
try:
|
| 127 |
+
config = known_plugins[plugin]
|
| 128 |
+
except KeyError:
|
| 129 |
+
request.finish()
|
| 130 |
+
raise ValueError(
|
| 131 |
+
f"`{plugin}` is not a registered plugin name."
|
| 132 |
+
) from None
|
| 133 |
+
|
| 134 |
+
def loader(request, **kwargs):
|
| 135 |
+
return config.plugin_class(request, **kwargs)
|
| 136 |
+
|
| 137 |
+
elif not legacy_mode:
|
| 138 |
+
|
| 139 |
+
def loader(request, **kwargs):
|
| 140 |
+
return plugin(request, **kwargs)
|
| 141 |
+
|
| 142 |
+
else:
|
| 143 |
+
request.finish()
|
| 144 |
+
raise ValueError("The `plugin` argument must be a string.")
|
| 145 |
+
|
| 146 |
+
try:
|
| 147 |
+
return loader(request, **kwargs)
|
| 148 |
+
except InitializationError as class_specific:
|
| 149 |
+
err_from = class_specific
|
| 150 |
+
err_type = RuntimeError if legacy_mode else IOError
|
| 151 |
+
err_msg = f"`{plugin}` can not handle the given uri."
|
| 152 |
+
except ImportError:
|
| 153 |
+
err_from = None
|
| 154 |
+
err_type = ImportError
|
| 155 |
+
err_msg = (
|
| 156 |
+
f"The `{config.name}` plugin is not installed. "
|
| 157 |
+
f"Use `pip install imageio[{config.install_name}]` to install it."
|
| 158 |
+
)
|
| 159 |
+
except Exception as generic_error:
|
| 160 |
+
err_from = generic_error
|
| 161 |
+
err_type = IOError
|
| 162 |
+
err_msg = f"An unknown error occured while initializing plugin `{plugin}`."
|
| 163 |
+
|
| 164 |
+
request.finish()
|
| 165 |
+
raise err_type(err_msg) from err_from
|
| 166 |
+
|
| 167 |
+
# fast-path based on format_hint
|
| 168 |
+
if request.format_hint is not None:
|
| 169 |
+
for candidate_format in known_extensions[format_hint]:
|
| 170 |
+
for plugin_name in candidate_format.priority:
|
| 171 |
+
config = known_plugins[plugin_name]
|
| 172 |
+
|
| 173 |
+
# v2 compatibility; delete in v3
|
| 174 |
+
if legacy_mode and not config.is_legacy:
|
| 175 |
+
continue
|
| 176 |
+
|
| 177 |
+
try:
|
| 178 |
+
candidate_plugin = config.plugin_class
|
| 179 |
+
except ImportError:
|
| 180 |
+
# not installed
|
| 181 |
+
continue
|
| 182 |
+
|
| 183 |
+
try:
|
| 184 |
+
plugin_instance = candidate_plugin(request, **kwargs)
|
| 185 |
+
except InitializationError:
|
| 186 |
+
# file extension doesn't match file type
|
| 187 |
+
continue
|
| 188 |
+
|
| 189 |
+
return plugin_instance
|
| 190 |
+
else:
|
| 191 |
+
resource = (
|
| 192 |
+
"<bytes>" if isinstance(request.raw_uri, bytes) else request.raw_uri
|
| 193 |
+
)
|
| 194 |
+
warnings.warn(f"`{resource}` can not be opened as a `{format_hint}` file.")
|
| 195 |
+
|
| 196 |
+
# fast-path based on file extension
|
| 197 |
+
if request.extension in known_extensions:
|
| 198 |
+
for candidate_format in known_extensions[request.extension]:
|
| 199 |
+
for plugin_name in candidate_format.priority:
|
| 200 |
+
config = known_plugins[plugin_name]
|
| 201 |
+
|
| 202 |
+
# v2 compatibility; delete in v3
|
| 203 |
+
if legacy_mode and not config.is_legacy:
|
| 204 |
+
continue
|
| 205 |
+
|
| 206 |
+
try:
|
| 207 |
+
candidate_plugin = config.plugin_class
|
| 208 |
+
except ImportError:
|
| 209 |
+
# not installed
|
| 210 |
+
continue
|
| 211 |
+
|
| 212 |
+
try:
|
| 213 |
+
plugin_instance = candidate_plugin(request, **kwargs)
|
| 214 |
+
except InitializationError:
|
| 215 |
+
# file extension doesn't match file type
|
| 216 |
+
continue
|
| 217 |
+
|
| 218 |
+
return plugin_instance
|
| 219 |
+
|
| 220 |
+
# error out for read-only special targets
|
| 221 |
+
# this is hacky; can we come up with a better solution for this?
|
| 222 |
+
if request.mode.io_mode == IOMode.write:
|
| 223 |
+
if isinstance(uri, str) and uri.startswith(SPECIAL_READ_URIS):
|
| 224 |
+
request.finish()
|
| 225 |
+
err_type = ValueError if legacy_mode else IOError
|
| 226 |
+
err_msg = f"`{source}` is read-only."
|
| 227 |
+
raise err_type(err_msg)
|
| 228 |
+
|
| 229 |
+
# error out for directories
|
| 230 |
+
# this is a bit hacky and should be cleaned once we decide
|
| 231 |
+
# how to gracefully handle DICOM
|
| 232 |
+
if request._uri_type == URI_FILENAME and Path(request.raw_uri).is_dir():
|
| 233 |
+
request.finish()
|
| 234 |
+
err_type = ValueError if legacy_mode else IOError
|
| 235 |
+
err_msg = (
|
| 236 |
+
"ImageIO does not generally support reading folders. "
|
| 237 |
+
"Limited support may be available via specific plugins. "
|
| 238 |
+
"Specify the plugin explicitly using the `plugin` kwarg, e.g. `plugin='DICOM'`"
|
| 239 |
+
)
|
| 240 |
+
raise err_type(err_msg)
|
| 241 |
+
|
| 242 |
+
# close the current request here and use fresh/new ones while trying each
|
| 243 |
+
# plugin This is slow (means potentially reopening a resource several
|
| 244 |
+
# times), but should only happen rarely because this is the fallback if all
|
| 245 |
+
# else fails.
|
| 246 |
+
request.finish()
|
| 247 |
+
|
| 248 |
+
# fallback option: try all plugins
|
| 249 |
+
for config in known_plugins.values():
|
| 250 |
+
# Note: for v2 compatibility
|
| 251 |
+
# this branch can be removed in ImageIO v3.0
|
| 252 |
+
if legacy_mode and not config.is_legacy:
|
| 253 |
+
continue
|
| 254 |
+
|
| 255 |
+
# each plugin gets its own request
|
| 256 |
+
request = Request(uri, io_mode, format_hint=format_hint)
|
| 257 |
+
|
| 258 |
+
try:
|
| 259 |
+
plugin_instance = config.plugin_class(request, **kwargs)
|
| 260 |
+
except InitializationError:
|
| 261 |
+
continue
|
| 262 |
+
except ImportError:
|
| 263 |
+
continue
|
| 264 |
+
else:
|
| 265 |
+
return plugin_instance
|
| 266 |
+
|
| 267 |
+
err_type = ValueError if legacy_mode else IOError
|
| 268 |
+
err_msg = f"Could not find a backend to open `{source}`` with iomode `{io_mode}`."
|
| 269 |
+
|
| 270 |
+
# check if a missing plugin could help
|
| 271 |
+
if request.extension in known_extensions:
|
| 272 |
+
missing_plugins = list()
|
| 273 |
+
|
| 274 |
+
formats = known_extensions[request.extension]
|
| 275 |
+
plugin_names = [
|
| 276 |
+
plugin for file_format in formats for plugin in file_format.priority
|
| 277 |
+
]
|
| 278 |
+
for name in plugin_names:
|
| 279 |
+
config = known_plugins[name]
|
| 280 |
+
|
| 281 |
+
try:
|
| 282 |
+
config.plugin_class
|
| 283 |
+
continue
|
| 284 |
+
except ImportError:
|
| 285 |
+
missing_plugins.append(config)
|
| 286 |
+
|
| 287 |
+
if len(missing_plugins) > 0:
|
| 288 |
+
install_candidates = "\n".join(
|
| 289 |
+
[
|
| 290 |
+
(
|
| 291 |
+
f" {config.name}: "
|
| 292 |
+
f"pip install imageio[{config.install_name}]"
|
| 293 |
+
)
|
| 294 |
+
for config in missing_plugins
|
| 295 |
+
]
|
| 296 |
+
)
|
| 297 |
+
err_msg += (
|
| 298 |
+
"\nBased on the extension, the following plugins might add capable backends:\n"
|
| 299 |
+
f"{install_candidates}"
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
request.finish()
|
| 303 |
+
raise err_type(err_msg)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/legacy_plugin_wrapper.py
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
from .request import IOMode, InitializationError
|
| 5 |
+
from .v3_plugin_api import PluginV3, ImageProperties
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _legacy_default_index(format):
|
| 9 |
+
if format._name == "FFMPEG":
|
| 10 |
+
index = Ellipsis
|
| 11 |
+
elif format._name == "GIF-PIL":
|
| 12 |
+
index = Ellipsis
|
| 13 |
+
else:
|
| 14 |
+
index = 0
|
| 15 |
+
|
| 16 |
+
return index
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class LegacyPlugin(PluginV3):
|
| 20 |
+
"""A plugin to make old (v2.9) plugins compatible with v3.0
|
| 21 |
+
|
| 22 |
+
.. depreciated:: 2.9
|
| 23 |
+
`legacy_get_reader` will be removed in a future version of imageio.
|
| 24 |
+
`legacy_get_writer` will be removed in a future version of imageio.
|
| 25 |
+
|
| 26 |
+
This plugin is a wrapper around the old FormatManager class and exposes
|
| 27 |
+
all the old plugins via the new API. On top of this it has
|
| 28 |
+
``legacy_get_reader`` and ``legacy_get_writer`` methods to allow using
|
| 29 |
+
it with the v2.9 API.
|
| 30 |
+
|
| 31 |
+
Methods
|
| 32 |
+
-------
|
| 33 |
+
read(index=None, **kwargs)
|
| 34 |
+
Read the image at position ``index``.
|
| 35 |
+
write(image, **kwargs)
|
| 36 |
+
Write image to the URI.
|
| 37 |
+
iter(**kwargs)
|
| 38 |
+
Iteratively yield images from the given URI.
|
| 39 |
+
get_meta(index=None)
|
| 40 |
+
Return the metadata for the image at position ``index``.
|
| 41 |
+
legacy_get_reader(**kwargs)
|
| 42 |
+
Returns the v2.9 image reader. (depreciated)
|
| 43 |
+
legacy_get_writer(**kwargs)
|
| 44 |
+
Returns the v2.9 image writer. (depreciated)
|
| 45 |
+
|
| 46 |
+
Examples
|
| 47 |
+
--------
|
| 48 |
+
|
| 49 |
+
>>> import imageio.v3 as iio
|
| 50 |
+
>>> with iio.imopen("/path/to/image.tiff", "r", legacy_mode=True) as file:
|
| 51 |
+
>>> reader = file.legacy_get_reader() # depreciated
|
| 52 |
+
>>> for im in file.iter():
|
| 53 |
+
>>> print(im.shape)
|
| 54 |
+
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
def __init__(self, request, legacy_plugin):
|
| 58 |
+
"""Instantiate a new Legacy Plugin
|
| 59 |
+
|
| 60 |
+
Parameters
|
| 61 |
+
----------
|
| 62 |
+
uri : {str, pathlib.Path, bytes, file}
|
| 63 |
+
The resource to load the image from, e.g. a filename, pathlib.Path,
|
| 64 |
+
http address or file object, see the docs for more info.
|
| 65 |
+
legacy_plugin : Format
|
| 66 |
+
The (legacy) format to use to interface with the URI.
|
| 67 |
+
|
| 68 |
+
"""
|
| 69 |
+
self._request = request
|
| 70 |
+
self._format = legacy_plugin
|
| 71 |
+
|
| 72 |
+
source = (
|
| 73 |
+
"<bytes>"
|
| 74 |
+
if isinstance(self._request.raw_uri, bytes)
|
| 75 |
+
else self._request.raw_uri
|
| 76 |
+
)
|
| 77 |
+
if self._request.mode.io_mode == IOMode.read:
|
| 78 |
+
if not self._format.can_read(request):
|
| 79 |
+
raise InitializationError(
|
| 80 |
+
f"`{self._format.name}`" f" can not read `{source}`."
|
| 81 |
+
)
|
| 82 |
+
else:
|
| 83 |
+
if not self._format.can_write(request):
|
| 84 |
+
raise InitializationError(
|
| 85 |
+
f"`{self._format.name}`" f" can not write to `{source}`."
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
def legacy_get_reader(self, **kwargs):
|
| 89 |
+
"""legacy_get_reader(**kwargs)
|
| 90 |
+
|
| 91 |
+
a utility method to provide support vor the V2.9 API
|
| 92 |
+
|
| 93 |
+
Parameters
|
| 94 |
+
----------
|
| 95 |
+
kwargs : ...
|
| 96 |
+
Further keyword arguments are passed to the reader. See :func:`.help`
|
| 97 |
+
to see what arguments are available for a particular format.
|
| 98 |
+
"""
|
| 99 |
+
|
| 100 |
+
# Note: this will break thread-safety
|
| 101 |
+
self._request._kwargs = kwargs
|
| 102 |
+
|
| 103 |
+
# safeguard for DICOM plugin reading from folders
|
| 104 |
+
try:
|
| 105 |
+
assert Path(self._request.filename).is_dir()
|
| 106 |
+
except OSError:
|
| 107 |
+
pass # not a valid path on this OS
|
| 108 |
+
except AssertionError:
|
| 109 |
+
pass # not a folder
|
| 110 |
+
else:
|
| 111 |
+
return self._format.get_reader(self._request)
|
| 112 |
+
|
| 113 |
+
self._request.get_file().seek(0)
|
| 114 |
+
return self._format.get_reader(self._request)
|
| 115 |
+
|
| 116 |
+
def read(self, *, index=None, **kwargs):
|
| 117 |
+
"""
|
| 118 |
+
Parses the given URI and creates a ndarray from it.
|
| 119 |
+
|
| 120 |
+
Parameters
|
| 121 |
+
----------
|
| 122 |
+
index : {integer, None}
|
| 123 |
+
If the URI contains a list of ndimages return the index-th
|
| 124 |
+
image. If None, stack all images into an ndimage along the
|
| 125 |
+
0-th dimension (equivalent to np.stack(imgs, axis=0)).
|
| 126 |
+
kwargs : ...
|
| 127 |
+
Further keyword arguments are passed to the reader. See
|
| 128 |
+
:func:`.help` to see what arguments are available for a particular
|
| 129 |
+
format.
|
| 130 |
+
|
| 131 |
+
Returns
|
| 132 |
+
-------
|
| 133 |
+
ndimage : np.ndarray
|
| 134 |
+
A numpy array containing the decoded image data.
|
| 135 |
+
|
| 136 |
+
"""
|
| 137 |
+
|
| 138 |
+
if index is None:
|
| 139 |
+
index = _legacy_default_index(self._format)
|
| 140 |
+
|
| 141 |
+
if index is Ellipsis:
|
| 142 |
+
img = np.stack([im for im in self.iter(**kwargs)])
|
| 143 |
+
return img
|
| 144 |
+
|
| 145 |
+
reader = self.legacy_get_reader(**kwargs)
|
| 146 |
+
return reader.get_data(index)
|
| 147 |
+
|
| 148 |
+
def legacy_get_writer(self, **kwargs):
|
| 149 |
+
"""legacy_get_writer(**kwargs)
|
| 150 |
+
|
| 151 |
+
Returns a :class:`.Writer` object which can be used to write data
|
| 152 |
+
and meta data to the specified file.
|
| 153 |
+
|
| 154 |
+
Parameters
|
| 155 |
+
----------
|
| 156 |
+
kwargs : ...
|
| 157 |
+
Further keyword arguments are passed to the writer. See :func:`.help`
|
| 158 |
+
to see what arguments are available for a particular format.
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
# Note: this will break thread-safety
|
| 162 |
+
self._request._kwargs = kwargs
|
| 163 |
+
return self._format.get_writer(self._request)
|
| 164 |
+
|
| 165 |
+
def write(self, ndimage, **kwargs):
|
| 166 |
+
"""
|
| 167 |
+
Write an ndimage to the URI specified in path.
|
| 168 |
+
|
| 169 |
+
If the URI points to a file on the current host and the file does not
|
| 170 |
+
yet exist it will be created. If the file exists already, it will be
|
| 171 |
+
appended if possible; otherwise, it will be replaced.
|
| 172 |
+
|
| 173 |
+
Parameters
|
| 174 |
+
----------
|
| 175 |
+
image : numpy.ndarray
|
| 176 |
+
The ndimage or list of ndimages to write.
|
| 177 |
+
kwargs : ...
|
| 178 |
+
Further keyword arguments are passed to the writer. See
|
| 179 |
+
:func:`.help` to see what arguments are available for a
|
| 180 |
+
particular format.
|
| 181 |
+
"""
|
| 182 |
+
with self.legacy_get_writer(**kwargs) as writer:
|
| 183 |
+
if self._request.mode.image_mode in "iv":
|
| 184 |
+
writer.append_data(ndimage)
|
| 185 |
+
else:
|
| 186 |
+
if len(ndimage) == 0:
|
| 187 |
+
raise RuntimeError("Zero images were written.")
|
| 188 |
+
for written, ndimage in enumerate(ndimage):
|
| 189 |
+
# Test image
|
| 190 |
+
imt = type(ndimage)
|
| 191 |
+
ndimage = np.asanyarray(ndimage)
|
| 192 |
+
if not np.issubdtype(ndimage.dtype, np.number):
|
| 193 |
+
raise ValueError(
|
| 194 |
+
"Image is not numeric, but {}.".format(imt.__name__)
|
| 195 |
+
)
|
| 196 |
+
elif self._request.mode.image_mode == "I":
|
| 197 |
+
if ndimage.ndim == 2:
|
| 198 |
+
pass
|
| 199 |
+
elif ndimage.ndim == 3 and ndimage.shape[2] in [1, 3, 4]:
|
| 200 |
+
pass
|
| 201 |
+
else:
|
| 202 |
+
raise ValueError(
|
| 203 |
+
"Image must be 2D " "(grayscale, RGB, or RGBA)."
|
| 204 |
+
)
|
| 205 |
+
elif self._request.mode.image_mode == "V":
|
| 206 |
+
if ndimage.ndim == 3:
|
| 207 |
+
pass
|
| 208 |
+
elif ndimage.ndim == 4 and ndimage.shape[3] < 32:
|
| 209 |
+
pass
|
| 210 |
+
else:
|
| 211 |
+
raise ValueError(
|
| 212 |
+
"Image must be 3D," " or 4D if each voxel is a tuple."
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
# Add image
|
| 216 |
+
writer.append_data(ndimage)
|
| 217 |
+
|
| 218 |
+
return writer.request.get_result()
|
| 219 |
+
|
| 220 |
+
def iter(self, **kwargs):
|
| 221 |
+
"""Iterate over a list of ndimages given by the URI
|
| 222 |
+
|
| 223 |
+
Parameters
|
| 224 |
+
----------
|
| 225 |
+
kwargs : ...
|
| 226 |
+
Further keyword arguments are passed to the reader. See
|
| 227 |
+
:func:`.help` to see what arguments are available for a particular
|
| 228 |
+
format.
|
| 229 |
+
"""
|
| 230 |
+
|
| 231 |
+
reader = self.legacy_get_reader(**kwargs)
|
| 232 |
+
for image in reader:
|
| 233 |
+
yield image
|
| 234 |
+
|
| 235 |
+
def properties(self, index=None):
|
| 236 |
+
"""Standardized ndimage metadata.
|
| 237 |
+
|
| 238 |
+
Parameters
|
| 239 |
+
----------
|
| 240 |
+
index : int
|
| 241 |
+
The index of the ndimage for which to return properties. If the
|
| 242 |
+
index is out of bounds a ``ValueError`` is raised. If ``None``,
|
| 243 |
+
return the properties for the ndimage stack. If this is impossible,
|
| 244 |
+
e.g., due to shape missmatch, an exception will be raised.
|
| 245 |
+
|
| 246 |
+
Returns
|
| 247 |
+
-------
|
| 248 |
+
properties : ImageProperties
|
| 249 |
+
A dataclass filled with standardized image metadata.
|
| 250 |
+
|
| 251 |
+
"""
|
| 252 |
+
|
| 253 |
+
if index is None:
|
| 254 |
+
index = _legacy_default_index(self._format)
|
| 255 |
+
|
| 256 |
+
# for backwards compatibility ... actually reads pixel data :(
|
| 257 |
+
image = self.read(index=index)
|
| 258 |
+
|
| 259 |
+
return ImageProperties(
|
| 260 |
+
shape=image.shape,
|
| 261 |
+
dtype=image.dtype,
|
| 262 |
+
is_batch=True if index is None else False,
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
def get_meta(self, *, index=None):
|
| 266 |
+
"""Read ndimage metadata from the URI
|
| 267 |
+
|
| 268 |
+
Parameters
|
| 269 |
+
----------
|
| 270 |
+
index : {integer, None}
|
| 271 |
+
If the URI contains a list of ndimages return the metadata
|
| 272 |
+
corresponding to the index-th image. If None, behavior depends on
|
| 273 |
+
the used api
|
| 274 |
+
|
| 275 |
+
Legacy-style API: return metadata of the first element (index=0)
|
| 276 |
+
New-style API: Behavior depends on the used Plugin.
|
| 277 |
+
|
| 278 |
+
Returns
|
| 279 |
+
-------
|
| 280 |
+
metadata : dict
|
| 281 |
+
A dictionary of metadata.
|
| 282 |
+
|
| 283 |
+
"""
|
| 284 |
+
|
| 285 |
+
return self.metadata(index=index, exclude_applied=False)
|
| 286 |
+
|
| 287 |
+
def metadata(self, index=None, exclude_applied: bool = True):
|
| 288 |
+
"""Format-Specific ndimage metadata.
|
| 289 |
+
|
| 290 |
+
Parameters
|
| 291 |
+
----------
|
| 292 |
+
index : int
|
| 293 |
+
The index of the ndimage to read. If the index is out of bounds a
|
| 294 |
+
``ValueError`` is raised. If ``None``, global metadata is returned.
|
| 295 |
+
exclude_applied : bool
|
| 296 |
+
If True (default), do not report metadata fields that the plugin
|
| 297 |
+
would apply/consume while reading the image.
|
| 298 |
+
|
| 299 |
+
Returns
|
| 300 |
+
-------
|
| 301 |
+
metadata : dict
|
| 302 |
+
A dictionary filled with format-specific metadata fields and their
|
| 303 |
+
values.
|
| 304 |
+
|
| 305 |
+
"""
|
| 306 |
+
|
| 307 |
+
if exclude_applied:
|
| 308 |
+
raise ValueError(
|
| 309 |
+
"Legacy plugins don't support excluding applied metadata fields."
|
| 310 |
+
)
|
| 311 |
+
|
| 312 |
+
if index is None:
|
| 313 |
+
index = _legacy_default_index(self._format)
|
| 314 |
+
|
| 315 |
+
return self.legacy_get_reader().get_meta_data(index=index)
|
| 316 |
+
|
| 317 |
+
def __del__(self) -> None:
|
| 318 |
+
pass
|
| 319 |
+
# turns out we can't close the file here for LegacyPlugin
|
| 320 |
+
# because it would break backwards compatibility
|
| 321 |
+
# with legacy_get_writer and legacy_get_reader
|
| 322 |
+
# self._request.finish()
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/request.py
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
"""
|
| 5 |
+
Definition of the Request object, which acts as a kind of bridge between
|
| 6 |
+
what the user wants and what the plugins can.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import os
|
| 10 |
+
from io import BytesIO
|
| 11 |
+
import zipfile
|
| 12 |
+
import tempfile
|
| 13 |
+
import shutil
|
| 14 |
+
import enum
|
| 15 |
+
import warnings
|
| 16 |
+
|
| 17 |
+
from ..core import urlopen, get_remote_file
|
| 18 |
+
|
| 19 |
+
from pathlib import Path
|
| 20 |
+
from urllib.parse import urlparse
|
| 21 |
+
from typing import Optional
|
| 22 |
+
|
| 23 |
+
# URI types
|
| 24 |
+
URI_BYTES = 1
|
| 25 |
+
URI_FILE = 2
|
| 26 |
+
URI_FILENAME = 3
|
| 27 |
+
URI_ZIPPED = 4
|
| 28 |
+
URI_HTTP = 5
|
| 29 |
+
URI_FTP = 6
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class IOMode(str, enum.Enum):
|
| 33 |
+
"""Available Image modes
|
| 34 |
+
|
| 35 |
+
This is a helper enum for ``Request.Mode`` which is a composite of a
|
| 36 |
+
``Request.ImageMode`` and ``Request.IOMode``. The IOMode that tells the
|
| 37 |
+
plugin if the resource should be read from or written to. Available values are
|
| 38 |
+
|
| 39 |
+
- read ("r"): Read from the specified resource
|
| 40 |
+
- write ("w"): Write to the specified resource
|
| 41 |
+
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
read = "r"
|
| 45 |
+
write = "w"
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class ImageMode(str, enum.Enum):
|
| 49 |
+
"""Available Image modes
|
| 50 |
+
|
| 51 |
+
This is a helper enum for ``Request.Mode`` which is a composite of a
|
| 52 |
+
``Request.ImageMode`` and ``Request.IOMode``. The image mode that tells the
|
| 53 |
+
plugin the desired (and expected) image shape. Available values are
|
| 54 |
+
|
| 55 |
+
- single_image ("i"): Return a single image extending in two spacial
|
| 56 |
+
dimensions
|
| 57 |
+
- multi_image ("I"): Return a list of images extending in two spacial
|
| 58 |
+
dimensions
|
| 59 |
+
- single_volume ("v"): Return an image extending into multiple dimensions.
|
| 60 |
+
E.g. three spacial dimensions for image stacks, or two spatial and one
|
| 61 |
+
time dimension for videos
|
| 62 |
+
- multi_volume ("V"): Return a list of images extending into multiple
|
| 63 |
+
dimensions.
|
| 64 |
+
- any_mode ("?"): Return an image in any format (the plugin decides the
|
| 65 |
+
appropriate action).
|
| 66 |
+
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
single_image = "i"
|
| 70 |
+
multi_image = "I"
|
| 71 |
+
single_volume = "v"
|
| 72 |
+
multi_volume = "V"
|
| 73 |
+
any_mode = "?"
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
@enum.unique
|
| 77 |
+
class Mode(str, enum.Enum):
|
| 78 |
+
"""The mode to use when interacting with the resource
|
| 79 |
+
|
| 80 |
+
``Request.Mode`` is a composite of ``Request.ImageMode`` and
|
| 81 |
+
``Request.IOMode``. The image mode that tells the plugin the desired (and
|
| 82 |
+
expected) image shape and the ``Request.IOMode`` tells the plugin the way
|
| 83 |
+
the resource should be interacted with. For a detailed description of the
|
| 84 |
+
available modes, see the documentation for ``Request.ImageMode`` and
|
| 85 |
+
``Request.IOMode`` respectively.
|
| 86 |
+
|
| 87 |
+
Available modes are all combinations of ``Request.IOMode`` and ``Request.ImageMode``:
|
| 88 |
+
|
| 89 |
+
- read_single_image ("ri")
|
| 90 |
+
- read_multi_image ("rI")
|
| 91 |
+
- read_single_volume ("rv")
|
| 92 |
+
- read_multi_volume ("rV")
|
| 93 |
+
- read_any ("r?")
|
| 94 |
+
- write_single_image ("wi")
|
| 95 |
+
- write_multi_image ("wI")
|
| 96 |
+
- write_single_volume ("wv")
|
| 97 |
+
- write_multi_volume ("wV")
|
| 98 |
+
- write_any ("w?")
|
| 99 |
+
|
| 100 |
+
Examples
|
| 101 |
+
--------
|
| 102 |
+
>>> Request.Mode("rI") # a list of simple images should be read from the resource
|
| 103 |
+
>>> Request.Mode("wv") # a single volume should be written to the resource
|
| 104 |
+
|
| 105 |
+
"""
|
| 106 |
+
|
| 107 |
+
read_single_image = "ri"
|
| 108 |
+
read_multi_image = "rI"
|
| 109 |
+
read_single_volume = "rv"
|
| 110 |
+
read_multi_volume = "rV"
|
| 111 |
+
read_any = "r?"
|
| 112 |
+
write_single_image = "wi"
|
| 113 |
+
write_multi_image = "wI"
|
| 114 |
+
write_single_volume = "wv"
|
| 115 |
+
write_multi_volume = "wV"
|
| 116 |
+
write_any = "w?"
|
| 117 |
+
|
| 118 |
+
@classmethod
|
| 119 |
+
def _missing_(cls, value):
|
| 120 |
+
"""Enable Mode("r") and Mode("w")
|
| 121 |
+
|
| 122 |
+
The sunder method ``_missing_`` is called whenever the constructor fails
|
| 123 |
+
to directly look up the corresponding enum value from the given input.
|
| 124 |
+
In our case, we use it to convert the modes "r" and "w" (from the v3
|
| 125 |
+
API) into their legacy versions "r?" and "w?".
|
| 126 |
+
|
| 127 |
+
More info on _missing_:
|
| 128 |
+
https://docs.python.org/3/library/enum.html#supported-sunder-names
|
| 129 |
+
"""
|
| 130 |
+
|
| 131 |
+
if value == "r":
|
| 132 |
+
return cls("r?")
|
| 133 |
+
elif value == "w":
|
| 134 |
+
return cls("w?")
|
| 135 |
+
else:
|
| 136 |
+
raise ValueError(f"{value} is no valid Mode.")
|
| 137 |
+
|
| 138 |
+
@property
|
| 139 |
+
def io_mode(self) -> IOMode:
|
| 140 |
+
return IOMode(self.value[0])
|
| 141 |
+
|
| 142 |
+
@property
|
| 143 |
+
def image_mode(self) -> ImageMode:
|
| 144 |
+
return ImageMode(self.value[1])
|
| 145 |
+
|
| 146 |
+
def __getitem__(self, key):
|
| 147 |
+
"""For backwards compatibility with the old non-enum modes"""
|
| 148 |
+
if key == 0:
|
| 149 |
+
return self.io_mode
|
| 150 |
+
elif key == 1:
|
| 151 |
+
return self.image_mode
|
| 152 |
+
else:
|
| 153 |
+
raise IndexError(f"Mode has no item {key}")
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
SPECIAL_READ_URIS = "<video", "<screen>", "<clipboard>"
|
| 157 |
+
|
| 158 |
+
# The user can use this string in a write call to get the data back as bytes.
|
| 159 |
+
RETURN_BYTES = "<bytes>"
|
| 160 |
+
|
| 161 |
+
# Example images that will be auto-downloaded
|
| 162 |
+
EXAMPLE_IMAGES = {
|
| 163 |
+
"astronaut.png": "Image of the astronaut Eileen Collins",
|
| 164 |
+
"camera.png": "A grayscale image of a photographer",
|
| 165 |
+
"checkerboard.png": "Black and white image of a chekerboard",
|
| 166 |
+
"wood.jpg": "A (repeatable) texture of wooden planks",
|
| 167 |
+
"bricks.jpg": "A (repeatable) texture of stone bricks",
|
| 168 |
+
"clock.png": "Photo of a clock with motion blur (Stefan van der Walt)",
|
| 169 |
+
"coffee.png": "Image of a cup of coffee (Rachel Michetti)",
|
| 170 |
+
"chelsea.png": "Image of Stefan's cat",
|
| 171 |
+
"wikkie.png": "Image of Almar's cat",
|
| 172 |
+
"coins.png": "Image showing greek coins from Pompeii",
|
| 173 |
+
"horse.png": "Image showing the silhouette of a horse (Andreas Preuss)",
|
| 174 |
+
"hubble_deep_field.png": "Photograph taken by Hubble telescope (NASA)",
|
| 175 |
+
"immunohistochemistry.png": "Immunohistochemical (IHC) staining",
|
| 176 |
+
"moon.png": "Image showing a portion of the surface of the moon",
|
| 177 |
+
"page.png": "A scanned page of text",
|
| 178 |
+
"text.png": "A photograph of handdrawn text",
|
| 179 |
+
"chelsea.zip": "The chelsea.png in a zipfile (for testing)",
|
| 180 |
+
"chelsea.bsdf": "The chelsea.png in a BSDF file(for testing)",
|
| 181 |
+
"newtonscradle.gif": "Animated GIF of a newton's cradle",
|
| 182 |
+
"cockatoo.mp4": "Video file of a cockatoo",
|
| 183 |
+
"stent.npz": "Volumetric image showing a stented abdominal aorta",
|
| 184 |
+
"meadow_cube.jpg": "A cubemap image of a meadow, e.g. to render a skybox.",
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
class Request(object):
|
| 189 |
+
"""ImageResource handling utility.
|
| 190 |
+
|
| 191 |
+
Represents a request for reading or saving an image resource. This
|
| 192 |
+
object wraps information to that request and acts as an interface
|
| 193 |
+
for the plugins to several resources; it allows the user to read
|
| 194 |
+
from filenames, files, http, zipfiles, raw bytes, etc., but offer
|
| 195 |
+
a simple interface to the plugins via ``get_file()`` and
|
| 196 |
+
``get_local_filename()``.
|
| 197 |
+
|
| 198 |
+
For each read/write operation a single Request instance is used and passed
|
| 199 |
+
to the can_read/can_write method of a format, and subsequently to
|
| 200 |
+
the Reader/Writer class. This allows rudimentary passing of
|
| 201 |
+
information between different formats and between a format and
|
| 202 |
+
associated reader/writer.
|
| 203 |
+
|
| 204 |
+
Parameters
|
| 205 |
+
----------
|
| 206 |
+
uri : {str, bytes, file}
|
| 207 |
+
The resource to load the image from.
|
| 208 |
+
mode : str
|
| 209 |
+
The first character is "r" or "w", indicating a read or write
|
| 210 |
+
request. The second character is used to indicate the kind of data:
|
| 211 |
+
"i" for an image, "I" for multiple images, "v" for a volume,
|
| 212 |
+
"V" for multiple volumes, "?" for don't care.
|
| 213 |
+
|
| 214 |
+
"""
|
| 215 |
+
|
| 216 |
+
def __init__(self, uri, mode, *, extension=None, format_hint: str = None, **kwargs):
|
| 217 |
+
|
| 218 |
+
# General
|
| 219 |
+
self.raw_uri = uri
|
| 220 |
+
self._uri_type = None
|
| 221 |
+
self._filename = None
|
| 222 |
+
self._extension = None
|
| 223 |
+
self._format_hint = None
|
| 224 |
+
self._kwargs = kwargs
|
| 225 |
+
self._result = None # Some write actions may have a result
|
| 226 |
+
|
| 227 |
+
# To handle the user-side
|
| 228 |
+
self._filename_zip = None # not None if a zipfile is used
|
| 229 |
+
self._bytes = None # Incoming bytes
|
| 230 |
+
self._zipfile = None # To store a zipfile instance (if used)
|
| 231 |
+
|
| 232 |
+
# To handle the plugin side
|
| 233 |
+
self._file = None # To store the file instance
|
| 234 |
+
self._file_is_local = False # whether the data needs to be copied at end
|
| 235 |
+
self._filename_local = None # not None if using tempfile on this FS
|
| 236 |
+
self._firstbytes = None # For easy header parsing
|
| 237 |
+
|
| 238 |
+
# To store formats that may be able to fulfil this request
|
| 239 |
+
# self._potential_formats = []
|
| 240 |
+
|
| 241 |
+
# Check mode
|
| 242 |
+
try:
|
| 243 |
+
self._mode = Mode(mode)
|
| 244 |
+
except ValueError:
|
| 245 |
+
raise ValueError(f"Invalid Request.Mode: {mode}")
|
| 246 |
+
|
| 247 |
+
# Parse what was given
|
| 248 |
+
self._parse_uri(uri)
|
| 249 |
+
|
| 250 |
+
# Set extension
|
| 251 |
+
if extension is not None:
|
| 252 |
+
if extension[0] != ".":
|
| 253 |
+
raise ValueError(
|
| 254 |
+
"`extension` should be a file extension starting with a `.`,"
|
| 255 |
+
f" but is `{extension}`."
|
| 256 |
+
)
|
| 257 |
+
self._extension = extension
|
| 258 |
+
elif self._filename is not None:
|
| 259 |
+
if self._uri_type in (URI_FILENAME, URI_ZIPPED):
|
| 260 |
+
path = self._filename
|
| 261 |
+
else:
|
| 262 |
+
path = urlparse(self._filename).path
|
| 263 |
+
ext = Path(path).suffix.lower()
|
| 264 |
+
self._extension = ext if ext != "" else None
|
| 265 |
+
|
| 266 |
+
if format_hint is not None:
|
| 267 |
+
warnings.warn(
|
| 268 |
+
"The usage of `format_hint` is deprecated and will be removed in ImageIO v3."
|
| 269 |
+
" Use `extension` instead."
|
| 270 |
+
)
|
| 271 |
+
|
| 272 |
+
if format_hint is not None and format_hint[0] != ".":
|
| 273 |
+
raise ValueError(
|
| 274 |
+
"`format_hint` should be a file extension starting with a `.`,"
|
| 275 |
+
f" but is `{format_hint}`."
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
self.format_hint = format_hint
|
| 279 |
+
|
| 280 |
+
def _parse_uri(self, uri):
|
| 281 |
+
"""Try to figure our what we were given"""
|
| 282 |
+
is_read_request = self.mode.io_mode is IOMode.read
|
| 283 |
+
is_write_request = self.mode.io_mode is IOMode.write
|
| 284 |
+
|
| 285 |
+
if isinstance(uri, str):
|
| 286 |
+
# Explicit
|
| 287 |
+
if uri.startswith("imageio:"):
|
| 288 |
+
if is_write_request:
|
| 289 |
+
raise RuntimeError("Cannot write to the standard images.")
|
| 290 |
+
fn = uri.split(":", 1)[-1].lower()
|
| 291 |
+
fn, _, zip_part = fn.partition(".zip/")
|
| 292 |
+
if zip_part:
|
| 293 |
+
fn += ".zip"
|
| 294 |
+
if fn not in EXAMPLE_IMAGES:
|
| 295 |
+
raise ValueError("Unknown standard image %r." % fn)
|
| 296 |
+
self._uri_type = URI_FILENAME
|
| 297 |
+
self._filename = get_remote_file("images/" + fn, auto=True)
|
| 298 |
+
if zip_part:
|
| 299 |
+
self._filename += "/" + zip_part
|
| 300 |
+
elif uri.startswith("http://") or uri.startswith("https://"):
|
| 301 |
+
self._uri_type = URI_HTTP
|
| 302 |
+
self._filename = uri
|
| 303 |
+
elif uri.startswith("ftp://") or uri.startswith("ftps://"):
|
| 304 |
+
self._uri_type = URI_FTP
|
| 305 |
+
self._filename = uri
|
| 306 |
+
elif uri.startswith("file://"):
|
| 307 |
+
self._uri_type = URI_FILENAME
|
| 308 |
+
self._filename = uri[7:]
|
| 309 |
+
elif uri.startswith(SPECIAL_READ_URIS) and is_read_request:
|
| 310 |
+
self._uri_type = URI_BYTES
|
| 311 |
+
self._filename = uri
|
| 312 |
+
elif uri.startswith(RETURN_BYTES) and is_write_request:
|
| 313 |
+
self._uri_type = URI_BYTES
|
| 314 |
+
self._filename = uri
|
| 315 |
+
else:
|
| 316 |
+
self._uri_type = URI_FILENAME
|
| 317 |
+
self._filename = uri
|
| 318 |
+
|
| 319 |
+
elif isinstance(uri, memoryview) and is_read_request:
|
| 320 |
+
self._uri_type = URI_BYTES
|
| 321 |
+
self._filename = "<bytes>"
|
| 322 |
+
self._bytes = uri.tobytes()
|
| 323 |
+
elif isinstance(uri, bytes) and is_read_request:
|
| 324 |
+
self._uri_type = URI_BYTES
|
| 325 |
+
self._filename = "<bytes>"
|
| 326 |
+
self._bytes = uri
|
| 327 |
+
elif isinstance(uri, Path):
|
| 328 |
+
self._uri_type = URI_FILENAME
|
| 329 |
+
self._filename = str(uri)
|
| 330 |
+
# Files
|
| 331 |
+
elif is_read_request:
|
| 332 |
+
if hasattr(uri, "read") and hasattr(uri, "close"):
|
| 333 |
+
self._uri_type = URI_FILE
|
| 334 |
+
self._filename = "<file>"
|
| 335 |
+
self._file = uri # Data must be read from here
|
| 336 |
+
elif is_write_request:
|
| 337 |
+
if hasattr(uri, "write") and hasattr(uri, "close"):
|
| 338 |
+
self._uri_type = URI_FILE
|
| 339 |
+
self._filename = "<file>"
|
| 340 |
+
self._file = uri # Data must be written here
|
| 341 |
+
|
| 342 |
+
# Expand user dir
|
| 343 |
+
if self._uri_type == URI_FILENAME and self._filename.startswith("~"):
|
| 344 |
+
self._filename = os.path.expanduser(self._filename)
|
| 345 |
+
|
| 346 |
+
# Check if a zipfile
|
| 347 |
+
if self._uri_type == URI_FILENAME:
|
| 348 |
+
# Search for zip extension followed by a path separater
|
| 349 |
+
for needle in [".zip/", ".zip\\"]:
|
| 350 |
+
zip_i = self._filename.lower().find(needle)
|
| 351 |
+
if zip_i > 0:
|
| 352 |
+
zip_i += 4
|
| 353 |
+
zip_path = self._filename[:zip_i]
|
| 354 |
+
if os.path.isdir(zip_path):
|
| 355 |
+
pass # is an existing dir (see #548)
|
| 356 |
+
elif is_write_request or os.path.isfile(zip_path):
|
| 357 |
+
self._uri_type = URI_ZIPPED
|
| 358 |
+
self._filename_zip = (
|
| 359 |
+
zip_path,
|
| 360 |
+
self._filename[zip_i:].lstrip("/\\"),
|
| 361 |
+
)
|
| 362 |
+
break
|
| 363 |
+
|
| 364 |
+
# Check if we could read it
|
| 365 |
+
if self._uri_type is None:
|
| 366 |
+
uri_r = repr(uri)
|
| 367 |
+
if len(uri_r) > 60:
|
| 368 |
+
uri_r = uri_r[:57] + "..."
|
| 369 |
+
raise IOError("Cannot understand given URI: %s." % uri_r)
|
| 370 |
+
|
| 371 |
+
# Check if this is supported
|
| 372 |
+
noWriting = [URI_HTTP, URI_FTP]
|
| 373 |
+
if is_write_request and self._uri_type in noWriting:
|
| 374 |
+
raise IOError("imageio does not support writing to http/ftp.")
|
| 375 |
+
|
| 376 |
+
# Deprecated way to load standard images, give a sensible error message
|
| 377 |
+
if is_read_request and self._uri_type in [URI_FILENAME, URI_ZIPPED]:
|
| 378 |
+
fn = self._filename
|
| 379 |
+
if self._filename_zip:
|
| 380 |
+
fn = self._filename_zip[0]
|
| 381 |
+
if (not os.path.exists(fn)) and (fn in EXAMPLE_IMAGES):
|
| 382 |
+
raise IOError(
|
| 383 |
+
"No such file: %r. This file looks like one of "
|
| 384 |
+
"the standard images, but from imageio 2.1, "
|
| 385 |
+
"standard images have to be specified using "
|
| 386 |
+
'"imageio:%s".' % (fn, fn)
|
| 387 |
+
)
|
| 388 |
+
|
| 389 |
+
# Make filename absolute
|
| 390 |
+
if self._uri_type in [URI_FILENAME, URI_ZIPPED]:
|
| 391 |
+
if self._filename_zip:
|
| 392 |
+
self._filename_zip = (
|
| 393 |
+
os.path.abspath(self._filename_zip[0]),
|
| 394 |
+
self._filename_zip[1],
|
| 395 |
+
)
|
| 396 |
+
else:
|
| 397 |
+
self._filename = os.path.abspath(self._filename)
|
| 398 |
+
|
| 399 |
+
# Check whether file name is valid
|
| 400 |
+
if self._uri_type in [URI_FILENAME, URI_ZIPPED]:
|
| 401 |
+
fn = self._filename
|
| 402 |
+
if self._filename_zip:
|
| 403 |
+
fn = self._filename_zip[0]
|
| 404 |
+
if is_read_request:
|
| 405 |
+
# Reading: check that the file exists (but is allowed a dir)
|
| 406 |
+
if not os.path.exists(fn):
|
| 407 |
+
raise FileNotFoundError("No such file: '%s'" % fn)
|
| 408 |
+
else:
|
| 409 |
+
# Writing: check that the directory to write to does exist
|
| 410 |
+
dn = os.path.dirname(fn)
|
| 411 |
+
if not os.path.exists(dn):
|
| 412 |
+
raise FileNotFoundError("The directory %r does not exist" % dn)
|
| 413 |
+
|
| 414 |
+
@property
|
| 415 |
+
def filename(self):
|
| 416 |
+
"""Name of the ImageResource.
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
The uri for which reading/saving was requested. This
|
| 420 |
+
can be a filename, an http address, or other resource
|
| 421 |
+
identifier. Do not rely on the filename to obtain the data,
|
| 422 |
+
but use ``get_file()`` or ``get_local_filename()`` instead.
|
| 423 |
+
"""
|
| 424 |
+
return self._filename
|
| 425 |
+
|
| 426 |
+
@property
|
| 427 |
+
def extension(self) -> str:
|
| 428 |
+
"""The (lowercase) extension of the requested filename.
|
| 429 |
+
Suffixes in url's are stripped. Can be None if the request is
|
| 430 |
+
not based on a filename.
|
| 431 |
+
"""
|
| 432 |
+
return self._extension
|
| 433 |
+
|
| 434 |
+
@property
|
| 435 |
+
def format_hint(self) -> Optional[str]:
|
| 436 |
+
return self._format_hint
|
| 437 |
+
|
| 438 |
+
@format_hint.setter
|
| 439 |
+
def format_hint(self, format: str) -> None:
|
| 440 |
+
self._format_hint = format
|
| 441 |
+
if self._extension is None:
|
| 442 |
+
self._extension = format
|
| 443 |
+
|
| 444 |
+
@property
|
| 445 |
+
def mode(self):
|
| 446 |
+
"""The mode of the request. The first character is "r" or "w",
|
| 447 |
+
indicating a read or write request. The second character is
|
| 448 |
+
used to indicate the kind of data:
|
| 449 |
+
"i" for an image, "I" for multiple images, "v" for a volume,
|
| 450 |
+
"V" for multiple volumes, "?" for don't care.
|
| 451 |
+
"""
|
| 452 |
+
return self._mode
|
| 453 |
+
|
| 454 |
+
@property
|
| 455 |
+
def kwargs(self):
|
| 456 |
+
"""The dict of keyword arguments supplied by the user."""
|
| 457 |
+
return self._kwargs
|
| 458 |
+
|
| 459 |
+
# For obtaining data
|
| 460 |
+
|
| 461 |
+
def get_file(self):
|
| 462 |
+
"""get_file()
|
| 463 |
+
Get a file object for the resource associated with this request.
|
| 464 |
+
If this is a reading request, the file is in read mode,
|
| 465 |
+
otherwise in write mode. This method is not thread safe. Plugins
|
| 466 |
+
should not close the file when done.
|
| 467 |
+
|
| 468 |
+
This is the preferred way to read/write the data. But if a
|
| 469 |
+
format cannot handle file-like objects, they should use
|
| 470 |
+
``get_local_filename()``.
|
| 471 |
+
"""
|
| 472 |
+
want_to_write = self.mode.io_mode is IOMode.write
|
| 473 |
+
|
| 474 |
+
# Is there already a file?
|
| 475 |
+
# Either _uri_type == URI_FILE, or we already opened the file,
|
| 476 |
+
# e.g. by using firstbytes
|
| 477 |
+
if self._file is not None:
|
| 478 |
+
return self._file
|
| 479 |
+
|
| 480 |
+
if self._uri_type == URI_BYTES:
|
| 481 |
+
if want_to_write:
|
| 482 |
+
# Create new file object, we catch the bytes in finish()
|
| 483 |
+
self._file = BytesIO()
|
| 484 |
+
self._file_is_local = True
|
| 485 |
+
else:
|
| 486 |
+
self._file = BytesIO(self._bytes)
|
| 487 |
+
|
| 488 |
+
elif self._uri_type == URI_FILENAME:
|
| 489 |
+
if want_to_write:
|
| 490 |
+
self._file = open(self.filename, "wb")
|
| 491 |
+
else:
|
| 492 |
+
self._file = open(self.filename, "rb")
|
| 493 |
+
|
| 494 |
+
elif self._uri_type == URI_ZIPPED:
|
| 495 |
+
# Get the correct filename
|
| 496 |
+
filename, name = self._filename_zip
|
| 497 |
+
if want_to_write:
|
| 498 |
+
# Create new file object, we catch the bytes in finish()
|
| 499 |
+
self._file = BytesIO()
|
| 500 |
+
self._file_is_local = True
|
| 501 |
+
else:
|
| 502 |
+
# Open zipfile and open new file object for specific file
|
| 503 |
+
self._zipfile = zipfile.ZipFile(filename, "r")
|
| 504 |
+
self._file = self._zipfile.open(name, "r")
|
| 505 |
+
self._file = SeekableFileObject(self._file)
|
| 506 |
+
|
| 507 |
+
elif self._uri_type in [URI_HTTP or URI_FTP]:
|
| 508 |
+
assert not want_to_write # This should have been tested in init
|
| 509 |
+
timeout = os.getenv("IMAGEIO_REQUEST_TIMEOUT")
|
| 510 |
+
if timeout is None or not timeout.isdigit():
|
| 511 |
+
timeout = 5
|
| 512 |
+
self._file = urlopen(self.filename, timeout=float(timeout))
|
| 513 |
+
self._file = SeekableFileObject(self._file)
|
| 514 |
+
|
| 515 |
+
return self._file
|
| 516 |
+
|
| 517 |
+
def get_local_filename(self):
|
| 518 |
+
"""get_local_filename()
|
| 519 |
+
If the filename is an existing file on this filesystem, return
|
| 520 |
+
that. Otherwise a temporary file is created on the local file
|
| 521 |
+
system which can be used by the format to read from or write to.
|
| 522 |
+
"""
|
| 523 |
+
|
| 524 |
+
if self._uri_type == URI_FILENAME:
|
| 525 |
+
return self._filename
|
| 526 |
+
else:
|
| 527 |
+
# Get filename
|
| 528 |
+
if self.extension is not None:
|
| 529 |
+
ext = self.extension
|
| 530 |
+
else:
|
| 531 |
+
ext = os.path.splitext(self._filename)[1]
|
| 532 |
+
self._filename_local = tempfile.mktemp(ext, "imageio_")
|
| 533 |
+
# Write stuff to it?
|
| 534 |
+
if self.mode.io_mode == IOMode.read:
|
| 535 |
+
with open(self._filename_local, "wb") as file:
|
| 536 |
+
shutil.copyfileobj(self.get_file(), file)
|
| 537 |
+
return self._filename_local
|
| 538 |
+
|
| 539 |
+
def finish(self) -> None:
|
| 540 |
+
"""Wrap up this request.
|
| 541 |
+
|
| 542 |
+
Finishes any pending reads or writes, closes any open files and frees
|
| 543 |
+
any resources allocated by this request.
|
| 544 |
+
"""
|
| 545 |
+
|
| 546 |
+
if self.mode.io_mode == IOMode.write:
|
| 547 |
+
|
| 548 |
+
# See if we "own" the data and must put it somewhere
|
| 549 |
+
bytes = None
|
| 550 |
+
if self._filename_local:
|
| 551 |
+
bytes = Path(self._filename_local).read_bytes()
|
| 552 |
+
elif self._file_is_local:
|
| 553 |
+
self._file_is_local = False
|
| 554 |
+
bytes = self._file.getvalue()
|
| 555 |
+
|
| 556 |
+
# Put the data in the right place
|
| 557 |
+
if bytes is not None:
|
| 558 |
+
if self._uri_type == URI_BYTES:
|
| 559 |
+
self._result = bytes # Picked up by imread function
|
| 560 |
+
elif self._uri_type == URI_FILE:
|
| 561 |
+
self._file.write(bytes)
|
| 562 |
+
elif self._uri_type == URI_ZIPPED:
|
| 563 |
+
zf = zipfile.ZipFile(self._filename_zip[0], "a")
|
| 564 |
+
zf.writestr(self._filename_zip[1], bytes)
|
| 565 |
+
zf.close()
|
| 566 |
+
# elif self._uri_type == URI_FILENAME: -> is always direct
|
| 567 |
+
# elif self._uri_type == URI_FTP/HTTP: -> write not supported
|
| 568 |
+
|
| 569 |
+
# Close open files that we know of (and are responsible for)
|
| 570 |
+
if self._file and self._uri_type != URI_FILE:
|
| 571 |
+
self._file.close()
|
| 572 |
+
self._file = None
|
| 573 |
+
if self._zipfile:
|
| 574 |
+
self._zipfile.close()
|
| 575 |
+
self._zipfile = None
|
| 576 |
+
|
| 577 |
+
# Remove temp file
|
| 578 |
+
if self._filename_local:
|
| 579 |
+
try:
|
| 580 |
+
os.remove(self._filename_local)
|
| 581 |
+
except Exception: # pragma: no cover
|
| 582 |
+
warnings.warn(
|
| 583 |
+
"Failed to delete the temporary file at "
|
| 584 |
+
f"`{self._filename_local}`. Please report this issue."
|
| 585 |
+
)
|
| 586 |
+
self._filename_local = None
|
| 587 |
+
|
| 588 |
+
# Detach so gc can clean even if a reference of self lingers
|
| 589 |
+
self._bytes = None
|
| 590 |
+
|
| 591 |
+
def get_result(self):
|
| 592 |
+
"""For internal use. In some situations a write action can have
|
| 593 |
+
a result (bytes data). That is obtained with this function.
|
| 594 |
+
"""
|
| 595 |
+
# Is there a reason to disallow reading multiple times?
|
| 596 |
+
self._result, res = None, self._result
|
| 597 |
+
return res
|
| 598 |
+
|
| 599 |
+
@property
|
| 600 |
+
def firstbytes(self):
|
| 601 |
+
"""The first 256 bytes of the file. These can be used to
|
| 602 |
+
parse the header to determine the file-format.
|
| 603 |
+
"""
|
| 604 |
+
if self._firstbytes is None:
|
| 605 |
+
self._read_first_bytes()
|
| 606 |
+
return self._firstbytes
|
| 607 |
+
|
| 608 |
+
def _read_first_bytes(self, N=256):
|
| 609 |
+
if self._bytes is not None:
|
| 610 |
+
self._firstbytes = self._bytes[:N]
|
| 611 |
+
else:
|
| 612 |
+
# Prepare
|
| 613 |
+
try:
|
| 614 |
+
f = self.get_file()
|
| 615 |
+
except IOError:
|
| 616 |
+
if os.path.isdir(self.filename): # A directory, e.g. for DICOM
|
| 617 |
+
self._firstbytes = bytes()
|
| 618 |
+
return
|
| 619 |
+
raise
|
| 620 |
+
try:
|
| 621 |
+
i = f.tell()
|
| 622 |
+
except Exception:
|
| 623 |
+
i = None
|
| 624 |
+
# Read
|
| 625 |
+
self._firstbytes = read_n_bytes(f, N)
|
| 626 |
+
# Set back
|
| 627 |
+
try:
|
| 628 |
+
if i is None:
|
| 629 |
+
raise Exception("cannot seek with None")
|
| 630 |
+
f.seek(i)
|
| 631 |
+
except Exception:
|
| 632 |
+
# Prevent get_file() from reusing the file
|
| 633 |
+
self._file = None
|
| 634 |
+
# If the given URI was a file object, we have a problem,
|
| 635 |
+
if self._uri_type == URI_FILE:
|
| 636 |
+
raise IOError("Cannot seek back after getting firstbytes!")
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
def read_n_bytes(f, N):
|
| 640 |
+
"""read_n_bytes(file, n)
|
| 641 |
+
|
| 642 |
+
Read n bytes from the given file, or less if the file has less
|
| 643 |
+
bytes. Returns zero bytes if the file is closed.
|
| 644 |
+
"""
|
| 645 |
+
bb = bytes()
|
| 646 |
+
while len(bb) < N:
|
| 647 |
+
extra_bytes = f.read(N - len(bb))
|
| 648 |
+
if not extra_bytes:
|
| 649 |
+
break
|
| 650 |
+
bb += extra_bytes
|
| 651 |
+
return bb
|
| 652 |
+
|
| 653 |
+
|
| 654 |
+
class SeekableFileObject:
|
| 655 |
+
"""A readonly wrapper file object that add support for seeking, even if
|
| 656 |
+
the wrapped file object does not. The allows us to stream from http and
|
| 657 |
+
still use Pillow.
|
| 658 |
+
"""
|
| 659 |
+
|
| 660 |
+
def __init__(self, f):
|
| 661 |
+
self.f = f
|
| 662 |
+
self._i = 0 # >=0 but can exceed buffer
|
| 663 |
+
self._buffer = b""
|
| 664 |
+
self._have_all = False
|
| 665 |
+
self.closed = False
|
| 666 |
+
|
| 667 |
+
def read(self, n=None):
|
| 668 |
+
|
| 669 |
+
# Fix up n
|
| 670 |
+
if n is None:
|
| 671 |
+
pass
|
| 672 |
+
else:
|
| 673 |
+
n = int(n)
|
| 674 |
+
if n < 0:
|
| 675 |
+
n = None
|
| 676 |
+
|
| 677 |
+
# Can and must we read more?
|
| 678 |
+
if not self._have_all:
|
| 679 |
+
more = b""
|
| 680 |
+
if n is None:
|
| 681 |
+
more = self.f.read()
|
| 682 |
+
self._have_all = True
|
| 683 |
+
else:
|
| 684 |
+
want_i = self._i + n
|
| 685 |
+
want_more = want_i - len(self._buffer)
|
| 686 |
+
if want_more > 0:
|
| 687 |
+
more = self.f.read(want_more)
|
| 688 |
+
if len(more) < want_more:
|
| 689 |
+
self._have_all = True
|
| 690 |
+
self._buffer += more
|
| 691 |
+
|
| 692 |
+
# Read data from buffer and update pointer
|
| 693 |
+
if n is None:
|
| 694 |
+
res = self._buffer[self._i :]
|
| 695 |
+
else:
|
| 696 |
+
res = self._buffer[self._i : self._i + n]
|
| 697 |
+
self._i += len(res)
|
| 698 |
+
|
| 699 |
+
return res
|
| 700 |
+
|
| 701 |
+
def tell(self):
|
| 702 |
+
return self._i
|
| 703 |
+
|
| 704 |
+
def seek(self, i, mode=0):
|
| 705 |
+
# Mimic BytesIO behavior
|
| 706 |
+
|
| 707 |
+
# Get the absolute new position
|
| 708 |
+
i = int(i)
|
| 709 |
+
if mode == 0:
|
| 710 |
+
if i < 0:
|
| 711 |
+
raise ValueError("negative seek value " + str(i))
|
| 712 |
+
real_i = i
|
| 713 |
+
elif mode == 1:
|
| 714 |
+
real_i = max(0, self._i + i) # negative ok here
|
| 715 |
+
elif mode == 2:
|
| 716 |
+
if not self._have_all:
|
| 717 |
+
self.read()
|
| 718 |
+
real_i = max(0, len(self._buffer) + i)
|
| 719 |
+
else:
|
| 720 |
+
raise ValueError("invalid whence (%s, should be 0, 1 or 2)" % i)
|
| 721 |
+
|
| 722 |
+
# Read some?
|
| 723 |
+
if real_i <= len(self._buffer):
|
| 724 |
+
pass # no need to read
|
| 725 |
+
elif not self._have_all:
|
| 726 |
+
assert real_i > self._i # if we don't have all, _i cannot be > _buffer
|
| 727 |
+
self.read(real_i - self._i) # sets self._i
|
| 728 |
+
|
| 729 |
+
self._i = real_i
|
| 730 |
+
return self._i
|
| 731 |
+
|
| 732 |
+
def close(self):
|
| 733 |
+
self.closed = True
|
| 734 |
+
self.f.close()
|
| 735 |
+
|
| 736 |
+
def isatty(self):
|
| 737 |
+
return False
|
| 738 |
+
|
| 739 |
+
def seekable(self):
|
| 740 |
+
return True
|
| 741 |
+
|
| 742 |
+
|
| 743 |
+
class InitializationError(Exception):
|
| 744 |
+
"""The plugin could not initialize from the given request.
|
| 745 |
+
|
| 746 |
+
This is a _internal_ error that is raised by plugins that fail to handle
|
| 747 |
+
a given request. We use this to differentiate incompatibility between
|
| 748 |
+
a plugin and a request from an actual error/bug inside a plugin.
|
| 749 |
+
|
| 750 |
+
"""
|
| 751 |
+
|
| 752 |
+
pass
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/core/v3_plugin_api.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from . import Request
|
| 2 |
+
from ..typing import ArrayLike
|
| 3 |
+
import numpy as np
|
| 4 |
+
from typing import Optional, Dict, Any, Tuple, Union, List, Iterator
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@dataclass
|
| 9 |
+
class ImageProperties:
|
| 10 |
+
"""Standardized Metadata
|
| 11 |
+
|
| 12 |
+
ImageProperties represent a set of standardized metadata that is available
|
| 13 |
+
under the same name for every supported format. If the ImageResource (or
|
| 14 |
+
format) does not specify the value, a sensible default value is chosen
|
| 15 |
+
instead.
|
| 16 |
+
|
| 17 |
+
Attributes
|
| 18 |
+
----------
|
| 19 |
+
shape : Tuple[int, ...]
|
| 20 |
+
The shape of the loaded ndimage.
|
| 21 |
+
dtype : np.dtype
|
| 22 |
+
The dtype of the loaded ndimage.
|
| 23 |
+
is_batch : bool
|
| 24 |
+
If True, the first dimension of the ndimage represents a batch dimension
|
| 25 |
+
along which several images are stacked.
|
| 26 |
+
spacing : Tuple
|
| 27 |
+
A tuple describing the spacing between pixels along each axis of the
|
| 28 |
+
ndimage. If the spacing is uniform along an axis the value corresponding
|
| 29 |
+
to that axis is a single float. If the spacing is non-uniform, the value
|
| 30 |
+
corresponding to that axis is a tuple in which the i-th element
|
| 31 |
+
indicates the spacing between the i-th and (i+1)-th pixel along that
|
| 32 |
+
axis.
|
| 33 |
+
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
shape: Tuple[int, ...]
|
| 37 |
+
dtype: np.dtype
|
| 38 |
+
is_batch: bool = False
|
| 39 |
+
spacing: Optional[tuple] = None
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class PluginV3:
|
| 43 |
+
"""A ImageIO Plugin.
|
| 44 |
+
|
| 45 |
+
This is an abstract plugin that documents the v3 plugin API interface. A
|
| 46 |
+
plugin is an adapter/wrapper around a backend that converts a request from
|
| 47 |
+
iio.core (e.g., read an image from file) into a sequence of instructions for
|
| 48 |
+
the backend that fullfill the request.
|
| 49 |
+
|
| 50 |
+
Plugin authors may choose to subclass this class when implementing a new
|
| 51 |
+
plugin, but aren't obliged to do so. As long as the plugin class implements
|
| 52 |
+
the interface (methods) described below the ImageIO core will treat it just
|
| 53 |
+
like any other plugin.
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
Parameters
|
| 57 |
+
----------
|
| 58 |
+
request : iio.Request
|
| 59 |
+
A request object that represents the users intent. It provides a
|
| 60 |
+
standard interface to access the various ImageResources and serves them
|
| 61 |
+
to the plugin as a file object (or file). Check the docs for details.
|
| 62 |
+
**kwargs : Any
|
| 63 |
+
Additional configuration arguments for the plugin or backend. Usually
|
| 64 |
+
these match the configuration arguments available on the backend and
|
| 65 |
+
are forwarded to it.
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
Raises
|
| 69 |
+
------
|
| 70 |
+
InitializationError
|
| 71 |
+
During ``__init__`` the plugin tests if it can fulfill the request. If
|
| 72 |
+
it can't, e.g., because the request points to a file in the wrong
|
| 73 |
+
format, then it should raise an ``InitializationError`` and provide a
|
| 74 |
+
reason for failure. This reason may be reported to the user.
|
| 75 |
+
ImportError
|
| 76 |
+
Plugins will be imported dynamically when listed in
|
| 77 |
+
``iio.config.known_plugins`` to fullfill requests. This way, users only
|
| 78 |
+
have to load plugins/backends they actually use. If this plugin's backend
|
| 79 |
+
is not installed, it should raise an ``ImportError`` either during
|
| 80 |
+
module import or during class construction.
|
| 81 |
+
|
| 82 |
+
Notes
|
| 83 |
+
-----
|
| 84 |
+
Upon successful construction the plugin takes ownership of the provided
|
| 85 |
+
request. This means that it is the plugin's responsibility to call
|
| 86 |
+
request.finish() to close the resource when it is no longer needed.
|
| 87 |
+
|
| 88 |
+
Plugins _must_ implement a context manager that closes and cleans any
|
| 89 |
+
resources held by the plugin upon exit.
|
| 90 |
+
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
def __init__(self, request: Request) -> None:
|
| 94 |
+
"""Initialize a new Plugin Instance.
|
| 95 |
+
|
| 96 |
+
See Plugin's docstring for detailed documentation.
|
| 97 |
+
|
| 98 |
+
Notes
|
| 99 |
+
-----
|
| 100 |
+
The implementation here stores the request as a local variable that is
|
| 101 |
+
exposed using a @property below. If you inherit from PluginV3, remember
|
| 102 |
+
to call ``super().__init__(request)``.
|
| 103 |
+
|
| 104 |
+
"""
|
| 105 |
+
|
| 106 |
+
self._request = request
|
| 107 |
+
|
| 108 |
+
def read(self, *, index: int = 0) -> np.ndarray:
|
| 109 |
+
"""Read a ndimage.
|
| 110 |
+
|
| 111 |
+
The ``read`` method loads a (single) ndimage, located at ``index`` from
|
| 112 |
+
the requested ImageResource.
|
| 113 |
+
|
| 114 |
+
It is at the plugin's descretion to decide (and document) what
|
| 115 |
+
constitutes a single ndimage. A sensible way to make this decision is to
|
| 116 |
+
choose based on the ImageResource's format and on what users will expect
|
| 117 |
+
from such a format. For example, a sensible choice for a TIFF file
|
| 118 |
+
produced by an ImageJ hyperstack is to read it as a volumetric ndimage
|
| 119 |
+
(1 color dimension followed by 3 spatial dimensions). On the other hand,
|
| 120 |
+
a sensible choice for a MP4 file produced by Davinci Resolve is to treat
|
| 121 |
+
each frame as a ndimage (2 spatial dimensions followed by 1 color
|
| 122 |
+
dimension).
|
| 123 |
+
|
| 124 |
+
The value ``index=None`` is special. It requests the plugin to load all
|
| 125 |
+
ndimages in the file and stack them along a new first axis. For example,
|
| 126 |
+
if a MP4 file is read with ``index=None`` and the plugin identifies
|
| 127 |
+
single frames as ndimages, then the plugin should read all frames and
|
| 128 |
+
stack them into a new ndimage which now contains a time axis as its
|
| 129 |
+
first axis. If a PNG file (single image format) is read with
|
| 130 |
+
``index=None`` the plugin does a very similar thing: It loads all
|
| 131 |
+
ndimages in the file (here it's just one) and stacks them along a new
|
| 132 |
+
first axis, effectively prepending an axis with size 1 to the image. If
|
| 133 |
+
a plugin does not wish to support ``index=None`` it should set a more
|
| 134 |
+
sensible default and raise a ``ValueError`` when requested to read using
|
| 135 |
+
``index=None``.
|
| 136 |
+
|
| 137 |
+
Parameters
|
| 138 |
+
----------
|
| 139 |
+
index : int
|
| 140 |
+
If the ImageResource contains multiple ndimages, and index is an
|
| 141 |
+
integer, select the index-th ndimage from among them and return it.
|
| 142 |
+
If index is an ellipsis (...), read all ndimages in the file and
|
| 143 |
+
stack them along a new batch dimension. If index is None, let the
|
| 144 |
+
plugin decide. If the index is out of bounds a ``ValueError`` is
|
| 145 |
+
raised.
|
| 146 |
+
**kwargs : Any
|
| 147 |
+
The read method may accept any number of plugin-specific keyword
|
| 148 |
+
arguments to further customize the read behavior. Usually these
|
| 149 |
+
match the arguments available on the backend and are forwarded to
|
| 150 |
+
it.
|
| 151 |
+
|
| 152 |
+
Returns
|
| 153 |
+
-------
|
| 154 |
+
ndimage : np.ndarray
|
| 155 |
+
A ndimage containing decoded pixel data (sometimes called bitmap).
|
| 156 |
+
|
| 157 |
+
Notes
|
| 158 |
+
-----
|
| 159 |
+
The ImageResource from which the plugin should read is managed by the
|
| 160 |
+
provided request object. Directly accessing the managed ImageResource is
|
| 161 |
+
_not_ permitted. Instead, you can get FileLike access to the
|
| 162 |
+
ImageResource via request.get_file().
|
| 163 |
+
|
| 164 |
+
If the backend doesn't support reading from FileLike objects, you can
|
| 165 |
+
request a temporary file to pass to the backend via
|
| 166 |
+
``request.get_local_filename()``. This is, however, not very performant
|
| 167 |
+
(involves copying the Request's content into a temporary file), so you
|
| 168 |
+
should avoid doing this whenever possible. Consider it a fallback method
|
| 169 |
+
in case all else fails.
|
| 170 |
+
|
| 171 |
+
"""
|
| 172 |
+
raise NotImplementedError()
|
| 173 |
+
|
| 174 |
+
def write(self, ndimage: Union[ArrayLike, List[ArrayLike]]) -> Optional[bytes]:
|
| 175 |
+
"""Write a ndimage to a ImageResource.
|
| 176 |
+
|
| 177 |
+
The ``write`` method encodes the given ndimage into the format handled
|
| 178 |
+
by the backend and writes it to the ImageResource. It overwrites
|
| 179 |
+
any content that may have been previously stored in the file.
|
| 180 |
+
|
| 181 |
+
If the backend supports only a single format then it must check if
|
| 182 |
+
the ImageResource matches that format and raise an exception if not.
|
| 183 |
+
Typically, this should be done during initialization in the form of a
|
| 184 |
+
``InitializationError``.
|
| 185 |
+
|
| 186 |
+
If the backend supports more than one format it must determine the
|
| 187 |
+
requested/desired format. Usually this can be done by inspecting the
|
| 188 |
+
ImageResource (e.g., by checking ``request.extension``), or by providing
|
| 189 |
+
a mechanism to explicitly set the format (perhaps with a - sensible -
|
| 190 |
+
default value). If the plugin can not determine the desired format, it
|
| 191 |
+
**must not** write to the ImageResource, but raise an exception instead.
|
| 192 |
+
|
| 193 |
+
If the backend supports at least one format that can hold multiple
|
| 194 |
+
ndimages it should be capable of handling ndimage batches and lists of
|
| 195 |
+
ndimages. If the ``ndimage`` input is a list of ndimages, the plugin
|
| 196 |
+
should not assume that the ndimages are not stackable, i.e., ndimages
|
| 197 |
+
may have different shapes. Otherwise, the ``ndimage`` may be a batch of
|
| 198 |
+
multiple ndimages stacked along the first axis of the array. The plugin
|
| 199 |
+
must be able to discover this, either automatically or via additional
|
| 200 |
+
`kwargs`. If there is ambiguity in the process, the plugin must clearly
|
| 201 |
+
document what happens in such cases and, if possible, describe how to
|
| 202 |
+
resolve this ambiguity.
|
| 203 |
+
|
| 204 |
+
Parameters
|
| 205 |
+
----------
|
| 206 |
+
ndimage : ArrayLike
|
| 207 |
+
The ndimage to encode and write to the current ImageResource.
|
| 208 |
+
**kwargs : Any
|
| 209 |
+
The write method may accept any number of plugin-specific keyword
|
| 210 |
+
arguments to customize the writing behavior. Usually these match the
|
| 211 |
+
arguments available on the backend and are forwarded to it.
|
| 212 |
+
|
| 213 |
+
Returns
|
| 214 |
+
-------
|
| 215 |
+
encoded_image : bytes or None
|
| 216 |
+
If the chosen ImageResource is the special target ``"<bytes>"`` then
|
| 217 |
+
write should return a byte string containing the encoded image data.
|
| 218 |
+
Otherwise, it returns None.
|
| 219 |
+
|
| 220 |
+
Notes
|
| 221 |
+
-----
|
| 222 |
+
The ImageResource to which the plugin should write to is managed by the
|
| 223 |
+
provided request object. Directly accessing the managed ImageResource is
|
| 224 |
+
_not_ permitted. Instead, you can get FileLike access to the
|
| 225 |
+
ImageResource via request.get_file().
|
| 226 |
+
|
| 227 |
+
If the backend doesn't support writing to FileLike objects, you can
|
| 228 |
+
request a temporary file to pass to the backend via
|
| 229 |
+
``request.get_local_filename()``. This is, however, not very performant
|
| 230 |
+
(involves copying the Request's content from a temporary file), so you
|
| 231 |
+
should avoid doing this whenever possible. Consider it a fallback method
|
| 232 |
+
in case all else fails.
|
| 233 |
+
|
| 234 |
+
"""
|
| 235 |
+
raise NotImplementedError()
|
| 236 |
+
|
| 237 |
+
def iter(self) -> Iterator[np.ndarray]:
|
| 238 |
+
"""Iterate the ImageResource.
|
| 239 |
+
|
| 240 |
+
This method returns a generator that yields ndimages in the order in which
|
| 241 |
+
they appear in the file. This is roughly equivalent to::
|
| 242 |
+
|
| 243 |
+
idx = 0
|
| 244 |
+
while True:
|
| 245 |
+
try:
|
| 246 |
+
yield self.read(index=idx)
|
| 247 |
+
except ValueError:
|
| 248 |
+
break
|
| 249 |
+
|
| 250 |
+
It works very similar to ``read``, and you can consult the documentation
|
| 251 |
+
of that method for additional information on desired behavior.
|
| 252 |
+
|
| 253 |
+
Parameters
|
| 254 |
+
----------
|
| 255 |
+
**kwargs : Any
|
| 256 |
+
The iter method may accept any number of plugin-specific keyword
|
| 257 |
+
arguments to further customize the reading/iteration behavior.
|
| 258 |
+
Usually these match the arguments available on the backend and are
|
| 259 |
+
forwarded to it.
|
| 260 |
+
|
| 261 |
+
Yields
|
| 262 |
+
------
|
| 263 |
+
ndimage : np.ndarray
|
| 264 |
+
A ndimage containing decoded pixel data (sometimes called bitmap).
|
| 265 |
+
|
| 266 |
+
See Also
|
| 267 |
+
--------
|
| 268 |
+
PluginV3.read
|
| 269 |
+
|
| 270 |
+
"""
|
| 271 |
+
raise NotImplementedError()
|
| 272 |
+
|
| 273 |
+
def properties(self, index: int = 0) -> ImageProperties:
|
| 274 |
+
"""Standardized ndimage metadata.
|
| 275 |
+
|
| 276 |
+
Parameters
|
| 277 |
+
----------
|
| 278 |
+
index : int
|
| 279 |
+
If the ImageResource contains multiple ndimages, and index is an
|
| 280 |
+
integer, select the index-th ndimage from among them and return its
|
| 281 |
+
properties. If index is an ellipsis (...), read all ndimages in the file
|
| 282 |
+
and stack them along a new batch dimension and return their properties.
|
| 283 |
+
If index is None, the plugin decides the default.
|
| 284 |
+
|
| 285 |
+
Returns
|
| 286 |
+
-------
|
| 287 |
+
properties : ImageProperties
|
| 288 |
+
A dataclass filled with standardized image metadata.
|
| 289 |
+
|
| 290 |
+
"""
|
| 291 |
+
raise NotImplementedError()
|
| 292 |
+
|
| 293 |
+
def metadata(self, index: int = 0, exclude_applied: bool = True) -> Dict[str, Any]:
|
| 294 |
+
"""Format-Specific ndimage metadata.
|
| 295 |
+
|
| 296 |
+
The method reads metadata stored in the ImageResource and returns it as
|
| 297 |
+
a python dict. The plugin is free to choose which name to give a piece
|
| 298 |
+
of metadata; however, if possible, it should match the name given by the
|
| 299 |
+
format. There is no requirement regarding the fields a plugin must
|
| 300 |
+
expose; however, if a plugin does expose any,``exclude_applied`` applies
|
| 301 |
+
to these fields.
|
| 302 |
+
|
| 303 |
+
If the plugin does return metadata items, it must check the value of
|
| 304 |
+
``exclude_applied`` before returning them. If ``exclude applied`` is
|
| 305 |
+
True, then any metadata item that would be applied to an ndimage
|
| 306 |
+
returned by ``read`` (or ``iter``) must not be returned. This is done to
|
| 307 |
+
avoid confusion; for example, if an ImageResource defines the ExIF
|
| 308 |
+
rotation tag, and the plugin applies the rotation to the data before
|
| 309 |
+
returning it, then ``exclude_applied`` prevents confusion on whether the
|
| 310 |
+
tag was already applied or not.
|
| 311 |
+
|
| 312 |
+
The `kwarg` ``index`` behaves similar to its counterpart in ``read``
|
| 313 |
+
with one exception: If the ``index`` is None, then global metadata is
|
| 314 |
+
returned instead of returning a combination of all metadata items. If
|
| 315 |
+
there is no global metadata, the Plugin should return an empty dict or
|
| 316 |
+
raise an exception.
|
| 317 |
+
|
| 318 |
+
Parameters
|
| 319 |
+
----------
|
| 320 |
+
index : int
|
| 321 |
+
If the ImageResource contains multiple ndimages, and index is an
|
| 322 |
+
integer, select the index-th ndimage from among them and return its
|
| 323 |
+
metadata. If index is an ellipsis (...), return global metadata. If
|
| 324 |
+
index is None, the plugin decides the default.
|
| 325 |
+
exclude_applied : bool
|
| 326 |
+
If True (default), do not report metadata fields that the plugin
|
| 327 |
+
would apply/consume while reading the image.
|
| 328 |
+
|
| 329 |
+
Returns
|
| 330 |
+
-------
|
| 331 |
+
metadata : dict
|
| 332 |
+
A dictionary filled with format-specific metadata fields and their
|
| 333 |
+
values.
|
| 334 |
+
|
| 335 |
+
"""
|
| 336 |
+
raise NotImplementedError()
|
| 337 |
+
|
| 338 |
+
def close(self) -> None:
|
| 339 |
+
"""Close the ImageResource.
|
| 340 |
+
|
| 341 |
+
This method allows a plugin to behave similar to the python build-in ``open``::
|
| 342 |
+
|
| 343 |
+
image_file = my_plugin(Request, "r")
|
| 344 |
+
...
|
| 345 |
+
image_file.close()
|
| 346 |
+
|
| 347 |
+
It is used by the context manager and deconstructor below to avoid leaking
|
| 348 |
+
ImageResources. If the plugin has no other cleanup to do it doesn't have
|
| 349 |
+
to overwrite this method itself and can rely on the implementation
|
| 350 |
+
below.
|
| 351 |
+
|
| 352 |
+
"""
|
| 353 |
+
|
| 354 |
+
self.request.finish()
|
| 355 |
+
|
| 356 |
+
@property
|
| 357 |
+
def request(self) -> Request:
|
| 358 |
+
return self._request
|
| 359 |
+
|
| 360 |
+
def __enter__(self) -> "PluginV3":
|
| 361 |
+
return self
|
| 362 |
+
|
| 363 |
+
def __exit__(self, type, value, traceback) -> None:
|
| 364 |
+
self.close()
|
| 365 |
+
|
| 366 |
+
def __del__(self) -> None:
|
| 367 |
+
self.close()
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/__init__.cpython-38.pyc
ADDED
|
Binary file (3.85 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_bsdf.cpython-38.pyc
ADDED
|
Binary file (25.3 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_dicom.cpython-38.pyc
ADDED
|
Binary file (22.9 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_freeimage.cpython-38.pyc
ADDED
|
Binary file (28.4 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/_swf.cpython-38.pyc
ADDED
|
Binary file (20.6 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/feisem.cpython-38.pyc
ADDED
|
Binary file (3.01 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/fits.cpython-38.pyc
ADDED
|
Binary file (4.72 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/freeimage.cpython-38.pyc
ADDED
|
Binary file (14.1 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/gdal.cpython-38.pyc
ADDED
|
Binary file (2.37 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/lytro.cpython-38.pyc
ADDED
|
Binary file (16.7 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/npz.cpython-38.pyc
ADDED
|
Binary file (3.44 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/opencv.cpython-38.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow.cpython-38.pyc
ADDED
|
Binary file (14.1 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow_info.cpython-38.pyc
ADDED
|
Binary file (35.5 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillow_legacy.cpython-38.pyc
ADDED
|
Binary file (24 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/pillowmulti.cpython-38.pyc
ADDED
|
Binary file (8.76 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/simpleitk.cpython-38.pyc
ADDED
|
Binary file (3.96 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/swf.cpython-38.pyc
ADDED
|
Binary file (8.73 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/__pycache__/tifffile.cpython-38.pyc
ADDED
|
Binary file (17.7 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/_dicom.py
ADDED
|
@@ -0,0 +1,925 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
""" Plugin for reading DICOM files.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
# todo: Use pydicom:
|
| 8 |
+
# * Note: is not py3k ready yet
|
| 9 |
+
# * Allow reading the full meta info
|
| 10 |
+
# I think we can more or less replace the SimpleDicomReader with a
|
| 11 |
+
# pydicom.Dataset For series, only ned to read the full info from one
|
| 12 |
+
# file: speed still high
|
| 13 |
+
# * Perhaps allow writing?
|
| 14 |
+
|
| 15 |
+
import sys
|
| 16 |
+
import os
|
| 17 |
+
import struct
|
| 18 |
+
import logging
|
| 19 |
+
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
logger = logging.getLogger(__name__)
|
| 24 |
+
|
| 25 |
+
# Determine endianity of system
|
| 26 |
+
sys_is_little_endian = sys.byteorder == "little"
|
| 27 |
+
|
| 28 |
+
# Define a dictionary that contains the tags that we would like to know
|
| 29 |
+
MINIDICT = {
|
| 30 |
+
(0x7FE0, 0x0010): ("PixelData", "OB"),
|
| 31 |
+
# Date and time
|
| 32 |
+
(0x0008, 0x0020): ("StudyDate", "DA"),
|
| 33 |
+
(0x0008, 0x0021): ("SeriesDate", "DA"),
|
| 34 |
+
(0x0008, 0x0022): ("AcquisitionDate", "DA"),
|
| 35 |
+
(0x0008, 0x0023): ("ContentDate", "DA"),
|
| 36 |
+
(0x0008, 0x0030): ("StudyTime", "TM"),
|
| 37 |
+
(0x0008, 0x0031): ("SeriesTime", "TM"),
|
| 38 |
+
(0x0008, 0x0032): ("AcquisitionTime", "TM"),
|
| 39 |
+
(0x0008, 0x0033): ("ContentTime", "TM"),
|
| 40 |
+
# With what, where, by whom?
|
| 41 |
+
(0x0008, 0x0060): ("Modality", "CS"),
|
| 42 |
+
(0x0008, 0x0070): ("Manufacturer", "LO"),
|
| 43 |
+
(0x0008, 0x0080): ("InstitutionName", "LO"),
|
| 44 |
+
# Descriptions
|
| 45 |
+
(0x0008, 0x1030): ("StudyDescription", "LO"),
|
| 46 |
+
(0x0008, 0x103E): ("SeriesDescription", "LO"),
|
| 47 |
+
# UID's
|
| 48 |
+
(0x0008, 0x0016): ("SOPClassUID", "UI"),
|
| 49 |
+
(0x0008, 0x0018): ("SOPInstanceUID", "UI"),
|
| 50 |
+
(0x0020, 0x000D): ("StudyInstanceUID", "UI"),
|
| 51 |
+
(0x0020, 0x000E): ("SeriesInstanceUID", "UI"),
|
| 52 |
+
(0x0008, 0x0117): ("ContextUID", "UI"),
|
| 53 |
+
# Numbers
|
| 54 |
+
(0x0020, 0x0011): ("SeriesNumber", "IS"),
|
| 55 |
+
(0x0020, 0x0012): ("AcquisitionNumber", "IS"),
|
| 56 |
+
(0x0020, 0x0013): ("InstanceNumber", "IS"),
|
| 57 |
+
(0x0020, 0x0014): ("IsotopeNumber", "IS"),
|
| 58 |
+
(0x0020, 0x0015): ("PhaseNumber", "IS"),
|
| 59 |
+
(0x0020, 0x0016): ("IntervalNumber", "IS"),
|
| 60 |
+
(0x0020, 0x0017): ("TimeSlotNumber", "IS"),
|
| 61 |
+
(0x0020, 0x0018): ("AngleNumber", "IS"),
|
| 62 |
+
(0x0020, 0x0019): ("ItemNumber", "IS"),
|
| 63 |
+
(0x0020, 0x0020): ("PatientOrientation", "CS"),
|
| 64 |
+
(0x0020, 0x0030): ("ImagePosition", "CS"),
|
| 65 |
+
(0x0020, 0x0032): ("ImagePositionPatient", "CS"),
|
| 66 |
+
(0x0020, 0x0035): ("ImageOrientation", "CS"),
|
| 67 |
+
(0x0020, 0x0037): ("ImageOrientationPatient", "CS"),
|
| 68 |
+
# Patient information
|
| 69 |
+
(0x0010, 0x0010): ("PatientName", "PN"),
|
| 70 |
+
(0x0010, 0x0020): ("PatientID", "LO"),
|
| 71 |
+
(0x0010, 0x0030): ("PatientBirthDate", "DA"),
|
| 72 |
+
(0x0010, 0x0040): ("PatientSex", "CS"),
|
| 73 |
+
(0x0010, 0x1010): ("PatientAge", "AS"),
|
| 74 |
+
(0x0010, 0x1020): ("PatientSize", "DS"),
|
| 75 |
+
(0x0010, 0x1030): ("PatientWeight", "DS"),
|
| 76 |
+
# Image specific (required to construct numpy array)
|
| 77 |
+
(0x0028, 0x0002): ("SamplesPerPixel", "US"),
|
| 78 |
+
(0x0028, 0x0008): ("NumberOfFrames", "IS"),
|
| 79 |
+
(0x0028, 0x0100): ("BitsAllocated", "US"),
|
| 80 |
+
(0x0028, 0x0101): ("BitsStored", "US"),
|
| 81 |
+
(0x0028, 0x0102): ("HighBit", "US"),
|
| 82 |
+
(0x0028, 0x0103): ("PixelRepresentation", "US"),
|
| 83 |
+
(0x0028, 0x0010): ("Rows", "US"),
|
| 84 |
+
(0x0028, 0x0011): ("Columns", "US"),
|
| 85 |
+
(0x0028, 0x1052): ("RescaleIntercept", "DS"),
|
| 86 |
+
(0x0028, 0x1053): ("RescaleSlope", "DS"),
|
| 87 |
+
# Image specific (for the user)
|
| 88 |
+
(0x0028, 0x0030): ("PixelSpacing", "DS"),
|
| 89 |
+
(0x0018, 0x0088): ("SliceSpacing", "DS"),
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
# Define some special tags:
|
| 93 |
+
# See PS 3.5-2008 section 7.5 (p.40)
|
| 94 |
+
ItemTag = (0xFFFE, 0xE000) # start of Sequence Item
|
| 95 |
+
ItemDelimiterTag = (0xFFFE, 0xE00D) # end of Sequence Item
|
| 96 |
+
SequenceDelimiterTag = (0xFFFE, 0xE0DD) # end of Sequence of undefined length
|
| 97 |
+
|
| 98 |
+
# Define set of groups that we're interested in (so we can quickly skip others)
|
| 99 |
+
GROUPS = set([key[0] for key in MINIDICT.keys()])
|
| 100 |
+
VRS = set([val[1] for val in MINIDICT.values()])
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class NotADicomFile(Exception):
|
| 104 |
+
pass
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
class CompressedDicom(RuntimeError):
|
| 108 |
+
pass
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
class SimpleDicomReader(object):
|
| 112 |
+
"""
|
| 113 |
+
This class provides reading of pixel data from DICOM files. It is
|
| 114 |
+
focussed on getting the pixel data, not the meta info.
|
| 115 |
+
|
| 116 |
+
To use, first create an instance of this class (giving it
|
| 117 |
+
a file object or filename). Next use the info attribute to
|
| 118 |
+
get a dict of the meta data. The loading of pixel data is
|
| 119 |
+
deferred until get_numpy_array() is called.
|
| 120 |
+
|
| 121 |
+
Comparison with Pydicom
|
| 122 |
+
-----------------------
|
| 123 |
+
|
| 124 |
+
This code focusses on getting the pixel data out, which allows some
|
| 125 |
+
shortcuts, resulting in the code being much smaller.
|
| 126 |
+
|
| 127 |
+
Since the processing of data elements is much cheaper (it skips a lot
|
| 128 |
+
of tags), this code is about 3x faster than pydicom (except for the
|
| 129 |
+
deflated DICOM files).
|
| 130 |
+
|
| 131 |
+
This class does borrow some code (and ideas) from the pydicom
|
| 132 |
+
project, and (to the best of our knowledge) has the same limitations
|
| 133 |
+
as pydicom with regard to the type of files that it can handle.
|
| 134 |
+
|
| 135 |
+
Limitations
|
| 136 |
+
-----------
|
| 137 |
+
|
| 138 |
+
For more advanced DICOM processing, please check out pydicom.
|
| 139 |
+
|
| 140 |
+
* Only a predefined subset of data elements (meta information) is read.
|
| 141 |
+
* This is a reader; it can not write DICOM files.
|
| 142 |
+
* (just like pydicom) it can handle none of the compressed DICOM
|
| 143 |
+
formats except for "Deflated Explicit VR Little Endian"
|
| 144 |
+
(1.2.840.10008.1.2.1.99).
|
| 145 |
+
|
| 146 |
+
"""
|
| 147 |
+
|
| 148 |
+
def __init__(self, file):
|
| 149 |
+
# Open file if filename given
|
| 150 |
+
if isinstance(file, str):
|
| 151 |
+
self._filename = file
|
| 152 |
+
self._file = open(file, "rb")
|
| 153 |
+
else:
|
| 154 |
+
self._filename = "<unknown file>"
|
| 155 |
+
self._file = file
|
| 156 |
+
# Init variable to store position and size of pixel data
|
| 157 |
+
self._pixel_data_loc = None
|
| 158 |
+
# The meta header is always explicit and little endian
|
| 159 |
+
self.is_implicit_VR = False
|
| 160 |
+
self.is_little_endian = True
|
| 161 |
+
self._unpackPrefix = "<"
|
| 162 |
+
# Dict to store data elements of interest in
|
| 163 |
+
self._info = {}
|
| 164 |
+
# VR Conversion
|
| 165 |
+
self._converters = {
|
| 166 |
+
# Numbers
|
| 167 |
+
"US": lambda x: self._unpack("H", x),
|
| 168 |
+
"UL": lambda x: self._unpack("L", x),
|
| 169 |
+
# Numbers encoded as strings
|
| 170 |
+
"DS": lambda x: self._splitValues(x, float, "\\"),
|
| 171 |
+
"IS": lambda x: self._splitValues(x, int, "\\"),
|
| 172 |
+
# strings
|
| 173 |
+
"AS": lambda x: x.decode("ascii", "ignore").strip("\x00"),
|
| 174 |
+
"DA": lambda x: x.decode("ascii", "ignore").strip("\x00"),
|
| 175 |
+
"TM": lambda x: x.decode("ascii", "ignore").strip("\x00"),
|
| 176 |
+
"UI": lambda x: x.decode("ascii", "ignore").strip("\x00"),
|
| 177 |
+
"LO": lambda x: x.decode("utf-8", "ignore").strip("\x00").rstrip(),
|
| 178 |
+
"CS": lambda x: self._splitValues(x, float, "\\"),
|
| 179 |
+
"PN": lambda x: x.decode("utf-8", "ignore").strip("\x00").rstrip(),
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
# Initiate reading
|
| 183 |
+
self._read()
|
| 184 |
+
|
| 185 |
+
@property
|
| 186 |
+
def info(self):
|
| 187 |
+
return self._info
|
| 188 |
+
|
| 189 |
+
def _splitValues(self, x, type, splitter):
|
| 190 |
+
s = x.decode("ascii").strip("\x00")
|
| 191 |
+
try:
|
| 192 |
+
if splitter in s:
|
| 193 |
+
return tuple([type(v) for v in s.split(splitter) if v.strip()])
|
| 194 |
+
else:
|
| 195 |
+
return type(s)
|
| 196 |
+
except ValueError:
|
| 197 |
+
return s
|
| 198 |
+
|
| 199 |
+
def _unpack(self, fmt, value):
|
| 200 |
+
return struct.unpack(self._unpackPrefix + fmt, value)[0]
|
| 201 |
+
|
| 202 |
+
# Really only so we need minimal changes to _pixel_data_numpy
|
| 203 |
+
def __iter__(self):
|
| 204 |
+
return iter(self._info.keys())
|
| 205 |
+
|
| 206 |
+
def __getattr__(self, key):
|
| 207 |
+
info = object.__getattribute__(self, "_info")
|
| 208 |
+
if key in info:
|
| 209 |
+
return info[key]
|
| 210 |
+
return object.__getattribute__(self, key) # pragma: no cover
|
| 211 |
+
|
| 212 |
+
def _read(self):
|
| 213 |
+
f = self._file
|
| 214 |
+
# Check prefix after peamble
|
| 215 |
+
f.seek(128)
|
| 216 |
+
if f.read(4) != b"DICM":
|
| 217 |
+
raise NotADicomFile("Not a valid DICOM file.")
|
| 218 |
+
# Read
|
| 219 |
+
self._read_header()
|
| 220 |
+
self._read_data_elements()
|
| 221 |
+
self._get_shape_and_sampling()
|
| 222 |
+
# Close if done, reopen if necessary to read pixel data
|
| 223 |
+
if os.path.isfile(self._filename):
|
| 224 |
+
self._file.close()
|
| 225 |
+
self._file = None
|
| 226 |
+
|
| 227 |
+
def _readDataElement(self):
|
| 228 |
+
f = self._file
|
| 229 |
+
# Get group and element
|
| 230 |
+
group = self._unpack("H", f.read(2))
|
| 231 |
+
element = self._unpack("H", f.read(2))
|
| 232 |
+
# Get value length
|
| 233 |
+
if self.is_implicit_VR:
|
| 234 |
+
vl = self._unpack("I", f.read(4))
|
| 235 |
+
else:
|
| 236 |
+
vr = f.read(2)
|
| 237 |
+
if vr in (b"OB", b"OW", b"SQ", b"UN"):
|
| 238 |
+
reserved = f.read(2) # noqa
|
| 239 |
+
vl = self._unpack("I", f.read(4))
|
| 240 |
+
else:
|
| 241 |
+
vl = self._unpack("H", f.read(2))
|
| 242 |
+
# Get value
|
| 243 |
+
if group == 0x7FE0 and element == 0x0010:
|
| 244 |
+
here = f.tell()
|
| 245 |
+
self._pixel_data_loc = here, vl
|
| 246 |
+
f.seek(here + vl)
|
| 247 |
+
return group, element, b"Deferred loading of pixel data"
|
| 248 |
+
else:
|
| 249 |
+
if vl == 0xFFFFFFFF:
|
| 250 |
+
value = self._read_undefined_length_value()
|
| 251 |
+
else:
|
| 252 |
+
value = f.read(vl)
|
| 253 |
+
return group, element, value
|
| 254 |
+
|
| 255 |
+
def _read_undefined_length_value(self, read_size=128):
|
| 256 |
+
"""Copied (in compacted form) from PyDicom
|
| 257 |
+
Copyright Darcy Mason.
|
| 258 |
+
"""
|
| 259 |
+
fp = self._file
|
| 260 |
+
# data_start = fp.tell()
|
| 261 |
+
search_rewind = 3
|
| 262 |
+
bytes_to_find = struct.pack(
|
| 263 |
+
self._unpackPrefix + "HH", SequenceDelimiterTag[0], SequenceDelimiterTag[1]
|
| 264 |
+
)
|
| 265 |
+
|
| 266 |
+
found = False
|
| 267 |
+
value_chunks = []
|
| 268 |
+
while not found:
|
| 269 |
+
chunk_start = fp.tell()
|
| 270 |
+
bytes_read = fp.read(read_size)
|
| 271 |
+
if len(bytes_read) < read_size:
|
| 272 |
+
# try again,
|
| 273 |
+
# if still don't get required amount, this is last block
|
| 274 |
+
new_bytes = fp.read(read_size - len(bytes_read))
|
| 275 |
+
bytes_read += new_bytes
|
| 276 |
+
if len(bytes_read) < read_size:
|
| 277 |
+
raise EOFError(
|
| 278 |
+
"End of file reached before sequence " "delimiter found."
|
| 279 |
+
)
|
| 280 |
+
index = bytes_read.find(bytes_to_find)
|
| 281 |
+
if index != -1:
|
| 282 |
+
found = True
|
| 283 |
+
value_chunks.append(bytes_read[:index])
|
| 284 |
+
fp.seek(chunk_start + index + 4) # rewind to end of delimiter
|
| 285 |
+
length = fp.read(4)
|
| 286 |
+
if length != b"\0\0\0\0":
|
| 287 |
+
logger.warning(
|
| 288 |
+
"Expected 4 zero bytes after undefined length " "delimiter"
|
| 289 |
+
)
|
| 290 |
+
else:
|
| 291 |
+
fp.seek(fp.tell() - search_rewind) # rewind a bit
|
| 292 |
+
# accumulate the bytes read (not including the rewind)
|
| 293 |
+
value_chunks.append(bytes_read[:-search_rewind])
|
| 294 |
+
|
| 295 |
+
# if get here then have found the byte string
|
| 296 |
+
return b"".join(value_chunks)
|
| 297 |
+
|
| 298 |
+
def _read_header(self):
|
| 299 |
+
f = self._file
|
| 300 |
+
TransferSyntaxUID = None
|
| 301 |
+
|
| 302 |
+
# Read all elements, store transferSyntax when we encounter it
|
| 303 |
+
try:
|
| 304 |
+
while True:
|
| 305 |
+
fp_save = f.tell()
|
| 306 |
+
# Get element
|
| 307 |
+
group, element, value = self._readDataElement()
|
| 308 |
+
if group == 0x02:
|
| 309 |
+
if group == 0x02 and element == 0x10:
|
| 310 |
+
TransferSyntaxUID = value.decode("ascii").strip("\x00")
|
| 311 |
+
else:
|
| 312 |
+
# No more group 2: rewind and break
|
| 313 |
+
# (don't trust group length)
|
| 314 |
+
f.seek(fp_save)
|
| 315 |
+
break
|
| 316 |
+
except (EOFError, struct.error): # pragma: no cover
|
| 317 |
+
raise RuntimeError("End of file reached while still in header.")
|
| 318 |
+
|
| 319 |
+
# Handle transfer syntax
|
| 320 |
+
self._info["TransferSyntaxUID"] = TransferSyntaxUID
|
| 321 |
+
#
|
| 322 |
+
if TransferSyntaxUID is None:
|
| 323 |
+
# Assume ExplicitVRLittleEndian
|
| 324 |
+
is_implicit_VR, is_little_endian = False, True
|
| 325 |
+
elif TransferSyntaxUID == "1.2.840.10008.1.2.1":
|
| 326 |
+
# ExplicitVRLittleEndian
|
| 327 |
+
is_implicit_VR, is_little_endian = False, True
|
| 328 |
+
elif TransferSyntaxUID == "1.2.840.10008.1.2.2":
|
| 329 |
+
# ExplicitVRBigEndian
|
| 330 |
+
is_implicit_VR, is_little_endian = False, False
|
| 331 |
+
elif TransferSyntaxUID == "1.2.840.10008.1.2":
|
| 332 |
+
# implicit VR little endian
|
| 333 |
+
is_implicit_VR, is_little_endian = True, True
|
| 334 |
+
elif TransferSyntaxUID == "1.2.840.10008.1.2.1.99":
|
| 335 |
+
# DeflatedExplicitVRLittleEndian:
|
| 336 |
+
is_implicit_VR, is_little_endian = False, True
|
| 337 |
+
self._inflate()
|
| 338 |
+
else:
|
| 339 |
+
# http://www.dicomlibrary.com/dicom/transfer-syntax/
|
| 340 |
+
t, extra_info = TransferSyntaxUID, ""
|
| 341 |
+
if "1.2.840.10008.1.2.4.50" <= t < "1.2.840.10008.1.2.4.99":
|
| 342 |
+
extra_info = " (JPEG)"
|
| 343 |
+
if "1.2.840.10008.1.2.4.90" <= t < "1.2.840.10008.1.2.4.99":
|
| 344 |
+
extra_info = " (JPEG 2000)"
|
| 345 |
+
if t == "1.2.840.10008.1.2.5":
|
| 346 |
+
extra_info = " (RLE)"
|
| 347 |
+
if t == "1.2.840.10008.1.2.6.1":
|
| 348 |
+
extra_info = " (RFC 2557)"
|
| 349 |
+
raise CompressedDicom(
|
| 350 |
+
"The dicom reader can only read files with "
|
| 351 |
+
"uncompressed image data - not %r%s. You "
|
| 352 |
+
"can try using dcmtk or gdcm to convert the "
|
| 353 |
+
"image." % (t, extra_info)
|
| 354 |
+
)
|
| 355 |
+
|
| 356 |
+
# From hereon, use implicit/explicit big/little endian
|
| 357 |
+
self.is_implicit_VR = is_implicit_VR
|
| 358 |
+
self.is_little_endian = is_little_endian
|
| 359 |
+
self._unpackPrefix = "><"[is_little_endian]
|
| 360 |
+
|
| 361 |
+
def _read_data_elements(self):
|
| 362 |
+
info = self._info
|
| 363 |
+
try:
|
| 364 |
+
while True:
|
| 365 |
+
# Get element
|
| 366 |
+
group, element, value = self._readDataElement()
|
| 367 |
+
# Is it a group we are interested in?
|
| 368 |
+
if group in GROUPS:
|
| 369 |
+
key = (group, element)
|
| 370 |
+
name, vr = MINIDICT.get(key, (None, None))
|
| 371 |
+
# Is it an element we are interested in?
|
| 372 |
+
if name:
|
| 373 |
+
# Store value
|
| 374 |
+
converter = self._converters.get(vr, lambda x: x)
|
| 375 |
+
info[name] = converter(value)
|
| 376 |
+
except (EOFError, struct.error):
|
| 377 |
+
pass # end of file ...
|
| 378 |
+
|
| 379 |
+
def get_numpy_array(self):
|
| 380 |
+
"""Get numpy arra for this DICOM file, with the correct shape,
|
| 381 |
+
and pixel values scaled appropriately.
|
| 382 |
+
"""
|
| 383 |
+
# Is there pixel data at all?
|
| 384 |
+
if "PixelData" not in self:
|
| 385 |
+
raise TypeError("No pixel data found in this dataset.")
|
| 386 |
+
|
| 387 |
+
# Load it now if it was not already loaded
|
| 388 |
+
if self._pixel_data_loc and len(self.PixelData) < 100:
|
| 389 |
+
# Reopen file?
|
| 390 |
+
close_file = False
|
| 391 |
+
if self._file is None:
|
| 392 |
+
close_file = True
|
| 393 |
+
self._file = open(self._filename, "rb")
|
| 394 |
+
# Read data
|
| 395 |
+
self._file.seek(self._pixel_data_loc[0])
|
| 396 |
+
if self._pixel_data_loc[1] == 0xFFFFFFFF:
|
| 397 |
+
value = self._read_undefined_length_value()
|
| 398 |
+
else:
|
| 399 |
+
value = self._file.read(self._pixel_data_loc[1])
|
| 400 |
+
# Close file
|
| 401 |
+
if close_file:
|
| 402 |
+
self._file.close()
|
| 403 |
+
self._file = None
|
| 404 |
+
# Overwrite
|
| 405 |
+
self._info["PixelData"] = value
|
| 406 |
+
|
| 407 |
+
# Get data
|
| 408 |
+
data = self._pixel_data_numpy()
|
| 409 |
+
data = self._apply_slope_and_offset(data)
|
| 410 |
+
|
| 411 |
+
# Remove data again to preserve memory
|
| 412 |
+
# Note that the data for the original file is loaded twice ...
|
| 413 |
+
self._info["PixelData"] = (
|
| 414 |
+
b"Data converted to numpy array, " + b"raw data removed to preserve memory"
|
| 415 |
+
)
|
| 416 |
+
return data
|
| 417 |
+
|
| 418 |
+
def _get_shape_and_sampling(self):
|
| 419 |
+
"""Get shape and sampling without actuall using the pixel data.
|
| 420 |
+
In this way, the user can get an idea what's inside without having
|
| 421 |
+
to load it.
|
| 422 |
+
"""
|
| 423 |
+
# Get shape (in the same way that pydicom does)
|
| 424 |
+
if "NumberOfFrames" in self and self.NumberOfFrames > 1:
|
| 425 |
+
if self.SamplesPerPixel > 1:
|
| 426 |
+
shape = (
|
| 427 |
+
self.SamplesPerPixel,
|
| 428 |
+
self.NumberOfFrames,
|
| 429 |
+
self.Rows,
|
| 430 |
+
self.Columns,
|
| 431 |
+
)
|
| 432 |
+
else:
|
| 433 |
+
shape = self.NumberOfFrames, self.Rows, self.Columns
|
| 434 |
+
elif "SamplesPerPixel" in self:
|
| 435 |
+
if self.SamplesPerPixel > 1:
|
| 436 |
+
if self.BitsAllocated == 8:
|
| 437 |
+
shape = self.SamplesPerPixel, self.Rows, self.Columns
|
| 438 |
+
else:
|
| 439 |
+
raise NotImplementedError(
|
| 440 |
+
"DICOM plugin only handles "
|
| 441 |
+
"SamplesPerPixel > 1 if Bits "
|
| 442 |
+
"Allocated = 8"
|
| 443 |
+
)
|
| 444 |
+
else:
|
| 445 |
+
shape = self.Rows, self.Columns
|
| 446 |
+
else:
|
| 447 |
+
raise RuntimeError(
|
| 448 |
+
"DICOM file has no SamplesPerPixel " "(perhaps this is a report?)"
|
| 449 |
+
)
|
| 450 |
+
|
| 451 |
+
# Try getting sampling between pixels
|
| 452 |
+
if "PixelSpacing" in self:
|
| 453 |
+
sampling = float(self.PixelSpacing[0]), float(self.PixelSpacing[1])
|
| 454 |
+
else:
|
| 455 |
+
sampling = 1.0, 1.0
|
| 456 |
+
if "SliceSpacing" in self:
|
| 457 |
+
sampling = (abs(self.SliceSpacing),) + sampling
|
| 458 |
+
|
| 459 |
+
# Ensure that sampling has as many elements as shape
|
| 460 |
+
sampling = (1.0,) * (len(shape) - len(sampling)) + sampling[-len(shape) :]
|
| 461 |
+
|
| 462 |
+
# Set shape and sampling
|
| 463 |
+
self._info["shape"] = shape
|
| 464 |
+
self._info["sampling"] = sampling
|
| 465 |
+
|
| 466 |
+
def _pixel_data_numpy(self):
|
| 467 |
+
"""Return a NumPy array of the pixel data."""
|
| 468 |
+
# Taken from pydicom
|
| 469 |
+
# Copyright (c) 2008-2012 Darcy Mason
|
| 470 |
+
|
| 471 |
+
if "PixelData" not in self:
|
| 472 |
+
raise TypeError("No pixel data found in this dataset.")
|
| 473 |
+
|
| 474 |
+
# determine the type used for the array
|
| 475 |
+
need_byteswap = self.is_little_endian != sys_is_little_endian
|
| 476 |
+
|
| 477 |
+
# Make NumPy format code, e.g. "uint16", "int32" etc
|
| 478 |
+
# from two pieces of info:
|
| 479 |
+
# self.PixelRepresentation -- 0 for unsigned, 1 for signed;
|
| 480 |
+
# self.BitsAllocated -- 8, 16, or 32
|
| 481 |
+
format_str = "%sint%d" % (
|
| 482 |
+
("u", "")[self.PixelRepresentation],
|
| 483 |
+
self.BitsAllocated,
|
| 484 |
+
)
|
| 485 |
+
try:
|
| 486 |
+
numpy_format = np.dtype(format_str)
|
| 487 |
+
except TypeError: # pragma: no cover
|
| 488 |
+
raise TypeError(
|
| 489 |
+
"Data type not understood by NumPy: format='%s', "
|
| 490 |
+
" PixelRepresentation=%d, BitsAllocated=%d"
|
| 491 |
+
% (numpy_format, self.PixelRepresentation, self.BitsAllocated)
|
| 492 |
+
)
|
| 493 |
+
|
| 494 |
+
# Have correct Numpy format, so create the NumPy array
|
| 495 |
+
arr = np.frombuffer(self.PixelData, numpy_format).copy()
|
| 496 |
+
|
| 497 |
+
# XXX byte swap - may later handle this in read_file!!?
|
| 498 |
+
if need_byteswap:
|
| 499 |
+
arr.byteswap(True) # True means swap in-place, don't make new copy
|
| 500 |
+
|
| 501 |
+
# Note the following reshape operations return a new *view* onto arr,
|
| 502 |
+
# but don't copy the data
|
| 503 |
+
arr = arr.reshape(*self._info["shape"])
|
| 504 |
+
return arr
|
| 505 |
+
|
| 506 |
+
def _apply_slope_and_offset(self, data):
|
| 507 |
+
"""
|
| 508 |
+
If RescaleSlope and RescaleIntercept are present in the data,
|
| 509 |
+
apply them. The data type of the data is changed if necessary.
|
| 510 |
+
"""
|
| 511 |
+
# Obtain slope and offset
|
| 512 |
+
slope, offset = 1, 0
|
| 513 |
+
needFloats, needApplySlopeOffset = False, False
|
| 514 |
+
if "RescaleSlope" in self:
|
| 515 |
+
needApplySlopeOffset = True
|
| 516 |
+
slope = self.RescaleSlope
|
| 517 |
+
if "RescaleIntercept" in self:
|
| 518 |
+
needApplySlopeOffset = True
|
| 519 |
+
offset = self.RescaleIntercept
|
| 520 |
+
if int(slope) != slope or int(offset) != offset:
|
| 521 |
+
needFloats = True
|
| 522 |
+
if not needFloats:
|
| 523 |
+
slope, offset = int(slope), int(offset)
|
| 524 |
+
|
| 525 |
+
# Apply slope and offset
|
| 526 |
+
if needApplySlopeOffset:
|
| 527 |
+
# Maybe we need to change the datatype?
|
| 528 |
+
if data.dtype in [np.float32, np.float64]:
|
| 529 |
+
pass
|
| 530 |
+
elif needFloats:
|
| 531 |
+
data = data.astype(np.float32)
|
| 532 |
+
else:
|
| 533 |
+
# Determine required range
|
| 534 |
+
minReq, maxReq = data.min(), data.max()
|
| 535 |
+
minReq = min([minReq, minReq * slope + offset, maxReq * slope + offset])
|
| 536 |
+
maxReq = max([maxReq, minReq * slope + offset, maxReq * slope + offset])
|
| 537 |
+
|
| 538 |
+
# Determine required datatype from that
|
| 539 |
+
dtype = None
|
| 540 |
+
if minReq < 0:
|
| 541 |
+
# Signed integer type
|
| 542 |
+
maxReq = max([-minReq, maxReq])
|
| 543 |
+
if maxReq < 2**7:
|
| 544 |
+
dtype = np.int8
|
| 545 |
+
elif maxReq < 2**15:
|
| 546 |
+
dtype = np.int16
|
| 547 |
+
elif maxReq < 2**31:
|
| 548 |
+
dtype = np.int32
|
| 549 |
+
else:
|
| 550 |
+
dtype = np.float32
|
| 551 |
+
else:
|
| 552 |
+
# Unsigned integer type
|
| 553 |
+
if maxReq < 2**8:
|
| 554 |
+
dtype = np.int8
|
| 555 |
+
elif maxReq < 2**16:
|
| 556 |
+
dtype = np.int16
|
| 557 |
+
elif maxReq < 2**32:
|
| 558 |
+
dtype = np.int32
|
| 559 |
+
else:
|
| 560 |
+
dtype = np.float32
|
| 561 |
+
# Change datatype
|
| 562 |
+
if dtype != data.dtype:
|
| 563 |
+
data = data.astype(dtype)
|
| 564 |
+
|
| 565 |
+
# Apply slope and offset
|
| 566 |
+
data *= slope
|
| 567 |
+
data += offset
|
| 568 |
+
|
| 569 |
+
# Done
|
| 570 |
+
return data
|
| 571 |
+
|
| 572 |
+
def _inflate(self):
|
| 573 |
+
# Taken from pydicom
|
| 574 |
+
# Copyright (c) 2008-2012 Darcy Mason
|
| 575 |
+
import zlib
|
| 576 |
+
from io import BytesIO
|
| 577 |
+
|
| 578 |
+
# See PS3.6-2008 A.5 (p 71) -- when written, the entire dataset
|
| 579 |
+
# following the file metadata was prepared the normal way,
|
| 580 |
+
# then "deflate" compression applied.
|
| 581 |
+
# All that is needed here is to decompress and then
|
| 582 |
+
# use as normal in a file-like object
|
| 583 |
+
zipped = self._file.read()
|
| 584 |
+
# -MAX_WBITS part is from comp.lang.python answer:
|
| 585 |
+
# groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
|
| 586 |
+
unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
|
| 587 |
+
self._file = BytesIO(unzipped) # a file-like object
|
| 588 |
+
|
| 589 |
+
|
| 590 |
+
class DicomSeries(object):
|
| 591 |
+
"""DicomSeries
|
| 592 |
+
This class represents a serie of dicom files (SimpleDicomReader
|
| 593 |
+
objects) that belong together. If these are multiple files, they
|
| 594 |
+
represent the slices of a volume (like for CT or MRI).
|
| 595 |
+
"""
|
| 596 |
+
|
| 597 |
+
def __init__(self, suid, progressIndicator):
|
| 598 |
+
# Init dataset list and the callback
|
| 599 |
+
self._entries = []
|
| 600 |
+
|
| 601 |
+
# Init props
|
| 602 |
+
self._suid = suid
|
| 603 |
+
self._info = {}
|
| 604 |
+
self._progressIndicator = progressIndicator
|
| 605 |
+
|
| 606 |
+
def __len__(self):
|
| 607 |
+
return len(self._entries)
|
| 608 |
+
|
| 609 |
+
def __iter__(self):
|
| 610 |
+
return iter(self._entries)
|
| 611 |
+
|
| 612 |
+
def __getitem__(self, index):
|
| 613 |
+
return self._entries[index]
|
| 614 |
+
|
| 615 |
+
@property
|
| 616 |
+
def suid(self):
|
| 617 |
+
return self._suid
|
| 618 |
+
|
| 619 |
+
@property
|
| 620 |
+
def shape(self):
|
| 621 |
+
"""The shape of the data (nz, ny, nx)."""
|
| 622 |
+
return self._info["shape"]
|
| 623 |
+
|
| 624 |
+
@property
|
| 625 |
+
def sampling(self):
|
| 626 |
+
"""The sampling (voxel distances) of the data (dz, dy, dx)."""
|
| 627 |
+
return self._info["sampling"]
|
| 628 |
+
|
| 629 |
+
@property
|
| 630 |
+
def info(self):
|
| 631 |
+
"""A dictionary containing the information as present in the
|
| 632 |
+
first dicomfile of this serie. None if there are no entries."""
|
| 633 |
+
return self._info
|
| 634 |
+
|
| 635 |
+
@property
|
| 636 |
+
def description(self):
|
| 637 |
+
"""A description of the dicom series. Used fields are
|
| 638 |
+
PatientName, shape of the data, SeriesDescription, and
|
| 639 |
+
ImageComments.
|
| 640 |
+
"""
|
| 641 |
+
info = self.info
|
| 642 |
+
|
| 643 |
+
# If no info available, return simple description
|
| 644 |
+
if not info: # pragma: no cover
|
| 645 |
+
return "DicomSeries containing %i images" % len(self)
|
| 646 |
+
|
| 647 |
+
fields = []
|
| 648 |
+
# Give patient name
|
| 649 |
+
if "PatientName" in info:
|
| 650 |
+
fields.append("" + info["PatientName"])
|
| 651 |
+
# Also add dimensions
|
| 652 |
+
if self.shape:
|
| 653 |
+
tmp = [str(d) for d in self.shape]
|
| 654 |
+
fields.append("x".join(tmp))
|
| 655 |
+
# Try adding more fields
|
| 656 |
+
if "SeriesDescription" in info:
|
| 657 |
+
fields.append("'" + info["SeriesDescription"] + "'")
|
| 658 |
+
if "ImageComments" in info:
|
| 659 |
+
fields.append("'" + info["ImageComments"] + "'")
|
| 660 |
+
|
| 661 |
+
# Combine
|
| 662 |
+
return " ".join(fields)
|
| 663 |
+
|
| 664 |
+
def __repr__(self):
|
| 665 |
+
adr = hex(id(self)).upper()
|
| 666 |
+
return "<DicomSeries with %i images at %s>" % (len(self), adr)
|
| 667 |
+
|
| 668 |
+
def get_numpy_array(self):
|
| 669 |
+
"""Get (load) the data that this DicomSeries represents, and return
|
| 670 |
+
it as a numpy array. If this serie contains multiple images, the
|
| 671 |
+
resulting array is 3D, otherwise it's 2D.
|
| 672 |
+
"""
|
| 673 |
+
|
| 674 |
+
# It's easy if no file or if just a single file
|
| 675 |
+
if len(self) == 0:
|
| 676 |
+
raise ValueError("Serie does not contain any files.")
|
| 677 |
+
elif len(self) == 1:
|
| 678 |
+
return self[0].get_numpy_array()
|
| 679 |
+
|
| 680 |
+
# Check info
|
| 681 |
+
if self.info is None:
|
| 682 |
+
raise RuntimeError("Cannot return volume if series not finished.")
|
| 683 |
+
|
| 684 |
+
# Init data (using what the dicom packaged produces as a reference)
|
| 685 |
+
slice = self[0].get_numpy_array()
|
| 686 |
+
vol = np.zeros(self.shape, dtype=slice.dtype)
|
| 687 |
+
vol[0] = slice
|
| 688 |
+
|
| 689 |
+
# Fill volume
|
| 690 |
+
self._progressIndicator.start("loading data", "", len(self))
|
| 691 |
+
for z in range(1, len(self)):
|
| 692 |
+
vol[z] = self[z].get_numpy_array()
|
| 693 |
+
self._progressIndicator.set_progress(z + 1)
|
| 694 |
+
self._progressIndicator.finish()
|
| 695 |
+
|
| 696 |
+
# Done
|
| 697 |
+
import gc
|
| 698 |
+
|
| 699 |
+
gc.collect()
|
| 700 |
+
return vol
|
| 701 |
+
|
| 702 |
+
def _append(self, dcm):
|
| 703 |
+
self._entries.append(dcm)
|
| 704 |
+
|
| 705 |
+
def _sort(self):
|
| 706 |
+
self._entries.sort(key=lambda k: k.InstanceNumber)
|
| 707 |
+
|
| 708 |
+
def _finish(self):
|
| 709 |
+
"""
|
| 710 |
+
Evaluate the series of dicom files. Together they should make up
|
| 711 |
+
a volumetric dataset. This means the files should meet certain
|
| 712 |
+
conditions. Also some additional information has to be calculated,
|
| 713 |
+
such as the distance between the slices. This method sets the
|
| 714 |
+
attributes for "shape", "sampling" and "info".
|
| 715 |
+
|
| 716 |
+
This method checks:
|
| 717 |
+
* that there are no missing files
|
| 718 |
+
* that the dimensions of all images match
|
| 719 |
+
* that the pixel spacing of all images match
|
| 720 |
+
"""
|
| 721 |
+
|
| 722 |
+
# The datasets list should be sorted by instance number
|
| 723 |
+
L = self._entries
|
| 724 |
+
if len(L) == 0:
|
| 725 |
+
return
|
| 726 |
+
elif len(L) == 1:
|
| 727 |
+
self._info = L[0].info
|
| 728 |
+
return
|
| 729 |
+
|
| 730 |
+
# Get previous
|
| 731 |
+
ds1 = L[0]
|
| 732 |
+
# Init measures to calculate average of
|
| 733 |
+
distance_sum = 0.0
|
| 734 |
+
# Init measures to check (these are in 2D)
|
| 735 |
+
dimensions = ds1.Rows, ds1.Columns
|
| 736 |
+
# sampling = float(ds1.PixelSpacing[0]), float(ds1.PixelSpacing[1])
|
| 737 |
+
sampling = ds1.info["sampling"][:2] # row, column
|
| 738 |
+
|
| 739 |
+
for index in range(len(L)):
|
| 740 |
+
# The first round ds1 and ds2 will be the same, for the
|
| 741 |
+
# distance calculation this does not matter
|
| 742 |
+
# Get current
|
| 743 |
+
ds2 = L[index]
|
| 744 |
+
# Get positions
|
| 745 |
+
pos1 = float(ds1.ImagePositionPatient[2])
|
| 746 |
+
pos2 = float(ds2.ImagePositionPatient[2])
|
| 747 |
+
# Update distance_sum to calculate distance later
|
| 748 |
+
distance_sum += abs(pos1 - pos2)
|
| 749 |
+
# Test measures
|
| 750 |
+
dimensions2 = ds2.Rows, ds2.Columns
|
| 751 |
+
# sampling2 = float(ds2.PixelSpacing[0]), float(ds2.PixelSpacing[1])
|
| 752 |
+
sampling2 = ds2.info["sampling"][:2] # row, column
|
| 753 |
+
if dimensions != dimensions2:
|
| 754 |
+
# We cannot produce a volume if the dimensions match
|
| 755 |
+
raise ValueError("Dimensions of slices does not match.")
|
| 756 |
+
if sampling != sampling2:
|
| 757 |
+
# We can still produce a volume, but we should notify the user
|
| 758 |
+
self._progressIndicator.write("Warn: sampling does not match.")
|
| 759 |
+
# Store previous
|
| 760 |
+
ds1 = ds2
|
| 761 |
+
|
| 762 |
+
# Finish calculating average distance
|
| 763 |
+
# (Note that there are len(L)-1 distances)
|
| 764 |
+
distance_mean = distance_sum / (len(L) - 1)
|
| 765 |
+
|
| 766 |
+
# Set info dict
|
| 767 |
+
self._info = L[0].info.copy()
|
| 768 |
+
|
| 769 |
+
# Store information that is specific for the serie
|
| 770 |
+
self._info["shape"] = (len(L),) + ds2.info["shape"]
|
| 771 |
+
self._info["sampling"] = (distance_mean,) + ds2.info["sampling"]
|
| 772 |
+
|
| 773 |
+
|
| 774 |
+
def list_files(files, path):
|
| 775 |
+
"""List all files in the directory, recursively."""
|
| 776 |
+
for item in os.listdir(path):
|
| 777 |
+
item = os.path.join(path, item)
|
| 778 |
+
if os.path.isdir(item):
|
| 779 |
+
list_files(files, item)
|
| 780 |
+
elif os.path.isfile(item):
|
| 781 |
+
files.append(item)
|
| 782 |
+
|
| 783 |
+
|
| 784 |
+
def process_directory(request, progressIndicator, readPixelData=False):
|
| 785 |
+
"""
|
| 786 |
+
Reads dicom files and returns a list of DicomSeries objects, which
|
| 787 |
+
contain information about the data, and can be used to load the
|
| 788 |
+
image or volume data.
|
| 789 |
+
|
| 790 |
+
if readPixelData is True, the pixel data of all series is read. By
|
| 791 |
+
default the loading of pixeldata is deferred until it is requested
|
| 792 |
+
using the DicomSeries.get_pixel_array() method. In general, both
|
| 793 |
+
methods should be equally fast.
|
| 794 |
+
"""
|
| 795 |
+
# Get directory to examine
|
| 796 |
+
if os.path.isdir(request.filename):
|
| 797 |
+
path = request.filename
|
| 798 |
+
elif os.path.isfile(request.filename):
|
| 799 |
+
path = os.path.dirname(request.filename)
|
| 800 |
+
else: # pragma: no cover - tested earlier
|
| 801 |
+
raise ValueError(
|
| 802 |
+
"Dicom plugin needs a valid filename to examine " "the directory"
|
| 803 |
+
)
|
| 804 |
+
|
| 805 |
+
# Check files
|
| 806 |
+
files = []
|
| 807 |
+
list_files(files, path) # Find files recursively
|
| 808 |
+
|
| 809 |
+
# Gather file data and put in DicomSeries
|
| 810 |
+
series = {}
|
| 811 |
+
count = 0
|
| 812 |
+
progressIndicator.start("examining files", "files", len(files))
|
| 813 |
+
for filename in files:
|
| 814 |
+
# Show progress (note that we always start with a 0.0)
|
| 815 |
+
count += 1
|
| 816 |
+
progressIndicator.set_progress(count)
|
| 817 |
+
# Skip DICOMDIR files
|
| 818 |
+
if filename.count("DICOMDIR"): # pragma: no cover
|
| 819 |
+
continue
|
| 820 |
+
# Try loading dicom ...
|
| 821 |
+
try:
|
| 822 |
+
dcm = SimpleDicomReader(filename)
|
| 823 |
+
except NotADicomFile:
|
| 824 |
+
continue # skip non-dicom file
|
| 825 |
+
except Exception as why: # pragma: no cover
|
| 826 |
+
progressIndicator.write(str(why))
|
| 827 |
+
continue
|
| 828 |
+
# Get SUID and register the file with an existing or new series object
|
| 829 |
+
try:
|
| 830 |
+
suid = dcm.SeriesInstanceUID
|
| 831 |
+
except AttributeError: # pragma: no cover
|
| 832 |
+
continue # some other kind of dicom file
|
| 833 |
+
if suid not in series:
|
| 834 |
+
series[suid] = DicomSeries(suid, progressIndicator)
|
| 835 |
+
series[suid]._append(dcm)
|
| 836 |
+
|
| 837 |
+
# Finish progress
|
| 838 |
+
# progressIndicator.finish('Found %i series.' % len(series))
|
| 839 |
+
|
| 840 |
+
# Make a list and sort, so that the order is deterministic
|
| 841 |
+
series = list(series.values())
|
| 842 |
+
series.sort(key=lambda x: x.suid)
|
| 843 |
+
|
| 844 |
+
# Split series if necessary
|
| 845 |
+
for serie in reversed([serie for serie in series]):
|
| 846 |
+
splitSerieIfRequired(serie, series, progressIndicator)
|
| 847 |
+
|
| 848 |
+
# Finish all series
|
| 849 |
+
# progressIndicator.start('analyse series', '', len(series))
|
| 850 |
+
series_ = []
|
| 851 |
+
for i in range(len(series)):
|
| 852 |
+
try:
|
| 853 |
+
series[i]._finish()
|
| 854 |
+
series_.append(series[i])
|
| 855 |
+
except Exception as err: # pragma: no cover
|
| 856 |
+
progressIndicator.write(str(err))
|
| 857 |
+
pass # Skip serie (probably report-like file without pixels)
|
| 858 |
+
# progressIndicator.set_progress(i+1)
|
| 859 |
+
progressIndicator.finish("Found %i correct series." % len(series_))
|
| 860 |
+
|
| 861 |
+
# Done
|
| 862 |
+
return series_
|
| 863 |
+
|
| 864 |
+
|
| 865 |
+
def splitSerieIfRequired(serie, series, progressIndicator):
|
| 866 |
+
"""
|
| 867 |
+
Split the serie in multiple series if this is required. The choice
|
| 868 |
+
is based on examing the image position relative to the previous
|
| 869 |
+
image. If it differs too much, it is assumed that there is a new
|
| 870 |
+
dataset. This can happen for example in unspitted gated CT data.
|
| 871 |
+
"""
|
| 872 |
+
|
| 873 |
+
# Sort the original list and get local name
|
| 874 |
+
serie._sort()
|
| 875 |
+
L = serie._entries
|
| 876 |
+
# Init previous slice
|
| 877 |
+
ds1 = L[0]
|
| 878 |
+
# Check whether we can do this
|
| 879 |
+
if "ImagePositionPatient" not in ds1:
|
| 880 |
+
return
|
| 881 |
+
# Initialize a list of new lists
|
| 882 |
+
L2 = [[ds1]]
|
| 883 |
+
# Init slice distance estimate
|
| 884 |
+
distance = 0
|
| 885 |
+
|
| 886 |
+
for index in range(1, len(L)):
|
| 887 |
+
# Get current slice
|
| 888 |
+
ds2 = L[index]
|
| 889 |
+
# Get positions
|
| 890 |
+
pos1 = float(ds1.ImagePositionPatient[2])
|
| 891 |
+
pos2 = float(ds2.ImagePositionPatient[2])
|
| 892 |
+
# Get distances
|
| 893 |
+
newDist = abs(pos1 - pos2)
|
| 894 |
+
# deltaDist = abs(firstPos-pos2)
|
| 895 |
+
# If the distance deviates more than 2x from what we've seen,
|
| 896 |
+
# we can agree it's a new dataset.
|
| 897 |
+
if distance and newDist > 2.1 * distance:
|
| 898 |
+
L2.append([])
|
| 899 |
+
distance = 0
|
| 900 |
+
else:
|
| 901 |
+
# Test missing file
|
| 902 |
+
if distance and newDist > 1.5 * distance:
|
| 903 |
+
progressIndicator.write(
|
| 904 |
+
"Warning: missing file after %r" % ds1._filename
|
| 905 |
+
)
|
| 906 |
+
distance = newDist
|
| 907 |
+
# Add to last list
|
| 908 |
+
L2[-1].append(ds2)
|
| 909 |
+
# Store previous
|
| 910 |
+
ds1 = ds2
|
| 911 |
+
|
| 912 |
+
# Split if we should
|
| 913 |
+
if len(L2) > 1:
|
| 914 |
+
# At what position are we now?
|
| 915 |
+
i = series.index(serie)
|
| 916 |
+
# Create new series
|
| 917 |
+
series2insert = []
|
| 918 |
+
for L in L2:
|
| 919 |
+
newSerie = DicomSeries(serie.suid, progressIndicator)
|
| 920 |
+
newSerie._entries = L
|
| 921 |
+
series2insert.append(newSerie)
|
| 922 |
+
# Insert series and remove self
|
| 923 |
+
for newSerie in reversed(series2insert):
|
| 924 |
+
series.insert(i, newSerie)
|
| 925 |
+
series.remove(serie)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/_tifffile.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/example.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
""" Example plugin. You can use this as a template for your own plugin.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
from .. import formats
|
| 10 |
+
from ..core import Format
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class DummyFormat(Format):
|
| 14 |
+
"""The dummy format is an example format that does nothing.
|
| 15 |
+
It will never indicate that it can read or write a file. When
|
| 16 |
+
explicitly asked to read, it will simply read the bytes. When
|
| 17 |
+
explicitly asked to write, it will raise an error.
|
| 18 |
+
|
| 19 |
+
This documentation is shown when the user does ``help('thisformat')``.
|
| 20 |
+
|
| 21 |
+
Parameters for reading
|
| 22 |
+
----------------------
|
| 23 |
+
Specify arguments in numpy doc style here.
|
| 24 |
+
|
| 25 |
+
Parameters for saving
|
| 26 |
+
---------------------
|
| 27 |
+
Specify arguments in numpy doc style here.
|
| 28 |
+
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
def _can_read(self, request):
|
| 32 |
+
# This method is called when the format manager is searching
|
| 33 |
+
# for a format to read a certain image. Return True if this format
|
| 34 |
+
# can do it.
|
| 35 |
+
#
|
| 36 |
+
# The format manager is aware of the extensions and the modes
|
| 37 |
+
# that each format can handle. It will first ask all formats
|
| 38 |
+
# that *seem* to be able to read it whether they can. If none
|
| 39 |
+
# can, it will ask the remaining formats if they can: the
|
| 40 |
+
# extension might be missing, and this allows formats to provide
|
| 41 |
+
# functionality for certain extensions, while giving preference
|
| 42 |
+
# to other plugins.
|
| 43 |
+
#
|
| 44 |
+
# If a format says it can, it should live up to it. The format
|
| 45 |
+
# would ideally check the request.firstbytes and look for a
|
| 46 |
+
# header of some kind.
|
| 47 |
+
#
|
| 48 |
+
# The request object has:
|
| 49 |
+
# request.filename: a representation of the source (only for reporting)
|
| 50 |
+
# request.firstbytes: the first 256 bytes of the file.
|
| 51 |
+
# request.mode[0]: read or write mode
|
| 52 |
+
# request.mode[1]: what kind of data the user expects: one of 'iIvV?'
|
| 53 |
+
|
| 54 |
+
if request.mode[1] in (self.modes + "?"):
|
| 55 |
+
if request.extension in self.extensions:
|
| 56 |
+
return True
|
| 57 |
+
|
| 58 |
+
def _can_write(self, request):
|
| 59 |
+
# This method is called when the format manager is searching
|
| 60 |
+
# for a format to write a certain image. It will first ask all
|
| 61 |
+
# formats that *seem* to be able to write it whether they can.
|
| 62 |
+
# If none can, it will ask the remaining formats if they can.
|
| 63 |
+
#
|
| 64 |
+
# Return True if the format can do it.
|
| 65 |
+
|
| 66 |
+
# In most cases, this code does suffice:
|
| 67 |
+
if request.mode[1] in (self.modes + "?"):
|
| 68 |
+
if request.extension in self.extensions:
|
| 69 |
+
return True
|
| 70 |
+
|
| 71 |
+
# -- reader
|
| 72 |
+
|
| 73 |
+
class Reader(Format.Reader):
|
| 74 |
+
def _open(self, some_option=False, length=1):
|
| 75 |
+
# Specify kwargs here. Optionally, the user-specified kwargs
|
| 76 |
+
# can also be accessed via the request.kwargs object.
|
| 77 |
+
#
|
| 78 |
+
# The request object provides two ways to get access to the
|
| 79 |
+
# data. Use just one:
|
| 80 |
+
# - Use request.get_file() for a file object (preferred)
|
| 81 |
+
# - Use request.get_local_filename() for a file on the system
|
| 82 |
+
self._fp = self.request.get_file()
|
| 83 |
+
self._length = length # passed as an arg in this case for testing
|
| 84 |
+
self._data = None
|
| 85 |
+
|
| 86 |
+
def _close(self):
|
| 87 |
+
# Close the reader.
|
| 88 |
+
# Note that the request object will close self._fp
|
| 89 |
+
pass
|
| 90 |
+
|
| 91 |
+
def _get_length(self):
|
| 92 |
+
# Return the number of images. Can be np.inf
|
| 93 |
+
return self._length
|
| 94 |
+
|
| 95 |
+
def _get_data(self, index):
|
| 96 |
+
# Return the data and meta data for the given index
|
| 97 |
+
if index >= self._length:
|
| 98 |
+
raise IndexError("Image index %i > %i" % (index, self._length))
|
| 99 |
+
# Read all bytes
|
| 100 |
+
if self._data is None:
|
| 101 |
+
self._data = self._fp.read()
|
| 102 |
+
# Put in a numpy array
|
| 103 |
+
im = np.frombuffer(self._data, "uint8")
|
| 104 |
+
im.shape = len(im), 1
|
| 105 |
+
# Return array and dummy meta data
|
| 106 |
+
return im, {}
|
| 107 |
+
|
| 108 |
+
def _get_meta_data(self, index):
|
| 109 |
+
# Get the meta data for the given index. If index is None, it
|
| 110 |
+
# should return the global meta data.
|
| 111 |
+
return {} # This format does not support meta data
|
| 112 |
+
|
| 113 |
+
# -- writer
|
| 114 |
+
|
| 115 |
+
class Writer(Format.Writer):
|
| 116 |
+
def _open(self, flags=0):
|
| 117 |
+
# Specify kwargs here. Optionally, the user-specified kwargs
|
| 118 |
+
# can also be accessed via the request.kwargs object.
|
| 119 |
+
#
|
| 120 |
+
# The request object provides two ways to write the data.
|
| 121 |
+
# Use just one:
|
| 122 |
+
# - Use request.get_file() for a file object (preferred)
|
| 123 |
+
# - Use request.get_local_filename() for a file on the system
|
| 124 |
+
self._fp = self.request.get_file()
|
| 125 |
+
|
| 126 |
+
def _close(self):
|
| 127 |
+
# Close the reader.
|
| 128 |
+
# Note that the request object will close self._fp
|
| 129 |
+
pass
|
| 130 |
+
|
| 131 |
+
def _append_data(self, im, meta):
|
| 132 |
+
# Process the given data and meta data.
|
| 133 |
+
raise RuntimeError("The dummy format cannot write image data.")
|
| 134 |
+
|
| 135 |
+
def set_meta_data(self, meta):
|
| 136 |
+
# Process the given meta data (global for all images)
|
| 137 |
+
# It is not mandatory to support this.
|
| 138 |
+
raise RuntimeError("The dummy format cannot write meta data.")
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
# Register. You register an *instance* of a Format class. Here specify:
|
| 142 |
+
format = DummyFormat(
|
| 143 |
+
"dummy", # short name
|
| 144 |
+
"An example format that does nothing.", # one line descr.
|
| 145 |
+
".foobar .nonexistentext", # list of extensions
|
| 146 |
+
"iI", # modes, characters in iIvV
|
| 147 |
+
)
|
| 148 |
+
formats.add_format(format)
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/gdal.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
""" Read GDAL files.
|
| 5 |
+
|
| 6 |
+
Backend: `GDAL <https://gdal.org/>`_
|
| 7 |
+
|
| 8 |
+
.. note::
|
| 9 |
+
To use this plugin you have to install its backend::
|
| 10 |
+
|
| 11 |
+
pip install imageio[gdal]
|
| 12 |
+
|
| 13 |
+
Parameters
|
| 14 |
+
----------
|
| 15 |
+
none
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
from ..core import Format, has_module
|
| 19 |
+
|
| 20 |
+
_gdal = None # lazily loaded in load_lib()
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def load_lib():
|
| 24 |
+
global _gdal
|
| 25 |
+
try:
|
| 26 |
+
import osgeo.gdal as _gdal
|
| 27 |
+
except ImportError:
|
| 28 |
+
raise ImportError(
|
| 29 |
+
"The GDAL format relies on the GDAL package."
|
| 30 |
+
"Please refer to http://www.gdal.org/"
|
| 31 |
+
"for further instructions."
|
| 32 |
+
)
|
| 33 |
+
return _gdal
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
GDAL_FORMATS = (".tiff", " .tif", ".img", ".ecw", ".jpg", ".jpeg")
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class GdalFormat(Format):
|
| 40 |
+
"""See :mod:`imageio.plugins.gdal`"""
|
| 41 |
+
|
| 42 |
+
def _can_read(self, request):
|
| 43 |
+
if request.extension in (".ecw",):
|
| 44 |
+
return True
|
| 45 |
+
if has_module("osgeo.gdal"):
|
| 46 |
+
return request.extension in self.extensions
|
| 47 |
+
|
| 48 |
+
def _can_write(self, request):
|
| 49 |
+
return False
|
| 50 |
+
|
| 51 |
+
# --
|
| 52 |
+
|
| 53 |
+
class Reader(Format.Reader):
|
| 54 |
+
def _open(self):
|
| 55 |
+
if not _gdal:
|
| 56 |
+
load_lib()
|
| 57 |
+
self._ds = _gdal.Open(self.request.get_local_filename())
|
| 58 |
+
|
| 59 |
+
def _close(self):
|
| 60 |
+
del self._ds
|
| 61 |
+
|
| 62 |
+
def _get_length(self):
|
| 63 |
+
return 1
|
| 64 |
+
|
| 65 |
+
def _get_data(self, index):
|
| 66 |
+
if index != 0:
|
| 67 |
+
raise IndexError("Gdal file contains only one dataset")
|
| 68 |
+
return self._ds.ReadAsArray(), self._get_meta_data(index)
|
| 69 |
+
|
| 70 |
+
def _get_meta_data(self, index):
|
| 71 |
+
return self._ds.GetMetadata()
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/plugins/npz.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# imageio is distributed under the terms of the (new) BSD License.
|
| 3 |
+
|
| 4 |
+
"""Read/Write NPZ files.
|
| 5 |
+
|
| 6 |
+
Backend: `Numpy <https://numpy.org/doc/stable/reference/generated/numpy.savez.html>`_
|
| 7 |
+
|
| 8 |
+
NPZ is a file format by numpy that provides storage of array data using gzip
|
| 9 |
+
compression. This imageio plugin supports data of any shape, and also supports
|
| 10 |
+
multiple images per file. However, the npz format does not provide streaming;
|
| 11 |
+
all data is read/written at once. Further, there is no support for meta data.
|
| 12 |
+
|
| 13 |
+
See the BSDF format for a similar (but more fully featured) format.
|
| 14 |
+
|
| 15 |
+
Parameters
|
| 16 |
+
----------
|
| 17 |
+
None
|
| 18 |
+
|
| 19 |
+
Notes
|
| 20 |
+
-----
|
| 21 |
+
This format is not available on Pypy.
|
| 22 |
+
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
import numpy as np
|
| 26 |
+
|
| 27 |
+
from ..core import Format
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class NpzFormat(Format):
|
| 31 |
+
"""See :mod:`imageio.plugins.npz`"""
|
| 32 |
+
|
| 33 |
+
def _can_read(self, request):
|
| 34 |
+
# We support any kind of image data
|
| 35 |
+
return request.extension in self.extensions
|
| 36 |
+
|
| 37 |
+
def _can_write(self, request):
|
| 38 |
+
# We support any kind of image data
|
| 39 |
+
return request.extension in self.extensions
|
| 40 |
+
|
| 41 |
+
# -- reader
|
| 42 |
+
|
| 43 |
+
class Reader(Format.Reader):
|
| 44 |
+
def _open(self):
|
| 45 |
+
# Load npz file, which provides another file like object
|
| 46 |
+
self._npz = np.load(self.request.get_file())
|
| 47 |
+
assert isinstance(self._npz, np.lib.npyio.NpzFile)
|
| 48 |
+
# Get list of names, ordered by name, but smarter
|
| 49 |
+
self._names = sorted(self._npz.files, key=lambda x: x.split("_")[-1])
|
| 50 |
+
|
| 51 |
+
def _close(self):
|
| 52 |
+
self._npz.close()
|
| 53 |
+
|
| 54 |
+
def _get_length(self):
|
| 55 |
+
return len(self._names)
|
| 56 |
+
|
| 57 |
+
def _get_data(self, index):
|
| 58 |
+
# Get data
|
| 59 |
+
if index < 0 or index >= len(self._names):
|
| 60 |
+
raise IndexError("Index out of range while reading from nzp")
|
| 61 |
+
im = self._npz[self._names[index]]
|
| 62 |
+
# Return array and empty meta data
|
| 63 |
+
return im, {}
|
| 64 |
+
|
| 65 |
+
def _get_meta_data(self, index):
|
| 66 |
+
# Get the meta data for the given index
|
| 67 |
+
raise RuntimeError("The npz format does not support meta data.")
|
| 68 |
+
|
| 69 |
+
# -- writer
|
| 70 |
+
|
| 71 |
+
class Writer(Format.Writer):
|
| 72 |
+
def _open(self):
|
| 73 |
+
# Npz is not such a great format. We cannot stream to the file.
|
| 74 |
+
# So we remember all images and write them to file at the end.
|
| 75 |
+
self._images = []
|
| 76 |
+
|
| 77 |
+
def _close(self):
|
| 78 |
+
# Write everything
|
| 79 |
+
np.savez_compressed(self.request.get_file(), *self._images)
|
| 80 |
+
|
| 81 |
+
def _append_data(self, im, meta):
|
| 82 |
+
self._images.append(im) # discart meta data
|
| 83 |
+
|
| 84 |
+
def set_meta_data(self, meta):
|
| 85 |
+
raise RuntimeError("The npz format does not support meta data.")
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/imageio/resources/images/realshort.mp4
ADDED
|
Binary file (96.8 kB). View file
|
|
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/__pycache__/patches.cpython-38.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:83e824a4d7719ede1c578409a91dc776783b1aec961dde5b7f5028cec27601bc
|
| 3 |
+
size 139669
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c3753f2ed6bc673f15846dc45addbeb3b9c872f32fb18fd53a21f1bef1ed7676
|
| 3 |
+
size 355692
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralBolIta.ttf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:98788fd4ba48dfbb2bd026c0e20a247a8b06c7372879628b7a6bb0d5bb09736c
|
| 3 |
+
size 181152
|
my_container_sandbox/workspace/anaconda3/lib/python3.8/site-packages/matplotlib/mpl-data/fonts/ttf/STIXGeneralItalic.ttf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6cfcb333d22b7c3c623bdfd40174f14c85c3d6731ca6166c1edc80140eae8527
|
| 3 |
+
size 175040
|