DCF Developers Guide
DCF Developers Guide
(DCF)
®
DICOM is the registered trademark of the National Electrical Manufacturers Association for its standards publications relating to digital
communications of medical information.
Page ii
Document History
This table is used to record activities related to the modification of this document.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page iii
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page iv
Table of Contents
1. Overview ............................................................................................................................................................................1
1.1. System Architecture Overview ...............................................................................................................................1
1.2. An Example DCF Application ................................................................................................................................1
1.3. Components.............................................................................................................................................................4
1.3.1. Component Classification...................................................................................................................................4
1.3.1.1. DCF Component Categories .....................................................................................................................4
1.3.1.2. DCF Component Physical Types ..............................................................................................................5
1.3.2. Selected DCF Components Organized by Category...........................................................................................6
1.3.2.1. DICOM Applications..................................................................................................................................6
1.3.2.2. Non DICOM Applications ..........................................................................................................................6
1.3.2.3. Examples...................................................................................................................................................7
1.3.2.4. Common Service Interface Libs................................................................................................................9
1.3.2.5. Common Service Implementation Libs ..................................................................................................10
1.3.2.6. Application Support Libs ........................................................................................................................10
1.3.2.7. IDL Interface Libs...................................................................................................................................11
1.4. Platforms ...............................................................................................................................................................12
1.5. Systems .................................................................................................................................................................13
2. Installing the DCF ............................................................................................................................................................15
2.1. Multi-user vs. Single-user Installation ..................................................................................................................15
2.2. DCF Shared Files ..................................................................................................................................................15
2.3. DCF Per-user Files ................................................................................................................................................16
2.4. The DCF Remote Service Interface ......................................................................................................................19
2.4.1. Running the Apache Web Server .....................................................................................................................19
2.4.1.1. Alternate Web Servers ............................................................................................................................19
2.4.2. Connecting to the web server ...........................................................................................................................20
2.4.3. The DCF Remote Service Interface..................................................................................................................20
2.4.3.1. Start with … (Choose a configuration) ...................................................................................................21
2.4.3.2. Shutdown DCF Processes .......................................................................................................................21
2.4.3.3. Clear Log Files........................................................................................................................................21
2.4.3.4. View Log Files........................................................................................................................................21
2.4.3.5. View DCF Real-Time Log......................................................................................................................22
2.4.3.6. View/Edit Configuration Files ................................................................................................................23
2.4.3.7. View DCF Online Documentation..........................................................................................................24
2.4.3.8. Set Debug Flags ......................................................................................................................................25
2.4.3.9. Configure [DCF system config name] ....................................................................................................25
2.4.3.10. Edit Global Filter Sets.............................................................................................................................26
2.4.4. The DCF Command-line Operation .................................................................................................................27
2.5. Using Multiple Versions of the DCF.....................................................................................................................28
3. DICOM Programming Overview .......................................................................................................................................29
3.1. Core DCF DICOM classes ......................................................................................................................................29
3.1.1. Element related.................................................................................................................................................29
3.1.2. Association Manager ........................................................................................................................................29
3.2. Verification Service Class .....................................................................................................................................30
3.2.1. Verification Client (SCU).................................................................................................................................30
3.2.2. Verification Server (SCP).................................................................................................................................30
3.3. Storage-related Service Classes.............................................................................................................................30
3.3.1. Store Client (SCU) ...........................................................................................................................................30
3.3.2. Store Server (SCP) ...........................................................................................................................................30
3.3.3. Storage Commitment Server (SCP)..................................................................................................................31
3.3.4. Storage Commitment Client (SCU)..................................................................................................................31
3.3.5. Storage Commitment Client Agent ..................................................................................................................31
3.4. Query/Retrieve (Q/R) Service Class .....................................................................................................................32
3.4.1. Q/R Client (SCU) .............................................................................................................................................32
3.4.2. Q/R Server (SCP) .............................................................................................................................................32
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page v
3.5. Modality Worklist Service Class...........................................................................................................................33
3.5.1. MWL SCU .......................................................................................................................................................33
3.5.2. MWL Server (SCP) ..........................................................................................................................................33
3.6. Modality Performed Procedure Step Service Class...............................................................................................33
3.6.1. MPPS Client (SCU)..........................................................................................................................................33
3.6.2. MPPS Server (SCP)..........................................................................................................................................33
3.7. Print Service Class ................................................................................................................................................34
3.7.1. Print Client (SCU) ............................................................................................................................................34
3.7.2. Print Server (SCP) – (C++ only) ......................................................................................................................34
3.8. DICOM File (Media Storage) Services ...................................................................................................................34
3.8.1. DICOM File Set Reader (FSR role) ...................................................................................................................34
3.8.2. DICOM File Set Creator and Updater (FSC and FSU roles)..............................................................................34
4. C++ Programming Examples ...........................................................................................................................................35
4.1. Running Example Servers .....................................................................................................................................35
4.2. DICOM Programming Examples..........................................................................................................................35
4.2.1. Reading a DICOM file and extracting an element from the header ...................................................................35
4.2.2. Creating a DICOM file that contains image data and patient demographics......................................................37
4.2.3. Using the C++ StoreClient ...............................................................................................................................38
4.2.4. Using the C++ PrintClient ................................................................................................................................38
4.2.5. Media Storage Application Profiles – DICOMDIR files..................................................................................40
4.2.5.1. Example – Creating a DICOMDIR.........................................................................................................40
4.2.5.2. Example – Adding to a DICOMDIR ......................................................................................................41
4.2.5.3. Example – Reading a DICOMDIR .........................................................................................................42
4.3. Deploying a Simple Standalone DCF C++ Application........................................................................................42
4.4. Common Services Programming Examples ..........................................................................................................44
4.4.1. C++ "hello world" Example Application Using the DCF ................................................................................44
4.4.2. Using the LOG interface – Logging from C++ programs ................................................................................48
4.4.3. Using the CDS interface ...................................................................................................................................48
4.4.4. Using the APC interface ...................................................................................................................................49
4.5. Advanced DICOM Programming Examples.........................................................................................................49
4.5.1. Writing a customized storage SCP ...................................................................................................................49
4.5.2. Writing a customized query retrieve SCP ........................................................................................................52
4.6. DICOM compression transfer syntax support for C++ .........................................................................................55
5. Java Programming Examples ...........................................................................................................................................57
5.1. Running Example Servers .....................................................................................................................................57
5.2. Using the DCF with Java IDE tools ......................................................................................................................57
5.2.1. Using the DCF with Eclipse for Java ...............................................................................................................57
5.3. DICOM Programming Examples..........................................................................................................................58
5.3.1. Using Java Print Element Value Program ........................................................................................................58
5.3.1.1. Example – ex_jprint_element_value.......................................................................................................59
5.3.2. Using Java modify DICOM image data program ...............................................................................................60
5.3.2.1. Example – ex_jModPixelData ................................................................................................................60
5.3.3. Using Java DICOM Verification (Echo) Client Classes.....................................................................................62
5.3.3.1. Example – ex_jecho_scu.........................................................................................................................63
5.3.4. Using Java Modality Worklist Query SCU Classes .........................................................................................64
5.3.4.1. Example – ex_jmwl_client......................................................................................................................64
5.3.5. Using Java Print Client Classes ........................................................................................................................68
5.3.5.1. Example – ex_jprint_client .....................................................................................................................69
5.3.6. Using Java Store Client Classes .......................................................................................................................71
5.3.6.1. Example – ex_jstore_client.....................................................................................................................71
5.3.7. Using Java Q/R Client Classes .........................................................................................................................73
5.3.7.1. Example – ex_jqr_scu.............................................................................................................................73
5.4. Deploying a Simple Standalone DCF Java Application........................................................................................75
5.5. Common Services Programming Examples ..........................................................................................................77
5.5.1. Java "Hello World" Example Using DCF Common Services ..........................................................................77
5.5.2. Using the LOG interface – Logging from Java programs ................................................................................82
5.5.3. Using the CDS interface ...................................................................................................................................82
5.5.4. Using the APC interface ...................................................................................................................................82
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page vi
5.6. Advanced DICOM Programming Examples.........................................................................................................83
5.6.1. Using StorageCommitmentSCU.......................................................................................................................83
5.6.1.1. Example – Send store commit requests, and receive StoreCommitClientListener notifications ............83
5.6.2. Using Java MWLClient Classes .......................................................................................................................84
5.6.2.1. Example – ex_jmwl_scu .........................................................................................................................85
5.6.3. Using Java MPPSClient Classes.......................................................................................................................85
5.6.3.1. Example – ex_jmpps_scu........................................................................................................................85
5.6.4. Using Java Store, Q/R, and MWL Server-Related Classes ..............................................................................86
5.6.4.1. Example – ex_jstore_scp ........................................................................................................................86
5.6.4.2. Example – ex_jqr_scp.............................................................................................................................90
5.6.4.3. Example – ex_jmwl_scp .........................................................................................................................91
5.6.4.4. Using the MWL Server as an MPPS Server ...........................................................................................91
5.6.4.5. Example – Server Objects.......................................................................................................................91
5.6.4.6. Example – StoreSCP: Implementing a custom storeObject method .......................................................91
5.6.4.7. Additional coding examples: ..................................................................................................................93
5.7. DICOM Compression Transfer Syntax Support for Java ......................................................................................93
5.7.1. Example – ex_jdcf_filter: Uncompressed to Compressed................................................................................94
5.7.2. Example – ex_jdcf_filter: Compressed to Uncompressed................................................................................94
5.8. JAI – DCF integration for Java .............................................................................................................................94
5.8.1. Example – ex_jdcf_dcm2jai: Convert a DICOM file to a JAI type....................................................................94
5.8.2. Example – ex_jdcf_jai2dcm: Convert JAI types to a DICOM file .....................................................................95
5.8.3. Example – ex_jdcf_dcmview: View a DICOM Image file.................................................................................96
5.8.4. Example – Writing a JPEG Image with Java....................................................................................................96
6. C# Programming Examples..............................................................................................................................................98
6.1. Running Example Servers .....................................................................................................................................98
6.2. Using the DCF with MS Visual Studio .NET 2003/2005 for C# ..........................................................................99
6.2.1. Opening an Existing C# Example Project ........................................................................................................99
6.2.2. Quick Start - Using create_cs_app.pl to generate VS project files and source code...........................100
6.2.3. Using dcfmake.pl to generate a .csproj file ........................................................................................100
6.2.4. Manually Creating C# Projects from MS Visual Studio 2003/2005 IDE.......................................................100
6.3. DICOM Programming Examples........................................................................................................................102
6.3.1. DICOM File Access .........................................................................................................................................102
6.3.1.1. Example – Open a DICOM file ..............................................................................................................102
6.3.1.2. Example – Create a DICOM file.............................................................................................................102
6.3.1.3. Example – Create a DICOM file from Config Group Data ....................................................................103
6.3.1.4. Example – Open, Modify, and Save a DICOM file ................................................................................103
6.3.2. Using VerificationClient ................................................................................................................................105
6.3.2.1. Example – Connect to a Verification SCP ............................................................................................105
6.3.3. Using PrintClient ............................................................................................................................................106
6.3.3.1. Example – Create and submit a print job, handling status events .........................................................107
6.3.3.2. Example – Create and submit a print job where ImageBox data comes from DICOM disk files...........108
6.3.4. Using StoreClient ...........................................................................................................................................109
6.3.4.1. Example – Create and submit a store job from files on disk................................................................109
6.3.4.2. Example – Create and submit a store job – Handling Events ...............................................................109
6.3.5. Using Query/Retrieve classes.........................................................................................................................110
6.3.5.1. Example – Using Query/Retrieve .........................................................................................................112
6.3.6. Creating and Populating DICOM Sequences ...................................................................................................112
6.3.6.1. Example – Explicitly creating DICOM Sequence elements ...................................................................112
6.3.6.2. Example – Setting DICOM Sequence elements using a config group....................................................113
6.4. Deploying a Simple C# Standalone Application.................................................................................................114
6.4.1. Deploying a Simple C# Standalone DCF Application ...................................................................................114
6.4.2. Deploying a Simple C# Standalone OEM Application ..................................................................................116
6.5. Common Services Programming Examples ........................................................................................................118
6.5.1. C# “hello world” Example Application Using the DCF.................................................................................118
6.5.2. Using the LOG interface – Logging from C# programs.................................................................................122
6.5.3. Avoiding or Embracing use of the Common Services....................................................................................123
6.5.4. Using the CDS interface .................................................................................................................................125
6.5.5. Using the APC interface .................................................................................................................................125
6.6. Advanced DICOM Programming Examples.......................................................................................................125
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page vii
6.6.1. Using StorageCommitmentSCU.....................................................................................................................125
6.6.1.1. Example – Send store commit requests and receive StoreCommitClientListener notifications ...........125
6.6.2. Using MWLClient ..........................................................................................................................................126
6.6.2.1. Example – Send Worklist Query and wait for all responses before continuing....................................126
6.6.2.2. Example – Send Worklist Query and handle responses as they arrive .................................................127
6.6.3. Using MPPSClient..........................................................................................................................................127
6.6.3.1. Example – MPPSClient Console Application.......................................................................................127
6.6.3.2. Example – Send DIMSE N-CREATE or N-SET messages to a MPPS Server.....................................127
6.6.4. C# Store, Q/R, and MWL Server-Related Examples .....................................................................................128
6.6.4.1. Using the MWL Server as an MPPS Server .........................................................................................129
6.6.4.2. Example – Implementing a custom storeObject() method ....................................................................129
6.6.4.3. Example – How DicomDataService (DDS) gets called:.......................................................................131
6.6.4.4. Example – Adding OEM specific data to DicomSessionSettings:........................................................132
6.6.4.5. Example – Receiving or Logging Retired SOP classes: .......................................................................132
6.7. DICOM compression transfer syntax support for C# ..........................................................................................133
7. Using DCF System Manager to control processes .........................................................................................................134
7.1. Installing and Starting the System Manager........................................................................................................134
7.1.1. Installing and starting as a service on Windows.............................................................................................134
7.1.2. Installing and starting as a normal server process on Windows .....................................................................134
7.1.3. Installing and starting on Unix .......................................................................................................................135
7.2. System Manager Related Interfaces ....................................................................................................................135
7.3. System Manager Configuration...........................................................................................................................136
7.3.1. System Manager Application Configuration ..................................................................................................136
7.3.2. System Manager System Configuration .........................................................................................................136
7.4. System startup for a DCF server application.......................................................................................................140
7.5. System shutdown for a DCF server application ..................................................................................................140
8. The DCF Development Environment.............................................................................................................................141
8.1. Using the dcfmake.pl utility ................................................................................................................................141
8.1.1. Command line options for dcfmake.pl ...........................................................................................................141
8.1.2. The cinfo.cfg file ............................................................................................................................................142
8.1.3. Generated files for various component types .................................................................................................145
8.2. Example: Creating a DCF library component .....................................................................................................148
8.3. Example: Creating a DCF application component ..............................................................................................149
8.4. Using iodgen to create DICOM dataset wrappers to represent an IOD.................................................................150
9. Configuring DCF Applications ......................................................................................................................................153
9.1. Configuration Files and the CDS interface .........................................................................................................153
9.1.1. Using cds_client to access data in the configuration database........................................................................154
9.1.2. Receiving notifications of updated data .........................................................................................................154
9.2. Application and Process Configurations .............................................................................................................155
9.2.1. Application Configuration Settings ................................................................................................................155
9.2.1.1. Structure of an application or process configuration.............................................................................156
9.3. Process Configuration Settings ...........................................................................................................................156
9.3.1. Process configuration with AppControl setup ................................................................................................156
9.3.1.1. Monitoring the Process Configuration ..................................................................................................157
9.3.2. Process configuration without AppControl setup...........................................................................................157
9.3.3. Creating a custom application configuration ..................................................................................................157
9.4. Log/Debug tracing control using “debug_flags” ..........................................................................................159
9.5. C#-related Configuration Notes ..........................................................................................................................160
9.5.1. Description of DCF setup code ......................................................................................................................160
9.5.2. Common services setup description: ..............................................................................................................160
10. Configuring DICOM features ....................................................................................................................................161
10.1. Java and C# DICOM configuration.....................................................................................................................161
10.1.1. Example Session settings ...............................................................................................................................161
10.2. C++ DICOM configuration.................................................................................................................................164
10.3. Customizing DicomDataDictionary ....................................................................................................................166
11. I/O Statistics for Java and C# .....................................................................................................................................167
12. Deploying a DCF-based application ..........................................................................................................................168
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page viii
12.1. Deployment Guidelines.......................................................................................................................................168
12.2. License Key for a Deployed Application ............................................................................................................168
12.2.1. OEM applications that ship with an installed license .....................................................................................168
12.2.2. OEM applications that do not ship with an installed license ..........................................................................168
12.3. Limiting the DCF libraries required for Deployment..........................................................................................169
12.3.1. Find Application Dependencies - Windows ...................................................................................................171
12.3.2. Find Application Dependencies - Linux.........................................................................................................171
12.3.3. Find Application Dependencies - Java ...........................................................................................................172
12.4. Deploying standalone applications containing DCF code...................................................................................173
12.4.1. Language Specific Standalone Installation.....................................................................................................173
12.4.2. An Example Application Installer ..................................................................................................................173
Appendix A: Glossary of Terms.............................................................................................................................................176
Appendix B: Bibliography .....................................................................................................................................................181
1. The DICOM Standard ....................................................................................................................................................181
2. Integrating the Healthcare Enterprise (IHE)...................................................................................................................181
Appendix C: DCF Tech Note: Storing Images from Print SCP .............................................................................................182
1. Collecting image and association info from Print_SCP .................................................................................................182
1.1. Preparation and Configuration Steps...................................................................................................................182
1.2. Example Batch Script..........................................................................................................................................183
1.3. Viewing Print SCP output via a web browser .....................................................................................................183
Appendix D: DCF Tech Note: Using DCF DICOM Filters .....................................................................................................185
1. Fixing or working-around protocol problems.................................................................................................................185
1.1. An application is sending an incorrect field in a DICOM print request ................................................................185
1.2. Modifying the DIMSE messages sent by a Java application...............................................................................188
2. Using DicomTestFilter to support automated testing .....................................................................................................189
3. Logging/Debugging Dicom Filter Effects ......................................................................................................................190
4. Using DCF Dicom Filters Overview ..............................................................................................................................190
5. DCF Dicom Filter Configuration Overview...................................................................................................................191
5.1. Sample configuration for the DicomElementFilter class.....................................................................................193
5.2. Other Filter Types ...............................................................................................................................................193
5.3. Filter Configuration Files ....................................................................................................................................193
5.3.1. Specifying a Sequence in a Configuration File ..............................................................................................197
5.3.2. Using Macros to Specify Data........................................................................................................................198
5.4. Example Filters ...................................................................................................................................................199
Example 1: Replacing a Value .......................................................................................................................................199
Example 2: Removing an Element .................................................................................................................................199
Example 3: Modifying an Element’s Value with Regular Expressions..........................................................................200
6. Developing Custom Filters.............................................................................................................................................200
6.1. Custom Filters in Java .........................................................................................................................................201
6.2. Custom Filters in C# ...........................................................................................................................................202
Appendix E: DCF Tech Note: DCF MakeUID Function .......................................................................................................203
1. Description of the DCF makeUID function....................................................................................................................203
2. The function getUIDPrefix() returns the uid_prefix.......................................................................................................203
3. The function getUIDSuffix() returns a new UID suffix each time it is called..............................................................204
Appendix F: DCF Tech Note: Using Nunit tests with DCF .NET Applications ....................................................................205
1. Example NUnit test class................................................................................................................................................205
2. Some Background on NUnit: .........................................................................................................................................206
Appendix G: DCF Tech Note: Using Perl with the DCF .......................................................................................................207
Appendix H: Customizing the DCF Remote Service Interface ..............................................................................................208
1. Shortcuts for Setting Debug Flags..................................................................................................................................208
1.1. Debug Shortcuts ..................................................................................................................................................209
1.2. Viewing the current settings................................................................................................................................210
2. Example Debug Shortcut File ........................................................................................................................................210
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page ix
3. CDS Configuration Shortcuts.........................................................................................................................................212
3.1. Shortcut Attributes ..............................................................................................................................................212
3.1.1. Types of shortcuts...........................................................................................................................................213
3.1.1.1. title ........................................................................................................................................................213
3.1.1.2. html .......................................................................................................................................................213
3.1.1.3. display_only..........................................................................................................................................213
3.1.1.4. integer or string .....................................................................................................................................214
3.1.1.5. boolean..................................................................................................................................................214
3.1.2. Optional attributes: .........................................................................................................................................214
3.1.3. Synchronizing attributes:................................................................................................................................215
3.2. Automatic Shortcut Generation...........................................................................................................................216
3.3. Example shortcut configuration file: ...................................................................................................................217
4. Authenticating Access to DCF Web Pages ....................................................................................................................219
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page x
Table of Figures
Conventions
Italics
is used for emphasis.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 1
1. Overview
The DICOM Connectivity Framework – or DCF – is a software product that enables a medical imaging
system – printer, scanner, modality, archive device, workstation, etc. – to communicate with other
devices over a network, using the DICOM version 3 protocol. By using the DCF, an OEM can provide
DICOM connectivity for their device with a minimum of effort. The DCF provides much more than
DICOM libraries – Common Services Components allow an OEM to produce commercial-quality
applications without having to reinvent such facilities as logging, configuration data management, and
process control. The DCF development environment allows developers to focus on adding value to their
products and getting to market quickly.
The DICOM Connectivity Framework supports modular programming and mixed language development
environments. In most large-scale software development efforts, there are multiple languages or
technologies involved, possibly multiple target platforms, and multiple developers working on different
subsystems. Managing these processes and technologies is at best time-consuming and tedious – at
worst it can be a nightmare. The DCF provides technology to simplify these complex software
development tasks.
The DCF can be used in two distinct ways. First, where local conventions, file system layout, build
processes, and such are well established, DCF applications and libraries can be used like any other
software tool product: point your makefiles and/or IDE settings and various environment variables to
the DCF library, include, and binary directories, and go. The second approach uses the DCF to help
organize the structure of applications and automate much of the process. The DCF will generate
makefiles, Windows Visual Studio project files, debug/trace instrumentation for your code,
configuration files, and API documentation. The DCF encourages the re-use of both software AND the
processes used to create and manage that software. The DCF performs all of these tasks using Laurel
Bridge Software proprietary technologies, along with best-of-breed commercial or open source
software products.
The DCF can be used to create DICOM solutions in the Microsoft .NET environment, using C# or other
.NET programming languages.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 2
Application dcf_store_scp
DCFUtil
DSS (DCF Utilities)
DCS
Application Support (DIcom Store
(Dicom Core Services)
Libraries Services) DCF
(DCF common
facilities)
Common Services
LOG CDS APC DDS
Interface Libraries
Common Services
LOG_a CDS_a APC_a DDS_a
AdapterLibraries
DBMS
Platform (Operating
System / H/W)
Networking Devices
Mass Storage
The diagram shows the division of DCF libraries into layers. The top layer “application” contains the
“dcf_store_scp” application component. This is the entry point for the application. During initialization,
dcf_store_scp installs the selected Common Services Adapters, and then uses objects in the DCS and
DSS libraries to perform the real work of implementing the Storage SCP.
The libraries in the “application support” layer perform the real DICOM work. The DCS library provides
the basic classes for DICOM attributes or elements, data sets, PDUs, DIMSE messages, as well as higher
level classes such as AssociationManager, DicomAssociation, for easily managing multiple
concurrent associations, DicomDataDictionary, numerous classes for network and file I/O and Data
set/Image filtering.
The DSS library provides the StoreSCP class which registers as the handler for all Storage
presentation contexts. C-Store-Request messages are dispatched to StoreSCP.
The “common services interface” layer provides abstract interfaces for services such as logging,
application configuration, process control, and data storage/retrieval. StoreSCP invokes the
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 3
storeObject() method on the DDS (DICOM Data Service) interface to locally store the dataset
contained in the C-Store-Request message.
The “common services adapter” layer provides concrete implementations of common services. The
LOG adapter (LOG_a) library writes log messages to either the file system or the LOG Server, via the
DLOG (Distributed LOG) CORBA interface. The Configuration Data Service adapter (CDS_a)
accesses configuration data from either the file system or the DCDS_Server, using the DCDS
(Distributed CDS) CORBA interface. The DICOM Data Service adapter might store image or SOP
instance data to the file system, and may store header data in an SQL database system. An OEM that
wishes to customize the behavior of the store_scp for example to use a locally defined schema needs
only implement one function: “storeObject()”. The developer can opt to hide all handling of
concurrent network associations, DIMSE messages, and other complex DICOM details. See the section
“writing a customized Storage SCP” (Section 4.3) for an example of extending the
DicomDataService implementation.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 4
1.3. Components
The DCF is designed as a collection of components. Components in the DCF are rather large-grained,
along the lines of “package” in the UML terminology, or “subsystem” in certain other models. This is
as opposed to some systems where “component” is synonymous with “class” or “object” which would
lead to a more fine-grained component architecture.
A DCF Component that is used directly by Microsoft.NET clients is delivered as a binary “Assembly”,
along with associated configuration data.
Type Description
DICOM Applications Executable programs which function as a DICOM SCU or
SCP, plus various other DICOM utilities
Applications DCF support applications and other executable programs
Common Services Interface Libraries Interfaces to horizontal services
Common Services Adapter Libraries Implementations of horizontal services
Application Support Libraries Interfaces and implementations of vertical services
IDL Interface Libraries CORBA interfaces (Java and C++ only)
Miscellaneous Scripts and other items
Examples Library or Application components used to demonstrate use
of the DCF
Tests Components used to test other DCF components
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 5
1.3.1.2. DCF Component Physical Types
Type Description
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 6
1.3.2. Selected DCF Components Organized by Category
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 7
dcf_sysmgr cpp_ipc_app DCF System Manager
NDCDS_Server cs_app C# Configuration DataBase Server
CfgEdit java_app Configuration program for java CDS/CDS_a components
DCDS_Server java_app Distributed Config Data Service - Java server for CDS data
storage/retrieval
DLOG_Server java_app Java server implementation of DLOG interface, for centralized logging
facilities
FilterEditor java_app Editor for filters used by the DCF
FilterSetEditor java_app Editor for filter sets used by the DCF
Log_viewer java_app Java viewer of DLOG_Server output
PrinterServer java_app Java Printer Server application
Std_applets java_app Standard configuration information for all applets to use
1.3.2.3. Examples
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 8
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 9
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 10
1.3.2.5. Common Service Implementation Libs
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 11
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 12
1.4. Platforms
The DCF defines a platform as the computer hardware, operating system, and any third-party tools or
programs that have been added to that system.
The currently supported platforms for the DCF and a brief description of each are shown in the
following table.
DCF code is designed for portability. Contact Laurel Bridge Software for information regarding
additional platform support.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 13
1.5. Systems
In practice, it is the OEM or system integrator who decides what a system is. For the purposes of DCF
development, we define a system as a specific platform running a specific set of application
components with their associated configuration data.
Giving a name to this particular combination of hardware, off-the-shelf software, DCF, and OEM
software provides a structure, which can be useful for defining tests. This structure helps during the
debugging, testing, and potentially field support phases, providing a more concise way of answering
common questions like: “What did the computer that xyz happened on look like?” or “What else was
running at the time that abc application failed?” or “Did we ever try the combination of applications x
and y with operating system z?”
The following table lists examples of systems that are defined for internal DCF testing at Laurel Bridge:
Name Description
all_servers_unix All DICOM servers running on Unix platform
all_servers_win32 All DICOM servers running on Win32 platform
dcds_server_unix Simple DCDS Server only configuration running on Unix platform
dcds_server_win32 Simple DCDS Server only configuration running on Win32 platform.
dcf_switch_unix Dicom Switch configuration with echo and store SCP's running on Unix platform
dcf_switch_win32 Dicom Switch configuration with echo and store SCP's running on Win32
platform
jmwl_server_unix Java Modality Worklist server configuration running on Unix platform
jmwl_server_win32 Java Modality Worklist server configuration running on Win32 platform
jqr_server_unix Java QR server configuration running on Unix platform
jqr_server_win32 Java QR server configuration running on Win32 platform
jstorecommit_scu_agent_unix Java Storage Commitment SCU Agent configuration running on UNIX platform
jstorecommit_scu_agent_win32 Java Storage Commitment SCU Agent configuration running on Win32 platform
jstorecommit_server_unix Java Storage Commitment Server configuration running on Unix platform
jstorecommit_server_win32 Java Storage Commitment server configuration running on Win32 platform
jstore_server_unix Java Store server configuration running on Unix platform
jstore_server_win32 Java Store server configuration running on Win32 platform
mwl_server_unix Modality Worklist server configuration running on Unix platform
mwl_server_win32 Modality Worklist server configuration running on Win32 platform
ndcds_server_win32 Simple DCDS Server only configuration running on Win32 platform.
nmwl_server_win32 C# Modality Worklist server configuration running on Win32 platform
nqr_server_win32 C# QR server configuration running on Win32 platform
nstorecommit_scu_agent_win32 C# Storage Commitment SCU Agent configuration running on Win32 platform
nstorecommit_server_win32 C# Storage Commitment Server with C# Storage Commitment SCU agent
configuration running on Win32 platform
nstore_server_win32 C# Store server configuration running on Win32 platform
only_jmwl_server_unix Java Modality Worklist server only configuration running on Unix platform
only_jmwl_server_win32 Java Modality Worklist server-only configuration running on Win32 platform
only_jqr_server_unix Java QR server only configuration running on Unix platform
only_jqr_server_win32 Java QR server-only configuration running on Win32 platform
only_jstore_server_unix Java Store server only configuration running on Unix platform
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 14
Name Description
only_jstore_server_win32 Java Store server-only configuration running on Win32 platform
only_nstore_server_win32 C# Store server only configuration running on Win32 platform
print_server_unix Print server configuration running on Unix platform
print_server_win32 Print server configuration running on Win32 platform
qr_server_unix Query Retrieve server configuration running on Unix platform
qr_server_win32 Query Retrieve server configuration running on Win32 platform
store_server_unix Store server configuration running on Unix platform
store_server_win32 Store server configuration running on Win32 platform
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 15
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 16
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 17
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 18
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 19
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 20
2.4.2. Connecting to the web server
Point the web browser of your choice to the address for the per-user web server. For example:
http://yourhostname:2004 (where 2004 is replaced with the appropriate port)
or
http://yourhostname:8080 (typical for Windows installations)
If your Apache port is 2004, you should see the DCF Remote Service Interface. (Note: the typical
Apache port for Windows installations is 8080.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 21
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 22
If a process is running, it may be adding to its log file while you are viewing it. If you think there may
be more text available, click the refresh- or reload-page button on your browser.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 23
2.4.3.6. View/Edit Configuration Files
View or edit objects in the CDS (Configuration Data Services) repository. The CDS is the facility in
DCF for managing configuration data. CDS configuration data is stored in the file system under the
directory: $DCF_USER_ROOT/cfg (a.k.a. $DCF_CFG). This interface allows you access to all the
configuration files used by the DCF and its components. Use of this interface is recommended
primarily for advanced users who are familiar with the DCF and its components, as there are many files
and each file has many configuration attributes in it. (For information on presenting a simplified view
of the configuration attributes, see Appendix H: Customizing the DCF Remote Service Interface.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 24
2.4.3.7. View DCF Online Documentation
This link leads to the online documentation page.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 25
2.4.3.8. Set Debug Flags
This allows debugging or verbosity settings to be adjusted for applications. Debug flags are a special
type of configuration data that are defined for each application, they are typically used to control
logging verbosity, but may also be used to enable special operating modes.
Two selections are under the set debug flags link: Set application debug flags and Set
process debug flags. The first will save configuration data under the /apps CDS hierarchy. Any
program can be adjusted here and the settings will take effect the next time that program is run. The
second option allows you to make changes to the /procs CDS hierarchy. Only programs that are
currently running can be adjusted here. Changes will take effect immediately; the process does not need
to be restarted. This can prove valuable when it is desirable to adjust the logging verbosity of a server,
but the server cannot be shutdown or restarted at the time.
Either of the two “Set Debug Flags” selections prints a list of applications or processes (an application
that is running). Selecting an application or process will take you to a page which prints the list of
library components contained by that application. Selecting one of the components will take you to a
page that lists the available debug settings for that component. Debug settings for components can be
adjusted independently. This can prove valuable when it is desirable to have verbose output from one
component but not from the others. (See Appendix H: Customizing the DCF Remote Service Interface
for information on presenting a simpler interface for modifying the debug flags.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 26
(See Appendix H: Customizing the DCF Remote Service Interface for information on this option and
creating your own customized configuration screen.)
A DicomElementFilter is used to modify DICOM elements in a DIMSE message. For example, you
can specify that a certain tag is always changed to another value or that the data element with a
particular tag is removed from the message. Many ways to use the DicomElementFilter are
provided and not all are detailed here.
The DicomElementFilter has five versions. The “Copy Filter” version allows you to copy elements
in a DIMSE message. The “Remove Filter” will remove elements from a message, while the
“Add/Replace Filter” will add or replace elements in a message, and the “Modify Filter” allows you to
modify the data in a DIMSE message via regular expressions. The fifth version, “Element Filter (full)”,
allows you to do all of these things. As the fifth is the most general, its basic functionality is described
here, with the understanding that these descriptions apply to the other options, each of which has a
subset of these capabilities.
The “Element Filter (full)” has six tables each displaying a list of elements. These elements are checked
against the elements in a message and applied accordingly to the rule for the section where they are
listed. (As you enter data into the filter's fields, please note that the rules are applied top-to-bottom.
That is, the results of the first filter's actions are passed to the next filter, e.g., the results of the elements
that are copied will then be processed through the list of elements that are to be removed, etc.)
Elements may be:
• matched
• copied
• removed
• removed if null
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 27
To stop the running servers, you would type in a dcfstop command at a DCF Command Prompt:
perl –S dcfstop.pl
This sort of common activity is often done more easily through the web service interface, which is one
reason that option is provided.
Note that similar commands may be used under Windows or UNIX OSes; syntax changes slightly for
path and environment variable specification.
For more information about starting and stopping systems see Chapter 7 (Using DCF System Manager
to control processes).
(Appendix D: Section 1.2 shows an example of starting a configuration of DCF servers from the
command line to run a Java app from the command line.)
(Appendix G: has helpful information about invoking the Perl interpreter.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 28
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 29
For additional information, see also Chapter 8 – The DCF Development Environment.
Refer to The DICOM Standard, Chapter4 for DICOM service class specifications:
A Service Class Specification defines a group of one or more SOP Classes related to a
specific function which is to be accomplished by communicating Application Entities. A
Service Class Specification also defines rules which allow implementations to state some
pre-defined level of conformance to one or more SOP Classes. Applications may conform
to SOP Classes as either a Service Class User (SCU) or Service Class Provider (SCP).
Note: Such interaction between peer Application Entities work on a 'client/server model.'
The SCU acts as the 'client,' while the SCP acts as the 'server'. The SCU/SCP roles are
determined during Association establishment.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 30
Objects that implement the AssociationListener interface can be registered with an
AssociationManager. Each time an association or DICOM connection starts or ends, each registered
listener is notified. At association startup, for example, an AssociationListener object might create
an SCP object of some type. This object may register as a PresentationContextAcceptor with the
AssociationAcceptor that is handling the connection. If negotiation succeeds, messages for a given
DICOM presentation context are dispatched to the appropriate SCP objects. In this way, complex
servers can be created that can handle multiple service classes on a particular connection.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 31
without needing to be involved with the details involved with handling concurrent DICOM
associations.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 32
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 33
matching data sets, or references to matching instances in mass storage. QRSCP takes that
information and forms the appropriate DIMSE response messages, and/or StoreClient requests.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 34
3.8.2. DICOM File Set Creator and Updater (FSC and FSU roles)
The DicomDirectoryRecord and DicomDir classes along with DicomFileOutput provide
write and update functionality for DICOM File Sets, as defined in Part 10 of the standard. This
amounts to creating and updating a DICOMDIR file.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 35
Running the DCF tools and/or servers via the DCF Remote Service Interface generally makes running
these examples easier. Taking this approach allows easy access to convenient tools for starting and
stopping DCF server processes, viewing log files, and controlling trace/debug settings.
Start the Apache web server and open the DCF Remote Service Interface. In a Windows environment
this is all handled for you by the startup script:
Select “Start” Æ “All Programs” Æ “DICOM Connectivity Framework” Æ
“DCF Service Interface”
This command runs an Apache web server in its own window and invokes the default browser client to
display the DCF home page, called the “DCF Remote Service Interface”.
Alternately, if you prefer a manual approach, type “run_apache.pl” from a DCF command window,
and then use your favorite web browser to browse to “localhost:8080”, which will display the DCF
home page.
4.2.1. Reading a DICOM file and extracting an element from the header
The following complete application demonstrates loading a DICOM encoded file, and extracting a value
for a particular element or attribute.
#include <iostream>
#include <DCS/DicomFileInput.h>
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 36
//
// print a single dicom element from a file
//
int main( int argc, char** argv )
{
try
{
if (argc != 3)
{
cerr <<
<< "use: print_element_value <dicom_filename> <element_tag as hhhh,hhhh>"
<< endl;
return 1;
}
LBS::DCS::DicomFileInput dfi( *++argv );
LBS::DCS::DicomDataSet ds;
dfi.readDataSetNoPixels(ds);
cout
<< ds.findElement( LBS::DCS::AttributeTag(*++argv) ).getValueAsString()
<< endl;
}
catch ( LBS::DCF::DCFException &e )
{
cerr << e << endl;
}
return 0;
}
This application can be built on any supported platform using the dcfmake.pl utility. You can use any
standard C++ build tools, as long as you direct them to the required include and library files. For
example, using GNU make on Linux build this application with the following makefile:
CCFLAGS=-g -Wall -DLINUX -I$(DCF_ROOT)/include -I/opt/omniORB-4.0.7/include \
-D__OMNIORB4__ -D_REENTRANT -D__linux__ -D__OSVERSION__=2 -D__x86__
all: print_element_value
print_element_value: print_element_value.o
gcc $(LDFLAGS) -o print_element_value print_element_value.o
print_element_value.o: print_element_value.cpp
gcc $(CCFLAGS) -c print_element_value.cpp
Note: This example intentionally does not configure the DCF common services – i.e., there are no calls
to LOG/CDS/APC adapter setup methods or to “Framework::initDefaultServices()”. This is to
demonstrate that a very simple application can be created with no reliance on the larger DCF
infrastructure.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 37
4.2.2. Creating a DICOM file that contains image data and patient demographics
One of the first things a DICOM developer often needs to do is to create an image file. DICOM defines
IODs – Information Object Descriptions – to represent images from different modalities. DICOM also
defines the encoding rules for communicating those IODs. An Image IOD can be written to the file
system for later use. Many systems store images to local mass storage as they are acquired from the
image generation source. Later these images are sent to DICOM printers or archive devices.
The following code fragment shows how DCF objects are used to create an image and store it to the
DicomDataService.
1 //
2 // create an image object
3 //
4 DCS::DicomObject image_object( UID_SOPCLASSXRAYANGIO, DCS::DCMUID::makeUID() );
5 dicom_data_set& image_ds = image_object.getDataSet();
40 //
41 // display the image info in a log message
42 //
43 LOG_INFO_MSG << "Image created by combo_example:\n"
44 << image_object << endl;
45 //
46 // save to local storage
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 38
47 //
48 DicomPersistentObjectDescriptor image_dpod;
The reference implementation of the DicomDataService adapter saves the data set as a DICOM format
file. An alternate implementation can be provided which stores the data using some other format or
mechanism. You could also use the DicomFileOutput class directly.
This code was taken from the C++ combo_example, which shows a combination of basic DICOM tasks
being performed by a demonstration program. The full source for the program can be found in
$DCF_ROOT/devel/csrc/examples/ex_combo.
//
// initialize the StoreJobDescription
//
DSS::StoreJobDescrption job;
job.serverAddress( “archive:3004:StoreSCP” );
job.clientAddress( “StoreSCU” );
DicomPersistentObjectDescriptor dpod("","", “/tmp/test.dcm”, UID_TRANSFERLITTLEENDIAN);
DSS::StoreObjectInfo soi( dpod );
job.addObject( soi );
//
// create the StoreClient object, and submit the job!
//
DSS::StoreClient client;
DSS::StoreJobStatus status;
client.submitStoreJob( job, status );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 39
job.serverAddress( print_server_address );
job.clientAddress( "DEMO");
job.requestPrintJobSOPClass( true );
job.pollPrintJob(true);
job.printJobPollRateSeconds(2);
job.jobTimeoutSeconds( 30 );
film_session.numberOfCopies("1");
film_session.printPriority("HIGH");
film_session.mediumType("BLUE FILM");
film_session.filmDestination("MAGAZINE");
film_session.filmSessionLabel("test");
film_session.memoryAllocation("0");
film_session.ownerId("DCF");
film_box.imageDisplayFormat( "STANDARD\\1,1" );
film_box.filmOrientation("PORTRAIT");
film_box.filmSizeId("14INX17IN");
film_box.magnificationType("NONE");
film_box.smoothingType("NONE");
film_box.borderDensity("0");
film_box.emptyImageDensity("0");
film_box.minDensity(0);
film_box.maxDensity(280);
film_box.trim("YES");
film_box.configurationInformation("NONE");
film_box.illumination(0);
film_box.reflectedAmbientLight(0);
film_box.requestedResolutionId("HIGH");
PrintJobImageBox image_box;
image_box.imagePosition(1);
image_box.polarity("NORMAL");
image_box.magnificationType("NONE");
image_box.smoothingType("NONE");
image_box.configurationInformation("NONE");
image_box.requestedImageSize("0");
image_box.reqdDecimatecropBehavior("DECIMATE");
image_box.imageDPOD( image_dpod );
film_box.addImageBox( image_box );
film_session.addFilmBox( film_box );
job.filmSession( film_session );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 40
//
// create the PrintClient object, and submit the job!
//
DPS::PrintClient client;
DPS::PrintJobStatus print_job_status("1"); // id of this job is 1
This code was taken from the C++ ex_combo, which shows a combination of basic DICOM tasks being
performed by a demonstration program. The full source for the program can be found in
$DCF_ROOT/devel/csrc/examples/ex_combo.
DicomDir dicom_dir;
dicom_dir.fileSetId("EXAMPLE1");
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 41
series_dir.seriesNumber("2");
dicom_dir.save("/tmp/cdrom-image/DICOMDIR");
The getXXDirRecord() methods search for matching records and create new ones if a match is not
found. Elements are copied from the image data set into the various record types according to
configuration settings.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 42
4.2.5.3. Example – Reading a DICOMDIR
Read a DICOMDIR from a file, and traverse the contents.
Note: this produces similar output to the code “cout << dir;” but the method of descending into the
directory record objects is illustrated here.
DicomDir dir("/cdrom/DICOMDIR");
DicomDirectoryRecord& root = dir.getRootDirectory();
DicomDirectoryRecordPtrList& root_records = root.getDirEntries();
DicomDirectoryRecordPtrList::iterator itr = root_records.begin();
string indent;
while ( itr != root_records.end() )
{
DicomDirectoryRecord* p_dirrec = *itr++;
displayDirRecord( *p_dirrec, indent );
}
See the online class documentation for DSS::DicomDir for additional information about DICOM
media storage.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 43
Select “Start” Æ “All Programs” Æ “DICOM Connectivity Framework” Æ
“DCF Command Prompt”
2. Create the test install directory:
Note: You could paste this text into a batch file and run it to automate this process.
REM ###
REM ### create install dir
REM ###
mkdir DCF_test_cpp_install
cd DCF_test_cpp_install
REM ###
REM ### copy required library files from %DCF_LIB% (../DCF/lib)
REM ###
REM ### Note: DCF_COM is not needed for VisualStudio6.x toolkits.
copy %DCF_LIB%\DCF_COM.dll
copy %DCF_LIB%\DCF_DCFCore.dll
copy %DCF_LIB%\DCF_DCF_cl.dll
copy %DCF_LIB%\DCF_ljpeg12.dll
copy %DCF_LIB%\DCF_ljpeg16.dll
copy %DCF_LIB%\DCF_ljpeg8.dll
copy %DCF_LIB%\DCF_APC_a.dll
copy %DCF_LIB%\DCF_CDS_a.dll
copy %DCF_LIB%\DCF_LOG_a.dll
copy %DCF_LIB%\DCF_boost_regex.dll
copy %DCF_LIB%\DCF_DAPC.dll
copy %DCF_LIB%\DCF_DCDS.dll
copy %DCF_LIB%\DCF_DLOG.dll
copy %DCF_LIB%\DCF_DCS.dll
copy %DCF_LIB%\DCF_DCFUtil.dll
copy %DCF_LIB%\DCF_J2KWrappers.dll
REM ### If you are building from a DCF VisualStudio7.x .NET toolkit:
copy %DCF_BIN%\msvcp71.dll
copy %DCF_BIN%\msvcr71.dll
REM ### If you are building from a DCF VisualStudio8.x .NET toolkit:
copy %DCF_BIN%\msvcp80.dll
copy %DCF_BIN%\msvcr80.dll
copy %DCF_BIN%\omniORB407_rt.dll
copy %DCF_BIN%\omniDynamic407_rt.dll
copy %DCF_BIN%\omnithread32_rt.dll
REM ###
REM ### Copy the application that you want - for example,
REM ### include both the C++ dcf_filter example, and the dcf_dump
REM ### utilities.
REM ###
copy %DCF_BIN%\dcf_dump.exe
copy %DCF_BIN%\dcf_filter.exe
REM ###
REM ### Create a minimal configuration directory.
REM ###
mkdir cfg
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 44
mkdir cfg\apps
mkdir cfg\apps\defaults
mkdir cfg\procs
REM ###
REM ### Copy the license configuration file, and the application configs
REM ### for the installed programs.
REM ###
copy %DCF_CFG%\systeminfo cfg\systeminfo
copy %DCF_CFG%\apps\defaults\dcf_filter cfg\apps\defaults
copy %DCF_CFG%\apps\defaults\dcf_dump cfg\apps\defaults
3. Create the media by which you will deliver the install directory
4. On the target machine do the following:
a) Unpack, copy or otherwise make the DCF app install directory available. For example, copy
or unzip to C:\temp\DCF
b) From a command window, go to the install directory. For example, use C:\temp\DCF.
cd C:\temp\DCF
c) Register the DCF_COM dll (you could put this in a setup.bat file; this is not required for
VisualStudio6.x)
regsvr32 DCF_COM.dll
d) Set environment vars and run your apps (you could put these steps in a run_app.bat file).
set DCF_CFG=C:\temp\DCF\cfg
set DCF_LIB=C:\temp\DCF
set DCF_TMP=C:\temp\DCF
### display input image (choose a dicom file in the line below)
dcf_dump \temp\test.dcm
Note that currently, all DCF standard C++ dll’s are prefixed with “DCF_”.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 45
1. Create a directory for the new application component – in the DCF, every application or library is a
component, and has its own source directory.
mkdir $DCF_USER_ROOT/devel/csrc/examples/ex_hello_world
2. Create a component information file in that directory. This file must be called “cinfo.cfg”. For
this example it contains the following:
#==============================================================================
# static information common to all instances of the ex_hello_world component
#==============================================================================
[ component_info ]
name = ex_hello_world
type = cpp_app
category = examples
docfile = ex_hello_world.cpp
description = Example program that uses DCF common services to implement the classic
first application
[ build_info ]
gen_app_cfg = yes
bin_dir = .
[ debug_controls ]
debug_flag = df_TEST1, 0x10000, place holder for test 1 debug setting
debug_flag = df_TEST2, 0x20000, Do something cool
[ required_components ]
component = cpp_lib_pkg/DCFCore
component = cpp_lib/DCFUtil
component = cpp_lib/LOG_a
component = cpp_lib/APC_a
component = cpp_lib/CDS_a
component = idl_lib/DCDS
#==============================================================================
# per-instance information for the ex_hello_world component
#==============================================================================
[ ex_hello_world ]
debug_flags = 0x00000
#==============================================================================
# The following sections allow the customization of the generated default
# application configuration.
# After the application configuration is created,
# selected library component configuration settings can be overridden.
# Note that this affects the settings for that library only within the context
# of this application.
#==============================================================================
[ lib_cfg_overrides ]
[ lib_cfg_overrides/LOG_a ]
use_log_server = FALSE
The file is in the DCF configuration file format, which provides for attributes, groups, and nested
groups.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 46
Note: The easiest way to create the cinfo.cfg file for your application or library is to copy one from
a similar component, then edit as needed.
Explanation:
The first group [ component_info ] describes basic attributes of the component. The name
“ex_hello_world” is simply the file name.The component type is “cpp_app” which indicates a
C++ application.
Note: you can use dcfmake.pl to create applications in any directory, as long as you create a
cinfo.cfg file in that directory.
The group [ debug_controls ] is where the developer can add support for conditional logging
or other behavior specific to this component. Debug controls that are defined here can be accessed
via the web interface.
The [ required_components ] group specifies the components needed by this application.
The [ex_hello_world ] group contains the instance configuration for the component. This data
is used directly in the example code.
3. Create the application source code
For this example, the file is called “ex_hello_world.cpp”.
#include <iostream>
#include <DCF/Framework.h>
#include "ex_hello_worldCInfoL.h"
using namespace LBS::ex_hello_world;
using namespace LBS;
using namespace LBS::DCF;
using namespace std;
try
{
DCF::Framework::initDefaultServices( argc, argv );
status = APC::AppControl::instance()->exitStatus();
}
catch (DCF::DCFException& e)
{
LOG_ERROR_MSG(-1) << e << endl;
status = -1;
}
if (status == 0)
{
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 47
cerr << "Test succeeded. See the generated log file for more information" << endl;
}
else
{
cerr << "Test failed. See the generated log file for more information" << endl;
}
return(status);
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 48
copied various macros are expanded, so, for example, the files in the working config can have the
correct port numbers, path names, etc.
The application is now ready to run!
First, the LOG adapter must be initialized. Normally, all of the common services are installed at once,
during application initialization. This can be done with either the lines:
LBS::LOG_a::LogClient_a::setup( argc, argv);
LBS::CDS_a::CFGDB_a::setup( argc, argv );
LBS::APC_a::AppControl_a::setup( argc, argv );
LBS::LOG_a::LogClient_a::setup( argc, argv );
or
LBS::DCF::Framework::initDefaultServices( argc, argv );
All of the LOG macros establish a message header, and then evaluate to a C++ standard ostream
(output stream) object reference, so the interface is similar to using the familiar cout or cerr streams.
For example:
LOG_INFO_MSG << “this message will always be printed” << endl;
The endl is significant. When the ostream is flushed (using the standard endl or flush
manipulator), a message boundary is established, and all text between the beginning of the message and
the flush is logged with a single message header. This is preferable to having either a continuous stream
of output text, or adding a header to each line of text.
To print debug messages, use:
LOG_DEBUG_MSG( df_SOME_DEBUG_SETTING ) << “the value of x is: “ << x
<< “ the value of y in hex is: “ << hex << y << endl;
The previous message will only be logged if the df_SOME_DEBUG_SETTING bit is set in the debug flags for
the component that contains the code. Note the use of the standard ostream insertion (<<) operators,
and the various manipulators (hex, endl).
Error messages are logged with:
LOG_ERROR_MSG(-1) << “an exception was caught: “ << exception << endl;
In that example, “exception” is some object that provides an ostream print method, i.e.,
friend ostream& operator<<( ostream&, SomeExceptionClass& );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 49
4.4.4. Using the APC interface
See language-specific documentation for APC.AppControl and APC_a.AppControl_a.
//
// Setup adapters.
//
AppControl_a::setupORB( argc, argv );
CFGDB_a::setup( argc, argv );
AppControl_a::setup( argc, argv );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 50
LOG_a::LOGClient_a::setup( argc, argv );
DPS::OEMPrinterInfo_a::setup( argc, argv );
DDS_a::DicomDataService_a::setup( argc, argv );
//
// run Event loop returns in multi-threaded mode. The CORBA
// services are enabled, and running in their own threads.
//
AppControl::instance()->runEventLoop( false );
//
// create an Association Manager
//
AssociationManager amgr;
//
// create a StoreServer object. It will register with the
// AssociationManager and receive notifications when an
// association is being started.
//
StoreServer store_server( amgr );
//
// start the Association Manager. It will wait for incoming
// connections.
//
amgr.run();
status = 0;
}
catch (IOTimeoutException& e )
{
LOG_FATAL_ERROR_MSG(-1) << (DCFException&)e << endl; // cast stops solaris CC error
status = 1;
}
catch (IOException& e )
{
LOG_FATAL_ERROR_MSG(-1) << (DCFException&)e << endl;
status = 2;
}
catch (DCFException& e )
{
LOG_FATAL_ERROR_MSG(-1) << e << endl;
status = 3;
}
catch (std::exception& e )
{
LOG_FATAL_ERROR_MSG(-1) << "dcf_store_scp: caught unexpected c++ exception:\n" <<
e.what() << endl;
return( 4 );
}
catch (...)
{
LOG_FATAL_ERROR_MSG(-1) << "dcf_store_scp: caught unknown exception:\n" << endl;
return( 5 );
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 51
p_appctrl->shutdown( status );
status = p_appctrl->exitStatus(); // may not be what we just gave it
}
LOG_INFO_MSG << "dcf_print_scp exiting with status:" << status << endl;
return status;
}
try
{
LBS::DCS::DicomObject obj( c_store_rq.data() );
string sop_instance_uid =
f_make_new_uids_ ? DCMUID::makeUID() : obj.sopinstanceUid();
dpod_ret.sopinstanceUid( sop_instance_uid );
dpod_ret.persistentId( persistent_id );
dpod_ret.persistentInfo( ts_uid_ );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 52
/**
* Find objects that match the given query criterion, and return the location
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 53
* in storage for those objects. This method is normally called by a Query Retrieve
* SCP when it receives a C-Move-Request or C-Get-Request. The QRSCP will handle the
* Store sub-operations when it gets back the list of matching instances.
* @param association the current DICOM association. This contains information about the
* client AE, negotiated contexts, etc.
* @param transfer_request the c-move or c-get request dimse message which contains the
* query criterion. This object
* contains both the command dataset, and the "data" dataset, which contains the
* query identifier.
* @param results reference to list which will be filled in with the matching objects.
* Only the information on how to load the object from storage is returned.
* @throw DDSException if an error occurs
*/
void DicomDataService_a::findObjectsForTransfer(
const LBS::DCS::DicomAssociation& association,
const LBS::DCS::DimseMessage& transfer_request,
DicomPersistentObjectDescriptor::List& results )
throw ( DDSException )
{
omni_mutex_lock lock( mutex_ );
findObjects( association, transfer_request, &results, (DicomQueryListener*)0 );
}
void DicomDataService_a::findObjects(
const LBS::DCS::DicomAssociation& association,
const LBS::DCS::DimseMessage& c_find_request,
DicomQueryListener* p_listener )
throw ( DDSException )
{
omni_mutex_lock lock( mutex_ );
findObjects( association, c_find_request, (DicomPersistentObjectDescriptor::List*)0,
p_listener );
}
. . .
void DicomDataService_a::findObjects(
const LBS::DCS::DicomAssociation& association,
const LBS::DCS::DimseMessage& query,
DicomPersistentObjectDescriptor::List* p_result_dpods,
DicomQueryListener* p_listener )
throw ( DDSException )
{
DicomObject* p_test_object = 0;
try
{
LOG_DEBUG_MSG( df_SHOW_GENERAL_FLOW ) << "findObjects: query =\n" << query <<
endl;
if ( DCF_DEBUG( df_FORCE_ERROR_ON_FIND_OBJECTS ) )
{
throw DDSException("simulating error condition during findObjects");
}
//
// prepare the query identifier by making a writable copy of it, and then
// removing the query-retrieve-level element
//
DicomDataSet query_dataset( query.data() );
query_dataset.removeElement( E_QUERYRETRIEVE_LEVEL );
//
// search for matches in the list of stored objects.
// This is a simple linear search using the compare() method
// in DicomDataSet/Element/Sequence. Only the header portion
// (everything up to 7FE0,0010) of each stored object is loaded
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 54
// prior to comparing.
//
updateInstanceDPODList();
DicomPersistentObjectDescriptor::List::const_iterator itr =
instance_dpod_list_.begin();
while ( itr != instance_dpod_list_.end() )
{
const DicomPersistentObjectDescriptor& dpod = *itr++;
if ( p_test_object->getDataSet().compare( query_dataset ) )
{
LOG_DEBUG_MSG( df_SHOW_GENERAL_FLOW )
<< "DicomDataService_a::findObjects: adding DPOD for DicomObject to
result set:\n:"
<< *p_test_object
<< "\n" << dpod << endl;
if (p_result_dpods)
{
p_result_dpods->push_back( dpod );
delete p_test_object;
}
if (p_listener)
{
p_listener->returnQueryResult( *p_test_object );
delete p_test_object; // make sure listener has his own copy of this!
}
p_test_object = 0;
}
}
if (p_listener)
{
p_listener->queryComplete( 0 );
}
}
catch (LBS::DCF::DCFException& e)
{
delete p_test_object;
if (p_listener)
{
try
{
p_listener->queryComplete( 2 );
}
catch (...)
{
LOG_ERROR_MSG(-1) << "DicomQueryListener threw unexpected exception" <<
endl;
}
}
if ( p_result_dpods )
{
p_result_dpods->clear();
}
ostringstream os;
os << "DicomDataService_a::findObjects failed:\n" << e;
throw DDSException(os.str());
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 55
The method findObjects() extracts the supported query attributes from the C-Find-Request message
and creates a query. The attributes supported are defined in a CFGGroup for each level. This example
forms the query as a DicomDataSet.
A local database is searched at the appropriate level, using the query created above. The
DicomDataSet::compare() method is used to compare the query data set with data sets created
from stored data at the selected level.
Note: this is not intended to show an efficient search algorithm!
Each matching data set is returned in the DicomObjectPtrList, which is simply an STL list of
pointers to allocated objects of type DicomObject.
To create an SQL query from the C-Find-Request, you might do something like:
QRIdentifier qi( c_find_rq.data() );
string query = “SELECT * from PATIENT where “;
query += “patientId like \”“
query += qi.patientId();
query += “\””;
// pull columns from known offsets in the result, and create elements
dds.insert( DicomElement( E_PATIENTS_NAME, db_result[0] ) );
dds.insert( DicomElement( E_PATIENT_ID, db_result[1] ) );
dds.insert( DicomElement( E_PATIENTS_BIRTH_DATE, db_result[2] ) );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 56
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 57
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 58
cd $DCF_USER_ROOT/devel/jsrc/com/lbs/examples/ex_jprint_element_value
# if you want to rebuild the application (you must have the appropriate
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 59
# version of Visual Studio (6, 7, or 8) installed, and in the path.
# (you can run the script vsvars.bat (7.x or 8.x) or vcvars.bat (6.x)
# from the visual studio directory, or perhaps run in the command window
# shortcut provided with studio 7 or 8). **** Note for Java, this is only because
# dcfmake.pl uses the Visual Studio simply to process the “makefile”.
#
dcfmake.pl
#
# alternately, you can run the javac compiler on the source code directly.
# make sure that %DCF_ROOT%\classes is in the CLASSPATH.
This application shows how easy it is to load DICOM format files, and extract elements from them. The
“jrun_example.pl” script calls the Java interpreter with the common DCF options (most of the Java
examples use this launcher script; you may also create individual wrapper scripts for each example –
see “ex_jdcf_HelloWorld” for an example). The first argument is the class name of the Java
example to be run; specifically, it is the name of the class that defines the main() method. The second
argument is the name of some DICOM file. The third argument is the DICOM tag for which value data is
to be extracted – in this example the file is test.dcm and the attribute to be extracted is “Patients
Name”:
jrun_example.pl
com.lbs.examples.ex_jprint_element_value.ex_jprint_element_value
%DCF_ROOT%\test\images\test.dcm 0010,0010
import com.lbs.DCS.*;
import com.lbs.LOG_a.*;
import com.lbs.APC_a.*;
import com.lbs.DCF.*;
import com.lbs.DCFUtil.*;
//
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 60
// setup DCF Logger and start DDCSServer I/O subsystem.
// logger will write to stdout in this configuration.
//
LOGClient_a.setup( args );
if (AppControl.isInitialized())
{
AppControl.instance().shutdown(0);
}
System.exit( 0 );
}
}
This application shows how to extract image header fields and modify the image pixel data. The DCF
provides an image processing framework that allows standard and custom filter objects to be chained
together. This example shows a simplified alternative for users who just want to gain access to the pixel
data to change it, or perhaps to display it.
package com.lbs.examples.ex_jModPixelData;
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 61
import com.lbs.DCF.*;
import com.lbs.LOG_a.*;
import com.lbs.APC_a.*;
import com.lbs.DCS.*;
// Get some of the basic image header fields. Use the DicomDataSet
// convenience methods to get integer values for these.
int rows = dds.getElementIntValue( DCM.E_ROWS );
int cols = dds.getElementIntValue( DCM.E_COLUMNS );
int bits_allocated = dds.getElementIntValue( DCM.E_BITS_ALLOCATED );
int bits_stored = dds.getElementIntValue( DCM.E_BITS_STORED );
int high_bit = dds.getElementIntValue( DCM.E_HIGH_BIT );
int pixel_count = rows * cols;
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 62
// Give the object a new UID.
// There are other attributes that should also be set to
// indicate that this is a "derived image".
// That is beyond the scope of this example.
dds.insert( DicomElementFactory.create(
DCM.E_SOPINSTANCE_UID, DicomDataDictionary.makeUID() ) );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 63
cd $DCF_USER_ROOT/devel/jsrc/com/lbs/examples/ex_jecho_scu
dcfmake.pl
jrun_example.pl com.lbs.examples.ex_jecho_scu.ex_jecho_scu MWLSCP1
localhost 2000
import com.lbs.LOG.*;
import com.lbs.APC.*;
import com.lbs.CDS.*;
import com.lbs.DCF.*;
import com.lbs.DCS.*;
import com.lbs.LOG_a.*;
import com.lbs.APC_a.*;
if ( args.length != 3 )
{
throw new DCFException( usage_ );
}
try
{
VerificationClient client = new VerificationClient(
"ECHO_SCU",
args[0],
args[1] + ":" + args[2]
);
client.requestAssociation();
client.cEcho(10);
client.releaseAssociation();
}
catch ( DCFException e)
{
LOG.error( -1, "DCFException caught:\n", e );
System.err.println("test failed - see log files for output");
}
}
catch (Exception e )
{
LOG.error( -1, "Exception caught:\n", e );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 64
System.err.println("test failed - see log files for output");
}
if (AppControl.isInitialized())
{
AppControl.instance().shutdown(0);
}
System.Exit(0);
}
}
package com.lbs.examples.ex_jmwl_client;
import java.util.Vector;
import com.lbs.DCF.*;
import com.lbs.APC.*;
import com.lbs.DCS.*;
import com.lbs.DIS.*;
/**
*/
public class ex_jmwl_client extends AssociationRequester
{
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 65
public ex_jmwl_client( String calling_ae, String called_ae, String called_addr )
throws DCSException
{
f_connected_ = false;
ainfo_.addRequestedPresentationContext( rq_ctx );
if (ctx.id() == 1)
{
f_connected_ = true;
}
}
if (!f_connected_)
{
releaseAssociation();
throw new DCSException("Association was accepted, but the required presentation
context was not");
}
msg.commandField( DimseMessage.C_FIND_RQ );
msg.affectedSopclassUid( UID.SOPMODALITYWORKLIST_FIND );
msg.dataSetType(0x0100);
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 66
msg.context_id(1);
msg.priority( 1 );
msg.data( query );
LOG.debug( CINFO.df_SHOW_GENERAL_FLOW,
"sending C-Find Request:\n" + msg );
sendDimseMessage( msg, 30 );
return 0;
return rsp;
}
try
{
//
// Uncomment if you want the standard common services setup -
// i.e.,
//==================================================================
// CDS_a.CFGDB adapter uses DCDS_Server,
//
// APC_a.AppControl adapter loads app config from
// /apps/defaults/examples/ex_jmwl_client,
// saves proc config to /procs/ex_jmwl_client.<pid>.
// DDCSServer jni Dicom IO library uses this proc configuration.
//
// LOG_a.LOGClient adapter uses file and DLOG_Server outputs, per
// app config settings.
//
//==================================================================
// Leave commented for minimal common services setup -
//==================================================================
// CFGDB adapter reads from files in $DCF_CFG as needed
//
// AppControl does not maintain an application or proc config. (DDCSServer
// jni Dicom IO library loads config info as needed from
// /apps/defaults/dcf_java_default)
//
// LOGClient writes to console
//
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 67
//------------------------------------
// Framework.initDefaultServices( CINFO );
//------------------------------------
if ( args.length != 3 )
{
throw new DCFException( usage_ );
}
// create SCU
ex_jmwl_client client = new ex_jmwl_client("MWL_SCU",
args[0],
args[1] + ":" + args[2]
);
// connect
client.requestAssociation();
query.patientsName("");
query.patientId("");
query.studyInstanceUid("");
query.scheduledProcStepSeq( sps );
if ( ( response.status() == DimseStatus.DIMSE_SUCCESS )
|| ( response.status() == DimseStatus.DIMSE_FAILURE ) )
{
break;
}
}
// hang up
client.releaseAssociation();
status = 0;
}
catch ( Exception e )
{
LOG.error(-1, "error", e );
status = 1;
}
if (AppControl.isInitialized())
{
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 68
AppControl.instance().shutdown(status);
}
System.exit(status);
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 69
5.3.5.1. Example – ex_jprint_client
The application initializes the DCF core framework – CDS, APC, etc – and then the
DicomDataService adapter, which is used by the DicomInstanceInfo class to load objects. It sets
up the print job – specifying items like the address of the DICOM printer, and configures the job with a
film box inside a film session and a print job object – and submits it. A PrintJobStatus object
reports the final status of the print operation.
The source code for the example is shown below:
//=========================================================================
// Copyright (C) 2005, Laurel Bridge Software, Inc.
// 160 East Main St.
// Newark, Delaware 19711 USA
// All Rights Reserved
//=========================================================================
package com.lbs.examples.ex_jprint_client;
import com.lbs.APC.*;
import com.lbs.LOG_a.*;
import com.lbs.CDS_a.*;
import com.lbs.APC_a.*;
import com.lbs.DDS.*;
import com.lbs.DDS_a.*;
import com.lbs.DCF.*;
import com.lbs.DCS.*;
import com.lbs.DPS.*;
// Print server
String print_server_address = args[ 1 ];
job.serverAddress( print_server_address );
job.clientAddress( "DEMO" );
job.requestPrintJobSOPClass( true );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 70
job.pollPrintJob( true );
job.printJobPollRateSeconds( 2 );
job.jobTimeoutSeconds( 30 );
film_session.numberOfCopies( "1" );
film_session.printPriority( "HIGH" );
film_session.mediumType( "BLUE FILM" );
film_session.filmDestination( "MAGAZINE" );
film_session.filmSessionLabel( "test" );
film_session.memoryAllocation( "0" );
film_session.ownerId( "DCF" );
film_box.imageDisplayFormat( "STANDARD\\1,1" );
film_box.filmOrientation( "PORTRAIT" );
film_box.filmSizeId( "14INX17IN" );
film_box.magnificationType( "NONE" );
film_box.smoothingType( "NONE" );
film_box.borderDensity( "0" );
film_box.emptyImageDensity( "0" );
film_box.minDensity( 0 );
film_box.maxDensity( 280 );
film_box.trim( "YES" );
film_box.configurationInformation( "NONE" );
film_box.illumination( 0 );
film_box.reflectedAmbientLight( 0 );
film_box.requestedResolutionId( "HIGH" );
image_box.imagePosition( 1 );
image_box.polarity( "NORMAL" );
image_box.magnificationType( "NONE" );
image_box.smoothingType( "NONE" );
image_box.configurationInformation( "NONE" );
image_box.requestedImageSize( "0" );
image_box.reqdDecimatecropBehavior( "DECIMATE" );
image_box.imageInstanceInfo( new DicomInstanceInfo( dpod ) );
film_box.addImageBox( image_box );
film_session.addFilmBox( film_box );
job.filmSession( film_session );
try
{
AppControl_a.setupORB( args );
CFGDB_a.setFSysMode( true );
CFGDB_a.setup( args );
AppControl_a.setup( args, CINFO.instance() );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 71
client.runPrint( args );
}
catch( DCSException e )
{
LOG.error( -1, "DCS Exception caught: ", e );
if ( AppControl.isInitialized() )
{
AppControl.instance().shutdown( -1 );
}
System.exit( -1 );
}
catch( DCFException e )
{
LOG.error( -1, "DCF Exception caught: ", e );
if ( AppControl.isInitialized() )
{
AppControl.instance().shutdown( -1 );
}
System.exit( -1 );
}
catch( Exception e )
{
LOG.error( -1, "Exception caught: ", e );
LOG.error( -1, LOG.formatStackTraceMsg( e ) );
if ( AppControl.isInitialized() )
{
AppControl.instance().shutdown( -1 );
}
System.exit( -1 );
}
AppControl.instance().shutdown( 0 );
System.exit( 0 );
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 72
• runJob() uses a StoreClient with the created StoreJobDescription to send the job to an
SCP.
The source code for the examples are shown below:
createStoreJobDescription:
sjd.callingAETitle( calling_ae_title_ );
sjd.responseTimeoutSeconds( 40 );
runJob:
public int runJob()
{
int exit_status= -1;
try
{
// create a job
StoreJobDescription sjd = createStoreJobDescription();
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 73
StoreClient client = new StoreClient();
CFGGroup session_cfg;
DicomSessionSettings session_settings = new DicomSessionSettings();
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 74
String session_cfg_name = "/dicom/QRSCU_default_session_settings.cfg";
try
{
session_cfg = CFGDB.instance().loadGroup( session_cfg_name, true );
session_settings = new DicomSessionSettings( session_cfg );
}
catch( CDSException e1 )
{
LOG.error( -1, "Error loading session settings from CFGDB group name = "
+ session_cfg_name, e1 );
}
// Fields to return:
query.patientId( "" );
query.patientsSex( "" );
query.modality( "" );
query.studyDate( "" );
query.numberStudyRelInstances( "" );
query.data_set().insert( DCM.E_INSTANCE_AVAILABILITY, "" );
parent_panel_.setFieldsExpected( expected_fields );
scu_.requestAssociation();
scu_.cFind( query.data_set(), QueryInfoPanel.this, false );
By implementing the QueryListener interface an object will notified when DIMSE Response
messages are received, such as C-FIND-RSP or C-MOVE-RSP or C-GET-RSP.
The queryEvent() method is called for each intermediate response.
public void queryEvent( DimseMessage rsp )
{
//output contents of message to log file
LOG.info( "Received a DIMSE response message " + rsp );
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 75
The queryComplete() method is called when a final response is received or if an internal error
occurs in the QRSCU class.
public void queryComplete( int status )
{
try
{
//internal error send an abort message.
if( status == 4 )
{
LOG.error( -1, "Aborting association\n" );
scu_.abortAssociation();
}
else
{
LOG.info( "Releasing association\n" );
scu_.releaseAssociation();
}
scu_ = null;
}
catch( DCSException e )
{
LOG.error( -1, "Error occurred while disconnecting association", e );
}
}
REM ###
REM ### copy required library files from %DCF_LIB% (../DCF/lib)
REM ###
copy %DCF_LIB%\DCF_com_lbs_DCFUtil_OSUtil.dll
copy %DCF_LIB%\DCF_DCF_cl.dll
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 76
REM ###
REM ### copy required Java JAR file from %DCF_ROOT%\classes
copy %DCF_ROOT%\classes\LaurelBridge.jar
REM ### If you are building from a DCF VisualStudio7.x .NET toolkit:
copy %DCF_BIN%\msvcp71.dll
copy %DCF_BIN%\msvcr71.dll
REM ### If you are building from a DCF VisualStudio8.x .NET toolkit:
copy %DCF_BIN%\msvcp80.dll
copy %DCF_BIN%\msvcr80.dll
REM ###
REM ### Copy the classes for the application that you have - for example,
REM ### include both the Java ex_jdcf_filter example and the ex_jdcf_dump
REM ### utilities. Make sure that the directory structure matches, i.e.,
REM ### you must have the class files in com\lbs\examples.
REM ###
copy %DCF_ROOT%\classes\com\lbs\examples\ex_jdcf_filter\*
classes\com\lbs\examples\ex_jdcf_filter
copy %DCF_ROOT%\classes\com\lbs\examples\ex_jdcf_dump\*
classes\com\lbs\examples\ex_dcf_dump
REM ###
REM ### Create a minimal configuration directory.
REM ###
mkdir cfg
mkdir cfg\apps
mkdir cfg\apps\defaults
mkdir cfg\procs
REM ###
REM ### Copy the license configuration file, and the application configs
REM ### for the installed programs.
REM ###
copy %DCF_CFG%\systeminfo cfg\systeminfo
copy %DCF_CFG%\apps\defaults\ex_jdcf_filter cfg\apps\defaults
copy %DCF_CFG%\apps\defaults\ex_jdcf_dump cfg\apps\defaults
3. Create the media by which you will deliver the install directory.
4. On the target machine do the following:
a) Unpack, copy or otherwise make the DCF app install directory available. For example, copy
or unzip to C:\temp\DCF
b) Install the Java JRE on the target box if it is not already installed; some applications may
also require the JAI and JAI Image I/O installations to read and write DICOM files with
JPEG data.
c) From a command window, go to the install directory. For example, use C:\temp\DCF.
cd C:\temp\DCF
d) Set environment variables and run your apps (you could put these steps in a run_app.bat
file). You need to put the path to the classes and the DCF JAR file in the CLASSPATH, as
well as putting your installation directory into the PATH so that the DLLs can be found.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 77
set DCF_CFG=C:\temp\DCF\cfg
set CLASSPATH=C:\temp\DCF\classes;C:\temp\DCF\LaurelBridge.jar;%CLASSPATH%
set PATH=C:\temp\DCF;%PATH%
### display input image (choose a dicom file in the line below)
java com.lbs.examples.ex_jdcf_dump.ex_jdcf_dump \temp\test.dcm
1. Create a directory for the new application component – In the DCF, every application or library is a
component, and has its own source directory.
mkdir $DCF_ROOT/devel/jsrc/com/lbs/examples/ex_jdcf_HelloWorld
2. Create a component information file in that directory. This file must be called “cinfo.cfg”. For
this example it contains the following:
#==============================================================================
# static information common to all instances of ex_jdcf_HelloWorld component
#==============================================================================
[ component_info ]
name = ex_jdcf_HelloWorld
type = java_app
category = examples
description = Java test application for DCF common services
package_prefix = com.lbs.examples
version = 0.1
[ required_components ]
component = java_lib/LOG_a
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 78
component = java_lib/APC_a
component = java_lib/CDS_a
[ debug_controls ]
debug_flag = DF_EXAMPLE, 0x10000, do something special if this debug flag is set
#==============================================================================
# per-instance information for the ex_jdcf_HelloWorld component
#==============================================================================
[ ex_jdcf_HelloWorld ]
debug_flags = 0x00000
[ ex_jdcf_HelloWorld/english ]
hello_world = hello world
[ ex_jdcf_HelloWorld/spanish ]
hello_world = hola mundo
[ ex_jdcf_HelloWorld/french ]
hello_world = bonjour le monde
[ ex_jdcf_HelloWorld/german ]
hello_world = hallo welt
The file is in the DCF configuration file format, which provides for attributes, groups, and nested
groups.
Note: The easiest way to create the cinfo.cfg file for your application or library is to copy one from
a similar component, then edit as needed.
The first group [ component_info ] describes basic attributes of the component. The name
“ex_jdcf_HelloWorld” is combined with the package_prefix “com.lbs.examples” to form the Java
package name “com.lbs.examples.ex_jdcf_HelloWorld”. Note that this corresponds to the source
directory name, relative to the Java source directory (DCF_ROOT/devel/jsrc). The component
type is “java_app” which indicates a Java application.
You can use dcfmake.pl to create applications in any directory, as long as you create a
cinfo.cfg file in that directory. You can also use DCF Java classes from your application as you
would any other Java class library.
The [ required_components ] group specifies three components needed by this application. The
group [ debug_controls ] is where the developer can add support for conditional logging or other
behavior specific to this component. Debug controls that are defined here can be accessed via the
web interface.
The [ ex_jdcf_HelloWorld ] group contains the instance configuration for the component. This
data is used directly in the example code.
3. Create the application source code
For this example, the file is called “ex_jdcf_HelloWorld.java”. Because of the package name
that was specified in the cinfo.cfg file, the generated class will thus be
com.lbs.examples.ex_jdcf_HelloWorld.ex_jdcf_HelloWorld
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 79
package com.lbs.examples.ex_jdcf_HelloWorld;
import com.lbs.LOG.*;
import com.lbs.APC.*;
import com.lbs.CDS.*;
import com.lbs.DCF.*;
/**
* The class ex_jdcf_HelloWorld demonstrates the most basic of programs
* using the DCF common services interfaces for Application Control (APC),
* Configuration Data Services (CDS), and Logging (LOG)
*
* To make it interesting, messages from different languages
* are retrieved from the application configuration. This is not intended
* to illustrate a production approach to internationalization.
*/
public class ex_jdcf_HelloWorld
{
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 80
// shutdown this application
AppControl.instance().shutdown(0);
}
catch ( DCFException e)
{
LOG.error( -1, "DCFException caught:\n", e );
AppControl.instance().shutdown(1);
}
catch (Exception e )
{
LOG.error( -1, "Exception caught:\n", e );
AppControl.instance().shutdown(1);
}
}
}
4. Create a wrapper script – The wrapper script is simply a convenience for Java applications. The
wrapper invokes the Java interpreter with the required options. (Note that many of the DCF’s Java
examples may use the same wrapper script – jrun_example.pl – that takes the class name that
defines the main() function as an argument.)
For this example, this script contains:
#!/usr/bin/perl -w
use strict;
use English;
use Env qw( DCF_CFG DCF_TMP);
use File::Basename;
my $myname = basename( $0 );
$ENV{"JAVA_NS"}="true";
exec ( "java "
. "-Dorg.omg.CORBA.ORBClass=com.sun.corba.se.internal.iiop.ORB "
. "-Dorg.omg.CORBA.ORBSingletonClass=com.sun.corba.se.internal.iiop.ORB "
. "-DDCF_CFG=\"${DCF_CFG}\" "
. "-DDCF_TMP=\"${DCF_TMP}\" "
. "com.lbs.examples.ex_jdcf_HelloWorld.ex_jdcf_HelloWorld "
. "-appcfg /apps/defaults/ex_jdcf_HelloWorld "
. "-CDS_a_use_fsys "
. join( " ", @ARGV ) );
The Java arguments seen above are listed and explained below:
-D property-name=property-value (multiple instances of this)
These four are always set for DCF Java applications, and are the Java equivalent of environment
variables
com.lbs.examples.ex_jdcf_HelloWorld.ex_jdcf_HelloWorld
This is the Java class name – i.e., the class that defines the “main” method.
appcfg /apps/defaults/ex_jdcf_HelloWorld
This tells the Application Control adapter where to find the configuration for the application.
This configuration data is generated automatically when the component is built.
-CDS_a_use_fsys
Tells the Configuration Data Service adapter to use the file system to access configuration data.
The default mode is to access configuration data via a server.
join(“”,@ARGV)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 81
Appends any additional parameters that were passed to the script. For the ex_jdcf_HelloWorld
application, this would include the “-lang” param.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 82
The application is now ready to run!
in conditionals, since in Java (and C#), the args to LOG.debug are evaluated before calling the method,
which then may decide to not log anything.
A better approach is to do something like what is illustrated in the following example:
if ( CINFO.debug( CINFO.df_SHOW_GENERAL_FLOW )
{
LOG.debug( "com.oem.module.StoreSCP.DicomDataService_a.storeObject: dimse-message =
" + c_store_rq);
}
By wrapping the debug message in a conditional at least you're not doing extra work when you are in
non-debug mode.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 83
Store related classes are in the com.lbs.DSS (DICOM Store Services) package.
//
// Put together the server_address.
//
String server_address = called_host_ + ":" + called_port_;
LOG.info("Called presentation address = " + server_address);
ainfo.calledPresentationAddress(server_address);
ainfo.calledTitle(called_ae_title_);
ainfo.callingTitle(calling_ae_title_);
ainfo.addRequestedPresentationContext(sc_ctx);
try
{
// populate the referenced sop sequence from the command line args
int count = 0;
ReferencedSopSequence[] ref_sop_sequence = new
ReferencedSopSequence[file_list_.size()];
request.transactionUid( DCMUID.makeUID());
while (count < file_list_.size())
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 84
{
DicomFileInput dfi = new DicomFileInput( (String)file_list_.elementAt(count));
dfi.open();
DicomDataSet dds = dfi.readDataSetNoPixels();
dfi.close();
count++;
}
scu_.requestAssociation();
scu_.nAction(request, 10, 10);
scu_.waitForNEvent( 1 );
scu_.releaseAssociation();
exit_status_ = 0;
}
catch (Exception e)
{
LOG.error(-1, "Exception caught:" + System.getProperty( "line.separator"), e);
System.err.println("test failed");
exit_status_ = 1;
}
finally
{
try
{
if ((scu_ != null) && scu_.connected())
{
scu_.releaseAssociation();
}
}
catch (DCSException e)
{
LOG.error(-1, "Error releasing Association, aborting", e);
scu_.abortAssociation();
exit_status_ = 1;
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 85
5.6.2.1. Example – ex_jmwl_scu
See $DCF_ROOT/devel/jsrc/com/lbs/examples/ex_jmwl_scu/ex_jmwl_scu.java for a
command line application that uses this class.
//
// Put together the server_address.
//
String server_address = host_ + ":" + port_;
LOG.info( "Called presentation address = " + server_address );
ainfo.calledPresentationAddress( server_address );
ainfo.calledTitle( called_ae_title_ );
ainfo.callingTitle( calling_ae_title_ );
ainfo.addRequestedPresentationContext( mpps_ctx );
scu_.requestAssociation();
CFGGroup mpps_cfg = null;
try
{
mpps_cfg = CFGDB.instance().loadGroup( cfg_file_, true );
}
catch( CDSException cds_e )
{
LOG.error( -1, "Error loading mpps cfg file " + usage(), cds_e );
System.exit( -1 );
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 86
LOG.info( "MPPS CFGGroup = " + mpps_cfg );
DicomDataSet ds = new DicomDataSet( mpps_cfg );
ModalityPerformedProcedureStep procedure =
new ModalityPerformedProcedureStep( ds );
if( f_opt_create_ )
{
scu_.nCreate( procedure, 10 );
}
else if( f_opt_set_ )
{
scu_.nSet( procedure, 10 );
}
scu_.releaseAssociation();
exit_status_ = 0;
}
package com.lbs.examples.ex_jstore_scp;
import com.lbs.CDS.*;
import com.lbs.CDS_a.*;
import com.lbs.APC.*;
import com.lbs.APC_a.*;
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 87
import com.lbs.LOG_a.*;
import com.lbs.DCS.*;
import com.lbs.DSS.*;
/**
* Example Java Store Service Class Provider (SCP).
* Uses DCF StoreServer and StoreSCP classes, along with a
* locally defined DicomDataService adapter to implement
* a DICOM Storage server application.
*/
public class ex_jstore_scp
implements AssociationConfigPolicyManager, AssociationListener
{
private AssociationManager mgr_;
private StoreServer store_server_;
private VerificationServer verification_server_;
// Create an AssociationManager
// You can override association manager settings after creating,
// e.g., tcp-port, max-number-concurrent-assocs, max-total-assocs, etc.
// For now, it will get them from proc-cfg/java_lib/DCS/AssociationManager.
//
mgr_ = new AssociationManager();
/**
* Ask AssociationManager to loop, waiting for connection requests, and handling
* associations. Each time a socket connect is detected, AssociationManager
* creates an instance of AssociationAcceptor that will handle all I/O for that
* association.
*/
public void runServer()
throws DCSException
{
LOG.info( "Starting ex_jstore_scp" );
mgr_.run();
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 88
/**
* Implementation of AssociationConfigPolicyManager interface.
* Here is where we optionally implement our custom policy of selecting
* the configuration used for a particular association.
*/
public DicomSessionSettings getSessionSettings( AssociationAcceptor assoc )
throws AssociationRejectedException, AssociationAbortedException
{
// Get the association info from the current acceptor.
AssociationInfo ainfo = assoc.getAssociationInfo();
//
// Demonstrate a configuration policy that selects/creates session settings
// based on the called-AE-title.
//
LOG.info( "ex_jstore_scp: getting session settings for '" + called_ae + "'" );
//
// Start with the default session settings. (Values for this come from
// the current app/proc config group java_lib/DCS/default_session_settings.)
//
DicomSessionSettings session_settings = new DicomSessionSettings();
//
// We can do different things based on the AE, either by loading
// a particular session settings configuration, or by modifying
// an existing settings object.
//
if ( calling_ae.trim().equals( "ECHO_SCU" ) || called_ae.trim().equals( "ECHO_SCP"
) )
{
// do nothing if this is an echo request
}
else if ( called_ae.trim().equals( "StoreSCP1" ) )
{
// Change the default settings by adding a
// pre- and post-processing scripts.
//
// Note that you either need a full path to the script, or it must be in the
// current working directory of this process (if you start this app via
// the web interface, that cwd will be $DCF_ROOT/httpd/cgi-bin).
session_settings.setPreAssociationScript( "perl pre_assoc.pl" );
session_settings.setPostAssociationScript( "perl post_assoc.pl" );
}
else if ( called_ae.equals( "StoreSCP2" ) )
{
// Add a filter set (by reference) to the default session settings.
String filter_cfg_name = "/dicom/filter_sets/example_filter.cfg";
session_settings.setInputFilterCfgName( filter_cfg_name );
}
else
{
// Load the session settings from a CFGGroup, based on the name
// of the called AE.
String session_cfg_name = "/dicom/example_session_" + called_ae + ".cfg";
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 89
}
catch( CDSException e )
{
LOG.error( -1, "Unable to load session cfg: " +
session_cfg_name + " - " + e + "\nRejecting the association..." );
return session_settings;
}
/**
* Optional implementation of AssociationListener interface.
*
* Indicates that a new association has been created.
* The AssociationAcceptor has selected configuration
* settings for the association, and has processed the
* A-Associate-Request PDU. The association has not yet
* been accepted.
* @param assoc the object handling the association.
* @throws AssociationRejectedException Indicates that
* the association should be rejected immediately.
* @throws AssociationAbortedException Indicates that
* the association should be aborted immediately.
*/
public void beginAssociation( AssociationAcceptor assoc )
throws AssociationRejectedException, AssociationAbortedException
{
LOG.info("Association has started:\n" + assoc.getAssociationInfo());
}
/**
* Optional implementation of AssociationListener interface.
*
* Indicates that an association has ended.
* @param assoc the object handling the association.
*/
public void endAssociation( AssociationAcceptor assoc )
{
LOG.info("Association has ended." );
}
/**
*
* Invoke with the following optional arguments:
* -CDS_a_use_fsys Do not require DCDS_Server.
* default is to expect it to
* be running. If this option is
* enabled, shutdown messages and
* runtime changes to debug settings
* are unsupported.
* -apc <proc-attr-name>=<value>
* Overrides any setting in the process
* configuration.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 90
*/
public static void main( String args[] )
{
try
{
LOG.info( "Setting up basic services" );
AppControl_a.setupORB( args );
if ( AppControl.isInitialized() )
{
AppControl.instance().shutdown( 0 );
}
System.exit( 0 );
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 91
returns the list of found objects for a C-FIND or performs C-STORE operations if a C-MOVE or a C-
GET was requested.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 92
The following illustrates what part of your DicomDataService adapter would look like:
package com.oem.StoreTest;
import com.lbs.DDS.*;
//protected constructor
//You can only create one of things be calling the public static setup method.
protected OEMDataServiceAdapter( String args[] )
{
//Here’s where you add your code to store images to your backend
public DicomPersistentObjectDescriptor storeObject(
AssociationAcceptor association_acceptor,
DimseMessage c_store_rq )
throws DDSException
{
//Your implementation goes here
}
//do something like the following for the other abstract methods
//in DicomDataService base class.
public abstract DicomDataSet loadObject(
DicomPersistentObjectDescriptor dpod,
boolean f_read_pixel_data )
throws DDSException
{
throw new DDSException( “loadObject unimplemented”)
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 93
}
In your application’s main() method, before you begin accepting incoming associations, call your
setup() method. For example:
public static void main( String args[] )
{
...
com.oem.StoreTest.OEMDataServiceAdapter.setup( args );
...
}
You could, in fact, simply replace the following line in ex_jstore_scp.java
DicomDataService_a.setup( args );
and then ex_jstore_scp.java will use your new DicomDataService adapter’s storeObject()
method whenever an incoming DICOM Image is stored.
The other methods in the DicomDataService interface support operations like finding previously
stored objects (findObjects() method) or loading previously stored objects (loadObject()
method ); this functionality is used to support the Query/Retrieve or Worklist SOP classes.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 94
Support for JPEG-LS syntaxes may be provided but has not been fully tested for the current release.
• 1.2.840.10008.1.2.4.80 JPEG-LS lossless
• 1.2.840.10008.1.2.4.81 JPEG-LS lossy
Run the ex_jdcf_filter app, using the Perl wrapper for convenience:
ex_jdcf_filter.pl –f file:/compress.cfg
Run the ex_jdcf_filter app, using the Perl wrapper for convenience:
ex_jdcf_filter.pl –f file:/decompress.cfg
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 95
Support is provided for DICOM images that are:
• Grayscale, 8 or 16 bit
• MONOCHROME2,
• RGB pixel interleaved, and
• RGB planar.
Data that is signed (pixel-representation==1) is first converted to unsigned, since many of the
destination formats or supporting software do not handle signed data properly. Certain conversions are
not supported, since the destination image format may not support the data format in the DICOM file.
For instance, a 16 bit DICOM image can not be converted directly to JPEG.
Facilities for performing certain other conversions are available, in particular the option “-8” will cause
a window-level LUT to be created and applied to 16 bit data so that it can be saved in an 8-bit format,
e.g., JPEG. The option “-16” will cause a linear LUT to be created and applied to 9-15 bit data.
Currently, the JPEG-2000 codec saves 9-15 bit data correctly, but when j2k files are reloaded, the data
is assumed to be 16 bit, and may display proportionally darker than the original.
Example conversions:
convert 12 bit DICOM to JPEG:
jrun_example.pl com.lbs.examples.ex_jdcf_dcm2jai.ex_jdcf_dcm2jai -i
12bit.dcm -t jpg -o 8bit.jpg -8
convert 8 bit DICOM to bmp:
jrun_example.pl com.lbs.examples.ex_jdcf_dcm2jai.ex_jdcf_dcm2jai -i
8bit.dcm -t bmp -o 8bit.bmp
convert 12 bit DICOM to JPEG2000:
jrun_example.pl com.lbs.examples.ex_jdcf_dcm2jai.ex_jdcf_dcm2jai -i
12bit.dcm -t jpeg2000 -o 16bit.j2k -16
Note: you could create an individual “.pl” wrapper script that would do the same as running
jrun_example.pl or as:
java com.lbs.examples.ex_jdcf_dcm2jai
This functionality can easily be added to your SCU or SCP applications for more seamless integration.
Currently only grayscale source images are properly converted. Support for various color formats will
be included in the next release.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 96
5.8.3. Example – ex_jdcf_dcmview: View a DICOM Image file
This utility very simply displays the selected image.
Example:
jrun_example.pl com.lbs.examples.ex_jdcf_dcmview.ex_jdcf_dcmview test.dcm
//=============================================================
// Saving Dicom image as JPEG
//=============================================================
BufferedImage b_image;
try
{
DicomFileInput dfi = new DicomFileInput( dicomfilename );
DicomDataSet dds = dfi.readDataSet();
RenderedImage r_image = JAIUtil.dataSetToRenderedImage(dds, false, false);
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 97
encoder = JPEGCodec.createJPEGEncoder(filestream);
}
catch (Exception e)
{
System.err.println("Error encoding image: " + e.toString());
encoder = null;
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 98
6. C# Programming Examples
This section presents a variety of C# programming examples for common DICOM integration tasks. See
$DCF_ROOT/devel/cssrc/examples/ for the complete working source code for these and
additional examples.
This chapter includes the following sections:
• DICOM Programming Examples section shows how simple DICOM related tasks are performed.
• Common Services Examples section covers use of the DCF framework services.
• Advanced DICOM Programming Examples covers some more complex server concepts.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 99
6.2. Using the DCF with MS Visual Studio .NET 2003/2005 for C#
Notes:
• You must launch Visual Studio from a DCF Command Prompt so that the correct environment is
available to Visual Studio (the environment file is %DCF_ROOT%\dcf_vars.bat if you want to
permanently set the environment, but that is not recommended).
Select “Start” Æ “All Programs” Æ “DICOM Connectivity Framework” Æ
“DCF Command Prompt”
• DCF assemblies are registered in the .NET “Global Assembly Cache” during the toolkit
installation. This removes the restriction that the DLL files must by collocated with any
executable that uses them.
Once you are at a DCF Command Prompt, you now have two choices:
• You may start Visual Studio by typing devenv and then navigate to an example project
and open it using Visual Studio’s GUI menus.
Or
• You can change directory to the C# examples directory of interest and run the desired
.csproj file, which will cause Visual Studio to start and open the selected project.
Assume you choose to work from the DCF Command Prompt and choose the second option and you
are interested in the example, ex_ndcf_dump. (This example shows how to read a DICOM data set
from a file, and write a formatted representation of that data to the console.)
• Open a DCF Command prompt:
“Start” Æ “All Programs” Æ “DICOM Connectivity Framework” Æ “DCF
Command Prompt”
• Change to the example directory:
cd %DCF_ROOT%\devel\cssrc\examples\ex_ndcf_dump
• To open the example project in Visual Studio, type the name of the project file and hit the Enter
key:
ex_ndcf_dump.csproj
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 100
• Alternately, to run the example and not open Visual Studio, type the name of the example and hit
the Enter key. For this example the command line invocation requires a file to dump:
ex_ndcf_dump %DCF_ROOT%\test\images\test.dcm
You may select other C# examples to view and/or run by making the appropriate substitutions. All C#
examples are found in: %DCF_ROOT%\devel\cssrc\examples.
6.2.2. Quick Start - Using create_cs_app.pl to generate VS project files and source
code
You can run the script %DCF_ROOT%\bin\create_cs_app.pl. This interactive script will generate
a C# source file template and a cinfo.cfg file. It will then invoke dcfmake.pl which creates .csproj file,
and DCF metadata files LOG.cs and CINFO.cs You can then open the .csproj file in Visual Studio
2003/2005 and immediately begin writing your DICOM application.
Launch Visual Studio from a DCF Command Prompt, see note above in Section 6.2.1.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 101
You should follow this same process for any assembly you wish to use directly. Note that currently, all
DCF C#.Net assemblies are prefixed with “LaurelBridge.”. You should not attempt to reference the
standard C++ dll’s (prefixed with “DCF_”) from C# projects.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 102
//
// or get the DicomElement and use its ToString() method to show value, length, etc
//
DicomElement e = dds.findElement( DCM.E_PATIENTS_NAME );
System.Console.WriteLine(“patients name element = {0}”, e );
// Create a DicomDataSet
DicomDataSet dds = new DicomDataSet();
//
// Create image header elements using the DicomDataSet convenience methods:
// insert( AttributeTag, string )
// insert( AttributeTag, int )
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 103
// These will use DicomElementFactory to create the appropriate DicomElement subclass
// and add it to the data set.
//
// Note also the use of DicomDataDictionary to create a new UID.
//
dds.insert( DCM.E_SOPCLASS_UID, DCM.UID_SOPCLASSUS );
dds.insert( DCM.E_SOPINSTANCE_UID, DicomDataDictionary.makeUID() );
dds.insert( DCM.E_ROWS, rows );
dds.insert( DCM.E_COLUMNS, cols );
dds.insert( DCM.E_PHOTOMETRIC_INTERPRETATION, “MONOCHROME2” );
dds.insert( DCM.E_BITS_ALLOCATED, 8 );
dds.insert( DCM.E_BITS_STORED, 8 );
dds.insert( DCM.E_HIGH_BIT, 7 );
dds.insert( DCM.E_SAMPLES_PER_PIXEL, 1 );
dds.insert( DCM.E_PIXEL_REPRESENTATION, 0 );
//
// for VM>1, we create elements explicitly
//
DicomOBElement e_pixel_data = new DicomOBElement( E_PIXEL_DATA, pixels );
dds.insert( e_pixel_data );
// save to a file
DicomFileOutput dfo = new DicomFileOutput(“myfile.dcm”);
dfo.writeDataSet( dds );
dfo.close();
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 104
using LaurelBridge.DCS;
namespace ex_ndcf_ModPixelData
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
DicomFileInput dfi = new DicomFileInput();
dfi.open("C:/temp/in.dcm");
DicomDataSet dds = dfi.readDataSet();
dfi.close();
// get some of the basic image header fields. Use the DicomDataSet
// convenience methods to get integer values for these.
int rows = dds.getElementIntValue( DCM.E_ROWS );
int cols = dds.getElementIntValue( DCM.E_COLUMNS );
int bits_allocated = dds.getElementIntValue( DCM.E_BITS_ALLOCATED );
int bits_stored = dds.getElementIntValue( DCM.E_BITS_STORED );
int pixel_count = rows*cols;
// get the pixel data element.
DicomElement e_pixel_data = dds.findElement( DCM.E_PIXEL_DATA );
// get a C style pointer to the pixels – this locks the
// element’s data buffer in memory,
// until “releaseBinaryData” is called.
// IntPtr’s can be used to create BitMap objects, or can be passed
// to a COM C++ object.
System.IntPtr p_raw_pixel_data = e_pixel_data.getBinaryData();
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 105
// save the data set with the new pixel data
DicomFileOutput dfo = new DicomFileOutput();
dfo.open( "C:/temp/out.dcm", UID.TRANSFERLITTLEENDIAN, false );
dfo.writeDataSet( dds );
dfo.close();
}
}
}
int status;
VerificationSCU client = null;
try
{
if( args.Length < 3 )
{
throw new DCFException(usage_);
}
Framework.FSysModeCFGDB = true;
Framework.ConsoleModeLogger = true;
Framework.initDefaultServices(args, CINFO.Instance );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 106
{
try
{
if ((client != null) && client.Connected)
{
client.releaseAssociation();
}
}
catch (DCSException e)
{
LOG.error(- 1, "Error releasing Association, aborting", e);
client.abortAssociation();
status = 1;
}
}
Framework.shutdown(status);
System.Environment.Exit(status);
To send images from a C# program to a DICOM Printer or Print “Service Class Provider” use the
PrintClient class. PrintClient provides a very high level interface to a DICOM Print SCU. The
application developer is removed from the process of negotiating an association, sending DIMSE
messages, managing the complex relationships between objects in the normalized service classes, and
handling printer and print job status notifications. The sheets of images that are to be printed are
defined in an intuitive hierarchical structure. The PrintClient object handles the messy details of
DICOM Print.
The PrintJobDescription object contains basic attributes of the job such as the server address and
various job level options. Also included in the PrintJobDescription is a single
PrintJobFilmSession object. This corresponds to the DICOM film-session object.
PrintJobFilmSession contains one or more PrintJobFilmBox objects. A PrintJobFilmBox
corresponds to the DICOM film-box object, which represents a sheet or film to be printed.
PrintJobFilmBox contains one or more PrintJobImageBox objects. A PrintJobImageBox
corresponds to a DICOM image-box and represents a single image to be placed somewhere on the film.
When the job has completed, a PrintJobStatus object is returned which summarizes the results of
the print operation.
The PrintClient also supports a listener or notification interface using the PrintClientListener
interface. If the user installs a method to receive events, then notifications will be sent to that object as
DICOM print-job or printer status values change.
//
// initialize the PrintJobDescription
//
PrintJobDescription job = new PrintJobDescription(); // describes the job we want to do
PrintJobFilmSession film_session = new PrintJobFilmSession();
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 107
PrintJobFilmBox film_box = new PrintJobFilmBox();
PrintJobImageBox image_box = new PrintJobImageBox();
job.serverAddress(print_server_address);
job.clientAddress("DEMO");
job.requestPrintJobSOPClass(true);
job.pollPrintJob(true);
job.printJobPollRateSeconds(2);
job.jobTimeoutSeconds(30);
film_session.numberOfCopies = ("1");
film_session.printPriority = ("HIGH");
film_session.mediumType = ("BLUE FILM");
film_session.filmDestination = ("MAGAZINE");
film_session.filmSessionLabel = ("test");
film_session.memoryAllocation = ("0");
film_session.ownerId = ("DCF");
film_box.imageDisplayFormat = ("STANDARD\\1,1");
film_box.filmOrientation = ("PORTRAIT");
film_box.filmSizeId = ("14INX17IN");
film_box.magnificationType = ("NONE");
film_box.smoothingType = ("NONE");
film_box.borderDensity = ("0");
film_box.emptyImageDensity = ("0");
film_box.minDensity = (0);
film_box.maxDensity = (280);
film_box.trim = ("YES");
film_box.configurationInformation = ("NONE");
film_box.illumination = (0);
film_box.reflectedAmbientLight = (0);
film_box.requestedResolutionId = ("HIGH");
image_box.imagePosition = (1);
image_box.polarity = ("NORMAL");
image_box.magnificationType = ("NONE");
image_box.smoothingType = ("NONE");
image_box.configurationInformation = ("NONE");
image_box.requestedImageSize = ("0");
image_box.reqdDecimatecropBehavior = ("DECIMATE");
image_box.imageInstanceInfo(dii);
film_box.addImageBox(image_box);
film_session.addFilmBox(film_box);
job.filmSession(film_session);
This code was taken from the C# ex_nprint_client example. The full source for the program can
be found in %DCF_ROOT\devel\cssrc\examples\ex_nprint_client.
6.3.3.1. Example – Create and submit a print job, handling status events
Create and submit a print job where ImageBox data comes from DICOM disk files and handle events
when Printer or PrintJob status changes. See $DCF_ROOT/devel/cssrc/examples/ex_nprint_scu for a
source code example.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 108
6.3.3.2. Example – Create and submit a print job where ImageBox data comes from DICOM
disk files.
See $DCF_ROOT/devel/cssrc/examples/ex_nprint_client/ex_nprint_client.cs for a
complete program.
public virtual int runPrint(System.String[] args)
{
DicomInstanceInfo dii = new DicomInstanceInfo( args[0] );
// Print server
System.String print_server_address = args[1];
job.serverAddress(print_server_address);
job.clientAddress("DEMO");
job.requestPrintJobSOPClass(true);
job.pollPrintJob(true);
job.printJobPollRateSeconds(2);
job.jobTimeoutSeconds(30);
film_session.numberOfCopies = ("1");
film_session.printPriority = ("HIGH");
film_session.mediumType = ("BLUE FILM");
film_session.filmDestination = ("MAGAZINE");
film_session.filmSessionLabel = ("test");
film_session.memoryAllocation = ("0");
film_session.ownerId = ("DCF");
film_box.imageDisplayFormat = ("STANDARD\\1,1");
film_box.filmOrientation = ("PORTRAIT");
film_box.filmSizeId = ("14INX17IN");
film_box.magnificationType = ("NONE");
film_box.smoothingType = ("NONE");
film_box.borderDensity = ("0");
film_box.emptyImageDensity = ("0");
film_box.minDensity = (0);
film_box.maxDensity = (280);
film_box.trim = ("YES");
film_box.configurationInformation = ("NONE");
film_box.illumination = (0);
film_box.reflectedAmbientLight = (0);
film_box.requestedResolutionId = ("HIGH");
image_box.imagePosition = (1);
image_box.polarity = ("NORMAL");
image_box.magnificationType = ("NONE");
image_box.smoothingType = ("NONE");
image_box.configurationInformation = ("NONE");
image_box.requestedImageSize = ("0");
image_box.reqdDecimatecropBehavior = ("DECIMATE");
image_box.imageInstanceInfo(dii);
film_box.addImageBox(image_box);
film_session.addFilmBox(film_box);
job.filmSession(film_session);
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 109
PrintJobStatus job_status = new PrintJobStatus(job.jobUID());
print_client.submitPrintJob(job, null, job_status);
if ( job_status.status().Equals("SUCCESS") )
{
return 0;
}
else
{
return 1;
}
}
6.3.4.1. Example – Create and submit a store job from files on disk
Create and submit a store job where instance data comes from DICOM files on disk.
doStoreJob()
{
// create a StoreJobDescription with one image
// create a StoreClient
// submit the job and then wait for completion - this blocks
// use “submitStoreJob” for non blocking behavior.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 110
// create a StoreClient
// submit the job and then wait for completion - this blocks
// use “submitStoreJob” for non blocking behavior.
/*
* Implementation of StoreClientListener interface.
*/
public virtual void storeObjectComplete(StoreJobInstanceStatus status)
{
/*
* Implementation of StoreClientListener interface.
*/
public virtual void storeJobComplete(StoreJobStatus status)
{
LOG.info("Received storeJobComplete event " + System.Environment.NewLine +
"status = " + status.status() + System.Environment.NewLine + "statusInfo = " +
status.statusInfo() + System.Environment.NewLine + "status Info Ex = " +
status.statusInfoEx());
}
CFGGroup session_cfg;
DicomSessionSettings session_settings = new DicomSessionSettings();
String session_cfg_name = "/dicom/QRSCU_default_session_settings.cfg";
try
{
session_cfg = CFGDB.instance().loadGroup( session_cfg_name, true );
session_settings = new DicomSessionSettings( session_cfg );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 111
}
catch( CDSException e1 )
{
LOG.error( -1, "Error loading session settings from CFGDB group name = "
+ session_cfg_name, e1 );
}
// Fields to return:
query.patientId = "";
query.patientsSex = "";
query.modality = "";
query.studyDate = "";
query.numberStudyRelInstances = "";
query.data_set.insert( DCM.E_INSTANCE_AVAILABILITY, "" );
parent_panel_.setFieldsExpected( expected_fields );
scu_.requestAssociation();
scu_.cFind( query.data_set(), QueryInfoPanel.this, false );
By implementing the QueryListener interface an object will notified when DIMSE Response
messages are received, such as C-FIND-RSP or C-MOVE-RSP or C-GET-RSP.
The queryEvent() method is called for each intermediate response.
public void queryEvent( DimseMessage rsp )
{
//output contents of message to log file
LOG.info( "Received a DIMSE response message " + rsp );
}
The queryComplete() method is called when a final response is received or if an internal error
occurs in the QRSCU class.
public void queryComplete( int status )
{
try
{
//internal error send an abort message.
if( status == QueryListenerStatus.QUERY_LISTENER_ERROR )
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 112
{
LOG.error( -1, "Aborting association\n" );
scu_.abortAssociation();
}
else
{
LOG.info( "Releasing association\n" );
scu_.releaseAssociation();
}
scu_ = null;
}
catch( DCSException e )
{
LOG.error( -1, "Error occurred while disconnecting association", e );
}
}
//(1)
DicomDataSet seq_ds_1 = new DicomDataSet();
//(2)
seq_ds_1.insert(new DicomUIElement(DCM.E_REFERENCED_SOPCLASS_UID,
"1.2.840.10008.5.1.4.1.1.14"));
seq_ds_1.insert(new DicomUIElement(DCM.E_REFERENCED_SOPINSTANCE_UID,
"1.2.840.114089.1.2.3.4"));
//(3)
DicomSQElement sq_e = new DicomSQElement(DCM.E_REFERENCED_IMAGE_SEQUENCE,
seq_ds_1);
//(4)
ds.insert( sq_e );
There are no doubt variations on how a given application will do things – refer to the online docs for
DicomSQElement, DicomDataSet, etc., for additional details and options.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 113
6.3.6.2. Example – Setting DICOM Sequence elements using a config group
If you have a CFGGroup similar to what dcf_pg uses, you can give that config group to a
DicomDataSet constructor, and create a dataset based on the specification in the config group.
For example, if you have a config group stored in a file and load that group as:
CFGGroup g = CFGDB.loadGroup("file:/data_set.cfg");
And the file data_set.cfg contains:
[ header_info ]
# sop class uid
0008,0016 = 1.2.840.10008.5.1.4.31
# sop instance uid
0008,0018 = 1.2.3.4.1.100
# Accession Number
0008,0050 = 111
# Referring Physician
0008,0090 = Dr. Nick
# referenced study sequence
# sop class uid
0008,1110.0008,1150 = 1.2.3.4.5
# sop instance uid
0008,1110.0008,1155 = 1.2.3.4.100
If no item number is specified, the first item (#0) is assumed. You can also specify the last element in a
sequence by “#L” (upper-case is important!) if you don’t know how many items are in a sequence. If
you are creating new elements, you can specify the next item in the sequence via “#N” (again, case is
important) to append to the sequence. For example: 0080,0100.#L.0010,0010.#N.0008,0060
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 114
REM###
REM### copy required library files from %DCF_LIB% (../DCF/lib)
REM###
copy %DCF_LIB%\DCF_COM.dll
copy %DCF_LIB%\DCF_DCFCore.dll
copy %DCF_LIB%\DCF_DCF_cl.dll
copy %DCF_LIB%\DCF_ljpeg12.dll
copy %DCF_LIB%\DCF_ljpeg16.dll
copy %DCF_LIB%\DCF_ljpeg8.dll
copy %DCF_LIB%\LaurelBridge.APC_a.dll
copy %DCF_LIB%\LaurelBridge.CDS_a.dll
copy %DCF_LIB%\LaurelBridge.DCF.dll
copy %DCF_LIB%\LaurelBridge.DCFUtil.dll
copy %DCF_LIB%\LaurelBridge.DCS.dll
copy %DCF_LIB%\LaurelBridge.DDS.dll
copy %DCF_LIB%\LaurelBridge.DDS_a.dll
copy %DCF_LIB%\LaurelBridge.Interop.DCF_COM.dll
copy %DCF_LIB%\LaurelBridge.LOG_a.dll
copy %DCF_LIB%\LaurelBridge.NDCDS.dll
REM ### If you are building from a DCF VisualStudio7.x .NET toolkit:
copy %DCF_BIN%\msvcp71.dll
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 115
copy %DCF_BIN%\msvcr71.dll
REM ### If you are building from a DCF VisualStudio8.x .NET toolkit:
copy %DCF_BIN%\msvcp80.dll
copy %DCF_BIN%\msvcr80.dll
copy %DCF_BIN%\omniORB407_rt.dll
copy %DCF_BIN%\omnithread32_rt.dll
REM###
REM### Copy the application that you want - for example,
REM### include both the C#.Net ex_ndcf_filter example, and the ex_ndcf_dump
REM### example.
REM###
copy %DCF_BIN%\ex_ndcf_dump.exe
copy %DCF_BIN%\ex_ndcf_filter.exe
REM###
REM### Copy the sample filter configuration for ex_ndcf_filter
REM### if desired.
REM###
copy %DCF_ROOT%\devel\cssrc\examples\ex_ndcf_filter\example_filter.cfg
REM###
REM### Create a minimal configuration directory.
REM###
mkdir cfg
mkdir cfg\apps
mkdir cfg\apps\defaults
mkdir cfg\procs
REM###
REM### Copy the license configuration file, and the application configs
REM### for the installed programs.
REM###
copy %DCF_CFG%\systeminfo cfg\systeminfo
copy %DCF_CFG%\apps\defaults\ex_ndcf_filter cfg\apps\defaults
copy %DCF_CFG%\apps\defaults\ex_ndcf_dump cfg\apps\defaults
3. Create the media by which you will deliver the install directory to the target machine.
###
### filter that image - the example_filter.cfg
### uses "C:\temp\test.dcm" and "C:\temp\filtered_image.dcm"
### as input and output respectively.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 116
ex_ndcf_filter -f file:/example_filter.cfg
REM ###
REM ### copy required library files from %DCF_LIB% (../DCF/lib)
REM ###
copy %DCF_LIB%\DCF_COM.dll
copy %DCF_LIB%\DCF_DCFCore.dll
copy %DCF_LIB%\DCF_DCF_cl.dll
copy %DCF_LIB%\DCF_ljpeg12.dll
copy %DCF_LIB%\DCF_ljpeg16.dll
copy %DCF_LIB%\DCF_ljpeg8.dll
copy %DCF_LIB%\LaurelBridge.APC_a.dll
copy %DCF_LIB%\LaurelBridge.CDS_a.dll
copy %DCF_LIB%\LaurelBridge.DCF.dll
copy %DCF_LIB%\LaurelBridge.DCFUtil.dll
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 117
copy %DCF_LIB%\LaurelBridge.DCS.dll
copy %DCF_LIB%\LaurelBridge.DDS.dll
copy %DCF_LIB%\LaurelBridge.DDS_a.dll
copy %DCF_LIB%\LaurelBridge.Interop.DCF_COM.dll
copy %DCF_LIB%\LaurelBridge.LOG_a.dll
copy %DCF_LIB%\LaurelBridge.NDCDS.dll
REM ### If you are building from a DCF VisualStudio7.x .NET toolkit:
copy %DCF_BIN%\msvcp71.dll
copy %DCF_BIN%\msvcr71.dll
REM ### If you are building from a DCF VisualStudio8.x .NET toolkit:
copy %DCF_BIN%\msvcp80.dll
copy %DCF_BIN%\msvcr80.dll
copy %DCF_BIN%\omniORB407_rt.dll
copy %DCF_BIN%\omnithread32_rt.dll
REM ###
REM ### Copy the application that you want.
REM ###
REM ### In your C# project directory, the executable might
REM ### be in .\bin\Debug or .\bin\Release
REM ### Here, we assume the exe is in \temp.
copy C:\temp\ex_ndcf_simple_win_app.exe .
REM ###
REM ### Create a minimal configuration directory.
REM ###
mkdir cfg
mkdir cfg\apps
mkdir cfg\apps\defaults
mkdir cfg\procs
mkdir cfg\components
mkdir cfg\components\cs_lib
REM ###
REM ### Copy the license configuration file, and the
REM ### C# library component configuration data. Since
REM ### there is no application configuration, library
REM ### code may look to this data for default configuration.
REM ###
copy %DCF_CFG%\systeminfo cfg\systeminfo
copy %DCF_CFG%\components\cs_lib\* cfg\components\cs_lib
3. Create the media by which you will deliver the install directory to the target machine.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 118
e) Set the environment vars and run your apps (you could put this text in a run_app.bat file).
set DCF_CFG=C:\temp\DCF\cfg
set DCF_LIB=C:\temp\DCF
set DCF_TMP=C:\temp\DCF
Note: If you are separating the installed files into “bin” and “lib” directories – for example, your
executable is in the “install/bin” directory and any libraries it needs are in the “install/lib” directory –
you need to take some additional steps when deploying your application.
For one thing, you will need to make sure the the bin and lib directories are in the PATH environment
variable. You will also probably need to add each of the LaurelBridge C# DLLs to the Global
Assembly Cache (GAC) with the gacutil command, e.g., gacutil /i LaurelBridge.DCF.dll. You may
also need to register the DCF’s transfer syntax codecs DLL (regsvr32 COM_TSCWrappers.dll).
1. Create a directory for the new application component. In the DCF, every application or library is a
component and has its own source directory.
mkdir %DCF_ROOT%\devel\cssrc\examples\ex_ndcf_HelloWorld
2. Create a component information file in that directory. This file must be called “cinfo.cfg”. For
this example it contains the following:
#==============================================================================
# static information common to all instances of the ex_ndcf_HelloWorld component
#==============================================================================
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 119
[ component_info ]
name = ex_ndcf_HelloWorld
namespace_prefix = LaurelBridge
guid = 6BB35642-8400-44FA-850E-E7EAA1C03B21
type = cs_app
category = examples
docfile = none
description = C# example app logs.
[ build_info ]
platform = Windows_NT_4_x86_VisualStudio7.x
platform = Windows_NT_4_x86_VisualStudio8.x
platform = Windows_NT_4_x64_VisualStudio8.x
gen_build_file = yes
gen_cinfo_code_and_data = yes
[ debug_controls ]
debug_flag = df_EXAMPLE, 0x10000, do something special if this debug flag is set
[ required_components ]
component = cs_lib/DCF
component = cs_lib/LOG_a
component = cs_lib/APC_a
#==============================================================================
# per-instance information for the ex_ndcf_HelloWorld component
#==============================================================================
[ ex_ndcf_HelloWorld ]
debug_flags = 0x00000
[ ex_ndcf_HelloWorld/english ]
hello_world = hello world
[ ex_ndcf_HelloWorld/spanish ]
hello_world = hola mundo
[ ex_ndcf_HelloWorld/french ]
hello_world = bonjour le monde
[ ex_ndcf_HelloWorld/german ]
hello_world = hallo welt
The file is in the DCF configuration file format, which provides for attributes, groups, and nested
groups.
Note: The easiest way to create the cinfo.cfg file for your application or library is to copy one from
a similar component, then edit as needed. You will need to generate a new guid using a program
like “uuidgen /c”
The first group [ component_info ] describes basic attributes of the component. The component
type is “cs_app” which indicates a C# application. The guid (Globally Unique Identifier)is used by
Visual Studio. Each new component you create must have a new guid. You can use the program
“uuidgen” with the argument “/c” to generate a new guid in the correct format.
You can use dcfmake.pl to create applications in any directory, as long as you create a
cinfo.cfg file in that directory. You can also use DCF C# classes for your application as you
would any other C# class library.
The [ required_components ] group specifies three components needed by this application. The
group [ debug_controls ] is where the developer can add support for conditional logging or other
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 120
behavior specific to this component. Debug controls that are defined here can be accessed via the
web interface.
The [ ex_ndcf_HelloWorld ] group contains the instance configuration for the component. This
data is used directly in the example code.
3. Create the application source code
For this example, the file is called “ex_ndcf_HelloWorld.cs”.
using System;
using LaurelBridge.DCF;
namespace LaurelBridge
{
namespace ex_ndcf_HelloWorld
{
/// <summary> The class ex_ndcf_HelloWorld demonstrates the most basic of programs
/// using the DCF common services interfaces for Application Control (APC),
/// Configuration Data Services (CDS), and Logging (LOG)
///
/// To make it interesting, messages from different languages
/// are retrieved from the application configuration.
/// </summary>
public class ex_ndcf_HelloWorld
{
[STAThread]
public static void Main(System.String[] args)
{
int status;
try
{
System.String language = "english";
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 121
// we'll use the fully configured logger,
// but only the File-system mode CFGDB - i.e.,
// DCDS_Server is not required to be running
Framework.ConsoleModeLogger = false;
Framework.FSysModeCFGDB = true;
Framework.initDefaultServices( args, CINFO.Instance );
status = 0;
}
catch (Exception e)
{
LOG.error(-1, "Exception caught:\n", e );
status = -1;
}
Framework.shutdown( status );
}
}
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 122
f) Generate the CINFO.cs source file in the current directory. The CINFO class contains the
debug flag mask constants as well as code to initialize and update the debug flags value
from the CDS database. CINFO also provides convenience mechanisms for getting the
configuration group for the component within a particular application.
g) Generate the LOG.cs source file in the current directory. The LOG class (which is internal to
the component’s assembly) is simply a wrapper for the DCF LOG interface. It simplifies
checking debug flag settings in CINFO, and provides message header fields that remain
constant for the component.
h) Generate the .csproj.
i) Invoke “devenv .csproj <args>”. Any arguments given to dcfmake.pl are forwarded
to devenv. After the make completes, the generated .csproj file is removed. You can
have dcfmake.pl leave the generated file by using the “-keep” option.
5. Update the configuration data service repository.
This developer can determine when to deploy any newly created or edited configuration data. This
can be useful if you are testing with non-default configurations and do not want the fact that you
have rebuilt something to affect your working configuration files. To update the data execute the
command:
perl –S update_cds.pl
This will copy all files from the temporary areas %DCF_USER_ROOT%\devel\cfggen and
%DCF_USER_ROOT%\devel\cfgsrc to the working area: %DCF_USER_ROOT%\cfg. As the files
are copied various macros are expanded, e.g., the files in the working configuration can have the
correct port numbers, path names, etc.
The application is now ready to run!
in conditionals, since in C# (and Java), the args to LOG.debug are evaluated before calling the method,
which then may decide to not log anything.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 123
A better approach is to do something like what is illustrated in the following example:
if ( CINFO.debug( CINFO.df_SHOW_GENERAL_FLOW )
{
LOG.debug( "Namespace.StoreSCP.DicomDataService_a.storeObject: dimse-message = " +
c_store_rq);
}
By wrapping the debug message in a conditional at least you're not doing extra work when you are in
non-debug mode.
In this mode, default configuration data if needed for DCS classes comes from compiled-in data
in LaurelBridge.DCS.CINFO.
Note: If you do not initialize the logger component to write to a file; then by default you will get
the Console Mode logger facility. This may produce unexpected messages or behavior
depending on whether or not your application has a console. Even if your application does not
write LOG messages, DCF library code may write some info messages to the logger, which will
attempt to write to the console. In addition, if you ever need to turn on DICOM debug logging
(or any logging, for that matter), this could create a problem for a GUI or Service application
that does not have a console.
Note: A word of caution when no configuration files are used. Because configuration data is
not getting read from a file, but from burned in default data contained in the DCF assemblies,
this means that if you want to change a default value then your code must have a facility to
allow users to change those values programmatically. Example of things you might want to
change include: Debug flags, timeout values, AE titles, and the like.
2. Using no common services, no application config file, but including component configurations
Under this scenario component configurations are created and stored in the directory:
"%DCF_CFG%\components\cs_lib\*".
In this mode, default configuration data, if needed for DCS classes, comes from the file:
%DCF_CFG%\components\cs_lib\DCS. Other DCF libraries would find their config data in
the same fashion.
See Note in example 1 above.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 124
3. Use all the Common Services
In this scenario your system is considered fully configured, i.e.,
a) You have an application configuration, e.g.,
%DCF_CFG%\apps\defaults\some_app_name
You’re setting up common services.
You’re a server that is started by the system manager and will communicate with it as it initializes (See
configurations in %DCF_CFG%\systems.)
// init common services
LaurelBridge.LOG_a.LOGClient_a.setup( args );
LaurelBridge.CDS_a.CFGDB_a.setup( args );
LaurelBridge.APC_a.AppControl_a.setup( args, CINFO.Instance );
// let sysmgr know you’re done init (If you’re an SCP using AssociationManager,
// it will do this when run() is called
AppControl.Instance.applicationReady();
Note: In this mode (3), we're spelling out what is happening and not using
"Framework.initDefaultServices()". While this command still works, we're
discouraging its use. For the two lines that it saves, there are potential problems or confusing
issues. Since the class "Framework" is in namespace "DCF", which builds before CDS_a,
LOG_a, APC_a, it can't literally call those three "setup" methods as above. Instead, it uses
reflection to load the forward referenced assemblies and call them. Likewise, the
methods/properties on Framework to set various options are just pass-throughs to the real
classes. It seems cleaner to just let the user understand more of what's actually happening as
illustrated above.
4. Something in between choosing no services or all services.
The problem is there are MANY variations possible, so here's one example:
a) We have an app-config, so we'll setup AppControl.
We want to ignore the logger config data in the app-config, and just set a single file name.
We want to use the file system (fsys) mode cfg db.
We are not interacting with the system manager.
// set up logger with a single file
LaurelBridge.LOG_a.LOGClient_a.LogFileName = "test.log";
LaurelBridge.LOG_a.LOGClient_a.setup( args );
// setup AppControl and tell it we will not be receiving shutdown messages, which
// implies we don't talk to system manager
LaurelBridge.APC_a.AppControl_a.setHandleExternalShutdownRq( false );
LaurelBridge.APC_a.AppControl_a.setup( args, CINFO.Instance );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 125
6.5.4. Using the CDS interface
See language specific class documentation for CDS.CFGGroup, CDS.CFGAttribute, and
CDS.CFGDB.
//
// Put together the server_address.
//
String server_address = called_host_ + ":" + called_port_;
LOG.info("Called presentation address = " + server_address);
ainfo.calledPresentationAddress(server_address);
ainfo.calledTitle(called_ae_title_);
ainfo.callingTitle(calling_ae_title_);
ainfo.addRequestedPresentationContext(sc_ctx);
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 126
try
{
// populate the referenced sop sequence from the command line args
int count = 0;
ReferencedSopSequence[] ref_sop_sequence = new
ReferencedSopSequence[file_list_.size()];
request.transactionUid( DCMUID.makeUID());
while (count < file_list_.size())
{
DicomFileInput dfi = new DicomFileInput( (String)file_list_.elementAt(count));
dfi.open();
DicomDataSet dds = dfi.readDataSetNoPixels();
dfi.close();
scu_.requestAssociation();
scu_.nAction(request, 10, 10);
scu_.waitForNEvent( 1 );
scu_.releaseAssociation();
exit_status_ = 0;
6.6.2.1. Example – Send Worklist Query and wait for all responses before continuing
See %DCF_ROOT%\devel\cssrc\examples\ex_ndcf_mwl_scu for an example.
Note with this example the program processes incoming DIMSE Messages.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 127
6.6.2.2. Example – Send Worklist Query and handle responses as they arrive
See %DCF_ROOT%\devel\cssrc\examples\ex_ndcf_query_scu (Query/Retrieve) for an example of
installing an event handler to be notified (with the query result as the payload) when a
DIMSE Message has been processed.
//
// Put together the server_address.
//
System.String server_address = host_ + ":" + port_;
LOG.info("Called presentation address = " + server_address);
ainfo.calledPresentationAddress(server_address);
ainfo.calledTitle(called_ae_title_);
ainfo.callingTitle(calling_ae_title_);
ainfo.addRequestedPresentationContext(mpps_ctx);
scu_.requestAssociation();
CFGGroup mpps_cfg = null;
try
{
mpps_cfg = CFGDB.Instance.loadGroup(cfg_file_, true);
}
catch (CDSException cds_e)
{
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 128
LOG.error(- 1, "Error loading mpps cfg file " + usage(), cds_e);
System.Environment.Exit(- 1);
}
LOG.info("MPPS CFGGroup = " + mpps_cfg);
DicomDataSet ds = new DicomDataSet(mpps_cfg);
ModalityPerformedProcedureStep procedure = new ModalityPerformedProcedureStep(ds);
if (f_opt_create_)
{
scu_.nCreate(procedure, 10);
}
else if (f_opt_set_)
{
scu_.nSet(procedure, 10);
}
scu_.releaseAssociation();
exit_status_ = 0;
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 129
namespace OEM.StoreTest
{
using LaurelBridge.DDS;
{
//protected constructor
//You can only create one of things be calling the public static setup method.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 130
//Here’s where you add your code to store images to your backend
public DicomPersistentObjectDescriptor storeObject(
AssociationAcceptor association_acceptor,
DimseMessage c_store_rq )
throws DDSException
{
//Your implementation goes here
}
//Do something like the following for the other abstract methods
//in DicomDataService base class.
In your application’s main() method, before you begin accepting incoming associations, call your
setup() method, for example:
public static void Main( string[] args )
{
...
OEM.StoreTest.OEMDataServiceAdapter.setup( args );
...
You could, in fact, simply replace the following line in the example program ex_nstore_scp.cs
DicomDataService_a.setup( args );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 131
with this line:
OEM.StoreTest.OEMDataServiceAdapter.setup( args );
and then once this change is made ex_nstore_scp.cs will use your new DicomDataService
adapter’s storeObject() method whenever an incoming DICOM Image is stored.
The other methods in the DicomDataService interface support operations like finding previously
stored objects (findObjects() method) or loading previously stored objects (loadObject()
method); this functionality is used to support the Query/Retrieve or Worklist SOP classes.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 132
6.6.4.4. Example – Adding OEM specific data to DicomSessionSettings:
When implementing a custom StoreSCP it may become desirable to add custom processing for certain
clients, for example, you may customize your actions based on the calling AE-Title of the client. When
adding OEM specific data to DicomSessionSettings the main issue to be aware of is to assurethat
you don't use a group or element name that DCS.DicomSessionSettings is already using.
To add a setting you could do something like the following:
MyStoreSCPApp
{
DicomSessionSettings getSessionSettings( AssociationAcceptor acceptor )
{
// create default settings
DicomSessionSettings ss = new DicomSessionSettings();
DicomDataService_a
{
storeObject( AssociationAcceptor acceptor, ... )
{
string dir =
acceptor.SessionSettings.Cfg.getAttributeValue("OEM.DicomDataService_a/output_dir");
...
}
}
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 133
/// Indicates that an association has ended.
/// </summary>
/// <param name="assoc"> the object handling the association.
/// </param>
public virtual void endAssociation(AssociationAcceptor assoc)
{
LOG.info("Association has ended.");
System.Collections.ArrayList ctx_list =
assoc.AssociationInfo.rejectedPresentationContextList();
...
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 134
Make sure that the PATH contains the location of dcf_sysmgr.exe and any dll’s that it will need.
Note that the DCF toolkit installer will optionally perform this step on a development box.
You can use the “Services” administrator tool to adjust how the service is started, or to stop and start
the service. The “sc” command can also be used to start the system manager. For example:
sc start DCF.3.1.3a.dcfsysmgr
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 135
Note that the DCF toolkit installer will optionally perform this step on a development box.
Start the dcf_sysmgr process either by running it from the command line, in a batch file, or by
using the dcfstart.pl or apc_client.exe programs, which will start dcf_sysmgr if it is not
already running.
Start the dcf_sysmgr process like any other unix server process or daemon. For example:
dcf_sysmgr &
Interface Description
DAPC::SystemManager CORBA interface to start/stop/get-status of a system
DAPC::ApplicationControl CORBA interface by which dcf_sysmgr requests child server
(C++, Java) applications to shutdown
DAPC::SystemStatusListener CORBA interface used to deliver status events to system
management tools
DAPC::ProcessStatusListener CORBA interface used to deliver status events to system
management tools
ICOMAppControl COM interface by which dcf_sysmgr requests child server (C#)
applications to shutdown
ICOMSystemManager COM interface to start/stop/get-status of a system
_ICOMSystemManagerEvents COM interface used to deliver process and system status events to
management tools
The application apc_client is used to communicate with the system manager using various interfaces
from the DAPC component. The scripts dcfstart.pl, dcfstop.pl and dcfsysstatus.pl are simple wrappers
that invoke apc_client.
A GUI based example is available for C#.Net. This application can be found in
DCF_ROOT/devel/cssrc/examples/NDCFSystemMonitor. System manager must be running prior to
starting NDCFSystemMonitor. A system configuration can be selected, and the system manager can
be requested to start or stop that system. The status of the system and each process is updated
dynamically. Note that if “exit_after_system_stopped” is set in the dcf_sysmgr app configuration,
then the system manager process will exit after the first “Stop-System” request is completed.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 136
As of DCF version 3.1.4b, both COM and CORBA clients locate the system manager using a
stringified object reference which is stored in the directory given by the DCF_TMP environment
variable. For CORBA clients, this is a standard IIOP stringified object reference. For COM, a string
representation of an ObjRefMoniker object is used. On windows systems, a single instance of the
COMSystemManager class is created and registered in the Running Object Table. All COM clients
interact with this object.
# set name of Windows mutex that assures only one system manager will run
# by default it is dcf_sysmgr_${ver} where ver is 289a for 2.8.9a.
#mutex_name = dcf_sysmgr_289a
#
# If true, dcf_sysmgr will exit after system shutdown is complete.
# Will also exit if the first startsystem request fails.
# This means a call to "stopsystem" will behave the same as "shutdown"
# If this is false, then "stopsystem" will shutdown child processes,
# but dcf_sysmgr will remain running.
#
exit_after_system_stopped = YES
#
# Name of system configuration to auto-start
# e.g. file:C:/Program Files/DCF_3.1.3a/cfg/systems/store_server_win32.cfg
# or /systems/ndcds_server_win32.cfg
# In the latter case, CFGDB will look under the directory indicated by the
# DCF_CFG environment variable.
#
#auto_start_system_cfg =
reserved = 0
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 137
#
[ system_info ]
name = < name of system >
description = < description of this system >
#
# If the platform attribute is present, then the
# current platform (given by $DCF_PLATFORM)
# must match one of the attribute values. This is
# currently only used by the DCF service web pages
# to filter which system configurations are shown.
# see DCF_ROOT/platforms.cfg for a complete list
# of defined platforms.
#
platform = <first supported platform>
platform = <next supported platform>
…
#
# Any environment variables in the "environment" group
# are inherited by processes started by dcf_sysmgr.
# example attribute in environment group:
# DCF_ROOT = C:\LBS\DCF
[ environment ]
<env_var_name_1> = <value 1>
…
#
# List of processes that are run as part of the system startup sequence.
# Each value for the "process" attribute is a group name for
# a process configuration group below.
#
# The processes are started in the same order as the attribute values.
#
[ startup ]
process = <name of first startup process>
process = <name of next startup process>
…
#
# List of processes to run (for type=utility), or to stop (for
# server procs that from the [startup] group) as part of the
# system shutdown sequence.
#
# If one of these entries is a utility process, it is run in the
# foreground. If it is a server process, it must correspond to
# a server process from the startup group, in which case it
# is issued a shutdown or terminate request as appropriate.
#
# Processes are run/stopped in the same order as the attribute
# values.
#
[ shutdown ]
process = <name of first shutdown process>
process = <name of next shutdown process>
…
#=====================================================
# Per Process configuration settings:
#=====================================================
# Each Process group referenced by either the "startup" or
# "shutdown" groups has the following format:
#
# The group name is the string in the startup or shutdown group
# e.g. "dcf_store_scp.001"
#
#=====================================================
[ <process_name> ]
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 138
# Process type:
# utility : runs in the foreground. System Manager will execute
# this process and wait for its termination.
#
# dcf_server : A DCF server, i.e., one that is expected to send
# register_application and application_ready messages, and can
# accept shutdown messages.
# Server processes are run in the background.
# The next process will not be started until this process
# completes its start up sequence - i.e., sending
# register-app and then app-ready.
#
# server2 : A non-DCF server, i.e., some other app that is not
# DCF system manager aware.
# server2 processes are run in the background. The next
# process is started immediately after starting one of these.
#
# server : synonym for dcf_server. ("server" is used for compatibility
# with old versions of dcf_runsystem.pl.)
#
# Required attribute
#
type = utility | server | server2 | dcf_server
#
# For a utility process, the exit code that is expected.
# If you do not care about the exit code, use the special
# value "IGNORE_RETURN".
# Otherwise, if the exit code does not match the expected, the
# system will shutdown. If this occurs during shutdown,
# an error is logged, and shutdown continues.
#
# Default value = 0
#
expected_exit_code = <decimal number> | IGNORE_RETURN
#
# For a utility process, the number of seconds after starting
# to wait for termination.
# If this time is exceeded during startup, the system will shutdown.
# If this time is exceeded during shutdown, the utility is
# terminated, and shutdown continues.
# This timeout is used when utility processes are run either
# as part of the startup or shutdown sequence.
#
# Default value = 30
#
wait_timeout_seconds = <seconds>
#
# For a server or dcf_server process, the number of seconds
# to wait after starting the process for the register_application
# message.
# If this time is exceeded, the system will shutdown.
#
# Default value = 15
#
register_app_timeout_seconds = <seconds>
#
# For a server or dcf_server process, the number of seconds
# to wait after receiving the register_application
# message for the application_ready message.
# If this time is exceeded, the system will shutdown.
#
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 139
# Default value = 15
#
app_ready_timeout_seconds = <seconds>
#
# Number of seconds after starting a server2 process or after
# receiving application_ready from a server or dcf_server process
# before the next process is started.
#
# Default value = 0
#
post_start_delay_seconds = <seconds>
#
# Number of seconds to wait for process termination after a
# shutdown request is issued to a dcf_server process.
# If this time is exceeded, the process is terminated and
# shutdown continues.
#
# Default value = 30
#
shutdown_timeout_seconds = <seconds>
#
# The program and command line arguments to run for this process.
#
# Required attribute
#
command = <command line>
#
# Name of file to which stdout and stderr for this process will
# be redirected.
#
# Default value is "$DCF_LOG/<process_name>.out.log"
#
# A future release may provide a special value that redirects
# the process' stdout/stderr to the dcf_sysmgr's stdout/stderr.
# We may also allow stdout and stderr to go to different files.
# Note this has nothing to do with output for the DCF logger or
# other logging interfaces.
#
stdout_name = <filename>
#
# What to do if the process terminates while the system is starting
# or running:
#
# shutdown_system : the system will be shutdown. This is a required process.
# ignore : do nothing. This process is optional.
# restart : (Not currently implemented - in a future release, the
# process will be restarted)
#
# Default value = shutdown_system
#
terminate_action = shutdown_system | ignore | restart
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 140
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 141
See the ex_hello_world example for a step-by-step example of running dcfmake.pl to create an
application that uses the DCF development environment.
(See Appendix G for information on simplifying the invocation of the Perl interpreter on Windows.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 142
Options may be abbreviated as long as there is no ambiguity – i.e., “–v” is OK and selects “–
verbose”, but “–c” is not OK, it must be either “–cf” or “–ct” to distinguish which option to select.
Any options following the optional '--' are passed directly to the make or Visual Studio’s command
line interface.
#================================================================================
# The build_info group is optional and contains settings that control dcfmake.pl
#================================================================================
[ build_info ]
# 1 if application configuration file should be created (default = 1)
# only valid for application type components
gen_app_cfg = 1
#
# 1 if generated Component Information instrumentation and config data
# should be generated (default=1)
#
gen_cinfo_code_and_data = 1
#
# 1 if makefile or VS project file should be created. Set to 0 for
# custom built (or built with IDE or other tool) build files.
#
gen_build_file = 1
#
# name of generated application configuration file
# (default is $DCF_USER_ROOT/devel/cfggen/apps/defaults/<name>)
# only valid for application type components
#
app_cfg_name =
#
# set if idl module name is different from component name
# only valid for idl_lib components
#
module_name =
#
# additional compiler options added to generated dsp files
#
win_cpp_options =
#
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 143
# additional linker options added to generated dsp files
#
win_link_options =
#
# additional compiler options added to generated makefiles
#
cpp_options =
#
# additional linker options added to generated makefiles
#
link_options =
#
# extension for generated C++ source files (default = .cpp)
#
cinfo_cc_file_ext =
#
# command to execute prior to generating files (default = none)
#
pre_gen =
#
# command to execute after generating files (before invoking make) (default = none)
#
post_gen =
#
# command to execute after invoking make (default = none)
#
post_make =
#
# create executables in this directory(default = $DCF_BINDIR)
# only valid for application type components
#
bin_dir =
#
# create public CInfo header files in this directory
# (default = ${DCF_USER_ROOT}/include/$cinfo->{component_name})
inc_dir
#
# create libraries in this directory(default = $DCF_LIBDIR)
# only valid for library type components
#
lib_dir );
= .
#
# This group defines debug settings.
#
[ debug_controls ]
# debug_flag = <short_name>, <bit_value>, <description>
debug_flag = df_TEST1, 0x10000, place holder for test 1 debug setting
debug_flag = df_TEST2, 0x20000, Do something cool
# list of other DCF components required. This will affect makefile or dsp files,
# as well as the generated application configuration file if any.
[ required_components ]
component = cpp_lib_pkg/DCFCore
component = cpp_lib/DCFUtil
component = cpp_lib/LOG_a
component = cpp_lib/APC_a
component = cpp_lib/CDS_a
component = idl_lib/DCDS
#==============================================================================
# per-instance information for the ex_hello_world component
#==============================================================================
[ ex_hello_world ]
debug_flags = 0x00000
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 144
#==============================================================================
# The following sections allow the customization of the generated default
# application configuration.
# After the application configuration is created,
# selected library component configuration settings can be overridden.
# Note that this affects the settings for that library only within the context
# of this application.
#==============================================================================
[ lib_cfg_overrides ]
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 145
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 146
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 147
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 148
lib/libxyz.so
devel/csrc/xyz/*.cpp shared library produced by linker
devel/csrc/xyz/*.h
devel/cfggen/components/cpp_lib/xyz
static data for this component
devel/csrc/xyz/cinfo.cfg
dcfmake
component information file
devel/csrc/xyz/xyzCInfo.cpp
devel/csrc/xyz/xyzCInfo.h
log/debug wrappers and component
include/xyz/*.h information object
public headers
include/xyz/xyzCInfo.h
public component information header
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 149
devel/csrc/abc/*.cpp
devel/csrc/abc/*.h bin/abc
executable produced by linker
c++ source files and private headers
devel/cfggen/components/
devel/csrc/abc/cinfo.cfg
cpp_app/abc
component information file
static data for this component
lib/libxyz.so
include/xyz/*.h
devel/csrc/abc/abcCInfo.cpp
typical compile/link dependancies,
devel/csrc/abc/abcCInfo.h
repeat for each library component dcfmake
log/debug wrappers and
required by abc
component information object
devel/cfggen/components/cpp_lib/xyz
instance configuration data for xyz -
repeat for each required library devel/cfggen/apps/defaults/abc
component application config file for abc
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 150
The name field “DicomImage” indicates the name of the class. For each module, the file of the same
name with an extension “.mod” in the current directory is read. As a module example, the file
ModalityLUT.mod contains the following:
#
# Modality LUT
#
element = 0028 3000
>element = 0028 3002
>element = 0028 3003
>element = 0028 3004
>element = 0028 3006
element = 0028 1052
element = 0028 1053
A module file contains a list of element tags. Similar to the notation in the actual DICOM standard, if an
element is a “sequence” or container type, then the elements below it are indented with a “>” character.
For a sequence within a sequence, the elements are preceded by “>>”, and so on.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 151
For each top-level element, for example 0028, 1052 (rescale intercept) in the Modality LUT module,
the following member functions are added to the DicomImage class definitions.
/**
* rescaleIntercept()
* get the Rescale Intercept element value
* from the DicomImage's data set.
* dicom tag = (0028, 1052)
* Throws DCSException if that element has not been set (not in dataset).
* Throws DCSException if element is not multi-valued.
* @return the data for this element
*/
const string &rescaleIntercept( void ) const
throw( DCSException );
/**
* rescaleIntercept()
* set a new value for the Rescale Intercept element.
* dicom tag = (0028, 1052)
* A copy of the input string will be made by the object. (using string's copy
* on write logic).
* @param data - string value
* @return nothing
*/
void rescaleIntercept( const string &data );
For elements that are sequences, a new class is generated to represent the sequence. Member functions
to get or set that sequence are also added to the containing class. For example, for the element 0028,
3000 (modality LUT sequence) in the Modality LUT module, the following member functions are
added to the DicomImage class definitions:
/**
* getModalityLutSequenceCount()
* return the number of items (data sets) in the
* ModalityLutSequence sequence
* dicom tag = (0028, 3000)
* @return the number of items in the given sequence or -1 if the
* element is not present in the data set
*/
INT32 getModalityLutSequenceCount() const;
/**
* modalityLutSequence()
* get the requested item (data set) from the
* Modality LUT Sequence sequence
* in the DicomImage's data set.
* dicom tag = (0028, 3000)
* The default item index is 0.
* The returned DicomDataSet can be assigned directly to
* a ModalityLutSequence object (which will make a copy of that data set).
*
* The data that is returned is still owned by this object
* and may not be deleted.
* If this object goes out of scope, or is otherwise deleted, the pointer
* will become invalid.
*
* @param n the index of the sequence item (data set)to retrieve
* @return pointer to data set at the given index in the sequence, or NULL
* if the requested index is zero, and the sequence element exists, but is
* zero length.
* Throws DCSException if that element has not been set (not in dataset).
* Throws DCSException if the requested item is not present in the sequence
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 152
* (excepting case of requesting item 0, for a zero length sequence)
*
*/
DicomDataSet* modalityLutSequence( INT32 n=0 ) const
throw( DCSException );
/**
* modalityLutSequence()
* set a new value for the Modality LUT Sequence element.
* dicom tag = (0028, 3000)
* overwrites any existing element with tag E_MODALITY_LUT_SEQUENCE
*
* The sequence is created with one data set which is copied from
* the argument's data.
* @param data the ModalityLutSequence object from which the sequence data set will
* be copied.
* @return nothing
*/
void modalityLutSequence( ModalityLutSequence& data );
/**
* modalityLutSequence()
* set a new value for the Modality LUT Sequence element.
* dicom tag = (0028, 3000)
* overwrites any existing element with tag E_MODALITY_LUT_SEQUENCE
*
* The sequence is created with the data sets which are copied from
* each element of the argument vector.
* @param data the vector of ModalityLutSequence objects from which the sequence
* data set(s) will be copied.
* @return nothing
*/
void modalityLutSequence( std::vector<ModalityLutSequence>& data );
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 153
# group comment
[ group_name ]
# attribute comment
attrname = value
multival_attr_name = val_1
multival_attr_name = val_2
multival_attr_name = val_3
multi_line_attr = aaaaaaaaaaaaaaaaaaaaaaaaa \
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\
cccccccccccccccccccccccccccccccccccccccccc
[ group_name/sub_group_name ]
attr = value
Notice that there is no CFGFile object. A file is represented as a CFGGroup. If the DCDS_Server is
used, file system directories are also represented as CFGGroup objects.
The full name of any CFGGroup or CFGAttribute includes the names of all of its parent objects, up
to some root, separated with the “/” character.
The DCDS_Service allows an arbitrary collection of directories and configuration files to appear as a
single hierarchy of CFGGroup and CFGAttribute objects. From the programmers’ perspective there
is a simple hierarchical object database. Since the persistent storage for this data is simply directories
and text files, maintenance procedures are simple and flexible.
An alternate implementation might use some other persistent representation (e.g., XML files, SQL DB
tables, Windows Registry, etc). As long as the CFGDB interface can provide the notion of a hierarchy
of groups and attributes, the underlying format is unimportant.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 154
Configuration files or CFGGroup objects are used throughout the DCF. Configuration data is normally
stored under the directory indicated by the DCF_CFG environment variable (usually
$DCF_ROOT/cfg). A configuration group name /apps/defaults/dcf_store_scu indicates the file
$DCF_CFG/apps/defaults/dcf_store_scu. To describe a file that is outside of the DCF_CFG
directory (and/or that will not be handled by the DCDS_Server), add the “file:/” prefix to the name. For
example:
dcf_pg –f file://tmp/image.cfg
indicates the file /tmp/image.cfg.
dcf_pg –f file:/image.cfg
indicates the file ./image.cfg.
dcf_filter –f file:/C:/temp/filter1.cfg
indicates the file C:\temp\filter1.cfg.
Perl scripts can access CDS data using the CFG*.pm modules located in $DCF_ROOT/lib/perl5.
In order to be notified when an object changes, a process must register as an observer of the object.
(Note that a process can be an observer of several objects, not just one, and that multiple processes may
be observing the same object.) This is done via the CFGDB method register(). When the object
changes, the process’s notify() method is called with the name of the object that changed. The
process may then read the updated value and proceed accordingly.
If the process is observing changes in a CFGAttribute, it will be notified when that attribute changes.
Processes may also observe changes in CFGGroups. In this case, they will be notified if a change occurs
in the group or in any of the group’s sub-groups and attributes, including in sub-groups of those sub-
groups, and so on.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 155
[ tmp/status/status_info ]
device_xyz_status = NORMAL
device_abc_status = NORMAL
or
-appcfg file:/C:/temp/my_custom_cfg
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 156
Note that some programs may require additional configuration data. For example,
ex_nprint_client or ex_nstore_client can take a job configuration on their command line.
[ required_components ]
component = cs_lib/ABC
component = cs_lib/DEF
component = cs_lib/XYZ
[ cs_app ]
[ cs_app/my_scp_program ]
debug_flags = 0
my_cfg_1 = xxxxxx
my_cfg_2 = xxxxxx
[ cs_lib ]
[ cs_lib/ABC ]
debug_flags = 0
abc_cfg_1 = xxxxxx
[ cs_lib/DEF ]
debug_flags = 0
def_cfg_1 = xxxxxx
[ cs_lib/XYZ ]
debug_flags = 0
xyz_cfg_1 = xxxxxx
Will override the value for the attribute server_tcp_port in the group
cs_lib/DCS/AssociationManager.
The process configuration can optionally be written to the CFGDB data base. The default CFGDB
name for this will be “/procs/<base-name-of-program-exe>.<process-id>”, e.g.,
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 157
“/procs/dcf_print_scp.4355”
The proc cfg name can be specified on the command line using the -proccfg option, e.g.,
-proccfg /procs/dcf_store_scp.001
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 158
[ config_control ]
base = /apps/defaults/print_server
target = /apps/PrintSCP/PrintSCP1
remove_group = DCS/supported_sop_classes
[ DCS ]
[ DCS/scp_options ]
timeout = 30
[ DCS/supported_sop_classes ]
sopclass = 1.2.3.4
sopclass = 1.2.3.5
[ LOG_a ]
+output = /tmp/additional_log_output
[ DCS/scp_options ]
port = 3004
timeout = 10
max_concurrent_associations = 8
[ DCS/supported_sop_classes ]
sopclass = 1.2.3.4
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 159
sopclass = 1.2.3.5
sopclass = 1.2.3.6
sopclass = 1.2.3.7
[ LOG_a ]
debug_flags = 0
output = /tmp/logfile
[ DCS/scp_options ]
port = 3004
timeout = 30
max_concurrent_associations = 8
[ DCS/supported_sop_classes ]
sopclass = 1.2.3.4
sopclass = 1.2.3.5
[ LOG_a ]
debug_flags = 0
output = /tmp/logfile
output = /tmp/additional_log_output
The group DCS/supported_sop_classes which originally contained 4 attribute values was removed, and
replaced with the group containing 2 values.
The attribute timeout in the group DCS/scp_options was removed and replaced.
The attribute output in the group LOG_a was modified by adding a value. The original value was
preserved.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 160
Custom user interfaces can easily be designed to manipulate only those debug settings appropriate for a
particular use case.
LaurelBridge.APC_a.AppControl_a.setup(args, CINFO.Instance );
LaurelBridge.LOG_a.LOGClient_a.setup();
Each of these commands is explained further below. For the method calls which have an args
argument, args is a string array. For a command line program you would pass through the string array
passed into main from the command line to pass in parameters to custom implementations of our
common services. If you do not require any special parameters you can pass in some bogus array, e.g.,
string[] args = new string[0];
args[0] = stuff;
This call sets up the configuration database via .NET Remoting to the NDCDS_Server CFGDB Server.
The NDCDS_Server by default uses a filesystem database.
2. LaurelBridge.APC_a.AppControl_a.setup(args, CINFO.Instance )
This call sets up the Application Control component. AppControl manages and provides an API to
accessing an application’s configuration data at runtime, by default through the configuration database.
The second argument CINFO.Instance sets the application’s name and checks that any required
components for this application are located.
3. LaurelBridge.LOG_a.LOGClient_a.setup();
This call sets up the reference C# implementation of our LOG interface. LOG writes log files to text
files. It can also “rotate” log files based on size. You can create your own implementation of the LOG
interface to control logging, e.g., write to the event log, etc. In your app you would replace this call line
with something like:
OEMname.LOG_a.SystemLogger.setup();
Usually you at least want the Configuration Database (CFGDB) server running. You can launch it by
running ndcds_server from a command line. You could remove this requirement by adding the line:
LaurelBridge.CDS_a.CFGDB_a.FSysMode = true;
However, by making this choice, you will lose the ability to change logging levels and other
instrumentation while the process is running. You will have to restart the process to make changes to
these settings, which may not be practical in a production environment.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 161
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 162
# The maximum PDU size we wish to read. This is communicated to the # peer
device during association setup.
# (Network sessions only)
max_read_pdu_size = 32768
#
# The maximum PDU size we will write.
# (Network sessions only)
#
max_write_pdu_size = 32768
#
# For testing, max-length-negotiation can be ignored, allowing # apps to
write larger PDU’s than the remote AE expects. # (Network sessions only)
#
ignore_max_length_negotiation = NO
#
# The number of seconds DCF will wait for a single PDU to be # written to a
socket. -1 means wait forever. Note other timeouts # may prevent an
application from hanging.
# (Network sessions only)
#
pdu_write_timeout_seconds = -1
#
# If true, then pixel data is not fully buffered. Instead, blocks of # data
are read from the source and written to the destination of # a transfer as
needed. This enables very large data sets to be # transferred without
allocating large amounts of main memory. # Disabling this provides simpler
access to applications that # ultimately want all of the pixel data in
memory.
#
enable_streaming_mode = YES
#
# Size in bytes of buffers that are used for streaming mode transfers.
#
stream_mode_buffer_size = 16384
#
# Number of seconds that DicomSocket will delay before writing each #
outbound PDU. This can be useful for testing, to force a timeout condition, #
or to otherwise slow down data flow.
# (Network sessions only)
#
pdu_write_delay_seconds = 0
#
# Number of seconds that DicomSocket will delay before returning each #
inbound PDU. This can be useful for testing, to force a timeout condition, #
or to otherwise slow down data flow.
# (Network sessions only)
#
pdu_read_delay_seconds = 0
#
# debug support for forcing delays between PDU fragments # (Network sessions
only)
#
socket_write_delay_seconds = 0
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 163
# debug support for breaking PDU writes into multiple fragments
# (Network sessions only)
max_bytes_per_socket_write = 0
# name of extended data dictionary config group
extended_data_dictionary = /dicom/ext_data_dict
#
# Set flag to true if sequences should always be output with # undefined
length.
#
always_write_undef_length_seqs = YES
#
# Set flag to true if sequence items should always be output # with undefined
length.
#
always_write_undef_length_seq_items = YES
#
# Debug support for forcing end delimiters even for fixed length # sequences.
(some implementations incorrectly do this, and may expect it).
#
always_write_seq_end_delims = NO
#
# Debug support for forcing end item delimiters even for fixed length #
sequence items. (some implementations incorrectly do this, and may expect
it).
#
always_write_seq_item_end_delims = NO
#
# Number of seconds that AssociationAcceptor will wait for a message # before
sending an A-Abort-PDU to the Requester and ending the # association. -1
means wait forever.
#
association_idle_timeout_seconds = 600
#
# cmd line of program to be run at start of association
#
# The following variables will be added to the environment
# to be inherited by both the pre and post association scripts:
#
# CALLING_AE_TITLE (client DICOM AE name)
# CALLED_AE_TITLE (server DICOM AE name)
# CALLING_PRESENTATION_ADDRESS (client network addr from AssociationInfo)
# CALLED_PRESENTATION_ADDRESS (server network addr from AssociationInfo)
# DCF_ROOT (value of env var if any)
# DCF_USER_ROOT (value of env var if any)
# DCF_CFG (value of env var if any)
# DCF_TMP (value of env var if any)
# DCF_LOG (value of env var if any)
# PROC_CFG_NAME (name of proc configuration object if any)
#
pre_association_script =
#
# cmd line of program to be run at end of association
#
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 164
post_association_script =
#
# If set, we will not send out multiple pdv’s within a # single pdu. Some
implementations can not handle pdu’s # containing multiple pdv’s.
#
disable_multi_pdv_pdus = YES
#
# Name of input filter configuration group or file.
# For example “file:/C:/temp/some_filter_set.cfg”
# or “/dicom/filter_sets/example_set1” (which will be located # in CDS CFGDB
or beneath the $DCF_CFG directory.) # Incoming dimse messages are processed
by input filters.
#
# If this value is set, then the input_filters sub-group # shown below is
ignored.
#
input_filter_cfg_name =
#
# Name of output filter configuration group or file.
# Outgoing dimse messages are processed by output filters.
#
# If this value is set, then the output_filters sub-group # shown below is
ignored.
#
output_filter_cfg_name =
#
# Input filter configuration. Add one sub-group per filter.
#
[ DCS/default_session_cfg/input_filters ]
#
# Output filter configuration. Add one sub-group per filter.
#
[ DCS/default_session_cfg/output_filters ]
#
# Transfer syntaxes that will be accepted by an SCP. # The first
transfer_syntax in this group that also exists in the # proposed list will be
selected.
#
[ DCS/default_session_cfg/supported_transfer_syntaxes ]
# implicit-little-endian
transfer_syntax = 1.2.840.10008.1.2
# explicit-little-endian
transfer_syntax = 1.2.840.10008.1.2.1
# explicit-big-endian
transfer_syntax = 1.2.840.10008.1.2.2
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 165
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 166
#
default_association_config_name =
To change the base for UIDs that are generated by the DCF system edit the file:
$DCF_CFG/dicom/uid. An example of the text in that file is:
[ oem_info ]
uid_prefix = 1.2.3.4
uid_system_prefix = 192.131.14.4
The configuration attribute uid_prefix can be used to provide an organization wide prefix for UIDs,
containing perhaps your organization’s ANSI identifier. If this attribute is not present, the DCF will
establish the prefix.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 167
The attribute uid_system_prefix can be used to provide a per-host portion of each UID. If this attribute
is not present, the DCF will use a string based on the IP address of the system.
NOTE THAT IF YOU ARE USING PRIVATE IP ADDRESSES – e.g., 192.168.0.* – THE DEFAULT
IMPLEMENTATION MAY RESULT IN NON-UNIQUE UIDS.
When the DicomDataDictionary::makeUID() method is called, a uid is produced by combining
the results of DicomDataDictionary::getUIDPrefix() and
DicomDataDictionary::getUIDSuffix(). GetUIDPrefix() normally returns the concatenation
of the uid_prefix and uid_system_prefix strings. GetUIDSuffix() normally generates a suffix based
on an incrementing sequence number, combined with the current process ID.
By installing a custom DicomDataDictionary, any of the functions getUIDSuffix(),
getUIDPrefix() or initUIDPrefix() may be overridden by the user if an entirely different UID
generation algorithm is desired. For example, there may be a central UID factory implemented as a
COM or CORBA server. See the online documentation for DicomDataDictionary for more
information about this.
See the notes on UID generation in Appendix E: DCF Tech Note: DCF MakeUID Function.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 168
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 169
A typical OEM deployment plan for applications that do not ship with an installed license might look
something like the following:
1. Install the OEM application – this installation would include all appropriate DCF files, but no
DCF license key file (i.e., no systeminfo file).
2. An attempt to use a DCF component without a valid license present causes the DCF system to
write an error to the system console and exit. The OEM application should check for the
presence of a DCF license file and post some friendly message telling the end user how they can
purchase and install the appropriate license file to enable the desired DCF-based functionality.
Note: You may run the dcf_info utility command to check the validity of the installed license.
Running dcf_info –c produces “VALID” or “INVALID”; running dcf_info –C produces
a more verbose message. See the dcf_info usage statement for more information.
3. The end user orders and receives a license file, then installs it on their target system using the
license installation mechanism provided by the OEM.
4. The next time the end user runs the OEM application, the DCF license key is found and the
DCF-based functionality is available.
There are specific DCF related components that must be deployed to the target platform. These may
include portions of the following:
• Configuration information – the DCF configuration (CFG) database tree and its associated text
files (for more information about the DCF configuration database, see Section 9, Configuring
DCF Applications).
• O/S environment settings – appropriate O/S environment settings must be made. This may
involve setting environment variables that are read by the DCF libraries.
• O/S-specific dependent dll’s or libraries – ensure that the target contains all libraries required
by the O/S (e.g., a Windows application might require that the target platform has the .NET
framework installed, while a Linux application might require some GNU libraries).
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 170
• OEM application dependent dll’s or libraries – Running a dependency check on the OEM
executable to find the dependent libraries should show the minimal set of required libraries (e.g.,
on Windows, run dumpbin /dependents <filename>; on Linux run ldd <filename>).
These DCF related components are described more fully below:
Configuration information – DCF applications and components store their configuration
information in text files in the $DCF_CFG directory (usually $DCF_ROOT/cfg). Applications put
their files in the apps/defaults subdirectory, while components will have theirs in the appropriate
subdirectory under the components subdirectory: cpp_lib for C++ libraries, java_lib for Java
libraries, cs_lib for C# assemblies, etc. Applications that use DCF libraries and classes may need to
include the corresponding configuration files in a tree-structured directory hierarchy. It is important
to note that the DCF run-time license file must be included in the CFG database. Copy your run-time
license file to $DCF_ROOT/cfg/systeminfo and be sure your deployment includes this file.
O/S environment settings – The DCF often uses environment variables to specify the paths to
components. For example, the DCF_CFG variable may be set to indicate where the configuration
files are located – in fact, this environment variable usually must be set for proper operation of a
DCF-based application. Your installer may need to set this or other environment variables or settings,
or tell the user to set these configurations.
O/S-specific dependent dll’s or libraries – All applications use some libraries that are part of the
operating system and that did not come with the DCF toolkit. When deploying your application onto
a new system, you may have to include some of these libraries along with your application –
sometimes this is because that DLL (or library) does not exist on the target system, other times your
application may require a different version of the DLL than is already present on the system. These
dependencies can be determined by knowing what files your application and its components are
linking with. On Windows, this can be determined with the “dumpbin /dependents
<filename>” command; for Linux, you would use the “ldd <filename>” command. A Java app
would require that the target system have Java, JAI, and JAI_imageio installed and in its PATH.
Applications built with Microsoft Visual Studio 8 may need additional libraries to be installed in
order for them to operate correctly. Microsoft has provided the “VC 8.0 Redistributable” to install
updated versions of some C++ libraries, including the MSVCRT libraries (C run-time libraries). This
should be installed for VC8-based DCF applications. Additionally, applications built with Visual
Studio 7 or Visual Studio 8 may need to have the appropriate .NET Frameworks installed so that DCF
libraries can, if necessary, be installed into the Global Assembly Cache (GAC).
OEM application dependent dll’s or libraries – There are also the DCF libraries that the
application uses, and this must be included. The dependencies can be determined by the “dumpbin”
or “ldd” commands (as described above; see below for an example) for C++ applications.
For Java applications, the DCF dependencies are those libraries and classes that are imported. At a
minimum, that includes DCF_com_lbs_DCFUtil_OSUtil.dll, DCF_DCF_cl.dll and their
dependencies. An example showing this is included as Section 5.4: Deploying a Simple Standalone
DCF Java Application.
For C# applications, the DCF dependencies are those libraries and classes that are imported or
included for use by the application, including DCF_COM.dll and its dependencies.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 171
Note: the OEM must also include any libraries developed specifically for the OEM application to use.
MSVCR80.dll
MSVCP80.dll
omniORB407_rt.dll
omnithread32_rt.dll
DCF_DCFCore.DLL
DCF_LOG_a.DLL
DCF_CDS_a.DLL
DCF_APC_a.DLL
DCF_DDS_a.DLL
DCF_DCS.DLL
DCF_DSS.DLL
KERNEL32.dll
Summary
1000 .data
3000 .rdata
1000 .rsrc
2000 .text
C:\DCF-3.1.10c\bin>
Alternately, you might find the same information by using a program like “Dependency Walker”
(http://www.dependencywalker.com).
Troubleshooting application dependencies may be aided by the use of a freeware tool like FileMon for
Windows, which may be downloaded from:
http://www.sysinternals.com/utilities/filemon.html .
In their own words: FileMon monitors and displays file system activity on a system in real-time. Its advanced
capabilities make it a powerful tool for exploring the way Windows works, seeing how applications use the files and DLLs,
or tracking down problems in system or application file configurations.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 172
$ . ./dcf.env
[snip]
$ cd $DCF_ROOT/bin
$ ldd dcf_store_scp
libDCF_dcfcore.so => /home/dcfbuild/DCF/lib/libDCF_dcfcore.so (0x40018000)
libDCF_dcfutil.so => /home/dcfbuild/DCF/lib/libDCF_dcfutil.so (0x4005d000)
libDCF_log_a.so => /home/dcfbuild/DCF/lib/libDCF_log_a.so (0x40063000)
libDCF_dlog.so => /home/dcfbuild/DCF/lib/libDCF_dlog.so (0x40079000)
libDCF_apc_a.so => /home/dcfbuild/DCF/lib/libDCF_apc_a.so (0x40084000)
libDCF_dcf_cl.so => /home/dcfbuild/DCF/lib/libDCF_dcf_cl.so (0x4009b000)
libDCF_cds_a.so => /home/dcfbuild/DCF/lib/libDCF_cds_a.so (0x400b4000)
libDCF_dcds.so => /home/dcfbuild/DCF/lib/libDCF_dcds.so (0x400d3000)
libDCF_dds_a.so => /home/dcfbuild/DCF/lib/libDCF_dds_a.so (0x400ee000)
libDCF_dds.so => /home/dcfbuild/DCF/lib/libDCF_dds.so (0x400ff000)
libDCF_dcs.so => /home/dcfbuild/DCF/lib/libDCF_dcs.so (0x40104000)
libDCF_ddcs.so => /home/dcfbuild/DCF/lib/libDCF_ddcs.so (0x40286000)
libDCF_boost_regex.so => /home/dcfbuild/DCF/lib/libDCF_boost_regex.so (0x402dd000)
libDCF_dss.so => /home/dcfbuild/DCF/lib/libDCF_dss.so (0x4038e000)
libomniORB4.so.0 => /opt/omniORB-4.0.7/lib/libomniORB4.so.0 (0x00f75000)
libomnithread.so.3 => /opt/omniORB-4.0.7/lib/libomnithread.so.3 (0x0038b000)
libpthread.so.0 => /lib/i686/libpthread.so.0 (0x405e3000)
libstdc++.so.5 => /opt/gcc-3.2.2/lib/libstdc++.so.5 (0x405f8000)
libm.so.6 => /lib/i686/libm.so.6 (0x406b3000)
libgcc_s.so.1 => /opt/gcc-3.2.2/lib/libgcc_s.so.1 (0x406d6000)
libc.so.6 => /lib/i686/libc.so.6 (0x406df000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 173
;---------------------------------------------------------------------
# Write environment changes for the current user only
# !define ALL_USERS ; uncomment this if changes should be for all users
!include WriteEnvStr.nsh
;---------------------------------------------------------------------
!include ReplaceInFile.nsh
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 174
Name "DCF Filter"
;---------------------------------------------------------------------
; Indicate where additional libraries should be gotten from
…
;---------------------------------------------------------------------
; Version information
; (all these may be overriden on compilation with /D switches)
…
;---------------------------------------------------------------------
; Indicate the version of the product in the installer
…
;====================================================================
; Pages
;====================================================================
Page directory # Let the user choose where to install the app
Page instfiles # Install the files
UninstPage instfiles # on uninstall, remove the files
;---------------------------------------------------------------------
; The files to install
Section "" ;No components page, name is not important
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 175
; The appcfg must be included – this is the configuration file for the app
SetOutPath $INSTDIR\cfg\apps\defaults
File cfg\apps\defaults\dcf_filter
;---------------------------------------------------------------------
; This shows how to uninstall the application.
Section Uninstall
…
[remainder of file ommitted]
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 176
A
Abstract Syntax: A DICOM term which is identical to a DICOM SOP Class; it identifies a set of SOPs which, when
taken together, represent a logical grouping. An Abstract Syntax identifies one SOP Class or Meta SOP Class.
ACR: American College of Radiology.
Annotation Box: A DICOM name for annotation text printed on the film or other media.
ANSI: American National Standards Institute.
Application Entity (AE): A DICOM term for defining a particular user at an IP address.
Association: A DICOM term for a communication context which is used by two Application Entities that communicate
to one another.
Association Negotiation: The software handshaking that occurs between two DICOM Application Entities to set up an
Association.
Attribute: Each DICOM information object has its own set of characteristics or attributes. Each attribute has a name and
may have a value (see IOD), depending on its category.
B
Big Endian: A term for encoding data where the most-significant byte appears first and remaining bytes follow in
descending order of significance; sometimes known as “Motorola” format (see Little Endian). (The term is used
because of an analogy with the story Gulliver’s Travels, in which Jonathan Swift imagined a never-ending fight
between the kingdoms of the Big-Endians and the Little-Endians, whose only difference is in where they crack
open a hard-boiled egg.)
C
Calling (Requesting) AE Title: The name used by the receiver in a DICOM Association to indicate which Application
Entity it received the data from. It is the AE Title of the AE that is initiating the transfer.
Called (Receiving) AE Title: The name used by the sender in a DICOM Association to indicate which Application
Entity it wants to transmit its data to. It is the AE Title of the AE that is receiving the transfer.
Command Element: An encoding of a parameter of a command which conveys this parameter’s value.
Command Stream: The result of encoding a set of DICOM Command Elements using the DICOM encoding scheme.
Composite Information Object: A DICOM information object (see IOD) whose attributes contain multiple real world
objects.
Conformance: Conformance in the DICOM sense means to be in compliance with the parts of the DICOM Standard.
Conformance Statement: A document whose organization and content are mandated by the DICOM Standard, which
allows users to communicate how they have chosen to comply with the Standard in their implementations (see
Section 8).
Combined Print Image: a pixel matrix created by superimposing an image and an overlay, the size of which is defined
by the smallest rectangle enclosing the superimposed image and overlay.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 177
D
Data Dictionary: A registry of DICOM Data Elements which assigns a unique tag, a name, value characteristics, and
semantics to each Data Element (see the DICOM Data Element Dictionary in DICOM PS 3.6-2004).
Data Element: A unit of information as defined by a single entry in the data dictionary. An encoded Information
Object Definition (IOD) Attribute that is composed of, at a minimum, three fields: a Data Element Tag, a Value
Length, and a Value Field. For some specific Transfer Syntaxes, a Data Element also contains a VR Field where the
Value Representation of that Data Element is specified explicitly.
Data Set: Exchanged information consisting of a structured set of Attribute values directly or indirectly related to
Information Objects. The value of each Attribute in a Data Set is expressed as a Data Element.
Data Stream: The result of encoding a Data Set using the DICOM encoding scheme (Data Element Numbers and
representations as specified by the Data Dictionary).
DICOM: Digital Imaging and Communications in Medicine.
DICOMDIR File: A unique and mandatory DICOM File within a File-set which contains the Media Storage Directory
SOP Class. This File is given a single component File ID, DICOMDIR.
DICOM File: A DICOM File is a file with a content formatted according to the requirements of DICOM PS 3.10-2004.
In particular such files shall contain, the File Meta Information and a properly formatted Data Set.
DICOM File Format: The DICOM File Format provides a means to encapsulate in a File the Data Set representing a
SOP Instance related to a DICOM Information Object.
DICOM File Service: The DICOM File Service specifies a minimum abstract view of files to be provided by the
Media Format Layer. Constraining access to the content of files by the Application Entities through such a
DICOM File Service boundary ensures Media Format and Physical Media independence.
DIMSE: DICOM Message Service Element. This represents an abstraction of a common set of things that a user would
do to a data element, would likely use over and over, and would appear in various different contexts.
DIMSE-C: DICOM Message Service Element—Composite.
DIMSE-C services: A subset of the DIMSE services which supports operations on Composite SOP Instances related
to composite Information Object Definitions with peer DIMSE-service-users.
DIMSE-N: DICOM Message Service Element—Normalized.
DIMSE-N services: A subset of the DIMSE services which supports operations and notifications on Normalized SOP
Instances related to Normalized Information Object Definitions with peer DIMSE-service-users.
E, F
File: A File is an ordered string of zero or more bytes, where the first byte is at the beginning of the file and the last byte
at the end of the File. Files are identified by a unique File ID and may by written, read and/or deleted.
File ID: Files are identified by a File ID which is unique within the context of the File-set they belong to. A set of
ordered File ID Components (up to a maximum of eight) forms a File ID.
File ID Component: A string of one to eight characters of a defined character set.
File Meta Information: The File Meta Information includes identifying information on the encapsulated Data Set. It is
a mandatory header at the beginning of every DICOM File.
File-set: A File-set is a collection of DICOM Files (and possibly non-DICOM Files) that share a common naming space
within which File IDs are unique.
File-set Creator: An Application Entity that creates the DICOMDIR File (see DICOM PS 3.10, section 8.6) and zero
or more DICOM Files.
File-set Reader: An Application Entity that accesses one or more files in a File-set.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 178
File-set Updater: An Application Entity that accesses Files, creates additional Files, or deletes existing Files in a File-
set. A File-set Updater makes the appropriate alterations to the DICOMDIR file reflecting the additions or
deletions.
Film Box: A Normalized Information Object which is the DICOM name for the equivalent of a sheet of physical film.
Film Session: A Normalized Information Object which is the DICOM name for the equivalent of a typical “study” or
“series”.
G, H, I
Image Box: A Normalized Information Object which is the DICOM name for the equivalent of a typical “frame” or
“image”.
Information Object Class or
Information Object [Definition] (IOD): A software representation of a real object (e.g., CT Image, Study, etc.). An
Information Object is generally a list of characteristics (Attributes) which completely describe the object as far as
the software is concerned. The formal description of an Information Object generally includes a description of its
purpose and the Attributes it possesses.
Information Object Instance or
Instance (of an IOD): A software representation of a specific occurrence of a real object or entity, including values for
the Attributes of the Information Object Class to which the entity belongs..
J, K, L
Little Endian: A term for encoding data where the least-significant byte appears first and remaining bytes follow in
ascending order of significance; sometimes known as “Intel” format (see Big Endian).
LUT: Lookup Table.
M
Media Storage Application Profile: A Media Storage Application Profile defines a selection of choices at the various
layers of the DICOM Media Storage Model which are applicable to a specific need or context in which the media
interchange is intended to be performed.
Media Format: Data structures and associated policies which organizes the bit streams defined by the Physical Media
format into data file structures and associated file directories.
Media Storage Model: The DICOM Media Storage Model pertains to the data structures used at different layers to
achieve interoperability through media interchange.
Media Storage Services: DICOM Media Storage Services define a set of operations with media that facilitate storage
to and retrieval from the media of DICOM SOP Instances.
Message: A data unit of the Message Exchange Protocol exchanged between two cooperating DICOM Application
Entities. A Message is composed of a Command Stream followed by an optional Data Stream.
Meta Service-Object Pair (SOP) Class: a pre-defined set of SOP Classes that may be associated under a single SOP
for the purpose of negotiating the use of the set with a single item.
Meta SOP Class: A collection or group of related SOP Classes identified by a single Abstract Syntax UID, which,
when taken together, represent a logical grouping and which are used together to provide a high-level functionality,
e.g., for the purpose of negotiating the use of the set with a single item.
Module: A logical group of the valid attributes of DICOM information objects.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 179
N
NEMA: National Electrical Manufacturers Association.
Normalized Information Object: A DICOM Information Object (see IOD) whose attributes contain a single real world
object. Note: the differentiation of normalized versus composite information object definitions is not strongly
enforced in DICOM 3.0.
O, P
Physical Media: A piece of material with recording capabilities for streams of bits. Characteristics of a Physical Media
include form factor, mechanical characteristics, recording properties and rules for recording and organizing bit
streams in accessible structures
Presentation Context: A Presentation Context consists of an Abstract Syntax plus a list of acceptable Transfer
Syntaxes. The Presentation Context defines both what data will be sent (Abstract Syntax) and how the data are
encoded to be sent (Transfer Syntax).
Print Job SOP Class: A DICOM representation of a Print Job which consists of a set of IODs which describe a Print
Job and a set of services which can be performed on those IODs.
Print Management Service Class or
Print Service Class (PSC): A DICOM term for a logical grouping of Service Classes which all involve printing, also
referred to as Print Management Service Class (an example of a Meta SOP Class).
Printer SOP Class: A DICOM representation of a Printer which consists of a set of IODs which describe a Printer and a
set of services which can be performed on those IODs.
Protocol Data Unit (PDU): A data object which is exchanged by software protocol devices (entities, machines) within
a given layer of the protocol stack.
Q, R
Real-World Activity: Something which exists in the real world and which pertains to specific area of information
processing within the area of interest of the DICOM Standard. A Real-World Activity may be represented by one or
more SOP Classes.
Real-World Object: Something which exists in the real world and upon which operations may be performed which are
within the area of interest of the DICOM Standard. A Real-World Object may be represented through a SOP
Instance.
S
Secure DICOM File: A DICOM File that is encapsulated with the Cryptographic Message Syntax specified in RFC
2630.
Secure File-set: A File-set in which all DICOM Files are Secure DICOM Files.
Secure Media Storage Application Profile: A DICOM Media Storage Application Profile that requires a Secure File-
set.
Service Class: A group of operations that a user might want to perform on particular Information Objects. Formally, a
structured description of a service which is supported by cooperating DICOM Application Entities using specific
DICOM Commands acting on a specific class of Information Object.
Service Class Provider (SCP, Provider, Server): A device (DICOM Application Entity (DIMSE-Service-User))
which provides the services of a DICOM Service Class or Classes which are utilized by another device (SCU) and
which performs operations and invokes notifications on a specific Association.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 180
Service Class User (SCU, User, Client): A device (DICOM Application Entity (DIMSE-Service-User)) which utilizes
the DICOM Service Class or Classes which are provided by another device (SCP) and which invokes operations and
performs notifications on a specific Association.
Service-Object Pair (SOP) Class: the union of a specific set of DIMSE Services and one related Information Object
Definition (as specified by a Service Class Definition) which completely defines a precise context for
communication of operations on such an object or notifications about its state.
Service-Object Pair (SOP) Instance: a concrete occurrence of an Information Object that is managed by a DICOM
Application Entity and may be operated upon in a communication context defined by a specific set of DIMSE
Services (on a network or interchange media). A SOP Instance is persistent beyond the context of its
communication.
SOP Class: A DICOM term which is identical to an Abstract Syntax; it identifies a set of SOPs which, when taken
together, represent a logical grouping (see Meta SOP Class).
Storage Service Class (SSC): A DICOM term for a logical grouping of Service Classes which all involve storage of
images.
T
Tag: A unique identifier for an element of information composed of an ordered pair of numbers (a Group Number
followed by an Element Number), which is used to identify Attributes and corresponding Data Elements.
TCP/IP: Transmission Control Protocol / Internet Protocol.
Transfer Syntax: A part of the DICOM Presentation Context which specifies a set of encoding rules that allow
Application Entities to unambiguously negotiate the encoding techniques (e.g., Data Element structure, byte
ordering, compression) they are able to support, thereby allowing these Application Entities to communicate.
U
Unique Identifier (UID): A globally unique identifier (based on the structure defined by ISO 8824 for OSI Object
Identifiers) which is assigned to every DICOM information object as specified by the DICOM Standard (see
Section 2.1.1.4) and which guarantees global unique identification for objects across multiple countries, sites,
vendors and equipment.
V
Value Representation (VR): A VR is the defined format of a particular data element.
W, X, Y, Z
- End of Glossary -
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 181
Appendix B: Bibliography
The IHE Technical Frameworks are the detailed reference documents for implementing standards to
achieve successful data integration.
The IHE Technical Frameworks, available for download below, are a resource for
users, developers and implementers of healthcare imaging and information systems.
They define specific implementations of established standards to achieve effective
systems integration, facilitate appropriate sharing of medical information and support
optimal patient care. They are expanded annually, after a period of public review, and
maintained regularly by the IHE Technical Committees through the identification and
correction of errata.
Copies are available at: http://www.ihe.net/Technical_Framework/index.cfm.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 182
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 183
@ECHO OFF
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 184
Important: Print-SCP support is not available in all languages - e.g., to access print-scp in C# today,
one would need both the C++ dcf_print_scp and the Java PrinterServer code. These are
currently not included with the DCF C# toolkit.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 185
[ print_job_description/film_session ]
number_of_copies = 1
print_priority = HIGH
medium_type = BLUE FILM
film_destination = MAGAZINE
film_session_label = test1
memory_allocation = 0
owner_id = dcftest
film_box_count = 1
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 186
[ print_job_description/film_session/film_box_1 ]
image_display_format = STANDARD\1,1
annotation_display_fmt_id =
film_orientation = PORTRAIT
film_size_id = 14INX17IN
magnification_type = NONE
smoothing_type = NONE
border_density = 0
empty_image_density = 0
min_density = 0
max_density = 400
trim = YES
configuration_information = NONE
illumination = 0
reflected_ambient_light = 0
requested_resolution_id = HIGH
image_box_count = 1
annotation_box_count = 0
presentation_lut_count = 0
[ print_job_description/film_session/film_box_1/image_box_1 ]
image_position = 1
polarity = NORMAL
magnification_type = NONE
smoothing_type = NONE
configuration_information = NONE
requested_image_size = 0
reqd_decimatecrop_behavior = DECIMATE
overlay_box_count= 0
presentation_lut_count = 0
# name of image file
persistent_id = /DCF-3.1.10c/test/images/mr-knee.dcm
# transfer syntax of image file – leave blank for auto-detect
persistent_info = 1.2.840.10008.1.2
Enable the DIMSE Read/Write debug flags for the DCS library in the
/apps/defaults/dcf_print_scu application configuration using the web interface, or the
command:
cds_client saveattr /apps/defaults/dcf_print_scu/DCS/debug_flags
0x300000
Run the client with the new job configuration file
dcf_print_scu –f file:/print_job.cfg
Now, let’s create a filter set configuration to modify some field in the job. Save the following to a file,
filter1.cfg, for example.
[ filter_1 ]
filter_type = DICOM_ELEMENT_FILTER
[ filter_1/elements_to_match ]
# affected SOP class uid = Film Box
0000,0002 = 1.2.840.10008.5.1.1.2
# command field = N-Create-Rq
0000,0100 = 0x140
[ filter_1/elements_to_replace ]
2010,0040 = LANDSCAPE
That configuration specifies one filter of type DICOM_ELEMENT_FILTER, and that only messages that
contain the fields defined in the elements_to_match group will be filtered, which should be the N-
CREATE-RQ for FilmBox. Before that message is sent (or received, depending on how we install the
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 187
filters), the elements_to_replace group will indicate that the field 2010,0040 (orientation) should be
added or replaced with a new value.
Modify the configuration for the dcf_print_scu application to use this filter set for processing out-
bound messages – either edit the configuration file %DCF_CFG%\apps\defaults\dcf_print_scu,
and restart the system, or run the command:
cds_client saveattr
/apps/defaults/dcf_print_scu/DCS/association/output_filters/filter_set
_name file:/filter1.cfg
(If you want to affect incoming messages, add the filter set to the “input_filters” group.)
Run the application again, and note the DIMSE Message debug output:
dcf_print_scu –f file:/C:/temp/print_job.cfg
If you want to see the effect at the printer server back end, set the debug flags for the OEMPrinter
library component in the PrinterServer process using the web interface, or use the command:
cds_client saveattr /procs/PrinterServer.001/OEMPrinter/debug_flags
0x40000
Run the command again, then examine the printer_server log file.
Stop the print server system using the web interface or the command:
dcfstop.pl
Note: see the online documentation for C++ class LBS::DCS::DicomElementFilter for more
information about this object (to access the on-line docs: from the DCF Remote Service Interface, click
on “docs”, then “C++ docs”, “namespace list”, “DCS”, and finally “DicomElementFilter”).
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 188
[ filter_1/elements_to_replace ]
0010,0010 = This^Is^Bogus
This will perform the rather ridiculous action of adding a patient name DICOM attribute to any DIMSE
message that is sent.
Set this filter as the output filter set for the Java I/O library by running the following command (type as
one line!):
cds_client saveattr
/apps/defaults/ex_jecho_scu/java_lib/DCS/association/output_filters/fi
lter_set_name file:/sample_filter.cfg
Set the DIMSE Message debug flags for the Java I/O library using the web interface, or by running the
command:
cds_client saveattr
/apps/defaults/ex_jecho_scu/java_lib/DCS/debug_flags 0x300000
Run the Java SCU application:
jrun_example.pl com.lbs.examples.ex_jecho_scu.ex_jecho_scu StoreSCP1
localhost 2000
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 189
[filter_1/elements_to_match ]
0000,0100 = 0x30
[ filter_1/abort ]
Note: If you want this configuration to be available permanently, create the file in the directory
%DCF_ROOT%\devel\cfgsrc\dicom\filter_configs and then run update_cds.pl to
install it to %DCF_CFG%.
2. Start the configuration database server and supporting tasks using the web interface, or by running
the command:
dcf_start.pl –cfg %DCF_CFG%\systems\dcds_server_win32.cfg
3. Modify the Echo SCP application’s configuration so that it applies the defined filter set to received
messages.
cds_client saveattr
/apps/defaults/dcf_echo_scp/DCS/association/input_filters/filter_set_n
ame /dicom/filter_sets/abort_sample
Note: You could have accomplished the same thing prior to starting dcds_server by editing the
file %DCF_CFG%/apps/defaults/dcf_echo_scp and then adding the filter_set_name
attribute to the DCS/association/input_filters group:
[ DCS/association/input_filters ]
filter_set_name = /dicom/filter_sets/abort_sample
4. Start the Verification or Echo SCP from the command line. (Note that all other pre-built
dcf_*_scp applications support Verification, but we’re not running them now.)
dcf_echo_scp
5. In another command window, run the Echo SCU
dcf_echo_scu localhost 2000
You should see the echo client application fail with an error similar to the following:
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 190
[ ERROR(-1) 2004/08/05 17:14:28.721 dcf_echo_scu.25929/DCS thrd=2051
DicomSocket.cpp:464 ]
Error reading PDU:
DCSException:
IOException:
IOReadException:
DicomSocket: OS socket read or recv failed: end of file
file descriptor = 12
remote address = localhost:3004
local address = 127.0.0.1:51417
This error is returned because the application dcf_echo_scp intentionally called abort() when it got
the C-ECHO-RQ message and dcf_echo_scu logged an error like the one above when it failed to
successfully read (i.e., receive) a C-Echo-Response message.
In your application, you might use such a configuration to test that the appropriate user notification is
generated on such a failure.
Simulating other types of error conditions by this approach is especially useful in DICOM testing
activities.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 191
Job descriptions for DSS.StoreClient or DPS.PrintClient can be defined such that each
image or instance is processed with a different set of filters. In this case, the image filtering is
performed prior to association negotiation, and prior to the application of any output_filters defined by
the DicomSessionSettings.
Filters can be created by user code to filter a data set as it is read from a file, and then the filtered data
set can be given to some DCF SCU to send as is.
Note that filtering operations can be defined that can easily make an image invalid for a particular use.
For example, changing the SOP-CLASS-UID element in a C-Store-Request DIMSE message could
result in an image being received by an archive for what appears to be a SOP class that was not
originally negotiated.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 192
Each sub group defines one filtering operation. The filtering operations are performed in the following
order:
1. [ elements_to_copy ]
If this group is present, then only elements with tags contained in the cfggroup are “copied” from
input to output. All other elements in the input data are ignored and will not be copied to the output, i.e.,
this filter effectively removes all but the selected elements. If a tag is in the list of tags to copy, but is not
present in a particular data set, then nothing is done and this is not considered an error.
If this group is not present, the output data set starts as a full copy of the input data set.
2. [ elements_to_remove ]
If this group is present, then any elements with tags contained in the cfggroup are removed from
the output data set.
3. [ elements_to_remove_if_null ]
If this group is present, then any elements with tags contained in the cfggroup that have a zero
length value are removed from the output data set.
4. [ elements_to_replace ]
If this group is present, then each attribute defines a DICOM Element that will be created and added to
the output data set. If the element previously existed in the data set, it is overwritten with the new
element. (Note: this could be called elements_to_add_or_replace.)
5. [ elements_to_modify ]
If this group is present, it is searched for sub groups. Each sub group defines modification rules for a
single element in the output data set.
For example, consider the following CFGGroup:
[ elements_to_modify/1 ]
tag = 0010,0010
old_value = Smith^Joseph
new_value = Doe^John
new_case = U
move_to = 1111,2222
copy_to = 3333,4444
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 193
The filters that you use have the capability to record the changes made in the Original Attributes
Sequence (OAS). This can be used to create a “history” of the changes to the data resulting from the
filtering of the data – the sequence will have the original values of the elements that were changed.
How to enable this feature will be described below.
[ filter_1/elements_to_match ]
0010,0010 = Public^Jane^Q
[ filter_1/elements_to_remove ]
tag = 0028,0010
[ filter_1/elements_to_replace ]
0010,0010 = Doe^John
[ more_examples 1/elements_to_match ]
0010,0010 = Doe^John
[ more_examples 1/elements_to_copy ]
tag = 1111,1111
[ more_examples 1/elements_to_remove ]
tag = 1234,4321
[ more_examples 1/elements_to_remove_if_null ]
tag = 5678,9123
[ more_examples 1/elements_to_replace ]
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 194
0010,0010 = Bob
[ more_examples 1/elements_to_modify ]
[ more_examples 2 ]
filter_type = DICOM_ELEMENT_FILTER
filter_sub_type = copy filter
create_original_attributes_seq = TRUE
source_of_previous_values = ....
source_of_previous_values_tag_name = ....
reason_for_modification = COERCE
modifying_system = MyDCFBasedSystem
save_pixels_in_oas = FALSE
[ more_examples 2/elements_to_match ]
[ more_examples 2/elements_to_copy ]
tag = 0051,0051
tag = 0051,0052
[ more_examples 3 ]
filter_type = DICOM_ELEMENT_FILTER
filter_sub_type = remove filter
create_original_attributes_seq = TRUE
source_of_previous_values = ....
source_of_previous_values_tag_name = ....
reason_for_modification = COERCE
modifying_system = MyDCFBasedSystem
save_pixels_in_oas = FALSE
[ more_examples 3/elements_to_match ]
[ more_examples 3/elements_to_remove ]
tag = 1111,2222
[ more_examples 3/elements_to_remove_if_null ]
tag = 1111,3333
[ more_examples 4 ]
filter_type = DICOM_ELEMENT_FILTER
filter_sub_type = add/replace filter
create_original_attributes_seq = TRUE
source_of_previous_values = ....
source_of_previous_values_tag_name = ....
reason_for_modification = COERCE
modifying_system = MyDCFBasedSystem
save_pixels_in_oas = FALSE
[ more_examples 4/elements_to_match ]
0010,0010 = Doe^Jane
[ more_examples 4/elements_to_replace ]
0010,0010 = Public^Jane^Q
[ modify_filter_1 ]
filter_type = DICOM_ELEMENT_FILTER
filter_sub_type = modify filter
create_original_attributes_seq = TRUE
source_of_previous_values = ....
source_of_previous_values_tag_name = ....
reason_for_modification = COERCE
modifying_system = MyDCFBasedSystem
save_pixels_in_oas = FALSE
[ modify_filter_1/elements_to_match ]
[ modify_filter_1/elements_to_modify ]
[ modify_filter_1/elements_to_modify/0 ]
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 195
tag = 0010,0010
old_value = (.*)
new_value = $1
new_case = N/C
move_to = 1234,5678
[ modify_filter_1/elements_to_modify/1 ]
tag = 0010,0011
old_value = (.*)
new_value = $1
new_case = N/C
copy_to = 8765,4321
The file shows a set of filters; each of the top-level groups (indicated by square brackets) in the file is
an individual filter – “more_examples 1”, “more_example 2”, “modify_filter_1”, etc. Filters are often
grouped into sets for the convenience of chaining related operations together into one file, although you
could put each filter into its own file and process the data through each one individually. The filters in
a set are processed in order, with the results of each filter being used by the succeeding filters. (Note:
the names of the filters are not important; the filters are processed in the order that they are specified in
the file.)
At the top of each filter definition you can see the attribute-value pairs specifying that the original
attribute sequence should be created and populated with the changes made by each filter.
• create_original_attributes_seq – TRUE (or 1) to enable the OAS; FALSE or 0 disable
• save_pixels_in_oas – TRUE (or 1) if changes to the pixel data should be recorded in the
OAS
• source_of_previous_values – you can specify the source of previous values
• source_of_previous_values_tag_name – the name of the DICOM tag to read for the source of
the previous values
• reason_for_modification – defaults to COERCE, but you can set it to the other valid values
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 196
For elements to copy, remove, and remove if null, specify the tags that the operation should apply to;
note that the format is “tag = value”, for each tag that is required.
For elements to add/replace (the filter operation name is “elements_to_replace”), you specify the tag
and the tag’s new value; if the tag does not exist, it will be created with the new value.
For elements to modify, each element to modify is specified in another subgroup
(“modify_filter_1/elements_to_modify/0”, “modify_filter_1/elements_to_modify/1”, etc).
Each subgroup (0, 1, 2,…) indicates a tag and how the data in that tag should be modified.
• old_value – a regular expression to parse the data
• new_value – how the data should be rearranged or modified from the regex
• new_case – UC for uppercase, LC for lower-case, N/C to leave the case as-is
• move_to – move the data from this tag to the new tag
• copy_to – copy the data from this tag to the new tag
The Modify filter uses Perl-style regular expressions for its regex syntax.
To create a Pixel Value Shift Bits Filter, the filter definition should look like this:
[ pixel filter ]
filter_type = DICOM_PIXEL_VALUE_SHIFT_FILTER
[ pixel filter/elements_to_match ]
[ pixel filter/pixel_shift ]
shift_bits = 2
The shift bits determines how many bits to left-shift each byte or word (16-bit) sample in OB or OW
pixel data values; negative values indicate a right shift.
Note that “elements to match” can be specified to determine if the filter should be applied. Also note
that the shift_bits attribute is in the pixel_shift subgroup. (The OAS attributes have been omitted
here for clarity; if needed, they would be inserted directly beneath the filter_type attribute.)
The match_tag acts like a key to a hash of changes that should be made, based on that value; the
replace_tags indicate what tags should have their values replaced. mapping_cfg_name specifies the
full path of the file of mappings to search; mapping_cfg_format indicates the format of that file
(which must be CSV), and mapping_cfg_delimiter_char specifies the data delimiter character in the
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 197
file. no_match_option tells the filter what to do if the match tag’s value cannot be found in the
mapping file. (Note that in this example filter, the OAS is turned off.)
The Mapping List Filter is a complicated filter, so it deserves a little more explanation here. The
mapping list file is normally a plain text file with comma-separated values corresponding to the “match
tag” and the “replace tag” elements. The values are usually separated by commas, but you can also use
tabs, semi-colons, or other characters. Note that the delimiter character must be enclosed in quotes.
When this filter is applied, the match tag is checked against the “mapping key” values in the mapping
list file. If a match is found, the corresponding replace tag values are used to replace those tag values in
the data set being processed.
For example, let’s say that your “match tag” is 0008,0050 (Accession Number), your “replace tags” are
0020,000D [Study Instance UID] and 0010,0010 [Patient Name] (recall that you can have more than
one), and the data in your mapping list file is:
12345, 1.2.3.4.5, Doe^John
45678, 4.5.6.7.8, Public^Jane^Q
...
The first column in your mapping list file corresponds to the match tag (0008,0050), and the following
ones to the replace tags (0020,000D and 0010,0010).
If the match tag in a dataset passing through the filter has the value “12345”, then the Study Instance
UID would be replaced with “1.2.3.4.5” and the Patient Name with “Doe^John”; if the match tag has
the value “45678”, then the Study Instance UID would be replaced with “4.5.6.7.8” and the Patient
Name with “Public^Jane^Q”, and so on.
When specifying this filter you must also set the behavior when no matching “match tag” is found in
the mapping list file. There are three choices when no match is found:
• 0 – Reject the data set by aborting the association; the data set is not forwarded to the destination.
• 1 – Log a warning message and forward the filtered data set to the destination.
• 2 – Ignore the error and forward the filtered data set to the destination
If no item number is specified, the first item (#0) is assumed. You can also specify the last element in a
sequence by “#L” (upper-case is important!) if you don’t know how many items are in a sequence. If
you are creating new elements, you can specify the next item in the sequence via “#N” (again, case is
important) to append to the sequence. For example: 0080,0100.#L.0010,0010.#N.0008,0060
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 198
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 199
Tag Value
0010,0010 Public^Jane^Q
If you want to correct the element every time, even when the value is not “Public^Jane^Q” or the
element is not present at all, you would leave this table empty.
Secondly, you would specify the “elements to add/replace”:
Tag Value
0010,0010 Doe^John
You could configure the filter to be applied under certain conditions – i.e., when an element has a
certain value – by specifying the “elements to match” (as in the previous example); or you would leave
“elements to match” empty to apply the filter all the time.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 200
Example 3: Modifying an Element’s Value with Regular Expressions
The “elements to modify” portion of the Element Filter is designed to allow you to modify the value of
an element by using a regular expression (or a “regex”, as it is commonly called); the so-called “Modify
Filter” also allows you the option to move or copy one element’s data into other elements.
For example, suppose that your receiving software expects the patient’s name to be in your proprietary
DICOM tag “abcd,abcd”, but you are not getting that tag sent from the modalities. In addition,
suppose that the data has the first name first, instead of the DICOM default of last name first. You could
use the Modify Filter and regular expressions to switch the elements around and move it to the desired
tag.
First, you would specify for “elements to modify” the tag value for the standard DICOM Patient Name
tag:
Tag 0010,0010
Recall that this is part of a sub-group under “elements_to_modify”, in which you would specify the
tag and how the tag’s data should be modified.
Use old_value and new_value to define how the regular expression should modify the data. (An
explanation of regular expression syntax is beyond the scope of this document, but many fine examples
can be easily found on the Internet.) In this case, you would enter the following:
Old value ([^ ]*)\^([^ ]*)
New value $2\^$1
Second, to copy the modified result to your private tag as proposed in this example, you would enter
your proprietary tag – “abcd,abcd” – as the value for copy_to. The end result is that the order of the
first name and last name will be swapped, and the data will be copied to your tag.
Your text configuration file would look like this:
[ my_filter ]
[ my_filter/elements_to_modify ]
[ my_filter/elements_to_modify/0 ]
tag = 0010,0010
old_value = ([^ ]*)\^([^ ]*)
new_value = $2\^$1
new_case = N/C
copy_to = abcd,abcd
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 201
For C++ implementations, dynamic loading of OEM-provided filter implementations (in a user’s
named DLL, for example) is not currently supported. Instead, the OEM can create a custom
DicomFilterFactory subclass to their DCF based C++ application. The comment in
DCS/DicomFilterFactory explains this:
DicomInputFilter objects are created by the DicomFilterFactory by the createFilter() method. The
DicomFilterFactory is a singleton that can be extended by an OEM to allow custom filters to be
addedto the system.
The filter_class_name attribute specifies the Java class to be loaded by the DCF, while the
filter_editor_class attribute specifies the Java class that the Filter Set Editor should load to
permit a user to configure the filter. The filter configuration would also include whatever data is
necessary to define the filter’s operation.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 202
To use your custom filter editor GUI in the DCF Filter Set Editor, you would enter the name of the GUI
class when you are adding a new filter to a filter set (see above). The class you specify must be in the
CLASSPATH; for applets (including the Filter Set Editor applet), this means that the class must be
loaded in the JAR file along with the Filter Set Editor’s classes.
For more information, see the documentation for the class com.lbs.DCS.FilterEditorGUI.
The filter_class_name attribute specifies the C# class to be loaded by the DCF; the
filter_assembly_name specifies the assembly that has the class in it – the assembly is loaded first,
and the filter class is loaded from it. The filter configuration would also include whatever data is
necessary to define the filter’s operation.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 203
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 204
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 205
Appendix F: DCF Tech Note: Using Nunit tests with DCF .NET
Applications
What Is NUnit?: NUnit is a unit-testing framework for all Microsoft .Net languages, written entirely
in C#; NUnit brings xUnit capabilities to all .NET languages. (See http://www.nunit.org and the next
page for additional information.)
Here is the InitTest class. This will keep AppControl and other common services from being setup
multiple times.
using System;
using LaurelBridge.DCF;
namespace OEM_name
{
namespace SomeTest
{
public class InitTest
{
private static bool isInitialized_ = false;
public static AppControl apc_;
public static CFGDB cfgdb_;
private static string[] args_ = {"-appcfg",
"/apps/defaults/NAppControl_atest"};
public static void setup()
{
if( ! isInitialized_ )
{
try
{
LaurelBridge.CDS_a.CFGDB_a.setup(args_);
cfgdb_ = CFGDB.Instance;
LaurelBridge.APC_a.AppControl_a.setup(args_, CINFO.Instance);
apc_ = AppControl.Instance;
}
catch ( SystemException e )
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 206
{
System.Console.WriteLine( e );
}
isInitialized_ = true;
}
}
}
}
}
Please see the NUnit web site (http://www.nunit.org) for additional and the most current information on
this tool.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 207
The DCF uses many Perl scripts to simplify and to automate tasks that need to be done in the
development, testing, and deployment of an application. To use these scripts, Perl must be installed on
your system, and the Perl interpreter must be in your PATH. The Windows DCF includes a version of
Perl that can be used if you do not already have Perl installed; most versions of Linux come with Perl
already installed.
On Linux, the “shebang” line – “#!” – at the top of the script is sufficient to run the Perl interpreter
without explicitly invoking it on the command line. For example, you can type “dcfmake.pl” instead
of “perl dcfmake.pl”.
On Windows, you need to call the Perl interpreter explicitly – e.g., perl –S dcfstop.pl – unless there
is a Windows file association between the .pl file extension and the Perl interpreter. If the file
association exists, you may call dcfstop.pl and other Perl scripts just by using their names, without
invoking the Perl interpreter, e.g., dcfstop.pl.
If you do not have a Perl file association, the Perl interpreter looks for the script to run in the current
directory. You may also specify the script’s path explicitly – e.g., perl /home/mydir/myscript.pl –
or specify the “-S” flag to find the script in the PATH, e.g., perl –S dcfstop.pl
To create a Perl file association on Windows, enter the following commands in a DOS prompt, such as
the DCF Command Prompt:
• assoc .pl=Perl
• ftype Perl=<path to perl interpreter> “%1” %*
o Example: ftype Perl=”C:\Program Files\DCF-3.1.1a\perl\bin\perl.exe”
“%1” %*
Note that most of the example invocations of Perl scripts throughout this guide assume that such a file
association exists, or the explicit invocation of Perl is omitted for the sake of simplicity and brevity.
Note that on Windows platforms that in order to do I/O redirection the Perl interpreter must be
explicitly invoked, e.g. “perl –S dcfmake.pl > make.txt 2>&1”
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 208
If the CGI is being used to set the values of the debug flags, the data is passed to the CGI through its
STDIN. (For HTML viewed in a web browser, this means that the data is passed via the POST
method.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 209
Each shortcut group can also have the optional attribute df_linked_to. This attribute can have multiple
values. If this attribute is set with the name(s) of another shortcut group, when the first group is
selected on the generated web page, the other group(s) will also be selected. This provides a way of
suggesting that certain debug flags should be set when other flags are set, while allowing the user to
disable those flags if they are not desired.
An example shortcut group is shown below:
app_name = /apps/defaults/dcm_switch
proc_name = /procs/dcm_switch
name = Show DICOM Association information
component_name = DCS
component_type = cpp_lib
df_name = df_SHOW_GENERAL_FLOW
df_linked_to = 5
These attributes are put together to determine the complete name of the debug flag to set/unset. Please
note that when the flag is modified, it can be changed in both the application’s configuration file and in
every process instance of the application that is running – you cannot change the flag in one instance of
an application but not another. Checking the “Save these settings for next time” box will change the
debug flags in the application’s configuration data as well as in any matching processes. (The
processes’ debug flags are always changed.) When this group is selected, the shortcut group named “5”
will also be selected.
The above example would load the attribute /components/cpp_lib/DCS/debug_controls/debug_flag,
find the value for the debug flag df_SHOW_GENERAL_FLOW, and modify it in the attribute
/apps/defaults/dcf_switch/cpp_lib/DCS/debug_flags and in
/procs/defaults/dcf_switch.*/cpp_lib/DCS/debug_flags.
Note that it is possible for the df_name value to have multiple debug flags, separated by colons (‘:’).
This allows for multiple flags to be enabled/disabled in one shortcut. One caveat of this is that if a
group sets a flag that was unset by a previous group, the flag will be set.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 210
[ debug_shortcuts ]
heading = DCM Switch
[ debug_shortcuts/7 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show DICOM Association information
component_name = DCS
component_type = cpp_lib
df_name = df_SHOW_GENERAL_FLOW
[ debug_shortcuts/1 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show ACSE PDUs
component_name = DCS
component_type = cpp_lib
df_name = df_DUMP_ACSE
[ debug_shortcuts/3 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show PDU summaries
component_name = DCS
component_type = cpp_lib
df_name = df_DUMP_PDATA
[ debug_shortcuts/4 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show verbose PDU data
component_name = DCS
component_type = cpp_lib
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 211
df_name = df_DUMP_PDATA_VERBOSE
df_linked_to = 1
df_linked_to = 3
[ debug_shortcuts/5 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show DIMSE reads/writes
component_name = DCS
component_type = cpp_lib
df_name = df_SHOW_DIMSE_READ:df_SHOW_DIMSE_WRITE
df_linked_to = 1
[ debug_shortcuts/6 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Show TCP/IP network related debugging
component_name = DCS
component_type = cpp_lib
df_name = df_TCP_NETWORK
df_linked_to = 5
[ debug_shortcuts/2 ]
app_name = /apps/defaults/dcf_switch
proc_name = /procs/dcf_switch
name = Enable ADVT Logging
component_name = DCS
component_type = cpp_lib
df_name = df_LOG_ADVT_FORMAT
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 212
If the CGI is being used to set the values of attributes, the data is passed to the CGI through its STDIN.
(For HTML viewed in a web browser, this means that the data is passed via the POST method.)
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 213
There are two attributes that are mandatory – they are required by all CDS shortcut groups.
1. type – This is the type of the shortcut, and determines how the group will be processed and
displayed.
2. desc – This is the text that will be displayed for the shortcut; it describes the shortcut.
Most groups will also require the attribute attribute_name – this is the full path of the CDS attribute to
be retrieved/modified.
As each group is parsed, it will be put into a bulleted list of shortcuts on the generated page. Each
shortcut will be put on the page in the order that it is in the cds_shortcuts group. Each group can have
any name, but the name must be unique in the cds_shortcuts group.
3.1.1.1. title
This type of group is used to display a heading on the page. The description (“desc”) attribute of the
group will be displayed in an <H2> tag. This item will not be bulleted, but it will be indented since it is
contained in the enclosing <UL> tag for the list.
Required attributes: type, desc
Example:
type = title
desc = DPA Configuration Data
When the data is updated, this will be displayed on the page, but it cannot be modified.
3.1.1.2. html
This type of group is used to display HTML on the page, allowing the user to add some customization
to the display of the page. The text of the HTML to be inserted into the page is contained in the desc
attribute – note that this means that the lines of HTML text must be continued with a backslash (“\”) if
there is more than one line to display. This item will not be bulleted, but it will be indented since it is
contained in the enclosing <UL> tag for the list.
Required attributes: type, desc
Example:
type = html
desc = <hr>\
<center><img src=”/world1.gif”></center> \
<hr>
This example will display the image file world1.gif, centered between two lines.
When the data is updated, this will be displayed on the page, but it cannot be modified.
3.1.1.3. display_only
This type of group retrieves the value of a specified attribute from the CDS database and displays it in
<PRE> tags on the page.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 214
Required attributes: type, desc, attribute_name
Example:
type = display_only
desc = DPA TCP port
attribute_name = /apps/defaults/dcf_switch/cpp_lib/DCS/AssociationManager/tcp_port
When the data is updated, this will be displayed on the page, but it cannot be modified.
3.1.1.5. boolean
This type will display a checkbox to simplify enabling/disabling the attribute. This type also requires
the attributes on_value and off_value – these are used to determine if the checkbox should be checked
when the value is displayed, and what the value should be set to when the box is changed. (A Boolean
value cannot have multiple values, so multiplicity is ignored.)
Required attributes: type, desc, attribute_name, on_value, off_value
Example:
attribute_name = /apps/defaults/dcf_switch/cpp_app/dcf_switch/enable_statistics
type = boolean
desc = Enable statistics
on_value = yes
off_value = no
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 215
does not recognize the disabling of the input [as older browsers may do], the data will be ignored and
not updated when the form is processed.)
This will cause both CFGDB attributes specified by sync_attributes to get the same value as the
primary attribute – if the main one is set to 20000, those two will also be set to 20000 at the same time.
If you are setting a Boolean attribute, you have additional options that you can specify: sync_on_value
and sync_off_value. If the Boolean attribute is set, then the sync_on_value is used for any
sync_attributes specified; if the Boolean attribute is unset, then the sync_off_value will be
used. If either of sync_on_value or sync_off_value are unspecified, then the
sync_attributes will get the same value as the primary attribute.
Consider this example:
attribute name = /apps/defaults/dcf_switch/cpp_app/dcf_switch/enable_statistics
type = boolean
desc = Enable statistics
on_value = yes
off_value = no
sync_attributes = /apps/dcf_switch/dcf_switch/cpp_app/dcf_switch/enable_statistics
Since sync_on_value and sync_off_value are not specified, the sync_attributes will be
turned on and off exactly the same as the primary attribute.
Consider another example:
attribute_name = /apps/defaults/dcf_switch/cpp_app/dcf_switch/enable_statistics
type = boolean
desc = Enable statistics
on_value = yes
off_value = no
sync_attributes = /apps/dcf_switch/dcf_switch/cpp_app/dcf_switch/enable_statistics
sync_on_value = false
sync_off_value = true
In this case, the sync_attributes will be set to “false” when the primary attribute is set to “yes”,
or to “true” when the primary is set to “no”. Any values can be used – the values for the
sync_attributes could be “1” and “5”, “Peter” and “Mary”, or whatever you desire, set in sync
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 216
with the primary attribute. This capability also allows you to toggle settings together – as you can see
in this example, one attribute is set to a positive value when the other is negative, and vice versa.
This list is easily viewed at the top of DCFGenStartCfg.pm should the list need to be changed. Each
server is also given a title attribute within the shortcut file, to clearly indicate what server is being
configured by each set of attributes.
As the startup configuration is parsed, the application configuration group for each server is
determined, and shortcuts are set up for the common attributes in that appconfig. If an attribute does
not exist, the shortcut is omitted.
Some servers may have attributes that need to be set but that are not part of the common nine listed
above. In this case, special parameters may be set up in the server’s per-instance application
configuration group describing these attributes; these are listed as multiple values of the
“special_params” attribute. For example, special parameters for the DLOG_Server, using its default
appconfig, would be in the configuration attribute
/apps/defaults/DLOG_Server/java_app/DLOG_Server/special_params.
Each value should be a semi-colon separated list of items describing the desired shortcut, in this order:
type, description, subgroup, attribute_name, multiplicity, width, height,
on_value, off_value, read_only. Subgroup and attribute_name are combined by the module
to create the complete name of the attribute to be configured; the values of the other fields are as
described earlier in this document. If a field is not applicable to a certain shortcut type, it may be
omitted and will be ignored, but its place should be indicated by the semi-colon separator.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 217
Example:
special_params = integer;TCP Port;
java_app/DLOG_Server/output_configuration_info;
server_port_number;single;6;;;;
(Note: All of this text would be on one line.)
In addition, each server group in the startup configuration file may have special parameters that should
be configured for that specific startup configuration. This is indicated via the special_params attribute
in the server’s startup group. The format is the same as for the other special_params attribute, except
that this one has the name of the appconfig to use at the beginning.
Example:
special_params = /apps/defaults/DCDS_Server;boolean;
Enable upward notifications;java_app/DCDS_Server;
enable_upward_notifications;single;;;YES;NO;true
The shortcut configuration file is generated upon startup of the system, and a link is provided on the
DCF Operations page to configure the servers via this shortcut file.
[ cds_shortcuts/1 ]
attribute_name = /apps/defaults/dcf_switch/cpp_lib/DCS/AssociationManager/tcp_port
multiplicity = single
type = integer
desc = DPA TCP port
width = 5
[ cds_shortcuts/2 ]
attribute_name = /apps/defaults/dcf_switch/cpp_lib/LOG_a/use_log_server
type = boolean
read_only = true
desc = DPA connects to DLOG_Server
on_value = true
off_value = false
[ cds_shortcuts/3a]
attribute_name = /test2.cfg/required_components/component
type = display_only
desc = test2.cfg required component list
[ cds_shortcuts/3 ]
attribute_name = /test2.cfg/required_components/component
multiplicity = multiple
type = string
read_only = true
desc = Required components for test2.cfg
width = 40
height = 5
[ cds_shortcuts/log_server_flag ]
attribute_name = /apps/defaults/dcf_switch/cpp_lib/LOG_a/use_log_server
multiplicity = single
type = string
desc = Log server flag as string
width = 7
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 218
[ cds_shortcuts/title_2 ]
type = title
desc = Echo server
[ cds_shortcuts/html_1 ]
type = html
desc = <hr> \
<center><img src="/world1.gif"></center> \
<hr>
[ cds_shortcuts/echo_server_mode ]
attribute_name = /apps/dcf_switch/dcf_echo_scp/cpp_app/dcf_echo_scp/one_shot_mode
type = boolean
desc = Echo server one-shot mode
on_value = yes
off_value = no
[ cds_shortcuts/continued_line_test ]
desc = line with continuation characters
attribute_name =
/test3.cfg/testapp/another_group/level3/level4/level5/level6/level7/level8/level9/attr1
type = string
multiplicity = single
width = 60
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 219
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 220
appropriate permissions; it is also possible to configure the access restrictions so that some users could
access certain sections but not other sections.
The steps described below will allow you to require authentication to access the DCF’s web pages.
(Please note that these steps are valid only for the DCF’s version of Apache, v1.3.33; if you are using a
different web server, the steps will be similar but not identical.)
You must create the password file to use if it does not already exist. From outside the httpd docs
tree (for example, at DCF_ROOT), run
htpasswd -c %DCF_ROOT%\dcf_passwords <username>
This will create the password file “dcf_passwords”. (The file should be created outside the web
server root so that it is not accidentally served up by the web server.)
You will be prompted for a password for the user, and required to type it twice. Once the password
file exists, you should omit the “-c” flag. (The “-c” flag is only for creating the file the first time; if
you use it and the file exists, then you will create a new file, overwriting the existing one, and you
will lose any user info in the original file.)
For subsequent users that need to be added or to change the passwords of existing users, run the
command
htpasswd %DCF_ROOT%\dcf_passwords <username>
3. Modify the httpd.conf file (in %DCF_ROOT%/httpd/conf) to allow the .htaccess file to override
some options.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21
Page 221
You should do this for each “<Directory>” section in the httpd.conf file that has a directory you
wish to protect. Thus, to require authentication for all DCF web pages, you would modify the
“<Directory>” section in the file that corresponds to %DCF_ROOT%/httpd/html, and change the
value AllowOverride in those sections from “none” to “AuthConfig”.
If you wish to restrict access to the CGI scripts, find the “<Directory>” section for the cgi-bin
directory (%DCF_ROOT%/httpd/cgi-bin) and change AllowOverride from None to AuthConfig.
This will (obviously) stop the DCF’s Apache web server. Restart the server by running the
command
perl run_apache.pl
For more information about authenticating users and additional measures you can use, see
http://httpd.apache.org/docs/1.3/howto/auth.html
For example, this page can show you how to configure the Apache web server so that it can be accessed
only from your internal network.
DCF - Developers Guide Copyright 2008, Laurel Bridge Software, Inc. All Rights Reserved v 2.21