diff --git a/setup.py b/setup.py index 50dfb49b..be73b003 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,10 @@ "tifffile@git+https://github.com/TileDB-Inc/tifffile.git@gsa/python-3.7", "imagecodecs", ] -full = sorted({*zarr, *openslide, *tiff}) + +isyntax = ["openphi"] + +full = sorted({*zarr, *openslide, *tiff, *isyntax}) setuptools.setup( setup_requires=["setuptools_scm"], @@ -21,6 +24,7 @@ extras_require={ "zarr": zarr, "openslide": openslide, + "isyntax": isyntax, "tiff": tiff, "full": full, }, diff --git a/tiledbimg/converters/isyntax.py b/tiledbimg/converters/isyntax.py new file mode 100644 index 00000000..fb2f64f6 --- /dev/null +++ b/tiledbimg/converters/isyntax.py @@ -0,0 +1,46 @@ +from typing import Any, Dict, cast + +import numpy as np +import openphi as op + +from .base import Axes, ImageConverter, ImageReader, ImageWriter + + +class ISyntaxReader(ImageReader): + def __init__(self, input_path: str): + self._ophi = op.OpenPhi(input_path) + + def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: + self._ophi.close() + + @property + def level_count(self) -> int: + return cast(int, self._ophi.level_count) + + def level_axes(self, level: int) -> Axes: + return Axes("YXC") + + def level_metadata(self, level: int) -> Dict[str, Any]: + return {} + + @property + def group_metadata(self) -> Dict[str, Any]: + return cast(Dict[str, Any], self._ophi.properties) + + def level_image(self, level: int) -> np.ndarray: + dims = self._ophi.level_dimensions[level] + # image is in (width, height, channel) == XYC + image = self._ophi.read_region((0, 0), level, dims).convert("RGB") + # np.asarray() transposes it to (height, width, channel) == YXC + # https://stackoverflow.com/questions/49084846/why-different-size-when-converting-pil-image-to-numpy-array + return np.asarray(image) + + +class ISyntaxConverter(ImageConverter): + """Converter of OpenSlide-supported images to TileDB Groups of Arrays""" + + def _get_image_reader(self, input_path: str) -> ImageReader: + return ISyntaxReader(input_path) + + def _get_image_writer(self, input_path: str, output_path: str) -> ImageWriter: + raise NotImplementedError