コード例 #1
0
        private void CreateKeyObjectDocuments()
        {
            KeyImageSerializer serializer = new KeyImageSerializer();

            serializer.Description       = _sourceInformation.Description;
            serializer.DocumentTitle     = _sourceInformation.DocumentTitle;
            serializer.SeriesDescription = _sourceInformation.SeriesDescription;
            serializer.SourceAETitle     = DicomServer.AETitle;

            foreach (KeyValuePair <Frame, DicomSoftcopyPresentationState> presentationFrame in SourceFrames)
            {
                serializer.AddImage(presentationFrame.Key, presentationFrame.Value);
            }

            _keyObjectDocuments.AddRange(serializer.Serialize(
                                             delegate(KeyImageSerializer.KeyObjectDocumentSeries keyObjectDocumentSeries)
            {
                string key = keyObjectDocumentSeries.StudyInstanceUid;
                if (_seriesIndex.ContainsKey(key))
                {
                    keyObjectDocumentSeries.SeriesDateTime    = _seriesIndex[key].KeyObjectSeriesDateTime;
                    keyObjectDocumentSeries.SeriesNumber      = _seriesIndex[key].KeyObjectSeriesNumber;
                    keyObjectDocumentSeries.SeriesInstanceUid = _seriesIndex[key].KeyObjectSeriesUid;
                }
            }
                                             ));
        }
コード例 #2
0
ファイル: DisplaySetFactoryTests.cs プロジェクト: nhannd/Xian
		public void TestKeyImages(int numberOfFrames, int numberOfMultiframeKeyImages, int numberOfSingleFrameKeyImages, bool doSplitting)
		{
			Assert.IsTrue(numberOfFrames == 0 || numberOfFrames > 1);
			Assert.IsTrue(numberOfMultiframeKeyImages <= numberOfFrames);

			const int numberOfSeries = 1;
			int instancesPerSeries = numberOfSingleFrameKeyImages + ((numberOfFrames > 0) ? 1:0);

			Assert.IsTrue(instancesPerSeries > 0);

			List<TestDataSource> dataSources = CreateMRStudyDataSources(numberOfSeries, instancesPerSeries, "1.2.3");
			if (numberOfFrames > 0)
			{
				TestDataSource multiFrameDataSource = dataSources[0];
				DicomAttributeCollection oldDataSet = multiFrameDataSource._file.DataSet;
				DicomAttributeCollection newDataSet = new DicomAttributeCollection();
				DicomFile newFile = new DicomFile("", new DicomAttributeCollection(), newDataSet);
				//Yes this is the world's crappiest hack.
				base.SetupMultiframeXA(newDataSet, 512,512, (uint)numberOfFrames);
				//because of an exception that gets thrown from the DateTimeParser
				newDataSet[DicomTags.StudyDate].SetNullValue();
				newDataSet[DicomTags.StudyTime].SetNullValue();
				newDataSet[DicomTags.SeriesDate].SetNullValue();
				newDataSet[DicomTags.SeriesTime].SetNullValue();
				newDataSet[DicomTags.ReferencedStudySequence].SetEmptyValue();
				newDataSet[DicomTags.Modality].SetStringValue("MR");
				newDataSet[DicomTags.StudyInstanceUid].SetStringValue(oldDataSet[DicomTags.StudyInstanceUid].ToString());
				newDataSet[DicomTags.SeriesInstanceUid].SetStringValue(oldDataSet[DicomTags.SeriesInstanceUid].ToString());
				dataSources[0] = new TestDataSource(newFile);
			}

			StudyTree studyTree = CreateStudyTree(ConvertToSops(dataSources));
			KeyImageSerializer serializer = new KeyImageSerializer();

			Patient patient = studyTree.Patients[0];
			Study study = patient.Studies[0];
			Series sourceSeries = study.Series[0];

			List<IDisplaySet> allDisplaySets = new List<IDisplaySet>();

			BasicDisplaySetFactory factory = new BasicDisplaySetFactory();
			factory.SetStudyTree(studyTree);

			List<IDisplaySet> displaySets = factory.CreateDisplaySets(sourceSeries);
			allDisplaySets.AddRange(displaySets);

			List<DicomFile> presentationStates = new List<DicomFile>();
			int numberOfMultiframeKeyImagesCreated = 0;
			foreach (IDisplaySet displaySet in displaySets)
			{
				foreach (IPresentationImage image in displaySet.PresentationImages)
				{
					Frame frame = ((IImageSopProvider)image).Frame;
					if (frame.ParentImageSop.NumberOfFrames > 1)
					{
						if(numberOfMultiframeKeyImagesCreated >= numberOfMultiframeKeyImages)
							continue;

						++numberOfMultiframeKeyImagesCreated;
					}

					DicomSoftcopyPresentationState presentationState = DicomSoftcopyPresentationState.Create(image);
					//because of an exception that gets thrown from the DateTimeParser
					presentationState.DicomFile.DataSet[DicomTags.StudyDate].SetNullValue();
					presentationState.DicomFile.DataSet[DicomTags.StudyTime].SetNullValue();
					presentationState.DicomFile.DataSet[DicomTags.SeriesDate].SetNullValue();
					presentationState.DicomFile.DataSet[DicomTags.SeriesTime].SetNullValue();

					presentationStates.Add(presentationState.DicomFile);
					serializer.AddImage(frame, presentationState);
				}
			}

			List<DicomFile> files = serializer.Serialize();
			List<TestDataSource> keyImageDataSources = ConvertToDataSources(files);
			List<Sop> keyImageSops = ConvertToSops(keyImageDataSources);
			keyImageSops.AddRange(ConvertToSops(ConvertToDataSources(presentationStates)));

			foreach (Sop sop in keyImageSops)
				studyTree.AddSop(sop);

			try
			{
				foreach (Series series in study.Series)
				{
					if (series.Modality != "KO")
						continue;

				    List<IDisplaySet> keyImageDisplaySets;
                    if (doSplitting)
                    {
                        factory.CreateSingleImageDisplaySets = true;
                        keyImageDisplaySets = factory.CreateDisplaySets(series);
                        if (keyImageDisplaySets.Count == 0)
                        {
                            factory.CreateSingleImageDisplaySets = false;
                            keyImageDisplaySets = factory.CreateDisplaySets(series);
                        }
                    }
                    else
                    {
                        keyImageDisplaySets = factory.CreateDisplaySets(series);
                    }

					allDisplaySets.AddRange(keyImageDisplaySets);

					int numberOfKeyImages = numberOfMultiframeKeyImages + numberOfSingleFrameKeyImages;
					if (!doSplitting)
					{
						Assert.AreEqual(1, keyImageDisplaySets.Count, "There should be only one display set");
						IDisplaySet keyImageDisplaySet = keyImageDisplaySets[0];
						Assert.AreEqual(numberOfKeyImages, keyImageDisplaySet.PresentationImages.Count, "Expected {0} images", numberOfKeyImages);
						Assert.AreEqual(typeof(SeriesDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
					}
					else
					{
						Assert.AreEqual(numberOfKeyImages, keyImageDisplaySets.Count, "Expected {0} display sets", numberOfKeyImages);

						foreach (IDisplaySet keyImageDisplaySet in keyImageDisplaySets)
						{
							Assert.AreEqual(1, keyImageDisplaySet.PresentationImages.Count, "There should be only one presentation image");
							IPresentationImage keyImage = keyImageDisplaySet.PresentationImages[0];
							ImageSop sop = ((IImageSopProvider)keyImage).ImageSop;

							Assert.AreEqual(sourceSeries.SeriesInstanceUid, sop.SeriesInstanceUid, "Series Instance Uid is not that of the source series");
							if (numberOfKeyImages == 1)
								Assert.AreEqual(typeof(SeriesDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
							else if (sop.NumberOfFrames > 1)
								Assert.AreEqual(typeof(SingleFrameDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
							else
								Assert.AreEqual(typeof(SingleImageDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
						}
					}
				}
			}
			finally
			{
				foreach (IDisplaySet displaySet in allDisplaySets)
					displaySet.Dispose();

				studyTree.Dispose();
			}
		}
コード例 #3
0
        public void TestKeyImages(int numberOfFrames, int numberOfMultiframeKeyImages, int numberOfSingleFrameKeyImages, bool doSplitting)
        {
            Assert.IsTrue(numberOfFrames == 0 || numberOfFrames > 1);
            Assert.IsTrue(numberOfMultiframeKeyImages <= numberOfFrames);

            const int numberOfSeries     = 1;
            int       instancesPerSeries = numberOfSingleFrameKeyImages + ((numberOfFrames > 0) ? 1 : 0);

            Assert.IsTrue(instancesPerSeries > 0);

            List <TestDataSource> dataSources = CreateMRStudyDataSources(numberOfSeries, instancesPerSeries, "1.2.3");

            if (numberOfFrames > 0)
            {
                TestDataSource           multiFrameDataSource = dataSources[0];
                DicomAttributeCollection oldDataSet           = multiFrameDataSource.File.DataSet;
                DicomAttributeCollection newDataSet           = new DicomAttributeCollection();
                DicomFile newFile = new DicomFile("", new DicomAttributeCollection(), newDataSet);
                //Yes this is the world's crappiest hack.
                base.SetupMultiframeXA(newDataSet, 512, 512, (uint)numberOfFrames);
                //because of an exception that gets thrown from the DateTimeParser
                newDataSet[DicomTags.StudyDate].SetNullValue();
                newDataSet[DicomTags.StudyTime].SetNullValue();
                newDataSet[DicomTags.SeriesDate].SetNullValue();
                newDataSet[DicomTags.SeriesTime].SetNullValue();
                newDataSet[DicomTags.ReferencedStudySequence].SetEmptyValue();
                newDataSet[DicomTags.Modality].SetStringValue("MR");
                newDataSet[DicomTags.StudyInstanceUid].SetStringValue(oldDataSet[DicomTags.StudyInstanceUid].ToString());
                newDataSet[DicomTags.SeriesInstanceUid].SetStringValue(oldDataSet[DicomTags.SeriesInstanceUid].ToString());
                dataSources[0] = new TestDataSource(newFile);
            }

            StudyTree          studyTree  = CreateStudyTree(ConvertToSops(dataSources));
            KeyImageSerializer serializer = new KeyImageSerializer();

            Patient patient      = studyTree.Patients[0];
            Study   study        = patient.Studies[0];
            Series  sourceSeries = study.Series[0];

            List <IDisplaySet> allDisplaySets = new List <IDisplaySet>();

            BasicDisplaySetFactory factory = new BasicDisplaySetFactory();

            factory.SetStudyTree(studyTree);

            List <IDisplaySet> displaySets = factory.CreateDisplaySets(sourceSeries);

            allDisplaySets.AddRange(displaySets);

            List <DicomFile> presentationStates    = new List <DicomFile>();
            int numberOfMultiframeKeyImagesCreated = 0;

            foreach (IDisplaySet displaySet in displaySets)
            {
                foreach (IPresentationImage image in displaySet.PresentationImages)
                {
                    Frame frame = ((IImageSopProvider)image).Frame;
                    if (frame.ParentImageSop.NumberOfFrames > 1)
                    {
                        if (numberOfMultiframeKeyImagesCreated >= numberOfMultiframeKeyImages)
                        {
                            continue;
                        }

                        ++numberOfMultiframeKeyImagesCreated;
                    }

                    DicomSoftcopyPresentationState presentationState = DicomSoftcopyPresentationState.Create(image);
                    //because of an exception that gets thrown from the DateTimeParser
                    presentationState.DicomFile.DataSet[DicomTags.StudyDate].SetNullValue();
                    presentationState.DicomFile.DataSet[DicomTags.StudyTime].SetNullValue();
                    presentationState.DicomFile.DataSet[DicomTags.SeriesDate].SetNullValue();
                    presentationState.DicomFile.DataSet[DicomTags.SeriesTime].SetNullValue();

                    presentationStates.Add(presentationState.DicomFile);
                    serializer.AddImage(frame, presentationState);
                }
            }

            List <DicomFile>      files = serializer.Serialize();
            List <TestDataSource> keyImageDataSources = ConvertToDataSources(files);
            List <Sop>            keyImageSops        = ConvertToSops(keyImageDataSources);

            keyImageSops.AddRange(ConvertToSops(ConvertToDataSources(presentationStates)));

            foreach (Sop sop in keyImageSops)
            {
                studyTree.AddSop(sop);
            }

            try
            {
                foreach (Series series in study.Series)
                {
                    if (series.Modality != "KO")
                    {
                        continue;
                    }

                    List <IDisplaySet> keyImageDisplaySets;
                    if (doSplitting)
                    {
                        factory.CreateSingleImageDisplaySets = true;
                        keyImageDisplaySets = factory.CreateDisplaySets(series);
                        if (keyImageDisplaySets.Count == 0)
                        {
                            factory.CreateSingleImageDisplaySets = false;
                            keyImageDisplaySets = factory.CreateDisplaySets(series);
                        }
                    }
                    else
                    {
                        keyImageDisplaySets = factory.CreateDisplaySets(series);
                    }

                    allDisplaySets.AddRange(keyImageDisplaySets);

                    int numberOfKeyImages = numberOfMultiframeKeyImages + numberOfSingleFrameKeyImages;
                    if (!doSplitting)
                    {
                        Assert.AreEqual(1, keyImageDisplaySets.Count, "There should be only one display set");
                        IDisplaySet keyImageDisplaySet = keyImageDisplaySets[0];
                        Assert.AreEqual(numberOfKeyImages, keyImageDisplaySet.PresentationImages.Count, "Expected {0} images", numberOfKeyImages);
                        Assert.AreEqual(typeof(KOSelectionDocumentDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
                    }
                    else
                    {
                        Assert.AreEqual(numberOfKeyImages, keyImageDisplaySets.Count, "Expected {0} display sets", numberOfKeyImages);

                        foreach (IDisplaySet keyImageDisplaySet in keyImageDisplaySets)
                        {
                            Assert.AreEqual(1, keyImageDisplaySet.PresentationImages.Count, "There should be only one presentation image");
                            IPresentationImage keyImage = keyImageDisplaySet.PresentationImages[0];
                            ImageSop           sop      = ((IImageSopProvider)keyImage).ImageSop;

                            Assert.AreEqual(sourceSeries.SeriesInstanceUid, sop.SeriesInstanceUid, "Series Instance Uid is not that of the source series");
                            if (numberOfKeyImages == 1)
                            {
                                Assert.AreEqual(typeof(KOSelectionDocumentDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
                            }
                            else if (sop.NumberOfFrames > 1)
                            {
                                Assert.AreEqual(typeof(KOSelectionSingleFrameDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
                            }
                            else
                            {
                                Assert.AreEqual(typeof(KOSelectionSingleImageDisplaySetDescriptor), keyImageDisplaySet.Descriptor.GetType(), "Wrong display set descriptor type");
                            }
                        }
                    }
                }
            }
            finally
            {
                foreach (IDisplaySet displaySet in allDisplaySets)
                {
                    displaySet.Dispose();
                }

                studyTree.Dispose();
            }
        }
コード例 #4
0
        /// <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()));
        }
コード例 #5
0
		/// <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 = null)
		{
			if (!HasChanges || !Items.Any()) return new Dictionary<IStudySource, List<DicomFile>>(0);

			// 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 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
					if (_parentStudyInstanceUid == studyInstanceUid && _seriesNumber.HasValue)
						studyInfo.KeyObjectSeriesNumber = _seriesNumber.Value;
				}

				// 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;
				}

				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 (both 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(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());
		}