Mercurial > hg > orthanc
comparison OrthancServer/FromDcmtkBridge.cpp @ 302:238134081136
modification of dicom files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Dec 2012 17:29:30 +0100 |
parents | 4d7469f72a0b |
children | c76a35a85c69 |
comparison
equal
deleted
inserted
replaced
301:be378326f50b | 302:238134081136 |
---|---|
45 | 45 |
46 #include <limits> | 46 #include <limits> |
47 | 47 |
48 #include <boost/lexical_cast.hpp> | 48 #include <boost/lexical_cast.hpp> |
49 | 49 |
50 #include <dcmtk/dcmdata/dcchrstr.h> | |
50 #include <dcmtk/dcmdata/dcdicent.h> | 51 #include <dcmtk/dcmdata/dcdicent.h> |
51 #include <dcmtk/dcmdata/dcdict.h> | 52 #include <dcmtk/dcmdata/dcdict.h> |
52 #include <dcmtk/dcmdata/dcfilefo.h> | 53 #include <dcmtk/dcmdata/dcfilefo.h> |
53 #include <dcmtk/dcmdata/dcistrmb.h> | 54 #include <dcmtk/dcmdata/dcistrmb.h> |
55 #include <dcmtk/dcmdata/dcuid.h> | |
56 | |
57 #include <dcmtk/dcmdata/dcvrae.h> | |
58 #include <dcmtk/dcmdata/dcvras.h> | |
59 #include <dcmtk/dcmdata/dcvrcs.h> | |
60 #include <dcmtk/dcmdata/dcvrda.h> | |
61 #include <dcmtk/dcmdata/dcvrds.h> | |
62 #include <dcmtk/dcmdata/dcvrdt.h> | |
54 #include <dcmtk/dcmdata/dcvrfd.h> | 63 #include <dcmtk/dcmdata/dcvrfd.h> |
55 #include <dcmtk/dcmdata/dcvrfl.h> | 64 #include <dcmtk/dcmdata/dcvrfl.h> |
65 #include <dcmtk/dcmdata/dcvris.h> | |
66 #include <dcmtk/dcmdata/dcvrlo.h> | |
67 #include <dcmtk/dcmdata/dcvrlt.h> | |
68 #include <dcmtk/dcmdata/dcvrpn.h> | |
69 #include <dcmtk/dcmdata/dcvrsh.h> | |
56 #include <dcmtk/dcmdata/dcvrsl.h> | 70 #include <dcmtk/dcmdata/dcvrsl.h> |
57 #include <dcmtk/dcmdata/dcvrss.h> | 71 #include <dcmtk/dcmdata/dcvrss.h> |
72 #include <dcmtk/dcmdata/dcvrst.h> | |
73 #include <dcmtk/dcmdata/dcvrtm.h> | |
74 #include <dcmtk/dcmdata/dcvrui.h> | |
58 #include <dcmtk/dcmdata/dcvrul.h> | 75 #include <dcmtk/dcmdata/dcvrul.h> |
59 #include <dcmtk/dcmdata/dcvrus.h> | 76 #include <dcmtk/dcmdata/dcvrus.h> |
60 #include <dcmtk/dcmdata/dcuid.h> | 77 #include <dcmtk/dcmdata/dcvrut.h> |
61 | 78 |
62 #include <boost/math/special_functions/round.hpp> | 79 #include <boost/math/special_functions/round.hpp> |
63 #include <glog/logging.h> | 80 #include <glog/logging.h> |
64 #include <dcmtk/dcmdata/dcostrmb.h> | 81 #include <dcmtk/dcmdata/dcostrmb.h> |
65 | 82 |
84 file_->transferEnd(); | 101 file_->transferEnd(); |
85 } | 102 } |
86 | 103 |
87 | 104 |
88 static void SendPathValueForDictionary(RestApiOutput& output, | 105 static void SendPathValueForDictionary(RestApiOutput& output, |
89 DcmItem& dicom) | 106 DcmItem& dicom) |
90 { | 107 { |
91 Json::Value v = Json::arrayValue; | 108 Json::Value v = Json::arrayValue; |
92 | 109 |
93 for (unsigned long i = 0; i < dicom.card(); i++) | 110 for (unsigned long i = 0; i < dicom.card(); i++) |
94 { | 111 { |
162 } | 179 } |
163 | 180 |
164 output.AnswerJson(v); | 181 output.AnswerJson(v); |
165 } | 182 } |
166 | 183 |
167 static void SendField(RestApiOutput& output, | 184 static void AnswerDicomField(RestApiOutput& output, |
168 DcmElement& element) | 185 DcmElement& element) |
169 { | 186 { |
170 // This element is not a sequence | 187 // This element is not a sequence |
171 std::string buffer; | 188 std::string buffer; |
172 buffer.resize(65536); | 189 buffer.resize(65536); |
173 Uint32 length = element.getLength(); | 190 Uint32 length = element.getLength(); |
192 output.GetLowLevelOutput().Send(&buffer[0], nbytes); | 209 output.GetLowLevelOutput().Send(&buffer[0], nbytes); |
193 offset += nbytes; | 210 offset += nbytes; |
194 } | 211 } |
195 else | 212 else |
196 { | 213 { |
214 LOG(ERROR) << "Error while sending a DICOM field"; | |
197 return; | 215 return; |
198 } | 216 } |
199 } | 217 } |
200 | 218 |
201 output.MarkLowLevelOutputDone(); | 219 output.MarkLowLevelOutputDone(); |
224 if (dicom.findAndGetElement(k, element).good() && | 242 if (dicom.findAndGetElement(k, element).good() && |
225 element != NULL && | 243 element != NULL && |
226 element->getVR() != EVR_UNKNOWN && | 244 element->getVR() != EVR_UNKNOWN && |
227 element->getVR() != EVR_SQ) | 245 element->getVR() != EVR_SQ) |
228 { | 246 { |
229 SendField(output, *element); | 247 AnswerDicomField(output, *element); |
230 } | 248 } |
231 } | 249 } |
232 | 250 |
233 void ParsedDicomFile::SendPathValue(RestApiOutput& output, | 251 void ParsedDicomFile::SendPathValue(RestApiOutput& output, |
234 const UriComponents& uri) | 252 const UriComponents& uri) |
270 SendPathValueForLeaf(output, uri.back(), *dicom); | 288 SendPathValueForLeaf(output, uri.back(), *dicom); |
271 } | 289 } |
272 } | 290 } |
273 | 291 |
274 | 292 |
275 void FromDcmtkBridge::Convert(DicomMap& target, DcmDataset& dataset) | 293 |
276 { | 294 |
277 target.Clear(); | 295 |
278 for (unsigned long i = 0; i < dataset.card(); i++) | 296 static DcmElement* CreateElementForTag(const DicomTag& tag) |
279 { | 297 { |
280 DcmElement* element = dataset.getElement(i); | 298 DcmTag key(tag.GetGroup(), tag.GetElement()); |
281 if (element && element->isLeaf()) | 299 |
282 { | 300 switch (key.getEVR()) |
283 target.SetValue(element->getTag().getGTag(), | |
284 element->getTag().getETag(), | |
285 ConvertLeafElement(*element)); | |
286 } | |
287 } | |
288 } | |
289 | |
290 | |
291 DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) | |
292 { | |
293 return DicomTag(element.getGTag(), element.getETag()); | |
294 } | |
295 | |
296 | |
297 DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element) | |
298 { | |
299 if (!element.isLeaf()) | |
300 { | |
301 throw OrthancException("Only applicable to leaf elements"); | |
302 } | |
303 | |
304 if (element.isaString()) | |
305 { | |
306 char *c; | |
307 if (element.getString(c).good() && | |
308 c != NULL) | |
309 { | |
310 std::string s(c); | |
311 std::string utf8 = Toolbox::ConvertToUtf8(s, "ISO-8859-1"); // TODO Parameter? | |
312 return new DicomString(utf8); | |
313 } | |
314 else | |
315 { | |
316 return new DicomNullValue; | |
317 } | |
318 } | |
319 | |
320 try | |
321 { | 301 { |
322 // http://support.dcmtk.org/docs/dcvr_8h-source.html | 302 // http://support.dcmtk.org/docs/dcvr_8h-source.html |
323 switch (element.getVR()) | 303 |
324 { | 304 /** |
325 | 305 * TODO. |
326 /** | 306 **/ |
327 * TODO. | |
328 **/ | |
329 | 307 |
330 case EVR_DS: // decimal string | |
331 case EVR_IS: // integer string | |
332 case EVR_OB: // other byte | 308 case EVR_OB: // other byte |
333 case EVR_OF: // other float | 309 case EVR_OF: // other float |
334 case EVR_OW: // other word | 310 case EVR_OW: // other word |
311 case EVR_AT: // attribute tag | |
312 throw OrthancException(ErrorCode_NotImplemented); | |
313 | |
314 case EVR_UN: // unknown value representation | |
315 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
316 | |
317 | |
318 /** | |
319 * String types. | |
320 * http://support.dcmtk.org/docs/classDcmByteString.html | |
321 **/ | |
322 | |
335 case EVR_AS: // age string | 323 case EVR_AS: // age string |
336 case EVR_AT: // attribute tag | 324 return new DcmAgeString(key); |
325 | |
326 case EVR_AE: // application entity title | |
327 return new DcmApplicationEntity(key); | |
328 | |
329 case EVR_CS: // code string | |
330 return new DcmCodeString(key); | |
331 | |
337 case EVR_DA: // date string | 332 case EVR_DA: // date string |
333 return new DcmDate(key); | |
334 | |
338 case EVR_DT: // date time string | 335 case EVR_DT: // date time string |
336 return new DcmDateTime(key); | |
337 | |
338 case EVR_DS: // decimal string | |
339 return new DcmDecimalString(key); | |
340 | |
341 case EVR_IS: // integer string | |
342 return new DcmIntegerString(key); | |
343 | |
339 case EVR_TM: // time string | 344 case EVR_TM: // time string |
340 case EVR_UN: // unknown value representation | 345 return new DcmTime(key); |
341 return new DicomNullValue(); | 346 |
342 | 347 case EVR_UI: // unique identifier |
343 | 348 return new DcmUniqueIdentifier(key); |
344 /** | 349 |
345 * String types, should never happen at this point because of | 350 case EVR_ST: // short text |
346 * "element.isaString()". | 351 return new DcmShortText(key); |
347 **/ | 352 |
348 | 353 case EVR_LO: // long string |
349 case EVR_AE: // application entity title | 354 return new DcmLongString(key); |
350 case EVR_CS: // code string | 355 |
356 case EVR_LT: // long text | |
357 return new DcmLongText(key); | |
358 | |
359 case EVR_UT: // unlimited text | |
360 return new DcmUnlimitedText(key); | |
361 | |
351 case EVR_SH: // short string | 362 case EVR_SH: // short string |
352 case EVR_LO: // long string | 363 return new DcmShortString(key); |
353 case EVR_ST: // short text | 364 |
354 case EVR_LT: // long text | |
355 case EVR_UT: // unlimited text | |
356 case EVR_PN: // person name | 365 case EVR_PN: // person name |
357 case EVR_UI: // unique identifier | 366 return new DcmPersonName(key); |
358 return new DicomNullValue(); | 367 |
359 | 368 |
360 | 369 /** |
361 /** | 370 * Numerical types |
362 * Numerical types | 371 **/ |
363 **/ | |
364 | 372 |
365 case EVR_SL: // signed long | 373 case EVR_SL: // signed long |
366 { | 374 return new DcmSignedLong(key); |
367 Sint32 f; | |
368 if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good()) | |
369 { | |
370 return new DicomString(boost::lexical_cast<std::string>(f)); | |
371 } | |
372 else | |
373 { | |
374 return new DicomNullValue(); | |
375 } | |
376 } | |
377 | 375 |
378 case EVR_SS: // signed short | 376 case EVR_SS: // signed short |
379 { | 377 return new DcmSignedShort(key); |
380 Sint16 f; | |
381 if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good()) | |
382 { | |
383 return new DicomString(boost::lexical_cast<std::string>(f)); | |
384 } | |
385 else | |
386 { | |
387 return new DicomNullValue(); | |
388 } | |
389 } | |
390 | 378 |
391 case EVR_UL: // unsigned long | 379 case EVR_UL: // unsigned long |
392 { | 380 return new DcmUnsignedLong(key); |
393 Uint32 f; | |
394 if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good()) | |
395 { | |
396 return new DicomString(boost::lexical_cast<std::string>(f)); | |
397 } | |
398 else | |
399 { | |
400 return new DicomNullValue(); | |
401 } | |
402 } | |
403 | 381 |
404 case EVR_US: // unsigned short | 382 case EVR_US: // unsigned short |
405 { | 383 return new DcmUnsignedShort(key); |
406 Uint16 f; | |
407 if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good()) | |
408 { | |
409 return new DicomString(boost::lexical_cast<std::string>(f)); | |
410 } | |
411 else | |
412 { | |
413 return new DicomNullValue(); | |
414 } | |
415 } | |
416 | 384 |
417 case EVR_FL: // float single-precision | 385 case EVR_FL: // float single-precision |
418 { | 386 return new DcmFloatingPointSingle(key); |
419 Float32 f; | |
420 if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good()) | |
421 { | |
422 return new DicomString(boost::lexical_cast<std::string>(f)); | |
423 } | |
424 else | |
425 { | |
426 return new DicomNullValue(); | |
427 } | |
428 } | |
429 | 387 |
430 case EVR_FD: // float double-precision | 388 case EVR_FD: // float double-precision |
431 { | 389 return new DcmFloatingPointDouble(key); |
432 Float64 f; | |
433 if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good()) | |
434 { | |
435 return new DicomString(boost::lexical_cast<std::string>(f)); | |
436 } | |
437 else | |
438 { | |
439 return new DicomNullValue(); | |
440 } | |
441 } | |
442 | 390 |
443 | 391 |
444 /** | 392 /** |
445 * Sequence types, should never occur at this point because of | 393 * Sequence types, should never occur at this point. |
446 * "element.isLeaf()". | |
447 **/ | 394 **/ |
448 | 395 |
449 case EVR_SQ: // sequence of items | 396 case EVR_SQ: // sequence of items |
450 return new DicomNullValue; | 397 throw OrthancException(ErrorCode_ParameterOutOfRange); |
451 | 398 |
452 | 399 |
453 /** | 400 /** |
454 * Internal to DCMTK. | 401 * Internal to DCMTK. |
455 **/ | 402 **/ |
456 | 403 |
457 case EVR_ox: // OB or OW depending on context | 404 case EVR_ox: // OB or OW depending on context |
458 case EVR_xs: // SS or US depending on context | 405 case EVR_xs: // SS or US depending on context |
459 case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) | 406 case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) |
460 case EVR_na: // na="not applicable", for data which has no VR | 407 case EVR_na: // na="not applicable", for data which has no VR |
469 case EVR_pixelItem: // used internally for pixel items in a compressed image | 416 case EVR_pixelItem: // used internally for pixel items in a compressed image |
470 case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) | 417 case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) |
471 case EVR_PixelData: // used internally for uncompressed pixeld data | 418 case EVR_PixelData: // used internally for uncompressed pixeld data |
472 case EVR_OverlayData: // used internally for overlay data | 419 case EVR_OverlayData: // used internally for overlay data |
473 case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR | 420 case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR |
421 default: | |
422 break; | |
423 } | |
424 | |
425 throw OrthancException(ErrorCode_InternalError); | |
426 } | |
427 | |
428 | |
429 | |
430 static void FillElementWithString(DcmElement& element, | |
431 const DicomTag& tag, | |
432 const std::string& value) | |
433 { | |
434 DcmTag key(tag.GetGroup(), tag.GetElement()); | |
435 bool ok = false; | |
436 | |
437 try | |
438 { | |
439 switch (key.getEVR()) | |
440 { | |
441 // http://support.dcmtk.org/docs/dcvr_8h-source.html | |
442 | |
443 /** | |
444 * TODO. | |
445 **/ | |
446 | |
447 case EVR_OB: // other byte | |
448 case EVR_OF: // other float | |
449 case EVR_OW: // other word | |
450 case EVR_AT: // attribute tag | |
451 throw OrthancException(ErrorCode_NotImplemented); | |
452 | |
453 case EVR_UN: // unknown value representation | |
454 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
455 | |
456 | |
457 /** | |
458 * String types. | |
459 **/ | |
460 | |
461 case EVR_DS: // decimal string | |
462 case EVR_IS: // integer string | |
463 case EVR_AS: // age string | |
464 case EVR_DA: // date string | |
465 case EVR_DT: // date time string | |
466 case EVR_TM: // time string | |
467 case EVR_AE: // application entity title | |
468 case EVR_CS: // code string | |
469 case EVR_SH: // short string | |
470 case EVR_LO: // long string | |
471 case EVR_ST: // short text | |
472 case EVR_LT: // long text | |
473 case EVR_UT: // unlimited text | |
474 case EVR_PN: // person name | |
475 case EVR_UI: // unique identifier | |
476 { | |
477 ok = element.putString(value.c_str()).good(); | |
478 break; | |
479 } | |
480 | |
481 | |
482 /** | |
483 * Numerical types | |
484 **/ | |
485 | |
486 case EVR_SL: // signed long | |
487 { | |
488 ok = element.putSint32(boost::lexical_cast<Sint32>(value)).good(); | |
489 break; | |
490 } | |
491 | |
492 case EVR_SS: // signed short | |
493 { | |
494 ok = element.putSint16(boost::lexical_cast<Sint16>(value)).good(); | |
495 break; | |
496 } | |
497 | |
498 case EVR_UL: // unsigned long | |
499 { | |
500 ok = element.putUint32(boost::lexical_cast<Uint32>(value)).good(); | |
501 break; | |
502 } | |
503 | |
504 case EVR_US: // unsigned short | |
505 { | |
506 ok = element.putUint16(boost::lexical_cast<Uint16>(value)).good(); | |
507 break; | |
508 } | |
509 | |
510 case EVR_FL: // float single-precision | |
511 { | |
512 ok = element.putFloat32(boost::lexical_cast<float>(value)).good(); | |
513 break; | |
514 } | |
515 | |
516 case EVR_FD: // float double-precision | |
517 { | |
518 ok = element.putFloat64(boost::lexical_cast<double>(value)).good(); | |
519 break; | |
520 } | |
521 | |
522 | |
523 /** | |
524 * Sequence types, should never occur at this point. | |
525 **/ | |
526 | |
527 case EVR_SQ: // sequence of items | |
528 { | |
529 ok = false; | |
530 break; | |
531 } | |
532 | |
533 | |
534 /** | |
535 * Internal to DCMTK. | |
536 **/ | |
537 | |
538 case EVR_ox: // OB or OW depending on context | |
539 case EVR_xs: // SS or US depending on context | |
540 case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) | |
541 case EVR_na: // na="not applicable", for data which has no VR | |
542 case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor | |
543 case EVR_item: // used internally for items | |
544 case EVR_metainfo: // used internally for meta info datasets | |
545 case EVR_dataset: // used internally for datasets | |
546 case EVR_fileFormat: // used internally for DICOM files | |
547 case EVR_dicomDir: // used internally for DICOMDIR objects | |
548 case EVR_dirRecord: // used internally for DICOMDIR records | |
549 case EVR_pixelSQ: // used internally for pixel sequences in a compressed image | |
550 case EVR_pixelItem: // used internally for pixel items in a compressed image | |
551 case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) | |
552 case EVR_PixelData: // used internally for uncompressed pixeld data | |
553 case EVR_OverlayData: // used internally for overlay data | |
554 case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR | |
555 default: | |
556 break; | |
557 } | |
558 } | |
559 catch (boost::bad_lexical_cast&) | |
560 { | |
561 ok = false; | |
562 } | |
563 | |
564 if (!ok) | |
565 { | |
566 throw OrthancException(ErrorCode_InternalError); | |
567 } | |
568 } | |
569 | |
570 | |
571 void ParsedDicomFile::Remove(const DicomTag& tag) | |
572 { | |
573 DcmTagKey key(tag.GetGroup(), tag.GetElement()); | |
574 | |
575 // TODO This call results in memory leaks inside DCMTK | |
576 file_->getDataset()->remove(key); | |
577 } | |
578 | |
579 | |
580 | |
581 void ParsedDicomFile::Insert(const DicomTag& tag, | |
582 const std::string& value) | |
583 { | |
584 std::auto_ptr<DcmElement> element(CreateElementForTag(tag)); | |
585 FillElementWithString(*element, tag, value); | |
586 | |
587 if (!file_->getDataset()->insert(element.release(), false, false).good()) | |
588 { | |
589 // This field already exists | |
590 throw OrthancException(ErrorCode_InternalError); | |
591 } | |
592 } | |
593 | |
594 | |
595 void ParsedDicomFile::ReplaceInternal(const DicomTag& tag, | |
596 const std::string& value, | |
597 bool insertOnAbsent) | |
598 { | |
599 DcmTagKey key(tag.GetGroup(), tag.GetElement()); | |
600 DcmElement* element = NULL; | |
601 | |
602 if (!file_->getDataset()->findAndGetElement(key, element).good() || | |
603 element == NULL) | |
604 { | |
605 if (insertOnAbsent) | |
606 { | |
607 // This field does not exist, use "Insert()" instead | |
608 Insert(tag, value); | |
609 } | |
610 else | |
611 { | |
612 throw OrthancException(ErrorCode_InternalError); | |
613 } | |
614 } | |
615 else | |
616 { | |
617 FillElementWithString(*element, tag, value); | |
618 } | |
619 } | |
620 | |
621 | |
622 void ParsedDicomFile::Replace(const DicomTag& tag, | |
623 const std::string& value) | |
624 { | |
625 return ReplaceInternal(tag, value, false); | |
626 } | |
627 | |
628 void ParsedDicomFile::InsertOrReplace(const DicomTag& tag, | |
629 const std::string& value) | |
630 { | |
631 return ReplaceInternal(tag, value, true); | |
632 } | |
633 | |
634 | |
635 | |
636 void ParsedDicomFile::Answer(RestApiOutput& output) | |
637 { | |
638 std::string serialized; | |
639 if (FromDcmtkBridge::SaveToMemoryBuffer(serialized, file_->getDataset())) | |
640 { | |
641 output.AnswerBuffer(serialized, "application/octet-stream"); | |
642 } | |
643 } | |
644 | |
645 | |
646 void FromDcmtkBridge::Convert(DicomMap& target, DcmDataset& dataset) | |
647 { | |
648 target.Clear(); | |
649 for (unsigned long i = 0; i < dataset.card(); i++) | |
650 { | |
651 DcmElement* element = dataset.getElement(i); | |
652 if (element && element->isLeaf()) | |
653 { | |
654 target.SetValue(element->getTag().getGTag(), | |
655 element->getTag().getETag(), | |
656 ConvertLeafElement(*element)); | |
657 } | |
658 } | |
659 } | |
660 | |
661 | |
662 DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) | |
663 { | |
664 return DicomTag(element.getGTag(), element.getETag()); | |
665 } | |
666 | |
667 | |
668 DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element) | |
669 { | |
670 if (!element.isLeaf()) | |
671 { | |
672 throw OrthancException("Only applicable to leaf elements"); | |
673 } | |
674 | |
675 if (element.isaString()) | |
676 { | |
677 char *c; | |
678 if (element.getString(c).good() && | |
679 c != NULL) | |
680 { | |
681 std::string s(c); | |
682 std::string utf8 = Toolbox::ConvertToUtf8(s, "ISO-8859-1"); // TODO Parameter? | |
683 return new DicomString(utf8); | |
684 } | |
685 else | |
686 { | |
474 return new DicomNullValue; | 687 return new DicomNullValue; |
475 | 688 } |
689 } | |
690 | |
691 try | |
692 { | |
693 // http://support.dcmtk.org/docs/dcvr_8h-source.html | |
694 switch (element.getVR()) | |
695 { | |
476 | 696 |
477 /** | 697 /** |
478 * Default case. | 698 * TODO. |
479 **/ | 699 **/ |
480 | 700 |
481 default: | 701 case EVR_DS: // decimal string |
482 return new DicomNullValue; | 702 case EVR_IS: // integer string |
703 case EVR_OB: // other byte | |
704 case EVR_OF: // other float | |
705 case EVR_OW: // other word | |
706 case EVR_AS: // age string | |
707 case EVR_AT: // attribute tag | |
708 case EVR_DA: // date string | |
709 case EVR_DT: // date time string | |
710 case EVR_TM: // time string | |
711 case EVR_UN: // unknown value representation | |
712 return new DicomNullValue(); | |
713 | |
714 | |
715 /** | |
716 * String types, should never happen at this point because of | |
717 * "element.isaString()". | |
718 **/ | |
719 | |
720 case EVR_AE: // application entity title | |
721 case EVR_CS: // code string | |
722 case EVR_SH: // short string | |
723 case EVR_LO: // long string | |
724 case EVR_ST: // short text | |
725 case EVR_LT: // long text | |
726 case EVR_UT: // unlimited text | |
727 case EVR_PN: // person name | |
728 case EVR_UI: // unique identifier | |
729 return new DicomNullValue(); | |
730 | |
731 | |
732 /** | |
733 * Numerical types | |
734 **/ | |
735 | |
736 case EVR_SL: // signed long | |
737 { | |
738 Sint32 f; | |
739 if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good()) | |
740 { | |
741 return new DicomString(boost::lexical_cast<std::string>(f)); | |
742 } | |
743 else | |
744 { | |
745 return new DicomNullValue(); | |
746 } | |
747 } | |
748 | |
749 case EVR_SS: // signed short | |
750 { | |
751 Sint16 f; | |
752 if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good()) | |
753 { | |
754 return new DicomString(boost::lexical_cast<std::string>(f)); | |
755 } | |
756 else | |
757 { | |
758 return new DicomNullValue(); | |
759 } | |
760 } | |
761 | |
762 case EVR_UL: // unsigned long | |
763 { | |
764 Uint32 f; | |
765 if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good()) | |
766 { | |
767 return new DicomString(boost::lexical_cast<std::string>(f)); | |
768 } | |
769 else | |
770 { | |
771 return new DicomNullValue(); | |
772 } | |
773 } | |
774 | |
775 case EVR_US: // unsigned short | |
776 { | |
777 Uint16 f; | |
778 if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good()) | |
779 { | |
780 return new DicomString(boost::lexical_cast<std::string>(f)); | |
781 } | |
782 else | |
783 { | |
784 return new DicomNullValue(); | |
785 } | |
786 } | |
787 | |
788 case EVR_FL: // float single-precision | |
789 { | |
790 Float32 f; | |
791 if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good()) | |
792 { | |
793 return new DicomString(boost::lexical_cast<std::string>(f)); | |
794 } | |
795 else | |
796 { | |
797 return new DicomNullValue(); | |
798 } | |
799 } | |
800 | |
801 case EVR_FD: // float double-precision | |
802 { | |
803 Float64 f; | |
804 if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good()) | |
805 { | |
806 return new DicomString(boost::lexical_cast<std::string>(f)); | |
807 } | |
808 else | |
809 { | |
810 return new DicomNullValue(); | |
811 } | |
812 } | |
813 | |
814 | |
815 /** | |
816 * Sequence types, should never occur at this point because of | |
817 * "element.isLeaf()". | |
818 **/ | |
819 | |
820 case EVR_SQ: // sequence of items | |
821 return new DicomNullValue; | |
822 | |
823 | |
824 /** | |
825 * Internal to DCMTK. | |
826 **/ | |
827 | |
828 case EVR_ox: // OB or OW depending on context | |
829 case EVR_xs: // SS or US depending on context | |
830 case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) | |
831 case EVR_na: // na="not applicable", for data which has no VR | |
832 case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor | |
833 case EVR_item: // used internally for items | |
834 case EVR_metainfo: // used internally for meta info datasets | |
835 case EVR_dataset: // used internally for datasets | |
836 case EVR_fileFormat: // used internally for DICOM files | |
837 case EVR_dicomDir: // used internally for DICOMDIR objects | |
838 case EVR_dirRecord: // used internally for DICOMDIR records | |
839 case EVR_pixelSQ: // used internally for pixel sequences in a compressed image | |
840 case EVR_pixelItem: // used internally for pixel items in a compressed image | |
841 case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) | |
842 case EVR_PixelData: // used internally for uncompressed pixeld data | |
843 case EVR_OverlayData: // used internally for overlay data | |
844 case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR | |
845 return new DicomNullValue; | |
846 | |
847 | |
848 /** | |
849 * Default case. | |
850 **/ | |
851 | |
852 default: | |
853 return new DicomNullValue; | |
483 } | 854 } |
484 } | 855 } |
485 catch (boost::bad_lexical_cast) | 856 catch (boost::bad_lexical_cast) |
486 { | 857 { |
487 return new DicomNullValue; | 858 return new DicomNullValue; |
676 } | 1047 } |
677 | 1048 |
678 PixelFormat format; | 1049 PixelFormat format; |
679 switch (mode) | 1050 switch (mode) |
680 { | 1051 { |
681 case ImageExtractionMode_Preview: | 1052 case ImageExtractionMode_Preview: |
682 case ImageExtractionMode_UInt8: | 1053 case ImageExtractionMode_UInt8: |
683 format = PixelFormat_Grayscale8; | 1054 format = PixelFormat_Grayscale8; |
684 break; | 1055 break; |
685 | 1056 |
686 case ImageExtractionMode_UInt16: | 1057 case ImageExtractionMode_UInt16: |
687 format = PixelFormat_Grayscale16; | 1058 format = PixelFormat_Grayscale16; |
688 break; | 1059 break; |
689 | 1060 |
690 default: | 1061 default: |
691 throw OrthancException(ErrorCode_NotImplemented); | 1062 throw OrthancException(ErrorCode_NotImplemented); |
692 } | 1063 } |
693 | 1064 |
694 if (accessor.get() == NULL || | 1065 if (accessor.get() == NULL || |
695 accessor->GetWidth() == 0 || | 1066 accessor->GetWidth() == 0 || |
696 accessor->GetHeight() == 0) | 1067 accessor->GetHeight() == 0) |
700 } | 1071 } |
701 else | 1072 else |
702 { | 1073 { |
703 switch (mode) | 1074 switch (mode) |
704 { | 1075 { |
705 case ImageExtractionMode_Preview: | 1076 case ImageExtractionMode_Preview: |
706 ExtractPngImagePreview(result, *accessor); | 1077 ExtractPngImagePreview(result, *accessor); |
707 break; | 1078 break; |
708 | 1079 |
709 case ImageExtractionMode_UInt8: | 1080 case ImageExtractionMode_UInt8: |
710 ExtractPngImageTruncate<uint8_t>(result, *accessor, format); | 1081 ExtractPngImageTruncate<uint8_t>(result, *accessor, format); |
711 break; | 1082 break; |
712 | 1083 |
713 case ImageExtractionMode_UInt16: | 1084 case ImageExtractionMode_UInt16: |
714 ExtractPngImageTruncate<uint16_t>(result, *accessor, format); | 1085 ExtractPngImageTruncate<uint16_t>(result, *accessor, format); |
715 break; | 1086 break; |
716 | 1087 |
717 default: | 1088 default: |
718 throw OrthancException(ErrorCode_NotImplemented); | 1089 throw OrthancException(ErrorCode_NotImplemented); |
719 } | 1090 } |
720 } | 1091 } |
721 } | 1092 } |
722 | 1093 |
723 | 1094 |
826 { | 1197 { |
827 char uid[100]; | 1198 char uid[100]; |
828 | 1199 |
829 switch (level) | 1200 switch (level) |
830 { | 1201 { |
831 case DicomRootLevel_Instance: | 1202 case DicomRootLevel_Instance: |
832 return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); | 1203 return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); |
833 | 1204 |
834 case DicomRootLevel_Series: | 1205 case DicomRootLevel_Series: |
835 return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT); | 1206 return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT); |
836 | 1207 |
837 case DicomRootLevel_Study: | 1208 case DicomRootLevel_Study: |
838 return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT); | 1209 return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT); |
839 | 1210 |
840 default: | 1211 default: |
841 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1212 throw OrthancException(ErrorCode_ParameterOutOfRange); |
842 } | 1213 } |
843 } | 1214 } |
844 | 1215 |
845 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, | 1216 bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, |
846 DcmDataset* dataSet) | 1217 DcmDataset* dataSet) |
887 OFstatic_cast(Uint32, /*opt_filepad*/ 0), | 1258 OFstatic_cast(Uint32, /*opt_filepad*/ 0), |
888 OFstatic_cast(Uint32, /*opt_itempad*/ 0), | 1259 OFstatic_cast(Uint32, /*opt_itempad*/ 0), |
889 (opt_useMetaheader) ? EWM_fileformat : EWM_dataset); | 1260 (opt_useMetaheader) ? EWM_fileformat : EWM_dataset); |
890 #endif | 1261 #endif |
891 } | 1262 } |
892 | |
893 | |
894 } | 1263 } |