diff --git a/openslide/lowlevel.py b/openslide/lowlevel.py index 22704c2d..7e771b5d 100644 --- a/openslide/lowlevel.py +++ b/openslide/lowlevel.py @@ -37,6 +37,8 @@ import platform import sys +from . import _convert + if platform.system() == 'Windows': _lib = cdll.LoadLibrary('libopenslide-0.dll') elif platform.system() == 'Darwin': @@ -57,58 +59,6 @@ else: _lib = cdll.LoadLibrary('libopenslide.so.0') -try: - from . import _convert - def _load_image(buf, size): - '''buf must be a mutable buffer.''' - _convert.argb2rgba(buf) - return PIL.Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) -except ImportError: - def _load_image(buf, size): - '''buf must be a buffer.''' - - # Load entire buffer at once if possible - MAX_PIXELS_PER_LOAD = (1 << 29) - 1 - # Otherwise, use chunks smaller than the maximum to reduce memory - # requirements - PIXELS_PER_LOAD = 1 << 26 - - def do_load(buf, size): - '''buf can be a string, but should be a ctypes buffer to avoid an - extra copy in the caller.''' - # First reorder the bytes in a pixel from native-endian aRGB to - # big-endian RGBa to work around limitations in RGBa loader - rawmode = (sys.byteorder == 'little') and 'BGRA' or 'ARGB' - buf = PIL.Image.frombuffer('RGBA', size, buf, 'raw', rawmode, 0, 1) - # Image.tobytes() is named tostring() in Pillow 1.x and PIL - buf = (getattr(buf, 'tobytes', None) or buf.tostring)() - # Now load the image as RGBA, undoing premultiplication - return PIL.Image.frombuffer('RGBA', size, buf, 'raw', 'RGBa', 0, 1) - - # Fast path for small buffers - w, h = size - if w * h <= MAX_PIXELS_PER_LOAD: - return do_load(buf, size) - - # Load in chunks to avoid OverflowError in PIL.Image.frombuffer() - # https://github.com/python-pillow/Pillow/issues/1475 - if w > PIXELS_PER_LOAD: - # We could support this, but it seems like overkill - raise ValueError('Width %d is too large (maximum %d)' % - (w, PIXELS_PER_LOAD)) - rows_per_load = PIXELS_PER_LOAD // w - img = PIL.Image.new('RGBA', (w, h)) - for y in range(0, h, rows_per_load): - rows = min(h - y, rows_per_load) - if sys.version[0] == '2': - chunk = buffer(buf, 4 * y * w, 4 * rows * w) - else: - # PIL.Image.frombuffer() won't take a memoryview or - # bytearray, so we can't avoid copying - chunk = memoryview(buf)[y * w:(y + rows) * w].tobytes() - img.paste(do_load(chunk, (w, rows)), (0, y)) - return img - class OpenSlideError(Exception): """An error produced by the OpenSlide library. @@ -167,6 +117,11 @@ def from_param(cls, obj): else: raise TypeError('Incorrect type') +def _load_image(buf, size): + '''buf must be a mutable buffer.''' + _convert.argb2rgba(buf) + return PIL.Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) + # check for errors opening an image file and wrap the resulting handle def _check_open(result, _func, _args): if result is None: diff --git a/tests/__init__.py b/tests/__init__.py index d2158b3d..3be04922 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -22,13 +22,6 @@ from PIL import Image import unittest -try: - import openslide._convert as _ - have_optimizations = True -except ImportError: - have_optimizations = False - - # PIL.Image cannot have zero width or height on Pillow 3.4.0 - 3.4.2 # https://github.com/python-pillow/Pillow/issues/2259 try: diff --git a/tests/test_openslide.py b/tests/test_openslide.py index f3d12df4..9b781368 100644 --- a/tests/test_openslide.py +++ b/tests/test_openslide.py @@ -25,8 +25,7 @@ import sys import unittest -from . import (file_path, have_optimizations, image_dimensions_cannot_be_zero, - skip_if) +from . import file_path, image_dimensions_cannot_be_zero, skip_if # Tests should be written to be compatible with Python 2.6 unittest. @@ -127,8 +126,7 @@ def test_read_region_bad_size(self): @skip_if(sys.maxsize < 1 << 32, '32-bit Python') # Broken on PIL and on Pillow >= 3.4.0, < 6.2.0. # https://github.com/python-pillow/Pillow/issues/3963 - @skip_if(have_optimizations and - [int(i) for i in getattr(Image, '__version__', '0').split('.')] < [6,2,0], + @skip_if([int(i) for i in getattr(Image, '__version__', '0').split('.')] < [6,2,0], 'broken on PIL and Pillow < 6.2.0') # Disabled to avoid OOM killer on small systems, since the stdlib # doesn't provide a way to find out how much RAM we have @@ -137,12 +135,6 @@ def _test_read_region_2GB(self): self.osr.read_region((1000, 1000), 0, (32768, 16384)).size, (32768, 16384)) - @skip_if(have_optimizations, 'only relevant --without-performance') - @skip_if(sys.maxsize < 1 << 32, '32-bit Python') - def test_read_region_2GB_width(self): - self.assertRaises(ValueError, - lambda: self.osr.read_region((1000, 1000), 0, (1 << 29, 1))) - def test_thumbnail(self): self.assertEqual(self.osr.get_thumbnail((100, 100)).size, (100, 83))