# HG changeset patch # User Sebastien Jodogne # Date 1733348278 -3600 # Node ID 62dd571a40af49b145424828d0b3c1a3fce47e30 # Parent f011fc199b6aacacb0cbe08352019388c4a022a4 created OnTheFlyPyramid class diff -r f011fc199b6a -r 62dd571a40af .clang-format --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.clang-format Wed Dec 04 22:37:58 2024 +0100 @@ -0,0 +1,57 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignOperands: true +AlignTrailingComments: false +AlwaysBreakTemplateDeclarations: Yes +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: false +BreakConstructorInitializers: AfterColon +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 200 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ContinuationIndentWidth: 2 +IncludeCategories: + - Regex: '^<.*' + Priority: 1 + - Regex: '^".*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +InsertNewlineAtEOF: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +SpaceAfterCStyleCast: true +SpaceAfterTemplateKeyword: false +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +TabWidth: 2 +... diff -r f011fc199b6a -r 62dd571a40af Applications/CMakeLists.txt --- a/Applications/CMakeLists.txt Fri Oct 18 15:44:18 2024 +0200 +++ b/Applications/CMakeLists.txt Wed Dec 04 22:37:58 2024 +0100 @@ -119,6 +119,7 @@ ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidInstance.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidLevel.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/HierarchicalTiff.cpp + ${ORTHANC_WSI_DIR}/Framework/Inputs/OnTheFlyPyramid.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/OpenSlideLibrary.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/OpenSlidePyramid.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/PlainTiff.cpp diff -r f011fc199b6a -r 62dd571a40af Framework/Inputs/OnTheFlyPyramid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Inputs/OnTheFlyPyramid.cpp Wed Dec 04 22:37:58 2024 +0100 @@ -0,0 +1,122 @@ +/** +* Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "../PrecompiledHeadersWSI.h" +#include "OnTheFlyPyramid.h" + +#include + +#include +#include +#include + +#include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" + +namespace OrthancWSI +{ + void OnTheFlyPyramid::ReadRegion(Orthanc::ImageAccessor &target, + bool &isEmpty, + unsigned level, + unsigned x, + unsigned y) + { + isEmpty = false; + GetLevel(level).GetRegion(target, x, y, tileWidth_, tileHeight_); + } + + + OnTheFlyPyramid::OnTheFlyPyramid(Orthanc::ImageAccessor *baseLevel, + unsigned int tileWidth, + unsigned int tileHeight, + bool smooth) : + tileWidth_(tileWidth), + tileHeight_(tileHeight) + { + if (baseLevel == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + std::unique_ptr protection(baseLevel); + + if (protection->GetFormat() == Orthanc::PixelFormat_RGB24) + { + baseLevel_.reset(protection.release()); + } + else + { + baseLevel_.reset(new Orthanc::Image(Orthanc::PixelFormat_RGB24, protection->GetWidth(), protection->GetHeight(), false)); + Orthanc::ImageProcessing::Convert(*baseLevel_, *protection); + } + + Orthanc::ImageAccessor* current = baseLevel_.get(); + while (current->GetWidth() > tileWidth_ || + current->GetHeight() > tileHeight_) + { + std::unique_ptr next; + + if (smooth) + { + std::unique_ptr smoothed(Orthanc::Image::Clone(*current)); + Orthanc::ImageProcessing::SmoothGaussian5x5(*smoothed, false); + next.reset(Orthanc::ImageProcessing::Halve(*smoothed, false)); + } + else + { + next.reset(Orthanc::ImageProcessing::Halve(*current, false)); + } + + higherLevels_.push_back(next.release()); + current = higherLevels_.back(); + } + } + + + OnTheFlyPyramid::~OnTheFlyPyramid() + { + for (size_t i = 0; i < higherLevels_.size(); i++) + { + assert(higherLevels_[i] != NULL); + delete higherLevels_[i]; + } + } + + + const Orthanc::ImageAccessor & OnTheFlyPyramid::GetLevel(unsigned int level) const + { + if (level >= GetLevelCount()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else if (level == 0) + { + assert(baseLevel_.get() != NULL); + return *baseLevel_; + } + else + { + assert(higherLevels_[level - 1] != NULL); + return *higherLevels_[level - 1]; + } + } +} diff -r f011fc199b6a -r 62dd571a40af Framework/Inputs/OnTheFlyPyramid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Inputs/OnTheFlyPyramid.h Wed Dec 04 22:37:58 2024 +0100 @@ -0,0 +1,94 @@ +/** +* Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero 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 + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "DecodedTiledPyramid.h" + +#include + +#include + +namespace OrthancWSI +{ + class OnTheFlyPyramid : public DecodedTiledPyramid + { + private: + std::unique_ptr baseLevel_; + std::vector higherLevels_; + unsigned int tileWidth_; + unsigned int tileHeight_; + + protected: + void ReadRegion(Orthanc::ImageAccessor &target, + bool &isEmpty, + unsigned level, + unsigned x, + unsigned y) ORTHANC_OVERRIDE; + + public: + OnTheFlyPyramid(Orthanc::ImageAccessor* baseLevel /* takes ownership */, + unsigned int tileWidth, + unsigned int tileHeight, + bool smooth); + + virtual ~OnTheFlyPyramid(); + + const Orthanc::ImageAccessor& GetLevel(unsigned int level) const; + + unsigned GetLevelCount() const ORTHANC_OVERRIDE + { + return higherLevels_.size() + 1 /* base level */; + } + + unsigned GetLevelWidth(unsigned int level) const ORTHANC_OVERRIDE + { + return GetLevel(level).GetWidth(); + } + + unsigned GetLevelHeight(unsigned int level) const ORTHANC_OVERRIDE + { + return GetLevel(level).GetHeight(); + } + + unsigned GetTileWidth(unsigned int level) const ORTHANC_OVERRIDE + { + return tileWidth_; + } + + unsigned GetTileHeight(unsigned level) const ORTHANC_OVERRIDE + { + return tileHeight_; + } + + Orthanc::PixelFormat GetPixelFormat() const ORTHANC_OVERRIDE + { + return baseLevel_->GetFormat(); + } + + Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const ORTHANC_OVERRIDE + { + return Orthanc::PhotometricInterpretation_RGB; + } + }; +} diff -r f011fc199b6a -r 62dd571a40af ViewerPlugin/CMakeLists.txt --- a/ViewerPlugin/CMakeLists.txt Fri Oct 18 15:44:18 2024 +0200 +++ b/ViewerPlugin/CMakeLists.txt Wed Dec 04 22:37:58 2024 +0100 @@ -195,9 +195,11 @@ ${ORTHANC_WSI_DIR}/Framework/DicomToolbox.cpp ${ORTHANC_WSI_DIR}/Framework/Enumerations.cpp ${ORTHANC_WSI_DIR}/Framework/ImageToolbox.cpp + ${ORTHANC_WSI_DIR}/Framework/Inputs/DecodedTiledPyramid.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramid.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidInstance.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/DicomPyramidLevel.cpp + ${ORTHANC_WSI_DIR}/Framework/Inputs/OnTheFlyPyramid.cpp ${ORTHANC_WSI_DIR}/Framework/Inputs/PyramidWithRawTiles.cpp ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Reader.cpp ${ORTHANC_WSI_DIR}/Framework/Jpeg2000Writer.cpp