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 }