Immutable
release. Only release title and notes can be modified.
Added
- Vertical (3:4) cubemap cross layout support with automatic orientation detection. The bottom face (
-Z) follows the standard convention of being stored rotated 180°. A4R4G4B4_UNORM_PACK16support for DDS input/output.ctt::encoders::resolve_auto_encoderreturns the concrete encoderEncoder::Autowill select for a format.- Rust, CLI, and C API controls for acknowledging an intentional alpha-channel discard (
allow_discarding_alpha/--allow-discarding-alpha). The C settings struct includes the corresponding field. - C API:
CTT_PIPELINE_OUTPUT_KIND_INVALID;ctt_pipeline_output_get_kind(NULL)now returns it instead of masquerading asCTT_PIPELINE_OUTPUT_KIND_ENCODED. - C API: new example programs covering a real BC7 encode, error paths, and zero-initialized settings; all are compiled and run in CI.
- CI now builds a matrix of encoder feature combinations, catching feature/link breakage.
- README documents 2D-array assembly, cubemap arrays, 3D/volume passthrough,
--zlibsupercompression, and the per-encoder--<encoder>-opts/--help-encoderflags. - Feature-gated intra-image compression parallelism. The default-off Rust
rayonfeature uses the active Rayon pool; the CLI adds--threads, and the C API adds the process-widectt_set_thread_countconfiguration. - Conversion support for the packed 32-bit formats
E5B9G9R9_UFLOAT,B10G11R11_UFLOAT, andA2B10G10R10/A2R10G10B10(unorm, snorm, uint, sint), with scalar, SSE4.1, AVX2, AVX-512, and NEON load/store kernels. - C API:
ctt_set_log_callbackandctt_set_log_leveldeliver the library's log output to a caller-supplied callback.
Changed
- BREAKING (C ABI): enum discriminants renumbered so a zero-initialized
ctt_convert_settingsbehaves identically toctt_convert_settings_default().CTT_QUALITY_BASIC,CTT_MIPMAP_FILTER_TRIANGLE, and theCTT_CONTAINER_KTX2tag are now0; otherctt_quality/ctt_mipmap_filter/ctt_containervalues shifted. Recompile against the new header. - CLI:
--zstd/--zlibnow require=for an explicit level (--zstd=5); a bare--zstdno longer consumes the following input path. Levels are range-validated. - astcenc quality tiers are now all distinct and monotonic (
fastis no longer aliased tobasic);basicstill maps to astcenc's medium preset, so default performance is unchanged. - astcenc and Compressonator encoders now honor
Surface::stride(padded rows are repacked), matching the other backends. - Converting to an alpha-less format preserves straight-alpha RGB values by default; requesting premultiplied output still bakes alpha into RGB, and output alpha metadata now matches the requested mode.
ctt-intel-texture-compressorandctt-bc7enc-rdoemit a clearcompile_error!when built without an ISPC backend (prebuiltorbuild-from-source) instead of failing at link time.- The README library example and the crate-level quick start are now compile-checked doctests in CI.
- The in-place sRGB OETF/EOTF passes now dispatch to SSE4.1/AVX2/AVX-512/NEON kernels.
- Third-party C/C++ sources are vendored from pinned upstream commits recorded in
vendor.lock;cargo xtask vendorre-vendors or updates them.
Removed
- Removed an unused
criterionentry fromctt's[dependencies](it remains a dev-dependency), slimming downstream dependency trees. - The published prebuilt crates no longer package
*.sigstore.jsonlattestation bundles.
Fixed
- CLI: per-encoder option flags (
--bc7e-opts, etc.) were silently ignored when a bare format name (e.g.-f bc7) auto-selected the encoder; they now apply to the encoder Auto resolves to. - f32-pipeline conversions no longer silently drop existing mip levels; mipmap generation now preserves supplied levels and generates only the missing tail.
- Compressed inputs with a swizzle or mipmap request now error clearly instead of silently ignoring the request.
- Fixed R/B channel order for 16-bit packed DDS formats (
B5G6R5,B5G5R5A1,B4G4R4A4) and their legacy D3D9 equivalents, in both read and write paths. - DDS cubemaps flagged only via the DX10 header (no legacy caps2 bit) are now classified as cubemaps instead of 2D arrays.
split_cubemapvalidates its input and returns errors instead of panicking on short data or mis-divisible cross/strip dimensions.split_cubemapaccepts validated block-compressed separate faces while retaining the uncompressed requirement for cross/strip extraction.- Zero-width/height images are rejected up front instead of panicking downstream.
- f16 surfaces with odd row strides load without panicking.
- Mipmap count is clamped to the real chain length (no panic on huge counts, no duplicate 1×1 levels); mip-chain math uses integer
ilog2. - Fixed a u32 overflow in ASTC output-size allocation for very large surfaces; hardened dimension/stride math across the pipeline against integer overflow.
- 3D image validation no longer shift-panics on unusually long mip lists, and ASTC output-size/allocation failures return errors on all pointer widths.
- Fixed a bc7enc BC7 bit-packing bug: an anchor index bit-width reduction (
n--) was silently dropped because the macOS/arm64 build of ISPC miscompiles--on unsigned integers (the x86-64 build is unaffected; our macOS prebuilts are cross-built with the arm64 compiler), so every block was packed one bit too long. This caused an out-of-bounds write past each 16-byte block (memory corruption) and non-spec-compliant output (mis-sized anchor index). Unsigned decrements are now written-= 1(correct on all hosts), and the packer accumulates into twouint64words rather than scattering bytes. - C API: fixed a memory leak in
ctt_cubemap_input_separate_faceswhen aborting on a NULL face; all six faces are now consumed as documented. - C API: Rust panics in decode/convert/encode entry points are contained at the FFI boundary and reported as
CTT_STATUS_INTERNALinstead of aborting the host process. - C API: documented the enum/bool validity contract (out-of-range values are undefined behavior) and the zero-initialization guarantee in the generated header.
- CLI: I/O errors now include the file path; the CLI refuses to overwrite an input file with the output;
--cubemap-layouterrors when combined with multiple inputs instead of being silently ignored.
Security
- KTX2: a supercompressed file declaring a huge uncompressed size no longer triggers an unbounded allocation before validation (decompression bomb).
- KTX2 decoding now enforces decoded-byte and surface-count resource limits, including for otherwise self-consistent compressed headers.
- DDS/KTX2: malicious headers with absurd mip/level counts or overflowing dimensions now error cleanly instead of panicking.