dicom 0.8 → 0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/{CHANGELOG → CHANGELOG.rdoc} +100 -52
- data/README.rdoc +126 -0
- data/lib/dicom.rb +13 -7
- data/lib/dicom/anonymizer.rb +129 -111
- data/lib/dicom/constants.rb +60 -10
- data/lib/dicom/d_client.rb +230 -157
- data/lib/dicom/d_library.rb +88 -8
- data/lib/dicom/d_object.rb +141 -149
- data/lib/dicom/d_read.rb +42 -36
- data/lib/dicom/d_server.rb +8 -10
- data/lib/dicom/d_write.rb +25 -46
- data/lib/dicom/dictionary.rb +1 -3
- data/lib/dicom/{data_element.rb → element.rb} +61 -49
- data/lib/dicom/elemental.rb +126 -0
- data/lib/dicom/file_handler.rb +18 -17
- data/lib/dicom/image_item.rb +844 -0
- data/lib/dicom/image_processor.rb +69 -0
- data/lib/dicom/image_processor_mini_magick.rb +74 -0
- data/lib/dicom/image_processor_r_magick.rb +102 -0
- data/lib/dicom/item.rb +21 -19
- data/lib/dicom/link.rb +64 -82
- data/lib/dicom/{super_parent.rb → parent.rb} +270 -39
- data/lib/dicom/ruby_extensions.rb +175 -3
- data/lib/dicom/sequence.rb +5 -6
- data/lib/dicom/stream.rb +37 -25
- data/lib/dicom/variables.rb +51 -0
- data/lib/dicom/version.rb +6 -0
- metadata +97 -29
- data/README +0 -100
- data/init.rb +0 -1
- data/lib/dicom/elements.rb +0 -82
- data/lib/dicom/super_item.rb +0 -696
data/lib/dicom/d_read.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
# Copyright 2008-2010 Christoffer Lervag
|
2
|
-
#
|
3
|
-
# === Notes
|
4
|
-
#
|
5
|
-
# In addition to reading files that are compliant to DICOM 3 Part 10, the philosophy of the Ruby DICOM library is to feature maximum
|
6
|
-
# compatibility, and as such it will also successfully read many types of 'DICOM' files that deviate in some way from the standard.
|
7
|
-
|
8
1
|
module DICOM
|
9
2
|
|
10
3
|
# The DRead class parses the DICOM data from a binary string.
|
11
4
|
#
|
12
5
|
# The source of this binary string is typically either a DICOM file or a DICOM network transmission.
|
13
6
|
#
|
7
|
+
# === Notes
|
8
|
+
#
|
9
|
+
# In addition to reading files that are compliant to DICOM 3 Part 10, the philosophy of the
|
10
|
+
# Ruby DICOM library is to feature maximum compatibility, and as such it will also
|
11
|
+
# successfully read many types of 'DICOM' files that deviate in some way from the standard.
|
12
|
+
#
|
14
13
|
class DRead
|
15
14
|
|
16
15
|
# A boolean which reports the explicitness of the DICOM string, true if explicit and false if implicit.
|
@@ -18,7 +17,7 @@ module DICOM
|
|
18
17
|
# A boolean which reports the endianness of the post-meta group part of the DICOM string (true for big endian, false for little endian).
|
19
18
|
attr_reader :file_endian
|
20
19
|
# An array which records any status messages that are generated while parsing the DICOM string.
|
21
|
-
attr_reader :msg
|
20
|
+
attr_reader :msg
|
22
21
|
# A DObject instance which the parsed data elements will be connected to.
|
23
22
|
attr_reader :obj
|
24
23
|
# A boolean which records whether the DICOM string contained the proper DICOM header signature of 128 bytes + 'DICM'.
|
@@ -38,13 +37,16 @@ module DICOM
|
|
38
37
|
# === Options
|
39
38
|
#
|
40
39
|
# * <tt>:syntax</tt> -- String. If specified, the decoding of the DICOM string will be forced to use this transfer syntax.
|
41
|
-
# * <tt>:bin</tt> -- Boolean. If
|
42
|
-
#
|
40
|
+
# * <tt>:bin</tt> -- Boolean. If true, the string parameter will be interpreted as a binary DICOM string instead of a path string.
|
41
|
+
#
|
43
42
|
def initialize(obj, string=nil, options={})
|
44
43
|
# Set the DICOM object as an instance variable:
|
45
44
|
@obj = obj
|
46
|
-
#
|
47
|
-
|
45
|
+
# If a transfer syntax has been specified as an option for a DICOM object, make sure that it makes it into the object:
|
46
|
+
if options[:syntax]
|
47
|
+
@transfer_syntax = options[:syntax]
|
48
|
+
obj.add(Element.new("0002,0010", options[:syntax])) if obj.is_a?(DObject)
|
49
|
+
end
|
48
50
|
# Initiate the variables that are used during file reading:
|
49
51
|
init_variables
|
50
52
|
# Are we going to read from a file, or read from a binary string?
|
@@ -72,7 +74,7 @@ module DICOM
|
|
72
74
|
# Read and verify the DICOM header:
|
73
75
|
header = check_header
|
74
76
|
# If the file didnt have the expected header, we will attempt to read
|
75
|
-
# data elements from the very start file:
|
77
|
+
# data elements from the very start of the file:
|
76
78
|
if header == false
|
77
79
|
@stream.skip(-132)
|
78
80
|
elsif header == nil
|
@@ -88,9 +90,10 @@ module DICOM
|
|
88
90
|
begin
|
89
91
|
# Extracting Data element information (nil is returned if end of file is encountered in a normal way).
|
90
92
|
data_element = process_data_element
|
91
|
-
rescue
|
93
|
+
rescue Exception => msg
|
92
94
|
# The parse algorithm crashed. Set data_element to false to break the loop and toggle the success boolean to indicate failure.
|
93
|
-
@msg <<
|
95
|
+
@msg << msg
|
96
|
+
@msg << "Error: Failed to parse Data Elements. This was probably an invalid/corrupt DICOM file."
|
94
97
|
@success = false
|
95
98
|
data_element = false
|
96
99
|
end
|
@@ -218,12 +221,9 @@ module DICOM
|
|
218
221
|
@current_parent = @current_parent.parent
|
219
222
|
else
|
220
223
|
# Create an ordinary Data Element:
|
221
|
-
@current_element =
|
224
|
+
@current_element = Element.new(tag, value, :bin => bin, :name => name, :parent => @current_parent, :vr => vr)
|
222
225
|
# Check that the data stream didnt end abruptly:
|
223
|
-
if length != @current_element.bin.length
|
224
|
-
set_abrupt_error
|
225
|
-
return false # (Failed)
|
226
|
-
end
|
226
|
+
raise "Error: The actual length of the binary (#{@current_element.bin.length}) does not match the specified length (#{length}) for Data Element #{@current_element.tag}." if length != @current_element.bin.length
|
227
227
|
end
|
228
228
|
# Return true to indicate success:
|
229
229
|
return true
|
@@ -290,11 +290,8 @@ module DICOM
|
|
290
290
|
else
|
291
291
|
length = @stream.decode(bytes, "SL") # (4)
|
292
292
|
end
|
293
|
-
|
294
|
-
|
295
|
-
# If it is not, it may indicate a file that is not standards compliant or it might even not be a DICOM file.
|
296
|
-
@msg << "Warning: Odd number of bytes in data element's length occured. This is a violation of the DICOM standard, but program will attempt to read the rest of the file anyway."
|
297
|
-
end
|
293
|
+
# Check that length is valid (according to the DICOM standard, it must be even):
|
294
|
+
raise "Error: Encountered a Data Element (#{tag}) with an invalid (odd) value length." if length%2 == 1 and length > 0
|
298
295
|
return vr, length
|
299
296
|
end
|
300
297
|
|
@@ -341,12 +338,29 @@ module DICOM
|
|
341
338
|
#
|
342
339
|
# === Parameters
|
343
340
|
#
|
344
|
-
# * <tt>file</tt> -- A path/file string.
|
341
|
+
# * <tt>file</tt> -- A path/file string. The string may point to a local file or a http location.
|
345
342
|
#
|
346
343
|
def open_file(file)
|
347
|
-
if
|
344
|
+
if file.index('http')==0
|
345
|
+
# Try to open the remote file using open-uri:
|
346
|
+
@retrials = 0
|
347
|
+
begin
|
348
|
+
@file = open(file, 'rb') # binary encoding (ASCII-8BIT)
|
349
|
+
rescue Exception => e
|
350
|
+
if @retrials>3
|
351
|
+
@retrials = 0
|
352
|
+
raise "Unable to read the file. File does not exist?"
|
353
|
+
else
|
354
|
+
puts "Warning: Exception in ruby-dicom when loading a dicom file from: #{file}"
|
355
|
+
puts "Retrying... #{@retrials}"
|
356
|
+
@retrials+=1
|
357
|
+
retry
|
358
|
+
end
|
359
|
+
end
|
360
|
+
elsif File.exist?(file)
|
361
|
+
# Try to read the file on the local file system:
|
348
362
|
if File.readable?(file)
|
349
|
-
if
|
363
|
+
if !File.directory?(file)
|
350
364
|
if File.size(file) > 8
|
351
365
|
@file = File.new(file, "rb")
|
352
366
|
else
|
@@ -363,14 +377,6 @@ module DICOM
|
|
363
377
|
end
|
364
378
|
end
|
365
379
|
|
366
|
-
# Registers an unexpected error by toggling a success boolean and recording an error message.
|
367
|
-
# The DICOM string ended abruptly because the data element's value was shorter than expected.
|
368
|
-
#
|
369
|
-
def set_abrupt_error
|
370
|
-
@msg << "Error! The parsed data of the last data element #{@current_element.tag} does not match its specified length value. This is probably the result of invalid or corrupt DICOM data."
|
371
|
-
@success = false
|
372
|
-
end
|
373
|
-
|
374
380
|
# Changes encoding variables as the file reading proceeds past the initial meta group part (0002,xxxx) of the DICOM file.
|
375
381
|
#
|
376
382
|
def switch_syntax
|
data/lib/dicom/d_server.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# Copyright 2009-2010 Christoffer Lervag
|
2
|
-
|
3
1
|
module DICOM
|
4
2
|
|
5
3
|
# This class contains code for setting up a Service Class Provider (SCP),
|
@@ -20,9 +18,9 @@ module DICOM
|
|
20
18
|
# require 'dicom'
|
21
19
|
# require 'my_file_handler'
|
22
20
|
# include DICOM
|
23
|
-
# DServer.run(104, 'c:/temp/') do
|
24
|
-
# timeout = 100
|
25
|
-
# file_handler = MyFileHandler
|
21
|
+
# DServer.run(104, 'c:/temp/') do |s|
|
22
|
+
# s.timeout = 100
|
23
|
+
# s.file_handler = MyFileHandler
|
26
24
|
# end
|
27
25
|
#
|
28
26
|
def self.run(port=104, path='./received/', &block)
|
@@ -35,7 +33,7 @@ module DICOM
|
|
35
33
|
attr_accessor :file_handler
|
36
34
|
# The name of the server (application entity).
|
37
35
|
attr_accessor :host_ae
|
38
|
-
# The maximum allowed size of network packages (in bytes).
|
36
|
+
# The maximum allowed size of network packages (in bytes).
|
39
37
|
attr_accessor :max_package_size
|
40
38
|
# The network port to be used.
|
41
39
|
attr_accessor :port
|
@@ -43,7 +41,7 @@ module DICOM
|
|
43
41
|
attr_accessor :timeout
|
44
42
|
# A boolean which defines if notices/warnings/errors will be printed to the screen (true) or not (false).
|
45
43
|
attr_accessor :verbose
|
46
|
-
|
44
|
+
|
47
45
|
# A hash containing the abstract syntaxes that will be accepted.
|
48
46
|
attr_reader :accepted_abstract_syntaxes
|
49
47
|
# A hash containing the transfer syntaxes that will be accepted.
|
@@ -64,7 +62,7 @@ module DICOM
|
|
64
62
|
#
|
65
63
|
# * <tt>:file_handler</tt> -- A customized FileHandler class to use instead of the default FileHandler.
|
66
64
|
# * <tt>:host_ae</tt> -- String. The name of the server (application entity).
|
67
|
-
# * <tt>:max_package_size</tt> -- Fixnum. The maximum allowed size of network packages (in bytes).
|
65
|
+
# * <tt>:max_package_size</tt> -- Fixnum. The maximum allowed size of network packages (in bytes).
|
68
66
|
# * <tt>:timeout</tt> -- Fixnum. The maximum period the server will wait on an answer from a client before aborting the communication.
|
69
67
|
# * <tt>:verbose</tt> -- Boolean. If set to false, the DServer instance will run silently and not output warnings and error messages to the screen. Defaults to true.
|
70
68
|
#
|
@@ -107,7 +105,7 @@ module DICOM
|
|
107
105
|
#
|
108
106
|
def add_abstract_syntax(uid)
|
109
107
|
if uid.is_a?(String)
|
110
|
-
name = LIBRARY.get_syntax_description(uid) || "Unknown UID"
|
108
|
+
name = LIBRARY.get_syntax_description(uid) || "Unknown UID"
|
111
109
|
@accepted_abstract_syntaxes[uid] = name
|
112
110
|
else
|
113
111
|
raise "Invalid type of UID. Expected String, got #{uid.class}!"
|
@@ -123,7 +121,7 @@ module DICOM
|
|
123
121
|
#
|
124
122
|
def add_transfer_syntax(uid)
|
125
123
|
if uid.is_a?(String)
|
126
|
-
name = LIBRARY.get_syntax_description(uid) || "Unknown UID"
|
124
|
+
name = LIBRARY.get_syntax_description(uid) || "Unknown UID"
|
127
125
|
@accepted_transfer_syntaxes[uid] = name
|
128
126
|
else
|
129
127
|
raise "Invalid type of UID. Expected String, got #{uid.class}!"
|
data/lib/dicom/d_write.rb
CHANGED
@@ -1,23 +1,21 @@
|
|
1
|
-
# Copyright 2008-2010 Christoffer Lervag
|
2
|
-
#
|
3
|
-
# === Notes
|
4
|
-
#
|
5
|
-
# The philosophy of the Ruby DICOM library is to feature maximum conformance to the DICOM standard.
|
6
|
-
# As such, the class which writes DICOM files may manipulate the meta group, remove/change group lengths and add a header signature.
|
7
|
-
#
|
8
|
-
# Therefore, the file that is written may not be an exact bitwise copy of the file that was read,
|
9
|
-
# even if no DObject manipulation has been done on the part of the user.
|
10
|
-
#
|
11
|
-
# Remember: If this behaviour for some reason is not wanted, it is easy to modify the source code to avoid it.
|
12
|
-
#
|
13
|
-
# It is important to note, that while the goal is to be fully DICOM compliant, no guarantees are given
|
14
|
-
# that this is actually achieved. You are encouraged to thouroughly test your files for compatibility after creation.
|
15
|
-
|
16
1
|
module DICOM
|
17
2
|
|
18
3
|
# The DWrite class handles the encoding of a DObject instance to a valid DICOM string.
|
19
4
|
# The String is either written to file or returned in segments to be used for network transmission.
|
20
5
|
#
|
6
|
+
# === Notes
|
7
|
+
#
|
8
|
+
# The philosophy of the Ruby DICOM library is to feature maximum conformance to the DICOM standard.
|
9
|
+
# As such, the class which writes DICOM files may manipulate the meta group, remove/change group lengths and add a header signature.
|
10
|
+
#
|
11
|
+
# Therefore, the file that is written may not be an exact bitwise copy of the file that was read,
|
12
|
+
# even if no DObject manipulation has been done on the part of the user.
|
13
|
+
#
|
14
|
+
# Remember: If this behaviour for some reason is not wanted, it is easy to modify the source code to avoid it.
|
15
|
+
#
|
16
|
+
# It is important to note, that while the goal is to be fully DICOM compliant, no guarantees are given
|
17
|
+
# that this is actually achieved. You are encouraged to thouroughly test your files for compatibility after creation.
|
18
|
+
#
|
21
19
|
class DWrite
|
22
20
|
|
23
21
|
# An array which records any status messages that are generated while encoding/writing the DICOM string.
|
@@ -103,14 +101,10 @@ module DICOM
|
|
103
101
|
@max_size = max_size
|
104
102
|
@segments = Array.new
|
105
103
|
elements = @obj.children
|
106
|
-
# When sending a DICOM file across the network, no header or meta information is needed.
|
107
|
-
# We must therefore find the position of the first tag which is not a meta information tag.
|
108
|
-
first_pos = first_non_meta(elements)
|
109
|
-
selected_elements = elements[first_pos..-1]
|
110
104
|
# Create a Stream instance to handle the encoding of content to
|
111
105
|
# the binary string that will eventually be saved to file:
|
112
106
|
@stream = Stream.new(nil, @file_endian)
|
113
|
-
write_data_elements(
|
107
|
+
write_data_elements(elements)
|
114
108
|
# Extract the remaining string in our stream instance to our array of strings:
|
115
109
|
@segments << @stream.export
|
116
110
|
# Mark this write session as successful:
|
@@ -134,19 +128,21 @@ module DICOM
|
|
134
128
|
else
|
135
129
|
# As the encoded DICOM string will be cut in multiple, smaller pieces, we need to monitor the length of our encoded strings:
|
136
130
|
if (string.length + @stream.length) > @max_size
|
137
|
-
|
131
|
+
# Duplicate the string as not to ruin the binary of the data element with our slicing:
|
132
|
+
segment = string.dup
|
133
|
+
append = segment.slice!(0, @max_size-@stream.length)
|
138
134
|
# Join these strings together and add them to the segments:
|
139
135
|
@segments << @stream.export + append
|
140
|
-
if (30 +
|
136
|
+
if (30 + segment.length) > @max_size
|
141
137
|
# The remaining part of the string is bigger than the max limit, fill up more segments:
|
142
138
|
# How many full segments will this string fill?
|
143
|
-
number = (
|
144
|
-
number.times {@segments <<
|
139
|
+
number = (segment.length/@max_size.to_f).floor
|
140
|
+
number.times {@segments << segment.slice!(0, @max_size)}
|
145
141
|
# The remaining part is added to the stream:
|
146
|
-
@stream.add_last(
|
142
|
+
@stream.add_last(segment)
|
147
143
|
else
|
148
144
|
# The rest of the string is small enough that it can be added to the stream:
|
149
|
-
@stream.add_last(
|
145
|
+
@stream.add_last(segment)
|
150
146
|
end
|
151
147
|
elsif (30 + @stream.length) > @max_size
|
152
148
|
# End the current segment, and start on a new segment for this string.
|
@@ -209,7 +205,7 @@ module DICOM
|
|
209
205
|
# Among group length elements, only write the meta group element (the others have been retired in the DICOM standard):
|
210
206
|
write_data_element(element) if element.tag == "0002,0000"
|
211
207
|
else
|
212
|
-
write_data_element(element)
|
208
|
+
write_data_element(element)
|
213
209
|
end
|
214
210
|
end
|
215
211
|
end
|
@@ -315,7 +311,7 @@ module DICOM
|
|
315
311
|
#
|
316
312
|
def write_value(bin)
|
317
313
|
# This is pretty straightforward, just dump the binary data to the file/string:
|
318
|
-
add(bin)
|
314
|
+
add(bin) if bin
|
319
315
|
end
|
320
316
|
|
321
317
|
|
@@ -347,7 +343,7 @@ module DICOM
|
|
347
343
|
unless File.directory?(path)
|
348
344
|
# We need to create (parts of) this path:
|
349
345
|
require 'fileutils'
|
350
|
-
FileUtils.mkdir_p
|
346
|
+
FileUtils.mkdir_p(path)
|
351
347
|
end
|
352
348
|
end
|
353
349
|
# The path to this non-existing file is verified, and we can proceed to create the file:
|
@@ -384,23 +380,6 @@ module DICOM
|
|
384
380
|
@stream.endian = @rest_endian
|
385
381
|
end
|
386
382
|
|
387
|
-
# Identifies and returns the index of the first data element that does not have a meta group ("0002,xxxx") tag.
|
388
|
-
#
|
389
|
-
# === Parameters
|
390
|
-
#
|
391
|
-
# * <tt>elements</tt> -- An array of data elements.
|
392
|
-
#
|
393
|
-
def first_non_meta(elements)
|
394
|
-
non_meta_index = 0
|
395
|
-
elements.each_index do |i|
|
396
|
-
if elements[i].tag.group != META_GROUP
|
397
|
-
non_meta_index = i
|
398
|
-
break
|
399
|
-
end
|
400
|
-
end
|
401
|
-
return non_meta_index
|
402
|
-
end
|
403
|
-
|
404
383
|
# Creates various variables used when encoding the DICOM string.
|
405
384
|
#
|
406
385
|
def init_variables
|
data/lib/dicom/dictionary.rb
CHANGED
@@ -1,22 +1,20 @@
|
|
1
|
-
# Copyright 2010 Christoffer Lervag
|
2
|
-
|
3
1
|
module DICOM
|
4
2
|
|
5
|
-
# The
|
3
|
+
# The Element class handles information related to ordinary (non-parent) elementals (data elements).
|
6
4
|
#
|
7
|
-
class
|
5
|
+
class Element
|
8
6
|
|
9
|
-
# Include the
|
10
|
-
include
|
7
|
+
# Include the Elemental mix-in module:
|
8
|
+
include Elemental
|
11
9
|
|
12
10
|
# The (decoded) value of the data element.
|
13
11
|
attr_reader :value
|
14
12
|
|
15
|
-
# Creates a
|
13
|
+
# Creates a Element instance.
|
16
14
|
#
|
17
15
|
# === Notes
|
18
16
|
#
|
19
|
-
# * In the case where the
|
17
|
+
# * In the case where the Element is given a binary instead of value, the Element will not have a formatted value (value = nil).
|
20
18
|
# * Private data elements will have their names listed as "Private".
|
21
19
|
# * Non-private data elements that are not found in the dictionary will be listed as "Unknown".
|
22
20
|
#
|
@@ -30,20 +28,21 @@ module DICOM
|
|
30
28
|
#
|
31
29
|
# * <tt>:bin</tt> -- String. If you already have the value pre-encoded to a binary string, the string can be supplied with this option to avoid it being encoded a second time.
|
32
30
|
# * <tt>:encoded</tt> -- Boolean. If the value parameter contains a pre-encoded binary, this boolean must to be set as true.
|
33
|
-
# * <tt>:name</tt> - String. The name of the
|
34
|
-
# * <tt>:parent</tt> - Item or DObject instance which the
|
35
|
-
# * <tt>:vr</tt> -- String. If a private
|
31
|
+
# * <tt>:name</tt> - String. The name of the Element may be specified upon creation. If it is not, the name will be retrieved from the dictionary.
|
32
|
+
# * <tt>:parent</tt> - Item or DObject instance which the Element instance shall belong to.
|
33
|
+
# * <tt>:vr</tt> -- String. If a private Element is created with a custom value, this must be specified to enable the encoding of the value. If it is not specified, the vr will be retrieved from the dictionary.
|
36
34
|
#
|
37
35
|
# === Examples
|
38
36
|
#
|
39
37
|
# # Create a new data element and connect it to a DObject instance:
|
40
|
-
# patient_name =
|
38
|
+
# patient_name = Element.new("0010,0010", "John Doe", :parent => obj)
|
41
39
|
# # Create a "Pixel Data" element and insert image data that you have already encoded elsewhere:
|
42
|
-
# pixel_data =
|
40
|
+
# pixel_data = Element.new("7FE0,0010", processed_pixel_data, :encoded => true, :parent => obj)
|
43
41
|
# # Create a private data element:
|
44
|
-
# private_data =
|
42
|
+
# private_data = Element.new("0011,2102", some_data, :parent => obj, :vr => "LO")
|
45
43
|
#
|
46
44
|
def initialize(tag, value, options={})
|
45
|
+
raise ArgumentError, "The supplied tag (#{tag}) is not valid. The tag must be a string of the form 'GGGG,EEEE'." unless tag.is_a?(String) && tag.tag?
|
47
46
|
# Set instance variables:
|
48
47
|
@tag = tag
|
49
48
|
# We may beed to retrieve name and vr from the library:
|
@@ -78,11 +77,11 @@ module DICOM
|
|
78
77
|
# Manage the parent relation if specified:
|
79
78
|
if options[:parent]
|
80
79
|
@parent = options[:parent]
|
81
|
-
@parent.add(self)
|
80
|
+
@parent.add(self, :no_follow => true)
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
85
|
-
# Sets the binary string of a
|
84
|
+
# Sets the binary string of a Element.
|
86
85
|
#
|
87
86
|
# === Notes
|
88
87
|
#
|
@@ -94,46 +93,74 @@ module DICOM
|
|
94
93
|
# * <tt>new_bin</tt> -- A binary string of encoded data.
|
95
94
|
#
|
96
95
|
def bin=(new_bin)
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
else
|
102
|
-
@bin = new_bin
|
103
|
-
end
|
104
|
-
@value = nil
|
105
|
-
@length = @bin.length
|
96
|
+
raise ArgumentError, "Expected String, got #{new_bin.class}." unless new_bin.is_a?(String)
|
97
|
+
# Add a zero byte at the end if the length of the binary is odd:
|
98
|
+
if new_bin.length[0] == 1
|
99
|
+
@bin = new_bin + stream.pad_byte[@vr]
|
106
100
|
else
|
107
|
-
|
101
|
+
@bin = new_bin
|
108
102
|
end
|
103
|
+
@value = nil
|
104
|
+
@length = @bin.length
|
109
105
|
end
|
110
106
|
|
111
|
-
# Checks if
|
112
|
-
# Returns false, as
|
107
|
+
# Checks if the Element actually has any child elementals.
|
108
|
+
# Returns false, as Element instances by definition can not have children.
|
113
109
|
#
|
114
110
|
def children?
|
115
111
|
return false
|
116
112
|
end
|
117
113
|
|
118
|
-
#
|
119
|
-
# Returns false
|
114
|
+
# Returns the endianness of the encoded binary value of this data element.
|
115
|
+
# Returns false if little endian, true if big endian.
|
116
|
+
#
|
117
|
+
def endian
|
118
|
+
return stream.str_endian
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns a string containing a human-readable hash representation of the Element.
|
122
|
+
#
|
123
|
+
def inspect
|
124
|
+
to_hash.inspect
|
125
|
+
end
|
126
|
+
|
127
|
+
# Checks if the Element is a parent.
|
128
|
+
# Returns false, as Element instances by definition can not be parents.
|
120
129
|
#
|
121
130
|
def is_parent?
|
122
131
|
return false
|
123
132
|
end
|
124
133
|
|
125
|
-
#
|
134
|
+
# Returns the value of the elemental (used as value in the parent's hash representation).
|
135
|
+
#
|
136
|
+
def to_hash
|
137
|
+
return {self.send(DICOM.key_representation) => value}
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns a json string containing a human-readable representation of the Element.
|
141
|
+
#
|
142
|
+
def to_json
|
143
|
+
to_hash.to_json
|
144
|
+
end
|
145
|
+
|
146
|
+
# Returns a yaml string containing a human-readable representation of the Element.
|
147
|
+
#
|
148
|
+
def to_yaml
|
149
|
+
to_hash.to_yaml
|
150
|
+
end
|
151
|
+
|
152
|
+
# Sets the value of the Element instance.
|
126
153
|
#
|
127
154
|
# === Notes
|
128
155
|
#
|
129
156
|
# In addition to updating the value attribute, the specified value is encoded and used to
|
130
|
-
# update both the
|
157
|
+
# update both the Element's binary and length attributes too.
|
131
158
|
#
|
132
|
-
# The specified value must be of a type that is compatible with the
|
159
|
+
# The specified value must be of a type that is compatible with the Element's value representation (vr).
|
133
160
|
#
|
134
161
|
# === Parameters
|
135
162
|
#
|
136
|
-
# * <tt>new_value</tt> -- A custom value (String, Fixnum, etc..) that is assigned to the
|
163
|
+
# * <tt>new_value</tt> -- A custom value (String, Fixnum, etc..) that is assigned to the Element.
|
137
164
|
#
|
138
165
|
def value=(new_value)
|
139
166
|
@bin = encode(new_value)
|
@@ -156,20 +183,5 @@ module DICOM
|
|
156
183
|
return stream.encode_value(formatted_value, @vr)
|
157
184
|
end
|
158
185
|
|
159
|
-
# Returns a Stream instance which can be used for encoding a value to binary.
|
160
|
-
#
|
161
|
-
# === Notes
|
162
|
-
#
|
163
|
-
# * Retrieves the Stream instance of the top parent DObject instance.
|
164
|
-
# If this fails, a new Stream instance is created (with Little Endian encoding assumed).
|
165
|
-
#
|
166
|
-
def stream
|
167
|
-
if top_parent.is_a?(DObject)
|
168
|
-
return top_parent.stream
|
169
|
-
else
|
170
|
-
return Stream.new(nil, file_endian=false)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
186
|
end
|
175
187
|
end
|