Skip to content

Commit 1cb52ce

Browse files
committed
Add ICC profile in OpenSlide.read_region()
Take care to reuse the same profile so we're not keeping multiple copies in RAM. Add sRGB profile to boxes.tiff fixture. For openslide/openslide#469. Signed-off-by: Benjamin Gilbert <[email protected]>
1 parent 53f4648 commit 1cb52ce

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

openslide/__init__.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# openslide-python - Python bindings for the OpenSlide library
33
#
44
# Copyright (c) 2010-2014 Carnegie Mellon University
5-
# Copyright (c) 2021 Benjamin Gilbert
5+
# Copyright (c) 2021-2023 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
@@ -55,6 +55,9 @@
5555
class AbstractSlide:
5656
"""The base class of a slide object."""
5757

58+
def __init__(self):
59+
self._profile = None
60+
5861
def __enter__(self):
5962
return self
6063

@@ -164,6 +167,8 @@ def __init__(self, filename):
164167
AbstractSlide.__init__(self)
165168
self._filename = filename
166169
self._osr = lowlevel.open(str(filename))
170+
if lowlevel.read_icc_profile.available:
171+
self._profile = lowlevel.read_icc_profile(self._osr)
167172

168173
def __repr__(self):
169174
return f'{self.__class__.__name__}({self._filename!r})'
@@ -233,9 +238,12 @@ def read_region(self, location, level, size):
233238
234239
Unlike in the C interface, the image data returned by this
235240
function is not premultiplied."""
236-
return lowlevel.read_region(
241+
region = lowlevel.read_region(
237242
self._osr, location[0], location[1], level, size[0], size[1]
238243
)
244+
if self._profile is not None:
245+
region.info['icc_profile'] = self._profile
246+
return region
239247

240248
def set_cache(self, cache):
241249
"""Use the specified cache to store recently decoded slide tiles.

openslide/lowlevel.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from ctypes import (
3434
POINTER,
3535
byref,
36+
c_char,
3637
c_char_p,
3738
c_double,
3839
c_int32,
@@ -335,6 +336,31 @@ def read_region(slide, x, y, level, w, h):
335336
return _load_image(buf, (w, h))
336337

337338

339+
get_icc_profile_size = _func(
340+
'openslide_get_icc_profile_size',
341+
c_int64,
342+
[_OpenSlide],
343+
minimum_version='4.0.0',
344+
)
345+
346+
_read_icc_profile = _func(
347+
'openslide_read_icc_profile',
348+
None,
349+
[_OpenSlide, POINTER(c_char)],
350+
minimum_version='4.0.0',
351+
)
352+
353+
354+
@_wraps_funcs([get_icc_profile_size, _read_icc_profile])
355+
def read_icc_profile(slide):
356+
size = get_icc_profile_size(slide)
357+
if size == 0:
358+
return None
359+
buf = (size * c_char)()
360+
_read_icc_profile(slide, buf)
361+
return buf.raw
362+
363+
338364
get_error = _func('openslide_get_error', c_char_p, [_OpenSlide], _check_string)
339365

340366
get_property_names = _func(

tests/fixtures/boxes.tiff

4.02 KB
Binary file not shown.

tests/test_openslide.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ def test_properties(self):
123123
repr(self.osr.properties), '<_PropertyMap %r>' % dict(self.osr.properties)
124124
)
125125

126+
@unittest.skipUnless(
127+
lowlevel.read_icc_profile.available, "requires OpenSlide 4.0.0"
128+
)
129+
def test_color_profile(self):
130+
self.assertEqual(
131+
len(self.osr.read_region((0, 0), 0, (100, 100)).info['icc_profile']), 588
132+
)
133+
126134
def test_read_region(self):
127135
self.assertEqual(
128136
self.osr.read_region((-10, -10), 1, (400, 400)).size, (400, 400)
@@ -184,6 +192,11 @@ def mangle_repr(o):
184192
'<_AssociatedImageMap %s>' % mangle_repr(dict(self.osr.associated_images)),
185193
)
186194

195+
def test_color_profile(self):
196+
self.assertNotIn(
197+
'icc_profile', self.osr.read_region((0, 0), 0, (100, 100)).info
198+
)
199+
187200

188201
class TestUnreadableSlide(_SlideTest, unittest.TestCase):
189202
FILENAME = 'unreadable.svs'

0 commit comments

Comments
 (0)