v0.9.0-beta.10#

This software is in beta version, which means it is still undergoing testing and development before its official release. It may contain bugs, errors, or incomplete features that could affect its performance and functionality. By using this software, you agree to accept the risks and limitations associated with beta software. We appreciate your feedback and suggestions to help us improve this software, but we do not guarantee that we will implement them or that the software will meet your expectations. Please use this software at your own discretion and responsibility.

Key Features and Enhancements#

  • Added device_id parameter to Image.cuda() method, allowing explicit selection of the target GPU device when copying host images to device memory. When called on an image already in device memory with a different device_id, a direct device-to-device (peer-to-peer) copy is performed without going through host memory.

  • Added cuda_stream parameter to Image.cuda() method, allowing the caller to specify the CUDA stream for the data transfer.

  • Added read-only device_id property to Decoder, Encoder, and Image classes.

  • Added read-only cuda_stream property to Image class.

  • Added keyword-only precision parameter to nvimgcodec.as_image and nvimgcodec.as_images. Use it to describe lower-precision data stored in a wider container, e.g. 12-bit values held in a uint16 buffer: nvimgcodec.as_image(arr, precision=12). Accepted values are 0 (or None, both meaning “use the full bitdepth of the sample data type”) and any integer in 1..bitdepth(dtype). For floating-point dtypes only 0/None or the dtype’s full bitdepth (e.g. 32 for float32) is accepted. Defaults to None.

  • nvJPEG 2000 encoder now honors custom precision: a value set via as_image(arr, precision=N) is written into the JPEG 2000 SIZ marker and survives the bitstream round-trip.

  • Other built-in encoders log a warning when given a custom precision and continue encoding at the full type bitdepth.

  • Added keyword-only sample_format parameter to DecodeParams for driving the decoder’s output layout and channel order. Must be *_AUTO_COMPONENTS (a.k.a. *_UNCHANGED) or compatible with color_spec, otherwise a ValueError is raised. Defaults to I_AUTO_COMPONENTS.

  • Added SampleFormat.I_AUTO_COMPONENTS and SampleFormat.P_AUTO_COMPONENTS as the preferred names for the case where the caller wants to pin only the channel interleaving (I_ / P_) and let color_spec choose the components. They are exact aliases of I_UNCHANGED / P_UNCHANGED (identical values and behaviour); the older *_UNCHANGED names remain valid.

  • nvimgcodec.as_image / as_images accept planar (CHW) inputs: pass a concrete P_* format with a (C, H, W) array whose leading axis is at least the format’s arity (single-channel P_Y also accepts a 2-D (H, W) shape), or P_AUTO_COMPONENTS (P_UNCHANGED) as a layout hint with no arity constraint. Concrete interleaved formats (I_*) are similarly arity-checked against the input’s last axis.

  • Decoder.decode(..., image=) accepts multi-plane externally-managed reuse targets. Cross-layout reuse (e.g. a contiguous HWC buffer used as a CHW decode target) is allowed when the buffer is row- and plane-contiguous; layout mismatches with a padded buffer raise ValueError.

  • Added read-only num_channels property to Image, returning the total number of channels across all planes. Mirrors the existing CodeStream.num_channels property.

  • Updated CUDA 13 Docker images used to produce release binaries from CUDA Toolkit 13.0 to CUDA Toolkit 13.3.

  • Breaking change: When chroma_subsampling is not specified in EncodeParams, the default for images with at least 3 channels is now codec-dependent: JPEG uses CSS_420 (previously CSS_444), while other codecs continue to use CSS_444. Images with fewer than 3 channels still default to CSS_GRAY. The 4:2:0 JPEG default is broadly compatible and is the only mode the nvJPEG hardware encoder accepts. Pass an explicit chroma_subsampling to override - e.g. ChromaSubsampling.CSS_444 to keep full-resolution chroma for JPEG.

  • Breaking change: Image.precision and CodeStream.precision now return the full bitdepth of the sample data type (e.g. 8 for uint8, 16 for uint16) when no explicit precision is set, instead of the previous 0. Explicit precision values supplied via as_image are returned unchanged.

  • Breaking change: TIFF CodeStreamInfo::size and Python CodeStream.size now report the backing stream/file size, rather than an exact per-IFD compressed payload size. The size reported by the previous library version can be computed by using the generic TIFF metadata APIs to query the TIFF tile/strip size tags directly.

  • Breaking change: TIFF pagination and IFD selection model has been reworked:

    • limit_images has been removed.

    • bitstream_offset and image_idx now select a single IFD rather than a parse-start position, reporting num_images=1.

    • The next_bitstream_offset property was renamed to next_ifd_offset; it now exists alongside ifd_offset which reports the current offset of a selected IFD.

    • The TIFF parser keeps a cache of parsed IFDs to avoid repeated work and supports incremental parsing of the root IFD chain which is useful for very large images. See the advanced multi-image example for more details.

  • Added Torch DataLoader integration example notebook, demonstrating how to plug nvImageCodec into torch.utils.data.DataLoader for GPU-accelerated image decoding.

  • Improved nvJPEG hardware-decoder throughput on multi-engine GPUs for concurrent single-image decoding and batches with mixed chroma subsampling, including Python workloads using one Decoder per thread.

  • Breaking change: Python decoder is now using fancy_upsampling by default for JPEG (C decoder was already using it). Decoded images will now be upsampled using interpolation instead of nearest neighbor, which should improve the quality of the decoded images and make decoded images more similar to those produced by other libraries, but it may reduce the decode speed (especially for HW decoder). By default fancy upsampling with ROI decode is not enabled with nvJPEG version older than 13.2 (available in CTK 13.3) due to decode bug in nvJPEG, to enable it, pass :enable_roi_fancy_upsampling=1 option when creating decoder.

  • Updated Docker images to use the newest released nvTIFF, nvCOMP and nvJPEG2000.

Fixed Issues#

  • Pinned the nvidia-libnvcomp-cuXX dependency in the nvtiff and all extras to >=5,<6.

  • Fixed device_id not being propagated correctly when creating a Decoder or Encoder with a non-default device.

  • Fixed wrong copy direction in the strided device-to-host path of Image.cpu() that used cudaMemcpyHostToDevice instead of cudaMemcpyDeviceToHost.

  • Fixed DeviceGuard leaking a device switch when constructed in a thread or process with no current driver context.

  • Fixed coordinate-system mismatch for ROI decoding of EXIF-rotated images. When DecodeParams.apply_exif_orientation is set, nvimgcodecRegion_t is now consistently interpreted in display (post-orientation) coordinates instead of raw codestream coordinates. Previously, ROIs that fit within the display image but exceeded the raw codestream’s smaller axis (for EXIF orientations 5-8, which transpose width and height) were rejected with ROI_UNSUPPORTED.

  • Fixed a race in Encoder and Decoder where back-to-back submits on the same instance with different params (e.g. JPEG quality_value, apply_exif_orientation) could cause the first submission’s still-running worker threads to read the second submission’s params, silently producing output that did not match the requested params. Each submission now carries its own per-sample params snapshot, written only after the previous submission’s workers have drained.

  • Fixed CodeStream reuse (passing an existing CodeStream as code_stream_s= to Encoder.encode) when the existing CodeStream was created from a file or bytes. Previously the output buffer was left uninitialized in those cases, causing segfaults on the subsequent encode.

  • Fixed CUDA device handling for multi-GPU decode, encode, and image transfer paths. Internal worker threads, generic codec processing, metadata extraction, and device/pinned buffer allocation and release now establish the requested CUDA device before issuing CUDA work or invoking user allocators. Previously, work submitted for a non-current GPU could run with a different current device, causing hangs, allocations on the wrong GPU, or custom allocator/deleter calls on the wrong device.

  • Reorganized the native install layout so CUDA-major variants can coexist on the same system. The default layout is now:

    • Linux, with prefix /usr: runtime libraries in /usr/<libdir>/libnvimgcodec/<cuda_major>, extension modules in /usr/<libdir>/libnvimgcodec/<cuda_major>/extensions, runtime tools in /usr/bin/nvimgcodec/<cuda_major>, public headers in /usr/include, CMake package files in /usr/<libdir>/libnvimgcodec/<cuda_major>/cmake/nvimgcodec, package docs in /usr/share/doc/libnvimgcodec, and the loader drop-in at /etc/ld.so.conf.d/nvimgcodec-<cuda_major>.conf.

    • Windows, with prefix C:\Program Files\NVIDIA nvImageCodec: runtime DLLs and tools in bin\<cuda_major>, extension DLLs in bin\<cuda_major>\extensions, import/static libraries in lib\libnvimgcodec\<cuda_major> and lib\libnvimgcodec\<cuda_major>\extensions, headers in include, CMake package files in lib\libnvimgcodec\<cuda_major>\cmake\nvimgcodec, and docs in share\doc\libnvimgcodec.

  • Fixed CPU TIFF decoding of JPEG-compressed images that use YCbCr photometric interpretation in the libtiff extension.

  • Fixed several planar (CHW) host-device transfer and codec round-trip paths that produced truncated or misaligned planes when the buffer carried per-plane row padding

  • Hardened TIFF and JPEG 2000 parsers against malformed metadata that previously caused process-fatal SIGFPE / SIGSEGV crashes. The TIFF parser now rejects files whose ImageWidth or ImageLength is zero. The JPEG 2000 parser now rejects files whose component sub-sampling factors (XRSiz / YRSiz) are zero, and files whose JP2 ihdr image-header dimensions disagree with the codestream SIZ marker. The last case previously slipped through to the OpenCV fallback decoder and crashed inside libopencv_ext (opj_jp2_read_header).

  • Fixed silent zero-fill / Bad jpeg failures when decoding JPEG Lossless (SOF3) streams on nvJPEG older than 13.0.2, where a payload marker such as COMMENT or DHT precedes SOF3 (common in DICOM). Contributed by @bluna301 in nvImageCodec#51.

  • Hardened the OpenCV extension’s planar-to-cv::Mat conversion path to reject images with more channels than nvImageCodec supports.

  • Fixed a TIFF batched ROI performance bug for extremely large images with small tiles.

  • Fixed a crash (SIGSEGV) when a batch-only decoder (e.g. nvJPEG lossless) was reached through the single-sample fallback after a failed batch decode.

Deprecated and removed features#

  • Removed the dedicated WSL2 Ubuntu installer package. On WSL2, install the standard Linux (Ubuntu) package instead.

  • Removed support for nvTIFF versions older than 0.8.0.

  • Reworked the TIFF code-stream-view model from pagination to IFD selection:

    • limit_images has been removed

    • bitstream_offset now selects a single IFD rather than a parse-start position

    • the next_bitstream_offset property was renamed to next_ifd_offset.