fixr 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.
- fixr-0.1.0/LICENSE +21 -0
- fixr-0.1.0/MANIFEST.in +3 -0
- fixr-0.1.0/PKG-INFO +20 -0
- fixr-0.1.0/README.md +12 -0
- fixr-0.1.0/pyproject.toml +22 -0
- fixr-0.1.0/setup.cfg +4 -0
- fixr-0.1.0/setup.py +25 -0
- fixr-0.1.0/src/fixr/__init__.py +165 -0
- fixr-0.1.0/src/fixr.egg-info/PKG-INFO +20 -0
- fixr-0.1.0/src/fixr.egg-info/SOURCES.txt +10 -0
- fixr-0.1.0/src/fixr.egg-info/dependency_links.txt +1 -0
- fixr-0.1.0/src/fixr.egg-info/top_level.txt +1 -0
fixr-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Joseph D. Long
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fixr-0.1.0/MANIFEST.in
ADDED
fixr-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fixr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings to xrif, the extreme reordered image format
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
|
|
9
|
+
# fiXr
|
|
10
|
+
|
|
11
|
+
Open xrif archives from Python directly using the [xrif](https://github.com/jaredmales/xrif) library.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from fixr import xrif2numpy
|
|
17
|
+
fh = open('camwfs_20240315225750994842000.xrif', 'rb')
|
|
18
|
+
data = xrif2numpy(fh)
|
|
19
|
+
timings = xrif2numpy(fh)
|
|
20
|
+
```
|
fixr-0.1.0/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# fiXr
|
|
2
|
+
|
|
3
|
+
Open xrif archives from Python directly using the [xrif](https://github.com/jaredmales/xrif) library.
|
|
4
|
+
|
|
5
|
+
## Example
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from fixr import xrif2numpy
|
|
9
|
+
fh = open('camwfs_20240315225750994842000.xrif', 'rb')
|
|
10
|
+
data = xrif2numpy(fh)
|
|
11
|
+
timings = xrif2numpy(fh)
|
|
12
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# pyproject.toml
|
|
2
|
+
[build-system]
|
|
3
|
+
requires = ["setuptools"]
|
|
4
|
+
build-backend = "setuptools.build_meta"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "fixr"
|
|
8
|
+
description = "Python bindings to xrif, the extreme reordered image format"
|
|
9
|
+
version = "0.1.0"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
|
|
13
|
+
[tool.setuptools.packages.find]
|
|
14
|
+
where = ["src"]
|
|
15
|
+
|
|
16
|
+
[tool.cibuildwheel]
|
|
17
|
+
before-build = "bash build_xrif_and_generate_bindings.sh"
|
|
18
|
+
manylinux-x86_64-image = "quay.io/pypa/manylinux_2_28_x86_64"
|
|
19
|
+
manylinux-aarch64-image = "quay.io/pypa/manylinux_2_28_aarch64"
|
|
20
|
+
|
|
21
|
+
# skip pypi, 32bit windows, 32bit linux
|
|
22
|
+
skip = ["pp*", "*-win32", "*-manylinux_i686", "*-musllinux*"]
|
fixr-0.1.0/setup.cfg
ADDED
fixr-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from setuptools import setup, Extension
|
|
2
|
+
from setuptools.dist import Distribution
|
|
3
|
+
|
|
4
|
+
class BinaryDistribution(Distribution):
|
|
5
|
+
"""Distribution which always forces a binary package with platform name"""
|
|
6
|
+
def has_ext_modules(foo):
|
|
7
|
+
return True
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
if sys.platform == 'darwin':
|
|
12
|
+
lib_extension = 'dylib'
|
|
13
|
+
else:
|
|
14
|
+
lib_extension = 'so'
|
|
15
|
+
|
|
16
|
+
setup(
|
|
17
|
+
ext_modules=[
|
|
18
|
+
Extension(
|
|
19
|
+
name="fixr._xrif",
|
|
20
|
+
sources=[], # empty list because we compile this separately
|
|
21
|
+
),
|
|
22
|
+
],
|
|
23
|
+
package_data={"fixr": [f"libxrif.{lib_extension}"]},
|
|
24
|
+
distclass=BinaryDistribution,
|
|
25
|
+
)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
import ctypes
|
|
3
|
+
import numpy as np
|
|
4
|
+
from . import _xrif as xrif
|
|
5
|
+
import io
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
XRIF2NUMPY_DTYPE = {
|
|
9
|
+
xrif.XRIF_TYPECODE_UINT8: np.uint8,
|
|
10
|
+
xrif.XRIF_TYPECODE_INT8: np.int8,
|
|
11
|
+
xrif.XRIF_TYPECODE_UINT16: np.uint16,
|
|
12
|
+
xrif.XRIF_TYPECODE_INT16: np.int16,
|
|
13
|
+
xrif.XRIF_TYPECODE_UINT32: np.uint32,
|
|
14
|
+
xrif.XRIF_TYPECODE_INT32: np.int32,
|
|
15
|
+
xrif.XRIF_TYPECODE_UINT64: np.uint64,
|
|
16
|
+
xrif.XRIF_TYPECODE_INT64: np.int64,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class XrifReader:
|
|
20
|
+
def __init__(self, fh):
|
|
21
|
+
if 'b' not in fh.mode:
|
|
22
|
+
raise RuntimeError("File handle must be opened in binary mode")
|
|
23
|
+
self.fh = fh
|
|
24
|
+
# allocate and initialize xrif handle
|
|
25
|
+
self._reader = xrif.xrif_t()
|
|
26
|
+
xrif.xrif_new(self._reader)
|
|
27
|
+
self._decode_from_fh()
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def difference_method(self):
|
|
31
|
+
return xrif.string_cast((xrif.xrif_difference_method_string(self._reader.contents.difference_method)))
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def reorder_method(self):
|
|
35
|
+
return xrif.string_cast(xrif.xrif_reorder_method_string(self._reader.contents.reorder_method))
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def compress_method(self):
|
|
39
|
+
return xrif.string_cast(xrif.xrif_compress_method_string(self._reader.contents.compress_method))
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def lz4_acceleration(self):
|
|
43
|
+
return int(self._reader.contents.lz4_acceleration)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def width(self):
|
|
47
|
+
return int(self._reader.contents.width)
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def height(self):
|
|
51
|
+
return int(self._reader.contents.height)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def depth(self):
|
|
55
|
+
return int(self._reader.contents.depth)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def frames(self):
|
|
59
|
+
return int(self._reader.contents.frames)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def raw_size(self):
|
|
63
|
+
return self._reader.contents.width * self._reader.contents.height * self._reader.contents.depth * self._reader.contents.frames * self._reader.contents.data_size
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def shape(self):
|
|
67
|
+
return (
|
|
68
|
+
self._reader.contents.frames,
|
|
69
|
+
self._reader.contents.depth,
|
|
70
|
+
self._reader.contents.height,
|
|
71
|
+
self._reader.contents.width,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def compressed_size(self):
|
|
76
|
+
return int(self._reader.contents.compressed_size)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def ratio(self):
|
|
80
|
+
return self.compressed_size / self.raw_size
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def min_raw_size(self):
|
|
84
|
+
return xrif.xrif_min_raw_size(self._reader)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def min_reordered_size(self):
|
|
88
|
+
return xrif.xrif_min_reordered_size(self._reader)
|
|
89
|
+
|
|
90
|
+
def describe(self):
|
|
91
|
+
# construct a report like xrif2fits has
|
|
92
|
+
s = 'xrif compression details:\n'
|
|
93
|
+
s += f" difference method: {self.difference_method}\n"
|
|
94
|
+
s += f" reorder method: {self.reorder_method}\n"
|
|
95
|
+
s += f" compression method: {self.compress_method}\n"
|
|
96
|
+
if self._reader.contents.compress_method == xrif.XRIF_COMPRESS_LZ4:
|
|
97
|
+
s += f" LZ4 acceleration: {self.lz4_acceleration}\n"
|
|
98
|
+
s += f" dimensions: {self.width} x {self.height} x {self.depth} x {self.frames}\n"
|
|
99
|
+
|
|
100
|
+
s += f" raw size: {self.raw_size} bytes\n"
|
|
101
|
+
s += f" encoded size: {self.compressed_size} bytes\n"
|
|
102
|
+
s += f" ratio: {self.ratio:.3f}\n"
|
|
103
|
+
return s
|
|
104
|
+
|
|
105
|
+
def __del__(self):
|
|
106
|
+
xrif.xrif_delete(self._reader)
|
|
107
|
+
|
|
108
|
+
def _decode_from_fh(self):
|
|
109
|
+
# read one header's worth of bytes
|
|
110
|
+
buf = self.fh.read(xrif.XRIF_HEADER_SIZE)
|
|
111
|
+
header_size_ptr = ctypes.c_uint32()
|
|
112
|
+
# populate header fields in reader
|
|
113
|
+
rv = xrif.xrif_read_header(self._reader, header_size_ptr, buf)
|
|
114
|
+
assert header_size_ptr.value == xrif.XRIF_HEADER_SIZE
|
|
115
|
+
if rv != xrif.XRIF_NOERROR:
|
|
116
|
+
raise RuntimeError("XRIF error reading header, check stderr")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
rv = xrif.xrif_allocate_reordered(self._reader)
|
|
120
|
+
if rv != xrif.XRIF_NOERROR:
|
|
121
|
+
raise RuntimeError("XRIF error allocating reordered buffer")
|
|
122
|
+
|
|
123
|
+
# xrif can save you a buffer by decompressing into the raw buffer but that
|
|
124
|
+
# means it needs to be bigger than just `compressed_size`
|
|
125
|
+
min_buf_size = xrif.xrif_min_raw_size(self._reader)
|
|
126
|
+
# we need to own the raw (and then decompressed) buffer
|
|
127
|
+
buf = ctypes.c_buffer(min_buf_size)
|
|
128
|
+
# we're only filling the first `compressed_size` bytes
|
|
129
|
+
buf[:self._reader.contents.compressed_size] = self.fh.read(self._reader.contents.compressed_size)
|
|
130
|
+
# acquaint xrif with our arrangements
|
|
131
|
+
rv = xrif.xrif_set_raw(self._reader, buf, min_buf_size)
|
|
132
|
+
|
|
133
|
+
if rv != xrif.XRIF_NOERROR:
|
|
134
|
+
raise RuntimeError("XRIF error setting raw buffer, check stderr")
|
|
135
|
+
|
|
136
|
+
# do the business
|
|
137
|
+
xrif.xrif_decode(self._reader)
|
|
138
|
+
|
|
139
|
+
if rv != xrif.XRIF_NOERROR:
|
|
140
|
+
raise RuntimeError("XRIF decode error, check stderr")
|
|
141
|
+
|
|
142
|
+
# Now we need to make it intelligible to Python code.
|
|
143
|
+
# Fortunately xrif's data types are all available in NumPy
|
|
144
|
+
dtype = XRIF2NUMPY_DTYPE[self._reader.contents.type_code]
|
|
145
|
+
|
|
146
|
+
# figure out how many bytes it is now that it's decompressed
|
|
147
|
+
raw_size = self._reader.contents.width * self._reader.contents.height * self._reader.contents.depth * self._reader.contents.frames * self._reader.contents.data_size
|
|
148
|
+
|
|
149
|
+
# make a NumPy array from a buffer
|
|
150
|
+
self._decoded = np.frombuffer(buf[:raw_size], dtype).reshape(self.shape)
|
|
151
|
+
self._decoded.setflags(write=False)
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def array(self) -> np.ndarray:
|
|
155
|
+
return self._decoded
|
|
156
|
+
|
|
157
|
+
def copy_data(self) -> np.ndarray:
|
|
158
|
+
arr = self.array.copy()
|
|
159
|
+
arr.setflags(write=True)
|
|
160
|
+
return arr
|
|
161
|
+
|
|
162
|
+
def xrif2numpy(fh):
|
|
163
|
+
reader = XrifReader(fh)
|
|
164
|
+
print(reader.describe())
|
|
165
|
+
return reader.copy_data()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fixr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings to xrif, the extreme reordered image format
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
|
|
9
|
+
# fiXr
|
|
10
|
+
|
|
11
|
+
Open xrif archives from Python directly using the [xrif](https://github.com/jaredmales/xrif) library.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from fixr import xrif2numpy
|
|
17
|
+
fh = open('camwfs_20240315225750994842000.xrif', 'rb')
|
|
18
|
+
data = xrif2numpy(fh)
|
|
19
|
+
timings = xrif2numpy(fh)
|
|
20
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fixr
|