22# openslide-python - Python bindings for the OpenSlide library
33#
44# Copyright (c) 2010-2013 Carnegie Mellon University
5- # Copyright (c) 2016 Benjamin Gilbert
5+ # Copyright (c) 2016-2021 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
3737 c_double ,
3838 c_int32 ,
3939 c_int64 ,
40+ c_size_t ,
4041 c_uint32 ,
4142 c_void_p ,
4243 cdll ,
@@ -90,6 +91,17 @@ class OpenSlideError(Exception):
9091 """
9192
9293
94+ class OpenSlideVersionError (OpenSlideError ):
95+ """This version of OpenSlide does not support the requested functionality.
96+
97+ Import this from openslide rather than from openslide.lowlevel.
98+ """
99+
100+ def __init__ (self , minimum_version ):
101+ super ().__init__ (f'OpenSlide >= { minimum_version } required' )
102+ self .minimum_version = minimum_version
103+
104+
93105class OpenSlideUnsupportedFormatError (OpenSlideError ):
94106 """OpenSlide does not support the requested file.
95107
@@ -125,6 +137,27 @@ def from_param(cls, obj):
125137 return obj
126138
127139
140+ class _OpenSlideCache :
141+ """Wrapper class to make sure we correctly pass an OpenSlide cache."""
142+
143+ def __init__ (self , ptr ):
144+ self ._as_parameter_ = ptr
145+ # Retain a reference to cache_release() to avoid GC problems during
146+ # interpreter shutdown
147+ self ._cache_release = cache_release
148+
149+ def __del__ (self ):
150+ self ._cache_release (self )
151+
152+ @classmethod
153+ def from_param (cls , obj ):
154+ if obj .__class__ != cls :
155+ raise ValueError ("Not an OpenSlide cache reference" )
156+ if not obj ._as_parameter_ :
157+ raise ValueError ("Passing undefined cache object" )
158+ return obj
159+
160+
128161class _utf8_p :
129162 """Wrapper class to convert string arguments to bytes."""
130163
@@ -138,6 +171,18 @@ def from_param(cls, obj):
138171 raise TypeError ('Incorrect type' )
139172
140173
174+ class _size_t :
175+ """Wrapper class to convert size_t arguments to c_size_t."""
176+
177+ @classmethod
178+ def from_param (cls , obj ):
179+ if not isinstance (obj , int ):
180+ raise TypeError ('Incorrect type' )
181+ if obj < 0 :
182+ raise ValueError ('Value out of range' )
183+ return c_size_t (obj )
184+
185+
141186def _load_image (buf , size ):
142187 '''buf must be a mutable buffer.'''
143188 _convert .argb2rgba (buf )
@@ -160,6 +205,11 @@ def _check_close(_result, _func, args):
160205 args [0 ].invalidate ()
161206
162207
208+ # wrap the handle returned when creating a cache
209+ def _check_cache_create (result , _func , _args ):
210+ return _OpenSlideCache (c_void_p (result ))
211+
212+
163213# Convert returned byte array, if present, into a string
164214def _check_string (result , func , _args ):
165215 if func .restype is c_char_p and result is not None :
@@ -189,8 +239,18 @@ def _check_name_list(result, func, args):
189239
190240
191241# resolve and return an OpenSlide function with the specified properties
192- def _func (name , restype , argtypes , errcheck = _check_error ):
193- func = getattr (_lib , name )
242+ def _func (name , restype , argtypes , errcheck = _check_error , minimum_version = None ):
243+ try :
244+ func = getattr (_lib , name )
245+ except AttributeError :
246+ if minimum_version is None :
247+ raise
248+
249+ # optional function doesn't exist; fail at runtime
250+ def function_unavailable (* _args ):
251+ raise OpenSlideVersionError (minimum_version )
252+
253+ return function_unavailable
194254 func .argtypes = argtypes
195255 func .restype = restype
196256 if errcheck is not None :
@@ -201,7 +261,7 @@ def _func(name, restype, argtypes, errcheck=_check_error):
201261try :
202262 detect_vendor = _func ('openslide_detect_vendor' , c_char_p , [_utf8_p ], _check_string )
203263except AttributeError :
204- raise OpenSlideError ( 'OpenSlide >= 3.4.0 required ' )
264+ raise OpenSlideVersionError ( ' 3.4.0' )
205265
206266open = _func ('openslide_open' , c_void_p , [_utf8_p ], _check_open )
207267
@@ -295,3 +355,23 @@ def read_associated_image(slide, name):
295355
296356
297357get_version = _func ('openslide_get_version' , c_char_p , [], _check_string )
358+
359+ cache_create = _func (
360+ 'openslide_cache_create' ,
361+ c_void_p ,
362+ [_size_t ],
363+ _check_cache_create ,
364+ minimum_version = '3.5.0' ,
365+ )
366+
367+ set_cache = _func (
368+ 'openslide_set_cache' ,
369+ None ,
370+ [_OpenSlide , _OpenSlideCache ],
371+ None ,
372+ minimum_version = '3.5.0' ,
373+ )
374+
375+ cache_release = _func (
376+ 'openslide_cache_release' , None , [_OpenSlideCache ], None , minimum_version = '3.5.0'
377+ )
0 commit comments