@@ -3819,24 +3819,14 @@ def color_string_to_rgb(s: str) -> tuple[float, float, float]:
38193819 return channel_dict if channel_dict else None
38203820
38213821 @staticmethod
3822- def _parse_ome_metadata_mapping (
3823- root : ElementTree ,
3824- ) -> dict [str , tuple [float , float , float ]] | None :
3825- """Parse OME metadata from the given XML root element.
3826-
3827- Args:
3828- root (ElementTree): The root of the parsed XML tree.
3829-
3830- Returns:
3831- dict[str, tuple[float, float, float]] | None: A mapping
3832- of channel names to RGB tuples, or None if not found.
3833- """
3834- # 3) Try OME/Lunaphore format e.g. for COMET
3835- ns = {}
3822+ def _get_namespace (root : ElementTree ) -> dict :
38363823 if root .tag .startswith ("{" ):
38373824 ns_uri = root .tag .split ("}" )[0 ].strip ("{" )
3838- ns = {"ns" : ns_uri }
3825+ return {"ns" : ns_uri }
3826+ return {}
38393827
3828+ @staticmethod
3829+ def _extract_dye_mapping (root : ElementTree , ns : dict ) -> dict :
38403830 dye_mapping = {}
38413831 for annotation in root .findall (
38423832 ".//ns:StructuredAnnotations/ns:XMLAnnotation" , ns
@@ -3848,24 +3838,21 @@ def _parse_ome_metadata_mapping(
38483838 dye = chan_priv .attrib .get ("FluorescenceChannel" )
38493839 if chan_id and dye :
38503840 dye_mapping [chan_id ] = dye
3841+ return dye_mapping
38513842
3852- def _int_to_rgb (color_int : int ) -> tuple [float , float , float ]:
3853- """Convert a color string (e.g., 'Lime' or '255, 128, 0') to an RGB tuple.
3854-
3855- Args:
3856- color_int (str): The color string to convert.
3857-
3858- Returns:
3859- tuple[float, float, float]: The corresponding RGB values normalized to
3860- [0, 1].
3861- """
3862- if color_int < 0 :
3863- color_int += 1 << 32
3864- r = (color_int >> 16 ) & 0xFF
3865- g = (color_int >> 8 ) & 0xFF
3866- b = color_int & 0xFF
3867- return (r / 255 , g / 255 , b / 255 )
3843+ @staticmethod
3844+ def _int_to_rgb (color_int : int ) -> tuple [float , float , float ]:
3845+ if color_int < 0 :
3846+ color_int += 1 << 32
3847+ r = (color_int >> 16 ) & 0xFF
3848+ g = (color_int >> 8 ) & 0xFF
3849+ b = color_int & 0xFF
3850+ return (r / 255 , g / 255 , b / 255 )
38683851
3852+ @staticmethod
3853+ def _parse_channel_data (
3854+ root : ElementTree , ns : dict , dye_mapping : dict
3855+ ) -> list [dict ]:
38693856 channel_data = []
38703857 for pixels in root .findall (".//ns:Pixels" , ns ):
38713858 for channel in pixels .findall ("ns:Channel" , ns ):
@@ -3875,10 +3862,9 @@ def _int_to_rgb(color_int: int) -> tuple[float, float, float]:
38753862 if chan_id and name and color :
38763863 try :
38773864 color_int = int (color )
3878- rgb = _int_to_rgb (color_int )
3865+ rgb = TIFFWSIReader . _int_to_rgb (color_int )
38793866 except ValueError :
38803867 rgb = None
3881-
38823868 dye = dye_mapping .get (chan_id , "Unknown" )
38833869 label = f"{ chan_id } : { name } ({ dye } )"
38843870 channel_data .append (
@@ -3890,23 +3876,44 @@ def _int_to_rgb(color_int: int) -> tuple[float, float, float]:
38903876 "label" : label ,
38913877 }
38923878 )
3879+ return channel_data
38933880
3881+ @staticmethod
3882+ def _build_color_dict (
3883+ channel_data : list [dict ], dye_mapping : dict
3884+ ) -> dict [str , tuple [float , float , float ]]:
38943885 color_dict = {}
38953886 key_counts = defaultdict (int )
38963887 for c_data in channel_data :
38973888 chan_id = c_data ["id" ]
38983889 name = c_data ["name" ]
3899- dye = c_data ["dye" ]
3900- rgb = c_data ["rgb" ]
39013890 dye = dye_mapping .get (chan_id )
3891+ rgb = c_data ["rgb" ]
39023892 base_key = f"{ name } ({ dye } )" if dye else name
3903-
3904- # Check for duplicates
39053893 count = key_counts [base_key ]
39063894 key = base_key if count == 0 else f"{ base_key } [{ count + 1 } ]"
39073895 color_dict [key ] = rgb
39083896 key_counts [base_key ] += 1
3897+ return color_dict
39093898
3899+ @staticmethod
3900+ def _parse_ome_metadata_mapping (
3901+ root : ElementTree ,
3902+ ) -> dict [str , tuple [float , float , float ]] | None :
3903+ """Parse OME metadata from the given XML root element.
3904+
3905+ Args:
3906+ root (ElementTree): The root of the parsed XML tree.
3907+
3908+ Returns:
3909+ dict[str, tuple[float, float, float]] | None: A mapping
3910+ of channel names to RGB tuples, or None if not found.
3911+ """
3912+ # 3) Try OME/Lunaphore format e.g. for COMET
3913+ ns = TIFFWSIReader ._get_namespace (root )
3914+ dye_mapping = TIFFWSIReader ._extract_dye_mapping (root , ns )
3915+ channel_data = TIFFWSIReader ._parse_channel_data (root , ns , dye_mapping )
3916+ color_dict = TIFFWSIReader ._build_color_dict (channel_data , dye_mapping )
39103917 return color_dict if color_dict else None
39113918
39123919 def _get_ome_xml (self : TIFFWSIReader ) -> ElementTree .Element :
0 commit comments