/// <summary> /// Saves given instances to temp files and performs requested operation on each of the saved file. /// NOTE: The temp file must me manually deleted during post save operation or it will stay in the temp folder. /// <exception cref="AimManagerException">AimManagerException</exception> can be thrown if save of an annotation fails. /// </summary> /// <param name="aimAnnotationReferences">List of annotation containers to save</param> /// <param name="postSaveProcessor">Operation to perform on each saved temp file</param> public void WriteDicomAnnotationsToTempFiles(List <IAimObjectReference> aimAnnotationReferences, Action <string> postSaveProcessor) { if (aimAnnotationReferences == null) { return; } var aim3Annotations = aimAnnotationReferences.Where(aimObject => aimObject != null && aimObject.AimVersion == AimVersion.AimVersion3).ToList(); if (aim3Annotations.Any()) { using (var aim3NativeHelper = new Aim3.Aim3NativeDcmHelper()) { foreach (var aim3Annotation in aim3Annotations) { var tempFileName = aim3NativeHelper.WriteAnnotationToTempFile(aim3Annotation); if (tempFileName != null && postSaveProcessor != null) { postSaveProcessor(tempFileName); } else if (tempFileName != null) { // TODO - delete temp file? } } } } var aim4Annotations = aimAnnotationReferences.Where(aimObject => aimObject != null && aimObject.AimVersion == AimVersion.AimVersion4).ToList(); if (aim4Annotations.Any()) { using (var aim4NativeHelper = new Aim4.Aim4NativeDcmHelper()) { foreach (var aim4Annotation in aim4Annotations) { var tempFileName = aim4NativeHelper.WriteAnnotationToTempFile(aim4Annotation); if (tempFileName != null && postSaveProcessor != null) { postSaveProcessor(tempFileName); } else if (tempFileName != null) { // TODO - delete temp file? } } } } if (aim3Annotations.Count + aim4Annotations.Count != aimAnnotationReferences.Count) { Platform.Log(LogLevel.Error, "AimManager.WriteDicomAnnotationsToTempFiles: not all annotations can be saved to DICOM files."); throw new NotImplementedException("Cannot save some of the annotations to DICOM files. Unknown version of AIM was encountered?"); } }
// Loads annotations from local storage private List <IAimDocumentInstance> LoadLocalAimDocumentsForStudy(string studyInstanceUid) { var seriesIdentifier = new SeriesIdentifier { StudyInstanceUid = studyInstanceUid, Modality = AimManager.AimModality }; var seriesEntryRequest = new GetSeriesEntriesRequest { Criteria = new SeriesEntry { Series = seriesIdentifier } }; IList <SeriesEntry> entries = null; Platform.GetService <IStudyStoreQuery>(s => entries = s.GetSeriesEntries(seriesEntryRequest).SeriesEntries); var instanceToAimFileInfoMap = new Dictionary <string, AimFileInfo>(); // Get all unique AE Titles for the study. Can study have more than one? // We only need to query each AETitle once, or there will be duplicates/errors. var studyAes = (from seriesEntry in entries where seriesEntry != null select seriesEntry.Series.RetrieveAE).GroupBy(ae => ae.AETitle).Select(ae1 => ae1.First()).OfType <IDicomServiceNode>().ToList(); if (!studyAes.Any()) { Platform.Log(LogLevel.Debug, "Study ({0}} has no SR (AIM Annotations) objects", studyInstanceUid); return(null); } foreach (var studyAe in studyAes) { IStudyLoader studyLoader; try { studyLoader = studyAe.GetService <IStudyLoader>(); } catch (Exception ex) { throw new AimManagerException("Cannot get study loader", ex); } int numberOfSops = studyLoader.Start(new StudyLoaderArgs(studyInstanceUid, null, new StudyLoaderOptions(true))); for (int i = 0; i < numberOfSops; i++) { using (var sop = studyLoader.LoadNextSop()) { if (sop != null && sop.Modality == AimManager.AimModality) { var localSopDataSource = sop.DataSource as ILocalSopDataSource; if (localSopDataSource != null) { var filePathName = localSopDataSource.Filename; switch (AimManager.GetAimVersionFromSop(sop)) { case AimVersion.AimVersion3: instanceToAimFileInfoMap.Add(filePathName, new AimFileInfo(AimVersion.AimVersion3, sop.StudyInstanceUid, sop.SeriesInstanceUid, sop.SopInstanceUid)); break; case AimVersion.AimVersion4: instanceToAimFileInfoMap.Add(filePathName, new AimFileInfo(AimVersion.AimVersion4, sop.StudyInstanceUid, sop.SeriesInstanceUid, sop.SopInstanceUid)); break; } } } } } } if (instanceToAimFileInfoMap.Any()) { var aimDocumentInstances = new List <IAimDocumentInstance>(); var aim4Instances = instanceToAimFileInfoMap.Where(instance => instance.Value.AimVersion == AimVersion.AimVersion4).ToList(); if (aim4Instances.Any()) { using (var dcmHelper = new Aim4.Aim4NativeDcmHelper()) { foreach (var instanceInfo in aim4Instances) { var aimDocumentInstance = ReadAimDocumentFromDicomFile(dcmHelper, instanceInfo.Key, instanceInfo.Value.StudyInstanceUid, instanceInfo.Value.SeriesInstanceUid, instanceInfo.Value.SopInstanceUid); if (aimDocumentInstance != null) { aimDocumentInstances.Add(aimDocumentInstance); } } } } return(aimDocumentInstances.Any() ? aimDocumentInstances : null); } return(null); }
public static List <string> ConvertAnnotationsFromXmlToDicomFiles(AimVersion aimVersion, List <string> xmlAnnotationsFilePathNames, IBackgroundTaskContext context, out List <string> invalidFiles) { Platform.CheckForNullReference(xmlAnnotationsFilePathNames, "xmlAnnotationsFilePathNames"); var convertedAnnotations = new List <string>(); invalidFiles = new List <string>(); switch (aimVersion) { case AimVersion.AimVersion3: { int cnt = 0; using (var aim3NativeXmlHelper = new Aim3.Aim3NativeXmlHelper()) { using (var aim3NativeDcmHelper = new Aim3.Aim3NativeDcmHelper()) { foreach (string aimFile in xmlAnnotationsFilePathNames.Where(pathName => pathName != null)) { // Read XML file ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Reading file {0}", Path.GetFileName(aimFile))); var annotations = aim3NativeXmlHelper.ReadAnnotationsFromFile(aimFile); if (annotations.IsNullOrEmpty()) { Platform.Log(LogLevel.Info, "No annotation is read from file {0}", Path.GetFileName(aimFile)); invalidFiles.Add(Path.GetFileName(aimFile)); } else { // Write to temp file ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Read {0} annotations from file {1}", annotations.Count, Path.GetFileName(aimFile))); int dcmFileCnt = 0; foreach (var annotation in annotations) { ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Writing converted annotation to temporary file [{0} of {1}]", ++dcmFileCnt, annotations.Count)); var tempFileName = aim3NativeDcmHelper.WriteAnnotationToTempFile(annotation); convertedAnnotations.Add(tempFileName); ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Wrote converted annotation to file {0} [{1} of {2}]", tempFileName, dcmFileCnt, annotations.Count)); } } if (context != null && context.CancelRequested) { break; } cnt++; } } } } break; case AimVersion.AimVersion4: { int cnt = 0; using (var aim4NativeXmlHelper = new Aim4.Aim4NativeXmlHelper()) { using (var aim4NativeDcmHelper = new Aim4.Aim4NativeDcmHelper()) { foreach (string aimFile in xmlAnnotationsFilePathNames.Where(pathName => pathName != null)) { // Read XML file ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Reading file {0}", Path.GetFileName(aimFile))); var annotation = aim4NativeXmlHelper.ReadAnnotationFromFile(aimFile); if (annotation == null) { Platform.Log(LogLevel.Info, "No annotation is read from file {0}", Path.GetFileName(aimFile)); invalidFiles.Add(Path.GetFileName(aimFile)); } else { // Write to temp file ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Read annotation collection from file {0}", Path.GetFileName(aimFile))); var tempFileName = aim4NativeDcmHelper.WriteAnnotationToTempFile(annotation); convertedAnnotations.Add(tempFileName); ReportTaskProgress(context, cnt, xmlAnnotationsFilePathNames.Count, String.Format("Wrote converted annotation collection to file {0}", tempFileName)); } if (context != null && context.CancelRequested) { break; } cnt++; } } } } break; default: Debug.Assert(false, "AimManager.ConvertAnnotationsFromXmlToDicomFiles: Unexpected AIM version"); break; } return(convertedAnnotations); }
// Loads annotations from local storage private List<IAimDocumentInstance> LoadLocalAimDocumentsForStudy(string studyInstanceUid) { var seriesIdentifier = new SeriesIdentifier { StudyInstanceUid = studyInstanceUid, Modality = AimManager.AimModality }; var seriesEntryRequest = new GetSeriesEntriesRequest { Criteria = new SeriesEntry { Series = seriesIdentifier } }; IList<SeriesEntry> entries = null; Platform.GetService<IStudyStoreQuery>(s => entries = s.GetSeriesEntries(seriesEntryRequest).SeriesEntries); var instanceToAimFileInfoMap = new Dictionary<string, AimFileInfo>(); // Get all unique AE Titles for the study. Can study have more than one? // We only need to query each AETitle once, or there will be duplicates/errors. var studyAes = (from seriesEntry in entries where seriesEntry != null select seriesEntry.Series.RetrieveAE).GroupBy(ae => ae.AETitle).Select(ae1 => ae1.First()).OfType<IDicomServiceNode>().ToList(); if (!studyAes.Any()) { Platform.Log(LogLevel.Debug, "Study ({0}} has no SR (AIM Annotations) objects", studyInstanceUid); return null; } foreach (var studyAe in studyAes) { IStudyLoader studyLoader; try { studyLoader = studyAe.GetService<IStudyLoader>(); } catch (Exception ex) { throw new AimManagerException("Cannot get study loader", ex); } int numberOfSops = studyLoader.Start(new StudyLoaderArgs(studyInstanceUid, null, new StudyLoaderOptions(true))); for (int i = 0; i < numberOfSops; i++) { using (var sop = studyLoader.LoadNextSop()) { if (sop != null && sop.Modality == AimManager.AimModality) { var localSopDataSource = sop.DataSource as ILocalSopDataSource; if (localSopDataSource != null) { var filePathName = localSopDataSource.Filename; switch (AimManager.GetAimVersionFromSop(sop)) { case AimVersion.AimVersion3: instanceToAimFileInfoMap.Add(filePathName, new AimFileInfo(AimVersion.AimVersion3, sop.StudyInstanceUid, sop.SeriesInstanceUid, sop.SopInstanceUid)); break; case AimVersion.AimVersion4: instanceToAimFileInfoMap.Add(filePathName, new AimFileInfo(AimVersion.AimVersion4, sop.StudyInstanceUid, sop.SeriesInstanceUid, sop.SopInstanceUid)); break; } } } } } } if (instanceToAimFileInfoMap.Any()) { var aimDocumentInstances = new List<IAimDocumentInstance>(); var aim4Instances = instanceToAimFileInfoMap.Where(instance => instance.Value.AimVersion == AimVersion.AimVersion4).ToList(); if (aim4Instances.Any()) { using (var dcmHelper = new Aim4.Aim4NativeDcmHelper()) { foreach (var instanceInfo in aim4Instances) { var aimDocumentInstance = ReadAimDocumentFromDicomFile(dcmHelper, instanceInfo.Key, instanceInfo.Value.StudyInstanceUid, instanceInfo.Value.SeriesInstanceUid, instanceInfo.Value.SopInstanceUid); if (aimDocumentInstance != null) aimDocumentInstances.Add(aimDocumentInstance); } } } return aimDocumentInstances.Any() ? aimDocumentInstances : null; } return null; }