- Windows compatibility (no forking -> no sharing open file descriptors)
This commit is contained in:
2
setup.py
2
setup.py
@@ -5,7 +5,7 @@ with open('README.md', 'r') as fh:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name='tiffwrite',
|
name='tiffwrite',
|
||||||
version='2022.10.1',
|
version='2022.10.2',
|
||||||
author='Wim Pomp @ Lenstra lab NKI',
|
author='Wim Pomp @ Lenstra lab NKI',
|
||||||
author_email='w.pomp@nki.nl',
|
author_email='w.pomp@nki.nl',
|
||||||
description='Parallel tiff writer compatible with ImageJ.',
|
description='Parallel tiff writer compatible with ImageJ.',
|
||||||
|
|||||||
14
test.py
Normal file
14
test.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import tiffwrite
|
||||||
|
import numpy as np
|
||||||
|
from itertools import product
|
||||||
|
|
||||||
|
|
||||||
|
def test():
|
||||||
|
with tiffwrite.IJTiffWriter('test.tif', (3, 4, 5)) as tif:
|
||||||
|
for c, z, t in product(range(3), range(4), range(5)):
|
||||||
|
tif.save(np.random.randint(0, 255, (64, 64)), c, z, t)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
||||||
@@ -357,9 +357,9 @@ class IJTiffFile:
|
|||||||
self.spp = self.shape[0] if self.colormap is None and self.colors is None else 1 # samples/pixel
|
self.spp = self.shape[0] if self.colormap is None and self.colors is None else 1 # samples/pixel
|
||||||
self.nframes = np.prod(self.shape[1:]) if self.colormap is None and self.colors is None else np.prod(self.shape)
|
self.nframes = np.prod(self.shape[1:]) if self.colormap is None and self.colors is None else np.prod(self.shape)
|
||||||
self.offsets = {}
|
self.offsets = {}
|
||||||
self.fh = FileHandle(path, 'w+b')
|
self.fh = FileHandle(path)
|
||||||
self.namespace_manager = multiprocessing.Manager()
|
manager = multiprocessing.Manager()
|
||||||
self.hashes = self.namespace_manager.dict()
|
self.hashes = manager.dict()
|
||||||
self.strips = {}
|
self.strips = {}
|
||||||
self.ifds = {}
|
self.ifds = {}
|
||||||
self.frame_extra_tags = {}
|
self.frame_extra_tags = {}
|
||||||
@@ -503,7 +503,6 @@ class IJTiffFile:
|
|||||||
with self.fh.lock() as fh:
|
with self.fh.lock() as fh:
|
||||||
if len(self.frames_added) == 0:
|
if len(self.frames_added) == 0:
|
||||||
warn('At least one frame should be added to the tiff, removing file.')
|
warn('At least one frame should be added to the tiff, removing file.')
|
||||||
fh.close()
|
|
||||||
os.remove(self.path)
|
os.remove(self.path)
|
||||||
else:
|
else:
|
||||||
if len(self.frames_written) < np.prod(self.shape): # add empty frames if needed
|
if len(self.frames_written) < np.prod(self.shape): # add empty frames if needed
|
||||||
@@ -541,7 +540,6 @@ class IJTiffFile:
|
|||||||
self.ifds[framenr].write_offset(self.ifds[framenr - 1].where_to_write_next_ifd_offset)
|
self.ifds[framenr].write_offset(self.ifds[framenr - 1].where_to_write_next_ifd_offset)
|
||||||
else:
|
else:
|
||||||
self.ifds[framenr].write_offset(self.header.offset - self.header.offsetsize)
|
self.ifds[framenr].write_offset(self.header.offset - self.header.offsetsize)
|
||||||
fh.close()
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@@ -677,27 +675,28 @@ class PoolManager:
|
|||||||
|
|
||||||
class FileHandle:
|
class FileHandle:
|
||||||
""" Process safe file handle """
|
""" Process safe file handle """
|
||||||
def __init__(self, name, mode='rb'):
|
def __init__(self, name):
|
||||||
|
if os.path.exists(name):
|
||||||
|
os.remove(name)
|
||||||
|
with open(name, 'xb'):
|
||||||
|
pass
|
||||||
self.name = name
|
self.name = name
|
||||||
self.mode = mode
|
manager = multiprocessing.Manager()
|
||||||
self._lock = multiprocessing.RLock()
|
self._lock = manager.RLock()
|
||||||
self._fh = open(name, mode, 0)
|
self._pos = manager.Value('i', 0)
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, *args, **kwargs):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self._fh.close()
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def lock(self):
|
def lock(self):
|
||||||
self._lock.acquire()
|
self._lock.acquire()
|
||||||
|
f = None
|
||||||
try:
|
try:
|
||||||
yield self._fh
|
f = open(self.name, 'rb+')
|
||||||
|
f.seek(self._pos.value)
|
||||||
|
yield f
|
||||||
finally:
|
finally:
|
||||||
|
if f is not None:
|
||||||
|
self._pos.value = f.tell()
|
||||||
|
f.close()
|
||||||
self._lock.release()
|
self._lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user