comparison Core/DicomParsing/DicomModification.cpp @ 2519:2e6b7862ccf2

ParseAnonymizationRequest/ParseModifyRequest now in DicomModification
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 29 Mar 2018 14:52:11 +0200
parents 51b91ead6c38
children b94ed97508e6
comparison
equal deleted inserted replaced
2518:63d2cc0fb40a 2519:2e6b7862ccf2
1002 { 1002 {
1003 visitor.RemoveRelationships(toModify); 1003 visitor.RemoveRelationships(toModify);
1004 } 1004 }
1005 } 1005 }
1006 } 1006 }
1007
1008
1009 static bool IsDatabaseKey(const DicomTag& tag)
1010 {
1011 return (tag == DICOM_TAG_PATIENT_ID ||
1012 tag == DICOM_TAG_STUDY_INSTANCE_UID ||
1013 tag == DICOM_TAG_SERIES_INSTANCE_UID ||
1014 tag == DICOM_TAG_SOP_INSTANCE_UID);
1015 }
1016
1017
1018 static void ParseListOfTags(DicomModification& target,
1019 const Json::Value& query,
1020 DicomModification::TagOperation operation,
1021 bool force)
1022 {
1023 if (!query.isArray())
1024 {
1025 throw OrthancException(ErrorCode_BadRequest);
1026 }
1027
1028 for (Json::Value::ArrayIndex i = 0; i < query.size(); i++)
1029 {
1030 std::string name = query[i].asString();
1031
1032 DicomTag tag = FromDcmtkBridge::ParseTag(name);
1033
1034 if (!force && IsDatabaseKey(tag))
1035 {
1036 LOG(ERROR) << "Marking tag \"" << name << "\" as to be "
1037 << (operation == DicomModification::TagOperation_Keep ? "kept" : "removed")
1038 << " requires the \"Force\" option to be set to true";
1039 throw OrthancException(ErrorCode_BadRequest);
1040 }
1041
1042 switch (operation)
1043 {
1044 case DicomModification::TagOperation_Keep:
1045 target.Keep(tag);
1046 VLOG(1) << "Keep: " << name << " " << tag << std::endl;
1047 break;
1048
1049 case DicomModification::TagOperation_Remove:
1050 target.Remove(tag);
1051 VLOG(1) << "Remove: " << name << " " << tag << std::endl;
1052 break;
1053
1054 default:
1055 throw OrthancException(ErrorCode_InternalError);
1056 }
1057 }
1058 }
1059
1060
1061 static void ParseReplacements(DicomModification& target,
1062 const Json::Value& replacements,
1063 bool force)
1064 {
1065 if (!replacements.isObject())
1066 {
1067 throw OrthancException(ErrorCode_BadRequest);
1068 }
1069
1070 Json::Value::Members members = replacements.getMemberNames();
1071 for (size_t i = 0; i < members.size(); i++)
1072 {
1073 const std::string& name = members[i];
1074 const Json::Value& value = replacements[name];
1075
1076 DicomTag tag = FromDcmtkBridge::ParseTag(name);
1077
1078 if (!force && IsDatabaseKey(tag))
1079 {
1080 LOG(ERROR) << "Marking tag \"" << name << "\" as to be replaced "
1081 << "requires the \"Force\" option to be set to true";
1082 throw OrthancException(ErrorCode_BadRequest);
1083 }
1084
1085 target.Replace(tag, value, false);
1086
1087 VLOG(1) << "Replace: " << name << " " << tag
1088 << " == " << value.toStyledString() << std::endl;
1089 }
1090 }
1091
1092
1093 static bool GetBooleanValue(const std::string& member,
1094 const Json::Value& json,
1095 bool defaultValue)
1096 {
1097 if (!json.isMember(member))
1098 {
1099 return defaultValue;
1100 }
1101 else if (json[member].type() == Json::booleanValue)
1102 {
1103 return json[member].asBool();
1104 }
1105 else
1106 {
1107 LOG(ERROR) << "Member \"" << member << "\" should be a Boolean value";
1108 throw OrthancException(ErrorCode_BadFileFormat);
1109 }
1110 }
1111
1112
1113 void DicomModification::ParseModifyRequest(const Json::Value& request)
1114 {
1115 if (!request.isObject())
1116 {
1117 throw OrthancException(ErrorCode_BadFileFormat);
1118 }
1119
1120 bool force = GetBooleanValue("Force", request, false);
1121
1122 if (GetBooleanValue("RemovePrivateTags", request, false))
1123 {
1124 SetRemovePrivateTags(true);
1125 }
1126
1127 if (request.isMember("Remove"))
1128 {
1129 ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force);
1130 }
1131
1132 if (request.isMember("Replace"))
1133 {
1134 ParseReplacements(*this, request["Replace"], force);
1135 }
1136
1137 // The "Keep" operation only makes sense for the tags
1138 // StudyInstanceUID, SeriesInstanceUID and SOPInstanceUID. Avoid
1139 // this feature as much as possible, as this breaks the DICOM
1140 // model of the real world, except if you know exactly what
1141 // you're doing!
1142 if (request.isMember("Keep"))
1143 {
1144 ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force);
1145 }
1146 }
1147
1148
1149 void DicomModification::ParseAnonymizationRequest(bool& patientNameReplaced,
1150 const Json::Value& request)
1151 {
1152 if (!request.isObject())
1153 {
1154 throw OrthancException(ErrorCode_BadFileFormat);
1155 }
1156
1157 bool force = GetBooleanValue("Force", request, false);
1158
1159 // As of Orthanc 1.3.0, the default anonymization is done
1160 // according to PS 3.15-2017c Table E.1-1 (basic profile)
1161 DicomVersion version = DicomVersion_2017c;
1162 if (request.isMember("DicomVersion"))
1163 {
1164 if (request["DicomVersion"].type() != Json::stringValue)
1165 {
1166 throw OrthancException(ErrorCode_BadFileFormat);
1167 }
1168 else
1169 {
1170 version = StringToDicomVersion(request["DicomVersion"].asString());
1171 }
1172 }
1173
1174 SetupAnonymization(version);
1175
1176 std::string patientName = GetReplacementAsString(DICOM_TAG_PATIENT_NAME);
1177
1178 if (GetBooleanValue("KeepPrivateTags", request, false))
1179 {
1180 SetRemovePrivateTags(false);
1181 }
1182
1183 if (request.isMember("Remove"))
1184 {
1185 ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force);
1186 }
1187
1188 if (request.isMember("Replace"))
1189 {
1190 ParseReplacements(*this, request["Replace"], force);
1191 }
1192
1193 if (request.isMember("Keep"))
1194 {
1195 ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force);
1196 }
1197
1198 patientNameReplaced = (IsReplaced(DICOM_TAG_PATIENT_NAME) &&
1199 GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName);
1200 }
1007 } 1201 }