Repository navigation
Wheel validation included full test suite runs on RTX A6000 (compute capability 8.6), RTX 6000 Ada Generation (8.9),
and GeForce RTX 5090 (12.0). NVIDIA driver R580 and compute capability 7.5 (Turing) have not been verified on hardware.
Added
- Added a public C and C++ SDK: headers,
libpixtreme.so.2, and a CMake package are included in the Linux wheel.
C11 and C++17 applications can use pixtreme without embedding Python. Locate the package with
pixtreme.core.get_cmake_dir(), usefind_package(pixtreme CONFIG REQUIRED), and linkpixtreme::pixtreme.
Python and native consumers share the same library; keep pixtreme installed rather than copying its library. - The SDK provides GPU Frames with color metadata, channel parsing, borrowed pixel owners, transactional pixel
replacement, shallow or deep cloning, and DLPack 1.x exchange. Operations accept a CUDA stream and an optional
allocator for output and scratch memory; the default allocator uses CUDA stream-ordered memory allocation. - The SDK exposes token matching and canonical token constants, colorspace and reference-white definitions,
andLut/Lut1Dvalidation. It also providescast_dtype,recode_dtype,quantize,dequantize,
full_to_legal,legal_to_full, and channelshuffle. Nativeshufflerequires matching colorspace and gamma;
Python'sshuffle(adapt=True)retains its color-conversion behavior. - C and C++ callers can read EXR headers and pixels, write EXR images, and write mixed HALF, FLOAT, and UINT
channel groups without Python. Supported EXR options, pixel types, and color metadata follow the Python EXR APIs. - The shared library has a C ABI with opaque handles and size-prefixed structs, plus a header-only C++ wrapper.
Within a major version, the ABI grows through added functions and trailing struct fields; programs built with
earlier minor headers run against later minor libraries without rebuilding. Usepixtreme_check_abior
pixtreme::require_abi()to check the loaded library against the headers used to build the application. - Wheels include full license texts for bundled third-party components in
dist-info/licenses/and identify them
in the SPDXLicense-Expression. A separate notice identifies the statically linked CUDA runtime's license. - GitHub Releases include an HTML documentation archive containing the API reference and the C and C++ SDK guide.
Changed
pixtreme.core.Framenow wraps one persistent C++ Frame. It no longer inherits
pydantic.BaseModeland no longer providesmodel_fields,model_dump,
model_construct, ormodel_copy.vars(frame)andframe.__dict__are
unavailable, and fields cannot be deleted withdel. Read and assign the five
properties instead. Validation errors areValueErrorrather
thanpydantic.ValidationError. For migration, read the five fields directly,
use the keyword-only constructor to build a Frame, and usecopy.copyor
copy.deepcopyto copy one. Field names and order, defaults, validation on
assignment, contiguous-array identity, equality, unhashability, and pickle
roundtrips are preserved.pixtreme.io.ImageHeaderremains a pydantic model.- The Python source, tests, project metadata, and lock file now live in
python/; native C++ implementations follow
the corresponding Python package paths undercpp/. The build backend is scikit-build-core with setuptools-scm
versions fromvX.Y.Ztags and a nanobind extension. Existing Python image-processing operation names and
arguments remain unchanged. - 2.0.0 wheels target Linux x86_64 (
manylinux_2_28) with thecp312-abi3tag for standard CPython 3.12 and newer.
Free-threaded CPython builds are not supported. 2.0.0 does not provide native Windows wheels. On Windows, use the
Linux wheel under WSL2, or use 1.x for native Windows. Installing and using the wheel requires no compiler or
CUDA toolkit; CUDA's runtime is linked statically. PyPI and GitHub Releases distribute wheels only; source
distributions are not published. - EXR reading and writing now use the shared C++ library, including container parsing, part and channel selection,
and all ten compression modes: NONE, RLE, ZIPS, ZIP, PIZ, PXR24, B44, B44A, DWAA, and DWAB. Native implementations
use C++ and CUDA. ZIP, ZIPS, and PXR24 use libdeflate for Deflate compression and decompression, and the
nvidia-nvcomp-cu13runtime dependency has been removed. - Floating-point results follow each operation's specified precision. Bit-for-bit equality is not guaranteed
across GPU generations, CPU instruction sets, or math libraries.
Fixed
- Fixed reading PXR24 EXR images with mixed HALF, FLOAT, and UINT channels into a float32 Frame, including
scanline, tiled, and multipart files. - Corrected B44 and B44A pLinear HALF decoding to match OpenEXR for external EXR files, including the
0x1935pattern decoding to0xd1f9. - For EXR files without chromaticities,
read_header(...).color.rawnow retains an explicitly stored
acesImageContainerFlag=0as{'acesImageContainerFlag': False}. white_point_simulationrejects reference whites on or within float64 roundoff of an edge of the Frame
primaries' chromaticity triangle with aValueErrorexplaining the reason and correction. This also applies
when the input and output reference whites are equal.- Frame cleanup releases pixels without unraisable exceptions when the active Python frame's builtins omit
__import__, including garbage collection insidecollections.namedtupleconstructors. - Keeping Frames alive until Python interpreter shutdown no longer emits cleanup errors to stderr or interferes
with process exit.
Migration
Frame uses five properties: data, colorspace, gamma, channels, and
matrix. Replace pydantic model operations with field access and the validated
keyword-only constructor.
# Before
fields = frame.model_dump()
frame = px.core.Frame.model_construct(
data=data, colorspace="ACEScg", gamma="linear", channels="RGB", matrix=None
)
# 2.0
fields = {name: getattr(frame, name) for name in ("data", "colorspace", "gamma", "channels", "matrix")}
frame = px.core.Frame(
data=data, colorspace="ACEScg", gamma="linear", channels="RGB", matrix=None
)Use the standard library's copy operations. A shallow copy shares pixels, a deep
copy copies pixels, and both copies have independent metadata.
# Before
shallow = frame.model_copy()
deep = frame.model_copy(deep=True)
# 2.0
import copy
shallow = copy.copy(frame)
deep = copy.deepcopy(frame)Catch ValueError when constructing a Frame or assigning a field:
# Before
try:
frame.gamma = gamma
except pydantic.ValidationError as error:
print(error)
# 2.0
try:
frame.gamma = gamma
except ValueError as error:
print(error)vars(frame) and frame.__dict__ are unavailable; read the five properties or
create a field dictionary as above. Mutating such a dictionary does not assign
Frame properties. Fields cannot be removed with del frame.colorspace or another
del frame.<field> operation. Assign valid values through the properties.