Mercurial > hg > orthanc
comparison OrthancServer/ParsedDicomFile.cpp @ 1693:558b25228a23
creation of tag hierarchy from json
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 08 Oct 2015 13:45:33 +0200 |
parents | 26083d84d237 |
children | 06d579e82bb8 |
comparison
equal
deleted
inserted
replaced
1692:4eaf164dd574 | 1693:558b25228a23 |
---|---|
135 #include <dcmtk/dcmdata/dcpxitem.h> | 135 #include <dcmtk/dcmdata/dcpxitem.h> |
136 | 136 |
137 | 137 |
138 #include <boost/math/special_functions/round.hpp> | 138 #include <boost/math/special_functions/round.hpp> |
139 #include <dcmtk/dcmdata/dcostrmb.h> | 139 #include <dcmtk/dcmdata/dcostrmb.h> |
140 #include <boost/algorithm/string/predicate.hpp> | |
140 | 141 |
141 | 142 |
142 static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream"; | 143 static const char* CONTENT_TYPE_OCTET_STREAM = "application/octet-stream"; |
143 | 144 |
144 | 145 |
577 } | 578 } |
578 } | 579 } |
579 } | 580 } |
580 | 581 |
581 | 582 |
583 static void InsertInternal(DcmDataset& dicom, | |
584 DcmElement* element) | |
585 { | |
586 OFCondition cond = dicom.insert(element, false, false); | |
587 if (!cond.good()) | |
588 { | |
589 // This field already exists | |
590 delete element; | |
591 throw OrthancException(ErrorCode_InternalError); | |
592 } | |
593 } | |
594 | |
595 | |
582 void ParsedDicomFile::Insert(const DicomTag& tag, | 596 void ParsedDicomFile::Insert(const DicomTag& tag, |
583 const std::string& value) | 597 const std::string& value) |
584 { | 598 { |
585 OFCondition cond; | 599 std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag)); |
586 | 600 FromDcmtkBridge::FillElementWithString(*element, tag, value, false); |
587 if (FromDcmtkBridge::IsPrivateTag(tag) || | 601 InsertInternal(*pimpl_->file_->getDataset(), element.release()); |
588 FromDcmtkBridge::IsUnknownTag(tag)) | 602 } |
589 { | 603 |
590 // This is a private tag | 604 |
591 // http://support.dcmtk.org/redmine/projects/dcmtk/wiki/howto_addprivatedata | 605 void ParsedDicomFile::Insert(const DicomTag& tag, |
592 | 606 const Json::Value& value, |
593 DcmTag key(tag.GetGroup(), tag.GetElement(), EVR_OB); | 607 bool decodeBinaryTags) |
594 cond = pimpl_->file_->getDataset()->putAndInsertUint8Array | 608 { |
595 (key, (const Uint8*) value.c_str(), value.size(), false); | 609 std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeBinaryTags)); |
596 } | 610 InsertInternal(*pimpl_->file_->getDataset(), element.release()); |
597 else | 611 } |
598 { | 612 |
599 std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag)); | 613 |
600 FromDcmtkBridge::FillElementWithString(*element, tag, value, false); | 614 static void ReplaceInternal(DcmDataset& dicom, |
601 | 615 std::auto_ptr<DcmElement>& element, |
602 cond = pimpl_->file_->getDataset()->insert(element.release(), false, false); | 616 DicomReplaceMode mode) |
603 } | 617 { |
604 | 618 const DcmTagKey& tag = element->getTag(); |
605 if (!cond.good()) | 619 |
606 { | 620 if (!dicom.findAndDeleteElement(tag).good()) |
607 // This field already exists | |
608 throw OrthancException(ErrorCode_InternalError); | |
609 } | |
610 } | |
611 | |
612 | |
613 void ParsedDicomFile::Replace(const DicomTag& tag, | |
614 const std::string& value, | |
615 DicomReplaceMode mode) | |
616 { | |
617 DcmTagKey key(tag.GetGroup(), tag.GetElement()); | |
618 DcmElement* element = NULL; | |
619 | |
620 if (!pimpl_->file_->getDataset()->findAndGetElement(key, element).good() || | |
621 element == NULL) | |
622 { | 621 { |
623 // This field does not exist, act wrt. the specified "mode" | 622 // This field does not exist, act wrt. the specified "mode" |
624 switch (mode) | 623 switch (mode) |
625 { | 624 { |
626 case DicomReplaceMode_InsertIfAbsent: | 625 case DicomReplaceMode_InsertIfAbsent: |
627 Insert(tag, value); | |
628 break; | 626 break; |
629 | 627 |
630 case DicomReplaceMode_ThrowIfAbsent: | 628 case DicomReplaceMode_ThrowIfAbsent: |
631 throw OrthancException(ErrorCode_InexistentItem); | 629 throw OrthancException(ErrorCode_InexistentItem); |
632 | 630 |
633 case DicomReplaceMode_IgnoreIfAbsent: | 631 case DicomReplaceMode_IgnoreIfAbsent: |
634 return; | 632 return; |
635 } | 633 } |
636 } | 634 } |
637 else | 635 |
638 { | 636 // Either the tag was not existing, or the replace mode was set to |
639 FromDcmtkBridge::FillElementWithString(*element, tag, value, false); | 637 // "InsertIfAbsent" |
640 } | 638 InsertInternal(dicom, element.release()); |
641 | 639 } |
640 | |
641 | |
642 void ParsedDicomFile::UpdateStorageUid(const DicomTag& tag, | |
643 const std::string& value, | |
644 bool decodeBinaryTags) | |
645 { | |
646 if (tag != DICOM_TAG_SOP_CLASS_UID && | |
647 tag != DICOM_TAG_SOP_INSTANCE_UID) | |
648 { | |
649 return; | |
650 } | |
651 | |
652 std::string binary; | |
653 const std::string* decoded = &value; | |
654 | |
655 if (decodeBinaryTags && | |
656 boost::starts_with(value, "data:application/octet-stream;base64,")) | |
657 { | |
658 std::string mime; | |
659 Toolbox::DecodeDataUriScheme(mime, binary, value); | |
660 decoded = &binary; | |
661 } | |
642 | 662 |
643 /** | 663 /** |
644 * dcmodify will automatically correct 'Media Storage SOP Class | 664 * dcmodify will automatically correct 'Media Storage SOP Class |
645 * UID' and 'Media Storage SOP Instance UID' in the metaheader, if | 665 * UID' and 'Media Storage SOP Instance UID' in the metaheader, if |
646 * you make changes to the related tags in the dataset ('SOP Class | 666 * you make changes to the related tags in the dataset ('SOP Class |
649 * option. | 669 * option. |
650 **/ | 670 **/ |
651 | 671 |
652 if (tag == DICOM_TAG_SOP_CLASS_UID) | 672 if (tag == DICOM_TAG_SOP_CLASS_UID) |
653 { | 673 { |
654 Replace(DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, value, DicomReplaceMode_InsertIfAbsent); | 674 Replace(DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, *decoded, DicomReplaceMode_InsertIfAbsent); |
655 } | 675 } |
656 | 676 |
657 if (tag == DICOM_TAG_SOP_INSTANCE_UID) | 677 if (tag == DICOM_TAG_SOP_INSTANCE_UID) |
658 { | 678 { |
659 Replace(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, value, DicomReplaceMode_InsertIfAbsent); | 679 Replace(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, *decoded, DicomReplaceMode_InsertIfAbsent); |
680 } | |
681 } | |
682 | |
683 | |
684 void ParsedDicomFile::Replace(const DicomTag& tag, | |
685 const std::string& value, | |
686 DicomReplaceMode mode) | |
687 { | |
688 std::auto_ptr<DcmElement> element(FromDcmtkBridge::CreateElementForTag(tag)); | |
689 FromDcmtkBridge::FillElementWithString(*element, tag, value, false); | |
690 ReplaceInternal(*pimpl_->file_->getDataset(), element, mode); | |
691 UpdateStorageUid(tag, value, false); | |
692 } | |
693 | |
694 | |
695 void ParsedDicomFile::Replace(const DicomTag& tag, | |
696 const Json::Value& value, | |
697 bool decodeBinaryTags, | |
698 DicomReplaceMode mode) | |
699 { | |
700 std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeBinaryTags)); | |
701 ReplaceInternal(*pimpl_->file_->getDataset(), element, mode); | |
702 | |
703 if (tag == DICOM_TAG_SOP_CLASS_UID || | |
704 tag == DICOM_TAG_SOP_INSTANCE_UID) | |
705 { | |
706 if (value.type() != Json::stringValue) | |
707 { | |
708 throw OrthancException(ErrorCode_BadParameterType); | |
709 } | |
710 | |
711 UpdateStorageUid(tag, value.asString(), decodeBinaryTags); | |
660 } | 712 } |
661 } | 713 } |
662 | 714 |
663 | 715 |
664 void ParsedDicomFile::Answer(RestApiOutput& output) | 716 void ParsedDicomFile::Answer(RestApiOutput& output) |
863 { | 915 { |
864 EmbedPdf(content); | 916 EmbedPdf(content); |
865 } | 917 } |
866 else | 918 else |
867 { | 919 { |
868 LOG(ERROR) << "Unsupported MIME type for the content of a new DICOM file"; | 920 LOG(ERROR) << "Unsupported MIME type for the content of a new DICOM file: " << mime; |
869 throw OrthancException(ErrorCode_NotImplemented); | 921 throw OrthancException(ErrorCode_NotImplemented); |
870 } | 922 } |
871 } | 923 } |
872 | 924 |
873 | 925 |