dicom 0.7 → 0.8
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 +55 -0
- data/README +51 -29
- data/init.rb +1 -0
- data/lib/dicom.rb +35 -21
- data/lib/dicom/{Anonymizer.rb → anonymizer.rb} +178 -80
- data/lib/dicom/constants.rb +121 -0
- data/lib/dicom/d_client.rb +888 -0
- data/lib/dicom/d_library.rb +208 -0
- data/lib/dicom/d_object.rb +424 -0
- data/lib/dicom/d_read.rb +433 -0
- data/lib/dicom/d_server.rb +397 -0
- data/lib/dicom/d_write.rb +420 -0
- data/lib/dicom/data_element.rb +175 -0
- data/lib/dicom/{Dictionary.rb → dictionary.rb} +390 -398
- data/lib/dicom/elements.rb +82 -0
- data/lib/dicom/file_handler.rb +116 -0
- data/lib/dicom/item.rb +87 -0
- data/lib/dicom/{Link.rb → link.rb} +749 -388
- data/lib/dicom/ruby_extensions.rb +44 -35
- data/lib/dicom/sequence.rb +62 -0
- data/lib/dicom/stream.rb +493 -0
- data/lib/dicom/super_item.rb +696 -0
- data/lib/dicom/super_parent.rb +615 -0
- metadata +25 -18
- data/DOCUMENTATION +0 -469
- data/lib/dicom/DClient.rb +0 -584
- data/lib/dicom/DLibrary.rb +0 -194
- data/lib/dicom/DObject.rb +0 -1579
- data/lib/dicom/DRead.rb +0 -532
- data/lib/dicom/DServer.rb +0 -304
- data/lib/dicom/DWrite.rb +0 -410
- data/lib/dicom/FileHandler.rb +0 -50
- data/lib/dicom/Stream.rb +0 -354
@@ -1,47 +1,56 @@
|
|
1
|
-
# This file contains extensions to the Ruby library which are used by Ruby
|
1
|
+
# This file contains extensions to the Ruby library which are used by Ruby-DICOM.
|
2
2
|
|
3
|
-
class
|
3
|
+
# Extension to the String class. These extensions are focused on processing/analysing Data Element tags.
|
4
|
+
# A tag string (as used by the Ruby-DICOM library) is 9 characters long and of the form "GGGG,EEEE"
|
5
|
+
# (where G represents a group hexadecimal, and E represents an element hexadecimal).
|
6
|
+
#
|
7
|
+
class String
|
4
8
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
def
|
8
|
-
|
9
|
-
self.each do |pos|
|
10
|
-
result << pos if array[pos] == value
|
11
|
-
end
|
12
|
-
return result
|
9
|
+
# Returns the element part of the tag string: The last 4 characters.
|
10
|
+
#
|
11
|
+
def element
|
12
|
+
return self[5..8]
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
def
|
18
|
-
|
19
|
-
self.each do |pos|
|
20
|
-
result << pos if array[pos].include?(value)
|
21
|
-
end
|
22
|
-
return result
|
15
|
+
# Returns the group part of the tag string: The first 4 characters.
|
16
|
+
#
|
17
|
+
def group
|
18
|
+
return self[0..3]
|
23
19
|
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
# Returns the "Group Length" ("GGGG,0000") tag which corresponds to the original tag/group string.
|
22
|
+
# This string may either be a 4 character group string, or a 9 character custom tag.
|
23
|
+
#
|
24
|
+
def group_length
|
25
|
+
if self.length == 4
|
26
|
+
return self + ",0000"
|
27
|
+
else
|
28
|
+
return self.group + ",0000"
|
29
|
+
end
|
30
|
+
end
|
28
31
|
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
#result = true if self =~ /\A\h{4},\h{4}\z/ # (turns out the hex reference '\h' isnt compatible with ruby 1.8)
|
35
|
-
result = true if self =~ /\A[a-fA-F\d]{4},[a-fA-F\d]{4}\z/
|
36
|
-
return result
|
32
|
+
# Checks if the string is a "Group Length" tag (its element part is "0000").
|
33
|
+
# Returns true if it is and false if not.
|
34
|
+
#
|
35
|
+
def group_length?
|
36
|
+
return (self.element == "0000" ? true : false)
|
37
37
|
end
|
38
38
|
|
39
|
-
#
|
39
|
+
# Checks if the string is a private tag (has an odd group number).
|
40
|
+
# Returns true if it is, false if not.
|
41
|
+
#
|
40
42
|
def private?
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
#return ((self.upcase =~ /\A\h{3}[1,3,5,7,9,B,D,F],\h{4}\z/) == nil ? false : true) # (incompatible with ruby 1.8)
|
44
|
+
return ((self.upcase =~ /\A[a-fA-F\d]{3}[1,3,5,7,9,B,D,F],[a-fA-F\d]{4}\z/) == nil ? false : true)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Checks if the string is a valid tag (as defined by Ruby-DICOM: "GGGG,EEEE").
|
48
|
+
# Returns true if it is a valid tag, false if not.
|
49
|
+
#
|
50
|
+
def tag?
|
51
|
+
# Test that the string is composed of exactly 4 HEX characters, followed by a comma, then 4 more HEX characters:
|
52
|
+
#return ((self.upcase =~ /\A\h{4},\h{4}\z/) == nil ? false : true) # (It turns out the hex reference '\h' isnt compatible with ruby 1.8)
|
53
|
+
return ((self.upcase =~ /\A[a-fA-F\d]{4},[a-fA-F\d]{4}\z/) == nil ? false : true)
|
45
54
|
end
|
46
55
|
|
47
|
-
end
|
56
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Copyright 2010 Christoffer Lervag
|
2
|
+
|
3
|
+
module DICOM
|
4
|
+
|
5
|
+
# The Sequence class handles information related to Sequence elements.
|
6
|
+
#
|
7
|
+
class Sequence < SuperParent
|
8
|
+
|
9
|
+
# Include the Elements mix-in module:
|
10
|
+
include Elements
|
11
|
+
|
12
|
+
# Creates a Sequence instance.
|
13
|
+
#
|
14
|
+
# === Notes
|
15
|
+
#
|
16
|
+
# * Private sequences will have their names listed as "Private".
|
17
|
+
# * Non-private sequences that are not found in the dictionary will be listed as "Unknown".
|
18
|
+
#
|
19
|
+
# === Parameters
|
20
|
+
#
|
21
|
+
# * <tt>tag</tt> -- A string which identifies the tag of the sequence.
|
22
|
+
# * <tt>options</tt> -- A hash of parameters.
|
23
|
+
#
|
24
|
+
# === Options
|
25
|
+
#
|
26
|
+
# * <tt>:length</tt> -- Fixnum. The Sequence length, which refers to the length of the encoded string of children of this Sequence.
|
27
|
+
# * <tt>:name</tt> - String. The name of the Sequence may be specified upon creation. If it is not, the name will be retrieved from the dictionary.
|
28
|
+
# * <tt>:parent</tt> - Item or DObject instance which the Sequence instance shall belong to.
|
29
|
+
# * <tt>:vr</tt> -- String. The value representation of the Sequence may be specified upon creation. If it is not, a default vr is chosen.
|
30
|
+
#
|
31
|
+
# === Examples
|
32
|
+
#
|
33
|
+
# # Create a new Sequence and connect it to a DObject instance:
|
34
|
+
# structure_set_roi = Sequence.new("3006,0020", :parent => obj)
|
35
|
+
# # Create an "Encapsulated Pixel Data" Sequence:
|
36
|
+
# encapsulated_pixel_data = Sequence.new("7FE0,0010", :name => "Encapsulated Pixel Data", :parent => obj, :vr => "OW")
|
37
|
+
#
|
38
|
+
def initialize(tag, options={})
|
39
|
+
# Set common parent variables:
|
40
|
+
initialize_parent
|
41
|
+
# Set instance variables:
|
42
|
+
@tag = tag
|
43
|
+
@value = nil
|
44
|
+
@bin = nil
|
45
|
+
# We may beed to retrieve name and vr from the library:
|
46
|
+
if options[:name] and options[:vr]
|
47
|
+
@name = options[:name]
|
48
|
+
@vr = options[:vr]
|
49
|
+
else
|
50
|
+
name, vr = LIBRARY.get_name_vr(tag)
|
51
|
+
@name = options[:name] || name
|
52
|
+
@vr = options[:vr] || "SQ"
|
53
|
+
end
|
54
|
+
@length = options[:length] || -1
|
55
|
+
if options[:parent]
|
56
|
+
@parent = options[:parent]
|
57
|
+
@parent.add(self)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/dicom/stream.rb
ADDED
@@ -0,0 +1,493 @@
|
|
1
|
+
# Copyright 2009-2010 Christoffer Lervag
|
2
|
+
|
3
|
+
module DICOM
|
4
|
+
|
5
|
+
# The Stream class handles string operations (encoding to and decoding from binary strings).
|
6
|
+
# It is used by the various classes of Ruby DICOM for tasks such as reading and writing from/to files or network packets.
|
7
|
+
# These methods have been gathered in this single class in an attempt to minimize code duplication.
|
8
|
+
#
|
9
|
+
class Stream
|
10
|
+
|
11
|
+
# A boolean which reports the relationship between the endianness of the system and the instance string.
|
12
|
+
attr_reader :equal_endian
|
13
|
+
# Our current position in the instance string (used only for decoding).
|
14
|
+
attr_accessor :index
|
15
|
+
# The instance string.
|
16
|
+
attr_accessor :string
|
17
|
+
# An array of warning/error messages that (may) have been accumulated.
|
18
|
+
attr_reader :errors
|
19
|
+
# A hash with vr as key and its corresponding pad byte as value.
|
20
|
+
attr_reader :pad_byte
|
21
|
+
|
22
|
+
# Creates a Stream instance.
|
23
|
+
#
|
24
|
+
# === Parameters
|
25
|
+
#
|
26
|
+
# * <tt>binary</tt> -- A binary string.
|
27
|
+
# * <tt>string_endian</tt> -- Boolean. The endianness of the instance string (true for big endian, false for small endian).
|
28
|
+
# * <tt>options</tt> -- A hash of parameters.
|
29
|
+
#
|
30
|
+
# === Options
|
31
|
+
#
|
32
|
+
# * <tt>:index</tt> -- Fixnum. A position (offset) in the instance string where reading will start.
|
33
|
+
#
|
34
|
+
def initialize(binary, string_endian, options={})
|
35
|
+
@string = binary || ""
|
36
|
+
@index = options[:index] || 0
|
37
|
+
@errors = Array.new
|
38
|
+
self.endian = string_endian
|
39
|
+
end
|
40
|
+
|
41
|
+
# Prepends a pre-encoded string to the instance string (inserts at the beginning).
|
42
|
+
#
|
43
|
+
# === Parameters
|
44
|
+
#
|
45
|
+
# * <tt>binary</tt> -- A binary string.
|
46
|
+
#
|
47
|
+
def add_first(binary)
|
48
|
+
@string = binary + @string if binary
|
49
|
+
end
|
50
|
+
|
51
|
+
# Appends a pre-encoded string to the instance string (inserts at the end).
|
52
|
+
#
|
53
|
+
# === Parameters
|
54
|
+
#
|
55
|
+
# * <tt>binary</tt> -- A binary string.
|
56
|
+
#
|
57
|
+
def add_last(binary)
|
58
|
+
@string = @string + binary if binary
|
59
|
+
end
|
60
|
+
|
61
|
+
# Decodes a section of the instance string and returns the formatted data.
|
62
|
+
# The instance index is offset in accordance with the length read.
|
63
|
+
#
|
64
|
+
# === Notes
|
65
|
+
#
|
66
|
+
# * If multiple numbers are decoded, these are returned in an array.
|
67
|
+
#
|
68
|
+
# === Parameters
|
69
|
+
#
|
70
|
+
# * <tt>length</tt> -- Fixnum. The string length which will be decoded.
|
71
|
+
# * <tt>type</tt> -- String. The type (vr) of data to decode.
|
72
|
+
#
|
73
|
+
def decode(length, type)
|
74
|
+
# Check if values are valid:
|
75
|
+
if (@index + length) > @string.length
|
76
|
+
# The index number is bigger then the length of the binary string.
|
77
|
+
# We have reached the end and will return nil.
|
78
|
+
value = nil
|
79
|
+
else
|
80
|
+
# Decode the binary string and return value:
|
81
|
+
value = @string.slice(@index, length).unpack(vr_to_str(type))
|
82
|
+
# If the result is an array of one element, return the element instead of the array.
|
83
|
+
# If result is contained in a multi-element array, the original array is returned.
|
84
|
+
if value.length == 1
|
85
|
+
value = value[0]
|
86
|
+
# If value is a string, strip away possible trailing whitespace:
|
87
|
+
value = value.rstrip if value.is_a?(String)
|
88
|
+
end
|
89
|
+
# Update our position in the string:
|
90
|
+
skip(length)
|
91
|
+
end
|
92
|
+
return value
|
93
|
+
end
|
94
|
+
|
95
|
+
# Decodes the entire instance string and returns the formatted data.
|
96
|
+
# Typically used for decoding image data.
|
97
|
+
#
|
98
|
+
# === Notes
|
99
|
+
#
|
100
|
+
# * If multiple numbers are decoded, these are returned in an array.
|
101
|
+
#
|
102
|
+
# === Parameters
|
103
|
+
#
|
104
|
+
# * <tt>type</tt> -- String. The type (vr) of data to decode.
|
105
|
+
#
|
106
|
+
def decode_all(type)
|
107
|
+
length = @string.length
|
108
|
+
value = @string.slice(@index, length).unpack(vr_to_str(type))
|
109
|
+
skip(length)
|
110
|
+
return value
|
111
|
+
end
|
112
|
+
|
113
|
+
# Decodes 4 bytes of the instance string as a tag.
|
114
|
+
# Returns the tag string as a Ruby DICOM type tag ("GGGG,EEEE").
|
115
|
+
# Returns nil if no tag could be decoded (end of string).
|
116
|
+
#
|
117
|
+
def decode_tag
|
118
|
+
length = 4
|
119
|
+
# Check if values are valid:
|
120
|
+
if (@index + length) > @string.length
|
121
|
+
# The index number is bigger then the length of the binary string.
|
122
|
+
# We have reached the end and will return nil.
|
123
|
+
tag = nil
|
124
|
+
else
|
125
|
+
# Decode and process:
|
126
|
+
string = @string.slice(@index, length).unpack(@hex)[0].upcase
|
127
|
+
if @equal_endian
|
128
|
+
tag = string[2..3] + string[0..1] + "," + string[6..7] + string[4..5]
|
129
|
+
else
|
130
|
+
tag = string[0..3] + "," + string[4..7]
|
131
|
+
end
|
132
|
+
# Update our position in the string:
|
133
|
+
skip(length)
|
134
|
+
end
|
135
|
+
return tag
|
136
|
+
end
|
137
|
+
|
138
|
+
# Encodes a value and returns the resulting binary string.
|
139
|
+
#
|
140
|
+
# === Parameters
|
141
|
+
#
|
142
|
+
# * <tt>value</tt> -- A custom value (String, Fixnum, etc..) or an array of numbers.
|
143
|
+
# * <tt>type</tt> -- String. The type (vr) of data to encode.
|
144
|
+
#
|
145
|
+
def encode(value, type)
|
146
|
+
value = [value] unless value.is_a?(Array)
|
147
|
+
return value.pack(vr_to_str(type))
|
148
|
+
end
|
149
|
+
|
150
|
+
# Encodes a value to a binary string and prepends it to the instance string.
|
151
|
+
#
|
152
|
+
# === Parameters
|
153
|
+
#
|
154
|
+
# * <tt>value</tt> -- A custom value (String, Fixnum, etc..) or an array of numbers.
|
155
|
+
# * <tt>type</tt> -- String. The type (vr) of data to encode.
|
156
|
+
#
|
157
|
+
def encode_first(value, type)
|
158
|
+
value = [value] unless value.is_a?(Array)
|
159
|
+
bin = value.pack(vr_to_str(type))
|
160
|
+
@string = bin + @string
|
161
|
+
end
|
162
|
+
|
163
|
+
# Encodes a value to a binary string and appends it to the instance string.
|
164
|
+
#
|
165
|
+
# === Parameters
|
166
|
+
#
|
167
|
+
# * <tt>value</tt> -- A custom value (String, Fixnum, etc..) or an array of numbers.
|
168
|
+
# * <tt>type</tt> -- String. The type (vr) of data to encode.
|
169
|
+
#
|
170
|
+
def encode_last(value, type)
|
171
|
+
value = [value] unless value.is_a?(Array)
|
172
|
+
bin = value.pack(vr_to_str(type))
|
173
|
+
@string = @string + bin
|
174
|
+
end
|
175
|
+
|
176
|
+
# Appends a string with trailling spaces to achieve a target length, and encodes it to a binary string.
|
177
|
+
# Returns the binary string.
|
178
|
+
#
|
179
|
+
# === Parameters
|
180
|
+
#
|
181
|
+
# * <tt>string</tt> -- A string to be processed.
|
182
|
+
# * <tt>target_length</tt> -- Fixnum. The target length of the string that is created.
|
183
|
+
#
|
184
|
+
def encode_string_with_trailing_spaces(string, target_length)
|
185
|
+
length = string.length
|
186
|
+
if length < target_length
|
187
|
+
return [string].pack(@str)+["20"*(target_length-length)].pack(@hex)
|
188
|
+
elsif length == target_length
|
189
|
+
return [string].pack(@str)
|
190
|
+
else
|
191
|
+
raise "The specified string is longer than the allowed maximum length (String: #{string}, Target length: #{target_length})."
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Encodes a tag from the Ruby DICOM format ("GGGG,EEEE"), to a proper binary string, and returns it.
|
196
|
+
#
|
197
|
+
# === Parameters
|
198
|
+
#
|
199
|
+
# * <tt>string</tt> -- A string to be processed.
|
200
|
+
#
|
201
|
+
def encode_tag(tag)
|
202
|
+
if @equal_endian
|
203
|
+
clean_tag = tag[2..3] + tag[0..1] + tag[7..8] + tag[5..6]
|
204
|
+
else
|
205
|
+
clean_tag = tag[0..3] + tag[5..8]
|
206
|
+
end
|
207
|
+
return [clean_tag].pack(@hex)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Encodes a value, and if the the resulting binary string has an odd length, appends a proper padding byte.
|
211
|
+
# Returns the processed binary string (which will always be of even length).
|
212
|
+
#
|
213
|
+
# === Parameters
|
214
|
+
#
|
215
|
+
# * <tt>value</tt> -- A custom value (String, Fixnum, etc..) or an array of numbers.
|
216
|
+
# * <tt>vr</tt> -- String. The type of data to encode.
|
217
|
+
#
|
218
|
+
def encode_value(value, vr)
|
219
|
+
# Make sure the value is in an array:
|
220
|
+
value = [value] unless value.is_a?(Array)
|
221
|
+
# Get the proper pack string:
|
222
|
+
type = vr_to_str(vr)
|
223
|
+
# Encode:
|
224
|
+
bin = value.pack(type)
|
225
|
+
# Add an empty byte if the resulting binary has an odd length:
|
226
|
+
bin = bin + @pad_byte[vr] if bin.length[0] == 1
|
227
|
+
return bin
|
228
|
+
end
|
229
|
+
|
230
|
+
# Sets the endianness of the instance string. The relationship between the string endianness and
|
231
|
+
# the system endianness, determines which encoding/decoding flags to use.
|
232
|
+
#
|
233
|
+
# === Parameters
|
234
|
+
#
|
235
|
+
# * <tt>string_endian</tt> -- Boolean. The endianness of the instance string (true for big endian, false for small endian).
|
236
|
+
#
|
237
|
+
def endian=(string_endian)
|
238
|
+
@str_endian = string_endian
|
239
|
+
configure_endian
|
240
|
+
set_pad_byte
|
241
|
+
set_string_formats
|
242
|
+
set_format_hash
|
243
|
+
end
|
244
|
+
|
245
|
+
# Extracts and returns the entire instance string, or optionally,
|
246
|
+
# just the first part of it if a length is specified.
|
247
|
+
# The extracted string is removed from the instance string, and returned.
|
248
|
+
#
|
249
|
+
# === Parameters
|
250
|
+
#
|
251
|
+
# * <tt>length</tt> -- Fixnum. The length of the string which will be cut out. If nil, the entire string is exported.
|
252
|
+
#
|
253
|
+
def export(length=nil)
|
254
|
+
if length
|
255
|
+
string = @string.slice!(0, length)
|
256
|
+
else
|
257
|
+
string = @string
|
258
|
+
reset
|
259
|
+
end
|
260
|
+
return string
|
261
|
+
end
|
262
|
+
|
263
|
+
# Extracts and returns a binary string of the given length, starting at the index position.
|
264
|
+
# The instance index is offset in accordance with the length read.
|
265
|
+
#
|
266
|
+
# === Parameters
|
267
|
+
#
|
268
|
+
# * <tt>length</tt> -- Fixnum. The length of the string which will extracted.
|
269
|
+
#
|
270
|
+
def extract(length)
|
271
|
+
str = @string.slice(@index, length)
|
272
|
+
skip(length)
|
273
|
+
return str
|
274
|
+
end
|
275
|
+
|
276
|
+
# Returns the length of the binary instance string.
|
277
|
+
#
|
278
|
+
def length
|
279
|
+
return @string.length
|
280
|
+
end
|
281
|
+
|
282
|
+
# Calculates and returns the remaining length of the instance string (from the index position).
|
283
|
+
#
|
284
|
+
def rest_length
|
285
|
+
length = @string.length - @index
|
286
|
+
return length
|
287
|
+
end
|
288
|
+
|
289
|
+
# Extracts and returns the remaining part of the instance string (from the index position to the end of the string).
|
290
|
+
#
|
291
|
+
def rest_string
|
292
|
+
str = @string[@index..(@string.length-1)]
|
293
|
+
return str
|
294
|
+
end
|
295
|
+
|
296
|
+
# Resets the instance string and index.
|
297
|
+
#
|
298
|
+
def reset
|
299
|
+
@string = ""
|
300
|
+
@index = 0
|
301
|
+
end
|
302
|
+
|
303
|
+
# Resets the instance index.
|
304
|
+
#
|
305
|
+
def reset_index
|
306
|
+
@index = 0
|
307
|
+
end
|
308
|
+
|
309
|
+
# Sets an instance file variable.
|
310
|
+
#
|
311
|
+
# === Notes
|
312
|
+
#
|
313
|
+
# For performance reasons, we enable the Stream instance to write directly to file,
|
314
|
+
# to avoid expensive string operations which will otherwise slow down the write performance.
|
315
|
+
#
|
316
|
+
# === Parameters
|
317
|
+
#
|
318
|
+
# * <tt>file</tt> -- A File instance.
|
319
|
+
#
|
320
|
+
def set_file(file)
|
321
|
+
@file = file
|
322
|
+
end
|
323
|
+
|
324
|
+
# Sets a new instance string, and resets the index variable.
|
325
|
+
#
|
326
|
+
# === Parameters
|
327
|
+
#
|
328
|
+
# * <tt>binary</tt> -- A binary string.
|
329
|
+
#
|
330
|
+
def set_string(binary)
|
331
|
+
binary = binary[0] if binary.is_a?(Array)
|
332
|
+
@string = binary
|
333
|
+
@index = 0
|
334
|
+
end
|
335
|
+
|
336
|
+
# Applies an offset (positive or negative) to the instance index.
|
337
|
+
#
|
338
|
+
# === Parameters
|
339
|
+
#
|
340
|
+
# * <tt>offset</tt> -- Fixnum. The length to skip (positive) or rewind (negative).
|
341
|
+
#
|
342
|
+
def skip(offset)
|
343
|
+
@index += offset
|
344
|
+
end
|
345
|
+
|
346
|
+
# Writes a binary string to the File instance.
|
347
|
+
#
|
348
|
+
# === Parameters
|
349
|
+
#
|
350
|
+
# * <tt>binary</tt> -- A binary string.
|
351
|
+
#
|
352
|
+
def write(binary)
|
353
|
+
@file.write(binary)
|
354
|
+
end
|
355
|
+
|
356
|
+
|
357
|
+
# Following methods are private:
|
358
|
+
private
|
359
|
+
|
360
|
+
|
361
|
+
# Determines the relationship between system and string endianness, and sets the instance endian variable.
|
362
|
+
#
|
363
|
+
def configure_endian
|
364
|
+
if CPU_ENDIAN == @str_endian
|
365
|
+
@equal_endian = true
|
366
|
+
else
|
367
|
+
@equal_endian = false
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Converts a data type/vr to an encode/decode string used by the pack/unpack methods, which is returned.
|
372
|
+
#
|
373
|
+
# === Parameters
|
374
|
+
#
|
375
|
+
# * <tt>vr</tt> -- String. A data type (value representation).
|
376
|
+
#
|
377
|
+
def vr_to_str(vr)
|
378
|
+
unless @format[vr]
|
379
|
+
errors << "Warning: Element type #{vr} does not have a reading method assigned to it. Something is not implemented correctly or the DICOM data analyzed is invalid."
|
380
|
+
return @hex
|
381
|
+
else
|
382
|
+
return @format[vr]
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
# Sets the hash which is used to convert data element types (VR) to
|
387
|
+
# encode/decode strings accepted by the pack/unpack methods.
|
388
|
+
#
|
389
|
+
def set_format_hash
|
390
|
+
@format = {
|
391
|
+
"BY" => @by, # Byte/Character (1-byte integers)
|
392
|
+
"US" => @us, # Unsigned short (2 bytes)
|
393
|
+
"SS" => @ss, # Signed short (2 bytes)
|
394
|
+
"UL" => @ul, # Unsigned long (4 bytes)
|
395
|
+
"SL" => @sl, # Signed long (4 bytes)
|
396
|
+
"FL" => @fs, # Floating point single (4 bytes)
|
397
|
+
"FD" => @fd, # Floating point double (8 bytes)
|
398
|
+
"OB" => @by, # Other byte string (1-byte integers)
|
399
|
+
"OF" => @fs, # Other float string (4-byte floating point numbers)
|
400
|
+
"OW" => @us, # Other word string (2-byte integers)
|
401
|
+
"AT" => @hex, # Tag reference (4 bytes) NB: This may need to be revisited at some point...
|
402
|
+
"UN" => @hex, # Unknown information (header element is not recognized from local database)
|
403
|
+
"HEX" => @hex, # HEX
|
404
|
+
# We have a number of VRs that are decoded as string:
|
405
|
+
"AE" => @str,
|
406
|
+
"AS" => @str,
|
407
|
+
"CS" => @str,
|
408
|
+
"DA" => @str,
|
409
|
+
"DS" => @str,
|
410
|
+
"DT" => @str,
|
411
|
+
"IS" => @str,
|
412
|
+
"LO" => @str,
|
413
|
+
"LT" => @str,
|
414
|
+
"PN" => @str,
|
415
|
+
"SH" => @str,
|
416
|
+
"ST" => @str,
|
417
|
+
"TM" => @str,
|
418
|
+
"UI" => @str,
|
419
|
+
"UT" => @str,
|
420
|
+
"STR" => @str
|
421
|
+
}
|
422
|
+
end
|
423
|
+
|
424
|
+
# Sets the hash which is used to keep track of which bytes to use for padding
|
425
|
+
# data elements of various vr which have an odd value length.
|
426
|
+
#
|
427
|
+
def set_pad_byte
|
428
|
+
@pad_byte = {
|
429
|
+
# Space character:
|
430
|
+
"AE" => "\x20",
|
431
|
+
"AS" => "\x20",
|
432
|
+
"CS" => "\x20",
|
433
|
+
"DA" => "\x20",
|
434
|
+
"DS" => "\x20",
|
435
|
+
"DT" => "\x20",
|
436
|
+
"IS" => "\x20",
|
437
|
+
"LO" => "\x20",
|
438
|
+
"LT" => "\x20",
|
439
|
+
"PN" => "\x20",
|
440
|
+
"SH" => "\x20",
|
441
|
+
"ST" => "\x20",
|
442
|
+
"TM" => "\x20",
|
443
|
+
"UT" => "\x20",
|
444
|
+
# Zero byte:
|
445
|
+
"AT" => "\x00",
|
446
|
+
"FL" => "\x00",
|
447
|
+
"FD" => "\x00",
|
448
|
+
"OB" => "\x00",
|
449
|
+
"OF" => "\x00",
|
450
|
+
"OW" => "\x00",
|
451
|
+
"SL" => "\x00",
|
452
|
+
"SQ" => "\x00",
|
453
|
+
"SS" => "\x00",
|
454
|
+
"UI" => "\x00",
|
455
|
+
"UL" => "\x00",
|
456
|
+
"UN" => "\x00",
|
457
|
+
"US" => "\x00"
|
458
|
+
}
|
459
|
+
end
|
460
|
+
|
461
|
+
# Sets the pack/unpack format strings that is used for encoding/decoding.
|
462
|
+
# Some of these depends on the endianness of the system and the String.
|
463
|
+
#
|
464
|
+
#--
|
465
|
+
# FIXME: Apparently the Ruby pack/unpack methods lacks a format for signed short
|
466
|
+
# and signed long in the network byte order. A solution needs to be found for this.
|
467
|
+
#
|
468
|
+
def set_string_formats
|
469
|
+
if @equal_endian
|
470
|
+
# Native byte order:
|
471
|
+
@us = "S*" # Unsigned short (2 bytes)
|
472
|
+
@ss = "s*" # Signed short (2 bytes)
|
473
|
+
@ul = "I*" # Unsigned long (4 bytes)
|
474
|
+
@sl = "l*" # Signed long (4 bytes)
|
475
|
+
@fs = "e*" # Floating point single (4 bytes)
|
476
|
+
@fd = "E*" # Floating point double ( 8 bytes)
|
477
|
+
else
|
478
|
+
# Network byte order:
|
479
|
+
@us = "n*"
|
480
|
+
@ss = "n*" # Not correct (gives US)
|
481
|
+
@ul = "N*"
|
482
|
+
@sl = "N*" # Not correct (gives UL)
|
483
|
+
@fs = "g*"
|
484
|
+
@fd = "G*"
|
485
|
+
end
|
486
|
+
# Format strings that are not dependent on endianness:
|
487
|
+
@by = "C*" # Unsigned char (1 byte)
|
488
|
+
@str = "a*"
|
489
|
+
@hex = "H*" # (this may be dependent on endianness(?))
|
490
|
+
end
|
491
|
+
|
492
|
+
end
|
493
|
+
end
|