public DicomFile GetDataset(ZipPool pool = null) { if (IsZipReference(FullPath)) { var bits = FullPath.Split('!'); var zip = pool != null?pool.OpenRead(bits[0]) : ZipFile.Open(bits[0], ZipArchiveMode.Read); try { var entry = zip.GetEntry(bits[1]); if (!IsDicomReference(bits[1])) { throw new AmbiguousFilePathResolutionException("Path provided '" + FullPath + "' was to a zip file but not to a dicom file entry"); } var buffer = ByteStreamHelper.ReadFully(entry.Open()); //todo: when GH-627 goes live we can use FileReadOption https://github.com/fo-dicom/fo-dicom/blob/GH-627/DICOM/DicomFile.cs //using (var memoryStream = new MemoryStream(buffer)) var memoryStream = new MemoryStream(buffer); return(DicomFile.Open(memoryStream)); } finally { if (pool == null) { zip.Dispose(); } } } if (!IsDicomReference(FullPath)) { throw new AmbiguousFilePathResolutionException("Path provided '" + FullPath + "' was not to either an entry in a zip file or to a dicom file"); } return(DicomFile.Open(FullPath)); }
public DicomFile GetDataset(ZipPool pool = null) { if (IsZipReference(FullPath)) { var bits = FullPath.Split('!'); var zip = pool != null?pool.OpenRead(bits[0]) : ZipFile.Open(bits[0], ZipArchiveMode.Read); try { var entry = zip.GetEntry(bits[1]); if (entry == null) { //Maybe user has formatted it dodgy //e.g. \2015\3\18\2.25.177481563701402448825228719253578992342.dcm string adjusted = bits[1].TrimStart('\\', '/'); //if that doesn't work if ((entry = zip.GetEntry(adjusted)) == null) { //try normalizing the slashes adjusted = adjusted.Replace('\\', '/'); //nope we just cannot get a legit path in this zip if ((entry = zip.GetEntry(adjusted)) == null) { throw new AmbiguousFilePathResolutionException($"Could not find path '{bits[1]}' within zip archive '{bits[0]}'"); } } //we fixed it to something that actually exists so update our state that we don't make the same mistake again FullPath = bits[0] + '!' + adjusted; } if (!IsDicomReference(bits[1])) { throw new AmbiguousFilePathResolutionException("Path provided '" + FullPath + "' was to a zip file but not to a dicom file entry"); } var buffer = ByteStreamHelper.ReadFully(entry.Open()); //todo: when GH-627 goes live we can use FileReadOption https://github.com/fo-dicom/fo-dicom/blob/GH-627/DICOM/DicomFile.cs //using (var memoryStream = new MemoryStream(buffer)) var memoryStream = new MemoryStream(buffer); return(DicomFile.Open(memoryStream)); } finally { if (pool == null) { zip.Dispose(); } } } if (!IsDicomReference(FullPath)) { throw new AmbiguousFilePathResolutionException("Path provided '" + FullPath + "' was not to either an entry in a zip file or to a dicom file"); } return(DicomFile.Open(FullPath)); }
public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { //Things we ignore, Lookups, SupportingSql etc if (_extractCommand == null) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Ignoring non dataset command ")); return(toProcess); } //if it isn't a dicom dataset don't process it if (!toProcess.Columns.Contains(RelativeArchiveColumnName)) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, "Dataset " + _extractCommand.DatasetBundle.DataSet + " did not contain field '" + RelativeArchiveColumnName + "' so we will not attempt to extract images")); return(toProcess); } if (_putter == null) { _putter = (IPutDicomFilesInExtractionDirectories) new ObjectConstructor().Construct(PutterType); } var projectNumber = _extractCommand.Configuration.Project.ProjectNumber.Value; var mappingServer = new MappingRepository(UIDMappingServer); var destinationDirectory = new DirectoryInfo(Path.Combine(_extractCommand.GetExtractionDirectory().FullName, "Images")); var releaseCol = _extractCommand.QueryBuilder.SelectColumns.Select(c => c.IColumn).Single(c => c.IsExtractionIdentifier); // See: ftp://medical.nema.org/medical/dicom/2011/11_15pu.pdf var flags = DicomAnonymizer.SecurityProfileOptions.BasicProfile | DicomAnonymizer.SecurityProfileOptions.CleanStructdCont | DicomAnonymizer.SecurityProfileOptions.CleanDesc | DicomAnonymizer.SecurityProfileOptions.RetainUIDs; if (RetainDates) { flags |= DicomAnonymizer.SecurityProfileOptions.RetainLongFullDates; } var profile = DicomAnonymizer.SecurityProfile.LoadProfile(null, flags); var anonymiser = new DicomAnonymizer(profile); using (var pool = new ZipPool()) { _sw.Start(); foreach (DataRow row in toProcess.Rows) { if (_errors > 0 && _errors > ErrorThreshold) { throw new Exception($"Number of errors reported ({_errors}) reached the threshold ({ErrorThreshold})"); } cancellationToken.ThrowIfAbortRequested(); var path = new AmbiguousFilePath(ArchiveRootIfAny, (string)row[RelativeArchiveColumnName]); DicomFile dicomFile; try { dicomFile = path.GetDataset(pool); } catch (Exception e) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, $"Failed to get image at path '{path.FullPath}'", e)); _errors++; continue; } //get the new patient ID var releaseId = row[releaseCol.GetRuntimeName()].ToString(); DicomDataset ds; try { ds = anonymiser.Anonymize(dicomFile.Dataset); } catch (Exception e) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error, $"Failed to anonymize image at path '{path.FullPath}'", e)); _errors++; continue; } //now we want to explicitly use our own release Id regardless of what FoDicom said ds.AddOrUpdate(DicomTag.PatientID, releaseId); //rewrite the UIDs foreach (var kvp in UIDMapping.SupportedTags) { if (!ds.Contains(kvp.Key)) { continue; } var value = ds.GetValue <string>(kvp.Key, 0); //if it has a value for this UID if (value == null) { continue; } var releaseValue = mappingServer.GetOrAllocateMapping(value, projectNumber, kvp.Value); //change value in dataset ds.AddOrUpdate(kvp.Key, releaseValue); //and change value in DataTable if (toProcess.Columns.Contains(kvp.Key.DictionaryEntry.Keyword)) { row[kvp.Key.DictionaryEntry.Keyword] = releaseValue; } } var newPath = _putter.WriteOutDataset(destinationDirectory, releaseId, ds); row[RelativeArchiveColumnName] = newPath; _anonymisedImagesCount++; listener.OnProgress(this, new ProgressEventArgs("Writing ANO images", new ProgressMeasurement(_anonymisedImagesCount, ProgressType.Records), _sw.Elapsed)); } _sw.Stop(); } return(toProcess); }