@@ -405,6 +405,15 @@ def open( # noqa: PLR0911
405405
406406 @staticmethod
407407 def _validate_input (input_img : str | Path | np .ndarray ) -> None :
408+ """Validate the input image type.
409+
410+ Args:
411+ input_img (str | Path | np.ndarray): The input image, which
412+ must be a path, string, numpy array, or WSIReader.
413+
414+ Raises:
415+ TypeError: If the input is not one of the accepted types.
416+ """
408417 if not isinstance (input_img , (WSIReader , np .ndarray , str , Path )):
409418 msg = "Invalid input: Must be a WSIReader, numpy array, string or Path"
410419 raise TypeError (msg )
@@ -457,8 +466,27 @@ def _handle_special_cases(
457466 post_proc : str | callable | None = "auto" ,
458467 ** kwargs : dict ,
459468 ) -> WSIReader | None :
460- reader = None
469+ """Handle special cases for selecting the appropriate WSIReader based on file
470+ type and metadata.
471+
472+ Args:
473+ input_path (Path): Path to the input image file.
474+ input_img (str | Path | np.ndarray): The input image or path.
475+ mpp (tuple[Number, Number] | None, optional): Microns per pixel resolution.
476+ power (Number | None, optional): Objective power.
477+ post_proc (str | callable | None, optional): Post-processing method
478+ or identifier.
479+ **kwargs (dict): Additional keyword arguments for specific reader types.
480+
481+ Returns:
482+ WSIReader | None: An appropriate WSIReader instance if a match is found,
483+ otherwise None.
461484
485+ Raises:
486+ FileNotSupportedError: If the file format is not supported for NGFF Zarr.
487+
488+ """
489+ reader = None
462490 if is_dicom (input_path ):
463491 reader = DICOMWSIReader (
464492 input_path , mpp = mpp , power = power , post_proc = post_proc
@@ -3668,18 +3696,28 @@ def _get_colors_from_meta(self: TIFFWSIReader) -> None:
36683696
36693697 # Try multiple formats
36703698 for parser in (
3671- self ._parse_scancolortable ,
3672- self ._parse_filtercolor_metadata ,
3673- self ._parse_ome_metadata_mapping ,
3699+ TIFFWSIReader ._parse_scancolortable ,
3700+ TIFFWSIReader ._parse_filtercolor_metadata ,
3701+ TIFFWSIReader ._parse_ome_metadata_mapping ,
36743702 ):
36753703 color_dict = parser (root )
36763704 if color_dict :
36773705 self .post_proc .color_dict = color_dict
36783706 return
36793707
3708+ @staticmethod
36803709 def _parse_scancolortable (
3681- self , root : ElementTree
3710+ root : ElementTree ,
36823711 ) -> dict [str , tuple [float , float , float ]] | None :
3712+ """Parse ScanColorTable metadata from XML and convert color values to RGB.
3713+
3714+ Args:
3715+ root (ElementTree): The root of the parsed XML tree.
3716+
3717+ Returns:
3718+ dict[str, tuple[float, float, float]] | None: A mapping of channel
3719+ names to RGB tuples, or None if not found.
3720+ """
36833721 color_info = root .find (".//ScanColorTable" )
36843722 if color_info is None :
36853723 return None
@@ -3703,9 +3741,19 @@ def _parse_scancolortable(
37033741
37043742 return color_dict
37053743
3744+ @staticmethod
37063745 def _parse_filtercolor_metadata (
3707- self , root : ElementTree
3746+ root : ElementTree ,
37083747 ) -> dict [str , tuple [float , float , float ]] | None :
3748+ """Parse FilterColors metadata from XML and convert color values to RGB.
3749+
3750+ Args:
3751+ root (ElementTree): The root of the parsed XML tree.
3752+
3753+ Returns:
3754+ dict[str, tuple[float, float, float]] | None: A mapping of channel
3755+ names to RGB tuples, or None if not found.
3756+ """
37093757 # try alternate metadata format
37103758 # Build a map from filter pair string -> color label or RGB string
37113759 # from the <FilterColors> section
@@ -3722,6 +3770,14 @@ def _parse_filtercolor_metadata(
37223770 # Helper function to convert color strings like "Lime" or
37233771 # "255, 128, 0" into (R,G,B)
37243772 def color_string_to_rgb (s : str ) -> tuple [float , float , float ]:
3773+ """Convert a color string (e.g., 'Lime' or '255, 128, 0') to an RGB tuple.
3774+
3775+ Args:
3776+ s (str): The color string.
3777+
3778+ Returns:
3779+ tuple[float, float, float]: RGB values normalized to [0, 1].
3780+ """
37253781 if "," in s :
37263782 return tuple (int (x .strip ()) / 255 for x in s .split ("," ))
37273783 return mcolors .to_rgb (s )
@@ -3762,9 +3818,19 @@ def color_string_to_rgb(s: str) -> tuple[float, float, float]:
37623818
37633819 return channel_dict if channel_dict else None
37643820
3821+ @staticmethod
37653822 def _parse_ome_metadata_mapping (
3766- self , root : ElementTree
3823+ root : ElementTree ,
37673824 ) -> 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+ """
37683834 # 3) Try OME/Lunaphore format e.g. for COMET
37693835 ns = {}
37703836 if root .tag .startswith ("{" ):
@@ -3783,6 +3849,23 @@ def _parse_ome_metadata_mapping(
37833849 if chan_id and dye :
37843850 dye_mapping [chan_id ] = dye
37853851
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 )
3868+
37863869 channel_data = []
37873870 for pixels in root .findall (".//ns:Pixels" , ns ):
37883871 for channel in pixels .findall ("ns:Channel" , ns ):
@@ -3792,12 +3875,7 @@ def _parse_ome_metadata_mapping(
37923875 if chan_id and name and color :
37933876 try :
37943877 color_int = int (color )
3795- if color_int < 0 :
3796- color_int += 1 << 32
3797- r = (color_int >> 16 ) & 0xFF
3798- g = (color_int >> 8 ) & 0xFF
3799- b = color_int & 0xFF
3800- rgb = (r / 255 , g / 255 , b / 255 )
3878+ rgb = _int_to_rgb (color_int )
38013879 except ValueError :
38023880 rgb = None
38033881
0 commit comments