Beispiel #1
0
        /// <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);
            }
        }