Mercurial > hg > orthanc
comparison OrthancFramework/Sources/DicomFormat/DicomStreamReader.cpp @ 4493:b57ca702a430
DicomStreamReader::LookupPixelDataOffset()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 04 Feb 2021 11:42:25 +0100 |
parents | d9473bd5ed43 |
children | 39192eb9b43d |
comparison
equal
deleted
inserted
replaced
4492:0b2484663233 | 4493:b57ca702a430 |
---|---|
24 #include "DicomStreamReader.h" | 24 #include "DicomStreamReader.h" |
25 | 25 |
26 #include "../OrthancException.h" | 26 #include "../OrthancException.h" |
27 | 27 |
28 #include <cassert> | 28 #include <cassert> |
29 #include <sstream> | |
30 | |
29 | 31 |
30 namespace Orthanc | 32 namespace Orthanc |
31 { | 33 { |
32 static bool IsNormalizationNeeded(const std::string& source, | 34 static bool IsNormalizationNeeded(const std::string& source, |
33 ValueRepresentation vr) | 35 ValueRepresentation vr) |
321 throw OrthancException(ErrorCode_InternalError); | 323 throw OrthancException(ErrorCode_InternalError); |
322 } | 324 } |
323 } | 325 } |
324 else | 326 else |
325 { | 327 { |
328 assert(reader_.GetProcessedBytes() >= block.size()); | |
329 const uint64_t tagOffset = reader_.GetProcessedBytes() - block.size(); | |
330 | |
326 ValueRepresentation vr = ValueRepresentation_Unknown; | 331 ValueRepresentation vr = ValueRepresentation_Unknown; |
327 | 332 |
328 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) | 333 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) |
329 { | 334 { |
330 if (sequenceDepth_ == 0) | 335 if (sequenceDepth_ == 0) |
331 { | 336 { |
332 danglingTag_ = tag; | 337 danglingTag_ = tag; |
333 danglingVR_ = vr; | 338 danglingVR_ = vr; |
339 danglingOffset_ = tagOffset; | |
334 } | 340 } |
335 | 341 |
336 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); | 342 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); |
337 HandleDatasetExplicitLength(length); | 343 HandleDatasetExplicitLength(length); |
338 } | 344 } |
370 | 376 |
371 if (sequenceDepth_ == 0) | 377 if (sequenceDepth_ == 0) |
372 { | 378 { |
373 danglingTag_ = tag; | 379 danglingTag_ = tag; |
374 danglingVR_ = vr; | 380 danglingVR_ = vr; |
381 danglingOffset_ = tagOffset; | |
375 } | 382 } |
376 } | 383 } |
377 } | 384 } |
378 } | 385 } |
379 | 386 |
398 state_ = State_DatasetValue; | 405 state_ = State_DatasetValue; |
399 } | 406 } |
400 } | 407 } |
401 | 408 |
402 | 409 |
403 void DicomStreamReader::HandleDatasetExplicitLength(const std::string& block) | 410 void DicomStreamReader::HandleDatasetExplicitLength(IVisitor& visitor, |
411 const std::string& block) | |
404 { | 412 { |
405 assert(block.size() == 4); | 413 assert(block.size() == 4); |
406 | 414 |
407 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); | 415 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); |
408 HandleDatasetExplicitLength(length); | 416 HandleDatasetExplicitLength(length); |
417 | |
418 std::string empty; | |
419 if (!visitor.VisitDatasetTag(danglingTag_, danglingVR_, empty, IsLittleEndian(), danglingOffset_)) | |
420 { | |
421 state_ = State_Done; | |
422 } | |
409 } | 423 } |
410 | 424 |
411 | 425 |
412 void DicomStreamReader::HandleSequenceExplicitLength(const std::string& block) | 426 void DicomStreamReader::HandleSequenceExplicitLength(const std::string& block) |
413 { | 427 { |
449 bool c; | 463 bool c; |
450 | 464 |
451 if (IsNormalizationNeeded(block, danglingVR_)) | 465 if (IsNormalizationNeeded(block, danglingVR_)) |
452 { | 466 { |
453 std::string s(block.begin(), block.end() - 1); | 467 std::string s(block.begin(), block.end() - 1); |
454 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, s, IsLittleEndian()); | 468 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, s, IsLittleEndian(), danglingOffset_); |
455 } | 469 } |
456 else | 470 else |
457 { | 471 { |
458 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, block, IsLittleEndian()); | 472 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, block, IsLittleEndian(), danglingOffset_); |
459 } | 473 } |
460 | 474 |
461 if (!c) | 475 if (!c) |
462 { | 476 { |
463 state_ = State_Done; | 477 state_ = State_Done; |
464 return; | 478 return; |
465 } | 479 } |
474 reader_(stream), | 488 reader_(stream), |
475 state_(State_Preamble), | 489 state_(State_Preamble), |
476 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy | 490 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy |
477 danglingTag_(0x0000, 0x0000), // Dummy | 491 danglingTag_(0x0000, 0x0000), // Dummy |
478 danglingVR_(ValueRepresentation_Unknown), // Dummy | 492 danglingVR_(ValueRepresentation_Unknown), // Dummy |
493 danglingOffset_(0), // Dummy | |
479 sequenceDepth_(0) | 494 sequenceDepth_(0) |
480 { | 495 { |
481 reader_.Schedule(128 /* empty header */ + | 496 reader_.Schedule(128 /* empty header */ + |
482 4 /* "DICM" magic value */ + | 497 4 /* "DICM" magic value */ + |
483 4 /* (0x0002, 0x0000) tag */ + | 498 4 /* (0x0002, 0x0000) tag */ + |
508 case State_DatasetTag: | 523 case State_DatasetTag: |
509 HandleDatasetTag(block, untilTag); | 524 HandleDatasetTag(block, untilTag); |
510 break; | 525 break; |
511 | 526 |
512 case State_DatasetExplicitLength: | 527 case State_DatasetExplicitLength: |
513 HandleDatasetExplicitLength(block); | 528 HandleDatasetExplicitLength(visitor, block); |
514 break; | 529 break; |
515 | 530 |
516 case State_SequenceExplicitLength: | 531 case State_SequenceExplicitLength: |
517 HandleSequenceExplicitLength(block); | 532 HandleSequenceExplicitLength(block); |
518 break; | 533 break; |
552 | 567 |
553 uint64_t DicomStreamReader::GetProcessedBytes() const | 568 uint64_t DicomStreamReader::GetProcessedBytes() const |
554 { | 569 { |
555 return reader_.GetProcessedBytes(); | 570 return reader_.GetProcessedBytes(); |
556 } | 571 } |
572 | |
573 | |
574 class DicomStreamReader::PixelDataVisitor : public DicomStreamReader::IVisitor | |
575 { | |
576 private: | |
577 bool hasPixelData_; | |
578 uint64_t pixelDataOffset_; | |
579 | |
580 public: | |
581 PixelDataVisitor() : | |
582 hasPixelData_(false), | |
583 pixelDataOffset_(0) | |
584 { | |
585 } | |
586 | |
587 virtual void VisitMetaHeaderTag(const DicomTag& tag, | |
588 const ValueRepresentation& vr, | |
589 const std::string& value) ORTHANC_OVERRIDE | |
590 { | |
591 } | |
592 | |
593 virtual void VisitTransferSyntax(DicomTransferSyntax transferSyntax) ORTHANC_OVERRIDE | |
594 { | |
595 } | |
596 | |
597 virtual bool VisitDatasetTag(const DicomTag& tag, | |
598 const ValueRepresentation& vr, | |
599 const std::string& value, | |
600 bool isLittleEndian, | |
601 uint64_t fileOffset) ORTHANC_OVERRIDE | |
602 { | |
603 if (tag == DICOM_TAG_PIXEL_DATA) | |
604 { | |
605 hasPixelData_ = true; | |
606 pixelDataOffset_ = fileOffset; | |
607 } | |
608 | |
609 // Stop processing once pixel data has been passed | |
610 return (tag < DICOM_TAG_PIXEL_DATA); | |
611 } | |
612 | |
613 bool HasPixelData() const | |
614 { | |
615 return hasPixelData_; | |
616 } | |
617 | |
618 uint64_t GetPixelDataOffset() const | |
619 { | |
620 return pixelDataOffset_; | |
621 } | |
622 }; | |
623 | |
624 | |
625 bool DicomStreamReader::LookupPixelDataOffset(uint64_t& offset, | |
626 const std::string& dicom) | |
627 { | |
628 std::stringstream stream(dicom); | |
629 | |
630 DicomStreamReader reader(stream); | |
631 | |
632 PixelDataVisitor visitor; | |
633 | |
634 try | |
635 { | |
636 reader.Consume(visitor); | |
637 } | |
638 catch (OrthancException& e) | |
639 { | |
640 // Invalid DICOM file | |
641 return false; | |
642 } | |
643 | |
644 if (visitor.HasPixelData()) | |
645 { | |
646 offset = visitor.GetPixelDataOffset(); | |
647 return true; | |
648 } | |
649 else | |
650 { | |
651 return false; | |
652 } | |
653 } | |
557 } | 654 } |