# HG changeset patch # User Sebastien Jodogne # Date 1440162081 -7200 # Node ID 1b7def486e62a8a7c2946f85d156d5339ad374c6 # Parent 9bb4164453192169804c4cfb62b67edd92214664 creation of DICOM series diff -r 9bb416445319 -r 1b7def486e62 OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri Aug 21 13:47:34 2015 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Fri Aug 21 15:01:21 2015 +0200 @@ -39,6 +39,8 @@ #include "../ServerContext.h" #include "../OrthancInitialization.h" +#include + namespace Orthanc { // Modification of DICOM instances ------------------------------------------ @@ -429,6 +431,27 @@ } + static bool StoreCreatedInstance(std::string& id /* out */, + ServerContext& context, + ParsedDicomFile& dicom) + { + DicomInstanceToStore toStore; + toStore.SetParsedDicomFile(dicom); + + StoreStatus status = context.Store(id, toStore); + + if (status == StoreStatus_Failure) + { + LOG(ERROR) << "Error while storing a manually-created instance"; + return false; + } + else + { + return true; + } + } + + static bool CreateDicomV1(ParsedDicomFile& dicom, const Json::Value& request) { @@ -465,16 +488,57 @@ } - static bool CreateDicomV2(ParsedDicomFile& dicom, - ServerContext& context, + static void CreateSeries(RestApiPostCall& call, + ParsedDicomFile& base /* in */, + const Json::Value& content) + { + assert(content.isArray()); + assert(content.size() > 0); + ServerContext& context = OrthancRestApi::GetContext(call); + + base.Replace(DICOM_TAG_IMAGES_IN_ACQUISITION, boost::lexical_cast(content.size())); + base.Replace(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "1"); + + std::string someInstance; + + for (Json::ArrayIndex i = 0; i < content.size(); i++) + { + if (content[i].type() != Json::stringValue) + { + LOG(ERROR) << "The payload of the DICOM instance must be specified according to Data URI scheme"; + return; + } + + std::auto_ptr dicom(base.Clone()); + dicom->EmbedContent(content[i].asString()); + dicom->Replace(DICOM_TAG_INSTANCE_NUMBER, boost::lexical_cast(i + 1)); + dicom->Replace(DICOM_TAG_IMAGE_INDEX, boost::lexical_cast(i + 1)); + + if (!StoreCreatedInstance(someInstance, context, *dicom)) + { + LOG(ERROR) << "Error while creating the series"; + return; + } + } + + std::string series; + if (context.GetIndex().LookupParent(series, someInstance)) + { + OrthancRestApi::GetApi(call).AnswerStoredResource(call, series, ResourceType_Series, StoreStatus_Success); + } + } + + + static void CreateDicomV2(RestApiPostCall& call, const Json::Value& request) { assert(request.isObject()); + ServerContext& context = OrthancRestApi::GetContext(call); if (!request.isMember("Tags") || request["Tags"].type() != Json::objectValue) { - return false; + return; } Encoding encoding; @@ -485,7 +549,7 @@ if (!GetDicomEncoding(encoding, tmp)) { LOG(ERROR) << "Unknown specific character set: " << tmp; - return false; + return; } } else @@ -494,6 +558,7 @@ encoding = StringToEncoding(tmp.c_str()); } + ParsedDicomFile dicom; dicom.SetEncoding(encoding); ResourceType parentType = ResourceType_Instance; @@ -505,13 +570,13 @@ if (!context.GetIndex().LookupResourceType(parentType, parent)) { LOG(ERROR) << "Trying to attach a new DICOM instance to an inexistent resource: " << parent; - return false; + return; } if (parentType == ResourceType_Instance) { LOG(ERROR) << "Trying to attach a new DICOM instance to an instance (must be a series, study or patient): " << parent; - return false; + return; } // Select one existing child instance of the parent resource, to @@ -525,7 +590,7 @@ if (siblingInstances.empty()) { - return false; // Error: No instance (should never happen) + return; // Error: No instance (should never happen) } context.ReadJson(siblingTags, siblingInstances.front()); @@ -549,7 +614,7 @@ std::string tmp; if (!context.GetIndex().LookupParent(tmp, parent)) { - return false; + return; } parent = tmp; @@ -611,7 +676,7 @@ if (request["Tags"][name].type() != Json::stringValue) { LOG(ERROR) << "Only string values are supported when creating DICOM instances"; - return false; + return; } std::string value = request["Tags"][name].asString(); @@ -622,13 +687,13 @@ if (dicom.HasTag(tag)) { LOG(ERROR) << "Trying to override a value inherited from a parent module"; - return false; + return; } if (tag == DICOM_TAG_PIXEL_DATA) { LOG(ERROR) << "Use \"Content\" to inject an image into a new DICOM instance"; - return false; + return; } else { @@ -637,51 +702,65 @@ } } - // Inject the content (either an image, or a PDF file) if (request.isMember("Content")) { - if (request["Content"].type() != Json::stringValue) + const Json::Value& content = request["Content"]; + + if (content.type() == Json::stringValue) + { + dicom.EmbedContent(request["Content"].asString()); + + } + else if (content.type() == Json::arrayValue) + { + if (content.size() > 0) + { + // Let's create a series + CreateSeries(call, dicom, content); + return; + } + } + else { LOG(ERROR) << "The payload of the DICOM instance must be specified according to Data URI scheme"; - return false; + return; } - - dicom.EmbedContent(request["Content"].asString()); } + std::string id; + if (StoreCreatedInstance(id, context, dicom)) + { + OrthancRestApi::GetApi(call).AnswerStoredResource(call, id, ResourceType_Instance, StoreStatus_Success); + } - return true; + return; } static void CreateDicom(RestApiPostCall& call) { - ServerContext& context = OrthancRestApi::GetContext(call); - Json::Value request; if (call.ParseJsonRequest(request) && request.isObject()) { - ParsedDicomFile dicom; - - if (request.isMember("Tags") ? - CreateDicomV2(dicom, context, request) : - CreateDicomV1(dicom, request)) + if (request.isMember("Tags")) + { + CreateDicomV2(call, request); + } + else { - DicomInstanceToStore toStore; - toStore.SetParsedDicomFile(dicom); - - std::string id; - StoreStatus status = OrthancRestApi::GetContext(call).Store(id, toStore); - - if (status == StoreStatus_Failure) + // Compatibility with Orthanc <= 0.9.3 + ServerContext& context = OrthancRestApi::GetContext(call); + ParsedDicomFile dicom; + if (CreateDicomV1(dicom, request)) { - LOG(ERROR) << "Error while storing a manually-created instance"; - return; + std::string id; + if (StoreCreatedInstance(id, context, dicom)) + { + OrthancRestApi::GetApi(call).AnswerStoredResource(call, id, ResourceType_Instance, StoreStatus_Success); + } } - - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, id, status); } } } diff -r 9bb416445319 -r 1b7def486e62 OrthancServer/OrthancRestApi/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Fri Aug 21 13:47:34 2015 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Fri Aug 21 15:01:21 2015 +0200 @@ -39,8 +39,9 @@ namespace Orthanc { - void OrthancRestApi::AnswerStoredInstance(RestApiPostCall& call, + void OrthancRestApi::AnswerStoredResource(RestApiPostCall& call, const std::string& publicId, + ResourceType resourceType, StoreStatus status) const { Json::Value result = Json::objectValue; @@ -48,7 +49,7 @@ if (status != StoreStatus_Failure) { result["ID"] = publicId; - result["Path"] = GetBasePath(ResourceType_Instance, publicId); + result["Path"] = GetBasePath(resourceType, publicId); } result["Status"] = EnumerationToString(status); @@ -88,7 +89,7 @@ std::string publicId; StoreStatus status = context.Store(publicId, toStore); - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, publicId, status); + OrthancRestApi::GetApi(call).AnswerStoredResource(call, publicId, ResourceType_Instance, status); } diff -r 9bb416445319 -r 1b7def486e62 OrthancServer/OrthancRestApi/OrthancRestApi.h --- a/OrthancServer/OrthancRestApi/OrthancRestApi.h Fri Aug 21 13:47:34 2015 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.h Fri Aug 21 15:01:21 2015 +0200 @@ -82,8 +82,9 @@ static ServerIndex& GetIndex(RestApiCall& call); - void AnswerStoredInstance(RestApiPostCall& call, + void AnswerStoredResource(RestApiPostCall& call, const std::string& publicId, + ResourceType resourceType, StoreStatus status) const; static bool ParseModifyRequest(DicomModification& target, diff -r 9bb416445319 -r 1b7def486e62 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Fri Aug 21 13:47:34 2015 +0200 +++ b/OrthancServer/ParsedDicomFile.cpp Fri Aug 21 15:01:21 2015 +0200 @@ -1111,8 +1111,10 @@ pimpl_(new PImpl) { pimpl_->file_.reset(dynamic_cast(other.pimpl_->file_->clone())); + pimpl_->encoding_ = other.pimpl_->encoding_; - pimpl_->encoding_ = other.pimpl_->encoding_; + // Create a new instance-level identifier + Replace(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance)); }