Class: DICOM::DClient

Inherits:
Object
  • Object
show all
Includes:
Logging
Defined in:
lib/dicom/d_client.rb

Overview

This class contains code for handling the client side of DICOM TCP/IP network communication.

For more information regarding queries, such as required/optional attributes and value matching, refer to the DICOM standard, PS3.4, C 2.2.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging

included, #logger

Constructor Details

#initialize(host_ip, port, options = {}) ⇒ DClient

Note:

To customize logging behaviour, refer to the Logging module documentation.

Creates a DClient instance.

Examples:

Create a client instance using default settings

node = DICOM::DClient.new("10.1.25.200", 104)

Parameters:

  • host_ip (String)

    the IP adress of the server which you are going to communicate with

  • port (Integer)

    the network port to be used

  • options (Hash) (defaults to: {})

    the options to use for the network communication

Options Hash (options):

  • :ae (String)

    the name of this client (application entity)

  • :host_ae (String)

    the name of the server (application entity)

  • :max_package_size (Integer)

    the maximum allowed size of network packages (in bytes)

  • :timeout (Integer)

    the number of seconds the client will wait on an answer from a server before aborting (defaults to 10)



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/dicom/d_client.rb', line 44

def initialize(host_ip, port, options={})
  require 'socket'
  # Required parameters:
  @host_ip = host_ip
  @port = port
  # Optional parameters (and default values):
  @ae =  options[:ae]  || "RUBY_DICOM"
  @host_ae =  options[:host_ae]  || "DEFAULT"
  @max_package_size = options[:max_package_size] || 32768 # 16384
  @timeout = options[:timeout] || 10 # seconds
  @min_length = 12 # minimum number of bytes to expect in an incoming transmission
  # Variables used for monitoring state of transmission:
  @association = nil # DICOM Association status
  @request_approved = nil # Status of our DICOM request
  @release = nil # Status of received, valid release response
  @data_elements = []
  # Results from a query:
  @command_results = Array.new
  @data_results = Array.new
  # Setup the user information used in the association request::
  set_user_information_array
  # Initialize the network package handler:
  @link = Link.new(:ae => @ae, :host_ae => @host_ae, :max_package_size => @max_package_size, :timeout => @timeout)
end

Instance Attribute Details

#aeObject

The name of this client (application entity).



13
14
15
# File 'lib/dicom/d_client.rb', line 13

def ae
  @ae
end

#command_resultsObject (readonly)

An array, where each index contains a hash with the data elements received in a command response (with tags as keys).



25
26
27
# File 'lib/dicom/d_client.rb', line 25

def command_results
  @command_results
end

#data_resultsObject (readonly)

An array, where each index contains a hash with the data elements received in a data response (with tags as keys).



27
28
29
# File 'lib/dicom/d_client.rb', line 27

def data_results
  @data_results
end

#host_aeObject

The name of the server (application entity).



15
16
17
# File 'lib/dicom/d_client.rb', line 15

def host_ae
  @host_ae
end

#host_ipObject

The IP adress of the server.



17
18
19
# File 'lib/dicom/d_client.rb', line 17

def host_ip
  @host_ip
end

#max_package_sizeObject

The maximum allowed size of network packages (in bytes).



19
20
21
# File 'lib/dicom/d_client.rb', line 19

def max_package_size
  @max_package_size
end

#portObject

The network port to be used.



21
22
23
# File 'lib/dicom/d_client.rb', line 21

def port
  @port
end

#timeoutObject

The maximum period the client will wait on an answer from a server before aborting the communication.



23
24
25
# File 'lib/dicom/d_client.rb', line 23

def timeout
  @timeout
end

Instance Method Details

#echoObject

Tests the connection to the server by performing a C-ECHO procedure.



71
72
73
74
75
# File 'lib/dicom/d_client.rb', line 71

def echo
  # Verification SOP Class:
  set_default_presentation_context(VERIFICATION_SOP)
  perform_echo
end

#find_images(query_params = {}) ⇒ Object

Note:

Caution: Calling this method without parameters will instruct your PACS to return info on ALL images in the database!

Queries a service class provider for images (composite object instances) that match the specified criteria.

Instance level attributes for this query:

  • ‘0008,0018’ (SOP Instance UID)

  • ‘0020,0013’ (Instance Number)

In addition to the above listed attributes, a number of “optional” attributes may be specified. For a general list of optional object instance level attributes, please refer to the DICOM standard, PS3.4 C.6.1.1.5, Table C.6-4.

Examples:

Find all images belonging to a given study and series

node.find_images('0020,000D' => '1.2.840.1145.342', '0020,000E' => '1.3.6.1.4.1.2452.6.687844')

Parameters:

  • query_params (Hash) (defaults to: {})

    the query parameters to use

Options Hash (query_params):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used in the query



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/dicom/d_client.rb', line 96

def find_images(query_params={})
  # Study Root Query/Retrieve Information Model - FIND:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.1")
  # These query attributes will always be present in the dicom query:
  default_query_params = {
    "0008,0018" => "", # SOP Instance UID
    "0008,0052" => "IMAGE", # Query/Retrieve Level: "IMAGE"
    "0020,0013" => "" # Instance Number
  }
  # Raising an error if a non-tag query attribute is used:
  query_params.keys.each do |tag|
    raise ArgumentError, "The supplied tag (#{tag}) is not valid. It must be a string of the form 'GGGG,EEEE'." unless tag.is_a?(String) && tag.tag?
  end
  # Set up the query parameters and carry out the C-FIND:
  set_data_elements(default_query_params.merge(query_params))
  perform_find
  return @data_results
end

#find_patients(query_params = {}) ⇒ Object

Note:

Caution: Calling this method without parameters will instruct your PACS to return info on ALL patients in the database!

Queries a service class provider for patients that match the specified criteria.

Instance level attributes for this query:

  • ‘0008,0052’ (Query/Retrieve Level)

  • ‘0010,0010’ (Patient’s Name)

  • ‘0010,0020’ (Patient ID)

  • ‘0010,0030’ (Patient’s Birth Date)

  • ‘0010,0040’ (Patient’s Sex)

In addition to the above listed attributes, a number of “optional” attributes may be specified. For a general list of optional object instance level attributes, please refer to the DICOM standard, PS3.4 C.6.1.1.2, Table C.6-1.

Examples:

Find all patients matching the given name

node.find_patients('0010,0010' => 'James*')

Parameters:

  • query_params (Hash) (defaults to: {})

    the query parameters to use

Options Hash (query_params):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used in the query



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/dicom/d_client.rb', line 137

def find_patients(query_params={})
  # Patient Root Query/Retrieve Information Model - FIND:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.1.1")
  # Every query attribute with a value != nil (required) will be sent in the dicom query.
  # The query parameters with nil-value (optional) are left out unless specified.
  default_query_params = {
    "0008,0052" => "PATIENT", # Query/Retrieve Level: "PATIENT"
    "0010,0010" => "", # Patient's Name
    "0010,0020" => "" # Patient's ID
  }
  # Raising an error if a non-tag query attribute is used:
  query_params.keys.each do |tag|
    raise ArgumentError, "The supplied tag (#{tag}) is not valid. It must be a string of the form 'GGGG,EEEE'." unless tag.is_a?(String) && tag.tag?
  end
  # Set up the query parameters and carry out the C-FIND:
  set_data_elements(default_query_params.merge(query_params))
  perform_find
  return @data_results
end

#find_series(query_params = {}) ⇒ Object

Note:

Caution: Calling this method without parameters will instruct your PACS to return info on ALL series in the database!

Queries a service class provider for series that match the specified criteria.

Instance level attributes for this query:

  • ‘0008,0060’ (Modality)

  • ‘0020,000E’ (Series Instance UID)

  • ‘0020,0011’ (Series Number)

In addition to the above listed attributes, a number of “optional” attributes may be specified. For a general list of optional object instance level attributes, please refer to the DICOM standard, PS3.4 C.6.1.1.4, Table C.6-3.

Examples:

Find all series belonging to the given study

node.find_series('0020,000D' => '1.2.840.1145.342')

Parameters:

  • query_params (Hash) (defaults to: {})

    the query parameters to use

Options Hash (query_params):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used in the query



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/dicom/d_client.rb', line 177

def find_series(query_params={})
  # Study Root Query/Retrieve Information Model - FIND:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.1")
  # Every query attribute with a value != nil (required) will be sent in the dicom query.
  # The query parameters with nil-value (optional) are left out unless specified.
  default_query_params = {
    "0008,0052" => "SERIES", # Query/Retrieve Level: "SERIES"
    "0008,0060" => "", # Modality
    "0020,000E" => "", # Series Instance UID
    "0020,0011" => "" # Series Number
  }
  # Raising an error if a non-tag query attribute is used:
  query_params.keys.each do |tag|
    raise ArgumentError, "The supplied tag (#{tag}) is not valid. It must be a string of the form 'GGGG,EEEE'." unless tag.is_a?(String) && tag.tag?
  end
  # Set up the query parameters and carry out the C-FIND:
  set_data_elements(default_query_params.merge(query_params))
  perform_find
  return @data_results
end

#find_studies(query_params = {}) ⇒ Object

Note:

Caution: Calling this method without parameters will instruct your PACS to return info on ALL studies in the database!

Queries a service class provider for studies that match the specified criteria.

Instance level attributes for this query:

  • ‘0008,0020’ (Study Date)

  • ‘0008,0030’ (Study Time)

  • ‘0008,0050’ (Accession Number)

  • ‘0010,0010’ (Patient’s Name)

  • ‘0010,0020’ (Patient ID)

  • ‘0020,000D’ (Study Instance UID)

  • ‘0020,0010’ (Study ID)

In addition to the above listed attributes, a number of “optional” attributes may be specified. For a general list of optional object instance level attributes, please refer to the DICOM standard, PS3.4 C.6.2.1.2, Table C.6-5.

Examples:

Find all studies matching the given study date and patient’s id

node.find_studies('0008,0020' => '20090604-', '0010,0020' => '123456789')

Parameters:

  • query_params (Hash) (defaults to: {})

    the query parameters to use

Options Hash (query_params):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used in the query



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/dicom/d_client.rb', line 222

def find_studies(query_params={})
  # Study Root Query/Retrieve Information Model - FIND:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.1")
  # Every query attribute with a value != nil (required) will be sent in the dicom query.
  # The query parameters with nil-value (optional) are left out unless specified.
  default_query_params = {
    "0008,0020" => "",  # Study Date
    "0008,0030" => "",  # Study Time
    "0008,0050" => "",  # Accession Number
    "0008,0052" => "STUDY", # Query/Retrieve Level:  "STUDY"
    "0010,0010" => "",  # Patient's Name
    "0010,0020" => "",  # Patient ID
    "0020,000D" => "",  # Study Instance UID
    "0020,0010" => ""  # Study ID
  }
  # Raising an error if a non-tag query attribute is used:
  query_params.keys.each do |tag|
    raise ArgumentError, "The supplied tag (#{tag}) is not valid. It must be a string of the form 'GGGG,EEEE'." unless tag.is_a?(String) && tag.tag?
  end
  # Set up the query parameters and carry out the C-FIND:
  set_data_elements(default_query_params.merge(query_params))
  perform_find
  return @data_results
end

#get_image(path, options = {}) ⇒ Object

Note:

This method has never actually been tested, and as such, it is probably not working! Feedback is welcome.

Retrieves a DICOM file from a service class provider (SCP/PACS).

Instance level attributes for this procedure:

  • ‘0008,0018’ (SOP Instance UID)

  • ‘0008,0052’ (Query/Retrieve Level)

  • ‘0020,000D’ (Study Instance UID)

  • ‘0020,000E’ (Series Instance UID)

Examples:

Retrieve a file as specified by its UIDs

node.get_image('c:/dicom/', '0008,0018' => sop_uid, '0020,000D' => study_uid, '0020,000E' => series_uid)

Parameters:

  • path (String)

    the directory where incoming files will be saved

  • options (Hash) (defaults to: {})

    the options to use for retrieving the DICOM object

Options Hash (options):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used for the procedure



266
267
268
269
270
271
272
273
274
275
# File 'lib/dicom/d_client.rb', line 266

def get_image(path, options={})
  # Study Root Query/Retrieve Information Model - GET:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.3")
  # Transfer the current options to the data_elements hash:
  set_command_fragment_get
  # Prepare data elements for this operation:
  set_data_fragment_get_image
  set_data_options(options)
  perform_get(path)
end

#move_image(destination, options = {}) ⇒ Object

Moves a single image to a DICOM server.

This DICOM node must be a third party (i.e. not the client instance you are requesting the move with!).

Instance level attributes for this procedure:

  • ‘0008,0018’ (SOP Instance UID)

  • ‘0008,0052’ (Query/Retrieve Level)

  • ‘0020,000D’ (Study Instance UID)

  • ‘0020,000E’ (Series Instance UID)

Examples:

Move an image from e.q. a PACS to another SCP on the network

node.move_image('SOME_SERVER', '0008,0018' => sop_uid, '0020,000D' => study_uid, '0020,000E' => series_uid)

Parameters:

  • destination (String)

    the AE title of the DICOM server which will receive the file

  • options (Hash) (defaults to: {})

    the options to use for moving the DICOM object

Options Hash (options):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used for the procedure



296
297
298
299
300
301
302
303
304
305
# File 'lib/dicom/d_client.rb', line 296

def move_image(destination, options={})
  # Study Root Query/Retrieve Information Model - MOVE:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.2")
  # Transfer the current options to the data_elements hash:
  set_command_fragment_move(destination)
  # Prepare data elements for this operation:
  set_data_fragment_move_image
  set_data_options(options)
  perform_move
end

#move_study(destination, options = {}) ⇒ Object

Move an entire study to a DICOM server.

This DICOM node must be a third party (i.e. not the client instance you are requesting the move with!).

Instance level attributes for this procedure:

  • ‘0008,0052’ (Query/Retrieve Level)

  • ‘0010,0020’ (Patient ID)

  • ‘0020,000D’ (Study Instance UID)

Examples:

Move an entire study from e.q. a PACS to another SCP on the network

node.move_study('SOME_SERVER', '0010,0020' => pat_id, '0020,000D' => study_uid)

Parameters:

  • destination (String)

    the AE title of the DICOM server which will receive the files

  • options (Hash) (defaults to: {})

    the options to use for moving the DICOM objects

Options Hash (options):

  • 'GGGG,EEEE' (String)

    a tag and value pair to be used for the procedure



325
326
327
328
329
330
331
332
333
334
# File 'lib/dicom/d_client.rb', line 325

def move_study(destination, options={})
  # Study Root Query/Retrieve Information Model - MOVE:
  set_default_presentation_context("1.2.840.10008.5.1.4.1.2.2.2")
  # Transfer the current options to the data_elements hash:
  set_command_fragment_move(destination)
  # Prepare data elements for this operation:
  set_data_fragment_move_study
  set_data_options(options)
  perform_move
end

#send(files) ⇒ Object

Sends one or more DICOM files to a service class provider (SCP/PACS).

Examples:

Send a DICOM file to a storage server

node.send('my_file.dcm')

Parameters:



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/dicom/d_client.rb', line 342

def send(files)
  # Prepare the DICOM object(s):
  objects, success, message = load_files(files)
  if success
    # Open a DICOM link:
    establish_association
    if association_established?
      if request_approved?
        # Continue with our c-store operation, since our request was accepted.
        # Handle the transmission:
        perform_send(objects)
      end
    end
    # Close the DICOM link:
    establish_release
  else
    # Failed when loading the specified parameter as DICOM file(s). Will not transmit.
    logger.error(message)
  end
end

#testObject

Tests the connection to the server in a very simple way by negotiating an association and then releasing it.



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/dicom/d_client.rb', line 366

def test
  logger.info("TESTING CONNECTION...")
  success = false
  # Verification SOP Class:
  set_default_presentation_context(VERIFICATION_SOP)
  # Open a DICOM link:
  establish_association
  if association_established?
    if request_approved?
      success = true
    end
    # Close the DICOM link:
    establish_release
  end
  if success
    logger.info("TEST SUCCSESFUL!")
  else
    logger.warn("TEST FAILED!")
  end
  return success
end