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)

[View source]

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.

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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:

[View source]

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.

[View source]

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