StupidSlowFinderService.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright (c) 2012-2020 fo-dicom contributors.
  2. // Licensed under the Microsoft Public License (MS-PL).
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Text.RegularExpressions;
  7. using Dicom;
  8. namespace QueryRetrieve_SCP.Model
  9. {
  10. public class StupidSlowFinderService : IDicomImageFinderService
  11. {
  12. private static readonly string _storagePath = @".\DICOM";
  13. public List<string> FindPatientFiles(string PatientName, string PatientId) =>
  14. // usually here a SQL statement is built to query a Patient-table
  15. SearchInFilesystem(
  16. dcmFile => dcmFile.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
  17. dcmFile =>
  18. {
  19. bool matches = true;
  20. matches &= MatchFilter(PatientName, dcmFile.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty));
  21. matches &= MatchFilter(PatientId, dcmFile.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty));
  22. return matches;
  23. });
  24. public List<string> FindStudyFiles(string PatientName, string PatientId, string AccessionNbr, string StudyUID) =>
  25. // usually here a SQL statement is built to query a Study-table
  26. SearchInFilesystem(
  27. dcmFile => dcmFile.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
  28. dcmFile =>
  29. {
  30. bool matches = true;
  31. matches &= MatchFilter(PatientName, dcmFile.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty));
  32. matches &= MatchFilter(PatientId, dcmFile.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty));
  33. matches &= MatchFilter(AccessionNbr, dcmFile.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty));
  34. matches &= MatchFilter(StudyUID, dcmFile.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty));
  35. return matches;
  36. });
  37. public List<string> FindSeriesFiles(string PatientName, string PatientId, string AccessionNbr, string StudyUID, string SeriesUID, string Modality) =>
  38. // usually here a SQL statement is built to query a Series-table
  39. SearchInFilesystem(
  40. dcmFile => dcmFile.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
  41. dcmFile =>
  42. {
  43. bool matches = true;
  44. matches &= MatchFilter(PatientName, dcmFile.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty));
  45. matches &= MatchFilter(PatientId, dcmFile.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty));
  46. matches &= MatchFilter(AccessionNbr, dcmFile.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty));
  47. matches &= MatchFilter(StudyUID, dcmFile.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty));
  48. matches &= MatchFilter(SeriesUID, dcmFile.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty));
  49. matches &= MatchFilter(Modality, dcmFile.GetSingleValueOrDefault(DicomTag.Modality, string.Empty));
  50. return matches;
  51. });
  52. private List<string> SearchInFilesystem(Func<DicomDataset, string> level, Func<DicomDataset, bool> matches)
  53. {
  54. string dicomRootDirectory = _storagePath;
  55. var allFilesOnHarddisk = Directory.GetFiles(dicomRootDirectory, "*.dcm", SearchOption.AllDirectories);
  56. var matchingFiles = new List<string>(); // holds the file matching the criteria. one representative file per key
  57. var foundKeys = new List<string>(); // holds the list of keys that have already been found so that only one file per key is returned
  58. foreach (string fileNameToTest in allFilesOnHarddisk)
  59. {
  60. try
  61. {
  62. var dcmFile = DicomFile.Open(fileNameToTest);
  63. var key = level(dcmFile.Dataset);
  64. if (!string.IsNullOrEmpty(key)
  65. && !foundKeys.Contains(key)
  66. && matches(dcmFile.Dataset))
  67. {
  68. matchingFiles.Add(fileNameToTest);
  69. foundKeys.Add(key);
  70. }
  71. }
  72. catch (Exception)
  73. {
  74. // invalid file, ignore here
  75. }
  76. }
  77. return matchingFiles;
  78. }
  79. public List<string> FindFilesByUID(string PatientId, string StudyUID, string SeriesUID)
  80. {
  81. // normally here a SQL query is constructed. But this implementation searches in file system
  82. string dicomRootDirectory = _storagePath;
  83. var allFilesOnHarddisk = Directory.GetFiles(dicomRootDirectory, "*.dcm", SearchOption.AllDirectories);
  84. var matchingFiles = new List<string>();
  85. foreach (string fileNameToTest in allFilesOnHarddisk)
  86. {
  87. try
  88. {
  89. var dcmFile = DicomFile.Open(fileNameToTest);
  90. bool matches = true;
  91. matches &= MatchFilter(PatientId, dcmFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty));
  92. matches &= MatchFilter(StudyUID, dcmFile.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty));
  93. matches &= MatchFilter(SeriesUID, dcmFile.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty));
  94. if (matches)
  95. {
  96. matchingFiles.Add(fileNameToTest);
  97. }
  98. }
  99. catch (Exception)
  100. {
  101. // invalid file, ignore here
  102. }
  103. }
  104. return matchingFiles;
  105. }
  106. private bool MatchFilter(string filterValue, string valueToTest)
  107. {
  108. if (string.IsNullOrEmpty(filterValue))
  109. {
  110. // if the QR SCU sends an empty tag, then no filtering should happen
  111. return true;
  112. }
  113. // take into account, that strings may contain a *-wildcard
  114. var filterRegex = "^" + Regex.Escape(filterValue).Replace("\\*", ".*") + "$";
  115. return Regex.IsMatch(valueToTest, filterRegex, RegexOptions.IgnoreCase);
  116. }
  117. }
  118. }