22# openslide-python - Python bindings for the OpenSlide library
33#
44# Copyright (c) 2010-2013 Carnegie Mellon University
5- # Copyright (c) 2016-2023 Benjamin Gilbert
5+ # Copyright (c) 2016-2024 Benjamin Gilbert
66#
77# This library is free software; you can redistribute it and/or modify it
88# under the terms of version 2.1 of the GNU Lesser General Public License
4848 cdll ,
4949)
5050from itertools import count
51+ import os
5152import platform
5253from typing import TYPE_CHECKING , Any , Callable , Protocol , TypeVar , cast
5354
5657from . import _convert
5758
5859if TYPE_CHECKING :
59- # Python 3.10+ for ParamSpec
60+ # Python 3.10+
6061 from typing import ParamSpec , TypeAlias
6162
6263 from _convert import _Buffer
@@ -196,6 +197,28 @@ def from_param(cls, obj: _OpenSlideCache) -> _OpenSlideCache:
196197 return obj
197198
198199
200+ if TYPE_CHECKING :
201+ # Python 3.10+
202+ Filename : TypeAlias = str | bytes | os .PathLike [Any ]
203+
204+
205+ class _filename_p :
206+ """Wrapper class to convert filename arguments to bytes."""
207+
208+ @classmethod
209+ def from_param (cls , obj : Filename ) -> bytes :
210+ # fspath and fsencode raise TypeError on unexpected types
211+ if platform .system () == 'Windows' :
212+ # OpenSlide 4.0.0+ requires UTF-8 on Windows
213+ obj = os .fspath (obj )
214+ if isinstance (obj , str ):
215+ return obj .encode ('UTF-8' )
216+ else :
217+ return obj
218+ else :
219+ return os .fsencode (obj )
220+
221+
199222class _utf8_p :
200223 """Wrapper class to convert string arguments to bytes."""
201224
@@ -350,14 +373,14 @@ def decorator(fn: Callable[_P, _T]) -> _Func[_P, _T]:
350373
351374
352375try :
353- detect_vendor : _Func [[str ], str ] = _func (
354- 'openslide_detect_vendor' , c_char_p , [_utf8_p ], _check_string
376+ detect_vendor : _Func [[Filename ], str ] = _func (
377+ 'openslide_detect_vendor' , c_char_p , [_filename_p ], _check_string
355378 )
356379except AttributeError :
357380 raise OpenSlideVersionError ('3.4.0' )
358381
359- open : _Func [[str ], _OpenSlide ] = _func (
360- 'openslide_open' , c_void_p , [_utf8_p ], _check_open
382+ open : _Func [[Filename ], _OpenSlide ] = _func (
383+ 'openslide_open' , c_void_p , [_filename_p ], _check_open
361384)
362385
363386close : _Func [[_OpenSlide ], None ] = _func (
@@ -452,7 +475,7 @@ def read_icc_profile(slide: _OpenSlide) -> bytes | None:
452475 'openslide_get_property_names' , POINTER (c_char_p ), [_OpenSlide ], _check_name_list
453476)
454477
455- get_property_value : _Func [[_OpenSlide , str ], str ] = _func (
478+ get_property_value : _Func [[_OpenSlide , str | bytes ], str ] = _func (
456479 'openslide_get_property_value' , c_char_p , [_OpenSlide , _utf8_p ]
457480)
458481
@@ -464,7 +487,7 @@ def read_icc_profile(slide: _OpenSlide) -> bytes | None:
464487)
465488
466489_get_associated_image_dimensions : _Func [
467- [_OpenSlide , str , _Pointer [c_int64 ], _Pointer [c_int64 ]], None
490+ [_OpenSlide , str | bytes , _Pointer [c_int64 ], _Pointer [c_int64 ]], None
468491] = _func (
469492 'openslide_get_associated_image_dimensions' ,
470493 None ,
@@ -473,46 +496,54 @@ def read_icc_profile(slide: _OpenSlide) -> bytes | None:
473496
474497
475498@_wraps_funcs ([_get_associated_image_dimensions ])
476- def get_associated_image_dimensions (slide : _OpenSlide , name : str ) -> tuple [int , int ]:
499+ def get_associated_image_dimensions (
500+ slide : _OpenSlide , name : str | bytes
501+ ) -> tuple [int , int ]:
477502 w , h = c_int64 (), c_int64 ()
478503 _get_associated_image_dimensions (slide , name , byref (w ), byref (h ))
479504 return w .value , h .value
480505
481506
482- _read_associated_image : _Func [[_OpenSlide , str , _Pointer [c_uint32 ]], None ] = _func (
483- 'openslide_read_associated_image' , None , [_OpenSlide , _utf8_p , POINTER (c_uint32 )]
507+ _read_associated_image : _Func [[_OpenSlide , str | bytes , _Pointer [c_uint32 ]], None ] = (
508+ _func (
509+ 'openslide_read_associated_image' ,
510+ None ,
511+ [_OpenSlide , _utf8_p , POINTER (c_uint32 )],
512+ )
484513)
485514
486515
487516@_wraps_funcs ([get_associated_image_dimensions , _read_associated_image ])
488- def read_associated_image (slide : _OpenSlide , name : str ) -> Image .Image :
517+ def read_associated_image (slide : _OpenSlide , name : str | bytes ) -> Image .Image :
489518 w , h = get_associated_image_dimensions (slide , name )
490519 buf = (w * h * c_uint32 )()
491520 _read_associated_image (slide , name , buf )
492521 return _load_image (buf , (w , h ))
493522
494523
495- get_associated_image_icc_profile_size : _Func [[_OpenSlide , str ], int ] = _func (
524+ get_associated_image_icc_profile_size : _Func [[_OpenSlide , str | bytes ], int ] = _func (
496525 'openslide_get_associated_image_icc_profile_size' ,
497526 c_int64 ,
498527 [_OpenSlide , _utf8_p ],
499528 minimum_version = '4.0.0' ,
500529)
501530
502- _read_associated_image_icc_profile : _Func [[ _OpenSlide , str , _Pointer [ c_char ]], None ] = (
503- _func (
504- 'openslide_read_associated_image_icc_profile' ,
505- None ,
506- [ _OpenSlide , _utf8_p , POINTER ( c_char )] ,
507- minimum_version = '4.0.0' ,
508- )
531+ _read_associated_image_icc_profile : _Func [
532+ [ _OpenSlide , str | bytes , _Pointer [ c_char ]], None
533+ ] = _func (
534+ 'openslide_read_associated_image_icc_profile' ,
535+ None ,
536+ [ _OpenSlide , _utf8_p , POINTER ( c_char )] ,
537+ minimum_version = '4.0.0' ,
509538)
510539
511540
512541@_wraps_funcs (
513542 [get_associated_image_icc_profile_size , _read_associated_image_icc_profile ]
514543)
515- def read_associated_image_icc_profile (slide : _OpenSlide , name : str ) -> bytes | None :
544+ def read_associated_image_icc_profile (
545+ slide : _OpenSlide , name : str | bytes
546+ ) -> bytes | None :
516547 size = get_associated_image_icc_profile_size (slide , name )
517548 if size == 0 :
518549 return None
0 commit comments