# HG changeset patch # User Sebastien Jodogne # Date 1689178107 -7200 # Node ID 34b507959e328299f4514bfbce43f7f5e64f7ab2 # Parent ac1508b438b1adb1746661589c72df40175ed165# Parent 77afef2cf64b1bced5eb2cd066e64719395ec586 integration mainline->iiif diff -r ac1508b438b1 -r 34b507959e32 Applications/Dicomizer.cpp --- a/Applications/Dicomizer.cpp Wed Jul 12 16:14:19 2023 +0200 +++ b/Applications/Dicomizer.cpp Wed Jul 12 18:08:27 2023 +0200 @@ -643,10 +643,10 @@ boost::program_options::options_description volumeOptions("Description of the imaged volume"); volumeOptions.add_options() - (OPTION_IMAGED_WIDTH, boost::program_options::value()->default_value(15), - "Width of the specimen (in mm)") - (OPTION_IMAGED_HEIGHT, boost::program_options::value()->default_value(15), - "Height of the specimen (in mm)") + (OPTION_IMAGED_WIDTH, boost::program_options::value(), + "Width of the specimen (in mm), defaults to 15mm if missing") + (OPTION_IMAGED_HEIGHT, boost::program_options::value(), + "Height of the specimen (in mm), defaults to 15mm if missing") (OPTION_IMAGED_DEPTH, boost::program_options::value()->default_value(1), "Depth of the specimen (in mm)") (OPTION_OFFSET_X, boost::program_options::value()->default_value(20), @@ -1010,6 +1010,7 @@ OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression, + OrthancWSI::ImagedVolumeParameters& volume, const std::string& path, const OrthancWSI::DicomizerParameters& parameters) { @@ -1072,9 +1073,26 @@ { LOG(WARNING) << "Trying to open the input pyramid with OpenSlide"; sourceCompression = OrthancWSI::ImageCompression_Unknown; - return new OrthancWSI::OpenSlidePyramid(path, - parameters.GetTargetTileWidth(512), - parameters.GetTargetTileHeight(512)); + + std::unique_ptr openslide( + new OrthancWSI::OpenSlidePyramid(path, parameters.GetTargetTileWidth(512), + parameters.GetTargetTileHeight(512))); + + float volumeWidth, volumeHeight; + if (openslide->LookupImagedVolumeSize(volumeWidth, volumeHeight)) + { + if (!volume.HasWidth()) + { + volume.SetWidth(volumeWidth); + } + + if (!volume.HasHeight()) + { + volume.SetHeight(volumeHeight); + } + } + + return openslide.release(); } catch (Orthanc::OrthancException&) { @@ -1101,7 +1119,7 @@ OrthancWSI::ImageCompression sourceCompression; std::unique_ptr source; - source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters)); + source.reset(OpenInputPyramid(sourceCompression, volume, parameters.GetInputFile(), parameters)); if (source.get() == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); diff -r ac1508b438b1 -r 34b507959e32 Framework/ImagedVolumeParameters.cpp --- a/Framework/ImagedVolumeParameters.cpp Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/ImagedVolumeParameters.cpp Wed Jul 12 18:08:27 2023 +0200 @@ -27,25 +27,54 @@ namespace OrthancWSI { - ImagedVolumeParameters::ImagedVolumeParameters() + ImagedVolumeParameters::ImagedVolumeParameters() : + hasWidth_(false), + hasHeight_(false) { - // Typical parameters of a specimen millimeters - width_ = 15; - height_ = 15; + // Typical parameters for a specimen, in millimeters depth_ = 1; offsetX_ = 20; offsetY_ = 40; } + float ImagedVolumeParameters::GetWidth() const + { + if (hasWidth_) + { + return width_; + } + else + { + return 15; // Typical width of a specimen + } + } + + + float ImagedVolumeParameters::GetHeight() const + { + if (hasHeight_) + { + return height_; + } + else + { + return 15; // Typical height of a specimen + } + } + + void ImagedVolumeParameters::SetWidth(float width) { if (width <= 0) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - - width_ = width; + else + { + width_ = width; + hasWidth_ = true; + } } @@ -55,8 +84,11 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - - height_ = height; + else + { + height_ = height; + hasHeight_ = true; + } } diff -r ac1508b438b1 -r 34b507959e32 Framework/ImagedVolumeParameters.h --- a/Framework/ImagedVolumeParameters.h Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/ImagedVolumeParameters.h Wed Jul 12 18:08:27 2023 +0200 @@ -27,6 +27,8 @@ class ImagedVolumeParameters { private: + bool hasWidth_; + bool hasHeight_; float width_; float height_; float depth_; @@ -36,15 +38,19 @@ public: ImagedVolumeParameters(); - float GetWidth() const + bool HasWidth() const { - return width_; + return hasWidth_; + } + + bool HasHeight() const + { + return hasHeight_; } - float GetHeight() const - { - return height_; - } + float GetWidth() const; + + float GetHeight() const; float GetDepth() const { diff -r ac1508b438b1 -r 34b507959e32 Framework/Inputs/OpenSlideLibrary.cpp --- a/Framework/Inputs/OpenSlideLibrary.cpp Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/Inputs/OpenSlideLibrary.cpp Wed Jul 12 18:08:27 2023 +0200 @@ -44,6 +44,8 @@ getLevelDownsample_ = (FunctionGetLevelDownsample) library_.GetFunction("openslide_get_level_downsample"); open_ = (FunctionOpen) library_.GetFunction("openslide_open"); readRegion_ = (FunctionReadRegion) library_.GetFunction("openslide_read_region"); + getPropertyNames_ = (FunctionGetPropertyNames) library_.GetFunction("openslide_get_property_names"); + getPropertyValue_ = (FunctionGetPropertyValue) library_.GetFunction("openslide_get_property_value"); } @@ -144,6 +146,27 @@ handle_(NULL) { Initialize(path); + + const char* const* properties = that_.getPropertyNames_(handle_); + if (properties == NULL) + { + that_.close_(handle_); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + for (size_t i = 0; properties[i] != NULL; i++) + { + const char* value = that_.getPropertyValue_(handle_, properties[i]); + if (value == NULL) + { + that_.close_(handle_); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + properties_[properties[i]] = value; + } + } } @@ -237,4 +260,21 @@ { globalLibrary_.reset(NULL); } + + + bool OpenSlideLibrary::Image::LookupProperty(std::string& value, + const std::string& property) const + { + std::map::const_iterator found = properties_.find(property); + + if (found == properties_.end()) + { + return false; + } + else + { + value = found->second; + return true; + } + } } diff -r ac1508b438b1 -r 34b507959e32 Framework/Inputs/OpenSlideLibrary.h --- a/Framework/Inputs/OpenSlideLibrary.h Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/Inputs/OpenSlideLibrary.h Wed Jul 12 18:08:27 2023 +0200 @@ -25,6 +25,7 @@ #include #include +#include #include namespace OrthancWSI @@ -39,6 +40,10 @@ typedef void* (*FunctionOpen) (const char*); typedef void (*FunctionReadRegion) (void*, uint32_t*, int64_t, int64_t, int32_t, int64_t, int64_t); + // New in WSI 2.0 + typedef const char* const* (*FunctionGetPropertyNames) (void*); + typedef const char* (*FunctionGetPropertyValue) (void*, const char*); + Orthanc::SharedLibrary library_; FunctionClose close_; FunctionGetLevelCount getLevelCount_; @@ -46,6 +51,8 @@ FunctionGetLevelDownsample getLevelDownsample_; FunctionOpen open_; FunctionReadRegion readRegion_; + FunctionGetPropertyNames getPropertyNames_; + FunctionGetPropertyValue getPropertyValue_; public: explicit OpenSlideLibrary(const std::string& path); @@ -72,9 +79,10 @@ double downsample); }; - OpenSlideLibrary& that_; - void* handle_; - std::vector levels_; + OpenSlideLibrary& that_; + void* handle_; + std::vector levels_; + std::map properties_; void Initialize(const std::string& path); @@ -109,6 +117,9 @@ uint64_t y, unsigned int width, unsigned int height); + + bool LookupProperty(std::string& value, + const std::string& property) const; }; }; } diff -r ac1508b438b1 -r 34b507959e32 Framework/Inputs/OpenSlidePyramid.cpp --- a/Framework/Inputs/OpenSlidePyramid.cpp Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/Inputs/OpenSlidePyramid.cpp Wed Jul 12 18:08:27 2023 +0200 @@ -26,6 +26,7 @@ #include // For std::unique_ptr #include #include +#include #include #include @@ -50,4 +51,28 @@ tileHeight_(tileHeight) { } + + + bool OpenSlidePyramid::LookupImagedVolumeSize(float& width, + float& height) const + { + std::string s; + double mppx; + double mppy; + + if (image_.LookupProperty(s, "openslide.mpp-x") && + Orthanc::SerializationToolbox::ParseDouble(mppx, s) && + image_.LookupProperty(s, "openslide.mpp-y") && + Orthanc::SerializationToolbox::ParseDouble(mppy, s)) + { + // In the 2 lines below, remember to switch X/Y when going from physical to pixel coordinates! + width = mppy / 1000.0 * static_cast(image_.GetLevelHeight(0)); + height = mppx / 1000.0 * static_cast(image_.GetLevelWidth(0)); + return true; + } + else + { + return false; + } + } } diff -r ac1508b438b1 -r 34b507959e32 Framework/Inputs/OpenSlidePyramid.h --- a/Framework/Inputs/OpenSlidePyramid.h Wed Jul 12 16:14:19 2023 +0200 +++ b/Framework/Inputs/OpenSlidePyramid.h Wed Jul 12 18:08:27 2023 +0200 @@ -79,5 +79,8 @@ { return Orthanc::PhotometricInterpretation_RGB; } + + bool LookupImagedVolumeSize(float& width, + float& height) const; }; } diff -r ac1508b438b1 -r 34b507959e32 NEWS --- a/NEWS Wed Jul 12 16:14:19 2023 +0200 +++ b/NEWS Wed Jul 12 18:08:27 2023 +0200 @@ -2,6 +2,7 @@ =============================== * Support of IIIF +* Automated extraction of the imaged volume if using OpenSlide * URI "/wsi/tiles/{id}/{z}/{x}/{y}" supports the "Accept" HTTP header to force JPEG, JPEG2k or PNG in the decoded tiles