# HG changeset patch # User Sebastien Jodogne # Date 1689684320 -7200 # Node ID c02d12eb34d434ac7c0c834e399f776bb6fab433 # Parent 1cc024bb662a1d179d340dc53d0e78970e0bc8b3 added LoadNifti() diff -r 1cc024bb662a -r c02d12eb34d4 CMakeLists.txt --- a/CMakeLists.txt Tue Jul 18 12:39:50 2023 +0200 +++ b/CMakeLists.txt Tue Jul 18 14:45:20 2023 +0200 @@ -62,6 +62,7 @@ SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") # Parameters to fine-tune linking against system libraries +set(USE_SYSTEM_NIFTILIB ON CACHE BOOL "Use the system version of niftilib") set(USE_SYSTEM_VTK ON CACHE BOOL "Use the system version of VTK") @@ -120,6 +121,7 @@ ##################################################################### include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibVtkConfiguration.cmake) +include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibNiftiConfiguration.cmake) add_definitions( -DHAS_ORTHANC_EXCEPTION=1 @@ -203,6 +205,7 @@ ${ORTHANC_DICOM_SOURCES_DEPENDENCIES} ${ORTHANC_DICOM_SOURCES_INTERNAL} ${ORTHANC_STL_SOURCES} + ${NIFTILIB_SOURCES} ) DefineSourceBasenameForTarget(OrthancSTL) diff -r 1cc024bb662a -r c02d12eb34d4 Resources/CMake/LibNiftiConfiguration.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/CMake/LibNiftiConfiguration.cmake Tue Jul 18 14:45:20 2023 +0200 @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: 2023 Sebastien Jodogne, UCLouvain, Belgium +# SPDX-License-Identifier: GPL-3.0-or-later + +# STL plugin for Orthanc +# Copyright (C) 2023 Sebastien Jodogne, UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +if (STATIC_BUILD OR NOT USE_SYSTEM_NIFTILIB) + set(NIFTILIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/nifti_clib-3.0.0) + DownloadPackage( + "ee40068103775a181522166e435ee82d" + "https://third-party.orthanc-labs.com/nifti_clib-3.0.0.tar.gz" + "${NIFTILIB_SOURCES_DIR}") + + include_directories( + ${NIFTILIB_SOURCES_DIR}/niftilib + ${NIFTILIB_SOURCES_DIR}/znzlib + ) + + add_definitions( + -DHAVE_ZLIB=1 + ) + + set(NIFTILIB_SOURCES + ${NIFTILIB_SOURCES_DIR}/niftilib/nifti1_io.c + ${NIFTILIB_SOURCES_DIR}/znzlib/znzlib.c + ) + +else() + find_path(NIFTILIB_INCLUDE_DIR + NAMES nifti1.h + PATHS + /usr/include + /usr/include/nifti + /usr/local/include + /usr/local/include/nifti + ) + + check_include_file(${NIFTILIB_INCLUDE_DIR}/nifti1.h HAVE_NIFTILIB_H) + if (NOT HAVE_NIFTILIB_H) + message(FATAL_ERROR "Please install the libnifti-dev package") + endif() + + include_directories(${NIFTILIB_INCLUDE_DIR}) + + link_libraries(niftiio znz) +endif() diff -r 1cc024bb662a -r c02d12eb34d4 Sources/Plugin.cpp --- a/Sources/Plugin.cpp Tue Jul 18 12:39:50 2023 +0200 +++ b/Sources/Plugin.cpp Tue Jul 18 14:45:20 2023 +0200 @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -47,6 +48,9 @@ #include +#include + + // Forward declaration void ReadStaticAsset(std::string& target, const std::string& path); @@ -1111,10 +1115,15 @@ padding->SetInputData(resize->GetOutput()); padding->Update(); + double range[2]; + padding->GetOutput()->GetScalarRange(range); + + const double isoValue = (range[0] + range[1]) / 2.0; + vtkNew surface; surface->SetInputData(padding->GetOutput()); surface->ComputeNormalsOn(); - surface->SetValue(0, 128 /*isoValue*/); + surface->SetValue(0, isoValue); surface->Update(); if (smooth) @@ -1397,6 +1406,95 @@ } + +class NiftiHeader : public boost::noncopyable +{ +private: + nifti_image* image_; + +public: + NiftiHeader(const std::string& nifti) + { + nifti_1_header header; + if (nifti.size() < sizeof(header)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + memcpy(&header, nifti.c_str(), sizeof(header)); + if (!nifti_hdr_looks_good(&header)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + image_ = nifti_convert_nhdr2nim(header, "dummy_filename"); + if (image_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + + ~NiftiHeader() + { + nifti_image_free(image_); + } + + const nifti_image& GetInfo() const + { + assert(image_ != NULL); + return *image_; + } +}; + + +static void LoadNifti(vtkImageData* volume, + std::string& nifti) +{ + if (volume == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + const uint8_t* p = reinterpret_cast(nifti.c_str()); + + if (nifti.size() >= 2 && + p[0] == 0x1f && + p[1] == 0x8b) + { + Orthanc::GzipCompressor compressor; + std::string uncompressed; + Orthanc::IBufferCompressor::Uncompress(uncompressed, compressor, nifti); + nifti.swap(uncompressed); + } + + NiftiHeader header(nifti); + + if (header.GetInfo().ndim != 3) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Only 3D NIfTI volumes are allowed"); + } + + if (header.GetInfo().datatype != DT_UNSIGNED_CHAR) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + assert(static_cast(header.GetInfo().nvox) == header.GetInfo().nx * header.GetInfo().ny * header.GetInfo().nz); + + const size_t pixelDataOffset = sizeof(nifti_1_header) + 4 /* extension */; + + if (nifti.size() != pixelDataOffset + header.GetInfo().nvox) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_CorruptedFile); + } + + volume->SetDimensions(header.GetInfo().nx, header.GetInfo().ny, header.GetInfo().nz); + volume->AllocateScalars(VTK_UNSIGNED_CHAR, 1); + volume->SetSpacing(header.GetInfo().dx, header.GetInfo().dy, header.GetInfo().dz); + memcpy(volume->GetScalarPointer(), &nifti[pixelDataOffset], header.GetInfo().nvox * sizeof(unsigned char)); +} + extern "C" { ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)