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 }