From e44b8ba2696c97765f6fe9f90a8cfda34f69cfdf Mon Sep 17 00:00:00 2001 From: Erik O Gabrielsson Date: Wed, 29 Nov 2023 21:16:02 +0100 Subject: [PATCH 1/3] Parse philips tiff mettadata --- tiffslide/tiffslide.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tiffslide/tiffslide.py b/tiffslide/tiffslide.py index 6120a98..8d89fe2 100644 --- a/tiffslide/tiffslide.py +++ b/tiffslide/tiffslide.py @@ -13,6 +13,8 @@ from typing import Iterator from typing import Literal from typing import Mapping +from typing import Optional +from typing import Tuple from typing import TypeVar from typing import overload from warnings import warn @@ -644,6 +646,7 @@ class _PropertyParser: scn="leica", bif="ventana", ndpi="hamamatsu", + philips="philips_tiff" # add more when needed ) @@ -843,6 +846,37 @@ def parse_generic_tiff(self) -> dict[str, Any]: md.update(self.collect_level_info(series0)) return md + def parse_philips_tiff(self) -> dict[str, Any]: + """parse Philips tiff properties""" + md = self.parse_generic_tiff() + if self._tf.philips_metadata is None: + return md + philips_metadata = ElementTree.fromstring(self._tf.philips_metadata) + def get_first_attribute_with_name( + root: ElementTree.Element, + name: str + ) -> Optional[str]: + return next( + root.iterfind(f".//Attribute[@Name='{name}']") + ).text + md[PROPERTY_NAME_VENDOR] = get_first_attribute_with_name( + philips_metadata, + 'DICOM_MANUFACTURER' + ) + pixel_spacing_attribute = get_first_attribute_with_name( + philips_metadata, + 'DICOM_PIXEL_SPACING' + ) + if pixel_spacing_attribute is not None: + pixel_spacings = [ + float(element.strip('"')) * 1000 + for element in pixel_spacing_attribute.split(' ') + ] + mpp_x, mpp_y = pixel_spacings[0], pixel_spacings[1] + md[PROPERTY_NAME_MPP_X] = mpp_x + md[PROPERTY_NAME_MPP_Y] = mpp_y + return md + def _parse_metadata_aperio(desc: str) -> dict[str, Any]: """Aperio SVS metadata""" From 93f9e25e6e4a83d5804e449e9907e40cad3469e8 Mon Sep 17 00:00:00 2001 From: Erik O Gabrielsson Date: Wed, 29 Nov 2023 21:38:26 +0100 Subject: [PATCH 2/3] Remove unused import --- tiffslide/tiffslide.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tiffslide/tiffslide.py b/tiffslide/tiffslide.py index 8d89fe2..7c241ca 100644 --- a/tiffslide/tiffslide.py +++ b/tiffslide/tiffslide.py @@ -14,7 +14,6 @@ from typing import Literal from typing import Mapping from typing import Optional -from typing import Tuple from typing import TypeVar from typing import overload from warnings import warn From 9963b57ea943104f70a58bad58729d6a638109a7 Mon Sep 17 00:00:00 2001 From: Andreas Poehlmann Date: Thu, 30 Nov 2023 00:15:03 +0100 Subject: [PATCH 3/3] pre-commit and typing fixes --- .pre-commit-config.yaml | 2 +- tiffslide/_types.py | 5 +---- tiffslide/tiffslide.py | 19 ++++++++----------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bfe2e50..8228b85 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - id: black language_version: python3 - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.6.1' + rev: 'v1.7.1' hooks: - id: mypy additional_dependencies: ["numpy"] diff --git a/tiffslide/_types.py b/tiffslide/_types.py index 663c661..1354f6d 100644 --- a/tiffslide/_types.py +++ b/tiffslide/_types.py @@ -56,10 +56,7 @@ def __getattr__(name: str) -> Any: raise AttributeError(name) -if sys.version_info >= (3, 9): - PathLikeStr: TypeAlias = os.PathLike[str] -else: - PathLikeStr: TypeAlias = os.PathLike +PathLikeStr: TypeAlias = "os.PathLike[str]" @runtime_checkable diff --git a/tiffslide/tiffslide.py b/tiffslide/tiffslide.py index 7c241ca..6288f42 100644 --- a/tiffslide/tiffslide.py +++ b/tiffslide/tiffslide.py @@ -851,25 +851,22 @@ def parse_philips_tiff(self) -> dict[str, Any]: if self._tf.philips_metadata is None: return md philips_metadata = ElementTree.fromstring(self._tf.philips_metadata) + def get_first_attribute_with_name( - root: ElementTree.Element, - name: str - ) -> Optional[str]: - return next( - root.iterfind(f".//Attribute[@Name='{name}']") - ).text + root: ElementTree.Element, name: str + ) -> str | None: + return next(root.iterfind(f".//Attribute[@Name='{name}']")).text + md[PROPERTY_NAME_VENDOR] = get_first_attribute_with_name( - philips_metadata, - 'DICOM_MANUFACTURER' + philips_metadata, "DICOM_MANUFACTURER" ) pixel_spacing_attribute = get_first_attribute_with_name( - philips_metadata, - 'DICOM_PIXEL_SPACING' + philips_metadata, "DICOM_PIXEL_SPACING" ) if pixel_spacing_attribute is not None: pixel_spacings = [ float(element.strip('"')) * 1000 - for element in pixel_spacing_attribute.split(' ') + for element in pixel_spacing_attribute.split(" ") ] mpp_x, mpp_y = pixel_spacings[0], pixel_spacings[1] md[PROPERTY_NAME_MPP_X] = mpp_x