Mercurial > hg > orthanc-stone
changeset 2174:2410a171ebfb
refactoring using DicomWebDataset and OrthancNativeDataset
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 22 Oct 2024 21:52:34 +0200 |
parents | 239fb2c893c1 |
children | 43ef60388fa2 |
files | OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp OrthancStone/Sources/Toolbox/DicomInstanceParameters.h OrthancStone/Sources/Toolbox/OrthancDatasets/DicomWebDataset.cpp OrthancStone/Sources/Toolbox/OrthancDatasets/DicomWebDataset.h OrthancStone/Sources/Toolbox/OrthancDatasets/OrthancNativeDataset.cpp OrthancStone/Sources/Toolbox/OrthancDatasets/OrthancNativeDataset.h |
diffstat | 7 files changed, 640 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Tue Oct 22 15:41:38 2024 +0200 +++ b/OrthancStone/Resources/CMake/OrthancStoneConfiguration.cmake Tue Oct 22 21:52:34 2024 +0200 @@ -226,8 +226,10 @@ list(APPEND ORTHANC_STONE_SOURCES ${ORTHANC_STONE_ROOT}/Toolbox/OrthancDatasets/DicomDatasetReader.cpp + ${ORTHANC_STONE_ROOT}/Toolbox/OrthancDatasets/DicomWebDataset.cpp ${ORTHANC_STONE_ROOT}/Toolbox/OrthancDatasets/FullOrthancDataset.cpp ${ORTHANC_STONE_ROOT}/Toolbox/OrthancDatasets/IOrthancConnection.cpp + ${ORTHANC_STONE_ROOT}/Toolbox/OrthancDatasets/OrthancNativeDataset.cpp ${ORTHANC_STONE_ROOT}/Fonts/FontRenderer.cpp ${ORTHANC_STONE_ROOT}/Fonts/Glyph.cpp
--- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp Tue Oct 22 15:41:38 2024 +0200 +++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp Tue Oct 22 21:52:34 2024 +0200 @@ -27,6 +27,9 @@ #include "../Scene2D/FloatTextureSceneLayer.h" #include "GeometryToolbox.h" #include "ImageToolbox.h" +#include "OrthancDatasets/DicomDatasetReader.h" +#include "OrthancDatasets/DicomWebDataset.h" +#include "OrthancDatasets/OrthancNativeDataset.h" #include <Images/Image.h> #include <Images/ImageProcessing.h> @@ -231,68 +234,103 @@ { instanceNumber_ = 0; } + } + void DicomInstanceParameters::InjectSequenceTags(const IDicomDataset& dataset) + { + /** + * Use DICOM tag "SequenceOfUltrasoundRegions" (0018,6011) in + * order to derive the pixel spacing on ultrasound (US) images + **/ + + static const Orthanc::DicomTag DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS(0x0018, 0x6011); + static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_UNITS_X_DIRECTION(0x0018, 0x6024); + static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_UNITS_Y_DIRECTION(0x0018, 0x6026); + static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_DELTA_X(0x0018, 0x602c); + static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_DELTA_Y(0x0018, 0x602e); + + DicomDatasetReader reader(dataset); + + size_t size; + + if (!data_.hasPixelSpacing_ && + dataset.GetSequenceSize(size, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS)) && + size == 1) + { + int directionX, directionY; + double deltaX, deltaY; + + if (reader.GetIntegerValue(directionX, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, + 0, DICOM_TAG_PHYSICAL_UNITS_X_DIRECTION)) && + reader.GetIntegerValue(directionY, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, + 0, DICOM_TAG_PHYSICAL_UNITS_Y_DIRECTION)) && + reader.GetDoubleValue(deltaX, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, + 0, DICOM_TAG_PHYSICAL_DELTA_X)) && + reader.GetDoubleValue(deltaY, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, + 0, DICOM_TAG_PHYSICAL_DELTA_Y)) && + directionX == 0x0003 && // Centimeters + directionY == 0x0003) // Centimeters + { + // Scene coordinates are expressed in millimeters => multiplication by 10 + SetPixelSpacing(10.0 * deltaX, 10.0 * deltaY); + } + } + + + /** + * New in Stone Web viewer 2.2: Deal with Philips multiframe + * (cf. mail from Tomas Kenda on 2021-08-17). This cannot be done + * in LoadSeriesDetailsFromInstance, as the "Per Frame Functional + * Groups Sequence" is not available at that point. + **/ + static const Orthanc::DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230); static const Orthanc::DicomTag DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE(0x0028, 0x9132); - const Orthanc::DicomValue* frames = dicom.TestAndGetValue(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE); - if (frames != NULL && - hasNumberOfFrames_ && - frames->IsSequence()) + if (dataset.GetSequenceSize(size, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE))) { - /** - * New in Stone Web viewer 2.2: Deal with Philips multiframe - * (cf. mail from Tomas Kenda on 2021-08-17). This cannot be done - * in LoadSeriesDetailsFromInstance, as the "Per Frame Functional Groups Sequence" - * is not available at that point. - **/ - - const Json::Value& sequence = frames->GetSequenceContent(); - - perFrameWindowing_.resize(numberOfFrames_); + data_.perFrameWindowing_.resize(data_.numberOfFrames_); // This corresponds to "ParsedDicomFile::GetDefaultWindowing()" - for (Json::ArrayIndex i = 0; i < sequence.size(); i++) + for (size_t i = 0; i < size; i++) { - if (i < numberOfFrames_ && - sequence[i].isMember(DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE.Format())) - { - const Json::Value& v = sequence[i][DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE.Format()]; - - static const char* KEY_VALUE = "Value"; + size_t tmp; + double center, width; - if (v.isMember(KEY_VALUE) && - v[KEY_VALUE].type() == Json::arrayValue && - v[KEY_VALUE].size() >= 1 && - v[KEY_VALUE][0].isMember(Orthanc::DICOM_TAG_WINDOW_CENTER.Format()) && - v[KEY_VALUE][0].isMember(Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()) && - v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()].isMember(KEY_VALUE) && - v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()].isMember(KEY_VALUE)) - { - const Json::Value& scenter = v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()][KEY_VALUE]; - const Json::Value& swidth = v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()][KEY_VALUE]; - - double center, width; - if (scenter.isString() && - swidth.isString() && - Orthanc::SerializationToolbox::ParseDouble(center, scenter.asString()) && - Orthanc::SerializationToolbox::ParseDouble(width, swidth.asString())) - { - perFrameWindowing_[i] = Windowing(center, width); - } - else if (scenter.isNumeric() && - swidth.isNumeric()) - { - perFrameWindowing_[i] = Windowing(scenter.asDouble(), swidth.asDouble()); - } - } + if (dataset.GetSequenceSize(tmp, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, + DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE)) && + tmp == 1 && + reader.GetDoubleValue(center, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, + DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE, 0, + Orthanc::DICOM_TAG_WINDOW_CENTER)) && + reader.GetDoubleValue(width, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, + DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE, 0, + Orthanc::DICOM_TAG_WINDOW_WIDTH))) + { + data_.perFrameWindowing_[i] = Windowing(center, width); } } } } + DicomInstanceParameters::DicomInstanceParameters(const DicomInstanceParameters& other) : + data_(other.data_), + tags_(other.tags_->Clone()) + { + } + + + DicomInstanceParameters::DicomInstanceParameters(const Orthanc::DicomMap& dicom) : + data_(dicom), + tags_(dicom.Clone()) + { + OrthancNativeDataset dataset(dicom); + InjectSequenceTags(dataset); + } + + double DicomInstanceParameters::GetSliceThickness() const { if (data_.hasSliceThickness_) @@ -814,38 +852,8 @@ void DicomInstanceParameters::EnrichUsingDicomWeb(const Json::Value& dicomweb) { - /** - * Use DICOM tag "SequenceOfUltrasoundRegions" (0018,6011) in - * order to derive the pixel spacing on ultrasound (US) images - **/ - - if (!data_.hasPixelSpacing_) - { - const Json::Value* region = LookupDicomWebSingleValue(dicomweb, "00186011", "SQ"); - if (region != NULL) - { - const Json::Value* physicalUnitsXDirection = LookupDicomWebSingleValue(*region, "00186024", "US"); - const Json::Value* physicalUnitsYDirection = LookupDicomWebSingleValue(*region, "00186026", "US"); - const Json::Value* physicalDeltaX = LookupDicomWebSingleValue(*region, "0018602C", "FD"); - const Json::Value* physicalDeltaY = LookupDicomWebSingleValue(*region, "0018602E", "FD"); - - if (physicalUnitsXDirection != NULL && - physicalUnitsYDirection != NULL && - physicalDeltaX != NULL && - physicalDeltaY != NULL && - physicalUnitsXDirection->type() == Json::intValue && - physicalUnitsYDirection->type() == Json::intValue && - physicalUnitsXDirection->asInt() == 0x0003 && // Centimeters - physicalUnitsYDirection->asInt() == 0x0003 && // Centimeters - physicalDeltaX->isNumeric() && - physicalDeltaY->isNumeric()) - { - // Scene coordinates are expressed in millimeters => multiplication by 10 - SetPixelSpacing(10.0 * physicalDeltaX->asDouble(), - 10.0 * physicalDeltaY->asDouble()); - } - } - } + DicomWebDataset dataset(dicomweb); + InjectSequenceTags(dataset); }
--- a/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h Tue Oct 22 15:41:38 2024 +0200 +++ b/OrthancStone/Sources/Toolbox/DicomInstanceParameters.h Tue Oct 22 21:52:34 2024 +0200 @@ -77,18 +77,12 @@ std::unique_ptr<Orthanc::DicomMap> tags_; std::unique_ptr<Orthanc::DicomImageInformation> imageInformation_; // Lazy evaluation + void InjectSequenceTags(const IDicomDataset& dataset); + public: - explicit DicomInstanceParameters(const DicomInstanceParameters& other) : - data_(other.data_), - tags_(other.tags_->Clone()) - { - } + explicit DicomInstanceParameters(const DicomInstanceParameters& other); - explicit DicomInstanceParameters(const Orthanc::DicomMap& dicom) : - data_(dicom), - tags_(dicom.Clone()) - { - } + explicit DicomInstanceParameters(const Orthanc::DicomMap& dicom); DicomInstanceParameters* Clone() const {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OrthancDatasets/DicomWebDataset.cpp Tue Oct 22 21:52:34 2024 +0200 @@ -0,0 +1,231 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "DicomWebDataset.h" + +#include <OrthancException.h> + +#include <boost/lexical_cast.hpp> + + +static const char* const VALUE = "Value"; +static const char* const VR = "vr"; +static const char* const SQ = "SQ"; +static const char* const ALPHABETIC = "Alphabetic"; + + +namespace OrthancStone +{ + static const Json::Value* GetValue(std::string& vr, + const Json::Value& node, + const Orthanc::DicomTag& tag) + { + char id[16]; + sprintf(id, "%04X%04X", tag.GetGroup(), tag.GetElement()); + + if (node.type() != Json::objectValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (!node.isMember(id)) + { + return NULL; + } + + if (node[id].type() == Json::objectValue && + node[id].isMember(VALUE) && + node[id].isMember(VR) && + node[id][VR].type() == Json::stringValue) + { + vr = node[id][VR].asString(); + return &node[id][VALUE]; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + + + static const Json::Value* GetSequenceArray(const Json::Value& node, + const Orthanc::DicomTag& tag) + { + std::string vr; + const Json::Value* value = GetValue(vr, node, tag); + + if (value != NULL && + vr == SQ && + value->type() == Json::arrayValue) + { + return value; + } + else + { + return NULL; + } + } + + + const Json::Value* DicomWebDataset::LookupValue(std::string& vr, + const Orthanc::DicomPath& path) const + { + const Json::Value* current = &dicomweb_; + + for (size_t i = 0; i < path.GetPrefixLength(); i++) + { + if (path.IsPrefixUniversal(i)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + Json::ArrayIndex index = path.GetPrefixIndex(i); + + const Json::Value* next = GetSequenceArray(*current, path.GetPrefixTag(i)); + if (next != NULL && + index < next->size()) + { + current = &((*next) [index]); + } + else + { + return NULL; + } + } + + return GetValue(vr, *current, path.GetFinalTag()); + } + + + DicomWebDataset::DicomWebDataset(const Json::Value& dicomweb) : + dicomweb_(dicomweb) + { + if (dicomweb.type() != Json::objectValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + } + + + bool DicomWebDataset::GetStringValue(std::string& result, + const Orthanc::DicomPath& path) const + { + std::string vr; + const Json::Value* value = LookupValue(vr, path); + + if (value == NULL) + { + return false; + } + else if (value->type() == Json::arrayValue && + value->size() == 1u && + (*value) [0].type() == Json::stringValue && ( + // This is the list of all the string value representations: + // https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html + vr == "AE" || + vr == "AS" || + vr == "CS" || + vr == "DA" || + vr == "DS" || + vr == "DT" || + vr == "IS" || + vr == "LO" || + vr == "LT" || + vr == "SH" || + vr == "ST" || + vr == "TM" || + vr == "UC" || + vr == "UI" || + vr == "UR" || + vr == "UT")) + { + result = (*value) [0].asString(); + return true; + } + else if (value->type() == Json::arrayValue && + value->size() == 1u && + vr == "PN" && + (*value) [0].type() == Json::objectValue && + (*value) [0].isMember(ALPHABETIC) && + (*value) [0][ALPHABETIC].type() == Json::stringValue) + { + result = (*value) [0][ALPHABETIC].asString(); + return true; + } + else if (value->type() == Json::arrayValue && + value->size() == 1u && + (vr == "FD" || vr == "FL") && + (*value) [0].isDouble()) + { + result = boost::lexical_cast<std::string>((*value) [0].asDouble()); + return true; + } + else if (value->type() == Json::arrayValue && + value->size() == 1u && + (vr == "UL" || + vr == "US") && + (*value) [0].isUInt64()) + { + result = boost::lexical_cast<std::string>((*value) [0].asUInt64()); + return true; + } + else if (value->type() == Json::arrayValue && + value->size() == 1u && + (vr == "SL" || + vr == "SS") && + (*value) [0].isInt64()) + { + result = boost::lexical_cast<std::string>((*value) [0].asInt64()); + return true; + } + else if (value->type() == Json::arrayValue && + vr == "SQ") + { + return false; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } + + + bool DicomWebDataset::GetSequenceSize(size_t& size, + const Orthanc::DicomPath& path) const + { + std::string vr; + const Json::Value* value = LookupValue(vr, path); + + if (value != NULL && + vr == SQ && + value->type() == Json::arrayValue) + { + size = value->size(); + return true; + } + else + { + return false; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OrthancDatasets/DicomWebDataset.h Tue Oct 22 21:52:34 2024 +0200 @@ -0,0 +1,49 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IDicomDataset.h" + +#include <json/value.h> + + +namespace OrthancStone +{ + class DicomWebDataset : public IDicomDataset + { + private: + Json::Value dicomweb_; + + const Json::Value* LookupValue(std::string& vr, + const Orthanc::DicomPath& path) const; + + public: + DicomWebDataset(const Json::Value& dicomweb); + + virtual bool GetStringValue(std::string& result, + const Orthanc::DicomPath& path) const ORTHANC_OVERRIDE; + virtual bool GetSequenceSize(size_t& size, + const Orthanc::DicomPath& path) const ORTHANC_OVERRIDE; + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OrthancDatasets/OrthancNativeDataset.cpp Tue Oct 22 21:52:34 2024 +0200 @@ -0,0 +1,213 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "OrthancNativeDataset.h" + +#include <OrthancException.h> + + +static const char* const NAME = "Name"; +static const char* const TYPE = "Type"; +static const char* const VALUE = "Value"; + + +namespace OrthancStone +{ + const Json::Value* OrthancNativeDataset::LookupValue(std::string& type, + const Orthanc::DicomPath& path) const + { + if (path.IsPrefixUniversal(0)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + const Orthanc::DicomValue* rootSequence = dicom_->TestAndGetValue(path.GetPrefixTag(0)); + if (rootSequence == NULL || + !rootSequence->IsSequence()) + { + return NULL; + } + + Json::ArrayIndex index = path.GetPrefixIndex(0); + + if (rootSequence->GetSequenceContent().type() != Json::arrayValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (index >= rootSequence->GetSequenceContent().size()) + { + return NULL; + } + + const Json::Value* current = &(rootSequence->GetSequenceContent() [index]); + + for (size_t i = 1; i < path.GetPrefixLength(); i++) + { + if (path.IsPrefixUniversal(i)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + index = path.GetPrefixIndex(i); + std::string tag = path.GetPrefixTag(i).Format(); + + if (current->type() != Json::objectValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (!current->isMember(tag)) + { + return NULL; + } + + if ((*current) [tag].type() != Json::objectValue || + !(*current) [tag].isMember(NAME) || + !(*current) [tag].isMember(TYPE) || + !(*current) [tag].isMember(VALUE) || + (*current) [tag][NAME].type() != Json::stringValue || + (*current) [tag][TYPE].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if ((*current) [tag][TYPE].asString() != "Sequence" || + (*current) [tag][VALUE].type() != Json::arrayValue || + index >= (*current) [tag][VALUE].size()) + { + return NULL; + } + + current = &(*current) [tag][VALUE][index]; + } + + std::string tag = path.GetFinalTag().Format(); + + if (current->type() != Json::objectValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + if (!current->isMember(tag)) + { + return NULL; + } + + if ((*current) [tag].type() != Json::objectValue || + !(*current) [tag].isMember(NAME) || + !(*current) [tag].isMember(TYPE) || + !(*current) [tag].isMember(VALUE) || + (*current) [tag][NAME].type() != Json::stringValue || + (*current) [tag][TYPE].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + else + { + type = (*current) [tag][TYPE].asString(); + return &((*current) [tag][VALUE]); + } + } + + + OrthancNativeDataset::OrthancNativeDataset(const Json::Value& dicom) : + dicom_(new Orthanc::DicomMap) + { + dicom_->FromDicomAsJson(dicom, false, true /* parse sequences */); + } + + + bool OrthancNativeDataset::GetStringValue(std::string& result, + const Orthanc::DicomPath& path) const + { + if (path.GetPrefixLength() == 0) + { + return dicom_->LookupStringValue(result, path.GetFinalTag(), false); + } + else + { + std::string type; + const Json::Value* value = LookupValue(type, path); + + if (value == NULL) + { + return false; + } + else if (type == "String" && + value->type() == Json::stringValue) + { + result = value->asString(); + return true; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } + } + + + bool OrthancNativeDataset::GetSequenceSize(size_t& size, + const Orthanc::DicomPath& path) const + { + if (path.GetPrefixLength() == 0) + { + const Orthanc::DicomValue* value = dicom_->TestAndGetValue(path.GetFinalTag()); + if (value == NULL || + !value->IsSequence()) + { + return false; + } + else if (value->GetSequenceContent().type() != Json::arrayValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + else + { + size = value->GetSequenceContent().size(); + return true; + } + } + else + { + std::string type; + const Json::Value* value = LookupValue(type, path); + + if (value == NULL || + type != "Sequence") + { + return false; + } + else if (value->type() != Json::arrayValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + else + { + size = value->size(); + return true; + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancStone/Sources/Toolbox/OrthancDatasets/OrthancNativeDataset.h Tue Oct 22 21:52:34 2024 +0200 @@ -0,0 +1,55 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., 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 Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IDicomDataset.h" + +#include <DicomFormat/DicomMap.h> + + +namespace OrthancStone +{ + class OrthancNativeDataset : public IDicomDataset + { + private: + std::unique_ptr<Orthanc::DicomMap> dicom_; + + const Json::Value* LookupValue(std::string& type, + const Orthanc::DicomPath& path) const; + + public: + OrthancNativeDataset(const Orthanc::DicomMap& dicom) : + dicom_(dicom.Clone()) + { + } + + OrthancNativeDataset(const Json::Value& dicom); + + virtual bool GetStringValue(std::string& result, + const Orthanc::DicomPath& path) const ORTHANC_OVERRIDE; + + virtual bool GetSequenceSize(size_t& size, + const Orthanc::DicomPath& path) const ORTHANC_OVERRIDE; + }; +}