Mercurial > hg > orthanc
comparison Core/DicomParsing/FromDcmtkBridge.cpp @ 2499:83b8b6743531
ITagVisitor - for anonymization relationships
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 23 Mar 2018 18:13:21 +0100 |
parents | 45de30d4f362 |
children | 4dcafa8d6633 |
comparison
equal
deleted
inserted
replaced
2498:0188c21e417a | 2499:83b8b6743531 |
---|---|
665 | 665 |
666 default: | 666 default: |
667 return new DicomValue; | 667 return new DicomValue; |
668 } | 668 } |
669 } | 669 } |
670 catch (boost::bad_lexical_cast) | 670 catch (boost::bad_lexical_cast&) |
671 { | 671 { |
672 return new DicomValue; | 672 return new DicomValue; |
673 } | 673 } |
674 catch (std::bad_cast) | 674 catch (std::bad_cast&) |
675 { | 675 { |
676 return new DicomValue; | 676 return new DicomValue; |
677 } | 677 } |
678 } | 678 } |
679 | 679 |
2094 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 | 2094 #if ORTHANC_ENABLE_DCMTK_JPEG == 1 |
2095 // Unregister JPEG codecs | 2095 // Unregister JPEG codecs |
2096 DJDecoderRegistration::cleanup(); | 2096 DJDecoderRegistration::cleanup(); |
2097 #endif | 2097 #endif |
2098 } | 2098 } |
2099 | |
2100 | |
2101 | |
2102 // Forward declaration | |
2103 static void ApplyVisitorToElement(DcmElement& element, | |
2104 ITagVisitor& visitor, | |
2105 const std::vector<DicomTag>& parentTags, | |
2106 const std::vector<size_t>& parentIndexes, | |
2107 Encoding encoding); | |
2108 | |
2109 static void ApplyVisitorToDataset(DcmItem& dataset, | |
2110 ITagVisitor& visitor, | |
2111 const std::vector<DicomTag>& parentTags, | |
2112 const std::vector<size_t>& parentIndexes, | |
2113 Encoding encoding) | |
2114 { | |
2115 assert(parentTags.size() == parentIndexes.size()); | |
2116 | |
2117 for (unsigned long i = 0; i < dataset.card(); i++) | |
2118 { | |
2119 DcmElement* element = dataset.getElement(i); | |
2120 if (element == NULL) | |
2121 { | |
2122 throw OrthancException(ErrorCode_InternalError); | |
2123 } | |
2124 else | |
2125 { | |
2126 ApplyVisitorToElement(*element, visitor, parentTags, parentIndexes, encoding); | |
2127 } | |
2128 } | |
2129 } | |
2130 | |
2131 | |
2132 static void ApplyVisitorToLeaf(DcmElement& element, | |
2133 ITagVisitor& visitor, | |
2134 const std::vector<DicomTag>& parentTags, | |
2135 const std::vector<size_t>& parentIndexes, | |
2136 const DicomTag& tag, | |
2137 Encoding encoding) | |
2138 { | |
2139 // TODO - Merge this function with ConvertLeafElement() | |
2140 | |
2141 assert(element.isLeaf()); | |
2142 | |
2143 DcmEVR evr = element.getTag().getEVR(); | |
2144 ValueRepresentation vr = FromDcmtkBridge::Convert(evr); | |
2145 | |
2146 char *c = NULL; | |
2147 if (element.isaString() && | |
2148 element.getString(c).good()) | |
2149 { | |
2150 std::string utf8; | |
2151 | |
2152 if (c != NULL) // This case corresponds to the empty string | |
2153 { | |
2154 std::string s(c); | |
2155 utf8 = Toolbox::ConvertToUtf8(s, encoding); | |
2156 } | |
2157 | |
2158 std::string newValue; | |
2159 ITagVisitor::Action action = visitor.VisitString | |
2160 (newValue, parentTags, parentIndexes, tag, vr, utf8); | |
2161 | |
2162 switch (action) | |
2163 { | |
2164 case ITagVisitor::Action_None: | |
2165 break; | |
2166 | |
2167 case ITagVisitor::Action_Replace: | |
2168 { | |
2169 std::string s = Toolbox::ConvertFromUtf8(newValue, encoding); | |
2170 if (element.putString(s.c_str(), s.size()) != EC_Normal) | |
2171 { | |
2172 LOG(ERROR) << "Cannot replace value of tag: " << tag.Format(); | |
2173 throw OrthancException(ErrorCode_InternalError); | |
2174 } | |
2175 | |
2176 break; | |
2177 } | |
2178 | |
2179 default: | |
2180 throw OrthancException(ErrorCode_InternalError); | |
2181 } | |
2182 | |
2183 return; // We're done | |
2184 } | |
2185 | |
2186 | |
2187 try | |
2188 { | |
2189 // http://support.dcmtk.org/docs/dcvr_8h-source.html | |
2190 switch (element.getVR()) | |
2191 { | |
2192 | |
2193 /** | |
2194 * Deal with binary data (including PixelData). | |
2195 **/ | |
2196 | |
2197 case EVR_OB: // other byte | |
2198 case EVR_OF: // other float | |
2199 case EVR_OW: // other word | |
2200 case EVR_UN: // unknown value representation | |
2201 case EVR_ox: // OB or OW depending on context | |
2202 case EVR_DS: // decimal string | |
2203 case EVR_IS: // integer string | |
2204 case EVR_AS: // age string | |
2205 case EVR_DA: // date string | |
2206 case EVR_DT: // date time string | |
2207 case EVR_TM: // time string | |
2208 case EVR_AE: // application entity title | |
2209 case EVR_CS: // code string | |
2210 case EVR_SH: // short string | |
2211 case EVR_LO: // long string | |
2212 case EVR_ST: // short text | |
2213 case EVR_LT: // long text | |
2214 case EVR_UT: // unlimited text | |
2215 case EVR_PN: // person name | |
2216 case EVR_UI: // unique identifier | |
2217 case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) | |
2218 case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR | |
2219 { | |
2220 Uint8* data = NULL; | |
2221 | |
2222 if (element.getUint8Array(data) == EC_Normal) | |
2223 { | |
2224 visitor.VisitBinary(parentTags, parentIndexes, tag, vr, data, element.getLength()); | |
2225 } | |
2226 else | |
2227 { | |
2228 visitor.VisitUnknown(parentTags, parentIndexes, tag, vr); | |
2229 } | |
2230 | |
2231 break; | |
2232 } | |
2233 | |
2234 /** | |
2235 * Numeric types | |
2236 **/ | |
2237 | |
2238 case EVR_SL: // signed long | |
2239 { | |
2240 Sint32 f; | |
2241 if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good()) | |
2242 { | |
2243 visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); | |
2244 } | |
2245 | |
2246 break; | |
2247 } | |
2248 | |
2249 case EVR_SS: // signed short | |
2250 { | |
2251 Sint16 f; | |
2252 if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good()) | |
2253 { | |
2254 visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); | |
2255 } | |
2256 | |
2257 break; | |
2258 } | |
2259 | |
2260 case EVR_UL: // unsigned long | |
2261 { | |
2262 Uint32 f; | |
2263 if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good()) | |
2264 { | |
2265 visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); | |
2266 } | |
2267 | |
2268 break; | |
2269 } | |
2270 | |
2271 case EVR_US: // unsigned short | |
2272 { | |
2273 Uint16 f; | |
2274 if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good()) | |
2275 { | |
2276 visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f); | |
2277 } | |
2278 | |
2279 break; | |
2280 } | |
2281 | |
2282 case EVR_FL: // float single-precision | |
2283 { | |
2284 Float32 f; | |
2285 if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good()) | |
2286 { | |
2287 visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f); | |
2288 } | |
2289 | |
2290 break; | |
2291 } | |
2292 | |
2293 case EVR_FD: // float double-precision | |
2294 { | |
2295 Float64 f; | |
2296 if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good()) | |
2297 { | |
2298 visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f); | |
2299 } | |
2300 | |
2301 break; | |
2302 } | |
2303 | |
2304 | |
2305 /** | |
2306 * Attribute tag. | |
2307 **/ | |
2308 | |
2309 case EVR_AT: | |
2310 { | |
2311 DcmTagKey tagKey; | |
2312 if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tagKey, 0).good()) | |
2313 { | |
2314 DicomTag t(tagKey.getGroup(), tagKey.getElement()); | |
2315 visitor.VisitAttribute(parentTags, parentIndexes, tag, vr, t); | |
2316 } | |
2317 | |
2318 break; | |
2319 } | |
2320 | |
2321 | |
2322 /** | |
2323 * Sequence types, should never occur at this point because of | |
2324 * "element.isLeaf()". | |
2325 **/ | |
2326 | |
2327 case EVR_SQ: // sequence of items | |
2328 return; | |
2329 | |
2330 | |
2331 /** | |
2332 * Internal to DCMTK. | |
2333 **/ | |
2334 | |
2335 case EVR_xs: // SS or US depending on context | |
2336 case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) | |
2337 case EVR_na: // na="not applicable", for data which has no VR | |
2338 case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor | |
2339 case EVR_item: // used internally for items | |
2340 case EVR_metainfo: // used internally for meta info datasets | |
2341 case EVR_dataset: // used internally for datasets | |
2342 case EVR_fileFormat: // used internally for DICOM files | |
2343 case EVR_dicomDir: // used internally for DICOMDIR objects | |
2344 case EVR_dirRecord: // used internally for DICOMDIR records | |
2345 case EVR_pixelSQ: // used internally for pixel sequences in a compressed image | |
2346 case EVR_pixelItem: // used internally for pixel items in a compressed image | |
2347 case EVR_PixelData: // used internally for uncompressed pixeld data | |
2348 case EVR_OverlayData: // used internally for overlay data | |
2349 visitor.VisitUnknown(parentTags, parentIndexes, tag, vr); | |
2350 return; | |
2351 | |
2352 | |
2353 /** | |
2354 * Default case. | |
2355 **/ | |
2356 | |
2357 default: | |
2358 return; | |
2359 } | |
2360 } | |
2361 catch (boost::bad_lexical_cast&) | |
2362 { | |
2363 return; | |
2364 } | |
2365 catch (std::bad_cast&) | |
2366 { | |
2367 return; | |
2368 } | |
2369 } | |
2370 | |
2371 | |
2372 static void ApplyVisitorToElement(DcmElement& element, | |
2373 ITagVisitor& visitor, | |
2374 const std::vector<DicomTag>& parentTags, | |
2375 const std::vector<size_t>& parentIndexes, | |
2376 Encoding encoding) | |
2377 { | |
2378 assert(parentTags.size() == parentIndexes.size()); | |
2379 | |
2380 DicomTag tag(FromDcmtkBridge::Convert(element.getTag())); | |
2381 | |
2382 if (element.isLeaf()) | |
2383 { | |
2384 ApplyVisitorToLeaf(element, visitor, parentTags, parentIndexes, tag, encoding); | |
2385 } | |
2386 else | |
2387 { | |
2388 // "All subclasses of DcmElement except for DcmSequenceOfItems | |
2389 // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset | |
2390 // etc. are not." The following dynamic_cast is thus OK. | |
2391 DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(element); | |
2392 | |
2393 std::vector<DicomTag> tags = parentTags; | |
2394 std::vector<size_t> indexes = parentIndexes; | |
2395 tags.push_back(tag); | |
2396 indexes.push_back(0); | |
2397 | |
2398 for (unsigned long i = 0; i < sequence.card(); i++) | |
2399 { | |
2400 indexes.back() = static_cast<size_t>(i); | |
2401 DcmItem* child = sequence.getItem(i); | |
2402 ApplyVisitorToDataset(*child, visitor, tags, indexes, encoding); | |
2403 } | |
2404 } | |
2405 } | |
2406 | |
2407 | |
2408 void FromDcmtkBridge::Apply(DcmItem& dataset, | |
2409 ITagVisitor& visitor, | |
2410 Encoding defaultEncoding) | |
2411 { | |
2412 std::vector<DicomTag> parentTags; | |
2413 std::vector<size_t> parentIndexes; | |
2414 Encoding encoding = DetectEncoding(dataset, defaultEncoding); | |
2415 ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding); | |
2416 } | |
2099 } | 2417 } |