pyisyntax 0.1.0__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.
Files changed (74) hide show
  1. pyisyntax-0.1.0/LICENSE +20 -0
  2. pyisyntax-0.1.0/MANIFEST.in +14 -0
  3. pyisyntax-0.1.0/PKG-INFO +81 -0
  4. pyisyntax-0.1.0/README.md +63 -0
  5. pyisyntax-0.1.0/isyntax/__init__.py +5 -0
  6. pyisyntax-0.1.0/isyntax/lowlevel/__init__.py +0 -0
  7. pyisyntax-0.1.0/isyntax/lowlevel/io_management.py +115 -0
  8. pyisyntax-0.1.0/isyntax/lowlevel/libisyntax.py +260 -0
  9. pyisyntax-0.1.0/isyntax/wrapper.py +228 -0
  10. pyisyntax-0.1.0/isyntax_build/__init__.py +0 -0
  11. pyisyntax-0.1.0/isyntax_build/builder.py +98 -0
  12. pyisyntax-0.1.0/isyntax_build/pyisyntax.c +2 -0
  13. pyisyntax-0.1.0/isyntax_build/src/python_platform_utils.c +83 -0
  14. pyisyntax-0.1.0/isyntax_build/src/python_platform_utils.h +12 -0
  15. pyisyntax-0.1.0/isyntax_build/src/win32_utils.c +57 -0
  16. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/LICENSE.txt +24 -0
  17. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/README.md +3 -0
  18. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/examples/isyntax_example.c +118 -0
  19. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/examples/isyntax_to_tiff.c +490 -0
  20. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.c +3430 -0
  21. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax.h +416 -0
  22. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_dwt.c +594 -0
  23. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.c +418 -0
  24. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_reader.h +30 -0
  25. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.c +1097 -0
  26. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/isyntax/isyntax_streamer.h +90 -0
  27. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/libisyntax.c +494 -0
  28. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/libisyntax.h +93 -0
  29. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/arena.h +92 -0
  30. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/common.h +379 -0
  31. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/intrinsics.h +262 -0
  32. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/linux_platform.c +52 -0
  33. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/linux_utils.c +106 -0
  34. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/platform.c +142 -0
  35. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/platform.h +188 -0
  36. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/win32_utils.c +264 -0
  37. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/win32_utils.h +49 -0
  38. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/work_queue.c +238 -0
  39. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/platform/work_queue.h +102 -0
  40. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.cc +1342 -0
  41. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/ltalloc.h +17 -0
  42. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/stb_ds.h +1895 -0
  43. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/stb_image.h +7987 -0
  44. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/stb_image_write.h +1724 -0
  45. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/stb_sprintf.h +1906 -0
  46. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/yxml.c +1060 -0
  47. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/third_party/yxml.h +162 -0
  48. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/benaphore.c +76 -0
  49. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/benaphore.h +60 -0
  50. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/block_allocator.c +133 -0
  51. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/block_allocator.h +88 -0
  52. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/libtiff_api.h +202 -0
  53. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/mathutils.c +328 -0
  54. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/mathutils.h +182 -0
  55. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/memrw.c +135 -0
  56. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/memrw.h +62 -0
  57. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/stringutils.c +163 -0
  58. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/stringutils.h +48 -0
  59. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/timerutils.c +99 -0
  60. pyisyntax-0.1.0/isyntax_build/vendor/libisyntax/src/utils/timerutils.h +48 -0
  61. pyisyntax-0.1.0/pyisyntax.egg-info/PKG-INFO +81 -0
  62. pyisyntax-0.1.0/pyisyntax.egg-info/SOURCES.txt +72 -0
  63. pyisyntax-0.1.0/pyisyntax.egg-info/dependency_links.txt +1 -0
  64. pyisyntax-0.1.0/pyisyntax.egg-info/not-zip-safe +1 -0
  65. pyisyntax-0.1.0/pyisyntax.egg-info/requires.txt +9 -0
  66. pyisyntax-0.1.0/pyisyntax.egg-info/top_level.txt +2 -0
  67. pyisyntax-0.1.0/pyproject.toml +65 -0
  68. pyisyntax-0.1.0/setup.cfg +4 -0
  69. pyisyntax-0.1.0/setup.py +13 -0
  70. pyisyntax-0.1.0/tests/__init__.py +0 -0
  71. pyisyntax-0.1.0/tests/conftest.py +16 -0
  72. pyisyntax-0.1.0/tests/data/DOWNLOAD.txt +1 -0
  73. pyisyntax-0.1.0/tests/test_lowlevel.py +189 -0
  74. pyisyntax-0.1.0/tests/test_wrapper.py +113 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2024 Aiden Nibali
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ include README.md
2
+ include LICENSE
3
+
4
+ graft isyntax_build
5
+ prune isyntax_build/vendor/libisyntax
6
+ graft isyntax_build/vendor/libisyntax/src
7
+ include isyntax_build/vendor/libisyntax/LICENSE.txt
8
+ include isyntax_build/vendor/libisyntax/README.md
9
+
10
+ graft tests
11
+ recursive-exclude tests *.isyntax
12
+
13
+ prune */.pytest_cache
14
+ prune */__pycache__
@@ -0,0 +1,81 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyisyntax
3
+ Version: 0.1.0
4
+ Summary: Python bindings for libisyntax
5
+ Author-email: Aiden Nibali <dismaldenizen@gmail.com>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: cffi>=1.12
11
+ Requires-Dist: numpy
12
+ Provides-Extra: dev
13
+ Requires-Dist: conda-lock; extra == "dev"
14
+ Requires-Dist: pytest; extra == "dev"
15
+ Requires-Dist: pytest-mock; extra == "dev"
16
+ Requires-Dist: ruff==0.2.1; extra == "dev"
17
+ Requires-Dist: twine; extra == "dev"
18
+
19
+ # pyisyntax
20
+
21
+ A Python library for working with pathology images in the iSyntax file format,
22
+ powered by [libisyntax](https://github.com/amspath/libisyntax).
23
+
24
+ ## Usage
25
+
26
+ Read and display a region of the WSI via
27
+ [Pillow](https://pillow.readthedocs.io/).
28
+
29
+ ```python
30
+ from isyntax import ISyntax
31
+ import PIL.Image
32
+
33
+ with ISyntax.open("my_file.isyntax") as isyntax:
34
+ # Read pixels from the specified region into a numpy array
35
+ pixels = isyntax.read_region(500, 500, 400, 200, level=4)
36
+ # Convert numpy array into a PIL image
37
+ pil_image = PIL.Image.fromarray(pixels)
38
+ # Show the image
39
+ pil_image.show()
40
+ ```
41
+
42
+ Extract and save the associated macro image.
43
+
44
+ ```python
45
+ from isyntax import ISyntax
46
+
47
+ with ISyntax.open("my_file.isyntax") as isyntax:
48
+ # The macro image will be returned as compressed JPEG data.
49
+ jpeg_data = isyntax.read_macro_image_jpeg()
50
+ # This JPEG data can be written directly to a file.
51
+ with open("macro_image.jpg", "wb") as f:
52
+ f.write(jpeg_data)
53
+ # Alternatively, you could decompress the data using Pillow:
54
+ # pil_image = PIL.Image.open(io.BytesIO(jpeg_data), formats=["JPEG"])
55
+ ```
56
+
57
+ ## Development
58
+
59
+ ### Dependency management
60
+
61
+ To set up a development environment from the lock file:
62
+
63
+ 1. Ensure that you have
64
+ [micromamba](https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html)
65
+ installed.
66
+ 2. Create the environment:
67
+ ```console
68
+ $ micromamba create -n pyisyntax -f conda-lock.yml --category main --category dev
69
+ ```
70
+ 3. Activate the environment:
71
+ ```console
72
+ $ micromamba activate pyisyntax
73
+ ```
74
+
75
+ To modify pyisyntax project dependencies:
76
+
77
+ 1. Edit pyproject.toml.
78
+ 2. Update the lock file using conda-lock:
79
+ ```console
80
+ $ conda-lock lock -f pyproject.toml -p linux-64 --micromamba
81
+ ```
@@ -0,0 +1,63 @@
1
+ # pyisyntax
2
+
3
+ A Python library for working with pathology images in the iSyntax file format,
4
+ powered by [libisyntax](https://github.com/amspath/libisyntax).
5
+
6
+ ## Usage
7
+
8
+ Read and display a region of the WSI via
9
+ [Pillow](https://pillow.readthedocs.io/).
10
+
11
+ ```python
12
+ from isyntax import ISyntax
13
+ import PIL.Image
14
+
15
+ with ISyntax.open("my_file.isyntax") as isyntax:
16
+ # Read pixels from the specified region into a numpy array
17
+ pixels = isyntax.read_region(500, 500, 400, 200, level=4)
18
+ # Convert numpy array into a PIL image
19
+ pil_image = PIL.Image.fromarray(pixels)
20
+ # Show the image
21
+ pil_image.show()
22
+ ```
23
+
24
+ Extract and save the associated macro image.
25
+
26
+ ```python
27
+ from isyntax import ISyntax
28
+
29
+ with ISyntax.open("my_file.isyntax") as isyntax:
30
+ # The macro image will be returned as compressed JPEG data.
31
+ jpeg_data = isyntax.read_macro_image_jpeg()
32
+ # This JPEG data can be written directly to a file.
33
+ with open("macro_image.jpg", "wb") as f:
34
+ f.write(jpeg_data)
35
+ # Alternatively, you could decompress the data using Pillow:
36
+ # pil_image = PIL.Image.open(io.BytesIO(jpeg_data), formats=["JPEG"])
37
+ ```
38
+
39
+ ## Development
40
+
41
+ ### Dependency management
42
+
43
+ To set up a development environment from the lock file:
44
+
45
+ 1. Ensure that you have
46
+ [micromamba](https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html)
47
+ installed.
48
+ 2. Create the environment:
49
+ ```console
50
+ $ micromamba create -n pyisyntax -f conda-lock.yml --category main --category dev
51
+ ```
52
+ 3. Activate the environment:
53
+ ```console
54
+ $ micromamba activate pyisyntax
55
+ ```
56
+
57
+ To modify pyisyntax project dependencies:
58
+
59
+ 1. Edit pyproject.toml.
60
+ 2. Update the lock file using conda-lock:
61
+ ```console
62
+ $ conda-lock lock -f pyproject.toml -p linux-64 --micromamba
63
+ ```
@@ -0,0 +1,5 @@
1
+ from isyntax.wrapper import ISyntax
2
+
3
+ __all__ = [
4
+ "ISyntax",
5
+ ]
File without changes
@@ -0,0 +1,115 @@
1
+ from collections.abc import Iterator
2
+ from dataclasses import dataclass
3
+ from io import BufferedIOBase, RawIOBase
4
+ from typing import Generic, NewType, TypeVar
5
+
6
+ from _pyisyntax import ffi, lib
7
+
8
+ VoidPtr = NewType("VoidPtr", object)
9
+ T = TypeVar("T")
10
+
11
+
12
+ @dataclass
13
+ class SizedIO:
14
+ #: The IO object.
15
+ f: RawIOBase | BufferedIOBase
16
+ #: The complete length of the IO object's data (in bytes).
17
+ n_bytes: int
18
+
19
+
20
+ class ByHandleRegistry(Generic[T]):
21
+ class _EmptySlot:
22
+ pass
23
+
24
+ def __init__(self) -> None:
25
+ """Creates a registry of objects keyed by integer handles.
26
+
27
+ Handles start at 1, autoincrement, and will automatically be recycled
28
+ once objects are removed from the registry.
29
+ """
30
+ self._list = []
31
+ self._n_free = 0
32
+ self._empty_slot = self._EmptySlot()
33
+
34
+ def pop(self, handle: int) -> T:
35
+ element = self._list[handle - 1]
36
+ self._list[handle - 1] = self._empty_slot
37
+ self._n_free += 1
38
+ if len(self._list) == handle:
39
+ while len(self._list) > 0 and self._list[-1] is self._empty_slot:
40
+ self._list.pop()
41
+ self._n_free -= 1
42
+ return element
43
+
44
+ def add(self, element: T) -> int:
45
+ if self._n_free == 0:
46
+ self._list.append(element)
47
+ return len(self._list)
48
+ index = self._list.index(self._empty_slot)
49
+ self._list[index] = element
50
+ self._n_free -= 1
51
+ # Handles start at 1.
52
+ return index + 1
53
+
54
+ def __getitem__(self, handle: int) -> T:
55
+ return self._list[handle - 1]
56
+
57
+ def items(self) -> Iterator[tuple[int, T]]:
58
+ for i, element in enumerate(self._list):
59
+ if element is not self._empty_slot:
60
+ yield i + 1, element
61
+
62
+
63
+ _io_registry = ByHandleRegistry[SizedIO]()
64
+
65
+
66
+ def init_python_io_hooks() -> None:
67
+ @ffi.def_extern()
68
+ def python_file_set_pos(handle: int, offset: int) -> bool:
69
+ _io_registry[handle].f.seek(offset)
70
+ return True
71
+
72
+
73
+ @ffi.def_extern()
74
+ def python_file_read_into(handle: int, dest: VoidPtr, bytes_to_read: int) -> int:
75
+ bytes_read = _io_registry[handle].f.readinto(ffi.buffer(dest, bytes_to_read))
76
+ if bytes_read is None:
77
+ raise RuntimeError
78
+ return max(bytes_read, 1)
79
+
80
+
81
+ @ffi.def_extern()
82
+ def python_file_get_size(handle: int) -> int:
83
+ return _io_registry[handle].n_bytes
84
+
85
+
86
+ @ffi.def_extern()
87
+ def python_file_close(handle: int) -> None:
88
+ _io_registry.pop(handle).f.close()
89
+
90
+
91
+ lib.init_python_platform_utils(
92
+ lib.python_file_set_pos,
93
+ lib.python_file_read_into,
94
+ lib.python_file_get_size,
95
+ lib.python_file_close,
96
+ )
97
+
98
+
99
+ def register_io(f: RawIOBase | BufferedIOBase, n_bytes: int) -> int:
100
+ """Registers a Python IO object for use with the underlying C library.
101
+
102
+ Args:
103
+ f: IO object to register.
104
+ n_bytes: Size of the IO object's data (in bytes).
105
+
106
+ Raises:
107
+ RuntimeError: When the IO object is not readable.
108
+
109
+ Returns:
110
+ New handle assigned to the IO object.
111
+ """
112
+ if not f.readable:
113
+ msg = "IO object must be readable"
114
+ raise RuntimeError(msg)
115
+ return _io_registry.add(SizedIO(f, n_bytes))
@@ -0,0 +1,260 @@
1
+ import os
2
+ from enum import IntEnum
3
+ from pathlib import Path
4
+ from typing import TYPE_CHECKING, NewType
5
+
6
+ from _pyisyntax import ffi, lib
7
+
8
+ from isyntax.lowlevel.io_management import init_python_io_hooks, register_io
9
+
10
+ if TYPE_CHECKING:
11
+ from cffi import FFI
12
+ from typing_extensions import Buffer
13
+
14
+
15
+ Pointer = NewType("Pointer", "FFI.CData")
16
+ ISyntaxPtr = NewType("ISyntaxPtr", Pointer)
17
+ ISyntaxImagePtr = NewType("ISyntaxImagePtr", Pointer)
18
+ ISyntaxLevelPtr = NewType("ISyntaxLevelPtr", Pointer)
19
+ ISyntaxCachePtr = NewType("ISyntaxCachePtr", Pointer)
20
+
21
+
22
+ LIBISYNTAX_OK = 0
23
+ # Generic error that the user should not expect to recover from.
24
+ LIBISYNTAX_FATAL = 1
25
+ # One of the arguments passed to a function is invalid.
26
+ LIBISYNTAX_INVALID_ARGUMENT = 2
27
+
28
+
29
+ class ISyntaxPixelFormat(IntEnum):
30
+ RGBA = lib.LIBISYNTAX_PIXEL_FORMAT_RGBA
31
+ BGRA = lib.LIBISYNTAX_PIXEL_FORMAT_BGRA
32
+
33
+
34
+ class LibISyntaxError(Exception):
35
+ pass
36
+
37
+
38
+ class LibISyntaxFatalError(LibISyntaxError):
39
+ pass
40
+
41
+
42
+ class LibISyntaxInvalidArgumentError(LibISyntaxError):
43
+ pass
44
+
45
+
46
+ class LibISyntaxUnknownError(LibISyntaxError):
47
+ pass
48
+
49
+
50
+ class NullPointerError(Exception):
51
+ pass
52
+
53
+
54
+ def check_error(status: int) -> None:
55
+ if status == LIBISYNTAX_OK:
56
+ return
57
+ if status == LIBISYNTAX_FATAL:
58
+ raise LibISyntaxFatalError
59
+ if status == LIBISYNTAX_INVALID_ARGUMENT:
60
+ raise LibISyntaxInvalidArgumentError
61
+ raise LibISyntaxUnknownError
62
+
63
+
64
+ def free(ptr: Pointer) -> None:
65
+ lib.free(ptr)
66
+
67
+
68
+ def _do_init() -> None:
69
+ check_error(lib.libisyntax_init())
70
+ init_python_io_hooks()
71
+
72
+
73
+ def init() -> None:
74
+ ffi.init_once(_do_init, "libisyntax_init")
75
+
76
+
77
+ def open_from_registered_handle(handle: int, *, is_init_allocators: bool = False) -> ISyntaxPtr:
78
+ init()
79
+
80
+ isyntax = ffi.new("isyntax_t**")
81
+ check_error(lib.libisyntax_open(
82
+ ffi.new("char[]", str(handle).encode("utf-8")),
83
+ is_init_allocators,
84
+ isyntax,
85
+ ))
86
+ return isyntax[0]
87
+
88
+
89
+ def open_from_filename(filename: str | Path, *, is_init_allocators: bool = False) -> ISyntaxPtr:
90
+ filename = Path(filename)
91
+ f = filename.open("rb")
92
+ handle = register_io(f, os.fstat(f.fileno()).st_size)
93
+ return open_from_registered_handle(handle, is_init_allocators=is_init_allocators)
94
+
95
+
96
+ def close(isyntax: ISyntaxPtr) -> None:
97
+ # If a null pointer gets through the program will segfault.
98
+ if isyntax == ffi.NULL:
99
+ raise NullPointerError
100
+ lib.libisyntax_close(isyntax)
101
+
102
+
103
+ def get_tile_width(isyntax: ISyntaxPtr) -> int:
104
+ return lib.libisyntax_get_tile_width(isyntax)
105
+
106
+
107
+ def get_tile_height(isyntax: ISyntaxPtr) -> int:
108
+ return lib.libisyntax_get_tile_height(isyntax)
109
+
110
+
111
+ def get_wsi_image_index(isyntax: ISyntaxPtr) -> int:
112
+ return lib.libisyntax_get_wsi_image_index(isyntax)
113
+
114
+
115
+ def get_image(isyntax: ISyntaxPtr, wsi_image_index: int) -> ISyntaxImagePtr:
116
+ return lib.libisyntax_get_image(isyntax, wsi_image_index)
117
+
118
+
119
+ def image_get_level_count(wsi_image: ISyntaxImagePtr) -> int:
120
+ return lib.libisyntax_image_get_level_count(wsi_image)
121
+
122
+
123
+ def image_get_level(wsi_image: ISyntaxImagePtr, index: int) -> ISyntaxLevelPtr:
124
+ return lib.libisyntax_image_get_level(wsi_image, index)
125
+
126
+
127
+ def level_get_scale(level: ISyntaxLevelPtr) -> int:
128
+ return lib.libisyntax_level_get_scale(level)
129
+
130
+
131
+ def level_get_width_in_tiles(level: ISyntaxLevelPtr) -> int:
132
+ return lib.libisyntax_level_get_width_in_tiles(level)
133
+
134
+
135
+ def level_get_height_in_tiles(level: ISyntaxLevelPtr) -> int:
136
+ return lib.libisyntax_level_get_height_in_tiles(level)
137
+
138
+
139
+ def level_get_width(level: ISyntaxLevelPtr) -> int:
140
+ return lib.libisyntax_level_get_width(level)
141
+
142
+
143
+ def level_get_height(level: ISyntaxLevelPtr) -> int:
144
+ return lib.libisyntax_level_get_height(level)
145
+
146
+
147
+ def level_get_mpp_x(level: ISyntaxLevelPtr) -> float:
148
+ return lib.libisyntax_level_get_mpp_x(level)
149
+
150
+
151
+ def level_get_mpp_y(level: ISyntaxLevelPtr) -> float:
152
+ return lib.libisyntax_level_get_mpp_y(level)
153
+
154
+
155
+ def cache_create(debug_name: str | None, cache_size: int) -> ISyntaxCachePtr:
156
+ isyntax_cache = ffi.new("isyntax_cache_t**")
157
+ if debug_name is None:
158
+ debug_name_or_null = ffi.NULL
159
+ else:
160
+ debug_name_or_null = ffi.new("char[]", debug_name.encode("utf-8"))
161
+ check_error(lib.libisyntax_cache_create(
162
+ debug_name_or_null,
163
+ cache_size,
164
+ isyntax_cache,
165
+ ))
166
+ return isyntax_cache[0]
167
+
168
+
169
+ def cache_inject(isyntax_cache: ISyntaxCachePtr, isyntax: ISyntaxPtr) -> None:
170
+ check_error(lib.libisyntax_cache_inject(isyntax_cache, isyntax))
171
+
172
+
173
+ def cache_destroy(isyntax_cache: ISyntaxCachePtr) -> None:
174
+ if isyntax_cache == ffi.NULL:
175
+ raise NullPointerError
176
+ lib.libisyntax_cache_destroy(isyntax_cache)
177
+
178
+
179
+ def tile_read(
180
+ isyntax: ISyntaxPtr,
181
+ isyntax_cache: ISyntaxCachePtr,
182
+ level: int,
183
+ tile_x: int,
184
+ tile_y: int,
185
+ pixels_buffer: "Buffer | FFI.buffer",
186
+ pixel_format: ISyntaxPixelFormat,
187
+ ) -> None:
188
+ check_error(lib.libisyntax_tile_read(
189
+ isyntax,
190
+ isyntax_cache,
191
+ level,
192
+ tile_x,
193
+ tile_y,
194
+ ffi.from_buffer("uint32_t[]", pixels_buffer, require_writable=True),
195
+ pixel_format,
196
+ ))
197
+
198
+
199
+ def read_region(
200
+ isyntax: ISyntaxPtr,
201
+ isyntax_cache: ISyntaxCachePtr,
202
+ level: int,
203
+ x: int,
204
+ y: int,
205
+ width: int,
206
+ height: int,
207
+ pixels_buffer: "Buffer | FFI.buffer",
208
+ pixel_format: ISyntaxPixelFormat,
209
+ ) -> None:
210
+ check_error(lib.libisyntax_read_region(
211
+ isyntax,
212
+ isyntax_cache,
213
+ level,
214
+ x,
215
+ y,
216
+ width,
217
+ height,
218
+ ffi.from_buffer("uint32_t[]", pixels_buffer, require_writable=True),
219
+ pixel_format,
220
+ ))
221
+
222
+
223
+ def read_label_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
224
+ jpeg_buffer_ptr = ffi.new("uint8_t**")
225
+ jpeg_size_ptr = ffi.new("uint32_t*")
226
+ check_error(lib.libisyntax_read_label_image_jpeg(
227
+ isyntax,
228
+ jpeg_buffer_ptr,
229
+ jpeg_size_ptr,
230
+ ))
231
+ jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
232
+ jpeg_size = jpeg_size_ptr[0]
233
+ return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
234
+
235
+
236
+ def read_macro_image_jpeg(isyntax: ISyntaxPtr) -> memoryview:
237
+ jpeg_buffer_ptr = ffi.new("uint8_t**")
238
+ jpeg_size_ptr = ffi.new("uint32_t*")
239
+ check_error(lib.libisyntax_read_macro_image_jpeg(
240
+ isyntax,
241
+ jpeg_buffer_ptr,
242
+ jpeg_size_ptr,
243
+ ))
244
+ jpeg_buffer = ffi.gc(jpeg_buffer_ptr[0], free)
245
+ jpeg_size = jpeg_size_ptr[0]
246
+ return memoryview(ffi.buffer(jpeg_buffer, jpeg_size))
247
+
248
+
249
+ def read_icc_profile(isyntax: ISyntaxPtr, image: ISyntaxImagePtr) -> memoryview:
250
+ profile_buffer_ptr = ffi.new("uint8_t**")
251
+ profile_size_ptr = ffi.new("uint32_t*")
252
+ check_error(lib.libisyntax_read_icc_profile(
253
+ isyntax,
254
+ image,
255
+ profile_buffer_ptr,
256
+ profile_size_ptr,
257
+ ))
258
+ profile_buffer = ffi.gc(profile_buffer_ptr[0], free)
259
+ profile_size = profile_size_ptr[0]
260
+ return memoryview(ffi.buffer(profile_buffer, profile_size))