Mercurial > hg > orthanc
diff OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp @ 1555:d6a93e12b1c1
Creation of DICOM files with encapsulated PDF
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 20 Aug 2015 15:18:13 +0200 |
parents | f967bdf8534e |
children | ad1e127b4ed5 |
line wrap: on
line diff
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Thu Aug 20 11:56:42 2015 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Thu Aug 20 15:18:13 2015 +0200 @@ -428,46 +428,256 @@ } - static void CreateDicom(RestApiPostCall& call) + static bool CreateDicomV1(ParsedDicomFile& dicom, + const Json::Value& request) { // curl http://localhost:8042/tools/create-dicom -X POST -d '{"PatientName":"Hello^World"}' // curl http://localhost:8042/tools/create-dicom -X POST -d '{"PatientName":"Hello^World","PixelData":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gUGDDcB53FulQAAAElJREFUGNNtj0sSAEEEQ1+U+185s1CtmRkblQ9CZldsKHJDk6DLGLJa6chjh0ooQmpjXMM86zPwydGEj6Ed/UGykkEM8X+p3u8/8LcOJIWLGeMAAAAASUVORK5CYII="}' - Json::Value replacements; - if (call.ParseJsonRequest(replacements) && replacements.isObject()) + assert(request.isObject()); + LOG(WARNING) << "Using a deprecated call to /tools/create-dicom"; + + Json::Value::Members members = request.getMemberNames(); + for (size_t i = 0; i < members.size(); i++) + { + const std::string& name = members[i]; + if (request[name].type() != Json::stringValue) + { + LOG(ERROR) << "Only string values are supported when creating DICOM instances"; + return false; + } + + std::string value = request[name].asString(); + + DicomTag tag = FromDcmtkBridge::ParseTag(name); + if (tag == DICOM_TAG_PIXEL_DATA) + { + dicom.EmbedImage(value); + } + else + { + dicom.Replace(tag, value); + } + } + + return true; + } + + + static bool CreateDicomV2(ParsedDicomFile& dicom, + ServerContext& context, + const Json::Value& request) + { + assert(request.isObject()); + + if (!request.isMember("Tags") || + request["Tags"].type() != Json::objectValue) + { + return false; + } + + ResourceType parentType = ResourceType_Instance; + + if (request.isMember("Parent")) + { + // Locate the parent tags + std::string parent = request["Parent"].asString(); + if (!context.GetIndex().LookupResourceType(parentType, parent)) + { + LOG(ERROR) << "Trying to attach a new DICOM instance to an inexistent resource: " << parent; + return false; + } + + 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; + } + + // Select one existing child instance of the parent resource, to + // retrieve all its tags + Json::Value siblingTags; + + { + // Retrieve all the instances of the parent resource + std::list<std::string> siblingInstances; + context.GetIndex().GetChildInstances(siblingInstances, parent); + + if (siblingInstances.empty()) + { + return false; // Error: No instance (should never happen) + } + + context.ReadJson(siblingTags, siblingInstances.front()); + } + + // Retrieve the tags for all the parent modules + typedef std::set<DicomTag> ModuleTags; + ModuleTags moduleTags; + + ResourceType type = parentType; + for (;;) + { + DicomTag::AddTagsForModule(moduleTags, GetModule(type)); + + if (type == ResourceType_Patient) + { + break; // We're done + } + + // Go up + std::string tmp; + if (!context.GetIndex().LookupParent(tmp, parent)) + { + return false; + } + + parent = tmp; + type = GetParentResourceType(type); + } + + for (ModuleTags::const_iterator it = moduleTags.begin(); + it != moduleTags.end(); it++) + { + std::string t = it->Format(); + if (siblingTags.isMember(t)) + { + const Json::Value& tag = siblingTags[t]; + if (tag["Type"] == "Null") + { + dicom.Replace(*it, ""); + } + else if (tag["Type"] == "String") + { + dicom.Replace(*it, tag["Value"].asString()); + } + } + } + } + + + // Inject time-related information + std::string date, time; + Toolbox::GetNowDicom(date, time); + dicom.Replace(DICOM_TAG_ACQUISITION_DATE, date); + dicom.Replace(DICOM_TAG_ACQUISITION_TIME, time); + dicom.Replace(DICOM_TAG_CONTENT_DATE, date); + dicom.Replace(DICOM_TAG_CONTENT_TIME, time); + dicom.Replace(DICOM_TAG_INSTANCE_CREATION_DATE, date); + dicom.Replace(DICOM_TAG_INSTANCE_CREATION_TIME, time); + + if (parentType == ResourceType_Patient || + parentType == ResourceType_Study || + parentType == ResourceType_Instance /* no parent */) + { + dicom.Replace(DICOM_TAG_SERIES_DATE, date); + dicom.Replace(DICOM_TAG_SERIES_TIME, time); + } + + if (parentType == ResourceType_Patient || + parentType == ResourceType_Instance /* no parent */) + { + dicom.Replace(DICOM_TAG_STUDY_DATE, date); + dicom.Replace(DICOM_TAG_STUDY_TIME, time); + } + + + // Inject the user-specified tags + Json::Value::Members members = request["Tags"].getMemberNames(); + for (size_t i = 0; i < members.size(); i++) + { + const std::string& name = members[i]; + if (request["Tags"][name].type() != Json::stringValue) + { + LOG(ERROR) << "Only string values are supported when creating DICOM instances"; + return false; + } + + std::string value = request["Tags"][name].asString(); + + DicomTag tag = FromDcmtkBridge::ParseTag(name); + if (dicom.HasTag(tag)) + { + LOG(ERROR) << "Trying to override a value inherited from a parent module"; + return false; + } + + if (tag == DICOM_TAG_PIXEL_DATA) + { + LOG(ERROR) << "Use \"Content\" to inject an image into a new DICOM instance"; + return false; + } + else + { + dicom.Replace(tag, value); + } + } + + + // Inject the content (either an image, or a PDF file) + if (request.isMember("Content")) + { + if (request["Content"].type() != Json::stringValue) + { + LOG(ERROR) << "The payload of the DICOM instance must be specified according to Data URI scheme"; + return false; + } + + std::string mime, base64; + Toolbox::DecodeDataUriScheme(mime, base64, request["Content"].asString()); + Toolbox::ToLowerCase(mime); + + std::string content; + Toolbox::DecodeBase64(content, base64); + + if (mime == "image/png") + { + dicom.EmbedImage(mime, content); + } + else if (mime == "application/pdf") + { + dicom.EmbedPdf(content); + } + else + { + LOG(ERROR) << "Unsupported MIME type for the content of a new DICOM file"; + return false; + } + } + + + return true; + } + + + static void CreateDicom(RestApiPostCall& call) + { + ServerContext& context = OrthancRestApi::GetContext(call); + + Json::Value request; + if (call.ParseJsonRequest(request) && + request.isObject()) { ParsedDicomFile dicom; - Json::Value::Members members = replacements.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) + if (request.isMember("Tags") ? + CreateDicomV2(dicom, context, request) : + CreateDicomV1(dicom, request)) { - const std::string& name = members[i]; - std::string value = replacements[name].asString(); + DicomInstanceToStore toStore; + toStore.SetParsedDicomFile(dicom); - DicomTag tag = FromDcmtkBridge::ParseTag(name); - if (tag == DICOM_TAG_PIXEL_DATA) + std::string id; + StoreStatus status = OrthancRestApi::GetContext(call).Store(id, toStore); + + if (status == StoreStatus_Failure) { - dicom.EmbedImage(value); - } - else - { - dicom.Replace(tag, value); + LOG(ERROR) << "Error while storing a manually-created instance"; + return; } + + OrthancRestApi::GetApi(call).AnswerStoredInstance(call, id, status); } - - DicomInstanceToStore toStore; - toStore.SetParsedDicomFile(dicom); - - std::string id; - StoreStatus status = OrthancRestApi::GetContext(call).Store(id, toStore); - - if (status == StoreStatus_Failure) - { - LOG(ERROR) << "Error while storing a manually-created instance"; - return; - } - - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, id, status); } }