public KeyImageContentItem(string imageSopInstanceUid, string presentationSopInstanceUid, KeyObjectSelectionDocumentIod source)
 {
     this.ReferencedImageSopInstanceUid   = imageSopInstanceUid;
     this.PresentationStateSopInstanceUid = presentationSopInstanceUid;
     this.FrameNumber = null;
     this._source     = source;
 }
Example #2
0
        /// <summary>
        /// Creates the presentation images for a given key object selection document.
        /// </summary>
        /// <param name="keyObjectDocument">The key object selection document from which presentation images are to be created.</param>
        /// <returns>A list of created presentation images.</returns>
        protected virtual List <IPresentationImage> CreateImages(KeyObjectSelectionDocumentIod keyObjectDocument)
        {
            List <IPresentationImage> images = new List <IPresentationImage>();

            if (_studyTree == null)
            {
                Platform.Log(LogLevel.Warn, "Key object document cannot be used to create images because there is no study tree to build from.");
            }
            else
            {
                IList <IKeyObjectContentItem> content = new KeyImageDeserializer(keyObjectDocument).Deserialize();
                var evidence = new HierarchicalSopInstanceReferenceDictionary(keyObjectDocument.KeyObjectDocument.CurrentRequestedProcedureEvidenceSequence);
                foreach (IKeyObjectContentItem item in content)
                {
                    if (item is KeyImageContentItem)
                    {
                        images.AddRange(CreateImages((KeyImageContentItem)item, evidence));
                    }
                    else
                    {
                        Platform.Log(LogLevel.Warn, "Unsupported key object content value type");
                    }
                }
            }

            return(images);
        }
        /// <summary>
        /// Creates the presentation images for a given key object selection document.
        /// </summary>
        /// <param name="keyObjectDocument">The key object selection document from which presentation images are to be created.</param>
        /// <returns>A list of created presentation images.</returns>
        protected virtual List <IPresentationImage> CreateImages(KeyObjectSelectionDocumentIod keyObjectDocument)
        {
            List <IPresentationImage> images = new List <IPresentationImage>();

            if (_studyTree == null)
            {
                Platform.Log(LogLevel.Warn, "Key object document cannot be used to create images because there is no study tree to build from.");
            }
            else
            {
                IList <IKeyObjectContentItem> content = new KeyImageDeserializer(keyObjectDocument).Deserialize();
                foreach (IKeyObjectContentItem item in content)
                {
                    if (item is KeyImageContentItem)
                    {
                        images.AddRange(CreateImages((KeyImageContentItem)item));
                    }
                    else
                    {
                        Platform.Log(LogLevel.Warn, "Unsupported key object content value type");
                    }
                }
            }

            return(images);
        }
        /// <summary>
        /// Creates the presentation images for a given key object selection document.
        /// </summary>
        /// <param name="keyObjectDocument">The key object selection document from which presentation images are to be created.</param>
        /// <returns>A list of created presentation images.</returns>
        protected virtual List <IPresentationImage> CreateImages(KeyObjectSelectionDocumentIod keyObjectDocument)
        {
            List <IPresentationImage> images = new List <IPresentationImage>();

            if (_studyTree == null)
            {
                Platform.Log(LogLevel.Warn, "Key object document cannot be used to create images because there is no study tree to build from.");
            }
            else
            {
                try
                {
                    IList <IKeyObjectContentItem> content = new KeyImageDeserializer(keyObjectDocument).Deserialize();
                    var evidence = new HierarchicalSopInstanceReferenceDictionary(keyObjectDocument.KeyObjectDocument.CurrentRequestedProcedureEvidenceSequence);
                    foreach (IKeyObjectContentItem item in content)
                    {
                        try
                        {
                            var contentItem = item as KeyImageContentItem;
                            if (contentItem != null)
                            {
                                images.AddRange(CreateImages(contentItem, evidence));
                            }
                            else
                            {
                                Platform.Log(LogLevel.Warn, "Unsupported key object content value type");
                            }
                        }
                        catch (Exception ex)
                        {
                            // catches KO errors with individual content items, allowing as many items as possible to be created
                            Platform.Log(LogLevel.Warn, ex, SR.MessageKeyObjectDeserializeFailure);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // catches KO errors with the entire document
                    Platform.Log(LogLevel.Warn, ex, SR.MessageKeyObjectDeserializeFailure);
                }
            }

            // return a KO error placeholder, otherwise the sop will be treated later as an unsupported sop class
            if (images.Count == 0 && keyObjectDocument.DataSource is Sop)
            {
                images.Add(PlaceholderDisplaySetFactory.CreatePlaceholderImage((Sop)keyObjectDocument.DataSource, SR.MessageKeyObjectDeserializeFailure));
            }
            return(images);
        }
 public KeyImageContentItem(string imageSopInstanceUid, int frameNumber, string presentationSopInstanceUid, KeyObjectSelectionDocumentIod source)
     : this(imageSopInstanceUid, presentationSopInstanceUid, source)
 {
     this.FrameNumber = frameNumber;
 }
 /// <summary>
 /// Constructs a new instance of <see cref="KeyImageDeserializer"/>.
 /// </summary>
 /// <remarks>
 /// <para>Due to the relatively new nature of key object support in the ClearCanvas Framework, this API may be more prone to changes in the next release.</para>
 /// </remarks>
 public KeyImageDeserializer(KeyObjectSelectionDocumentIod iod)
 {
     _document = iod;
 }
 /// <summary>
 /// Constructs a new instance of <see cref="KeyImageDeserializer"/>.
 /// </summary>
 /// <remarks>
 /// <para>Due to the relatively new nature of key object support in the ClearCanvas Framework, this API may be more prone to changes in the next release.</para>
 /// </remarks>
 public KeyImageDeserializer(Sop sourceSop)
 {
     _document = new KeyObjectSelectionDocumentIod(sourceSop.DataSource);
 }
        /// <summary>
        /// Serializes the current contents into a number of key object selection document SOP instances.
        /// </summary>
        /// <param name="callback">A callback method to initialize the series-level attributes of the key object document.
        /// Should return a data set from which patient and study level attributes can be copied, otherwise a KO document will not be created for this study.
        /// </param>
        public List <DicomFile> Serialize(InitializeKeyObjectDocumentSeriesCallback callback)
        {
            callback = callback ?? DefaultInitializeKeyObjectDocumentSeriesCallback;

            if (_framePresentationStates.Count == 0)
            {
                throw new InvalidOperationException("Key object selection cannot be empty.");
            }

            List <DicomFile>            keyObjectDocuments = new List <DicomFile>();
            List <SopInstanceReference> identicalDocuments = new List <SopInstanceReference>();
            Dictionary <string, KeyObjectSelectionDocumentIod> koDocumentsByStudy = new Dictionary <string, KeyObjectSelectionDocumentIod>();

            foreach (var frame in (IEnumerable <KeyImageReference>)_framePresentationStates)
            {
                string studyInstanceUid = frame.StudyInstanceUid;
                if (!koDocumentsByStudy.ContainsKey(studyInstanceUid))
                {
                    KeyObjectDocumentSeries seriesInfo = new KeyObjectDocumentSeries(studyInstanceUid);
                    var prototypeDataSet = callback.Invoke(seriesInfo);
                    if (prototypeDataSet == null)
                    {
                        continue;
                    }

                    DicomFile keyObjectDocument = new DicomFile();
                    keyObjectDocument.SourceApplicationEntityTitle = frame.SourceApplicationEntityTitle;

                    _sopInstanceFactory.InitializeDataSet(prototypeDataSet, keyObjectDocument.DataSet);

                    KeyObjectSelectionDocumentIod iod = new KeyObjectSelectionDocumentIod(keyObjectDocument.DataSet);

                    iod.GeneralEquipment.Manufacturer                = this.Manufacturer ?? string.Empty;      // this one is type 2 - all other GenEq attributes are type 3
                    iod.GeneralEquipment.ManufacturersModelName      = string.IsNullOrEmpty(this.ManufacturersModelName) ? null : this.ManufacturersModelName;
                    iod.GeneralEquipment.DeviceSerialNumber          = string.IsNullOrEmpty(this.DeviceSerialNumber) ? null : this.DeviceSerialNumber;
                    iod.GeneralEquipment.SoftwareVersions            = string.IsNullOrEmpty(this.SoftwareVersions) ? null : this.SoftwareVersions;
                    iod.GeneralEquipment.InstitutionName             = string.IsNullOrEmpty(this.Institution.Name) ? null : this.Institution.Name;
                    iod.GeneralEquipment.InstitutionAddress          = string.IsNullOrEmpty(this.Institution.Address) ? null : this.Institution.Address;
                    iod.GeneralEquipment.InstitutionalDepartmentName = string.IsNullOrEmpty(this.Institution.DepartmentName) ? null : this.Institution.DepartmentName;
                    iod.GeneralEquipment.StationName = string.IsNullOrEmpty(this.StationName) ? null : this.StationName;

                    iod.KeyObjectDocumentSeries.InitializeAttributes();
                    iod.KeyObjectDocumentSeries.Modality          = Modality.KO;
                    iod.KeyObjectDocumentSeries.SeriesDateTime    = seriesInfo.SeriesDateTime;
                    iod.KeyObjectDocumentSeries.SeriesDescription = SeriesDescription;
                    iod.KeyObjectDocumentSeries.SeriesInstanceUid = CreateUid(seriesInfo.SeriesInstanceUid);
                    iod.KeyObjectDocumentSeries.SeriesNumber      = seriesInfo.SeriesNumber ?? 1;
                    iod.KeyObjectDocumentSeries.ReferencedPerformedProcedureStepSequence = null;

                    iod.SopCommon.SopClass       = SopClass.KeyObjectSelectionDocumentStorage;
                    iod.SopCommon.SopInstanceUid = DicomUid.GenerateUid().UID;

                    identicalDocuments.Add(new SopInstanceReference(
                                               studyInstanceUid,
                                               iod.KeyObjectDocumentSeries.SeriesInstanceUid,
                                               iod.SopCommon.SopClassUid,
                                               iod.SopCommon.SopInstanceUid));

                    koDocumentsByStudy.Add(studyInstanceUid, iod);
                    keyObjectDocuments.Add(keyObjectDocument);
                }
            }

            foreach (KeyObjectSelectionDocumentIod iod in koDocumentsByStudy.Values)
            {
                iod.KeyObjectDocument.InitializeAttributes();
                iod.KeyObjectDocument.InstanceNumber            = 1;
                iod.KeyObjectDocument.ContentDateTime           = DateTime;
                iod.KeyObjectDocument.ReferencedRequestSequence = null;

                // only add docuemnts other than current to the identical documents sequence (and if there's only one, it's obviously the current)
                if (identicalDocuments.Count > 1)
                {
                    var identicalDocumentsSequence = new HierarchicalSopInstanceReferenceDictionary();
                    var thisDocument = new SopInstanceReference(iod.GeneralStudy.StudyInstanceUid, iod.KeyObjectDocumentSeries.SeriesInstanceUid, iod.SopCommon.SopClassUid, iod.SopCommon.SopInstanceUid);
                    foreach (var otherDocument in identicalDocuments.Where(d => !d.Equals(thisDocument)))
                    {
                        identicalDocumentsSequence.AddReference(otherDocument.StudyInstanceUid, otherDocument.SeriesInstanceUid, otherDocument.SopClassUid, otherDocument.SopInstanceUid);
                    }
                    iod.KeyObjectDocument.IdenticalDocumentsSequence = identicalDocumentsSequence;
                }

                iod.SrDocumentContent.InitializeContainerAttributes();
                iod.SrDocumentContent.ConceptNameCodeSequence = DocumentTitle;

                List <IContentSequence> contentList = new List <IContentSequence>();
                EvidenceDictionary      currentRequestedProcedureEvidenceList = new EvidenceDictionary();

                List <KeyImageReference> frameMap = new List <KeyImageReference>();
                foreach (var frameAndPresentationState in _framePresentationStates)
                {
                    var frame = frameAndPresentationState.Key;

                    // build frame map by unique sop - used to make the evidence sequence less verbose
                    if (!frameMap.Contains(frame))
                    {
                        frameMap.Add(frame);
                    }

                    // content sequence must still list all content as it was given, including any repeats
                    IContentSequence content = iod.SrDocumentContent.CreateContentSequence();
                    {
                        content.RelationshipType = RelationshipType.Contains;

                        IImageReferenceMacro imageReferenceMacro = content.InitializeImageReferenceAttributes();
                        imageReferenceMacro.ReferencedSopSequence.InitializeAttributes();
                        imageReferenceMacro.ReferencedSopSequence.ReferencedSopClassUid    = frame.SopClassUid;
                        imageReferenceMacro.ReferencedSopSequence.ReferencedSopInstanceUid = frame.SopInstanceUid;
                        if (frame.FrameNumber.HasValue)
                        {
                            imageReferenceMacro.ReferencedSopSequence.ReferencedFrameNumber = frame.FrameNumber.Value.ToString(CultureInfo.InvariantCulture);
                        }
                        else
                        {
                            imageReferenceMacro.ReferencedSopSequence.ReferencedFrameNumber = null;
                        }

                        // save the presentation state
                        if (frameAndPresentationState.Value != null)
                        {
                            var presentationState = frameAndPresentationState.Value;
                            imageReferenceMacro.ReferencedSopSequence.CreateReferencedSopSequence();
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.InitializeAttributes();
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.ReferencedSopClassUid    = presentationState.SopClassUid;
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.ReferencedSopInstanceUid = presentationState.SopInstanceUid;
                        }
                    }
                    contentList.Add(content);
                }

                // add the author
                if (!string.IsNullOrEmpty(Author))
                {
                    IContentSequence koAuthor = iod.SrDocumentContent.CreateContentSequence();
                    koAuthor.InitializeAttributes();
                    koAuthor.ConceptNameCodeSequence = KeyObjectSelectionCodeSequences.PersonObserverName;
                    koAuthor.PersonName       = Author;
                    koAuthor.RelationshipType = RelationshipType.HasObsContext;
                    contentList.Add(koAuthor);
                }

                // add the description
                if (!string.IsNullOrEmpty(Description))
                {
                    IContentSequence koDescription = iod.SrDocumentContent.CreateContentSequence();
                    koDescription.InitializeAttributes();
                    koDescription.ConceptNameCodeSequence = KeyObjectSelectionCodeSequences.KeyObjectDescription;
                    koDescription.TextValue        = Description;
                    koDescription.RelationshipType = RelationshipType.Contains;
                    contentList.Add(koDescription);
                }

                // add each unique sop to the evidence list using the map built earlier
                foreach (var sop in frameMap.Distinct())
                {
                    currentRequestedProcedureEvidenceList.Add(sop);
                }

                // add each referenced presentation state to the evidence list as well
                foreach (var state in (IEnumerable <PresentationStateReference>)_framePresentationStates)
                {
                    if (state == null)
                    {
                        continue;
                    }
                    currentRequestedProcedureEvidenceList.Add(state);
                }

                // set the content and the evidence sequences
                iod.SrDocumentContent.ContentSequence = contentList.ToArray();
                iod.KeyObjectDocument.CurrentRequestedProcedureEvidenceSequence = currentRequestedProcedureEvidenceList.ToArray();
            }

            // set meta for the files
            foreach (DicomFile keyObjectDocument in keyObjectDocuments)
            {
                keyObjectDocument.MediaStorageSopClassUid    = keyObjectDocument.DataSet[DicomTags.SopClassUid].ToString();
                keyObjectDocument.MediaStorageSopInstanceUid = keyObjectDocument.DataSet[DicomTags.SopInstanceUid].ToString();
            }

            return(keyObjectDocuments);
        }
Example #9
0
        private static KeyObjectSelectionDocumentIod CreatePrototypeDocument(IDicomAttributeProvider source, DicomAttributeCollection target, string specificCharacterSet)
        {
            KeyObjectSelectionDocumentIod iod = new KeyObjectSelectionDocumentIod(target);

            specificCharacterSet        = specificCharacterSet ?? string.Empty;
            target.SpecificCharacterSet = specificCharacterSet;
            target[DicomTags.SpecificCharacterSet].SetStringValue(specificCharacterSet);

            PatientModuleIod sourcePatient = new PatientModuleIod(source);

            if (true)             // patient module is always required
            {
                iod.Patient.BreedRegistrationSequence          = sourcePatient.BreedRegistrationSequence;
                iod.Patient.DeIdentificationMethod             = sourcePatient.DeIdentificationMethod;
                iod.Patient.DeIdentificationMethodCodeSequence = sourcePatient.DeIdentificationMethodCodeSequence;
                iod.Patient.EthnicGroup              = sourcePatient.EthnicGroup;
                iod.Patient.IssuerOfPatientId        = sourcePatient.IssuerOfPatientId;
                iod.Patient.OtherPatientIds          = sourcePatient.OtherPatientIds;
                iod.Patient.OtherPatientIdsSequence  = sourcePatient.OtherPatientIdsSequence;
                iod.Patient.OtherPatientNames        = sourcePatient.OtherPatientNames;
                iod.Patient.PatientBreedCodeSequence = sourcePatient.PatientBreedCodeSequence;
                iod.Patient.PatientBreedDescription  = sourcePatient.PatientBreedDescription;
                iod.Patient.PatientComments          = sourcePatient.PatientComments;
                iod.Patient.PatientId = sourcePatient.PatientId;
                iod.Patient.PatientIdentityRemoved     = sourcePatient.PatientIdentityRemoved;
                iod.Patient.PatientsBirthDateTime      = sourcePatient.PatientsBirthDateTime;
                iod.Patient.PatientsName               = sourcePatient.PatientsName;
                iod.Patient.PatientSpeciesCodeSequence = sourcePatient.PatientSpeciesCodeSequence;
                iod.Patient.PatientSpeciesDescription  = sourcePatient.PatientSpeciesDescription;
                iod.Patient.PatientsSex = sourcePatient.PatientsSex;
                iod.Patient.ReferencedPatientSequence = sourcePatient.ReferencedPatientSequence;
                iod.Patient.ResponsibleOrganization   = sourcePatient.ResponsibleOrganization;
                iod.Patient.ResponsiblePerson         = sourcePatient.ResponsiblePerson;
                iod.Patient.ResponsiblePersonRole     = sourcePatient.ResponsiblePersonRole;
            }

            SpecimenIdentificationModuleIod sourceSpecimen = new SpecimenIdentificationModuleIod(source);

            if (sourceSpecimen.HasValues())             // specimen module is required only if subject is a specimen
            {
                iod.SpecimenIdentification.SpecimenAccessionNumber = sourceSpecimen.SpecimenAccessionNumber;
                iod.SpecimenIdentification.SpecimenSequence        = sourceSpecimen.SpecimenSequence;
            }

            ClinicalTrialSubjectModuleIod sourceTrialSubject = new ClinicalTrialSubjectModuleIod(source);

            if (sourceTrialSubject.HasValues())             // clinical trial subkect module is user optional
            {
                iod.ClinicalTrialSubject.ClinicalTrialProtocolId       = sourceTrialSubject.ClinicalTrialProtocolId;
                iod.ClinicalTrialSubject.ClinicalTrialProtocolName     = sourceTrialSubject.ClinicalTrialProtocolName;
                iod.ClinicalTrialSubject.ClinicalTrialSiteId           = sourceTrialSubject.ClinicalTrialSiteId;
                iod.ClinicalTrialSubject.ClinicalTrialSiteName         = sourceTrialSubject.ClinicalTrialSiteName;
                iod.ClinicalTrialSubject.ClinicalTrialSponsorName      = sourceTrialSubject.ClinicalTrialSponsorName;
                iod.ClinicalTrialSubject.ClinicalTrialSubjectId        = sourceTrialSubject.ClinicalTrialSubjectId;
                iod.ClinicalTrialSubject.ClinicalTrialSubjectReadingId = sourceTrialSubject.ClinicalTrialSubjectReadingId;
            }

            GeneralStudyModuleIod sourceGeneralStudy = new GeneralStudyModuleIod(source);

            if (true)             // general study module is always required
            {
                iod.GeneralStudy.AccessionNumber = sourceGeneralStudy.AccessionNumber;
                iod.GeneralStudy.NameOfPhysiciansReadingStudy                 = sourceGeneralStudy.NameOfPhysiciansReadingStudy;
                iod.GeneralStudy.PhysiciansOfRecord                           = sourceGeneralStudy.PhysiciansOfRecord;
                iod.GeneralStudy.PhysiciansOfRecordIdentificationSequence     = sourceGeneralStudy.PhysiciansOfRecordIdentificationSequence;
                iod.GeneralStudy.PhysiciansReadingStudyIdentificationSequence = sourceGeneralStudy.PhysiciansReadingStudyIdentificationSequence;
                iod.GeneralStudy.ProcedureCodeSequence                        = sourceGeneralStudy.ProcedureCodeSequence;
                iod.GeneralStudy.ReferencedStudySequence                      = sourceGeneralStudy.ReferencedStudySequence;
                iod.GeneralStudy.ReferringPhysicianIdentificationSequence     = sourceGeneralStudy.ReferringPhysicianIdentificationSequence;
                iod.GeneralStudy.ReferringPhysiciansName                      = sourceGeneralStudy.ReferringPhysiciansName;
                iod.GeneralStudy.StudyDateTime    = sourceGeneralStudy.StudyDateTime;
                iod.GeneralStudy.StudyDescription = sourceGeneralStudy.StudyDescription;
                iod.GeneralStudy.StudyId          = sourceGeneralStudy.StudyId;
                iod.GeneralStudy.StudyInstanceUid = sourceGeneralStudy.StudyInstanceUid;
            }

            PatientStudyModuleIod sourcePatientStudy = new PatientStudyModuleIod(source);

            if (sourcePatientStudy.HasValues())             // patient study module is user optional
            {
                iod.PatientStudy.AdditionalPatientHistory = sourcePatientStudy.AdditionalPatientHistory;
                iod.PatientStudy.AdmissionId = sourcePatientStudy.AdmissionId;
                iod.PatientStudy.AdmittingDiagnosesCodeSequence = sourcePatientStudy.AdmittingDiagnosesCodeSequence;
                iod.PatientStudy.AdmittingDiagnosesDescription  = sourcePatientStudy.AdmittingDiagnosesDescription;
                iod.PatientStudy.IssuerOfAdmissionId            = sourcePatientStudy.IssuerOfAdmissionId;
                iod.PatientStudy.IssuerOfServiceEpisodeId       = sourcePatientStudy.IssuerOfServiceEpisodeId;
                iod.PatientStudy.Occupation                = sourcePatientStudy.Occupation;
                iod.PatientStudy.PatientsAge               = sourcePatientStudy.PatientsAge;
                iod.PatientStudy.PatientsSexNeutered       = sourcePatientStudy.PatientsSexNeutered;
                iod.PatientStudy.PatientsSize              = sourcePatientStudy.PatientsSize;
                iod.PatientStudy.PatientsWeight            = sourcePatientStudy.PatientsWeight;
                iod.PatientStudy.ServiceEpisodeDescription = sourcePatientStudy.ServiceEpisodeDescription;
                iod.PatientStudy.ServiceEpisodeId          = sourcePatientStudy.ServiceEpisodeId;
            }

            ClinicalTrialStudyModuleIod sourceTrialStudy = new ClinicalTrialStudyModuleIod(source);

            if (sourceTrialStudy.HasValues())             // clinical trial study module is user optional
            {
                iod.ClinicalTrialStudy.ClinicalTrialTimePointDescription = sourceTrialStudy.ClinicalTrialTimePointDescription;
                iod.ClinicalTrialStudy.ClinicalTrialTimePointId          = sourceTrialStudy.ClinicalTrialTimePointId;
            }

            return(iod);
        }
Example #10
0
        /// <summary>
        /// Serializes the current contents into a number of key object selection document SOP instances.
        /// </summary>
        /// <param name="callback">A callback method to initialize the series-level attributes of the key object document.</param>
        public List <DicomFile> Serialize(InitializeKeyObjectDocumentSeriesCallback callback)
        {
            callback = callback ?? DefaultInitializeKeyObjectDocumentSeriesCallback;

            if (_framePresentationStates.Count == 0)
            {
                throw new InvalidOperationException("Key object selection cannot be empty.");
            }

            List <DicomFile> keyObjectDocuments = new List <DicomFile>();
            List <IHierarchicalSopInstanceReferenceMacro>      identicalDocuments = new List <IHierarchicalSopInstanceReferenceMacro>();
            Dictionary <string, KeyObjectSelectionDocumentIod> koDocumentsByStudy = new Dictionary <string, KeyObjectSelectionDocumentIod>();

            foreach (Frame frame in (IEnumerable <Frame>)_framePresentationStates)
            {
                string studyInstanceUid = frame.StudyInstanceUid;
                if (!koDocumentsByStudy.ContainsKey(studyInstanceUid))
                {
                    KeyObjectDocumentSeries seriesInfo = new KeyObjectDocumentSeries(frame.ParentImageSop.PatientId, studyInstanceUid);
                    callback.Invoke(seriesInfo);

                    DicomFile keyObjectDocument = new DicomFile();
                    keyObjectDocument.SourceApplicationEntityTitle = this.SourceAETitle;

                    KeyObjectSelectionDocumentIod iod = CreatePrototypeDocument(frame.ParentImageSop.DataSource, keyObjectDocument.DataSet, SpecificCharacterSet);

                    iod.GeneralEquipment.Manufacturer                = this.Manufacturer ?? string.Empty;      // this one is type 2 - all other GenEq attributes are type 3
                    iod.GeneralEquipment.ManufacturersModelName      = string.IsNullOrEmpty(this.ManufacturersModelName) ? null : this.ManufacturersModelName;
                    iod.GeneralEquipment.DeviceSerialNumber          = string.IsNullOrEmpty(this.DeviceSerialNumber) ? null : this.DeviceSerialNumber;
                    iod.GeneralEquipment.SoftwareVersions            = string.IsNullOrEmpty(this.SoftwareVersions) ? null : this.SoftwareVersions;
                    iod.GeneralEquipment.InstitutionName             = string.IsNullOrEmpty(this.Institution.Name) ? null : this.Institution.Name;
                    iod.GeneralEquipment.InstitutionAddress          = string.IsNullOrEmpty(this.Institution.Address) ? null : this.Institution.Address;
                    iod.GeneralEquipment.InstitutionalDepartmentName = string.IsNullOrEmpty(this.Institution.DepartmentName) ? null : this.Institution.DepartmentName;
                    iod.GeneralEquipment.StationName = string.IsNullOrEmpty(this.StationName) ? null : this.StationName;

                    string seriesDescription = _seriesDescription;
                    if (!string.IsNullOrEmpty(_author))
                    {
                        seriesDescription = string.Format("{0} ({1})", seriesDescription, _author);
                    }

                    iod.KeyObjectDocumentSeries.InitializeAttributes();
                    iod.KeyObjectDocumentSeries.Modality          = Modality.KO;
                    iod.KeyObjectDocumentSeries.SeriesDateTime    = seriesInfo.SeriesDateTime;
                    iod.KeyObjectDocumentSeries.SeriesDescription = seriesDescription;
                    iod.KeyObjectDocumentSeries.SeriesInstanceUid = CreateUid(seriesInfo.SeriesInstanceUid);
                    iod.KeyObjectDocumentSeries.SeriesNumber      = seriesInfo.SeriesNumber ?? CalculateSeriesNumber(frame);
                    iod.KeyObjectDocumentSeries.ReferencedPerformedProcedureStepSequence = null;

                    iod.SopCommon.SopClass       = SopClass.KeyObjectSelectionDocumentStorage;
                    iod.SopCommon.SopInstanceUid = DicomUid.GenerateUid().UID;

                    identicalDocuments.Add(iod.KeyObjectDocument.CreateIdenticalDocumentsSequence(
                                               studyInstanceUid,
                                               iod.KeyObjectDocumentSeries.SeriesInstanceUid,
                                               iod.SopCommon.SopClassUid,
                                               iod.SopCommon.SopInstanceUid));

                    koDocumentsByStudy.Add(studyInstanceUid, iod);
                    keyObjectDocuments.Add(keyObjectDocument);
                }
            }

            foreach (KeyObjectSelectionDocumentIod iod in koDocumentsByStudy.Values)
            {
                iod.KeyObjectDocument.InitializeAttributes();
                iod.KeyObjectDocument.InstanceNumber            = 1;
                iod.KeyObjectDocument.ContentDateTime           = _datetime;
                iod.KeyObjectDocument.ReferencedRequestSequence = null;

                iod.KeyObjectDocument.IdenticalDocumentsSequence = identicalDocuments.ToArray();

                iod.SrDocumentContent.InitializeContainerAttributes();
                iod.SrDocumentContent.ConceptNameCodeSequence = _docTitle;

                List <IContentSequence> contentList = new List <IContentSequence>();
                EvidenceDictionary      currentRequestedProcedureEvidenceList = new EvidenceDictionary();

                Dictionary <ImageSop, List <int> > frameMap = new Dictionary <ImageSop, List <int> >();
                foreach (KeyValuePair <Frame, DicomSoftcopyPresentationState> frameAndPresentationState in _framePresentationStates)
                {
                    Frame    frame = frameAndPresentationState.Key;
                    ImageSop sop   = frame.ParentImageSop;

                    // build frame map by unique sop - used to make the evidence sequence less verbose
                    if (!frameMap.ContainsKey(frame.ParentImageSop))
                    {
                        frameMap.Add(frame.ParentImageSop, new List <int>());
                    }
                    List <int> frames = frameMap[frame.ParentImageSop];
                    if (!frames.Contains(frame.FrameNumber))
                    {
                        frames.Add(frame.FrameNumber);
                    }

                    // content sequence must still list all content as it was given, including any repeats
                    IContentSequence content = iod.SrDocumentContent.CreateContentSequence();
                    {
                        content.RelationshipType = RelationshipType.Contains;
                        content.ReferencedContentItemIdentifier = new uint[] { 1 };

                        IImageReferenceMacro imageReferenceMacro = content.InitializeImageReferenceAttributes();
                        imageReferenceMacro.ReferencedSopSequence.InitializeAttributes();
                        imageReferenceMacro.ReferencedSopSequence.ReferencedSopClassUid    = sop.SopClassUid;
                        imageReferenceMacro.ReferencedSopSequence.ReferencedSopInstanceUid = sop.SopInstanceUid;
                        if (sop.NumberOfFrames > 1)
                        {
                            imageReferenceMacro.ReferencedSopSequence.ReferencedFrameNumber = frame.FrameNumber.ToString();
                        }
                        else
                        {
                            imageReferenceMacro.ReferencedSopSequence.ReferencedFrameNumber = null;
                        }

                        // save the presentation state
                        if (frameAndPresentationState.Value != null)
                        {
                            DicomSoftcopyPresentationState presentationState = frameAndPresentationState.Value;
                            imageReferenceMacro.ReferencedSopSequence.CreateReferencedSopSequence();
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.InitializeAttributes();
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.ReferencedSopClassUid    = presentationState.PresentationSopClass.Uid;
                            imageReferenceMacro.ReferencedSopSequence.ReferencedSopSequence.ReferencedSopInstanceUid = presentationState.PresentationSopInstanceUid;
                        }
                    }
                    contentList.Add(content);
                }

                // add the description
                if (!string.IsNullOrEmpty(_description))
                {
                    IContentSequence koDescription = iod.SrDocumentContent.CreateContentSequence();
                    koDescription.InitializeAttributes();
                    koDescription.ConceptNameCodeSequence = KeyObjectSelectionCodeSequences.KeyObjectDescription;
                    koDescription.TextValue        = _description;
                    koDescription.RelationshipType = RelationshipType.Contains;
                    koDescription.ReferencedContentItemIdentifier = new uint[] { 1 };
                    contentList.Add(koDescription);
                }

                // add each unique sop to the evidence list using the map built earlier
                foreach (ImageSop sop in frameMap.Keys)
                {
                    currentRequestedProcedureEvidenceList.Add(sop);
                }

                // add each referenced presentation state to the evidence list as well
                foreach (DicomSoftcopyPresentationState state in (IEnumerable <DicomSoftcopyPresentationState>)_framePresentationStates)
                {
                    if (state == null)
                    {
                        continue;
                    }
                    currentRequestedProcedureEvidenceList.Add(state);
                }

                // set the content and the evidence sequences
                iod.SrDocumentContent.ContentSequence = contentList.ToArray();
                iod.KeyObjectDocument.CurrentRequestedProcedureEvidenceSequence = currentRequestedProcedureEvidenceList.ToArray();
            }

            // set meta for the files
            foreach (DicomFile keyObjectDocument in keyObjectDocuments)
            {
                keyObjectDocument.MediaStorageSopClassUid    = keyObjectDocument.DataSet[DicomTags.SopClassUid].ToString();
                keyObjectDocument.MediaStorageSopInstanceUid = keyObjectDocument.DataSet[DicomTags.SopInstanceUid].ToString();
            }

            return(keyObjectDocuments);
        }
        public IImageProperty[] GetProperties(IPresentationImage image)
        {
            List <IImageProperty> properties = new List <IImageProperty>();

            if (image != null && image.ParentDisplaySet != null)
            {
                IImageViewer viewer = image.ImageViewer;
                if (viewer != null)
                {
                    IDicomDisplaySetDescriptor descriptor = image.ParentDisplaySet.Descriptor as IDicomDisplaySetDescriptor;
                    if (descriptor != null && descriptor.SourceSeries != null)
                    {
                        string uid = descriptor.SourceSeries.SeriesInstanceUid;
                        if (!String.IsNullOrEmpty(uid))
                        {
                            StudyTree studyTree       = viewer.StudyTree;
                            Series    keyObjectSeries = studyTree.GetSeries(uid);
                            if (keyObjectSeries != null && keyObjectSeries.Sops.Count > 0)
                            {
                                Sop keyObjectSop = keyObjectSeries.Sops[0];
                                if (keyObjectSop.SopClassUid == SopClass.KeyObjectSelectionDocumentStorageUid)
                                {
                                    KeyObjectSelectionDocumentIod iod       = new KeyObjectSelectionDocumentIod(keyObjectSop);
                                    SrDocumentContentModuleIod    content   = iod.SrDocumentContent;
                                    GeneralEquipmentModuleIod     equipment = iod.GeneralEquipment;

                                    if (content != null)
                                    {
                                        string            codeValue       = "";
                                        CodeSequenceMacro conceptSequence = content.ConceptNameCodeSequence;
                                        if (conceptSequence != null)
                                        {
                                            KeyObjectSelectionDocumentTitle documentTitle = KeyObjectSelectionDocumentTitleContextGroup.LookupTitle(conceptSequence);
                                            if (documentTitle != null)
                                            {
                                                codeValue = documentTitle.ToString();
                                            }
                                        }

                                        string             documentDescription = "";
                                        IContentSequence[] contentSequences    = content.ContentSequence ?? new IContentSequence[0];
                                        for (int i = contentSequences.Length - 1; i >= 0; --i)
                                        {
                                            IContentSequence  contentSequence = contentSequences[i];
                                            CodeSequenceMacro sequenceMacro   = contentSequence.ConceptNameCodeSequence;
                                            if (sequenceMacro != null && sequenceMacro.CodeValue == KeyObjectSelectionCodeSequences.KeyObjectDescription.CodeValue)
                                            {
                                                documentDescription = contentSequence.TextValue;
                                                break;
                                            }
                                        }

                                        properties.Add(
                                            new ImageProperty("KeyImageDocumentTitle",
                                                              SR.CategoryKeyImageSeries,
                                                              SR.NameKeyImageDocumentTitle,
                                                              SR.DescriptionKeyImageDocumentTitle,
                                                              codeValue));

                                        properties.Add(
                                            new ImageProperty("KeyImageDocumentDescription",
                                                              SR.CategoryKeyImageSeries,
                                                              SR.NameKeyImageDocumentDescription,
                                                              SR.DescriptionKeyImageDocumentDescription,
                                                              documentDescription));

                                        properties.Add(
                                            new ImageProperty("KeyImageEquipmentManufacturer",
                                                              SR.CategoryKeyImageEquipment,
                                                              SR.NameManufacturer,
                                                              SR.DescriptionManufacturer,
                                                              equipment.Manufacturer ?? ""));
                                        properties.Add(
                                            new ImageProperty("KeyImageEquipmentManufacturersModelName",
                                                              SR.CategoryKeyImageEquipment,
                                                              SR.NameManufacturersModelName,
                                                              SR.DescriptionManufacturersModelName,
                                                              equipment.ManufacturersModelName ?? ""));
                                        properties.Add(
                                            new ImageProperty("KeyImageEquipmentSoftwareVersions",
                                                              SR.CategoryKeyImageEquipment,
                                                              SR.NameSoftwareVersions,
                                                              SR.DescriptionSoftwareVersions,
                                                              equipment.SoftwareVersions ?? ""));
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(properties.ToArray());
        }
        public KeyObjectDescriptionContentItem(string description, KeyObjectSelectionDocumentIod source)
        {
            _source = source;

            Description = description;
        }
        public PersonObserverContextContentItem(string personObserverName, KeyObjectSelectionDocumentIod source)
        {
            _source = source;

            PersonObserverName = personObserverName;
        }