/*! \page mod_dcmsr dcmsr: a structured reporting library and utility apps This module contains classes to read, write, create, modify, access, print and render DICOM Structured Reporting (SR) documents. The list of supported SOP classes is provided in DSRTypes::E_DocumentType. The main interface classes are: \li \b DSRDocument \li \b DSRDocumentTree \li \b DSRDocumentSubTree \li \b DSRDocumentTreeNode \li \b DSRContentItem \li \b DSRCodedEntryValue Here are some further classes that are useful when implementing SR templates: \li \b DSRBasicCodedEntry \li \b DSRContextGroup \li \b DSRRootTemplate \li \b DSRSubTemplate Currently, the following SR templates are implemented (see notes for details): \li \b TID300_Measurement \li \b TID1001_ObservationContext \li \b TID1204_LanguageOfContentItemAndDescendants \li \b TID1411_VolumetricROIMeasurements \li \b TID1419_ROIMeasurements_Measurement \li \b TID1500_MeasurementReport \li \b TID1501_MeasurementGroup \li \b TID1600_ImageLibrary \li \b TID4019_AlgorithmIdentification \section Tools This module contains the following command line tools: \li \ref dsr2html \li \ref dsr2xml \li \ref dsrdump \li \ref xml2dsr \section Examples The following example shows how to load a DICOM Structured Report and render its content in HTML format: \code DcmFileFormat fileformat; OFCondition status = fileformat.loadFile("test.dcm"); if (status.good()) { DSRDocument document; status = document.read(*fileformat.getDataset()); if (status.good()) { status = document.renderHTML(cout); if (status.bad()) cerr << "Error: cannot render SR document (" << status.text() << ")" << endl; } else cerr << "Error: cannot read SR document (" << status.text() << ")" << endl; } else cerr << "Error: cannot load DICOM file (" << status.text() << ")" << endl; \endcode The following example shows how to create a DICOM Structured Report and save it to a file (further details can be found in the \ref src_mkreport "mkreport" source file): \code DSRDocument document; document.setPatientName("Doe^John"); /* ... */ DSRDocumentTree &tree = document.getTree(); tree.addContentItem(DSRTypes::RT_isRoot, DSRTypes::VT_Container); tree.getCurrentContentItem().setConceptName(DSRCodedEntryValue(/* some code */)); tree.addChildContentItem(DSRTypes::RT_hasObsContext, DSRTypes::VT_Code, CODE_DCM_ObserverType); tree.getCurrentContentItem().setCodeValue(CODE_DCM_Person); /* ... */ DcmFileFormat fileformat; OFCondition status = document.write(*fileformat.getDataset()) if (status.good()) { status = fileformat.saveFile("test.dcm", EXS_LittleEndianExplicit); if (status.bad()) cerr << "Error: cannot save DICOM file (" << status.text() << ")" << endl; } else cerr << "Error: cannot write SR document (" << status.text() << ")" << endl; \endcode Alternatively, many properties of the document tree can be accessed and modified directly as the following example shows: \code DSRDocument document(DSRTypes::DT_KeyObjectSelectionDocument); /* ... */ DSRDocumentTree &tree = document.getTree(); tree.addContentItem(DSRTypes::RT_isRoot, DSRTypes::VT_Container); DSRCodedEntryValue *codePtr = tree.getCurrentContentItem().getConceptNamePtr(); if (codePtr != NULL) codePtr->setCode("113000", "DCM", "Of Interest"); /* ... */ tree.addContentItem(DSRTypes::RT_contains, DSRTypes::VT_Image); DSRImageReferenceValue *imagePtr = tree.getCurrentContentItem().getImageReferencePtr(); if (imagePtr != NULL) { imagePtr->setValue(DSRImageReferenceValue(UID_UltrasoundMultiframeImageStorage, /* image UID */)); imagePtr->setPresentationState(DSRCompositeReferenceValue(UID_GrayscaleSoftcopyPresentationStateStorage, /* GSPS UID */)); imagePtr->getFrameList().addItem(2); imagePtr->getFrameList().addItem(5); } /* ... */ \endcode In addition, there are specific DSRDocumentTree::addContentItem() and DSRDocumentTree::addChildContentItem() methods that expect a pointer to a newly created DSRDocumentTreeNode instance. Iterating over a document tree and searching for content items that meet certain criteria can be achieved in various ways. Here are two of them: \code DSRDocument document; /* ... */ DSRDocumentTree &tree = document.getTree(); /* #1: search for content items with a certain concept name */ if (tree.gotoNamedNode(CODE_DCM_ProcedureReported)) { do { const DSRDocumentTreeNode *node = tree.getNode(); /* and check for expected value type */ if ((node != NULL) && (node->getValueType() == DSRTypes::VT_Code)) { /* do something useful with the CODE content item */ } } while (tree.gotoNextNamedNode(CODE_DCM_ProcedureReported, OFFalse /*searchIntoSub*/)); } /* #2: search for content items using a more complex filter */ DSRDocumentTreeNodeAndFilter filter; filter.addFilter(new DSRDocumentTreeNodeValueTypeFilter(DSRTypes::VT_Code)); filter.addFilter(new DSRDocumentTreeNodeRelationshipTypeFilter(DSRTypes::RT_hasConceptMod)); filter.addFilter(new DSRDocumentTreeNodeHasChildrenFilter()); if (tree.gotoMatchingNode(filter)) { /* found first "has concept mod CODE" content item that has children */ } \endcode The final example shows how to deal with SR templates, e.g. when creating a DICOM Structured Report that is based on TID 1500 (Measurement Report): \code TID1500_MeasurementReport report(CMR_CID7021::ImagingMeasurementReport); report.setLanguage(CID5000_Languages::English); report.getObservationContext().addPersonObserver("Doe^Jane", "Some Organization"); /* ... */ CMR_TID1411_in_TID1500 &volumetric = report.getVolumetricROIMeasurements(); volumetric.setActivitySession("1"); volumetric.setTrackingIdentifier("aorta reference region"); /* ... */ CMR_TID1419_in_TID1411_in_TID1500 &measurement = volumetric.getMeasurement(); measurement.createNewMeasurement(CMR_CID7469::Volume, CMR_TID1419_in_TID1411_in_TID1500::MeasurementValue("15", CMR_CID7181::CubicMillimeter)); measurement.setDerivation(CMR_CID7464::StandardDeviation); /* ... */ DSRDocument document; document.setPatientName("Last Name^First Name"); /* ... */ if (document.setTreeFromRootTemplate(report).good()) document.print(cout, DSRTypes::PF_printTemplateIdentification); else cerr << "Error: cannot set template content as document tree" << endl; \endcode */ /*! \page src_mkreport mkreport source code \include mkreport.cc */