comparison OrthancServer/Sources/ServerContext.cpp @ 4514:5b929e6b3c36

removal of "dicom-as-json" attachments
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 16 Feb 2021 12:18:41 +0100
parents 1f455b86b054
children a3c6678aa7b1
comparison
equal deleted inserted replaced
4513:1f455b86b054 4514:5b929e6b3c36
581 FileContentType_Dicom, compression, storeMD5_); 581 FileContentType_Dicom, compression, storeMD5_);
582 582
583 ServerIndex::Attachments attachments; 583 ServerIndex::Attachments attachments;
584 attachments.push_back(dicomInfo); 584 attachments.push_back(dicomInfo);
585 585
586 FileInfo jsonInfo; 586 FileInfo dicomUntilPixelData;
587 if (true /* TODO - !area_.HasReadRange() || !hasPixelDataOffset || compression != CompressionType_DicomAsJson */) 587 if (hasPixelDataOffset &&
588 { 588 (!area_.HasReadRange() ||
589 jsonInfo = accessor.Write(dicomAsJson.toStyledString(), 589 compression != CompressionType_None))
590 FileContentType_DicomAsJson, compression, storeMD5_); 590 {
591 attachments.push_back(jsonInfo); 591 dicomUntilPixelData = accessor.Write(dicom.GetBufferData(), pixelDataOffset,
592 FileContentType_DicomUntilPixelData, compression, storeMD5_);
593 attachments.push_back(dicomUntilPixelData);
592 } 594 }
593 595
594 typedef std::map<MetadataType, std::string> InstanceMetadata; 596 typedef std::map<MetadataType, std::string> InstanceMetadata;
595 InstanceMetadata instanceMetadata; 597 InstanceMetadata instanceMetadata;
596 StoreStatus status = index_.Store( 598 StoreStatus status = index_.Store(
608 610
609 if (status != StoreStatus_Success) 611 if (status != StoreStatus_Success)
610 { 612 {
611 accessor.Remove(dicomInfo); 613 accessor.Remove(dicomInfo);
612 614
613 if (jsonInfo.IsValid()) 615 if (dicomUntilPixelData.IsValid())
614 { 616 {
615 accessor.Remove(jsonInfo); 617 accessor.Remove(dicomUntilPixelData);
616 } 618 }
617 } 619 }
618 620
619 switch (status) 621 switch (status)
620 { 622 {
805 throw; 807 throw;
806 } 808 }
807 } 809 }
808 810
809 811
812 static void InjectEmptyPixelData(Json::Value& dicomAsJson)
813 {
814 // This is for backward compatibility with Orthanc <= 1.9.0
815 Json::Value pixelData = Json::objectValue;
816 pixelData["Name"] = "PixelData";
817 pixelData["Type"] = "Null";
818 pixelData["Value"] = Json::nullValue;
819
820 dicomAsJson["7fe0,0010"] = pixelData;
821 }
822
823
810 void ServerContext::ReadDicomAsJson(Json::Value& result, 824 void ServerContext::ReadDicomAsJson(Json::Value& result,
811 const std::string& instancePublicId, 825 const std::string& instancePublicId,
812 const std::set<DicomTag>& ignoreTagLength) 826 const std::set<DicomTag>& ignoreTagLength)
813 { 827 {
814 if (ignoreTagLength.empty()) 828 /**
815 { 829 * CASE 1: The DICOM file, truncated at pixel data, is available
816 std::string tmp; 830 * as an attachment (it was created either because the storage
817 831 * area does not support range reads, or it "StorageCompression"
818 { 832 * is enabled). Simply return this attachment.
819 FileInfo attachment; 833 **/
820 if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
821 {
822 StorageAccessor accessor(area_, GetMetricsRegistry());
823 accessor.Read(tmp, attachment);
824 }
825 else
826 {
827 // The "DICOM as JSON" summary is not available from the Orthanc
828 // store (most probably deleted), reconstruct it from the DICOM file
829 std::string dicom;
830 ReadDicom(dicom, instancePublicId);
831
832 LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: "
833 << instancePublicId;
834 834
835 ParsedDicomFile parsed(dicom); 835 FileInfo attachment;
836 836
837 Json::Value summary; 837 if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomUntilPixelData))
838 OrthancConfiguration::DefaultDicomDatasetToJson(summary, parsed); 838 {
839
840 tmp = summary.toStyledString();
841
842 if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson,
843 tmp.c_str(), tmp.size()))
844 {
845 throw OrthancException(ErrorCode_InternalError,
846 "Cannot associate the DICOM-as-JSON summary to instance: " + instancePublicId);
847 }
848 }
849 }
850
851 if (!Toolbox::ReadJson(result, tmp))
852 {
853 throw OrthancException(ErrorCode_CorruptedFile);
854 }
855 }
856 else
857 {
858 // The "DicomAsJson" attachment might have stored some tags as
859 // "too long". We are forced to re-parse the DICOM file.
860 std::string dicom; 839 std::string dicom;
861 ReadDicom(dicom, instancePublicId); 840
841 {
842 StorageAccessor accessor(area_, GetMetricsRegistry());
843 accessor.Read(dicom, attachment);
844 }
862 845
863 ParsedDicomFile parsed(dicom); 846 ParsedDicomFile parsed(dicom);
864 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength); 847 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength);
848 InjectEmptyPixelData(result);
849 }
850 else
851 {
852 /**
853 * The truncated DICOM file is not stored as a standalone
854 * attachment. Lookup whether the pixel data offset has already
855 * been computed for this instance.
856 **/
857
858 bool hasPixelDataOffset;
859 uint64_t pixelDataOffset;
860
861 {
862 std::string s;
863 if (index_.LookupMetadata(s, instancePublicId, ResourceType_Instance,
864 MetadataType_Instance_PixelDataOffset))
865 {
866 hasPixelDataOffset = false;
867
868 if (!s.empty())
869 {
870 try
871 {
872 pixelDataOffset = boost::lexical_cast<uint64_t>(s);
873 hasPixelDataOffset = true;
874 }
875 catch (boost::bad_lexical_cast&)
876 {
877 }
878 }
879
880 if (!hasPixelDataOffset)
881 {
882 LOG(ERROR) << "Metadata \"PixelDataOffset\" is corrupted for instance: " << instancePublicId;
883 }
884 }
885 else
886 {
887 // This instance was created by a version of Orthanc <= 1.9.0
888 hasPixelDataOffset = false;
889 }
890 }
891
892
893 if (hasPixelDataOffset &&
894 area_.HasReadRange() &&
895 index_.LookupAttachment(attachment, instancePublicId, FileContentType_Dicom) &&
896 attachment.GetCompressionType() == CompressionType_None)
897 {
898 /**
899 * CASE 2: The pixel data offset is known, AND that a range read
900 * can be used to retrieve the truncated DICOM file. Note that
901 * this case cannot be used if "StorageCompression" option is
902 * "true".
903 **/
904
905 StorageAccessor accessor(area_, GetMetricsRegistry());
906 std::unique_ptr<IMemoryBuffer> dicom(
907 area_.ReadRange(attachment.GetUuid(), FileContentType_Dicom, 0, pixelDataOffset));
908
909 if (dicom.get() == NULL)
910 {
911 throw OrthancException(ErrorCode_InternalError);
912 }
913 else
914 {
915 assert(dicom->GetSize() == pixelDataOffset);
916 ParsedDicomFile parsed(dicom->GetData(), dicom->GetSize());
917 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength);
918 InjectEmptyPixelData(result);
919 }
920 }
921 else if (ignoreTagLength.empty() &&
922 index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
923 {
924 /**
925 * CASE 3: This instance was created using Orthanc <=
926 * 1.9.0. Reuse the old "DICOM-as-JSON" attachment if available.
927 * This is for backward compatibility: A call to
928 * "/tools/invalidate-tags" or to one flavors of
929 * "/.../.../reconstruct" will disable this case.
930 **/
931
932 std::string dicomAsJson;
933
934 {
935 StorageAccessor accessor(area_, GetMetricsRegistry());
936 accessor.Read(dicomAsJson, attachment);
937 }
938
939 if (!Toolbox::ReadJson(result, dicomAsJson))
940 {
941 throw OrthancException(ErrorCode_CorruptedFile,
942 "Corrupted DICOM-as-JSON attachment of instance: " + instancePublicId);
943 }
944 }
945 else
946 {
947 /**
948 * CASE 4: Neither the truncated DICOM file is accessible, nor
949 * the DICOM-as-JSON summary. We have to retrieve the full DICOM
950 * file from the storage area.
951 **/
952
953 std::string dicom;
954 ReadDicom(dicom, instancePublicId);
955
956 ParsedDicomFile parsed(dicom);
957 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength);
958
959 if (!hasPixelDataOffset)
960 {
961 /**
962 * The pixel data offset was never computed for this
963 * instance, which indicates that it was created using
964 * Orthanc <= 1.9.0, or that calls to
965 * "LookupPixelDataOffset()" from earlier versions of
966 * Orthanc have failed. Try again this precomputation now
967 * for future calls.
968 **/
969 if (DicomStreamReader::LookupPixelDataOffset(pixelDataOffset, dicom) &&
970 pixelDataOffset < dicom.size())
971 {
972 index_.SetMetadata(instancePublicId, MetadataType_Instance_PixelDataOffset,
973 boost::lexical_cast<std::string>(pixelDataOffset));
974
975 if (!area_.HasReadRange() ||
976 compressionEnabled_ != CompressionType_None)
977 {
978 AddAttachment(instancePublicId, FileContentType_DicomUntilPixelData,
979 dicom.empty() ? NULL: dicom.c_str(), pixelDataOffset);
980 }
981 }
982 }
983 }
865 } 984 }
866 } 985 }
867 986
868 987
869 void ServerContext::ReadDicomAsJson(Json::Value& result, 988 void ServerContext::ReadDicomAsJson(Json::Value& result,