Mercurial > hg > orthanc
changeset 2129:0c09d1af22f3
"/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 07 Nov 2016 17:44:10 +0100 |
parents | 9329ba17a069 |
children | 72cb107a7346 |
files | Core/FileStorage/FilesystemStorage.cpp Core/Toolbox.cpp Core/Toolbox.h NEWS OrthancServer/FromDcmtkBridge.cpp OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/ServerToolbox.cpp Resources/Configuration.json |
diffstat | 8 files changed, 105 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/FileStorage/FilesystemStorage.cpp Mon Nov 07 15:13:16 2016 +0100 +++ b/Core/FileStorage/FilesystemStorage.cpp Mon Nov 07 17:44:10 2016 +0100 @@ -223,9 +223,9 @@ void FilesystemStorage::Remove(const std::string& uuid, - FileContentType /*type*/) + FileContentType type) { - LOG(INFO) << "Deleting attachment \"" << uuid << "\""; + LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type); namespace fs = boost::filesystem;
--- a/Core/Toolbox.cpp Mon Nov 07 15:13:16 2016 +0100 +++ b/Core/Toolbox.cpp Mon Nov 07 17:44:10 2016 +0100 @@ -844,6 +844,23 @@ } + bool Toolbox::IsAsciiString(const void* data, + size_t size) + { + const uint8_t* p = reinterpret_cast<const uint8_t*>(data); + + for (size_t i = 0; i < size; i++, p++) + { + if (*p > 127 || (*p != 0 && iscntrl(*p))) + { + return false; + } + } + + return true; + } + + std::string Toolbox::ConvertToAscii(const std::string& source) { std::string result;
--- a/Core/Toolbox.h Mon Nov 07 15:13:16 2016 +0100 +++ b/Core/Toolbox.h Mon Nov 07 17:44:10 2016 +0100 @@ -163,6 +163,9 @@ std::string ConvertFromUtf8(const std::string& source, Encoding targetEncoding); + bool IsAsciiString(const void* data, + size_t size); + std::string ConvertToAscii(const std::string& source); std::string StripSpaces(const std::string& source);
--- a/NEWS Mon Nov 07 15:13:16 2016 +0100 +++ b/NEWS Mon Nov 07 17:44:10 2016 +0100 @@ -10,10 +10,12 @@ REST API -------- +* "/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files + (useful if private tags are registered, or if changing the default encoding) * "Permissive" flag for URI "/modalities/{...}/store" to ignore C-Store transfer errors * "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store" to avoid waiting for the completion of image transfers -* Possibility to DELETE "dicom-as-json" attachments to reconstruct them +* Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries Plugins -------
--- a/OrthancServer/FromDcmtkBridge.cpp Mon Nov 07 15:13:16 2016 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Mon Nov 07 17:44:10 2016 +0100 @@ -423,7 +423,7 @@ if (maxStringLength != 0 && utf8.size() > maxStringLength) { - return new DicomValue; // Create a NULL value + return new DicomValue; // Too long, create a NULL value } else { @@ -432,6 +432,47 @@ } } + + if (element.getVR() == EVR_UN) + { + // Unknown value representation: Lookup in the dictionary. This + // is notably the case for private tags registered with the + // "Dictionary" configuration option. + DictionaryLocker locker; + + const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(), + element.getTag().getPrivateCreator()); + if (entry != NULL && + entry->getVR().isaString()) + { + Uint8* data = NULL; + + // At (*), we do not try and convert to UTF-8, as nothing says + // the encoding of the private tag is the same as that of the + // remaining of the DICOM dataset. Only go for ASCII strings. + + if (element.getUint8Array(data) == EC_Normal && + Toolbox::IsAsciiString(data, element.getLength())) // (*) + { + if (data == NULL) + { + return new DicomValue("", false); // Empty string + } + else if (maxStringLength != 0 && + element.getLength() > maxStringLength) + { + return new DicomValue; // Too long, create a NULL value + } + else + { + std::string s(reinterpret_cast<const char*>(data), element.getLength()); + return new DicomValue(s, false); + } + } + } + } + + try { // http://support.dcmtk.org/docs/dcvr_8h-source.html @@ -758,7 +799,8 @@ if (element.isLeaf()) { - std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, maxStringLength, encoding)); + // The "0" below lets "LeafValueToJson()" take care of "TooLong" values + std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding)); LeafValueToJson(target, *v, format, flags, maxStringLength); } else
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Mon Nov 07 15:13:16 2016 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Mon Nov 07 17:44:10 2016 +0100 @@ -1354,6 +1354,32 @@ } + static void InvalidateTags(RestApiPostCall& call) + { + ServerIndex& index = OrthancRestApi::GetIndex(call); + + // Loop over the instances, grouping them by parent studies so as + // to avoid large memory consumption + std::list<std::string> studies; + index.GetAllUuids(studies, ResourceType_Study); + + for (std::list<std::string>::const_iterator + study = studies.begin(); study != studies.end(); ++study) + { + std::list<std::string> instances; + index.GetChildInstances(instances, *study); + + for (std::list<std::string>::const_iterator + instance = instances.begin(); instance != instances.end(); ++instance) + { + index.DeleteAttachment(*instance, FileContentType_DicomAsJson); + } + } + + call.GetOutput().AnswerBuffer("", "text/plain"); + } + + void OrthancRestApi::RegisterResources() { Register("/instances", ListResources<ResourceType_Instance>); @@ -1428,6 +1454,7 @@ Register("/{resourceType}/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression<CompressionType_None>); Register("/{resourceType}/{id}/attachments/{name}/verify-md5", VerifyAttachment); + Register("/tools/invalidate-tags", InvalidateTags); Register("/tools/lookup", Lookup); Register("/tools/find", Find);
--- a/OrthancServer/ServerToolbox.cpp Mon Nov 07 15:13:16 2016 +0100 +++ b/OrthancServer/ServerToolbox.cpp Mon Nov 07 17:44:10 2016 +0100 @@ -334,6 +334,13 @@ { // WARNING: The database should be locked with a transaction! + // TODO: This function might consume much memory if level == + // ResourceType_Instance. To improve this, first download the + // list of studies, then remove the instances for each single + // study (check out OrthancRestApi::InvalidateTags for an + // example). Take this improvement into consideration for the + // next upgrade of the database schema. + const char* plural = NULL; switch (level)
--- a/Resources/Configuration.json Mon Nov 07 15:13:16 2016 +0100 +++ b/Resources/Configuration.json Mon Nov 07 17:44:10 2016 +0100 @@ -326,6 +326,7 @@ // possibly the Private Creator (for private tags). "Dictionary" : { // "0014,1020" : [ "DA", "ValidationExpiryDate", 1, 1 ] - // "00e1,10c2" : [ "SH", "PET-CT Multi Modality Name", 1, 1, "ELSCINT1" ] + // "00e1,10c2" : [ "UI", "PET-CT Multi Modality Name", 1, 1, "ELSCINT1" ], + // "7053,1003" : [ "ST", "Original Image Filename", 1, 1, "Philips PET Private Group" ] } }