pyisyntax 0.1.3__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.3 → pyisyntax-0.1.5}/CHANGELOG.md +25 -1
- {pyisyntax-0.1.3/pyisyntax.egg-info → pyisyntax-0.1.5}/PKG-INFO +15 -28
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/README.md +6 -12
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax/lowlevel/io_management.py +11 -8
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax/lowlevel/libisyntax.py +72 -46
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax/wrapper.py +45 -5
- {pyisyntax-0.1.3 → 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.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/examples/isyntax_to_tiff.c +4 -3
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.c +220 -102
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.h +16 -4
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.c +16 -8
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.h +3 -2
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.c +81 -24
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/libisyntax.c +101 -39
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/libisyntax.h +13 -2
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.cc +12 -3
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/block_allocator.c +22 -13
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/mathutils.c +5 -3
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/mathutils.h +14 -7
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/memrw.c +24 -15
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/stringutils.c +2 -2
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/timerutils.c +24 -15
- {pyisyntax-0.1.3 → pyisyntax-0.1.5/pyisyntax.egg-info}/PKG-INFO +15 -28
- {pyisyntax-0.1.3 → 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.3 → pyisyntax-0.1.5}/pyproject.toml +39 -26
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/tests/conftest.py +2 -2
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/tests/test_lowlevel.py +38 -7
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/tests/test_wrapper.py +13 -1
- pyisyntax-0.1.3/pyisyntax.egg-info/requires.txt +0 -11
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/LICENSE +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/MANIFEST.in +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax/__init__.py +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax/lowlevel/__init__.py +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/__init__.py +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/pyisyntax.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/src/python_platform_utils.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/src/python_platform_utils.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/src/win32_utils.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/LICENSE.txt +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/README.md +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/examples/isyntax_example.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_dwt.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/arena.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/common.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/intrinsics.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/linux_platform.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/linux_utils.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/platform.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/platform.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/win32_utils.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/win32_utils.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/work_queue.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/platform/work_queue.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_ds.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_image.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_image_write.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/stb_sprintf.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/yxml.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/third_party/yxml.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/benaphore.c +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/benaphore.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/block_allocator.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/libtiff_api.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/memrw.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/stringutils.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/utils/timerutils.h +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/pyisyntax.egg-info/dependency_links.txt +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/pyisyntax.egg-info/not-zip-safe +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/pyisyntax.egg-info/top_level.txt +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/setup.cfg +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/setup.py +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/tests/__init__.py +0 -0
- {pyisyntax-0.1.3 → pyisyntax-0.1.5}/tests/data/DOWNLOAD.txt +0 -0
|
@@ -7,6 +7,28 @@ 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
|
+
|
|
21
|
+
## [0.1.4] - 2024-08-31
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Support for reading the slide barcode. The barcode string can be accessed via
|
|
26
|
+
the `barcode` property of an `ISyntax` instance.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Bump the `libisyntax` submodule commit.
|
|
31
|
+
|
|
10
32
|
## [0.1.3] - 2024-03-28
|
|
11
33
|
|
|
12
34
|
### Added
|
|
@@ -50,7 +72,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
50
72
|
|
|
51
73
|
- This is the initial release.
|
|
52
74
|
|
|
53
|
-
[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
|
|
77
|
+
[0.1.4]: https://github.com/anibali/pyisyntax/compare/v0.1.3...v0.1.4
|
|
54
78
|
[0.1.3]: https://github.com/anibali/pyisyntax/compare/v0.1.2...v0.1.3
|
|
55
79
|
[0.1.2]: https://github.com/anibali/pyisyntax/compare/v0.1.1...v0.1.2
|
|
56
80
|
[0.1.1]: https://github.com/anibali/pyisyntax/compare/v0.1.0...v0.1.1
|
|
@@ -1,27 +1,20 @@
|
|
|
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
|
|
7
|
-
Project-URL:
|
|
8
|
-
Project-URL:
|
|
9
|
-
Project-URL:
|
|
10
|
-
Project-URL:
|
|
11
|
-
Project-URL:
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/anibali/pyisyntax
|
|
8
|
+
Project-URL: Source, https://github.com/anibali/pyisyntax
|
|
9
|
+
Project-URL: Download, https://pypi.org/project/pyisyntax/#files
|
|
10
|
+
Project-URL: Tracker, https://github.com/anibali/pyisyntax/issues
|
|
11
|
+
Project-URL: Release notes, https://github.com/anibali/pyisyntax/blob/master/CHANGELOG.md
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
13
|
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
|
|
|
@@ -119,6 +121,10 @@ def get_macro_image(isyntax: ISyntaxPtr) -> ISyntaxImagePtr:
|
|
|
119
121
|
return lib.libisyntax_get_macro_image(isyntax)
|
|
120
122
|
|
|
121
123
|
|
|
124
|
+
def get_barcode(isyntax: ISyntaxPtr) -> bytes:
|
|
125
|
+
return ffi.string(lib.libisyntax_get_barcode(isyntax))
|
|
126
|
+
|
|
127
|
+
|
|
122
128
|
def image_get_level_count(wsi_image: ISyntaxImagePtr) -> int:
|
|
123
129
|
return lib.libisyntax_image_get_level_count(wsi_image)
|
|
124
130
|
|
|
@@ -127,6 +133,14 @@ def image_get_level(wsi_image: ISyntaxImagePtr, index: int) -> ISyntaxLevelPtr:
|
|
|
127
133
|
return lib.libisyntax_image_get_level(wsi_image, index)
|
|
128
134
|
|
|
129
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
|
+
|
|
130
144
|
def level_get_scale(level: ISyntaxLevelPtr) -> int:
|
|
131
145
|
return lib.libisyntax_level_get_scale(level)
|
|
132
146
|
|
|
@@ -161,11 +175,13 @@ def cache_create(debug_name: str | None, cache_size: int) -> ISyntaxCachePtr:
|
|
|
161
175
|
debug_name_or_null = ffi.NULL
|
|
162
176
|
else:
|
|
163
177
|
debug_name_or_null = ffi.new("char[]", debug_name.encode("utf-8"))
|
|
164
|
-
check_error(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
178
|
+
check_error(
|
|
179
|
+
lib.libisyntax_cache_create(
|
|
180
|
+
debug_name_or_null,
|
|
181
|
+
cache_size,
|
|
182
|
+
isyntax_cache,
|
|
183
|
+
),
|
|
184
|
+
)
|
|
169
185
|
return isyntax_cache[0]
|
|
170
186
|
|
|
171
187
|
|
|
@@ -188,15 +204,17 @@ def tile_read(
|
|
|
188
204
|
pixels_buffer: "Buffer | FFI.buffer",
|
|
189
205
|
pixel_format: ISyntaxPixelFormat,
|
|
190
206
|
) -> None:
|
|
191
|
-
check_error(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
+
)
|
|
200
218
|
|
|
201
219
|
|
|
202
220
|
def read_region(
|
|
@@ -210,27 +228,31 @@ def read_region(
|
|
|
210
228
|
pixels_buffer: "Buffer | FFI.buffer",
|
|
211
229
|
pixel_format: ISyntaxPixelFormat,
|
|
212
230
|
) -> None:
|
|
213
|
-
check_error(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
+
)
|
|
224
244
|
|
|
225
245
|
|
|
226
246
|
def read_label_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
227
247
|
jpeg_buffer_ptr = ffi.new("uint8_t**")
|
|
228
248
|
jpeg_size_ptr = ffi.new("uint32_t*")
|
|
229
|
-
check_error(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
249
|
+
check_error(
|
|
250
|
+
lib.libisyntax_read_label_image_jpeg(
|
|
251
|
+
isyntax,
|
|
252
|
+
jpeg_buffer_ptr,
|
|
253
|
+
jpeg_size_ptr,
|
|
254
|
+
),
|
|
255
|
+
)
|
|
234
256
|
jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
|
|
235
257
|
jpeg_size = jpeg_size_ptr[0]
|
|
236
258
|
return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
|
|
@@ -239,11 +261,13 @@ def read_label_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
|
239
261
|
def read_macro_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
240
262
|
jpeg_buffer_ptr = ffi.new("uint8_t**")
|
|
241
263
|
jpeg_size_ptr = ffi.new("uint32_t*")
|
|
242
|
-
check_error(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
check_error(
|
|
265
|
+
lib.libisyntax_read_macro_image_jpeg(
|
|
266
|
+
isyntax,
|
|
267
|
+
jpeg_buffer_ptr,
|
|
268
|
+
jpeg_size_ptr,
|
|
269
|
+
),
|
|
270
|
+
)
|
|
247
271
|
jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
|
|
248
272
|
jpeg_size = jpeg_size_ptr[0]
|
|
249
273
|
return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
|
|
@@ -252,12 +276,14 @@ def read_macro_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
|
|
|
252
276
|
def read_icc_profile(isyntax: ISyntaxPtr, image: ISyntaxImagePtr) -> memoryview:
|
|
253
277
|
profile_buffer_ptr = ffi.new("uint8_t**")
|
|
254
278
|
profile_size_ptr = ffi.new("uint32_t*")
|
|
255
|
-
check_error(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
279
|
+
check_error(
|
|
280
|
+
lib.libisyntax_read_icc_profile(
|
|
281
|
+
isyntax,
|
|
282
|
+
image,
|
|
283
|
+
profile_buffer_ptr,
|
|
284
|
+
profile_size_ptr,
|
|
285
|
+
),
|
|
286
|
+
)
|
|
261
287
|
profile_buffer = ffi.gc(profile_buffer_ptr[0], free)
|
|
262
288
|
profile_size = profile_size_ptr[0]
|
|
263
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:
|
|
@@ -178,6 +204,10 @@ class ISyntax:
|
|
|
178
204
|
except libisyntax.LibISyntaxFatalError:
|
|
179
205
|
return None
|
|
180
206
|
|
|
207
|
+
@property
|
|
208
|
+
def barcode(self) -> str:
|
|
209
|
+
return libisyntax.get_barcode(self.ptr).decode("ascii")
|
|
210
|
+
|
|
181
211
|
def read_icc_profile(self) -> memoryview | None:
|
|
182
212
|
"""Reads the ICC color profile for an image.
|
|
183
213
|
|
|
@@ -220,6 +250,16 @@ class ISyntax:
|
|
|
220
250
|
level0 = self.wsi.get_level(0)
|
|
221
251
|
return level0.mpp_y
|
|
222
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
|
+
|
|
223
263
|
def __enter__(self) -> "ISyntax":
|
|
224
264
|
return self
|
|
225
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
|
+
}
|
{pyisyntax-0.1.3 → pyisyntax-0.1.5}/isyntax_build/vendor/libisyntax/src/examples/isyntax_to_tiff.c
RENAMED
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
#endif
|
|
38
38
|
|
|
39
39
|
#include <stdint.h>
|
|
40
|
+
#include <inttypes.h>
|
|
40
41
|
#include <assert.h>
|
|
41
42
|
#include <stdlib.h>
|
|
42
43
|
#include <string.h>
|
|
@@ -221,7 +222,7 @@ uint64_t parse_cache_size(const char *size_str) {
|
|
|
221
222
|
uint64_t size;
|
|
222
223
|
char unit;
|
|
223
224
|
|
|
224
|
-
if (sscanf(size_str, "%
|
|
225
|
+
if (sscanf(size_str, "%"PRIu64"%c", &size, &unit) == 2) {
|
|
225
226
|
if (unit == 'M') {
|
|
226
227
|
if (size > INT64_MAX / (1024)) {
|
|
227
228
|
printf("Error: Cache size too large.\n");
|
|
@@ -238,7 +239,7 @@ uint64_t parse_cache_size(const char *size_str) {
|
|
|
238
239
|
printf("Error: Invalid unit for cache size. Use 'M' for megabytes or 'G' for gigabytes.\n");
|
|
239
240
|
return -1;
|
|
240
241
|
}
|
|
241
|
-
} else if (sscanf(size_str, "%
|
|
242
|
+
} else if (sscanf(size_str, "%"PRIu64, &size) != 1) {
|
|
242
243
|
printf("Error: Invalid cache size format.\n");
|
|
243
244
|
return -1;
|
|
244
245
|
}
|
|
@@ -426,7 +427,7 @@ int main(int argc, char **argv) {
|
|
|
426
427
|
|
|
427
428
|
isyntax_cache_t *isyntax_cache = NULL;
|
|
428
429
|
if (libisyntax_cache_create("isyntax-to-tiff cache", cache_size, &isyntax_cache) != LIBISYNTAX_OK) {
|
|
429
|
-
fprintf(stderr, "Failed to create iSyntax cache with size %
|
|
430
|
+
fprintf(stderr, "Failed to create iSyntax cache with size %"PRIu64".\n", cache_size);
|
|
430
431
|
libisyntax_close(isyntax);
|
|
431
432
|
return -1;
|
|
432
433
|
}
|