pyisyntax 0.1.4__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/CHANGELOG.md +13 -1
- {pyisyntax-0.1.4/pyisyntax.egg-info → pyisyntax-0.1.5}/PKG-INFO +10 -23
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/README.md +6 -12
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax/lowlevel/io_management.py +11 -8
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax/lowlevel/libisyntax.py +68 -46
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax/wrapper.py +41 -5
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/builder.py +21 -21
- pyisyntax-0.1.5/isyntax_build/vendor/libisyntax/src/examples/isyntax_dirwalk.c +91 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.c +58 -33
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.h +6 -3
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.c +16 -8
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.h +3 -2
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.c +4 -1
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/libisyntax.c +97 -39
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/libisyntax.h +11 -1
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/block_allocator.c +22 -13
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/memrw.c +24 -15
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/timerutils.c +24 -15
- {pyisyntax-0.1.4 → pyisyntax-0.1.5/pyisyntax.egg-info}/PKG-INFO +10 -23
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/pyisyntax.egg-info/SOURCES.txt +1 -0
- pyisyntax-0.1.5/pyisyntax.egg-info/requires.txt +2 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/pyproject.toml +30 -20
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/tests/conftest.py +2 -2
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/tests/test_lowlevel.py +33 -7
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/tests/test_wrapper.py +9 -1
- pyisyntax-0.1.4/pyisyntax.egg-info/requires.txt +0 -11
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/LICENSE +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/MANIFEST.in +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax/__init__.py +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax/lowlevel/__init__.py +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/__init__.py +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/pyisyntax.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/src/python_platform_utils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/src/python_platform_utils.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/src/win32_utils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/LICENSE.txt +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/README.md +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/examples/isyntax_example.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/examples/isyntax_to_tiff.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_dwt.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/arena.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/common.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/intrinsics.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/linux_platform.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/linux_utils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/platform.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/platform.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/win32_utils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/win32_utils.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/work_queue.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/work_queue.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.cc +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_ds.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_image.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_image_write.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_sprintf.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/yxml.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/yxml.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/benaphore.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/benaphore.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/block_allocator.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/libtiff_api.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/mathutils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/mathutils.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/memrw.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/stringutils.c +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/stringutils.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/timerutils.h +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/pyisyntax.egg-info/dependency_links.txt +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/pyisyntax.egg-info/not-zip-safe +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/pyisyntax.egg-info/top_level.txt +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/setup.cfg +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/setup.py +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/tests/__init__.py +0 -0
- {pyisyntax-0.1.4 → pyisyntax-0.1.5}/tests/data/DOWNLOAD.txt +0 -0
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.5] - 2025-04-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Properties `offset_x`and `offset_y` for the WSI image offset in relation to the macro image.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Bump the `libisyntax` submodule commit.
|
|
19
|
+
- Use `uv` for development environment management (was previously `conda-lock`).
|
|
20
|
+
|
|
10
21
|
## [0.1.4] - 2024-08-31
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -61,7 +72,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
61
72
|
|
|
62
73
|
- This is the initial release.
|
|
63
74
|
|
|
64
|
-
[unreleased]: https://github.com/anibali/pyisyntax/compare/v0.1.
|
|
75
|
+
[unreleased]: https://github.com/anibali/pyisyntax/compare/v0.1.5...HEAD
|
|
76
|
+
[0.1.4]: https://github.com/anibali/pyisyntax/compare/v0.1.4...v0.1.5
|
|
65
77
|
[0.1.4]: https://github.com/anibali/pyisyntax/compare/v0.1.3...v0.1.4
|
|
66
78
|
[0.1.3]: https://github.com/anibali/pyisyntax/compare/v0.1.2...v0.1.3
|
|
67
79
|
[0.1.2]: https://github.com/anibali/pyisyntax/compare/v0.1.1...v0.1.2
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pyisyntax
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Python bindings for libisyntax
|
|
5
5
|
Author-email: Aiden Nibali <dismaldenizen@gmail.com>
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/anibali/pyisyntax
|
|
8
8
|
Project-URL: Source, https://github.com/anibali/pyisyntax
|
|
9
9
|
Project-URL: Download, https://pypi.org/project/pyisyntax/#files
|
|
@@ -14,14 +14,7 @@ Description-Content-Type: text/markdown
|
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Requires-Dist: cffi>=1.12
|
|
16
16
|
Requires-Dist: numpy
|
|
17
|
-
|
|
18
|
-
Requires-Dist: conda-lock; extra == "dev"
|
|
19
|
-
Requires-Dist: pytest; extra == "dev"
|
|
20
|
-
Requires-Dist: pytest-mock; extra == "dev"
|
|
21
|
-
Requires-Dist: ruff==0.2.1; extra == "dev"
|
|
22
|
-
Requires-Dist: tox>=4.0; extra == "dev"
|
|
23
|
-
Requires-Dist: twine; extra == "dev"
|
|
24
|
-
Requires-Dist: typing_extensions; extra == "dev"
|
|
17
|
+
Dynamic: license-file
|
|
25
18
|
|
|
26
19
|
# pyisyntax
|
|
27
20
|
|
|
@@ -73,22 +66,16 @@ with ISyntax.open("my_file.isyntax") as isyntax:
|
|
|
73
66
|
|
|
74
67
|
To set up a development environment from the lock file:
|
|
75
68
|
|
|
76
|
-
1. Ensure that you have
|
|
77
|
-
|
|
78
|
-
installed.
|
|
79
|
-
2. Create the environment:
|
|
69
|
+
1. Ensure that you have [uv](https://docs.astral.sh/uv/) installed.
|
|
70
|
+
2. Create the virtual environment:
|
|
80
71
|
```console
|
|
81
|
-
$
|
|
82
|
-
```
|
|
83
|
-
3. Activate the environment:
|
|
84
|
-
```console
|
|
85
|
-
$ micromamba activate pyisyntax
|
|
72
|
+
$ uv sync --frozen
|
|
86
73
|
```
|
|
87
74
|
|
|
88
75
|
To modify pyisyntax project dependencies:
|
|
89
76
|
|
|
90
|
-
1. Edit pyproject.toml
|
|
91
|
-
2. Update the lock file using
|
|
77
|
+
1. Edit dependencies in `pyproject.toml`.
|
|
78
|
+
2. Update the lock file using uv:
|
|
92
79
|
```console
|
|
93
|
-
$
|
|
80
|
+
$ uv lock
|
|
94
81
|
```
|
|
@@ -48,22 +48,16 @@ with ISyntax.open("my_file.isyntax") as isyntax:
|
|
|
48
48
|
|
|
49
49
|
To set up a development environment from the lock file:
|
|
50
50
|
|
|
51
|
-
1. Ensure that you have
|
|
52
|
-
|
|
53
|
-
installed.
|
|
54
|
-
2. Create the environment:
|
|
51
|
+
1. Ensure that you have [uv](https://docs.astral.sh/uv/) installed.
|
|
52
|
+
2. Create the virtual environment:
|
|
55
53
|
```console
|
|
56
|
-
$
|
|
57
|
-
```
|
|
58
|
-
3. Activate the environment:
|
|
59
|
-
```console
|
|
60
|
-
$ micromamba activate pyisyntax
|
|
54
|
+
$ uv sync --frozen
|
|
61
55
|
```
|
|
62
56
|
|
|
63
57
|
To modify pyisyntax project dependencies:
|
|
64
58
|
|
|
65
|
-
1. Edit pyproject.toml
|
|
66
|
-
2. Update the lock file using
|
|
59
|
+
1. Edit dependencies in `pyproject.toml`.
|
|
60
|
+
2. Update the lock file using uv:
|
|
67
61
|
```console
|
|
68
|
-
$
|
|
62
|
+
$ uv lock
|
|
69
63
|
```
|
|
@@ -27,12 +27,15 @@ class ByHandleRegistry(Generic[T]):
|
|
|
27
27
|
Handles start at 1, autoincrement, and will automatically be recycled
|
|
28
28
|
once objects are removed from the registry.
|
|
29
29
|
"""
|
|
30
|
-
self._list = []
|
|
30
|
+
self._list: list[T | ByHandleRegistry._EmptySlot] = []
|
|
31
31
|
self._n_free = 0
|
|
32
32
|
self._empty_slot = self._EmptySlot()
|
|
33
33
|
|
|
34
34
|
def pop(self, handle: int) -> T:
|
|
35
35
|
element = self._list[handle - 1]
|
|
36
|
+
if isinstance(element, ByHandleRegistry._EmptySlot):
|
|
37
|
+
msg = "empty slot"
|
|
38
|
+
raise IndexError(msg)
|
|
36
39
|
self._list[handle - 1] = self._empty_slot
|
|
37
40
|
self._n_free += 1
|
|
38
41
|
if len(self._list) == handle:
|
|
@@ -52,11 +55,15 @@ class ByHandleRegistry(Generic[T]):
|
|
|
52
55
|
return index + 1
|
|
53
56
|
|
|
54
57
|
def __getitem__(self, handle: int) -> T:
|
|
55
|
-
|
|
58
|
+
element = self._list[handle - 1]
|
|
59
|
+
if isinstance(element, ByHandleRegistry._EmptySlot):
|
|
60
|
+
msg = "empty slot"
|
|
61
|
+
raise IndexError(msg)
|
|
62
|
+
return element
|
|
56
63
|
|
|
57
64
|
def items(self) -> Iterator[tuple[int, T]]:
|
|
58
65
|
for i, element in enumerate(self._list):
|
|
59
|
-
if element
|
|
66
|
+
if not isinstance(element, ByHandleRegistry._EmptySlot):
|
|
60
67
|
yield i + 1, element
|
|
61
68
|
|
|
62
69
|
|
|
@@ -69,7 +76,6 @@ def init_python_io_hooks() -> None:
|
|
|
69
76
|
_io_registry[handle].f.seek(offset)
|
|
70
77
|
return True
|
|
71
78
|
|
|
72
|
-
|
|
73
79
|
@ffi.def_extern()
|
|
74
80
|
def python_file_read_into(handle: int, dest: VoidPtr, bytes_to_read: int) -> int:
|
|
75
81
|
bytes_read = _io_registry[handle].f.readinto(ffi.buffer(dest, bytes_to_read))
|
|
@@ -77,17 +83,14 @@ def init_python_io_hooks() -> None:
|
|
|
77
83
|
raise RuntimeError
|
|
78
84
|
return max(bytes_read, 1)
|
|
79
85
|
|
|
80
|
-
|
|
81
86
|
@ffi.def_extern()
|
|
82
87
|
def python_file_get_size(handle: int) -> int:
|
|
83
88
|
return _io_registry[handle].n_bytes
|
|
84
89
|
|
|
85
|
-
|
|
86
90
|
@ffi.def_extern()
|
|
87
91
|
def python_file_close(handle: int) -> None:
|
|
88
92
|
_io_registry.pop(handle).f.close()
|
|
89
93
|
|
|
90
|
-
|
|
91
94
|
lib.init_python_platform_utils(
|
|
92
95
|
lib.python_file_set_pos,
|
|
93
96
|
lib.python_file_read_into,
|
|
@@ -109,7 +112,7 @@ def register_io(f: RawIOBase | BufferedIOBase, n_bytes: int) -> int:
|
|
|
109
112
|
Returns:
|
|
110
113
|
New handle assigned to the IO object.
|
|
111
114
|
"""
|
|
112
|
-
if not f.readable:
|
|
115
|
+
if not f.readable():
|
|
113
116
|
msg = "IO object must be readable"
|
|
114
117
|
raise RuntimeError(msg)
|
|
115
118
|
return _io_registry.add(SizedIO(f, n_bytes))
|
|
@@ -77,11 +77,13 @@ def open_from_registered_handle(handle: int, *, is_init_allocators: bool = False
|
|
|
77
77
|
init()
|
|
78
78
|
|
|
79
79
|
isyntax = ffi.new("isyntax_t**")
|
|
80
|
-
check_error(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
check_error(
|
|
81
|
+
lib.libisyntax_open(
|
|
82
|
+
ffi.new("char[]", str(handle).encode("utf-8")),
|
|
83
|
+
is_init_allocators,
|
|
84
|
+
isyntax,
|
|
85
|
+
),
|
|
86
|
+
)
|
|
85
87
|
return isyntax[0]
|
|
86
88
|
|
|
87
89
|
|
|
@@ -131,6 +133,14 @@ def image_get_level(wsi_image: ISyntaxImagePtr, index: int) -> ISyntaxLevelPtr:
|
|
|
131
133
|
return lib.libisyntax_image_get_level(wsi_image, index)
|
|
132
134
|
|
|
133
135
|
|
|
136
|
+
def image_get_offset_x(wsi_image: ISyntaxImagePtr) -> int:
|
|
137
|
+
return lib.libisyntax_image_get_offset_x(wsi_image)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def image_get_offset_y(wsi_image: ISyntaxImagePtr) -> int:
|
|
141
|
+
return lib.libisyntax_image_get_offset_y(wsi_image)
|
|
142
|
+
|
|
143
|
+
|
|
134
144
|
def level_get_scale(level: ISyntaxLevelPtr) -> int:
|
|
135
145
|
return lib.libisyntax_level_get_scale(level)
|
|
136
146
|
|
|
@@ -165,11 +175,13 @@ def cache_create(debug_name: str | None, cache_size: int) -> ISyntaxCachePtr:
|
|
|
165
175
|
debug_name_or_null = ffi.NULL
|
|
166
176
|
else:
|
|
167
177
|
debug_name_or_null = ffi.new("char[]", debug_name.encode("utf-8"))
|
|
168
|
-
check_error(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
check_error(
|
|
179
|
+
lib.libisyntax_cache_create(
|
|
180
|
+
debug_name_or_null,
|
|
181
|
+
cache_size,
|
|
182
|
+
isyntax_cache,
|
|
183
|
+
),
|
|
184
|
+
)
|
|
173
185
|
return isyntax_cache[0]
|
|
174
186
|
|
|
175
187
|
|
|
@@ -192,15 +204,17 @@ def tile_read(
|
|
|
192
204
|
pixels_buffer: "Buffer | FFI.buffer",
|
|
193
205
|
pixel_format: ISyntaxPixelFormat,
|
|
194
206
|
) -> None:
|
|
195
|
-
check_error(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
check_error(
|
|
208
|
+
lib.libisyntax_tile_read(
|
|
209
|
+
isyntax,
|
|
210
|
+
isyntax_cache,
|
|
211
|
+
level,
|
|
212
|
+
tile_x,
|
|
213
|
+
tile_y,
|
|
214
|
+
ffi.from_buffer("uint32_t[]", pixels_buffer, require_writable=True),
|
|
215
|
+
pixel_format,
|
|
216
|
+
),
|
|
217
|
+
)
|
|
204
218
|
|
|
205
219
|
|
|
206
220
|
def read_region(
|
|
@@ -214,27 +228,31 @@ def read_region(
|
|
|
214
228
|
pixels_buffer: "Buffer | FFI.buffer",
|
|
215
229
|
pixel_format: ISyntaxPixelFormat,
|
|
216
230
|
) -> None:
|
|
217
|
-
check_error(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
231
|
+
check_error(
|
|
232
|
+
lib.libisyntax_read_region(
|
|
233
|
+
isyntax,
|
|
234
|
+
isyntax_cache,
|
|
235
|
+
level,
|
|
236
|
+
x,
|
|
237
|
+
y,
|
|
238
|
+
width,
|
|
239
|
+
height,
|
|
240
|
+
ffi.from_buffer("uint32_t[]", pixels_buffer, require_writable=True),
|
|
241
|
+
pixel_format,
|
|
242
|
+
),
|
|
243
|
+
)
|
|
228
244
|
|
|
229
245
|
|
|
230
246
|
def read_label_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
231
247
|
jpeg_buffer_ptr = ffi.new("uint8_t**")
|
|
232
248
|
jpeg_size_ptr = ffi.new("uint32_t*")
|
|
233
|
-
check_error(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
249
|
+
check_error(
|
|
250
|
+
lib.libisyntax_read_label_image_jpeg(
|
|
251
|
+
isyntax,
|
|
252
|
+
jpeg_buffer_ptr,
|
|
253
|
+
jpeg_size_ptr,
|
|
254
|
+
),
|
|
255
|
+
)
|
|
238
256
|
jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
|
|
239
257
|
jpeg_size = jpeg_size_ptr[0]
|
|
240
258
|
return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
|
|
@@ -243,11 +261,13 @@ def read_label_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
|
243
261
|
def read_macro_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
244
262
|
jpeg_buffer_ptr = ffi.new("uint8_t**")
|
|
245
263
|
jpeg_size_ptr = ffi.new("uint32_t*")
|
|
246
|
-
check_error(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
264
|
+
check_error(
|
|
265
|
+
lib.libisyntax_read_macro_image_jpeg(
|
|
266
|
+
isyntax,
|
|
267
|
+
jpeg_buffer_ptr,
|
|
268
|
+
jpeg_size_ptr,
|
|
269
|
+
),
|
|
270
|
+
)
|
|
251
271
|
jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
|
|
252
272
|
jpeg_size = jpeg_size_ptr[0]
|
|
253
273
|
return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
|
|
@@ -256,12 +276,14 @@ def read_macro_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
|
256
276
|
def read_icc_profile(isyntax: ISyntaxPtr, image: ISyntaxImagePtr) -> memoryview:
|
|
257
277
|
profile_buffer_ptr = ffi.new("uint8_t**")
|
|
258
278
|
profile_size_ptr = ffi.new("uint32_t*")
|
|
259
|
-
check_error(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
279
|
+
check_error(
|
|
280
|
+
lib.libisyntax_read_icc_profile(
|
|
281
|
+
isyntax,
|
|
282
|
+
image,
|
|
283
|
+
profile_buffer_ptr,
|
|
284
|
+
profile_size_ptr,
|
|
285
|
+
),
|
|
286
|
+
)
|
|
265
287
|
profile_buffer = ffi.gc(profile_buffer_ptr[0], free)
|
|
266
288
|
profile_size = profile_size_ptr[0]
|
|
267
289
|
return memoryview(ffi.buffer(profile_buffer, profile_size))
|
|
@@ -76,6 +76,16 @@ class ISyntaxImage:
|
|
|
76
76
|
for i in range(self.level_count):
|
|
77
77
|
yield self.get_level(i)
|
|
78
78
|
|
|
79
|
+
@property
|
|
80
|
+
def offset_x(self) -> int:
|
|
81
|
+
"""X-offset in pixels of the WSI image origin from the macro image origin."""
|
|
82
|
+
return libisyntax.image_get_offset_x(self.ptr)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def offset_y(self) -> int:
|
|
86
|
+
"""Y-offset in pixels of the WSI image origin from the macro image origin."""
|
|
87
|
+
return libisyntax.image_get_offset_y(self.ptr)
|
|
88
|
+
|
|
79
89
|
|
|
80
90
|
class ISyntax:
|
|
81
91
|
def __init__(self, f: RawIOBase | BufferedIOBase, n_bytes: int, cache_size: int = 2000) -> None:
|
|
@@ -86,7 +96,7 @@ class ISyntax:
|
|
|
86
96
|
self.ptr = libisyntax.open_from_registered_handle(self.io_handle, is_init_allocators=False)
|
|
87
97
|
self.closed = False
|
|
88
98
|
self._cache_size = cache_size
|
|
89
|
-
self._cache = None
|
|
99
|
+
self._cache: ISyntaxCache | None = None
|
|
90
100
|
|
|
91
101
|
@classmethod
|
|
92
102
|
def open(cls: type["ISyntax"], filename: str | Path, cache_size: int = 2000) -> "ISyntax":
|
|
@@ -133,8 +143,15 @@ class ISyntax:
|
|
|
133
143
|
"""
|
|
134
144
|
cache = self.get_cache()
|
|
135
145
|
buf = np.empty((self.tile_height, self.tile_width, 4), dtype=np.uint8)
|
|
136
|
-
libisyntax.tile_read(
|
|
137
|
-
|
|
146
|
+
libisyntax.tile_read(
|
|
147
|
+
self.ptr,
|
|
148
|
+
cache.ptr,
|
|
149
|
+
level,
|
|
150
|
+
tile_x,
|
|
151
|
+
tile_y,
|
|
152
|
+
buf.data,
|
|
153
|
+
libisyntax.ISyntaxPixelFormat.RGBA,
|
|
154
|
+
)
|
|
138
155
|
return buf
|
|
139
156
|
|
|
140
157
|
def read_region(self, x: int, y: int, width: int, height: int, level: int = 0) -> np.ndarray:
|
|
@@ -152,8 +169,17 @@ class ISyntax:
|
|
|
152
169
|
"""
|
|
153
170
|
cache = self.get_cache()
|
|
154
171
|
buf = np.empty((height, width, 4), dtype=np.uint8)
|
|
155
|
-
libisyntax.read_region(
|
|
156
|
-
|
|
172
|
+
libisyntax.read_region(
|
|
173
|
+
self.ptr,
|
|
174
|
+
cache.ptr,
|
|
175
|
+
level,
|
|
176
|
+
x,
|
|
177
|
+
y,
|
|
178
|
+
width,
|
|
179
|
+
height,
|
|
180
|
+
buf.data,
|
|
181
|
+
libisyntax.ISyntaxPixelFormat.RGBA,
|
|
182
|
+
)
|
|
157
183
|
return buf
|
|
158
184
|
|
|
159
185
|
def read_label_image_jpeg(self) -> memoryview | None:
|
|
@@ -224,6 +250,16 @@ class ISyntax:
|
|
|
224
250
|
level0 = self.wsi.get_level(0)
|
|
225
251
|
return level0.mpp_y
|
|
226
252
|
|
|
253
|
+
@property
|
|
254
|
+
def offset_x(self) -> int:
|
|
255
|
+
"""X-offset in pixels of the WSI image origin from the macro image origin."""
|
|
256
|
+
return self.wsi.offset_x
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def offset_y(self) -> int:
|
|
260
|
+
"""Y-offset in pixels of the WSI image origin from the macro image origin."""
|
|
261
|
+
return self.wsi.offset_y
|
|
262
|
+
|
|
227
263
|
def __enter__(self) -> "ISyntax":
|
|
228
264
|
return self
|
|
229
265
|
|
|
@@ -27,13 +27,13 @@ def create_ffibuilder() -> FFI:
|
|
|
27
27
|
|
|
28
28
|
project_dir = Path(__file__).parent.parent
|
|
29
29
|
|
|
30
|
-
vendor = project_dir/"isyntax_build"/"vendor"
|
|
31
|
-
src = project_dir/"isyntax_build"/"src"
|
|
32
|
-
libisyntax_src = vendor/"libisyntax"/"src"
|
|
30
|
+
vendor = project_dir / "isyntax_build" / "vendor"
|
|
31
|
+
src = project_dir / "isyntax_build" / "src"
|
|
32
|
+
libisyntax_src = vendor / "libisyntax" / "src"
|
|
33
33
|
|
|
34
34
|
if os.name == "nt":
|
|
35
35
|
platform_sources = [
|
|
36
|
-
src/"win32_utils.c",
|
|
36
|
+
src / "win32_utils.c",
|
|
37
37
|
]
|
|
38
38
|
extra_compile_args = ["/std:c11"]
|
|
39
39
|
libraries = ["winmm"]
|
|
@@ -46,25 +46,25 @@ def create_ffibuilder() -> FFI:
|
|
|
46
46
|
"isyntax._pyisyntax",
|
|
47
47
|
resources.read_text(isyntax_build, "pyisyntax.c"),
|
|
48
48
|
sources=paths_to_strings(
|
|
49
|
-
libisyntax_src/"libisyntax.c",
|
|
50
|
-
libisyntax_src/"isyntax"/"isyntax.c",
|
|
51
|
-
libisyntax_src/"isyntax"/"isyntax_reader.c",
|
|
52
|
-
libisyntax_src/"utils"/"timerutils.c",
|
|
53
|
-
libisyntax_src/"utils"/"block_allocator.c",
|
|
54
|
-
libisyntax_src/"utils"/"benaphore.c",
|
|
55
|
-
libisyntax_src/"platform"/"platform.c",
|
|
56
|
-
libisyntax_src/"platform"/"work_queue.c",
|
|
57
|
-
libisyntax_src/"third_party"/"yxml.c",
|
|
58
|
-
libisyntax_src/"third_party"/"ltalloc.cc",
|
|
59
|
-
src/"python_platform_utils.c",
|
|
49
|
+
libisyntax_src / "libisyntax.c",
|
|
50
|
+
libisyntax_src / "isyntax" / "isyntax.c",
|
|
51
|
+
libisyntax_src / "isyntax" / "isyntax_reader.c",
|
|
52
|
+
libisyntax_src / "utils" / "timerutils.c",
|
|
53
|
+
libisyntax_src / "utils" / "block_allocator.c",
|
|
54
|
+
libisyntax_src / "utils" / "benaphore.c",
|
|
55
|
+
libisyntax_src / "platform" / "platform.c",
|
|
56
|
+
libisyntax_src / "platform" / "work_queue.c",
|
|
57
|
+
libisyntax_src / "third_party" / "yxml.c",
|
|
58
|
+
libisyntax_src / "third_party" / "ltalloc.cc",
|
|
59
|
+
src / "python_platform_utils.c",
|
|
60
60
|
*platform_sources,
|
|
61
61
|
),
|
|
62
62
|
include_dirs=paths_to_strings(
|
|
63
63
|
libisyntax_src,
|
|
64
|
-
libisyntax_src/"isyntax",
|
|
65
|
-
libisyntax_src/"platform",
|
|
66
|
-
libisyntax_src/"third_party",
|
|
67
|
-
libisyntax_src/"utils",
|
|
64
|
+
libisyntax_src / "isyntax",
|
|
65
|
+
libisyntax_src / "platform",
|
|
66
|
+
libisyntax_src / "third_party",
|
|
67
|
+
libisyntax_src / "utils",
|
|
68
68
|
src,
|
|
69
69
|
),
|
|
70
70
|
extra_compile_args=extra_compile_args,
|
|
@@ -72,13 +72,13 @@ def create_ffibuilder() -> FFI:
|
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
header_lines = []
|
|
75
|
-
with (libisyntax_src/"libisyntax.h").open() as f:
|
|
75
|
+
with (libisyntax_src / "libisyntax.h").open() as f:
|
|
76
76
|
for line in f:
|
|
77
77
|
if line.startswith("#"):
|
|
78
78
|
continue
|
|
79
79
|
header_lines.append(line)
|
|
80
80
|
header_lines.append("\n")
|
|
81
|
-
with (src/"python_platform_utils.h").open() as f:
|
|
81
|
+
with (src / "python_platform_utils.h").open() as f:
|
|
82
82
|
for line in f:
|
|
83
83
|
if line.startswith("#"):
|
|
84
84
|
continue
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#include "libisyntax.h"
|
|
2
|
+
|
|
3
|
+
#include <stdint.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <dirent.h>
|
|
6
|
+
#include <sys/stat.h>
|
|
7
|
+
#include <sys/types.h>
|
|
8
|
+
#include <malloc.h>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
#define CHECK_LIBISYNTAX_OK(_libisyntax_call) do { \
|
|
12
|
+
isyntax_error_t result = _libisyntax_call; \
|
|
13
|
+
assert(result == LIBISYNTAX_OK); \
|
|
14
|
+
} while(0)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
#define LOG_VAR(fmt, var) printf("%s: %s=" fmt "\n", __FUNCTION__, #var, var)
|
|
18
|
+
|
|
19
|
+
#ifdef _WIN32
|
|
20
|
+
#define PATH_SEP "\\"
|
|
21
|
+
#else
|
|
22
|
+
#define PATH_SEP "/";
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
// This program loops through all the .isyntax files in a folder (including subfolders),
|
|
26
|
+
// and outputs the barcode for each file to stdout (in comma-separated format).
|
|
27
|
+
// This may be useful for large collections of WSIs where you can't tell which is which from the filename.
|
|
28
|
+
|
|
29
|
+
// NOTE: the barcode/label information must be preserved for this to work.
|
|
30
|
+
// This information might be deleted when using the Philips IMS export function (unless that setting is changed).
|
|
31
|
+
|
|
32
|
+
int read_barcode_of_isyntax_files_in_directory(const char* dir, const char* subdir_prefix) {
|
|
33
|
+
// Looping through files in a folder.
|
|
34
|
+
// Reference: https://stackoverflow.com/questions/1271064/how-do-i-loop-through-all-files-in-a-folder-using-c
|
|
35
|
+
struct dirent *dp;
|
|
36
|
+
DIR *dfd;
|
|
37
|
+
if ((dfd = opendir(dir)) == NULL) {
|
|
38
|
+
fprintf(stderr, "Can't open %s\n", dir);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
char filename[260] ;
|
|
43
|
+
while ((dp = readdir(dfd)) != NULL) {
|
|
44
|
+
struct stat stbuf ;
|
|
45
|
+
sprintf(filename, "%s" PATH_SEP "%s", dir, dp->d_name);
|
|
46
|
+
if(stat(filename, &stbuf) == -1) {
|
|
47
|
+
printf("Unable to stat file: %s\n" , filename);
|
|
48
|
+
continue ;
|
|
49
|
+
}
|
|
50
|
+
if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
|
|
51
|
+
if (dp->d_name[0] != '.') {
|
|
52
|
+
char* subdir_path = malloc(260);
|
|
53
|
+
snprintf(subdir_path, 260, "%s" PATH_SEP "%s", dir, dp->d_name);
|
|
54
|
+
read_barcode_of_isyntax_files_in_directory(subdir_path, dp->d_name); // recurse into subdirectories
|
|
55
|
+
free(subdir_path);
|
|
56
|
+
}
|
|
57
|
+
continue; // Skip directories
|
|
58
|
+
} else {
|
|
59
|
+
size_t filename_len = strlen(dp->d_name);
|
|
60
|
+
const char* suffix = ".isyntax";
|
|
61
|
+
size_t suffix_len = strlen(suffix);
|
|
62
|
+
if (strncmp(dp->d_name + filename_len - suffix_len, suffix, suffix_len) == 0) {
|
|
63
|
+
// Open the iSyntax file in a special mode where the header is only read partially (for speed).
|
|
64
|
+
isyntax_t* isyntax;
|
|
65
|
+
if (libisyntax_open(filename, LIBISYNTAX_OPEN_FLAG_READ_BARCODE_ONLY, &isyntax) == LIBISYNTAX_OK) {
|
|
66
|
+
// Print out the path of the .isyntax file + the barcode in .csv format.
|
|
67
|
+
if (subdir_prefix) {
|
|
68
|
+
printf("%s" PATH_SEP "%s,%s\n", subdir_prefix, dp->d_name, libisyntax_get_barcode(isyntax));
|
|
69
|
+
} else {
|
|
70
|
+
printf("%s,%s\n", dp->d_name, libisyntax_get_barcode(isyntax));
|
|
71
|
+
}
|
|
72
|
+
libisyntax_close(isyntax);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
int main(int argc, char** argv) {
|
|
81
|
+
if (argc <= 1) {
|
|
82
|
+
printf("Usage: %s <directory_path> - output filename and barcode (comma-separated) for each iSyntax file in the directory and its subdirectories\n",
|
|
83
|
+
argv[0], argv[0], argv[0], argv[0]);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
libisyntax_init();
|
|
88
|
+
|
|
89
|
+
char* dir = argv[1];
|
|
90
|
+
return read_barcode_of_isyntax_files_in_directory(dir, NULL);
|
|
91
|
+
}
|