# HG changeset patch # User Sebastien Jodogne # Date 1448382277 -3600 # Node ID 2d8191b135674fc6c18a7040f844790c6e312a58 # Parent 87c069c94ac92c30d24186af62050124cb557d52# Parent 84f0a118a72ca68750612497a4ddaa8072ebbf5d integration worklists->mainline diff -r 87c069c94ac9 -r 2d8191b13567 Core/DicomFormat/DicomTag.h --- a/Core/DicomFormat/DicomTag.h Tue Nov 24 13:36:08 2015 +0100 +++ b/Core/DicomFormat/DicomTag.h Tue Nov 24 17:24:37 2015 +0100 @@ -66,6 +66,11 @@ return element_; } + bool IsPrivate() const + { + return group_ % 2 == 1; + } + const char* GetMainTagsName() const; bool operator< (const DicomTag& other) const; diff -r 87c069c94ac9 -r 2d8191b13567 Core/Toolbox.cpp --- a/Core/Toolbox.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/Core/Toolbox.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -554,6 +554,14 @@ } # endif + + void Toolbox::EncodeDataUriScheme(std::string& result, + const std::string& mime, + const std::string& content) + { + result = "data:" + mime + ";base64," + base64_encode(content); + } + #endif diff -r 87c069c94ac9 -r 2d8191b13567 Core/Toolbox.h --- a/Core/Toolbox.h Tue Nov 24 13:36:08 2015 +0100 +++ b/Core/Toolbox.h Tue Nov 24 17:24:37 2015 +0100 @@ -123,6 +123,10 @@ std::string& content, const std::string& source); # endif + + void EncodeDataUriScheme(std::string& result, + const std::string& mime, + const std::string& content); #endif std::string GetPathToExecutable(); diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/DicomModification.cpp --- a/OrthancServer/DicomModification.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/DicomModification.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -161,7 +161,7 @@ removals_.erase(tag); RemoveInternal(tag); - if (FromDcmtkBridge::IsPrivateTag(tag)) + if (tag.IsPrivate()) { privateTagsToKeep_.insert(tag); } diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/FromDcmtkBridge.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -354,19 +354,6 @@ } - bool FromDcmtkBridge::IsPrivateTag(const DicomTag& tag) - { -#if 1 - DcmTagKey tmp(tag.GetGroup(), tag.GetElement()); - return tmp.isPrivate(); -#else - // Implementation for Orthanc versions <= 0.8.5 - DcmTag tmp(tag.GetGroup(), tag.GetElement()); - return IsPrivateTag(tmp); -#endif - } - - DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element, DicomToJsonFlags flags, Encoding encoding) @@ -377,25 +364,19 @@ throw OrthancException(ErrorCode_BadParameterType); } - if (element.isaString()) + char *c = NULL; + if (element.isaString() && + element.getString(c).good()) { - char *c; - if (element.getString(c).good()) + if (c == NULL) // This case corresponds to the empty string { - if (c == NULL) // This case corresponds to the empty string - { - return new DicomValue("", false); - } - else - { - std::string s(c); - std::string utf8 = Toolbox::ConvertToUtf8(s, encoding); - return new DicomValue(utf8, false); - } + return new DicomValue("", false); } else { - return new DicomValue; + std::string s(c); + std::string utf8 = Toolbox::ConvertToUtf8(s, encoding); + return new DicomValue(utf8, false); } } @@ -414,24 +395,6 @@ case EVR_OW: // other word case EVR_UN: // unknown value representation case EVR_ox: // OB or OW depending on context - { - if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) - { - Uint8* data = NULL; - if (element.getUint8Array(data) == EC_Normal) - { - return new DicomValue(reinterpret_cast(data), element.getLength(), true); - } - } - - return new DicomValue; - } - - /** - * String types, should never happen at this point because of - * "element.isaString()". - **/ - case EVR_DS: // decimal string case EVR_IS: // integer string case EVR_AS: // age string @@ -447,12 +410,24 @@ case EVR_UT: // unlimited text case EVR_PN: // person name case EVR_UI: // unique identifier - return new DicomValue; - + case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) + case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR + { + if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) + { + Uint8* data = NULL; + if (element.getUint8Array(data) == EC_Normal) + { + return new DicomValue(reinterpret_cast(data), element.getLength(), true); + } + } - /** - * Numberic types - **/ + return new DicomValue; + } + + /** + * Numberic types + **/ case EVR_SL: // signed long { @@ -553,10 +528,8 @@ case EVR_dirRecord: // used internally for DICOMDIR records case EVR_pixelSQ: // used internally for pixel sequences in a compressed image case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) case EVR_PixelData: // used internally for uncompressed pixeld data case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR return new DicomValue; @@ -782,8 +755,11 @@ throw OrthancException(ErrorCode_InternalError); } - if (!(flags & DicomToJsonFlags_IncludePrivateTags) && - element->getTag().isPrivate()) + DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); + + /*element->getTag().isPrivate()*/ + if (tag.IsPrivate() && + !(flags & DicomToJsonFlags_IncludePrivateTags)) { continue; } @@ -805,8 +781,6 @@ evr == EVR_ox) { // This is a binary tag - DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); - if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) || (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary))) { @@ -1084,8 +1058,7 @@ static bool IsBinaryTag(const DcmTag& key) { - return (key.isPrivate() || - key.isUnknownVR() || + return (key.isUnknownVR() || key.getEVR() == EVR_OB || key.getEVR() == EVR_OF || key.getEVR() == EVR_OW || @@ -1098,7 +1071,8 @@ { DcmTag key(tag.GetGroup(), tag.GetElement()); - if (IsBinaryTag(key)) + if (tag.IsPrivate() || + IsBinaryTag(key)) { return new DcmOtherByteOtherWord(key); } @@ -1241,13 +1215,13 @@ void FromDcmtkBridge::FillElementWithString(DcmElement& element, const DicomTag& tag, const std::string& utf8Value, - bool decodeBinaryTags, + bool decodeDataUriScheme, Encoding dicomEncoding) { std::string binary; const std::string* decoded = &utf8Value; - if (decodeBinaryTags && + if (decodeDataUriScheme && boost::starts_with(utf8Value, "data:application/octet-stream;base64,")) { std::string mime; @@ -1262,7 +1236,8 @@ DcmTag key(tag.GetGroup(), tag.GetElement()); - if (IsBinaryTag(key)) + if (tag.IsPrivate() || + IsBinaryTag(key)) { if (element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good()) { @@ -1412,7 +1387,7 @@ DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag, const Json::Value& value, - bool decodeBinaryTags, + bool decodeDataUriScheme, Encoding dicomEncoding) { std::auto_ptr element; @@ -1421,7 +1396,7 @@ { case Json::stringValue: element.reset(CreateElementForTag(tag)); - FillElementWithString(*element, tag, value.asString(), decodeBinaryTags, dicomEncoding); + FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding); break; case Json::arrayValue: @@ -1442,7 +1417,7 @@ Json::Value::Members members = value[i].getMemberNames(); for (Json::Value::ArrayIndex j = 0; j < members.size(); j++) { - item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeBinaryTags, dicomEncoding)); + item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding)); } sequence->append(item.release()); diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/FromDcmtkBridge.h Tue Nov 24 17:24:37 2015 +0100 @@ -60,8 +60,6 @@ static DicomTag GetTag(const DcmElement& element); - static bool IsPrivateTag(const DicomTag& tag); - static bool IsUnknownTag(const DicomTag& tag); static DicomValue* ConvertLeafElement(DcmElement& element, @@ -125,12 +123,12 @@ static void FillElementWithString(DcmElement& element, const DicomTag& tag, const std::string& utf8alue, // Encoded using UTF-8 - bool interpretBinaryTags, + bool decodeDataUriScheme, Encoding dicomEncoding); static DcmElement* FromJson(const DicomTag& tag, const Json::Value& element, // Encoding using UTF-8 - bool interpretBinaryTags, + bool decodeDataUriScheme, Encoding dicomEncoding); static DcmEVR ParseValueRepresentation(const std::string& s); diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/OrthancRestApi/OrthancRestModalities.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -865,6 +865,32 @@ } + static void DicomFindWorklist(RestApiPostCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + Json::Value json; + if (call.ParseJsonRequest(json)) + { + const std::string& localAet = context.GetDefaultLocalApplicationEntityTitle(); + RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", "")); + + std::auto_ptr query(ParsedDicomFile::CreateFromJson(json, static_cast(0))); + + DicomFindAnswers answers; + + { + ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote); + locker.GetConnection().FindWorklist(answers, *query); + } + + Json::Value result; + answers.ToJson(result, true); + call.GetOutput().AnswerJson(result); + } + } + + void OrthancRestApi::RegisterModalities() { Register("/modalities", ListModalities); @@ -898,5 +924,7 @@ Register("/peers/{id}", UpdatePeer); Register("/peers/{id}", DeletePeer); Register("/peers/{id}/store", PeerStore); + + Register("/modalities/{id}/find-worklist", DicomFindWorklist); } } diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -80,6 +80,7 @@ #include "ParsedDicomFile.h" +#include "OrthancInitialization.h" #include "ServerToolbox.h" #include "FromDcmtkBridge.h" #include "ToDcmtkBridge.h" @@ -593,9 +594,9 @@ void ParsedDicomFile::Insert(const DicomTag& tag, const Json::Value& value, - bool decodeBinaryTags) + bool decodeDataUriScheme) { - std::auto_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeBinaryTags, GetEncoding())); + std::auto_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, GetEncoding())); InsertInternal(*pimpl_->file_->getDataset(), element.release()); } @@ -630,7 +631,7 @@ void ParsedDicomFile::UpdateStorageUid(const DicomTag& tag, const std::string& utf8Value, - bool decodeBinaryTags) + bool decodeDataUriScheme) { if (tag != DICOM_TAG_SOP_CLASS_UID && tag != DICOM_TAG_SOP_INSTANCE_UID) @@ -641,7 +642,7 @@ std::string binary; const std::string* decoded = &utf8Value; - if (decodeBinaryTags && + if (decodeDataUriScheme && boost::starts_with(utf8Value, "data:application/octet-stream;base64,")) { std::string mime; @@ -692,10 +693,10 @@ void ParsedDicomFile::Replace(const DicomTag& tag, const Json::Value& value, - bool decodeBinaryTags, + bool decodeDataUriScheme, DicomReplaceMode mode) { - std::auto_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeBinaryTags, GetEncoding())); + std::auto_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, GetEncoding())); ReplaceInternal(*pimpl_->file_->getDataset(), element, mode); if (tag == DICOM_TAG_SOP_CLASS_UID || @@ -706,7 +707,7 @@ throw OrthancException(ErrorCode_BadParameterType); } - UpdateStorageUid(tag, value.asString(), decodeBinaryTags); + UpdateStorageUid(tag, value.asString(), decodeDataUriScheme); } } @@ -728,7 +729,7 @@ DcmTagKey k(tag.GetGroup(), tag.GetElement()); DcmDataset& dataset = *pimpl_->file_->getDataset(); - if (FromDcmtkBridge::IsPrivateTag(tag) || + if (tag.IsPrivate() || FromDcmtkBridge::IsUnknownTag(tag) || tag == DICOM_TAG_PIXEL_DATA || tag == DICOM_TAG_ENCAPSULATED_DOCUMENT) @@ -1252,4 +1253,60 @@ { FromDcmtkBridge::Convert(tags, *pimpl_->file_->getDataset()); } + + + ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json, + DicomFromJsonFlags flags) + { + std::string tmp = Configuration::GetGlobalStringParameter("DefaultEncoding", "Latin1"); + Encoding encoding = StringToEncoding(tmp.c_str()); + + Json::Value::Members tags = json.getMemberNames(); + + for (size_t i = 0; i < tags.size(); i++) + { + DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); + if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) + { + const Json::Value& value = json[tags[i]]; + if (value.type() != Json::stringValue || + !GetDicomEncoding(encoding, value.asCString())) + { + LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value; + throw OrthancException(ErrorCode_BadRequest); + } + } + } + + const bool generateIdentifiers = (flags & DicomFromJsonFlags_GenerateIdentifiers); + const bool decodeDataUriScheme = (flags & DicomFromJsonFlags_DecodeDataUriScheme); + + std::auto_ptr result(new ParsedDicomFile(generateIdentifiers)); + result->SetEncoding(encoding); + + for (size_t i = 0; i < tags.size(); i++) + { + DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); + const Json::Value& value = json[tags[i]]; + + if (tag == DICOM_TAG_PIXEL_DATA || + tag == DICOM_TAG_ENCAPSULATED_DOCUMENT) + { + if (value.type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadRequest); + } + else + { + result->EmbedContent(value.asString()); + } + } + else if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) + { + result->Replace(tag, value, decodeDataUriScheme); + } + } + + return result.release(); + } } diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/ParsedDicomFile.h --- a/OrthancServer/ParsedDicomFile.h Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/ParsedDicomFile.h Tue Nov 24 17:24:37 2015 +0100 @@ -59,7 +59,7 @@ void UpdateStorageUid(const DicomTag& tag, const std::string& value, - bool decodeBinaryTags); + bool decodeDataUriScheme); public: ParsedDicomFile(bool createIdentifiers); // Create a minimal DICOM instance @@ -94,12 +94,12 @@ void Replace(const DicomTag& tag, const Json::Value& value, // Assumed to be encoded with UTF-8 - bool decodeBinaryTags, + bool decodeDataUriScheme, DicomReplaceMode mode = DicomReplaceMode_InsertIfAbsent); void Insert(const DicomTag& tag, const Json::Value& value, // Assumed to be encoded with UTF-8 - bool decodeBinaryTags); + bool decodeDataUriScheme); void RemovePrivateTags() { @@ -159,6 +159,9 @@ bool ExtractPdf(std::string& pdf); void Convert(DicomMap& tags); + + static ParsedDicomFile* CreateFromJson(const Json::Value& value, + DicomFromJsonFlags flags); }; } diff -r 87c069c94ac9 -r 2d8191b13567 OrthancServer/ServerEnumerations.h --- a/OrthancServer/ServerEnumerations.h Tue Nov 24 13:36:08 2015 +0100 +++ b/OrthancServer/ServerEnumerations.h Tue Nov 24 17:24:37 2015 +0100 @@ -127,6 +127,12 @@ DicomToJsonFlags_ConvertBinaryToNull) }; + enum DicomFromJsonFlags + { + DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0), + DicomFromJsonFlags_GenerateIdentifiers = (1 << 1) + }; + enum IdentifierConstraintType { IdentifierConstraintType_Equal, diff -r 87c069c94ac9 -r 2d8191b13567 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/Plugins/Engine/OrthancPlugins.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -363,7 +363,7 @@ Reset(); } - void GetQueryDicom(OrthancPluginMemoryBuffer& target) const + void GetDicomQuery(OrthancPluginMemoryBuffer& target) const { assert(currentQuery_ != NULL); std::string dicom; @@ -1966,7 +1966,7 @@ { const _OrthancPluginWorklistQueryOperation& p = *reinterpret_cast(parameters); - reinterpret_cast(p.query)->GetQueryDicom(*p.target); + reinterpret_cast(p.query)->GetDicomQuery(*p.target); return true; } diff -r 87c069c94ac9 -r 2d8191b13567 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Tue Nov 24 13:36:08 2015 +0100 +++ b/UnitTestsSources/FromDcmtkTests.cpp Tue Nov 24 17:24:37 2015 +0100 @@ -97,8 +97,8 @@ const DicomTag privateTag(0x0045, 0x0010); const DicomTag privateTag2(FromDcmtkBridge::ParseTag("0031-1020")); - ASSERT_TRUE(FromDcmtkBridge::IsPrivateTag(privateTag)); - ASSERT_TRUE(FromDcmtkBridge::IsPrivateTag(privateTag2)); + ASSERT_TRUE(privateTag.IsPrivate()); + ASSERT_TRUE(privateTag2.IsPrivate()); ASSERT_EQ(0x0031, privateTag2.GetGroup()); ASSERT_EQ(0x1020, privateTag2.GetElement()); @@ -543,6 +543,15 @@ ASSERT_EQ(Json::stringValue, v["7050,1000"].type()); ASSERT_EQ("Some public tag", v["7050,1000"].asString()); + f.ToJson(v, DicomToJsonFormat_Short, static_cast(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0); + ASSERT_EQ(Json::objectValue, v.type()); + ASSERT_EQ(7, v.getMemberNames().size()); + ASSERT_FALSE(v.isMember("7052,1000")); + ASSERT_TRUE(v.isMember("7050,1000")); + ASSERT_TRUE(v.isMember("7053,1000")); + ASSERT_EQ("Some public tag", v["7050,1000"].asString()); + ASSERT_EQ(Json::nullValue, v["7053,1000"].type()); + f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0); ASSERT_EQ(Json::objectValue, v.type()); ASSERT_EQ(7, v.getMemberNames().size()); @@ -550,26 +559,42 @@ ASSERT_TRUE(v.isMember("7050,1000")); ASSERT_TRUE(v.isMember("7053,1000")); ASSERT_EQ("Some public tag", v["7050,1000"].asString()); - ASSERT_EQ(Json::nullValue, v["7053,1000"].type()); // TODO SHOULD BE STRING + std::string mime, content; + ASSERT_EQ(Json::stringValue, v["7053,1000"].type()); + Toolbox::DecodeDataUriScheme(mime, content, v["7053,1000"].asString()); + ASSERT_EQ("application/octet-stream", mime); + ASSERT_EQ("Some private tag", content); - f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludeUnknownTags, 0); + f.ToJson(v, DicomToJsonFormat_Short, static_cast(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0); ASSERT_EQ(Json::objectValue, v.type()); ASSERT_EQ(7, v.getMemberNames().size()); ASSERT_TRUE(v.isMember("7050,1000")); ASSERT_TRUE(v.isMember("7052,1000")); ASSERT_FALSE(v.isMember("7053,1000")); ASSERT_EQ("Some public tag", v["7050,1000"].asString()); - ASSERT_EQ(Json::nullValue, v["7052,1000"].type()); // TODO SHOULD BE STRING + ASSERT_EQ(Json::nullValue, v["7052,1000"].type()); - f.ToJson(v, DicomToJsonFormat_Short, static_cast(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags), 0); + f.ToJson(v, DicomToJsonFormat_Short, static_cast(DicomToJsonFlags_IncludeUnknownTags), 0); + ASSERT_EQ(Json::objectValue, v.type()); + ASSERT_EQ(7, v.getMemberNames().size()); + ASSERT_TRUE(v.isMember("7050,1000")); + ASSERT_TRUE(v.isMember("7052,1000")); + ASSERT_FALSE(v.isMember("7053,1000")); + ASSERT_EQ("Some public tag", v["7050,1000"].asString()); + ASSERT_EQ(Json::stringValue, v["7052,1000"].type()); + Toolbox::DecodeDataUriScheme(mime, content, v["7052,1000"].asString()); + ASSERT_EQ("application/octet-stream", mime); + ASSERT_EQ("Some unknown tag", content); + + f.ToJson(v, DicomToJsonFormat_Short, static_cast(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0); ASSERT_EQ(Json::objectValue, v.type()); ASSERT_EQ(8, v.getMemberNames().size()); ASSERT_TRUE(v.isMember("7050,1000")); ASSERT_TRUE(v.isMember("7052,1000")); ASSERT_TRUE(v.isMember("7053,1000")); ASSERT_EQ("Some public tag", v["7050,1000"].asString()); - ASSERT_EQ(Json::nullValue, v["7052,1000"].type()); // TODO SHOULD BE STRING - ASSERT_EQ(Json::nullValue, v["7053,1000"].type()); // TODO SHOULD BE STRING + ASSERT_EQ(Json::nullValue, v["7052,1000"].type()); + ASSERT_EQ(Json::nullValue, v["7053,1000"].type()); } @@ -637,3 +662,101 @@ //std::cout << j; } + + +TEST(ParsedDicomFile, FromJson) +{ + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), EVR_OB, "MyPrivateTag", 1, 1); + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), EVR_OB, "MyPrivateTag", 1, 1); + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), EVR_PN, "Declared public tag", 1, 1); + + Json::Value v; + const std::string sopClassUid = "1.2.840.10008.5.1.4.1.1.1"; // CR Image Storage: + + { + v["SOPClassUID"] = sopClassUid; + v["SpecificCharacterSet"] = "ISO_IR 148"; // This is latin-5 + v["PatientName"] = "Sébastien"; + v["7050-1000"] = "Some public tag"; // Even group => public tag + v["7052-1000"] = "Some unknown tag"; // Even group => public, unknown tag + v["7057-1000"] = "Some private tag"; // Odd group => private tag + v["7059-1000"] = "Some private tag2"; // Odd group => private tag, with an odd length to test padding + + std::string s; + Toolbox::EncodeDataUriScheme(s, "application/octet-stream", "Sebastien"); + v["StudyDescription"] = s; + + v["PixelData"] = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // A red dot of 5x5 pixels + v["0040,0100"] = Json::arrayValue; // ScheduledProcedureStepSequence + + Json::Value vv; + vv["Modality"] = "MR"; + v["0040,0100"].append(vv); + + vv["Modality"] = "CT"; + v["0040,0100"].append(vv); + } + + const DicomToJsonFlags toJsonFlags = static_cast(DicomToJsonFlags_IncludeBinary | + DicomToJsonFlags_IncludePixelData | + DicomToJsonFlags_IncludePrivateTags | + DicomToJsonFlags_IncludeUnknownTags | + DicomToJsonFlags_ConvertBinaryToAscii); + + + { + std::auto_ptr dicom + (ParsedDicomFile::CreateFromJson(v, static_cast(DicomFromJsonFlags_GenerateIdentifiers))); + + Json::Value vv; + dicom->ToJson(vv, DicomToJsonFormat_Simple, toJsonFlags, 0); + + ASSERT_EQ(vv["SOPClassUID"].asString(), sopClassUid); + ASSERT_EQ(vv["MediaStorageSOPClassUID"].asString(), sopClassUid); + ASSERT_TRUE(vv.isMember("SOPInstanceUID")); + ASSERT_TRUE(vv.isMember("SeriesInstanceUID")); + ASSERT_TRUE(vv.isMember("StudyInstanceUID")); + ASSERT_TRUE(vv.isMember("PatientID")); + } + + + { + std::auto_ptr dicom + (ParsedDicomFile::CreateFromJson(v, static_cast(DicomFromJsonFlags_GenerateIdentifiers))); + + Json::Value vv; + dicom->ToJson(vv, DicomToJsonFormat_Simple, static_cast(DicomToJsonFlags_IncludePixelData), 0); + + std::string mime, content; + Toolbox::DecodeDataUriScheme(mime, content, vv["PixelData"].asString()); + ASSERT_EQ("application/octet-stream", mime); + ASSERT_EQ(5u * 5u * 3u /* the red dot is 5x5 pixels in RGB24 */ + 1 /* for padding */, content.size()); + } + + + { + std::auto_ptr dicom + (ParsedDicomFile::CreateFromJson(v, static_cast(DicomFromJsonFlags_DecodeDataUriScheme))); + + Json::Value vv; + dicom->ToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0); + + ASSERT_FALSE(vv.isMember("SOPInstanceUID")); + ASSERT_FALSE(vv.isMember("SeriesInstanceUID")); + ASSERT_FALSE(vv.isMember("StudyInstanceUID")); + ASSERT_FALSE(vv.isMember("PatientID")); + ASSERT_EQ(2u, vv["0040,0100"].size()); + ASSERT_EQ("MR", vv["0040,0100"][0]["0008,0060"].asString()); + ASSERT_EQ("CT", vv["0040,0100"][1]["0008,0060"].asString()); + ASSERT_EQ("Some public tag", vv["7050,1000"].asString()); + ASSERT_EQ("Some unknown tag", vv["7052,1000"].asString()); + ASSERT_EQ("Some private tag", vv["7057,1000"].asString()); + ASSERT_EQ("Some private tag2", vv["7059,1000"].asString()); + ASSERT_EQ("Sébastien", vv["0010,0010"].asString()); + ASSERT_EQ("Sebastien", vv["0008,1030"].asString()); + ASSERT_EQ("ISO_IR 148", vv["0008,0005"].asString()); + ASSERT_EQ("5", vv[DICOM_TAG_ROWS.Format()].asString()); + ASSERT_EQ("5", vv[DICOM_TAG_COLUMNS.Format()].asString()); + ASSERT_TRUE(vv[DICOM_TAG_PIXEL_DATA.Format()].asString().empty()); + } +}