dicom 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,58 +4,56 @@ module DICOM
4
4
  # Class which holds the methods that interact with the DICOM dictionary.
5
5
  class DLibrary
6
6
 
7
- attr_reader :de_tag, :de_vr, :de_name, :uid_value, :uid_name, :uid_type, :pi_type, :pi_description
7
+ attr_reader :tags, :uid
8
8
 
9
9
  # Initialize the DRead instance.
10
- def initialize()
11
- # Dictionary content will be stored in instance arrays.
10
+ def initialize
11
+ # Dictionary content will be stored in a number of hash objects.
12
12
  # Load the dictionary:
13
- dict = Dictionary.new()
13
+ dic = Dictionary.new
14
14
  # Data elements:
15
- de = dict.load_data_elements()
16
- @de_tag = de[0]
17
- @de_vr = de[1]
18
- @de_name = de[2]
19
- # Photometric Interpretation:
20
- pi = dict.load_image_types()
21
- @pi_type = pi[0]
22
- @pi_description = pi[1]
23
- # UID:
24
- uid = dict.load_uid()
25
- @uid_value = uid[0]
26
- @uid_name = uid[1]
27
- @uid_type = uid[2]
15
+ # Value of this hash is a two-element array [vr, name] (where vr itself is an array of 1-3 elements)
16
+ @tags = dic.load_data_elements
17
+ # UID (DICOM unique identifiers):
18
+ # Value of this hash is a two-element array [description, type]
19
+ @uid = dic.load_uid
20
+ # Photometric Interpretation: (not in use yet)
21
+ #@image_types = dic.load_image_types
22
+ # Value representation library: (not in use yet)
23
+ #@vr = dic.load_vr
24
+ # Frame of reference library: (not in use yet)
25
+ #@frame_of_ref = dic.load_frame_of_ref
28
26
  end
29
27
 
30
28
 
31
- # Returns data element name and value representation from library if data element is recognized, else it returns "Unknown Name" and "UN".
29
+ # Returns data element name and value representation from the dictionary if the data element
30
+ # is recognized, else it returns "Unknown Name" and "UN".
32
31
  def get_name_vr(tag)
33
- pos = get_pos(tag)
34
- if pos != nil
35
- name = @de_name[pos]
36
- vr = @de_vr[pos][0]
32
+ values = @tags[tag]
33
+ if values != nil
34
+ name = values[1]
35
+ vr = values[0][0]
37
36
  else
38
37
  # For the tags that are not recognised, we need to do some additional testing to see if it is one of the special cases:
39
38
  # Split tag in group and element:
40
39
  group = tag[0..3]
41
40
  element = tag[5..8]
42
- # Check for group length:
43
41
  if element == "0000"
42
+ # Group length:
44
43
  name = "Group Length"
45
44
  vr = "UL"
46
- end
47
- # Source Image ID's: (Retired)
48
- if tag[0..6] == "0020,31"
49
- pos = get_pos("0020,31xx")
50
- name = @de_name[pos]
51
- vr = @de_vr[pos][0]
52
- end
53
- # Group 50xx (retired) and 60xx:
54
- if tag[0..1] == "50" or tag[0..1] == "60"
55
- pos = get_pos(tag[0..1]+"xx"+tag[4..8])
56
- if pos != nil
57
- name = @de_name[pos]
58
- vr = @de_vr[pos][0]
45
+ elsif tag[0..6] == "0020,31"
46
+ # Source Image ID's: (Retired)
47
+ values = @tags["0020,31xx"]
48
+ name = values[1]
49
+ vr = values[0][0]
50
+ elsif tag[0..1] == "50" or tag[0..1] == "60"
51
+ # Group 50xx (retired) and 60xx:
52
+ new_tag = tag[0..1]+"xx"+tag[4..8]
53
+ values = @tags[new_tag]
54
+ if values != nil
55
+ name = values[1]
56
+ vr = values[0][0]
59
57
  end
60
58
  end
61
59
  # If none of the above checks yielded a result, the tag is unknown:
@@ -70,21 +68,23 @@ module DICOM
70
68
 
71
69
  # Returns the tag that matches the supplied data element name,
72
70
  # or if a tag is supplied, return that tag.
73
- def get_tag(value)
71
+ # (This method may be considered for removal: Does the usefulnes of being able to create a tag by Name,
72
+ # outweigh the performance impact of having this method?)
73
+ def get_tag(name)
74
74
  tag = false
75
75
  # The supplied value should be a string:
76
- if value.is_a?(String)
77
- # Is it a tag?
78
- # A tag is a string with 9 characters, where the 5th character should be a comma.
79
- if value[4..4] == ',' and value.length == 9
80
- # This is a tag.
81
- # (Here it is possible to have some further logic to check the validity of the string as a tag.)
82
- tag = value
76
+ if name.is_a?(String)
77
+ if name.is_a_tag?
78
+ # This is a tag:
79
+ tag = name
83
80
  else
84
81
  # We have presumably been dealt a name. Search the dictionary to see if we can identify
85
- # it along with its corresponding tag:
86
- pos = @de_name.index(value)
87
- tag = @de_tag[pos] unless pos == nil
82
+ # this name and return its corresponding tag:
83
+ @tags.each_pair do |key, value|
84
+ if value[1] == name
85
+ tag = key
86
+ end
87
+ end
88
88
  end
89
89
  end
90
90
  return tag
@@ -92,11 +92,11 @@ module DICOM
92
92
 
93
93
 
94
94
  # Checks whether a given string is a valid transfer syntax or not.
95
- def check_ts_validity(value)
95
+ def check_ts_validity(uid)
96
96
  result = false
97
- pos = @uid_value.index(value)
98
- if pos != nil
99
- if pos >= 1 and pos <= 34
97
+ value = @uid[uid.rstrip]
98
+ if value != nil
99
+ if value[1] == "Transfer Syntax"
100
100
  # Proved valid:
101
101
  result = true
102
102
  end
@@ -105,13 +105,12 @@ module DICOM
105
105
  end
106
106
 
107
107
 
108
- # Returns the name corresponding to a given UID.
109
- def get_uid(value)
110
- # Find the position of the specified value in the array:
111
- pos = @uid_value.index(value)
108
+ # Returns the name/description corresponding to a given UID.
109
+ def get_uid(uid)
110
+ value = @uid[uid.rstrip]
112
111
  # Fetch the name of this UID:
113
- if pos != nil
114
- name = @uid_name[pos]
112
+ if value != nil
113
+ name = value[0]
115
114
  else
116
115
  name = "Unknown UID!"
117
116
  end
@@ -120,29 +119,54 @@ module DICOM
120
119
 
121
120
 
122
121
  # Checks if the supplied transfer syntax indicates the presence of pixel compression or not.
123
- def get_compression(value)
124
- res = false
125
- # Index less or equal to 4 means no compression.
126
- pos = @uid_value.index(value)
127
- if pos != nil
128
- if pos > 4
129
- # It seems we have compression:
130
- res = true
122
+ def get_compression(uid)
123
+ result = false
124
+ if uid
125
+ value = @uid[uid.rstrip]
126
+ if value != nil
127
+ if value[1] == "Transfer Syntax" and not value[0].include?("Endian")
128
+ # It seems we have compression:
129
+ res = true
130
+ end
131
131
  end
132
132
  end
133
- return res
133
+ return result
134
134
  end
135
135
 
136
136
 
137
- # Following methods are private.
138
- private
139
-
140
- # Returns the position of the supplied data element name in the Dictionary array.
141
- def get_pos(tag)
142
- pos = @de_tag.index(tag)
143
- return pos
137
+ # Checks the Transfer Syntax UID and return the encoding settings associated with this value.
138
+ def process_transfer_syntax(value)
139
+ valid = check_ts_validity(value)
140
+ case value
141
+ # Some variations with uncompressed pixel data:
142
+ when "1.2.840.10008.1.2"
143
+ # Implicit VR, Little Endian
144
+ explicit = false
145
+ endian = false
146
+ when "1.2.840.10008.1.2.1"
147
+ # Explicit VR, Little Endian
148
+ explicit = true
149
+ endian = false
150
+ when "1.2.840.10008.1.2.1.99"
151
+ # Deflated Explicit VR, Little Endian
152
+ #@msg += ["Warning: Transfer syntax 'Deflated Explicit VR, Little Endian' is untested. Unknown if this is handled correctly!"]
153
+ explicit = true
154
+ endian = false
155
+ when "1.2.840.10008.1.2.2"
156
+ # Explicit VR, Big Endian
157
+ explicit = true
158
+ endian = true
159
+ else
160
+ # For everything else, assume compressed pixel data, with Explicit VR, Little Endian:
161
+ explicit = true
162
+ endian = false
163
+ end
164
+ return [valid, explicit, endian]
144
165
  end
145
166
 
146
167
 
147
- end # end of class
148
- end # end of module
168
+ # Following methods are private.
169
+ #private
170
+
171
+ end # of class
172
+ end # of module
@@ -16,10 +16,12 @@
16
16
  #--------------------------------------------------------------------------------------------------
17
17
 
18
18
  # TODO:
19
+ # -Improve the retrieve file network functionality
20
+ # -Make the networking more intelligent in its handling of (unexpected) messages
19
21
  # -Support for writing complex (hierarchical) DICOM files (basic write support is featured).
20
22
  # -Full support for compressed image data.
21
23
  # -Read 12 bit image data correctly.
22
- # -Support for color image data to get_image_narray() and get_image_magick().
24
+ # -Support for color image data to get_image_narray and get_image_magick.
23
25
  # -Complete support for Big endian (basic support is already featured).
24
26
  # -Complete support for multiple frame image data to NArray and RMagick objects (partial support already featured).
25
27
  # -Reading of image data in files that contain two different and unrelated images (this problem has been observed with some MR images).
@@ -29,29 +31,32 @@ module DICOM
29
31
  # Class for handling the DICOM contents:
30
32
  class DObject
31
33
 
32
- attr_reader :read_success, :write_success, :modality, :errors,
34
+ attr_reader :read_success, :write_success, :modality, :errors, :segments,
33
35
  :names, :tags, :types, :lengths, :values, :raw, :levels
34
36
 
35
37
  # Initialize the DObject instance.
36
- def initialize(file_name=nil, opts={})
38
+ def initialize(string=nil, options={})
37
39
  # Process option values, setting defaults for the ones that are not specified:
38
- @verbose = opts[:verbose]
39
- @lib = opts[:lib] || DLibrary.new
40
+ @verbose = options[:verbose]
41
+ @lib = options[:lib] || DLibrary.new
42
+ segment_size = options[:segment_size]
43
+ bin = options[:bin]
44
+ syntax = options[:syntax]
40
45
  # Default verbosity is true:
41
46
  @verbose = true if @verbose == nil
42
47
 
43
48
  # Initialize variables that will be used for the DICOM object:
44
- @names = Array.new()
45
- @tags = Array.new()
46
- @types = Array.new()
47
- @lengths = Array.new()
48
- @values = Array.new()
49
- @raw = Array.new()
50
- @levels = Array.new()
49
+ @names = Array.new
50
+ @tags = Array.new
51
+ @types = Array.new
52
+ @lengths = Array.new
53
+ @values = Array.new
54
+ @raw = Array.new
55
+ @levels = Array.new
51
56
  # Array that will holde any messages generated while reading the DICOM file:
52
- @errors = Array.new()
57
+ @errors = Array.new
53
58
  # Array to keep track of sequences/structure of the dicom elements:
54
- @sequence = Array.new()
59
+ @sequence = Array.new
55
60
  # Index of last element in data element arrays:
56
61
  @last_index=0
57
62
  # Structural information (default values):
@@ -63,83 +68,87 @@ module DICOM
63
68
  @modality = nil
64
69
  # Control variables:
65
70
  @read_success = false
66
- # Check endianness of the system (false if little endian):
67
- @sys_endian = check_sys_endian()
68
- # Set format strings for packing/unpacking:
69
- set_format_strings()
71
+ # Initialize a Stream instance which is used for encoding/decoding:
72
+ @stream = Stream.new(nil, @file_endian, @explicit)
70
73
 
71
74
  # If a (valid) file name string is supplied, call the method to read the DICOM file:
72
- if file_name.is_a?(String) and file_name != ""
73
- @file = file_name
74
- read(file_name)
75
+ if string.is_a?(String) and string != ""
76
+ @file = string
77
+ read(string, :bin => bin, :segment_size => segment_size, :syntax => syntax)
75
78
  end
76
- end # of method initialize
79
+ end # of initialize
77
80
 
78
81
 
79
82
  # Returns a DICOM object by reading the file specified.
80
83
  # This is accomplished by initliazing the DRead class, which loads DICOM information to arrays.
81
84
  # For the time being, this method is called automatically when initializing the DObject class,
82
85
  # but in the future, when write support is added, this method may have to be called manually.
83
- def read(file_name)
84
- dcm = DRead.new(file_name, :lib => @lib, :sys_endian => @sys_endian)
86
+ def read(string, options = {})
87
+ r = DRead.new(string, :lib => @lib, :sys_endian => @sys_endian, :bin => options[:bin], :syntax => options[:syntax])
85
88
  # Store the data to the instance variables if the readout was a success:
86
- if dcm.success
89
+ if r.success
87
90
  @read_success = true
88
- @names = dcm.names
89
- @tags = dcm.tags
90
- @types = dcm.types
91
- @lengths = dcm.lengths
92
- @values = dcm.values
93
- @raw = dcm.raw
94
- @levels = dcm.levels
95
- @explicit = dcm.explicit
96
- @file_endian = dcm.file_endian
97
- # Set format strings for packing/unpacking:
98
- set_format_strings(@file_endian)
91
+ @names = r.names
92
+ @tags = r.tags
93
+ @types = r.types
94
+ @lengths = r.lengths
95
+ @values = r.values
96
+ @raw = r.raw
97
+ @levels = r.levels
98
+ @explicit = r.explicit
99
+ @file_endian = r.file_endian
100
+ # Update Stream instance with settings from this DICOM file:
101
+ @stream.set_endian(@file_endian)
102
+ @stream.explicit = @explicit
99
103
  # Index of last data element in element arrays:
100
104
  @last_index=@names.length-1
101
105
  # Update status variables for this object:
102
- check_properties()
106
+ check_properties
103
107
  # Set the modality of the DICOM object:
104
- set_modality()
108
+ set_modality
105
109
  else
106
110
  @read_success = false
107
111
  end
108
- # If any messages has been recorded, send these to the message handling method:
109
- if dcm.msg.size != 0
110
- add_msg(dcm.msg)
112
+ # Check if a partial extraction has been requested (used for network communication purposes)
113
+ if options[:segment_size]
114
+ @segments = r.extract_segments(options[:segment_size])
111
115
  end
116
+ # If any messages has been recorded, send these to the message handling method:
117
+ add_msg(r.msg) if r.msg.size != 0
112
118
  end
113
119
 
114
120
 
115
121
  # Transfers necessary information from the DObject to the DWrite class, which
116
122
  # will attempt to write this information to a valid DICOM file.
117
- def write(file_name)
118
- w = DWrite.new(file_name, :lib => @lib, :sys_endian => @sys_endian)
119
- w.tags = @tags
120
- w.types = @types
121
- w.lengths = @lengths
122
- w.raw = @raw
123
- w.rest_endian = @file_endian
124
- w.rest_explicit = @explicit
123
+ def write(file_name, transfer_syntax = nil)
124
+ w = set_write_object(file_name, transfer_syntax)
125
125
  w.write
126
126
  # Write process succesful?
127
127
  @write_success = w.success
128
128
  # If any messages has been recorded, send these to the message handling method:
129
- if w.msg.size != 0
130
- add_msg(w.msg)
131
- end
129
+ add_msg(w.msg) if w.msg.size != 0
130
+ end
131
+
132
+
133
+ # Encodes the DICOM object into a series of binary string segments with a specified maximum length.
134
+ def encode_segments(size)
135
+ w = set_write_object
136
+ @segments = w.encode_segments(size)
137
+ # Write process succesful?
138
+ @write_success = w.success
139
+ # If any messages has been recorded, send these to the message handling method:
140
+ add_msg(w.msg) if w.msg.size != 0
132
141
  end
133
142
 
134
143
 
135
144
  #################################################
136
- # START OF METHODS FOR READING INFORMATION FROM DICOM OBJECT:#
145
+ # START OF METHODS FOR READING INFORMATION FROM DICOM OBJECT:
137
146
  #################################################
138
147
 
139
148
 
140
149
  # Checks the status of the pixel data that has been read from the DICOM file: whether it exists at all and if its greyscale or color.
141
150
  # Modifies instance variable @color if color image is detected and instance variable @compression if no pixel data is detected.
142
- def check_properties()
151
+ def check_properties
143
152
  # Check if pixel data is present:
144
153
  if @tags.index("7FE0,0010") == nil
145
154
  # No pixel data in DICOM file:
@@ -160,7 +169,7 @@ module DICOM
160
169
  # Returns image data from the provided element index, performing decompression of data if necessary.
161
170
  def read_image_magick(pos, columns, rows)
162
171
  if pos == false or columns == false or rows == false
163
- add_msg("Error: Method read_image_magick() does not have enough data available to build an image object.")
172
+ add_msg("Error: Method read_image_magick does not have enough data available to build an image object.")
164
173
  return false
165
174
  end
166
175
  if @compression != true
@@ -170,7 +179,7 @@ module DICOM
170
179
  image.import_pixels(0, 0, columns, rows, "I", image_data)
171
180
  return image
172
181
  else
173
- # Image data is compressed, we will attempt to unpack it using RMagick (ImageMagick):
182
+ # Image data is compressed, we will attempt to deflate it using RMagick (ImageMagick):
174
183
  begin
175
184
  image = Magick::Image.from_blob(@raw[pos])
176
185
  return image
@@ -184,7 +193,7 @@ module DICOM
184
193
 
185
194
  # Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
186
195
  # To call this method the user needs to have performed " require 'narray' " in advance.
187
- def get_image_narray()
196
+ def get_image_narray
188
197
  # Does pixel data exist at all in the DICOM object?
189
198
  if @compression == nil
190
199
  add_msg("It seems pixel data is not present in this DICOM object: returning false.")
@@ -203,8 +212,8 @@ module DICOM
203
212
  # Gather information about the dimensions of the image data:
204
213
  rows = get_value("0028,0010")
205
214
  columns = get_value("0028,0011")
206
- frames = get_frames()
207
- image_pos = get_image_pos()
215
+ frames = get_frames
216
+ image_pos = get_image_pos
208
217
  # Creating a NArray object using int to make sure we have a big enough range for our numbers:
209
218
  image = NArray.int(frames,columns,rows)
210
219
  image_temp = NArray.int(columns,rows)
@@ -244,12 +253,12 @@ module DICOM
244
253
  image[i,true,true]=temp_image
245
254
  end
246
255
  return image
247
- end # of method get_image_narray
256
+ end # of get_image_narray
248
257
 
249
258
 
250
259
  # Returns an array of RMagick image objects, where the size of the array corresponds with the number of frames in the image data.
251
260
  # To call this method the user needs to have performed " require 'RMagick' " in advance.
252
- def get_image_magick()
261
+ def get_image_magick
253
262
  # Does pixel data exist at all in the DICOM object?
254
263
  if @compression == nil
255
264
  add_msg("It seems pixel data is not present in this DICOM object: returning false.")
@@ -263,8 +272,8 @@ module DICOM
263
272
  # Gather information about the dimensions of the image data:
264
273
  rows = get_value("0028,0010")
265
274
  columns = get_value("0028,0011")
266
- frames = get_frames()
267
- image_pos = get_image_pos()
275
+ frames = get_frames
276
+ image_pos = get_image_pos
268
277
  # Array that will hold the RMagick image objects, one image object for each frame:
269
278
  image_arr = Array.new(frames)
270
279
  # Handling of image data will depend on whether we have one or more frames,
@@ -293,11 +302,11 @@ module DICOM
293
302
  end
294
303
  end
295
304
  return image_arr
296
- end # of method get_image_magick
305
+ end # of get_image_magick
297
306
 
298
307
 
299
308
  # Returns the number of frames present in the image data in the DICOM file.
300
- def get_frames()
309
+ def get_frames
301
310
  frames = get_value("0028,0008")
302
311
  if frames == false
303
312
  # If the DICOM object does not specify the number of frames explicitly, assume 1 image frame.
@@ -313,26 +322,19 @@ module DICOM
313
322
  # We need to know what kind of bith depth the pixel data is saved with:
314
323
  bit_depth = get_value("0028,0100")
315
324
  if bit_depth != false
316
- # Load the binary pixel data:
317
- bin = get_raw(pos)
325
+ # Load the binary pixel data to the Stream instance:
326
+ @stream.set_string(get_raw(pos))
318
327
  # Number of bytes used per pixel will determine how to unpack this:
319
328
  case bit_depth
320
329
  when 8
321
- pixels = bin.unpack(@by) # Byte/Character/Fixnum (1 byte)
330
+ pixels = @stream.decode_all("BY") # Byte/Character/Fixnum (1 byte)
322
331
  when 16
323
- pixels = bin.unpack(@us) # Unsigned short (2 bytes)
332
+ pixels = @stream.decode_all("US") # Unsigned short (2 bytes)
324
333
  when 12
325
334
  # 12 BIT SIMPLY NOT WORKING YET!
326
335
  # This one is a bit more tricky to extract.
327
336
  # I havent really given this priority so far as 12 bit image data is rather rare.
328
337
  add_msg("Warning: Bit depth 12 is not working correctly at this time! Please contact the author.")
329
- #pixels = Array.new(length)
330
- #(length).times do |i|
331
- #hex = bin.unpack('H3')
332
- #hex4 = "0"+hex[0]
333
- #num = hex[0].unpack('v')
334
- #data[i] = num
335
- #end
336
338
  else
337
339
  raise "Bit depth ["+bit_depth.to_s+"] has not received implementation in this procedure yet. Please contact the author."
338
340
  end # of case bit_depth
@@ -340,11 +342,11 @@ module DICOM
340
342
  add_msg("Error: DICOM object does not contain the 'Bit Depth' data element (0028,0010).")
341
343
  end # of if bit_depth ..
342
344
  return pixels
343
- end # of method get_pixels
345
+ end
344
346
 
345
347
 
346
348
  # Returns the index(es) of the element(s) that contain image data.
347
- def get_image_pos()
349
+ def get_image_pos
348
350
  image_element_pos = get_pos("7FE0,0010")
349
351
  item_pos = get_pos("FFFE,E000")
350
352
  # Proceed only if an image element actually exists:
@@ -365,22 +367,22 @@ module DICOM
365
367
  # Determine which of these late item elements contain image data.
366
368
  # Usually, there are frames+1 late items, and all except
367
369
  # the first item contain an image frame:
368
- frames = get_frames()
370
+ frames = get_frames
369
371
  if frames != false # note: function get_frames will never return false
370
372
  if late_item_pos.size == frames.to_i+1
371
373
  return late_item_pos[1..late_item_pos.size-1]
372
374
  else
373
- add_msg("Warning: Unexpected behaviour in DICOM file for method get_image_pos(). Expected number of image data items not equal to number of frames+1, returning false.")
375
+ add_msg("Warning: Unexpected behaviour in DICOM file for method get_image_pos. Expected number of image data items not equal to number of frames+1, returning false.")
374
376
  return false
375
377
  end
376
378
  else
377
- add_msg("Warning: 'Number of Frames' data element not found. Method get_image_pos() will return false.")
379
+ add_msg("Warning: 'Number of Frames' data element not found. Method get_image_pos will return false.")
378
380
  return false
379
381
  end
380
382
  end
381
383
  end
382
384
  end
383
- end # of method get_image_pos
385
+ end
384
386
 
385
387
 
386
388
  # Returns an array of the index(es) of the element(s) in the DICOM file that match the supplied element position, tag or name.
@@ -390,11 +392,8 @@ module DICOM
390
392
  # through the entire DICOM object. If myArray equals false, the method will return false.
391
393
  # :partial => true - get_pos will not only search for exact matches, but will search the names and tags arrays for
392
394
  # strings that contain the given search string.
393
- def get_pos(query, opts={})
394
- # Optional keywords:
395
- keyword_array = opts[:array]
396
- keyword_partial = opts[:partial]
397
- indexes = Array.new()
395
+ def get_pos(query, options={})
396
+ indexes = Array.new
398
397
  # For convenience, allow query to be a one-element array (its value will be extracted):
399
398
  if query.is_a?(Array)
400
399
  if query.length > 1 or query.length == 0
@@ -404,25 +403,25 @@ module DICOM
404
403
  query = query[0]
405
404
  end
406
405
  end
407
- if keyword_array == false
406
+ if options[:array] == false
408
407
  # If the supplied array option equals false, it signals that the user tries to search for an element
409
408
  # in an invalid position, and as such, this method will also return false:
410
- add_msg("Warning: Attempted to call get_pos() with query #{query}, but since keyword :array is false I will return false.")
409
+ add_msg("Warning: Attempted to call get_pos with query #{query}, but since keyword :array is false I will return false.")
411
410
  indexes = false
412
411
  else
413
- # Check if query is a number (some methods want to have the ability to call get_pos() with a number):
412
+ # Check if query is a number (some methods want to have the ability to call get_pos with a number):
414
413
  if query.is_a?(Integer)
415
414
  # Return the position if it is valid:
416
415
  indexes = [query] if query >= 0 and query < @names.length
417
416
  elsif query.is_a?(String)
418
417
  # Either use the supplied array, or search the entire DICOM object:
419
- if keyword_array.is_a?(Array)
420
- search_array = keyword_array
418
+ if options[:array].is_a?(Array)
419
+ search_array = options[:array]
421
420
  else
422
421
  search_array = Array.new(@names.length) {|i| i}
423
422
  end
424
423
  # Perform search:
425
- if keyword_partial == true
424
+ if options[:partial] == true
426
425
  # Search for partial string matches:
427
426
  partial_indexes = search_array.all_indices_partial_match(@tags, query.upcase)
428
427
  if partial_indexes.length > 0
@@ -443,51 +442,51 @@ module DICOM
443
442
  indexes = false if indexes.length == 0
444
443
  end
445
444
  return indexes
446
- end # of method get_pos
445
+ end # of get_pos
447
446
 
448
447
 
449
448
  # Dumps the binary content of the Pixel Data element to file.
450
449
  def image_to_file(file)
451
- pos = get_image_pos()
450
+ pos = get_image_pos
452
451
  if pos
453
452
  if pos.length == 1
454
453
  # Pixel data located in one element:
455
454
  pixel_data = get_raw(pos[0])
456
455
  f = File.new(file, "wb")
457
456
  f.write(pixel_data)
458
- f.close()
457
+ f.close
459
458
  else
460
459
  # Pixel data located in several elements:
461
460
  pos.each_index do |i|
462
461
  pixel_data = get_raw(pos[i])
463
462
  f = File.new(file + i.to_s, "wb")
464
463
  f.write(pixel_data)
465
- f.close()
464
+ f.close
466
465
  end
467
466
  end
468
- end # of if pos =...
469
- end # of method image_to_file
467
+ end
468
+ end
470
469
 
471
470
 
472
471
  # Returns the positions of all data elements inside the hierarchy of a sequence or an item.
473
472
  # Options:
474
473
  # :next_only => true - The method will only search immediately below the specified
475
474
  # item or sequence (that is, in the level of parent + 1).
476
- def children(element, opts={})
475
+ def children(element, options={})
477
476
  # Process option values, setting defaults for the ones that are not specified:
478
- opt_next_only = opts[:next_only] || false
477
+ opt_next_only = options[:next_only] || false
479
478
  value = false
480
479
  # Retrieve array position:
481
480
  pos = get_pos(element)
482
481
  if pos == false
483
- add_msg("Warning: Invalid data element provided to method children(). Returning false.")
482
+ add_msg("Warning: Invalid data element provided to method children. Returning false.")
484
483
  else
485
484
  if pos.size > 1
486
- add_msg("Warning: Method children() does not allow a query which yields multiple array hits. Please use array position instead of tag/name. Returning false.")
485
+ add_msg("Warning: Method children does not allow a query which yields multiple array hits. Please use array position instead of tag/name. Returning false.")
487
486
  else
488
487
  # Proceed to find the value:
489
488
  # First we need to establish in which positions to perform the search:
490
- below_pos = Array.new()
489
+ below_pos = Array.new
491
490
  pos.each do |p|
492
491
  parent_level = @levels[p]
493
492
  remain_array = @levels[p+1..@levels.size-1]
@@ -496,11 +495,11 @@ module DICOM
496
495
  if (remain_array[i] > parent_level) and (extract == true)
497
496
  # If search is targetted at any specific level, we can just add this position:
498
497
  if not opt_next_only == true
499
- below_pos += [p+1+i]
498
+ below_pos << (p+1+i)
500
499
  else
501
500
  # As search is restricted to parent level + 1, do a test for this:
502
501
  if remain_array[i] == parent_level + 1
503
- below_pos += [p+1+i]
502
+ below_pos << (p+1+i)
504
503
  end
505
504
  end
506
505
  else
@@ -513,7 +512,7 @@ module DICOM
513
512
  end # of if pos.size..else..
514
513
  end
515
514
  return value
516
- end # of method below
515
+ end
517
516
 
518
517
 
519
518
  # Returns the value (processed raw data) of the requested DICOM data element.
@@ -522,32 +521,31 @@ module DICOM
522
521
  # :array => true - Allows the query of the value of a tag that occurs more than one time in the
523
522
  # DICOM object. Values will be returned in an array with length equal to the number
524
523
  # of occurances of the tag. If keyword is not specified, the method returns false in this case.
525
- def get_value(element, opts={})
526
- opts_array = opts[:array]
527
- # As this method is also used internally, we want the possibility of warnings not being raised even if verbose is set to true by the user, to avoid confusion.
528
- silent = opts[:silent]
524
+ # :silent => true - As this method is also used internally, we want the possibility of warnings not being
525
+ # raised even if verbose is set to true by the user, in order to avoid confusion.
526
+ def get_value(element, options={})
529
527
  value = false
530
528
  # Retrieve array position:
531
529
  pos = get_pos(element)
532
530
  if pos == false
533
- add_msg("Warning: Invalid data element provided to method get_value(). Returning false.") unless silent
531
+ add_msg("Warning: Invalid data element provided to method get_value. Returning false.") unless options[:silent]
534
532
  else
535
533
  if pos.size > 1
536
- if opts_array == true
534
+ if options[:array] == true
537
535
  # Retrieve all values into an array:
538
- value = []
536
+ value = Array.new
539
537
  pos.each do |i|
540
538
  value << @values[i]
541
539
  end
542
540
  else
543
- add_msg("Warning: Method get_value() does not allow a query which yields multiple array hits. Please use array position instead of tag/name, or use keyword (:array => true). Returning false.") unless silent
541
+ add_msg("Warning: Method get_value does not allow a query which yields multiple array hits. Please use array position instead of tag/name, or use keyword (:array => true). Returning false.") unless options[:silent]
544
542
  end
545
543
  else
546
544
  value = @values[pos[0]]
547
545
  end
548
546
  end
549
547
  return value
550
- end # of method get_value
548
+ end
551
549
 
552
550
 
553
551
  # Returns the raw data of the requested DICOM data element.
@@ -556,30 +554,29 @@ module DICOM
556
554
  # :array => true - Allows the query of the value of a tag that occurs more than one time in the
557
555
  # DICOM object. Values will be returned in an array with length equal to the number
558
556
  # of occurances of the tag. If keyword is not specified, the method returns false in this case.
559
- def get_raw(element, opts={})
560
- opts_array = opts[:array]
557
+ def get_raw(element, options={})
561
558
  value = false
562
559
  # Retrieve array position:
563
560
  pos = get_pos(element)
564
561
  if pos == false
565
- add_msg("Warning: Invalid data element provided to method get_raw(). Returning false.")
562
+ add_msg("Warning: Invalid data element provided to method get_raw. Returning false.")
566
563
  else
567
564
  if pos.size > 1
568
- if opts_array == true
565
+ if options[:array] == true
569
566
  # Retrieve all values into an array:
570
- value = []
567
+ value = Array.new
571
568
  pos.each do |i|
572
569
  value << @raw[i]
573
570
  end
574
571
  else
575
- add_msg("Warning: Method get_raw() does not allow a query which yields multiple array hits. Please use array position instead of tag/name, or use keyword (:array => true). Returning false.")
572
+ add_msg("Warning: Method get_raw does not allow a query which yields multiple array hits. Please use array position instead of tag/name, or use keyword (:array => true). Returning false.")
576
573
  end
577
574
  else
578
575
  value = @raw[pos[0]]
579
576
  end
580
577
  end
581
578
  return value
582
- end # of method get_raw
579
+ end
583
580
 
584
581
 
585
582
  # Returns the position of (possible) parents of the specified data element in the hierarchy structure of the DICOM object.
@@ -588,10 +585,10 @@ module DICOM
588
585
  # Retrieve array position:
589
586
  pos = get_pos(element)
590
587
  if pos == false
591
- add_msg("Warning: Invalid data element provided to method parents(). Returning false.")
588
+ add_msg("Warning: Invalid data element provided to method parents. Returning false.")
592
589
  else
593
590
  if pos.length > 1
594
- add_msg("Warning: Method parents() does not allow a query which yields multiple array hits. Please use array position instead of tag/name. Returning false.")
591
+ add_msg("Warning: Method parents does not allow a query which yields multiple array hits. Please use array position instead of tag/name. Returning false.")
595
592
  else
596
593
  # Proceed to find the value:
597
594
  # Get the level of our element:
@@ -599,23 +596,23 @@ module DICOM
599
596
  # Element can obviously only have parents if it is not a top level element:
600
597
  unless level == 0
601
598
  # Search backwards, and record the position every time we encounter an upwards change in the level number.
602
- parents = Array.new()
599
+ parents = Array.new
603
600
  prev_level = level
604
601
  search_arr = @levels[0..pos[0]-1].reverse
605
602
  search_arr.each_index do |i|
606
603
  if search_arr[i] < prev_level
607
- parents += [search_arr.length-i-1]
604
+ parents << search_arr.length-i-1
608
605
  prev_level = search_arr[i]
609
606
  end
610
607
  end
611
608
  # When the element has several generations of parents, we want its top parent to be first in the returned array:
612
609
  parents = parents.reverse
613
610
  value = parents if parents.length > 0
614
- end # of if level == 0
615
- end # of if pos.length..else..
611
+ end
612
+ end
616
613
  end
617
614
  return value
618
- end # of method parents
615
+ end
619
616
 
620
617
 
621
618
  ##############################################
@@ -625,8 +622,8 @@ module DICOM
625
622
 
626
623
  # Prints the information of all elements stored in the DICOM object.
627
624
  # This method is kept for backwards compatibility.
628
- # Instead of calling print_all() you may use print(true) for the same functionality.
629
- def print_all()
625
+ # Instead of calling print_all you may use print(true) for the same functionality.
626
+ def print_all
630
627
  print(true)
631
628
  end
632
629
 
@@ -637,14 +634,14 @@ module DICOM
637
634
  # :levels => true - method will print the level numbers for each element.
638
635
  # :tree => true - method will print a tree structure for the elements.
639
636
  # :file => true - method will print to file instead of printing to screen.
640
- def print(pos, opts={})
637
+ def print(pos, options={})
641
638
  # Process option values, setting defaults for the ones that are not specified:
642
- opt_levels = opts[:levels] || false
643
- opt_tree = opts[:tree] || false
644
- opt_file = opts[:file] || false
639
+ opt_levels = options[:levels] || false
640
+ opt_tree = options[:tree] || false
641
+ opt_file = options[:file] || false
645
642
  # If pos is false, abort, and inform the user:
646
643
  if pos == false
647
- add_msg("Warning: Method print() was supplied false instead of a valid position. Aborting print.")
644
+ add_msg("Warning: Method print was supplied false instead of a valid position. Aborting print.")
648
645
  return
649
646
  end
650
647
  if not pos.is_a?(Array) and pos != true
@@ -658,21 +655,21 @@ module DICOM
658
655
  pos_valid = pos
659
656
  end
660
657
  # Extract the information to be printed from the object arrays:
661
- indices = Array.new()
662
- levels = Array.new()
663
- tags = Array.new()
664
- names = Array.new()
665
- types = Array.new()
666
- lengths = Array.new()
667
- values = Array.new()
658
+ indices = Array.new
659
+ levels = Array.new
660
+ tags = Array.new
661
+ names = Array.new
662
+ types = Array.new
663
+ lengths = Array.new
664
+ values = Array.new
668
665
  # There may be a more elegant way to do this.
669
666
  pos_valid.each do |pos|
670
- tags += [@tags[pos]]
671
- levels += [@levels[pos]]
672
- names += [@names[pos]]
673
- types += [@types[pos]]
674
- lengths += [@lengths[pos].to_s]
675
- values += [@values[pos].to_s]
667
+ tags << @tags[pos]
668
+ levels << @levels[pos]
669
+ names << @names[pos]
670
+ types << @types[pos]
671
+ lengths << @lengths[pos].to_s
672
+ values << @values[pos].to_s
676
673
  end
677
674
  # We have collected the data that is to be printed, now we need to do some string manipulation if hierarchy is to be displayed:
678
675
  if opt_tree
@@ -686,10 +683,10 @@ module DICOM
686
683
  end
687
684
  end
688
685
  # Extract the string lengths which are needed to make the formatting nice:
689
- tag_lengths = Array.new()
690
- name_lengths = Array.new()
691
- type_lengths = Array.new()
692
- length_lengths = Array.new()
686
+ tag_lengths = Array.new
687
+ name_lengths = Array.new
688
+ type_lengths = Array.new
689
+ length_lengths = Array.new
693
690
  names.each_index do |i|
694
691
  tag_lengths[i] = tags[i].length
695
692
  name_lengths[i] = names[i].length
@@ -703,7 +700,7 @@ module DICOM
703
700
  type_maxL = type_lengths.max
704
701
  length_maxL = length_lengths.max
705
702
  # Construct the strings, one for each line of output, where each line contain the information of one data element:
706
- elements = Array.new()
703
+ elements = Array.new
707
704
  # Start of loop which formats the element data:
708
705
  # (This loop is what consumes most of the computing time of this method)
709
706
  tags.each_index do |i|
@@ -733,19 +730,19 @@ module DICOM
733
730
  when "SQ","()"
734
731
  value = "(Encapsulated Elements)"
735
732
  end
736
- elements += [f0 + pos_valid[i].to_s + s + lev + s + tags[i] + f2 + names[i] + f3 + types[i] + f4 + f5 + lengths[i].to_s + s + s + value.rstrip]
733
+ elements << (f0 + pos_valid[i].to_s + s + lev + s + tags[i] + f2 + names[i] + f3 + types[i] + f4 + f5 + lengths[i].to_s + s + s + value.rstrip)
737
734
  end
738
735
  # Print to either screen or file, depending on what the user requested:
739
736
  if opt_file
740
737
  print_file(elements)
741
738
  else
742
739
  print_screen(elements)
743
- end # of tags.each do |i|
744
- end # of method print
740
+ end
741
+ end # of print
745
742
 
746
743
 
747
744
  # Prints the key structural properties of the DICOM file.
748
- def print_properties()
745
+ def print_properties
749
746
  # Explicitness:
750
747
  if @explicit
751
748
  explicit = "Explicit"
@@ -792,11 +789,11 @@ module DICOM
792
789
  puts "Bits per pixel: " + bits
793
790
  end
794
791
  puts "-------------------------------"
795
- end # of method print_properties
792
+ end # of print_properties
796
793
 
797
794
 
798
795
  ####################################################
799
- ### START OF METHODS FOR WRITING INFORMATION TO THE DICOM OBJECT:#
796
+ ### START OF METHODS FOR WRITING INFORMATION TO THE DICOM OBJECT:
800
797
  ####################################################
801
798
 
802
799
 
@@ -817,8 +814,8 @@ module DICOM
817
814
  set_value(bin, "7FE0,0010", :create => true, :bin => true)
818
815
  else
819
816
  add_msg("Content of file is of zero length. Nothing to store.")
820
- end # of if bin.length > 0
821
- end # of method set_image_file
817
+ end
818
+ end
822
819
 
823
820
 
824
821
  # Transfers pixel data from a RMagick object to the pixel data element:
@@ -835,7 +832,7 @@ module DICOM
835
832
  pos = get_pos(element)
836
833
  if pos != false
837
834
  if pos.length > 1
838
- add_msg("Warning: Method remove() does not allow an element query which yields multiple array hits. Please use array position instead of tag/name. Value NOT removed.")
835
+ add_msg("Warning: Method remove does not allow an element query which yields multiple array hits. Please use array position instead of tag/name. Value NOT removed.")
839
836
  else
840
837
  # Extract first array number:
841
838
  pos = pos[0]
@@ -855,29 +852,29 @@ module DICOM
855
852
  @raw.delete_at(pos)
856
853
  end
857
854
  else
858
- add_msg("Warning: The data element #{element} could not be found in the DICOM object. Method remove() has no data element to remove.")
855
+ add_msg("Warning: The data element #{element} could not be found in the DICOM object. Method remove has no data element to remove.")
859
856
  end
860
857
  end
861
858
 
862
859
 
863
860
  # Sets the value of a data element by modifying an existing element or creating a new one.
864
861
  # If the supplied value is not binary, it will attempt to encode the value to binary itself.
865
- def set_value(value, element, opts={})
862
+ def set_value(value, element, options={})
866
863
  # Options:
867
- create = opts[:create] # =false means no element creation
868
- bin = opts[:bin] # =true means value already encoded
864
+ create = options[:create] # =false means no element creation
865
+ bin = options[:bin] # =true means value already encoded
869
866
  # Retrieve array position:
870
867
  pos = get_pos(element)
871
868
  # We do not support changing multiple data elements:
872
869
  if pos.is_a?(Array)
873
870
  if pos.length > 1
874
- add_msg("Warning: Method set_value() does not allow an element query which yields multiple array hits. Please use array position instead of tag/name. Value NOT saved.")
871
+ add_msg("Warning: Method set_value does not allow an element query which yields multiple array hits. Please use array position instead of tag/name. Value NOT saved.")
875
872
  return
876
873
  end
877
874
  end
878
875
  if pos == false and create == false
879
876
  # Since user has requested an element shall only be updated, we can not do so as the element position is not valid:
880
- add_msg("Warning: Invalid data element provided to method set_value(). Value NOT updated.")
877
+ add_msg("Warning: Invalid data element provided to method set_value. Value NOT updated.")
881
878
  elsif create == false
882
879
  # Modify element:
883
880
  modify_element(value, pos[0], :bin => bin)
@@ -890,7 +887,7 @@ module DICOM
890
887
  # We need to create element:
891
888
  tag = @lib.get_tag(element)
892
889
  if tag == false
893
- add_msg("Warning: Method set_value() could not create data element, either because data element name was not recognized in the library, or data element tag is invalid (Expected format of tags is 'GGGG,EEEE').")
890
+ add_msg("Warning: Method set_value could not create data element, either because data element name was not recognized in the library, or data element tag is invalid (Expected format of tags is 'GGGG,EEEE').")
894
891
  else
895
892
  # As we wish to create a new data element, we need to find out where to insert it in the element arrays:
896
893
  # We will do this by finding the last array position of the last element that will (alphabetically/numerically) stay in front of this element.
@@ -913,44 +910,29 @@ module DICOM
913
910
  end
914
911
  # The necessary information is gathered; create new data element:
915
912
  create_element(value, tag, index, :bin => bin)
916
- end # of if tag ==..else..
917
- end # of unless pos ==..else..
918
- end # of if pos ==..and create ==..else..
919
- end # of method set_value
913
+ end
914
+ end
915
+ end
916
+ end # of set_value
920
917
 
921
918
 
922
919
  ##################################################
923
- ############## START OF PRIVATE METHODS:################
920
+ ############## START OF PRIVATE METHODS: ########
924
921
  ##################################################
925
922
  private
926
923
 
927
924
 
928
925
  # Adds a warning or error message to the instance array holding messages, and if verbose variable is true, prints the message as well.
929
926
  def add_msg(msg)
930
- if @verbose
931
- puts msg
932
- end
933
- if (msg.is_a? String)
934
- msg=[msg]
935
- end
936
- @errors += msg
937
- end
938
-
939
-
940
- # Checks the endianness of the system. Returns false if little endian, true if big endian.
941
- def check_sys_endian()
942
- x = 0xdeadbeef
943
- endian_type = {
944
- Array(x).pack("V*") => false, #:little
945
- Array(x).pack("N*") => true #:big
946
- }
947
- return endian_type[Array(x).pack("L*")]
927
+ puts msg if @verbose
928
+ @errors << msg
929
+ @errors.flatten
948
930
  end
949
931
 
950
932
 
951
933
  # Creates a new data element:
952
- def create_element(value, tag, last_pos, opts={})
953
- bin_only = opts[:bin]
934
+ def create_element(value, tag, last_pos, options={})
935
+ bin_only = options[:bin]
954
936
  # Fetch the VR:
955
937
  info = @lib.get_name_vr(tag)
956
938
  vr = info[1]
@@ -1020,7 +1002,7 @@ module DICOM
1020
1002
  else
1021
1003
  add_msg("Binary is nil. Nothing to save.")
1022
1004
  end
1023
- end # of method create_element
1005
+ end # of create_element
1024
1006
 
1025
1007
 
1026
1008
  # Encodes a value to binary (used for inserting values to a DICOM object).
@@ -1029,39 +1011,15 @@ module DICOM
1029
1011
  value = [value] if not value.is_a?(Array)
1030
1012
  # VR will decide how to encode this value:
1031
1013
  case vr
1032
- when "UL"
1033
- bin = value.pack(@ul)
1034
- when "SL"
1035
- bin = value.pack(@sl)
1036
- when "US"
1037
- bin = value.pack(@us)
1038
- when "SS"
1039
- bin = value.pack(@ss)
1040
- when "FL"
1041
- bin = value.pack(@fs)
1042
- when "FD"
1043
- bin = value.pack(@fd)
1044
- when "AT" # (Data element tag: Assume it has the format GGGGEEEE (no comma separation))
1045
- # Encode letter pairs indexes in following order 10 3 2:
1046
- # NB! This may not be encoded correctly on Big Endian files or computers.
1047
- old_format=value[0]
1048
- new_format = old_format[2..3]+old_format[0..1]+old_format[6..7]+old_format[4..5]
1049
- bin = [new_format].pack("H*")
1050
-
1014
+ when "AT" # (Data element tag: Assume it has the format "GGGG,EEEE"
1015
+ bin = @stream.encode_tag(value)
1051
1016
  # We have a number of VRs that are encoded as string:
1052
1017
  when 'AE','AS','CS','DA','DS','DT','IS','LO','LT','PN','SH','ST','TM','UI','UT'
1053
1018
  # In case we are dealing with a number string element, the supplied value might be a number
1054
1019
  # instead of a string, and as such, we convert to string just to make sure this will work nicely:
1055
1020
  value[0] = value[0].to_s
1056
- # Odd/even test (num[0]=1 if num is odd):
1057
- if value[0].length[0] == 1
1058
- # Odd (add a zero byte):
1059
- bin = value.pack('a*') + ["00"].pack("H*")
1060
- else
1061
- # Even:
1062
- bin = value.pack('a*')
1063
- end
1064
- # Image related VR's:
1021
+ bin = @stream.encode_value(value, "STR")
1022
+ # Image related value representations:
1065
1023
  when "OW"
1066
1024
  # What bit depth to use when encoding the pixel data?
1067
1025
  bit_depth = get_value("0028,0100")
@@ -1072,26 +1030,28 @@ module DICOM
1072
1030
  # 8,12 or 16 bits?
1073
1031
  case bit_depth
1074
1032
  when 8
1075
- bin = value.pack(@by)
1033
+ bin = @stream.encode(value, "BY")
1076
1034
  when 12
1077
1035
  # 12 bit not supported yet!
1078
1036
  add_msg("Encoding 12 bit pixel values not supported yet. Please change the bit depth to 8 or 16 bits.")
1079
1037
  when 16
1080
- bin = value.pack(@us)
1038
+ bin = @stream.encode(value, "US")
1081
1039
  else
1082
1040
  # Unknown bit depth:
1083
1041
  add_msg("Unknown bit depth #{bit_depth}. No data encoded.")
1084
- end # of case bit_depth
1085
- end # of if bit_depth..else..
1086
- else # Unsupported VR:
1087
- add_msg("Element type #{vr} does not have a dedicated encoding option assigned. Please contact author.")
1042
+ end
1043
+ end
1044
+ # All other VR's:
1045
+ else
1046
+ # Just encode:
1047
+ bin = @stream.encode(value, vr)
1088
1048
  end # of case vr
1089
1049
  return bin
1090
- end # of method encode
1050
+ end # of encode
1091
1051
 
1092
1052
  # Modifies existing data element:
1093
- def modify_element(value, pos, opts={})
1094
- bin_only = opts[:bin]
1053
+ def modify_element(value, pos, options={})
1054
+ bin_only = options[:bin]
1095
1055
  # Fetch the VR and old length:
1096
1056
  vr = @types[pos]
1097
1057
  old_length = @lengths[pos]
@@ -1123,7 +1083,7 @@ module DICOM
1123
1083
  else
1124
1084
  add_msg("Binary is nil. Nothing to save.")
1125
1085
  end
1126
- end # of method modify_element
1086
+ end
1127
1087
 
1128
1088
 
1129
1089
  # Prints the selected elements to an ascii text file.
@@ -1147,7 +1107,7 @@ module DICOM
1147
1107
 
1148
1108
 
1149
1109
  # Sets the modality variable of the current DICOM object, by querying the library with the object's SOP Class UID.
1150
- def set_modality()
1110
+ def set_modality
1151
1111
  value = get_value("0008,0016", :silent => true)
1152
1112
  if value == false
1153
1113
  @modality = "Not specified"
@@ -1158,29 +1118,20 @@ module DICOM
1158
1118
  end
1159
1119
 
1160
1120
 
1161
- # Sets the format strings that will be used for packing/unpacking numbers depending on endianness of file/system.
1162
- def set_format_strings(file_endian=@file_endian)
1163
- if @file_endian == @sys_endian
1164
- # System endian equals file endian:
1165
- # Native byte order.
1166
- @by = "C*" # Byte (1 byte)
1167
- @us = "S*" # Unsigned short (2 bytes)
1168
- @ss = "s*" # Signed short (2 bytes)
1169
- @ul = "I*" # Unsigned long (4 bytes)
1170
- @sl = "l*" # Signed long (4 bytes)
1171
- @fs = "e*" # Floating point single (4 bytes)
1172
- @fd = "E*" # Floating point double ( 8 bytes)
1173
- else
1174
- # System endian not equal to file endian:
1175
- # Network byte order.
1176
- @by = "C*"
1177
- @us = "n*"
1178
- @ss = "n*" # Not correct (gives US)
1179
- @ul = "N*"
1180
- @sl = "N*" # Not correct (gives UL)
1181
- @fs = "g*"
1182
- @fd = "G*"
1121
+ # Handles the creation of a DWrite object, and returns this object to the calling method.
1122
+ def set_write_object(file_name = nil, transfer_syntax = nil)
1123
+ unless transfer_syntax
1124
+ transfer_syntax = get_value("0002,0010", :silent => true)
1125
+ transfer_syntax = "1.2.840.10008.1.2" if not transfer_syntax # Default is implicit, little endian
1183
1126
  end
1127
+ w = DWrite.new(file_name, :lib => @lib, :sys_endian => @sys_endian, :transfer_syntax => transfer_syntax)
1128
+ w.tags = @tags
1129
+ w.types = @types
1130
+ w.lengths = @lengths
1131
+ w.raw = @raw
1132
+ w.rest_endian = @file_endian
1133
+ w.rest_explicit = @explicit
1134
+ return w
1184
1135
  end
1185
1136
 
1186
1137
 
@@ -1234,9 +1185,9 @@ module DICOM
1234
1185
  # Update arrays:
1235
1186
  @values[gl_pos] = value
1236
1187
  @raw[gl_pos] = bin
1237
- end # of if gl_pos
1238
- end # of method update_group_length
1188
+ end
1189
+ end # of update_group_length
1239
1190
 
1240
1191
 
1241
- end # End of class
1242
- end # End of module
1192
+ end # of class
1193
+ end # of module