Changelog
Notable changes to pixtreme are documented in this file.
2.0.0 - 2026-10-25
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 withpixtreme.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,
and
Lut/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. Use
pixtreme_check_abiorpixtreme::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 inheritspydantic.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.copyorcopy.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 storedacesImageContainerFlag=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.
1.9.3 - 2026-10-17
pixtreme 1.9.3 fixes reading DWAA and DWAB EXR images. Public operation names, arguments, accepted names, and return shapes remain compatible.
Fixed
- Fixed reading DWAA and DWAB EXR images with Deflate-compressed AC coefficients, including small tiles written by OpenEXR. Unsupported legacy DWA versions now report how to re-encode the image.
1.9.2 - 2026-10-17
pixtreme 1.9.2 fixes reading DWAA and DWAB EXR images. Public operation names, arguments, accepted names, and return shapes remain compatible.
Fixed
- Fixed reading DWAA and DWAB EXR images with nvCOMP 6.0.
- Fixed reading some DWAA and DWAB EXR images that previously failed during decompression.
1.9.1 - 2026-10-16
pixtreme 1.9.1 does not change library behavior: the pixtreme package code is the same as in 1.9.0. Public
operation names, arguments, accepted names, and return shapes remain compatible. This release changes how the
documentation site and the development tooling in the source distribution are produced.
Changed
- The documentation site is built and published to GitHub Pages by a GitHub Actions workflow in the public
repository. The documentation build dependencies (
mkdocs-material,mkdocstrings) form a separatedocsdependency group, which thedevgroup includes. - The token sheet generator scripts under
tests/require--output-dirinstead of writing to a default directory.
1.9.0 - 2026-10-15
pixtreme 1.9.0 moves its GPU dependencies from the CUDA 12 builds to the CUDA 13 builds, including CuPy
(cupy-cuda13x). It requires NVIDIA driver R580 or newer and an NVIDIA GPU with compute capability 7.5 or higher;
use pixtreme 1.8.0 for CUDA 12 environments. Public operation names, arguments, accepted names, and return shapes
remain compatible.
The published performance report (docs/performance.md) and README performance table still show the earlier
CUDA 12.9 baseline measured at commit 260fe6e; CUDA 13 measurements have not been taken for this release.
Changed
- pixtreme now requires CUDA 13 builds of its GPU dependencies, NVIDIA driver R580 or newer, and an NVIDIA GPU with compute capability 7.5 or higher. Applications pinned to CUDA 12 dependency builds must migrate to CUDA 13; drivers older than R580 and GPUs with compute capability 7.0 or lower are no longer supported.
1.8.0 - 2026-10-06
pixtreme 1.8.0 allows separately installed font packages to contribute subpackages beneath pixtreme.fonts.
px.io.to_v210 now writes zero to sample slots with no corresponding pixel in the last six-pixel group of a row;
encoded bytes change for widths not divisible by six, while pixel data and px.io.from_v210 results stay the same.
px.metrics.ssim and px.metrics.ssim_map have about 34% lower median runtimes in the measured FHD case, and EXR
decoding has internal speed improvements. Public operation names, arguments, accepted names, and return shapes remain
compatible.
The published performance report (docs/performance.md) and README performance table still show the earlier
210-case baseline measured at commit 260fe6e; the SSIM improvements below were measured separately and those
tables have not been regenerated.
Added
pixtreme.fontsis now a package, allowing a separately installed font package to contribute apixtreme/fonts/<name>/subtree and import it aspixtreme.fonts.<name>. The existingpx.fonts.available()andpx.fonts.font_path(name)operations and entry-point font discovery retain their behavior.
Changed
px.metrics.ssimandpx.metrics.ssim_mapuse a separable window calculation with compensated accumulation. On an NVIDIA RTX A6000 with FHD fp32 RGB inputs anddata_range=1.0, the medians across three targeted runs fell from 2.014 to 1.328 ms and 2.025 to 1.342 ms, respectively (about 34%). Results remain within the existing 4e-5 tolerance against the independent float64 oracle.- EXR decoding avoids repeated construction of channel rows and combines chunk replacements, improving its internal read path without changing the public API.
Fixed
px.io.to_v210now zeros unused Y, Cb, and Cr sample slots in the last six-pixel group of rows whose widths are not divisible by six. Encoded bytes for these widths differ from 1.7.0; samples that represent pixels, row padding, andpx.io.from_v210results are unchanged.
1.7.0 - 2026-10-04
pixtreme 1.7.0 adds two public capabilities. The first is the px.io.from_p210 / px.io.to_p210 pair, the tenth
named-format pair, which exchanges 10-bit 4:2:2 semi-planar frames (a uint16 Y plane followed by a uint16
interleaved Cb Cr plane, with the code in the upper 10 bits of each word) as one C-contiguous device array under the
existing 4:2:2 rules; the io module grows to 31 operations and the public API to 102. The second is the DCI
reference-white token for the SMPTE RP 431-2 D-Cinema white, accepted by px.color.chromatic_adaptation and
px.color.white_point_simulation. Both are additions: existing operations, signatures, defaults, and token spellings
are unchanged, and there are no breaking changes to the public API. The EXR reader and writer are reorganized
internally by compression, and corrupt-chunk errors now name the compression that failed. The published performance
baseline (docs/performance.md and the README table) is carried over from 1.6.0 unchanged and does not yet cover the
P210 pair.
Added
- Added the
DCIreference-white token for the SMPTE RP 431-2 D-Cinema white(0.3140, 0.3510).px.color.chromatic_adaptationandpx.color.white_point_simulationnow accept it in either white argument. This adds no operation; the public API remains at 102 operations. - Added
px.io.from_p210andpx.io.to_p210, the tenth named-format pair. P210 is 10-bit 4:2:2 semi-planar (auint16Y plane followed by auint16interleaved Cb Cr plane) exchanged as a C-contiguous 1D device array. Each word carries a fixed 10 effective code bits in its upper 10 bits with nobit_depthargument; import ignores the lower six padding bits and export writes them as zero.rangeuses the H.273 mapping forn = 10, export rounds half away from zero and clips only to the code range[0, 1023], and the even-width constraint, horizontally co-sited chroma at full vertical resolution, and theinterpolationtokens follow the existing 4:2:2 rules. Theiomodule now exposes 31 operations and the public API 102.
Changed
- EXR corrupt-chunk errors for RLE, PXR24, B44, B44A, and PIZ now name the compression whose chunk failed. The exception types and the situations that raise them are unchanged.
1.6.0 - 2026-09-23
pixtreme 1.6.0 adds two public capabilities. The first is the px.io.from_p216 / px.io.to_p216 pair, the ninth
named-format pair, which exchanges 16-bit 4:2:2 semi-planar frames (a uint16 Y plane followed by a uint16
interleaved Cb Cr plane) as one C-contiguous device array under the existing 4:2:2 planar rules; the io module grows
to 29 operations and the public API to 100. The second is the keyword-only preserve_shaper option of
px.io.read_lut and px.io.decode_lut, which evaluates a nonidentity .3dl shaper strictly in one GPU kernel
instead of the default same-edge bake. Both are independent additions: existing token spellings, aliases, signatures,
and float32 results are unchanged, and there are no breaking changes to the public API. The published performance
baseline (docs_site/performance.md and the README table) is regenerated from a single same-run measurement of the
current implementation on an NVIDIA RTX A6000 (WSL2, CUDA runtime 12.9, CuPy 14.1.1) and now covers 210 cases,
including the P216 pair and the shaper-aware LUT cases.
Added
- Added
px.io.from_p216andpx.io.to_p216, the ninth named-format pair. P216 is 16-bit 4:2:2 semi-planar (auint16Y plane followed by auint16interleaved Cb Cr plane) exchanged as a C-contiguous 1D device array. The effective code depth is fixed at 16 bits with nobit_depthargument;range, rounding, clipping, the even-width constraint, horizontally co-sited chroma at full vertical resolution, and theinterpolationtokens follow the existing 4:2:2 planar rules. Theiomodule now exposes 29 operations and the public API 100. - Added the keyword-only
preserve_shaperoption topx.io.read_lutandpx.io.decode_lut. For nonidentity.3dlspacing, opting in retains a shared shaper onpx.core.Lutand evaluates its linear stage with the existing trilinear or tetrahedral cube stage in one GPU kernel. The default remains the existing same-edge baked approximation. Writing a shaped LUT as Cube performs the same-edge bake on the GPU; the independent shaper and strict between-node evaluation are not recoverable from that output.
1.5.0 - 2026-09-10
pixtreme 1.5.0 adds six public capabilities and changes two raster decode defaults. The additions are the
per-channel px.color.grade operation, the px.fonts module and its pixtreme.fonts entry-point contract for
installable font packages, H.273 chroma sample location types 3 through 5 for the 4:2:0 wire formats, embedded ICC
profile inspection with the Adobe-RGB, ProPhoto-RGB, and Gamma-1.8 tokens, px.io.write_exr_channels for
mixed-dtype EXR output, and the antialiased lanczos2-aa / lanczos3-aa / lanczos4-aa resize tokens. The two
default changes are that a mappable embedded ICC profile now sets file-explicit colorspace and gamma metadata, and
that JPEG, PNG, TIFF, and WebP decodes now apply EXIF orientation; both keep pixel decoding unchanged, both carry a
migration note below, and both can be restored to the former behavior with explicit keyword arguments. Existing token
spellings, aliases, signatures, and float32 results are otherwise unchanged, and there are no breaking changes to the
public API. Frame construction no longer repeats validation on the common output path, which removes most of the
per-call host overhead introduced by the 1.3.0 token acceptance layer, and the published performance baseline
(docs_site/performance.md and the README table) is regenerated from a single same-run measurement of the current
implementation on an NVIDIA RTX A6000 (WSL2, CUDA runtime 12.9, CuPy 14.1.1).
Added
-
Added
px.color.grade, a per-channel Lift / Gamma / Gain operation that appliesz = gain * x + lift * (1 - x)followed by a sign-preserving pure power1 / gammato every stored sample without clipping. Each parameter accepts a scalar that broadcasts to every storage channel or a mapping keyed by exact channel labels that leaves unspecified channels bit-preserved. Parameters are converted to binary32 and validated before pixel processing; Frame metadata is inherited unchanged. The affine-power core matches Nuke Grade on its default-control0 <= z <= 1interval and converts to ASC CDL slope / offset / power; DaVinci Resolve numeric compatibility is not claimed. -
Added H.273 chroma sample location types 3 through 5 as the canonical
ChromaSitingtokenstop,bottomleft, andbottom. The NV12, P010, and planar YUV420 input and output boundaries now accept all six progressive-frame positions while retaining the existingleftdefault and existing-token output bits. -
Added embedded ICC profile inspection for PNG
iCCP, JPEG APP2, TIFF InterColorProfile, and WebPICCPatread_image,decode_image, andread_header. RGB matrix/TRC profiles are mapped numerically to existing colorspace and gamma vocabulary without transforming pixel values. The five canonical additions are theAdobe-RGBandProPhoto-RGBcolorspace tokens, the same two gamma tokens, and pure-powerGamma-1.8. -
Added
px.fonts, whoseavailable()andfont_path(name)functions expose bundled fonts and filesystem assets declared by installed font packages through thepixtreme.fontsentry-point contract. Discovery is lazy, atomic, deterministic, and cached for the process lifetime. Existingpx.draw.textsans/monotokens and their rendering behavior remain unchanged. -
px.io.write_exr_channels(path, frames, *, compression=None, dwa_level=None)writes same-shape, same-device, same-colorspacefloat16,float32, anduint32Frame channel groups into one single-part scanline EXR while retaining each channel's native HALF, FLOAT, or UINT storage. All ten EXR compression modes operate per channel, so exact UINT object IDs can share a file with HALF or FLOAT imagery. Existingpx.io.write_imageandpx.io.encode_imageremain single-Frame, single-output-dtype APIs. -
px.transform.resizeaccepts three new interpolation tokens,lanczos2-aa,lanczos3-aa, andlanczos4-aa. They are Lanczos kernels whose support widens by the reduction scale on each shrinking axis (the Pillow / ImageMagick family), with replicate edges and normalized weights; on a same-size or enlarging axis they are bit-identical tolanczos2/lanczos3/lanczos4. Existing tokens and the automaticarea/lanczos4choice are unchanged, and no other API accepts the new tokens.
Changed
-
Frame construction on the common metadata-inheriting output path and in
px.io.from_arraynow skips the duplicate pydantic validation pass when the output array and metadata are already verified at construction time, and canonical token spellings return early from normalization. This removes most of the per-call host overhead that the token acceptance layer added in 1.3.0 for small frames; public API, accepted and rejected inputs, exception types, output bits, and attribute-assignment validation are unchanged. -
Raster images with a supported embedded ICC profile now receive file-explicit colorspace and gamma metadata instead of the sRGB defaults. Decoded pixel samples are unchanged, but later color transforms driven by Frame metadata can now produce a different result that follows the file's intended color representation. Unmappable selected metadata warns once and falls back component by component unless the caller supplies an explicit claim. Migration note: existing code that reads PNG, JPEG, TIFF, or WebP files carrying an
Adobe-RGB,ProPhoto-RGB, or other mappable RGB matrix/TRC profile and then converts by Frame metadata (for examplepx.color.rgb_to_rgborpx.color.rgb_to_grayscalewithout explicit source tokens) now produces different output for those files; files without a mappable profile are unaffected. To keep the previous behavior, pass the former defaults explicitly,read_image(path, colorspace="sRGB", gamma="sRGB")or the same keywords ondecode_image; explicit tokens always override file metadata.read_header(path).color.mappablereports whether a file carries mappable profile metadata. -
px.io.read_imageandpx.io.decode_imagenow expose a trailing keyword-onlyapply_exif_orientation: bool = Trueargument. JPEG, PNG, TIFF, and WebP apply EXIF orientation 1 through 8 by default; invalid optional orientation metadata emits a warning and falls back to identity, whileFalsepreserves stored pixel order. ImageHeadernow includesorientation, defaulting to 1. For JPEG, PNG, TIFF, and WebP,widthandheightnow describe the default oriented decode, so orientations 5 through 8 exchange the former stored-dimension meaning. Migration note: existing code that reads JPEG, PNG, TIFF, or WebP files whose EXIF orientation is 2 through 8 now receives rotated or flipped pixels, and for orientations 5 through 8 the Frame andImageHeaderwidth and height are exchanged relative to the stored raster; files with orientation 1 or without orientation metadata are unaffected. To keep the previous behavior, passapply_exif_orientation=Falsetoread_imageordecode_image, which preserves the stored pixel order. The stored dimensions of a file can be recovered fromread_headerby exchangingwidthandheightwhenorientationis 5 through 8.
Fixed
px.io.from_arraynow validates thematrixtoken at the entry, together withlayout,colorspace,gamma, andchannels, before any repacking kernel, contiguity conversion, or copy runs. An unknown or non-stringmatrixraises a plain actionableValueErrorinstead of a pydanticValidationErrorafter the GPU pass. The accepted spellings, their canonical results, and every other argument contract are unchanged.
1.4.0 - 2026-09-07
pixtreme 1.4.0 widens the colour vocabulary from 18 to 27 colorspace tokens and from 19 to 33 gamma tokens by adding
23 tokens across the Canon, Panasonic, DJI, Fujifilm, Nikon, Leica, Apple, and Samsung camera families and the
P3 / SMPTE-C / ACEScc / ACEScct / Gamma-2.5 standard set. Every new token is an independent addition: existing token
spellings, aliases, and float32 results are unchanged, and there are no breaking changes to the public API. The
published performance baseline (docs_site/performance.md and the README table) is regenerated from a single
same-run measurement of the current kernels on an NVIDIA RTX A6000 (WSL2, CUDA runtime 12.9, CuPy 14.1.1), replacing
figures that predated the 1.3.0 kernel fusions.
Added
-
Added the independent
Apple-Wide-Gamutcolorspace andN-Log,L-Log,Apple-Log, andSamsung-Logtransfers. N-Log uses the maximum-real-root branch intersection, L-Log uses the printed cut's tangent, Apple Log preserves its published lower collapse, and Samsung Log derives its lower offset at the upper-branch cut and extends that branch without the vendor codec collapse. These numeric identities intentionally have non-parity with printed cuts, ACES CTL, OpenColorIO-family evaluation, or codec clipping where those definitions differ. Apple Wide Gamut uses its published primaries and D65 with the shared Bradford production path; its CAT02 ACES matrix remains an auxiliary check. Existing gamma and colorspace results remain float32 bit-identical. -
Added the independent
D-GamutandF-Gamut-Ccolorspaces andD-Log,F-Log, andF-Log2transfers. The transfers apply the vendor-published linear and logarithmic branches directly to reflectance, using each branch intersection's maximum real root and separately rounded binary64 encode/decode cuts. Printed cuts, the rounded D-Log inverse, ACES CTL, OpenColorIO-Config-ACES, and vendor IDTs are explicit non-parity targets. D-Gamut and F-Gamut-C use their published primaries with D65 and the shared Bradford production path; vendor and CAT02 matrices remain auxiliary checks. Existing gamma and colorspace results remain float32 bit-identical. -
Added the independent
P3-DCI,P3-D60,P3-D65, andSMPTE-Ccolorspaces andACEScc,ACEScct, andGamma-2.5transfers. P3-D60 uses ACES white to align with the public ACES/OpenColorIO ecosystem; SMPTE EG 432-1's distinct nominal D60 is an auxiliary comparison and Resolve parity is not claimed. Gamma-2.5 is the conventional sign-preserving pure power because Resolve publishes no formula. ACEScc and ACEScct evaluate the Academy AP1 analytic curves without an upper 65504 clip (a documented no-upper-clip extension);ACEScgsupplies the standard AP1 colorimetry independently. ACEScc intentionally collapses nonpositive encode inputs, so ACEScct is the path for preserving negative components. Existing token results remain float32 bit-identical. -
Added the independent
V-Gamutcolorspace andV-Loggamma tokens. V-Gamut uses Panasonic's published CIE 1931 xy primaries with D65 and the shared Bradford adaptation path. V-Log applies Panasonic's public logarithmic branch directly to reflectance and uses the cut-derived tangent for a C1-continuous lower branch, matching current OpenColorIO. Panasonic's printed linear branch, vendor IDT, and ACES CSC are not bit-parity targets. The externalPanasonic V-Gamut/Panasonic V-Loglabels, combined labels, andV-Log Lremain outside the alias guarantee. Existing token results remain float32 bit-identical. -
Added the independent
Canon-Cinema-Gamutcolorspace andCanon-Log,Canon-Log-2, andCanon-Log-3gamma tokens. The gamut uses Canon's published CIE 1931 xy primaries with D65 and the shared Bradford adaptation path. The transfers use the Canon 2018 full-range equations after mapping public reflectance withx = r / 0.9, extend their published signed branches without clipping or sign/magnitude mirroring, and retain values above 1.Canon Rawdecoding and proprietary capture-gamut or OETF recovery remain outside the guarantee. Existing token results remain float32 bit-identical.
Changed
- DPX writes tag frames whose gamma is
Canon-Log,Canon-Log-2,Canon-Log-3,V-Log,D-Log,F-Log,F-Log2,N-Log,L-Log,Apple-Log,Samsung-Log,ACEScc, orACEScctwith the logarithmic transfer characteristic in the file header, matching the existing camera-log tokens. Pixel encoding is unchanged.
1.3.0 - 2026-09-03
pixtreme 1.3.0 widens the camera and working colour vocabulary from 7 to 18 colorspace tokens and from 12 to 19
gamma tokens (Sony, ARRI, Blackmagic Design, DaVinci, and RED families), canonicalizes token spellings behind a
case- and separator-insensitive runtime that keeps every earlier spelling as a permanent alias, removes the pre-baked
LUT tonemap tokens in favour of the analytic ACES renderings, adds optional px.infer / px.transport companion
namespaces, and ships a round of bit-identical GPU kernel fusions. Absolute performance figures below are same-run
medians on an NVIDIA RTX A6000 (WSL2, CUDA runtime 12.9, CuPy 14.1.1) at 1920x1080 fp32 RGB unless stated.
Added
-
Added the independent RED colorspace tokens
REDWideGamutRGB,DRAGONcolor,DRAGONcolor2,REDcolor2,REDcolor3, andREDcolor4, plus theRED-Log3G10andREDlogFilmgamma tokens.RED-Log3G10uses RED's published piecewise curve without clipping or sign/magnitude mirroring.REDlogFilmis float32 bit-identical toCineonwhile preserving independent metadata. All six gamuts use coordinate-derived normalized primary matrices, production D65, shared Bradford adaptation, and independent gamma selection. Existing token results remain bit-identical. -
Added the independent canonical colorspace tokens
Blackmagic-Wide-Gamut-Gen-5andDaVinci-Wide-Gamut, plus theBlackmagic-Film-Gen-5andDaVinci-Intermediategamma tokens. The two gamuts use their published primaries with production D65 and remain independent from gamma selection. Film Gen 5 uses Blackmagic Design's natural-log transfer and published anchors; DaVinci Intermediate uses its base-2 transfer and the decode threshold derived from its linear branch. Both curves extend directly to negative values and leave scene overshoot unclipped. Existing camera-log token results remain bit-identical. -
Added explicit optional companion namespaces for
px.inferandpx.transport. Separately installedpixtreme-inferandpixtreme-transportdistributions can contribute their matchingpixtremesubpackages while the root package keeps its existing constant public surface. Accessing an absent companion reports its matchingpip installcommand. -
Added the independent canonical colorspace tokens
ARRI-Wide-Gamut-3andARRI-Wide-Gamut-4, plus theARRI-LogC3gamma token. ARRI-LogC3 is fixed to ARRI's EI 800 relative scene-exposure curve, maps 18% gray to400 / 1023, extends its tangent-derived lower linear branch to negative values, and leaves scene overshoot unclipped. The two gamut tokens publish their ARRI primaries with D65 white and remain independent from gamma selection. Existing ARRI-LogC4 remains bit-identical. -
Added the independent canonical tokens
S-Gamut,S-Log, andS-Log2. S-Log and S-Log2 use Sony's published scene-linear IRE equations with public reflectance normalization and legal-range code embedding; the S-Log negative forward branch is the algebraic inverse of Sony's published decoder linear branch, not a separately published Sony forward equation. Their 0% / 18% / 90% reflection anchors round to90 / 394 / 636and90 / 347 / 582, respectively. S-Gamut is numerically identical to S-Gamut3 while retaining separate metadata identity. S-Gamut3 and S-Log3 remain unchanged.
Breaking
-
Removed the pre-baked LUT tonemap tokens
aces-1.3-lutandaces-2.0-lutfrompx.color.rgb_to_rgb, together with their four bundled 65^3 LUT archives (13,280,928 bytes) and the view-transform LUT runtime. The tonemap vocabulary is nowACES-1.3,ACES-2.0, andBT.2408with six supply pairs (Rec.709/BT.1886andsRGB/sRGBfor both ACES renderings,Rec.2020/HLGandRec.2020/PQfor BT.2408). The analytic paths keep their float32 output bits for negative, reference-white, super-white, and saturated inputs. Passing a removed token raises the existing closed-vocabularyValueErrorbefore any pixel work, listing the six valid pairs. -
The pre-release intermediate canonical gamma tokens
LogC3andLogC4are renamed toARRI-LogC3andARRI-LogC4before publication. NoLogC3compatibility alias is added. Relative to v1.2.1, runtime inputlogc4remains accepted through its permanent alias, canonical output changes fromlogc4toARRI-LogC4, and the staticLiteralaliases and public signatures replacelogc4withARRI-LogC4. Both ARRI curves retain the same equations, branches, signed extensions, anchors, and float32 output bits. -
S-Log3andARRI-LogC4now apply their vendor-published piecewise equations directly to signed inputs instead of sign/magnitude mirroring. S-Log3 applies the Sony piecewise formula directly to signed inputs, including the lower linear branch below zero. ARRI-LogC4 applies the ARRI piecewise formula directly to signed inputs, selecting its log branch at and above the negative cut and its lower linear branch below it. Negative encoded ARRI-LogC4 values decode linearly. Negative-input results change. Results for nonnegative inputs remain float32 bit-identical. -
Canonical token spellings now preserve standards and proper-name typography. Static
Literalaliases, public signatures, defaults, Frame metadata, representations, return values, and error recovery candidates expose only the canonical spellings below. Runtime validation is case-insensitive and treats U+0020 SPACE,.,-, and_as interchangeable separators. All earlier spellings are permanent runtime aliases.
| Family | Earlier spelling | Canonical spelling |
|---|---|---|
| Gamma | srgb |
sRGB |
| Gamma | rec709 |
Rec.709 |
| Gamma | bt1886 |
BT.1886 |
| Gamma | pq |
PQ |
| Gamma | hlg |
HLG |
| Gamma | s-log3 |
S-Log3 |
| Gamma | logc4 |
ARRI-LogC4 |
| Gamma | cineon |
Cineon |
| Gamma | 2.2 |
Gamma-2.2 |
| Gamma | 2.4 |
Gamma-2.4 |
| Gamma | 2.6 |
Gamma-2.6 |
| Matrix | bt601 |
BT.601 |
| Matrix | bt709 |
BT.709 |
| Matrix | bt2020 |
BT.2020 |
| ChromaticAdaptation | bradford |
Bradford |
| ChromaticAdaptation | cat02 |
CAT02 |
| ChromaticAdaptation | cat16 |
CAT16 |
| ChromaticAdaptation | von-kries |
von-Kries |
| ReferenceWhite | d65 |
D65 |
| ReferenceWhite | d93 |
D93 |
| ReferenceWhite | d50 |
D50 |
| ReferenceWhite | aces |
ACES |
| Tonemap | aces-1.3 |
ACES-1.3 |
| Tonemap | aces-2.0 |
ACES-2.0 |
| Tonemap | bt2408 |
BT.2408 |
| ColorBarsStandard | arib-std-b28 |
ARIB-STD-B28 |
| ColorBarsStandard | smpte-rp219 |
SMPTE-RP219 |
| ColorBarsStandard | bt2111-hlg |
BT.2111-HLG |
| ColorBarsStandard | bt2111-pq |
BT.2111-PQ |
| ColorBarsStandard | bt2111-pq-full |
BT.2111-PQ-full |
The three numeric gamma spellings remain permanent runtime aliases. Their transfer implementation and GPU kernels
are unchanged. BT.1886 is the Annex 1 ideal-black specialization and is numerically equivalent to Gamma-2.4,
while the two canonical tokens retain distinct meanings and metadata identities.
Changed
px.color.rgb_to_rgbwithtonemap="ACES-2.0"moves the hue-dependent algorithm table from CUDA constant memory to read-only global memory, reuses the CAM response powers, and resolves cusp intervals in two fixed steps. FHD RGB shortens from 1.270 ms to 0.141 ms (Rec.709 / BT.1886) and from 1.276 ms to 0.144 ms (sRGB / sRGB); outputs are bit-identical and the OCIO corpus statistics are unchanged.tonemap="ACES-1.3"moves its spline coefficient arrays to packed read-only global memory; divergent FHD inputs shorten from 0.201 ms to 0.146 ms with bit-identical output.px.values.recode_dtyperuns every conversion pair that involves an integer dtype in one fused RawKernel; same-dtype and float-to-float pairs keep thecast_dtypedelegation. All 25 dtype pairs remain bit-identical to the previous composition, including NaN payloads and theuint32NaN code. Formerly multi-pass pairs shorten by up to 7.4 times (uint16touint87.39x,uint8touint167.32x,uint32touint166.22x,float32touint324.53x); theuint8/float32registry cases shorten from 0.104 ms and 0.097 ms to 0.083 ms.- EXR
UINTchannel decoding reuses the shared unpack RawKernel instead of a per-chunk CuPy composition. The unpack stage shortens from 94.55 ms to 0.48 ms for an FHD-sized UINT scanline image and a full ZIP decode of the same container from 98.90 ms to 22.33 ms; decoded bits are unchanged across all ten compressions. - Raster decode (channel gather, cast, normalization) and raster write (recode, canonical gather) boundary stages each run as one fused RawKernel launch for every raster format. The boundary stages shorten by 2.2 to 3.0 times with bit-identical results (signed zero and non-finite values included); end-to-end PNG timing is within measurement noise because the codec dominates.
px.channel.shuffleassembles its output in one routing kernel launch instead of one full-frame pass per output channel. FHD fp32 reorder shortens from 0.297 ms to 0.119 ms, multi-source with fill from 0.400 ms to 0.203 ms, andadapt=Truefrom 0.383 ms to 0.244 ms; the routing copies float32 bit patterns verbatim.- EXR DWAA / DWAB write fuses normalization, HALF rounding, forward transfer, mirror gather, and RGB to YCbCr into one kernel, and read fuses YCbCr to RGB, inverse transfer, and HALF selection. Encoded bytes and decoded bits are unchanged across compression levels, channel layouts, and input dtypes. Dedicated-GPU FHD medians shorten by 4.8% for DWAA / DWAB read and by 2.2% / 3.3% for DWAA / DWAB write.
1.2.1 - 2026-08-17
pixtreme 1.2.1 shortens seven morphology operations by 25 to 48 times, cuts match_template
FFT-path runtime nearly in half, and reduces long-path blur, procedural noise, LUT text
serialization, and white-management host composition times by 22 to 71 percent. Public
signatures, observable behavior, and output bits are unchanged; measured outputs are
byte-identical to 1.2.0 across independent verification. Absolute figures below were
remeasured on an NVIDIA RTX A6000 (WSL2, CUDA runtime 12.9, CuPy 14.1.1) with GPU 0
dedicated to a single full-suite uv run pytest -m performance run at commit 5f71032.
Changed
px.morphology.erosion(),dilation(),opening(),closing(),morphological_gradient(),white_tophat(), andblack_tophat()now load an output tile with radius halo into shared memory once per block, reduce from that shared substrate, and select disk membership from an integer row-limit cache keyed on(device, radius).morphological_gradient()fuses the min/max into a single pass and the tophat pair fuses the trailing subtraction. FHD RGB radius-5 disk cases shorten by 25 to 48 times (morphological_gradientfrom 17.16 ms to 0.36 ms;erosionanddilationfrom 8.65 ms to 0.34 ms). Channel counts above 4 or tiles exceeding 48 KiB fall back to the original global kernel unchanged.px.feature.match_template()fuses the FFT-path response reduction, centering, denominator construction, zero-variance handling, square root, and division into one RawKernel for channel counts 1 through 3. FHD RGB with a 64x64 template atccoeff_normedshortens from 24.72 ms to 13.10 ms (47.0%). Channel counts 4 and above retain the original composition path.px.generate.grain()atsize=1uses a lattice-aligned kernel that evaluates only the two contributing z-layer lattice values per channel.px.generate.fractal_noise()andpx.generate.turbulent_noise()atscale >= 16use a per-block shared gradient kernel that reuses at most 32 lattice gradients across each 16x16 output block. FHD RGB grain atintensity=0.1shortens from 12.35 ms to 3.60 ms (70.9%); FHDscale=64,octaves=4fractal and turbulent cases each shorten from about 4.4 ms to 2.16 ms (roughly 50%).px.filter.directional_blur(),zoom_blur(),spin_blur(), andvector_blur()use a noinline global fast-gather for path sample counts of 65 and above; shorter paths retain the shared-memory loop with the original gather via macro separation. Representative long-path FHD RGB cases shorten by 22 to 32% (vector_bluruniform |v|=128 from 10.78 ms to 7.30 ms;directional_blurlength=128 from 11.00 ms to 7.52 ms;zoom_bluramount=0.2 from 12.29 ms to 9.14 ms;spin_blurangle=10 from 10.38 ms to 8.07 ms).px.color.chromatic_adaptation(),px.color.white_balance(), andpx.color.white_point_simulation()memoize their pure host matrix composition in a bounded LRU (128 identities per operation) keyed on the resolved binary64 x/y values, Frame colorspace, and CAT token. FHD RGB cases shorten by 27 to 49% (white_point_simulationfrom 0.266 ms to 0.137 ms,white_balancefrom 0.281 ms to 0.157 ms,chromatic_adaptationfrom 0.238 ms to 0.148 ms), reaching the effective bandwidth of the same-shapepx.color.rgb_to_rgboperation.px.io.write_lut(),px.io.read_lut(), andpx.io.decode_lut()avoid full data-row materialization during Cube sniffing, replace repeated directive scans with a singlefinditerpass, and serialize Cube rows through a bulk zipped%soperation that preserves thestr(numpy.float32)shortest round-trip spelling. FHD RGB 65^3 Cube write shortens from 918.76 ms to 323.92 ms (64.7%), decode from 452.96 ms to 154.03 ms (66.0%), and read from 294.87 ms to 138.60 ms (53.0%).
1.2.0 - 2026-08-16
pixtreme 1.2.0 adds user-supplied fonts for text drawing, expands LUT support with 1D LUTs, new file formats, and bytes/write entry points, and introduces a white-management trio: chromatic adaptation, temperature/tint white balance, and physical white point simulation with named reference whites. The release is purely additive; public signatures and existing behavior are unchanged.
Added
px.draw.FontandFont.from_file(path, face_index=0)load user OpenType/TrueType fonts (static faces, variable fonts, and collections).px.draw.text()accepts aFontin place of the bundled font tokens, mapsweightto the font's realwghtaxis andvariationsto its other axes, and renders missing glyphs with the selected face's.notdefglyph without fallback lookup.px.core.Lut1Dis a public 1D LUT type with per-channel domains.px.color.apply_lut()acceptsLut | Lut1Dand a newlinearinterpolation token; interpolation defaults staytetrahedralfor 3D andlinearfor 1D.px.io.read_lut()additionally reads.cube1D,.3dl(Lustre and headerless dialects),.spi1d, and.spi3dfiles.px.io.decode_lut()parses LUT bytes with signature sniffing, andpx.io.write_lut()writes deterministic.cubetext for both LUT types with fullfloat32round-trip preservation.px.color.chromatic_adaptation()adapts afloat32RGB Frame between CIE 1931 xy white points usingpx.core.ChromaticAdaptationCAT tokens (bradford,cat02,cat16,von-kries; defaultcat02).px.color.white_balance()corrects a source illuminant described by temperature (Kelvin on the Planckian locus) and tint (signed Duv offset, positive toward green).px.color.white_point_simulation()physically re-encodes absolute colorimetry between display device whites (the ICC absolute-colorimetric-intent analogue) without chromatic adaptation, reducing to per-channel gain for same-primaries device pairs.px.core.ReferenceWhitenames the reference-white tokensd65,d93,d50, andaces, accepted bywhite_point_simulation()andchromatic_adaptation()alongside direct CIE 1931 xy pairs.
1.1.1 - 2026-08-14
pixtreme 1.1.1 hardens the public error contract. Out-of-contract inputs that previously leaked raw interpreter
exceptions now raise the documented actionable ValueError diagnostics. Public signatures and successful-path
behavior are unchanged.
Fixed
px.io.to_array()and the eight wire-format exporters now reject non-Frame inputs with actionableValueErrordiagnostics instead of leaking attribute errors.px.io.read_image(),write_image(),read_header(), andread_lut()now translate invalid path types into actionableValueErrordiagnostics while retaining the underlying cause.px.transform.resize()now rejects non-finite or unrepresentable factor-derived dimensions before rounding or allocation and guides callers to a smaller factor or explicit dimensions.px.composite.merge()now names its actual public path when guiding callers after a non-Frame input.- Shared finite-real validation now translates numeric conversion failures into the parameter's actionable
ValueErrorinstead of leakingOverflowError. - The
px.io.to_array()docstring now describes its function input and links topx.values.quantize()correctly.
1.1.0 - 2026-08-13
pixtreme 1.1.0 reshapes the public namespace into 13 responsibility modules with a single canonical path per
operation, adds uint32 as the fifth Frame storage dtype with end-to-end EXR UINT support, and completes the
source-fixed EXR lanes so OpenEXR is no longer a runtime dependency. It is a breaking release within the 1.x
line; the Migration section below maps every removed path to its canonical replacement. A hosted API reference
covering the full public surface accompanies this release.
Added
px.io.write_image()has a keyword-onlydtypeoption for EXR output. It acceptsfloat16,float32, oruint32; explicitly passing it for another format raisesValueError.uint32is the fifth Frame storage dtype.px.core.Frame,px.io.from_array(),px.io.to_array(frame, ...),px.values.cast_dtype(), andpx.values.recode_dtype()preserve or convert it under the same five-dtype contracts.- EXR UINT channels are supported end to end. Default reads convert integer values literally to
float32, with documented precision loss possible above2^24;unchanged=Truepreserves the originaluint32sample bits. - The EXR reader handles tiled ONE_LEVEL, MIPMAP, and RIPMAP images at full-resolution level 0, flat multi-part images, and subsampled channels. Flat channels remain readable in mixed deep/flat files; explicitly selecting a deep channel reports the unsupported part and channel.
Changed
- Breaking: Frame construction and
dataassignment now reject zero height, width, or channel count withValueError. Values operations no longer accept zero-sized Frames because such Frames cannot be constructed. - Breaking:
px.transform.resize()now rejects non-float32Frame storage withValueErrorand public value-conversion guidance instead of silently converting the input tofloat32. - The seven
px.drawoperations andpx.filter.gaussian_blur(),box_blur(),median_blur(),bilateral_blur(),directional_blur(),zoom_blur(),spin_blur(),vector_blur(),lens_blur(), andconvolve_box()now reject non-float32Frame storage withValueErrorand public value-conversion guidance, before any identity shortcut.vector_blur()applies the same check to its vector Frame. These inputs previously reached fp32 CUDA paths with undefined behavior. - Breaking: omitting
dtypewhen writing afloat32Frame to EXR now writes HALF instead of FLOAT. Passdtype="float32"to preserve FLOAT output. Auint32Frame is the only dtype that defaults to native UINT. px.io.write_image()andpx.io.encode_image()accept all five Frame storage dtypes for every supported output format. Non-EXR native container matches are preserved; other non-EXR inputs are full-scale recoded to the format's default storage. EXR uses the Frame-dependent defaults or explicitdtypeselection described above.- Breaking: the package root now exposes only 13 responsibility modules and
__version__. Types, helpers, and all 89 operations use a single canonicalpx.<module>.<leaf>path, without compatibility aliases or deprecation shims. Publishing this breaking change within the 1.x line is an intentional departure from semantic-versioning major-version rules. - I/O boundaries are grouped under
px.io; blur operations are grouped underpx.filter; quality metrics and image features are split intopx.metricsandpx.feature; histogram equalization and CLAHE are grouped underpx.color. - Frame-to-array and Frame-to-wire-format exits are
px.io.to_array(frame, ...)andpx.io.to_<format>(frame, ...)functions.px.core.Frameno longer has operation methods. - EXR read and write use source-fixed pixtreme GPU or CPU lanes for all ten compression modes: NONE, RLE, ZIPS, ZIP, PIZ, PXR24, B44, B44A, DWAA, and DWAB. OpenEXR is no longer a runtime dependency or fallback; it remains a development dependency only as a test and fixture oracle.
- Reading a subsampled channel by itself now returns its stored dimensions and samples. It no longer places samples at the start of a full-resolution buffer with an uninitialized remainder.
- Known trade-off: the current GPU writers produce larger files for ZIP (+11.5% / +28.8%), ZIPS (+4.0% / +10.3%), PXR24 (+25.2% / +38.6%), and DWA (+2.8% / +4.0%), for fp16 / fp32 respectively. Other codecs are effectively unchanged; reducing these differences is future work.
Fixed
- The GPU PIZ writer now serializes Huffman code-length tables with canonical zero-run tokens instead of writing every zero length literally. Files written by earlier versions remain valid and readable; new files are byte-identical to the canonical form and smaller for sparse code-length tables.
Removed
- Breaking: root-level
Frame,Lut,ImageHeader,channels, and the 15 root-level I/O functions were removed. - Breaking:
px.blurandpx.analyzewere removed; their operations are available only from their new canonical modules. - Breaking:
Frame.to_array()and the eightFrame.to_<format>()wire-format methods were removed.
Migration
- Pass
dtype="float32"topx.io.write_image()when EXR FLOAT precision must be preserved; omission now selects HALF for every Frame storage dtype exceptuint32. - Keep object IDs and other exact integers in a
uint32Frame. Omitdtypeor passdtype="uint32"to write native EXR UINT, and useunchanged=Trueto read the original bits. Default reads return literalfloat32values and can lose integer precision above2^24. - OpenEXR no longer needs to be installed in runtime environments. Keep it only in development environments that run the EXR oracle tests or generate fixtures.
| Previous path | New canonical path |
|---|---|
px.Frame / px.Lut / px.channels |
px.core.Frame / px.core.Lut / px.core.channels |
px.ImageHeader |
px.io.ImageHeader |
px.read_image / px.write_image / px.read_header / px.read_lut |
px.io.read_image / px.io.write_image / px.io.read_header / px.io.read_lut |
px.decode_image / px.encode_image / px.from_array |
px.io.decode_image / px.io.encode_image / px.io.from_array |
px.from_uyvy422 / px.from_v210 |
px.io.from_uyvy422 / px.io.from_v210 |
px.from_nv12 / px.from_p010 |
px.io.from_nv12 / px.io.from_p010 |
px.from_yuv420p / px.from_yuv422p |
px.io.from_yuv420p / px.io.from_yuv422p |
px.from_yuv444p / px.from_yuva444p |
px.io.from_yuv444p / px.io.from_yuva444p |
frame.to_array(...) / frame.to_<format>(...) |
px.io.to_array(frame, ...) / px.io.to_<format>(frame, ...) |
px.blur.<name> |
px.filter.<name> |
px.filter.equalize_histogram / px.filter.clahe |
px.color.equalize_histogram / px.color.clahe |
px.analyze.psnr / px.analyze.ssim / px.analyze.ssim_map |
px.metrics.psnr / px.metrics.ssim / px.metrics.ssim_map |
px.analyze.corner_harris / px.analyze.match_template |
px.feature.corner_harris / px.feature.match_template |
1.0.1 - 2026-08-06
pixtreme 1.0.1 is the first supported release of the 1.x line, a ground-up rewrite. It does not provide a compatibility layer for the 0.x API, so applications upgrading from 0.9.0 should treat 1.x as a new public API.
Added
- A single
pixtremedistribution centered on a metadata-bearing GPUFrame, with operations grouped into 12 focused modules:io,color,blur,filter,analyze,morphology,transform,draw,generate,channel,values, andcomposite. - Analytic ACES 1.3 and ACES 2.0 output transforms, explicit pre-baked LUT variants, and BT.2408 direct mapping for supported Rec.2020 HLG and PQ outputs.
- Explicit GPU format boundaries for UYVY422, v210, NV12, P010, YUV420p, YUV422p, YUV444p, and YUVA444p, alongside file, encoded-byte, and device-array boundaries.
- GPU drawing primitives including CJK text, morphology and image-analysis modules, and histogram equalization and CLAHE operations.
- A reproducible performance report covering the public GPU operation and I/O registry.
Changed
- The 0.x component distributions
pixtreme-core,pixtreme-aces,pixtreme-filter,pixtreme-draw, andpixtreme-upscaleare discontinued. Version 1.0 ships only as the singlepixtremedistribution. Framereplaces raw arrays as the primary value passed between image operations. It carries colorspace, transfer, channel, and YCbCr-matrix claims with HWC GPU data.- Public operations now use canonical module paths. The package root exports only
Frame,Lut,ImageHeader, andchannels; it no longer aggregates operation aliases from installed component packages. Framemethods are limited to exits from the Frame domain:to_array()and eightto_<format>()methods. Image processing remains in module functions.- The default channel order returned by image reading is RGB. Version 0.x returned BGR by default following the OpenCV convention; callers with BGR-specific indexing or conversion steps must update them.
- Named option tokens are case-sensitive and validated immediately. They replace the 0.x pattern of root-level interpolation, codec, template-matching, and border constants where the corresponding 1.0 operation exists.
- Floating-point working values are not implicitly clipped to
[0, 1]. Negative scene values, highlights above 1.0, and filter overshoot remain valid until an explicit quantization or clipping boundary. - CUDA array interoperability uses CuPy arrays and the DLPack protocol.
io.from_array()accepts CUDA producers, andFrameandto_array()provide the device-array exit; CPU NumPy arrays are not accepted by this boundary.
Removed
- The 0.x compatibility surface, including legacy root-level operation exports and import paths under
pixtreme_core,pixtreme_aces,pixtreme_filter,pixtreme_draw, andpixtreme_upscale. - Built-in ONNX Runtime, PyTorch, and TensorRT upscalers and model-conversion utilities. Super-resolution and inference runtime integration now belong in application-side packages built on pixtreme's DLPack and array boundaries.
- GUI lifecycle helpers such as
imshow,waitkey, anddestroy_all_windows. - Dedicated
to_numpy,to_tensor, andto_cupyconversion helpers. Host transfer uses CuPy's APIs; CUDA tensor exchange uses DLPack.
Migration
- Replace component-package dependencies and imports with the single
pixtremedistribution and canonical module paths such aspx.io.read_image,px.color.rgb_to_rgb, andpx.transform.resize. - Pass
Framevalues between operations, and cross array or encoded-format boundaries explicitly withpx.io.from_*andFrame.to_*. - Audit every image-reading call site for the BGR-to-RGB default change.
- Replace integer option constants and permissive aliases with the documented named tokens, and quantize or clip only at the intended output boundary.
1.0.0 - 2026-08-06 (yanked)
Yanked shortly after publication. Use 1.0.1 instead; the changes above describe the 1.x line.