# HG changeset patch # User Sebastien Jodogne # Date 1687091824 -7200 # Node ID e8dea04df69ba60e6cc05de5bef57e25a4f2358e # Parent cc4c81d08bf0de4d4ae6402399571a0b86fde937 caching OHIF dicom-json as metadata diff -r cc4c81d08bf0 -r e8dea04df69b CMakeLists.txt --- a/CMakeLists.txt Sun Jun 18 13:48:13 2023 +0200 +++ b/CMakeLists.txt Sun Jun 18 14:37:04 2023 +0200 @@ -32,6 +32,8 @@ set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web") endif() +set(METADATA_VERSION 1) + ##################################################################### ## Parameters of the build @@ -109,6 +111,7 @@ -DORTHANC_ENABLE_LOGGING_PLUGIN=1 -DORTHANC_FRAMEWORK_BUILDING_PLUGIN=1 -DORTHANC_OHIF_VERSION="${ORTHANC_OHIF_VERSION}" + -DMETADATA_VERSION=${METADATA_VERSION} ) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR diff -r cc4c81d08bf0 -r e8dea04df69b Sources/OrthancExplorer.js --- a/Sources/OrthancExplorer.js Sun Jun 18 13:48:13 2023 +0200 +++ b/Sources/OrthancExplorer.js Sun Jun 18 14:37:04 2023 +0200 @@ -70,7 +70,7 @@ if (${USE_DICOM_WEB}) { window.open('../ohif/viewer?StudyInstanceUIDs=' + studyInstanceUid); } else { - window.open('../ohif/viewer?url=../ohif-source/' + studyId); + window.open('../ohif/viewer?url=../studies/' + studyId + '/ohif-dicom-json'); } }); @@ -78,7 +78,7 @@ if (${USE_DICOM_WEB}) { window.open('../ohif/viewer?hangingprotocolId=mprAnd3DVolumeViewport&StudyInstanceUIDs=' + studyInstanceUid); } else { - window.open('../ohif/viewer?hangingprotocolId=mprAnd3DVolumeViewport&url=../ohif-source/' + studyId); + window.open('../ohif/viewer?hangingprotocolId=mprAnd3DVolumeViewport&url=../studies/' + studyId + '/ohif-dicom-json'); } }); @@ -86,7 +86,7 @@ if (${USE_DICOM_WEB}) { window.open('../ohif/tmtv?StudyInstanceUIDs=' + studyInstanceUid); } else { - window.open('../ohif/tmtv?url=../ohif-source/' + studyId); + window.open('../ohif/tmtv?url=../studies/' + studyId + '/ohif-dicom-json'); } }); diff -r cc4c81d08bf0 -r e8dea04df69b Sources/Plugin.cpp --- a/Sources/Plugin.cpp Sun Jun 18 13:48:13 2023 +0200 +++ b/Sources/Plugin.cpp Sun Jun 18 14:37:04 2023 +0200 @@ -37,6 +37,10 @@ #include +static const std::string METADATA_OHIF = "4202"; +static const char* const KEY_VERSION = "Version"; + + // Reference: https://v3-docs.ohif.org/configuration/dataSources/dicom-json enum DataType @@ -350,57 +354,131 @@ } -static bool GetOhifDicomTags(Json::Value& target, - const std::string& instanceId) +static bool EncodeOhifInstance(Json::Value& target, + const std::string& instanceId) { Json::Value source; if (!OrthancPlugins::RestApiGet(source, "/instances/" + instanceId + "/tags?short", false)) { return false; } - - if (source.type() != Json::objectValue) + else if (source.type() != Json::objectValue) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } + else + { + target[KEY_VERSION] = static_cast(METADATA_VERSION); + + for (TagsDictionary::const_iterator it = allTags_.begin(); it != allTags_.end(); ++it) + { + ParseTagFromOrthanc(target, it->first, it->first.Format(), it->second.GetType(), source); + } - for (TagsDictionary::const_iterator it = allTags_.begin(); it != allTags_.end(); ++it) + /** + * This is a sequence for PET scans that is manually injected, to be + * used in function "getPTImageIdInstanceMetadata()" of + * "extensions/default/src/getPTImageIdInstanceMetadata.ts" + **/ + static const Orthanc::DicomTag RADIONUCLIDE_HALF_LIFE(0x0018, 0x1075); + static const Orthanc::DicomTag RADIONUCLIDE_TOTAL_DOSE(0x0018, 0x1074); + static const Orthanc::DicomTag RADIOPHARMACEUTICAL_START_DATETIME(0x0018, 0x1078); + static const Orthanc::DicomTag RADIOPHARMACEUTICAL_START_TIME(0x0018, 0x1072); + + if (source.isMember(RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format())) + { + const Json::Value& pharma = source[RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format()]; + if (pharma.type() == Json::arrayValue && + pharma.size() > 0 && + pharma[0].type() == Json::objectValue) + { + Json::Value info; + if (ParseTagFromOrthanc(info, RADIONUCLIDE_HALF_LIFE, "RadionuclideHalfLife", DataType_Float, pharma[0]) && + ParseTagFromOrthanc(info, RADIONUCLIDE_TOTAL_DOSE, "RadionuclideTotalDose", DataType_Float, pharma[0]) && + (ParseTagFromOrthanc(info, RADIOPHARMACEUTICAL_START_DATETIME, "RadiopharmaceuticalStartDateTime", DataType_String, pharma[0]) || + ParseTagFromOrthanc(info, RADIOPHARMACEUTICAL_START_TIME, "RadiopharmaceuticalStartTime", DataType_String, pharma[0]))) + { + Json::Value sequence = Json::arrayValue; + sequence.append(info); + + target[RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format()] = sequence; + } + } + } + + return true; + } +} + + +static std::string GetCacheUri(const std::string& instanceId) +{ + return "/instances/" + instanceId + "/metadata/" + METADATA_OHIF; +} + + +static void CacheAsMetadata(const Json::Value& instanceTags, + const std::string& instanceId) +{ + std::string uncompressed; + Orthanc::Toolbox::WriteFastJson(uncompressed, instanceTags); + + std::string compressed; + Orthanc::GzipCompressor compressor; + Orthanc::IBufferCompressor::Compress(compressed, compressor, uncompressed); + + std::string metadata; + Orthanc::Toolbox::EncodeBase64(metadata, compressed); + + Json::Value answer; + OrthancPlugins::RestApiPut(answer, GetCacheUri(instanceId), metadata.c_str(), metadata.size(), false); +} + + +static bool GetOhifInstance(Json::Value& target, + const std::string& instanceId) +{ + const std::string uri = GetCacheUri(instanceId); + + std::string metadata; + + if (OrthancPlugins::RestApiGetString(metadata, uri, false)) { - ParseTagFromOrthanc(target, it->first, it->first.Format(), it->second.GetType(), source); + try + { + std::string compressed; + Orthanc::Toolbox::DecodeBase64(compressed, metadata); + + std::string uncompressed; + Orthanc::GzipCompressor compressor; + Orthanc::IBufferCompressor::Uncompress(uncompressed, compressor, compressed); + + if (Orthanc::Toolbox::ReadJson(target, uncompressed) && + target.isMember(KEY_VERSION) && + target[KEY_VERSION].type() == Json::intValue && + target[KEY_VERSION].asInt() == METADATA_VERSION) + { + // Success, we can reuse the cached value + return true; + } + } + catch (Orthanc::OrthancException&) + { + } + + // Remove corrupted or metadata with an earlier version + OrthancPlugins::RestApiDelete(uri, false); } - /** - * This is a sequence for PET scans that is manually injected, to be - * used in function "getPTImageIdInstanceMetadata()" of - * "extensions/default/src/getPTImageIdInstanceMetadata.ts" - **/ - static const Orthanc::DicomTag RADIONUCLIDE_HALF_LIFE(0x0018, 0x1075); - static const Orthanc::DicomTag RADIONUCLIDE_TOTAL_DOSE(0x0018, 0x1074); - static const Orthanc::DicomTag RADIOPHARMACEUTICAL_START_DATETIME(0x0018, 0x1078); - static const Orthanc::DicomTag RADIOPHARMACEUTICAL_START_TIME(0x0018, 0x1072); - - if (source.isMember(RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format())) + if (EncodeOhifInstance(target, instanceId)) { - const Json::Value& pharma = source[RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format()]; - if (pharma.type() == Json::arrayValue && - pharma.size() > 0 && - pharma[0].type() == Json::objectValue) - { - Json::Value info; - if (ParseTagFromOrthanc(info, RADIONUCLIDE_HALF_LIFE, "RadionuclideHalfLife", DataType_Float, pharma[0]) && - ParseTagFromOrthanc(info, RADIONUCLIDE_TOTAL_DOSE, "RadionuclideTotalDose", DataType_Float, pharma[0]) && - (ParseTagFromOrthanc(info, RADIOPHARMACEUTICAL_START_DATETIME, "RadiopharmaceuticalStartDateTime", DataType_String, pharma[0]) || - ParseTagFromOrthanc(info, RADIOPHARMACEUTICAL_START_TIME, "RadiopharmaceuticalStartTime", DataType_String, pharma[0]))) - { - Json::Value sequence = Json::arrayValue; - sequence.append(info); - - target[RADIOPHARMACEUTICAL_INFORMATION_SEQUENCE.Format()] = sequence; - } - } + CacheAsMetadata(target, instanceId); + return true; } - - return true; + else + { + return false; + } } @@ -490,7 +568,7 @@ } Json::Value t; - if (GetOhifDicomTags(t, instancesIds[i][KEY_ID].asString())) + if (GetOhifInstance(t, instancesIds[i][KEY_ID].asString())) { instancesTags.push_back(t); } @@ -717,7 +795,7 @@ OrthancPlugins::RegisterRestCallback("/ohif", true); OrthancPlugins::RegisterRestCallback("/ohif/(.*)", true); - OrthancPlugins::RegisterRestCallback("/ohif-source/(.*)", true); + OrthancPlugins::RegisterRestCallback("/studies/([0-9a-f-]+)/ohif-dicom-json", true); OrthancPluginRegisterOnChangeCallback(context, OnChangeCallback);