Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
70e0e73
cuslide2: add OME-TIFF semantics and nvImageCodec 0.9 support
cdinea Jul 22, 2026
57aa615
cuslide2: harden nvimgcodec 0.9 OME parsing path
cdinea Jul 27, 2026
9bd44b8
fix(cuslide2): restore decoder thread-count heuristic
cdinea Jul 29, 2026
0912636
fix(cuslide2): require nvImageCodec 0.9 in dependency discovery
cdinea Jul 29, 2026
ce00b56
fix(cuslide2): sync vendored nvImageCodec headers with 0.9.0
cdinea Jul 29, 2026
d7c0023
fix(cuslide2): widen row stride arithmetic to 64-bit
cdinea Jul 29, 2026
1328a76
fix(cuslide2): restore zero-downsample guard in Philips metadata
cdinea Jul 29, 2026
bafbdb5
fix(cuslide2): bound associated-image scan to image description
cdinea Jul 29, 2026
eac5aee
fix(cuslide2): own channel names as strings while building
cdinea Jul 29, 2026
84fe4ed
test(cuslide2): strengthen pyramidal OME-TIFF validation
cdinea Jul 29, 2026
aef0ca1
style(cuslide2): satisfy pre-commit copyright and codespell checks
cdinea Jul 29, 2026
15752d3
test(cuslide2): cover uint16 pyramidal OME-TIFF decode
cdinea Jul 29, 2026
aeca33b
fix(cuslide2): correct pyramid geometry assertions in OME-TIFF test
cdinea Jul 29, 2026
1563e4c
fix(cuslide2): report TIFF resolution and preserve OME pyramid levels
cdinea Jul 30, 2026
0914c4a
fix(cuslide2): stop aborting in free() during process exit
cdinea Jul 30, 2026
729d27a
fix(cuslide2): return background for fully out-of-bounds regions
cdinea Jul 30, 2026
e011f44
docs(cuslide2): drop references to unsupported nvImageCodec versions
cdinea Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions conda/environments/all_cuda-129_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ dependencies:
- imagecodecs>=2021.6.8
- ipython
- lazy-loader>=0.4
- libnvimgcodec-dev>=0.8.0,<0.9.0
- libnvimgcodec>=0.8.0,<0.9.0
- libnvimgcodec-dev>=0.9.0,<0.10.0
- libnvimgcodec>=0.9.0,<0.10.0
- libnvjpeg-dev
- matplotlib-base>=3.7
- nbsphinx
- ninja
- numpy>=2.0,<3.0
- numpydoc>=1.7
- nvimgcodec>=0.8.0,<0.9.0
- nvimgcodec>=0.9.0,<0.10.0
- openslide-python>=1.3.0
- pip
- pooch>=1.6.0
Expand Down
6 changes: 3 additions & 3 deletions conda/environments/all_cuda-129_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ dependencies:
- ipython
- lazy-loader>=0.4
- libcufile-dev
- libnvimgcodec-dev>=0.8.0,<0.9.0
- libnvimgcodec>=0.8.0,<0.9.0
- libnvimgcodec-dev>=0.9.0,<0.10.0
- libnvimgcodec>=0.9.0,<0.10.0
- libnvjpeg-dev
- matplotlib-base>=3.7
- nbsphinx
- ninja
- numpy>=2.0,<3.0
- numpydoc>=1.7
- nvimgcodec>=0.8.0,<0.9.0
- nvimgcodec>=0.9.0,<0.10.0
- openslide-python>=1.3.0
- pip
- pooch>=1.6.0
Expand Down
6 changes: 3 additions & 3 deletions conda/environments/all_cuda-133_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ dependencies:
- imagecodecs>=2021.6.8
- ipython
- lazy-loader>=0.4
- libnvimgcodec-dev>=0.8.0,<0.9.0
- libnvimgcodec>=0.8.0,<0.9.0
- libnvimgcodec-dev>=0.9.0,<0.10.0
- libnvimgcodec>=0.9.0,<0.10.0
- libnvjpeg-dev
- matplotlib-base>=3.7
- nbsphinx
- ninja
- numpy>=2.0,<3.0
- numpydoc>=1.7
- nvimgcodec>=0.8.0,<0.9.0
- nvimgcodec>=0.9.0,<0.10.0
- openslide-python>=1.3.0
- pip
- pooch>=1.6.0
Expand Down
6 changes: 3 additions & 3 deletions conda/environments/all_cuda-133_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ dependencies:
- ipython
- lazy-loader>=0.4
- libcufile-dev
- libnvimgcodec-dev>=0.8.0,<0.9.0
- libnvimgcodec>=0.8.0,<0.9.0
- libnvimgcodec-dev>=0.9.0,<0.10.0
- libnvimgcodec>=0.9.0,<0.10.0
- libnvjpeg-dev
- matplotlib-base>=3.7
- nbsphinx
- ninja
- numpy>=2.0,<3.0
- numpydoc>=1.7
- nvimgcodec>=0.8.0,<0.9.0
- nvimgcodec>=0.9.0,<0.10.0
- openslide-python>=1.3.0
- pip
- pooch>=1.6.0
Expand Down
2 changes: 1 addition & 1 deletion conda/recipes/libcucim/conda_build_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ cmake_version:
- ">=4.0"

nvimgcodec_version:
- ">=0.8.0,<0.9.0"
- ">=0.9.0,<0.10.0"
110 changes: 85 additions & 25 deletions cpp/cmake/deps/nvimgcodec.cmake
Original file line number Diff line number Diff line change
@@ -1,19 +1,83 @@
#
# cmake-format: off
# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
# cmake-format: on
#

if (NOT TARGET deps::nvimgcodec)
# Packaging pins nvImageCodec to >=0.9.0,<0.10.0 and the vendored headers
# declare 0.9, so only 0.9 is supported here. The unversioned entries are
# kept for wheel and system layouts that ship just the symlinks.
set(NVIMGCODEC_SONAME_CANDIDATES
"libnvimgcodec.so.0.9.0"
"libnvimgcodec.so.0"
"libnvimgcodec.so")

function(_cucim_find_nvimgcodec_library out_var root_dir)
foreach(_soname IN LISTS NVIMGCODEC_SONAME_CANDIDATES)
if(EXISTS "${root_dir}/${_soname}")
set(${out_var} "${root_dir}/${_soname}" PARENT_SCOPE)
return()
endif()
endforeach()
set(${out_var} "" PARENT_SCOPE)
endfunction()

# The unversioned "libnvimgcodec.so.0" / "libnvimgcodec.so" candidates above
# resolve to whatever major-0 build is installed, so a version below the
# required minimum would otherwise be picked up silently. That API is not
# compatible and there are no compile-time version guards, so fail at
# configure time instead of at runtime.
function(_cucim_check_nvimgcodec_version include_dir)
set(_version_header "${include_dir}/nvimgcodec_version.h")
if(NOT EXISTS "${_version_header}")
message(WARNING
"nvImageCodec: nvimgcodec_version.h not found under '${include_dir}' - "
"skipping version check. cuCIM requires >=0.9.0,<0.10.0.")
return()
endif()

file(STRINGS "${_version_header}" _major_line
REGEX "^#define[ \t]+NVIMGCODEC_VER_MAJOR[ \t]+[0-9]+")
file(STRINGS "${_version_header}" _minor_line
REGEX "^#define[ \t]+NVIMGCODEC_VER_MINOR[ \t]+[0-9]+")
string(REGEX REPLACE ".*NVIMGCODEC_VER_MAJOR[ \t]+([0-9]+).*" "\\1" _major "${_major_line}")
string(REGEX REPLACE ".*NVIMGCODEC_VER_MINOR[ \t]+([0-9]+).*" "\\1" _minor "${_minor_line}")

if(NOT _major MATCHES "^[0-9]+$" OR NOT _minor MATCHES "^[0-9]+$")
message(WARNING
"nvImageCodec: could not parse version from '${_version_header}' - "
"skipping version check.")
return()
endif()

if(_major EQUAL 0 AND _minor LESS 9)
message(FATAL_ERROR
"nvImageCodec ${_major}.${_minor} found at '${include_dir}', but cuCIM "
"requires >=0.9.0 (packaging pins >=0.9.0,<0.10.0). The 0.9 API is not "
"backward compatible and this build has no compile-time version guards, "
"so it would fail at runtime. Install libnvimgcodec-dev >=0.9.")
elseif(_major GREATER 0 OR _minor GREATER_EQUAL 10)
message(WARNING
"nvImageCodec ${_major}.${_minor} is outside the pinned range "
"(>=0.9.0,<0.10.0) and is untested with this cuCIM build.")
endif()
endfunction()

# First try to find it as a package
find_package(nvimgcodec QUIET)

if(nvimgcodec_FOUND)
# Use the found package
if(DEFINED nvimgcodec_VERSION AND nvimgcodec_VERSION VERSION_LESS "0.9.0")
message(FATAL_ERROR
"nvImageCodec ${nvimgcodec_VERSION} found via find_package, but cuCIM "
"requires >=0.9.0 (packaging pins >=0.9.0,<0.10.0).")
endif()
add_library(deps::nvimgcodec INTERFACE IMPORTED GLOBAL)
target_link_libraries(deps::nvimgcodec INTERFACE nvimgcodec::nvimgcodec)
message(STATUS "βœ“ nvImageCodec found via find_package")
message(STATUS "βœ“ nvImageCodec found via find_package (version: ${nvimgcodec_VERSION})")
else()
# Manual detection in various environments
set(NVIMGCODEC_LIB_PATH "")
Expand All @@ -22,31 +86,23 @@ if (NOT TARGET deps::nvimgcodec)
# Try conda environment detection (both Python packages and native packages)
if(DEFINED ENV{CONDA_BUILD})
# Conda build environment
set(NVIMGCODEC_LIB_PATH "$ENV{PREFIX}/lib/libnvimgcodec.so.0")
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "$ENV{PREFIX}/lib")
set(NVIMGCODEC_INCLUDE_PATH "$ENV{PREFIX}/include/")
if(NOT EXISTS "${NVIMGCODEC_LIB_PATH}")
set(NVIMGCODEC_LIB_PATH "$ENV{PREFIX}/lib/libnvimgcodec.so")
endif()
elseif(DEFINED ENV{CONDA_PREFIX})
# Active conda environment - try native package first
set(CONDA_NATIVE_ROOT "$ENV{CONDA_PREFIX}")
if(EXISTS "${CONDA_NATIVE_ROOT}/include/nvimgcodec.h")
set(NVIMGCODEC_INCLUDE_PATH "${CONDA_NATIVE_ROOT}/include/")
if(EXISTS "${CONDA_NATIVE_ROOT}/lib/libnvimgcodec.so.0")
set(NVIMGCODEC_LIB_PATH "${CONDA_NATIVE_ROOT}/lib/libnvimgcodec.so.0")
elseif(EXISTS "${CONDA_NATIVE_ROOT}/lib/libnvimgcodec.so")
set(NVIMGCODEC_LIB_PATH "${CONDA_NATIVE_ROOT}/lib/libnvimgcodec.so")
endif()
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "${CONDA_NATIVE_ROOT}/lib")
else()
# Fallback: try Python site-packages in conda environment
foreach(PY_VER "3.13" "3.12" "3.11" "3.10" "3.9")
set(CONDA_PYTHON_ROOT "$ENV{CONDA_PREFIX}/lib/python${PY_VER}/site-packages/nvidia/nvimgcodec")
if(EXISTS "${CONDA_PYTHON_ROOT}/include/nvimgcodec.h")
set(NVIMGCODEC_INCLUDE_PATH "${CONDA_PYTHON_ROOT}/include/")
if(EXISTS "${CONDA_PYTHON_ROOT}/lib/libnvimgcodec.so.0")
set(NVIMGCODEC_LIB_PATH "${CONDA_PYTHON_ROOT}/lib/libnvimgcodec.so.0")
elseif(EXISTS "${CONDA_PYTHON_ROOT}/lib/libnvimgcodec.so")
set(NVIMGCODEC_LIB_PATH "${CONDA_PYTHON_ROOT}/lib/libnvimgcodec.so")
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "${CONDA_PYTHON_ROOT}/lib")
if(NOT NVIMGCODEC_LIB_PATH)
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "${CONDA_PYTHON_ROOT}")
endif()
break()
endif()
Expand All @@ -67,32 +123,36 @@ if (NOT TARGET deps::nvimgcodec)
set(NVIMGCODEC_PYTHON_ROOT "${PYTHON_SITE_PACKAGES}/nvidia/nvimgcodec")
if(EXISTS "${NVIMGCODEC_PYTHON_ROOT}/include/nvimgcodec.h")
set(NVIMGCODEC_INCLUDE_PATH "${NVIMGCODEC_PYTHON_ROOT}/include/")
if(EXISTS "${NVIMGCODEC_PYTHON_ROOT}/lib/libnvimgcodec.so.0")
set(NVIMGCODEC_LIB_PATH "${NVIMGCODEC_PYTHON_ROOT}/lib/libnvimgcodec.so.0")
elseif(EXISTS "${NVIMGCODEC_PYTHON_ROOT}/lib/libnvimgcodec.so")
set(NVIMGCODEC_LIB_PATH "${NVIMGCODEC_PYTHON_ROOT}/lib/libnvimgcodec.so")
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "${NVIMGCODEC_PYTHON_ROOT}/lib")
if(NOT NVIMGCODEC_LIB_PATH)
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "${NVIMGCODEC_PYTHON_ROOT}")
endif()
endif()
endif()
endif()

# System-wide installation fallback
if(NOT NVIMGCODEC_LIB_PATH)
if(EXISTS /usr/lib/x86_64-linux-gnu/libnvimgcodec.so.0)
set(NVIMGCODEC_LIB_PATH /usr/lib/x86_64-linux-gnu/libnvimgcodec.so.0)
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "/usr/lib/x86_64-linux-gnu")
if(NVIMGCODEC_LIB_PATH)
set(NVIMGCODEC_INCLUDE_PATH "/usr/include/")
elseif(EXISTS /usr/lib/aarch64-linux-gnu/libnvimgcodec.so.0)
set(NVIMGCODEC_LIB_PATH /usr/lib/aarch64-linux-gnu/libnvimgcodec.so.0)
else()
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "/usr/lib/aarch64-linux-gnu")
endif()
if(NVIMGCODEC_LIB_PATH)
set(NVIMGCODEC_INCLUDE_PATH "/usr/include/")
elseif(EXISTS /usr/lib64/libnvimgcodec.so.0) # CentOS (x86_64)
set(NVIMGCODEC_LIB_PATH /usr/lib64/libnvimgcodec.so.0)
else()
_cucim_find_nvimgcodec_library(NVIMGCODEC_LIB_PATH "/usr/lib64") # CentOS (x86_64)
endif()
if(NVIMGCODEC_LIB_PATH)
set(NVIMGCODEC_INCLUDE_PATH "/usr/include/")
endif()
endif()
endif()

# Create the target if we found the library
if(NVIMGCODEC_LIB_PATH AND EXISTS "${NVIMGCODEC_LIB_PATH}")
_cucim_check_nvimgcodec_version("${NVIMGCODEC_INCLUDE_PATH}")
add_library(deps::nvimgcodec SHARED IMPORTED GLOBAL)
set_target_properties(deps::nvimgcodec PROPERTIES
IMPORTED_LOCATION "${NVIMGCODEC_LIB_PATH}"
Expand Down
2 changes: 2 additions & 0 deletions cpp/plugins/cucim.kit.cuslide2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ set(CUSLIDE2_CORE_SOURCES
# TIFF structure management (uses nvImageCodec for parsing)
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/ifd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/ifd.h
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/ome_xml.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/ome_xml.h
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/tiff.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/tiff.h
${CMAKE_CURRENT_SOURCE_DIR}/src/cuslide/tiff/types.h
Expand Down
Loading