/// <remarks> /// The current implementation of <see cref="KeyImagePublisher"/> supports only locally stored images that are <see cref="IImageSopProvider"/>s and supports <see cref="DicomSoftcopyPresentationState"/>s. /// </remarks> public static bool IsSupportedImage(IPresentationImage image) { var imageSopProvider = image as IImageSopProvider; if (imageSopProvider == null) { return(false); } return(imageSopProvider.ImageSop.DataSource.IsStored && DicomSoftcopyPresentationState.IsSupported(image)); }
/// <summary> /// Creates all the SOP instances associated with the key object selection and the content presentation states. /// </summary> public IDictionary <IStudySource, List <DicomFile> > CreateSopInstances(NextSeriesNumberDelegate nextSeriesNumberDelegate) { if (!HasChanges || !Items.Any()) { return(new Dictionary <IStudySource, List <DicomFile> >(0)); } // update the author field Author = GetUserName(); // the series index ensures consistent series level data because we only create one KO series and one PR series per study var studyIndex = new Dictionary <string, StudyInfo>(); var secondaryCaptureImageFactory = new SecondaryCaptureImageFactory(nextSeriesNumberDelegate); var framePresentationStates = new List <KeyValuePair <KeyImageReference, PresentationStateReference> >(); // create presentation states for the images in the clipboard var presentationStates = new List <DicomSoftcopyPresentationState>(); foreach (var item in Items.Where(i => i.Item is IPresentationImage)) { var image = (IPresentationImage)item.Item; // if the item is a placeholder image (e.g. because source study wasn't available), simply reserialize the original sop references if (image is KeyObjectPlaceholderImage) { // because source study wasn't available, we don't have enough information to create the identical KO for that study // and thus an entry in the study index table is not needed var ko = (KeyObjectPlaceholderImage)image; framePresentationStates.Add(new KeyValuePair <KeyImageReference, PresentationStateReference>(ko.KeyImageReference, ko.PresentationStateReference)); continue; } var provider = image as IImageSopProvider; if (provider == null) { continue; } StudyInfo studyInfo; var studyInstanceUid = provider.ImageSop.StudyInstanceUid; if (!studyIndex.TryGetValue(studyInstanceUid, out studyInfo)) { studyIndex.Add(studyInstanceUid, studyInfo = new StudyInfo(provider, nextSeriesNumberDelegate)); // keep the previous series number if the one we know about is the same study as this new document // otherwise, pre-allocate a series number for the KO now (ensures the number will be lower than any SC and PR series) if (_parentStudyInstanceUid == studyInstanceUid && _seriesNumber.HasValue) { studyInfo.KeyObjectSeriesNumber = _seriesNumber.Value; } else { studyInfo.AllocateKeyObjectSeriesNumber(); } } // if the item doesn't have changes and the presentation state is DICOM, simply reserialize the original sop references if (!item.HasChanges() && image is IDicomPresentationImage) { var dicomPresentationState = ((IDicomPresentationImage)image).PresentationState as DicomSoftcopyPresentationState; framePresentationStates.Add(new KeyValuePair <KeyImageReference, PresentationStateReference>(provider.Frame, dicomPresentationState)); continue; } // if the image is not a permanent stored instance (i.e. it was dynamically generated), create a secondary capture from it if (!provider.Sop.DataSource.IsStored) { image = secondaryCaptureImageFactory.CreateSecondaryCapture(image); provider = (IImageSopProvider)image; } var presentationState = DicomSoftcopyPresentationState.IsSupported(image) ? DicomSoftcopyPresentationState.Create (image, ps => { ps.PresentationSeriesInstanceUid = studyInfo.PresentationSeriesUid; ps.PresentationSeriesNumber = studyInfo.PresentationSeriesNumber; ps.PresentationSeriesDateTime = studyInfo.PresentationSeriesDateTime; ps.PresentationInstanceNumber = studyInfo.GetNextPresentationInstanceNumber(); ps.SourceAETitle = provider.ImageSop.DataSource[DicomTags.SourceApplicationEntityTitle].ToString(); }) : null; if (presentationState != null) { presentationStates.Add(presentationState); } framePresentationStates.Add(new KeyValuePair <KeyImageReference, PresentationStateReference>(provider.Frame, presentationState)); } // serialize the key image document var serializer = new KeyImageSerializer(); serializer.Author = Author; serializer.Description = Description; serializer.DocumentTitle = DocumentTitle; serializer.SeriesDescription = SeriesDescription; foreach (var presentationFrame in framePresentationStates) { serializer.AddImage(presentationFrame.Key, presentationFrame.Value); } // collect all the SOP instances that were created (SC, PR and KO) var documents = new List <DicomFile>(); documents.AddRange(serializer.Serialize(koSeries => { var uid = koSeries.StudyInstanceUid; if (studyIndex.ContainsKey(uid)) { koSeries.SeriesDateTime = studyIndex[uid].KeyObjectSeriesDateTime; koSeries.SeriesNumber = studyIndex[uid].KeyObjectSeriesNumber; koSeries.SeriesInstanceUid = studyIndex[uid].KeyObjectSeriesUid; return(studyIndex[uid].DataSource); } return(null); } )); documents.AddRange(secondaryCaptureImageFactory.Files); documents.AddRange(presentationStates.Select(ps => ps.DicomFile)); // return the created instances grouped by study (and thus study origin/source) return(documents.GroupBy(f => (IStudySource)studyIndex[f.DataSet[DicomTags.StudyInstanceUid].ToString()]).ToDictionary(g => g.Key, g => g.ToList())); }
public IPresentationImage CreateSecondaryCapture(IPresentationImage image) { var imageSopProvider = image as IImageSopProvider; if (imageSopProvider == null) { const string msg = "image must implement IImageSopProvider"; throw new ArgumentException(msg, "image"); } SeriesInfo seriesInfo; var seriesKey = MakeSeriesKey(imageSopProvider.Frame.StudyInstanceUid, imageSopProvider.Sop.Modality); if (!_seriesInfo.TryGetValue(seriesKey, out seriesInfo)) { _seriesInfo[seriesKey] = seriesInfo = new SeriesInfo(_nextSeriesNumberDelegate.Invoke(imageSopProvider.Frame.StudyInstanceUid)); } var dcf = CreatePrototypeFile(imageSopProvider.Sop.DataSource); FillGeneralSeriesModule(dcf.DataSet, imageSopProvider.Frame, seriesInfo); FillScEquipmentModule(dcf.DataSet, Manufacturer, ManufacturersModelName, SoftwareVersions); FillFrameOfReferenceModule(dcf.DataSet, imageSopProvider.Frame); FillGeneralImageModule(dcf.DataSet, imageSopProvider.Frame, seriesInfo); FillScImageModule(dcf.DataSet, imageSopProvider.Frame); FillImagePlaneModule(dcf.DataSet, imageSopProvider.Frame); FillSopCommonModule(dcf.DataSet, SopClass.SecondaryCaptureImageStorageUid); FillAuxiliaryImageData(dcf.DataSet, imageSopProvider.Frame); if (image is GrayscalePresentationImage) { FillModalityLutModule(dcf.DataSet, imageSopProvider.Frame); FillVoiLutModule(dcf.DataSet, imageSopProvider.Frame); // create image pixel last - this method may need to override some attributes set previously CreateImagePixelModuleGrayscale(dcf.DataSet, imageSopProvider.Frame); } else if (image is ColorPresentationImage) { // create image pixel last - this method may need to override some attributes set previously CreateImagePixelModuleColor(dcf.DataSet, imageSopProvider.Frame); } else { // create image pixel last - this method may need to override some attributes set previously CreateImagePixelModuleRasterRgb(dcf.DataSet, image); } dcf.MediaStorageSopClassUid = dcf.DataSet[DicomTags.SopClassUid].ToString(); dcf.MediaStorageSopInstanceUid = dcf.DataSet[DicomTags.SopInstanceUid].ToString(); _files.Add(dcf); using (var sop = new ImageSop(new LocalSopDataSource(dcf))) { var secondaryCapture = PresentationImageFactory.Create(sop).Single(); try { var presentationState = DicomSoftcopyPresentationState.IsSupported(image) ? DicomSoftcopyPresentationState.Create(image) : null; if (presentationState != null) { presentationState.DeserializeOptions |= DicomSoftcopyPresentationStateDeserializeOptions.IgnoreImageRelationship; presentationState.Deserialize(secondaryCapture); // override the spatial transform of the secondary capture because the presentation state doesn't save exact parameters var sourceTransform = image as ISpatialTransformProvider; var targetTransform = secondaryCapture as ISpatialTransformProvider; if (sourceTransform != null && targetTransform != null) { targetTransform.SpatialTransform.CenterOfRotationXY = sourceTransform.SpatialTransform.CenterOfRotationXY; targetTransform.SpatialTransform.FlipX = sourceTransform.SpatialTransform.FlipX; targetTransform.SpatialTransform.FlipY = sourceTransform.SpatialTransform.FlipY; targetTransform.SpatialTransform.RotationXY = sourceTransform.SpatialTransform.RotationXY; targetTransform.SpatialTransform.Scale = sourceTransform.SpatialTransform.Scale; targetTransform.SpatialTransform.TranslationX = sourceTransform.SpatialTransform.TranslationX; targetTransform.SpatialTransform.TranslationY = sourceTransform.SpatialTransform.TranslationY; var sourceImageTransform = sourceTransform as IImageSpatialTransform; var targetImageTransform = targetTransform as IImageSpatialTransform; if (sourceImageTransform != null && targetImageTransform != null) { targetImageTransform.ScaleToFit = sourceImageTransform.ScaleToFit; } } } // force a render to update the client rectangle and scaling of the image secondaryCapture.RenderImage(image.ClientRectangle).Dispose(); } catch (Exception ex) { Platform.Log(LogLevel.Warn, ex, "An error has occurred while deserializing the image presentation state."); } return(secondaryCapture); } }