dicom 0.9.5 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/{CHANGELOG.rdoc → CHANGELOG.md} +50 -30
- data/{CONTRIBUTING.rdoc → CONTRIBUTING.md} +16 -16
- data/Gemfile.lock +47 -0
- data/README.md +152 -0
- data/dicom.gemspec +11 -10
- data/lib/dicom.rb +30 -11
- data/lib/dicom/anonymizer.rb +654 -649
- data/lib/dicom/audit_trail.rb +0 -2
- data/lib/dicom/d_client.rb +1 -1
- data/lib/dicom/d_library.rb +45 -15
- data/lib/dicom/d_object.rb +18 -18
- data/lib/dicom/d_read.rb +28 -4
- data/lib/dicom/d_write.rb +49 -26
- data/lib/dicom/dictionary/{elements.txt → elements.tsv} +0 -0
- data/lib/dicom/dictionary/{uids.txt → uids.tsv} +0 -0
- data/lib/dicom/element.rb +6 -7
- data/lib/dicom/elemental.rb +1 -0
- data/lib/dicom/elemental_parent.rb +64 -0
- data/lib/dicom/extensions/array.rb +57 -0
- data/lib/dicom/extensions/hash.rb +31 -0
- data/lib/dicom/extensions/string.rb +126 -0
- data/lib/dicom/{constants.rb → general/constants.rb} +29 -38
- data/lib/dicom/{deprecated.rb → general/deprecated.rb} +0 -0
- data/lib/dicom/{logging.rb → general/logging.rb} +0 -0
- data/lib/dicom/{variables.rb → general/methods.rb} +0 -22
- data/lib/dicom/general/variables.rb +29 -0
- data/lib/dicom/{version.rb → general/version.rb} +1 -1
- data/lib/dicom/image_item.rb +0 -2
- data/lib/dicom/image_processor.rb +2 -0
- data/lib/dicom/item.rb +1 -13
- data/lib/dicom/link.rb +2 -1
- data/lib/dicom/parent.rb +34 -86
- data/lib/dicom/sequence.rb +1 -13
- data/lib/dicom/stream.rb +94 -114
- data/rakefile.rb +1 -1
- metadata +73 -36
- data/README.rdoc +0 -149
- data/lib/dicom/ruby_extensions.rb +0 -249
@@ -0,0 +1,31 @@
|
|
1
|
+
# Extensions to the Hash class used by the dicom gem.
|
2
|
+
#
|
3
|
+
class Hash
|
4
|
+
|
5
|
+
# Creates a gap in the integer keys at the specified index.
|
6
|
+
# This is achieved by incrementing by one all existing index keys that are equal or
|
7
|
+
# bigger than the given index.
|
8
|
+
#
|
9
|
+
# @note It is assumed that this hash features integers as keys and items as values!
|
10
|
+
# @param [Integer] index the index at which to clear
|
11
|
+
# @return [Hash] the modified self
|
12
|
+
#
|
13
|
+
def create_key_gap_at(index)
|
14
|
+
# Extract existing Hash entries to an array:
|
15
|
+
pairs = self.sort
|
16
|
+
h = Hash.new
|
17
|
+
# Change the key of those equal or larger than index and put these key,value pairs back in a new Hash:
|
18
|
+
pairs.each do |pair|
|
19
|
+
if pair[0] < index
|
20
|
+
# The key keeps its old index:
|
21
|
+
h[pair[0]] = pair[1]
|
22
|
+
else
|
23
|
+
# The key (and the value Item) gets its index incremented by one:
|
24
|
+
h[pair[0]+1] = pair[1]
|
25
|
+
pair[1].index = pair[0]+1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
h
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Extension to the String class. These mainly facilitate the processing and analysis of 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
|
8
|
+
|
9
|
+
# Checks if a string value LOOKS like a DICOM name - it may still not be valid one.
|
10
|
+
#
|
11
|
+
# @return [Boolean] true if a string looks like a DICOM name, and false if not
|
12
|
+
#
|
13
|
+
def dicom_name?
|
14
|
+
self == self.dicom_titleize
|
15
|
+
end
|
16
|
+
|
17
|
+
# Checks if a string value LOOKS like a DICOM method name - it may still not be valid one.
|
18
|
+
#
|
19
|
+
# @return [Boolean] true if a string looks like a DICOM method name, and false if not
|
20
|
+
#
|
21
|
+
def dicom_method?
|
22
|
+
self == self.dicom_underscore
|
23
|
+
end
|
24
|
+
|
25
|
+
# Capitalizes all the words in the string and replaces some characters to make a nicer looking title.
|
26
|
+
#
|
27
|
+
# @return [String] a formatted, capitalized string
|
28
|
+
#
|
29
|
+
def dicom_titleize
|
30
|
+
self.dicom_underscore.gsub(/_/, ' ').gsub(/\b('?[a-z])/) { $1.capitalize }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Makes an underscored, lowercased version of the string.
|
34
|
+
#
|
35
|
+
# @return [String] an underscored, lower case string
|
36
|
+
#
|
37
|
+
def dicom_underscore
|
38
|
+
word = self.dup
|
39
|
+
word.tr!('-', '_')
|
40
|
+
word.downcase!
|
41
|
+
word
|
42
|
+
end
|
43
|
+
|
44
|
+
# Divides a string into a number of sub-strings of exactly equal length.
|
45
|
+
#
|
46
|
+
# @note The length of self must be a multiple of parts, or an exception will be raised.
|
47
|
+
# @param [Integer] parts the number of sub-strings to create
|
48
|
+
# @return [Array<String>] the divided sub-strings
|
49
|
+
#
|
50
|
+
def divide(parts)
|
51
|
+
parts = parts.to_i
|
52
|
+
raise ArgumentError, "Argument must be in the range <1 - self.length (#{self.length})>. Got #{parts}." if parts < 1 or parts > self.length
|
53
|
+
raise ArgumentError, "Length of self (#{self.length}) must be a multiple of parts (#{parts})." if (self.length/parts.to_f % 1) != 0
|
54
|
+
sub_strings = Array.new
|
55
|
+
sub_length = self.length/parts
|
56
|
+
start_index = 0
|
57
|
+
parts.times {
|
58
|
+
sub_strings << self.slice(start_index, sub_length)
|
59
|
+
start_index += sub_length
|
60
|
+
}
|
61
|
+
sub_strings
|
62
|
+
end
|
63
|
+
|
64
|
+
# Extracts the element part of the tag string: The last 4 characters.
|
65
|
+
#
|
66
|
+
# @return [String] the element part of the tag
|
67
|
+
#
|
68
|
+
def element
|
69
|
+
return self[5..8]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the group part of the tag string: The first 4 characters.
|
73
|
+
#
|
74
|
+
# @return [String] the group part of the tag
|
75
|
+
#
|
76
|
+
def group
|
77
|
+
return self[0..3]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the "Group Length" ('GGGG,0000') tag which corresponds to the original tag/group string.
|
81
|
+
# The original string may either be a 4 character group string, or a 9 character custom tag.
|
82
|
+
#
|
83
|
+
# @return [String] a group length tag
|
84
|
+
#
|
85
|
+
def group_length
|
86
|
+
if self.length == 4
|
87
|
+
return self + ',0000'
|
88
|
+
else
|
89
|
+
return self.group + ',0000'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Checks if the string is a "Group Length" tag (its element part is '0000').
|
94
|
+
#
|
95
|
+
# @return [Boolean] true if it is a group length tag, and false if not
|
96
|
+
#
|
97
|
+
def group_length?
|
98
|
+
return (self.element == '0000' ? true : false)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Checks if the string is a private tag (has an odd group number).
|
102
|
+
#
|
103
|
+
# @return [Boolean] true if it is a private tag, and false if not
|
104
|
+
#
|
105
|
+
def private?
|
106
|
+
return ((self.upcase =~ /\A\h{3}[1,3,5,7,9,B,D,F],\h{4}\z/) == nil ? false : true)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Checks if the string is a valid tag (as defined by ruby-dicom: 'GGGG,EEEE').
|
110
|
+
#
|
111
|
+
# @return [Boolean] true if it is a valid tag, and false if not
|
112
|
+
#
|
113
|
+
def tag?
|
114
|
+
# Test that the string is composed of exactly 4 HEX characters, followed by a comma, then 4 more HEX characters:
|
115
|
+
return ((self.upcase =~ /\A\h{4},\h{4}\z/) == nil ? false : true)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Converts the string to a proper DICOM element method name symbol.
|
119
|
+
#
|
120
|
+
# @return [Symbol] a DICOM element method name
|
121
|
+
#
|
122
|
+
def to_element_method
|
123
|
+
self.gsub(/^3/,'three_').gsub(/[#*?!]/,' ').gsub(', ',' ').gsub('&','and').gsub(' - ','_').gsub(' / ','_').gsub(/[\s\-\.\,\/\\]/,'_').gsub(/[\(\)\']/,'').gsub(/\_+/, '_').downcase.to_sym
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -1,8 +1,5 @@
|
|
1
1
|
module DICOM
|
2
2
|
|
3
|
-
# Defines the gem root directory in the file system.
|
4
|
-
ROOT_DIR = "#{File.dirname(__FILE__)}"
|
5
|
-
|
6
3
|
# Ruby DICOM's registered DICOM UID root (Implementation Class UID).
|
7
4
|
UID_ROOT = "1.2.826.0.1.3680043.8.641"
|
8
5
|
# Ruby DICOM name & version (max 16 characters).
|
@@ -109,14 +106,6 @@ module DICOM
|
|
109
106
|
# System (CPU) Endianness.
|
110
107
|
CPU_ENDIAN = endian_type[Array(x).pack("L*")]
|
111
108
|
|
112
|
-
# Custom string used for (un)packing big endian signed short.
|
113
|
-
CUSTOM_SS = "k*"
|
114
|
-
# Custom string used for (un)packing big endian signed long.
|
115
|
-
CUSTOM_SL = "r*"
|
116
|
-
|
117
|
-
# ruby-dicom's library instance (data dictionary).
|
118
|
-
LIBRARY = DICOM::DLibrary.new
|
119
|
-
|
120
109
|
# Transfer Syntaxes (taken from the DICOM Specification PS 3.5, Chapter 10).
|
121
110
|
|
122
111
|
# General
|
@@ -184,36 +173,38 @@ module DICOM
|
|
184
173
|
'GB18030' => 'GB18030',
|
185
174
|
'ISO_IR 192' => 'UTF-8'
|
186
175
|
}
|
176
|
+
ENCODING_NAME.default = 'ASCII-8BIT'
|
187
177
|
|
188
178
|
# The type conversion (method) used for the various value representations.
|
189
179
|
VALUE_CONVERSION = {
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
180
|
+
'BY' => :to_i,
|
181
|
+
'US' => :to_i,
|
182
|
+
'SS' => :to_i,
|
183
|
+
'UL' => :to_i,
|
184
|
+
'SL' => :to_i,
|
185
|
+
'OB' => :to_i,
|
186
|
+
'OW' => :to_i,
|
187
|
+
'OF' => :to_f,
|
188
|
+
'FL' => :to_f,
|
189
|
+
'FD' => :to_f,
|
190
|
+
'AT' => :to_s,
|
191
|
+
'AE' => :to_s,
|
192
|
+
'AS' => :to_s,
|
193
|
+
'CS' => :to_s,
|
194
|
+
'DA' => :to_s,
|
195
|
+
'DS' => :to_s,
|
196
|
+
'DT' => :to_s,
|
197
|
+
'IS' => :to_s,
|
198
|
+
'LO' => :to_s,
|
199
|
+
'LT' => :to_s,
|
200
|
+
'PN' => :to_s,
|
201
|
+
'SH' => :to_s,
|
202
|
+
'ST' => :to_s,
|
203
|
+
'TM' => :to_s,
|
204
|
+
'UI' => :to_s,
|
205
|
+
'UT' => :to_s
|
206
|
+
}
|
207
|
+
VALUE_CONVERSION.default = :to_s
|
217
208
|
|
218
209
|
end
|
219
210
|
|
File without changes
|
File without changes
|
@@ -2,17 +2,6 @@ module DICOM
|
|
2
2
|
|
3
3
|
class << self
|
4
4
|
|
5
|
-
#--
|
6
|
-
# Module attributes:
|
7
|
-
#++
|
8
|
-
|
9
|
-
# The ruby-dicom image processor to be used.
|
10
|
-
attr_accessor :image_processor
|
11
|
-
# The key representation for hashes, json, yaml.
|
12
|
-
attr_accessor :key_representation
|
13
|
-
# Source Application Entity Title (gets written to the DICOM header in files where it is undefined).
|
14
|
-
attr_accessor :source_app_title
|
15
|
-
|
16
5
|
#--
|
17
6
|
# Module methods:
|
18
7
|
#++
|
@@ -91,15 +80,4 @@ module DICOM
|
|
91
80
|
|
92
81
|
end
|
93
82
|
|
94
|
-
#--
|
95
|
-
# Default variable settings:
|
96
|
-
#++
|
97
|
-
|
98
|
-
# The default image processor.
|
99
|
-
self.image_processor = :rmagick
|
100
|
-
# The default key representation.
|
101
|
-
self.key_representation = :name
|
102
|
-
# The default source application entity title.
|
103
|
-
self.source_app_title = 'RUBY-DICOM'
|
104
|
-
|
105
83
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DICOM
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
#--
|
6
|
+
# Module attributes:
|
7
|
+
#++
|
8
|
+
|
9
|
+
# The ruby-dicom image processor to be used.
|
10
|
+
attr_accessor :image_processor
|
11
|
+
# The key representation for hashes, json, yaml.
|
12
|
+
attr_accessor :key_representation
|
13
|
+
# Source Application Entity Title (gets written to the DICOM header in files where it is undefined).
|
14
|
+
attr_accessor :source_app_title
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
#--
|
19
|
+
# Default variable settings:
|
20
|
+
#++
|
21
|
+
|
22
|
+
# The default image processor.
|
23
|
+
self.image_processor = :rmagick
|
24
|
+
# The default key representation.
|
25
|
+
self.key_representation = :name
|
26
|
+
# The default source application entity title.
|
27
|
+
self.source_app_title = 'RUBY-DICOM'
|
28
|
+
|
29
|
+
end
|
data/lib/dicom/image_item.rb
CHANGED
@@ -119,7 +119,6 @@ module DICOM
|
|
119
119
|
# image frames, the first image frame is returned, unless the :frame option is used.
|
120
120
|
#
|
121
121
|
# @note Creates an image object in accordance with the selected image processor. Available processors are :rmagick and :mini_magick.
|
122
|
-
# @note When calling this method the corresponding image processor gem must have been loaded in advance (example: require 'RMagick').
|
123
122
|
#
|
124
123
|
# @param [Hash] options the options to use for extracting the image
|
125
124
|
# @option options [Integer] :frame for DICOM objects containing multiple frames, this option can be used to extract a specific image frame (defaults to 0)
|
@@ -145,7 +144,6 @@ module DICOM
|
|
145
144
|
# the image related elements in the DICOM object.
|
146
145
|
#
|
147
146
|
# @note Creates an array of image objects in accordance with the selected image processor. Available processors are :rmagick and :mini_magick.
|
148
|
-
# @note When calling this method the corresponding image processor gem must have been loaded in advance (example: require 'RMagick').
|
149
147
|
#
|
150
148
|
# @param [Hash] options the options to use for extracting the images
|
151
149
|
# @option options [Integer] :frame makes the method return an array containing only the image object corresponding to the specified frame number
|
data/lib/dicom/item.rb
CHANGED
@@ -9,8 +9,8 @@ module DICOM
|
|
9
9
|
#
|
10
10
|
class Item < ImageItem
|
11
11
|
|
12
|
-
# Include the Elemental mix-in module:
|
13
12
|
include Elemental
|
13
|
+
include ElementalParent
|
14
14
|
|
15
15
|
# The index of this Item in the group of items belonging to its parent. If the Item is without parent, index is nil.
|
16
16
|
attr_accessor :index
|
@@ -98,18 +98,6 @@ module DICOM
|
|
98
98
|
state.hash
|
99
99
|
end
|
100
100
|
|
101
|
-
# Loads data from an encoded DICOM string and creates
|
102
|
-
# sequences and elements which are linked to this instance.
|
103
|
-
#
|
104
|
-
# @param [String] bin an encoded binary string containing DICOM information
|
105
|
-
# @param [String] syntax the transfer syntax to use when decoding the DICOM string
|
106
|
-
#
|
107
|
-
def parse(bin, syntax)
|
108
|
-
raise ArgumentError, "Invalid argument 'bin'. Expected String, got #{bin.class}." unless bin.is_a?(String)
|
109
|
-
raise ArgumentError, "Invalid argument 'syntax'. Expected String, got #{syntax.class}." unless syntax.is_a?(String)
|
110
|
-
read(bin, signature=false, :syntax => syntax)
|
111
|
-
end
|
112
|
-
|
113
101
|
# Returns self.
|
114
102
|
#
|
115
103
|
# @return [Item] self
|
data/lib/dicom/link.rb
CHANGED
@@ -1426,6 +1426,7 @@ module DICOM
|
|
1426
1426
|
response = IO.select([@session], nil, nil, @timeout)
|
1427
1427
|
if response.nil?
|
1428
1428
|
logger.error("No answer was received within the specified timeout period. Aborting.")
|
1429
|
+
stop_receiving
|
1429
1430
|
else
|
1430
1431
|
data = @session.recv(@max_receive_size)
|
1431
1432
|
end
|
@@ -1486,7 +1487,7 @@ module DICOM
|
|
1486
1487
|
if info[:role_negotiation]
|
1487
1488
|
pos = 3
|
1488
1489
|
info[:role_negotiation].each do |role|
|
1489
|
-
msg = Stream.new(
|
1490
|
+
msg = Stream.new('', @net_endian)
|
1490
1491
|
uid = role[:sop_uid]
|
1491
1492
|
# Length of UID (2 bytes):
|
1492
1493
|
msg.encode_first(uid.length, "US")
|
data/lib/dicom/parent.rb
CHANGED
@@ -61,76 +61,6 @@ module DICOM
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
-
# Adds a child item to a Sequence (or Item in some cases where pixel data is encapsulated).
|
65
|
-
#
|
66
|
-
# If no existing Item is given, a new item will be created and added.
|
67
|
-
#
|
68
|
-
# @note Items are specified by index (starting at 0) instead of a tag string!
|
69
|
-
#
|
70
|
-
# @param [Item] item the Item instance to be added
|
71
|
-
# @param [Hash] options the options used for adding the item
|
72
|
-
# option options [Integer] :if specified, forces the item to be inserted at that specific index (Item number)
|
73
|
-
# option options [Boolean] :no_follow when true, the method does not update the parent attribute of the child that is added
|
74
|
-
# * <tt>options</tt> -- A hash of parameters.
|
75
|
-
# @example Add an empty Item to a specific Sequence
|
76
|
-
# dcm["3006,0020"].add_item
|
77
|
-
# @example Add an existing Item at the 2nd item position/index in the specific Sequence
|
78
|
-
# dcm["3006,0020"].add_item(my_item, :index => 1)
|
79
|
-
#
|
80
|
-
def add_item(item=nil, options={})
|
81
|
-
unless self.is_a?(DObject)
|
82
|
-
if item
|
83
|
-
if item.is_a?(Item)
|
84
|
-
if options[:index]
|
85
|
-
# This Item will take a specific index, and all existing Items with index higher or equal to this number will have their index increased by one.
|
86
|
-
# Check if index is valid (must be an existing index):
|
87
|
-
if options[:index] >= 0
|
88
|
-
# If the index value is larger than the max index present, we dont need to modify the existing items.
|
89
|
-
if options[:index] < @tags.length
|
90
|
-
# Extract existing Hash entries to an array:
|
91
|
-
pairs = @tags.sort
|
92
|
-
@tags = Hash.new
|
93
|
-
# Change the key of those equal or larger than index and put these key,value pairs back in a new Hash:
|
94
|
-
pairs.each do |pair|
|
95
|
-
if pair[0] < options[:index]
|
96
|
-
@tags[pair[0]] = pair[1] # (Item keeps its old index)
|
97
|
-
else
|
98
|
-
@tags[pair[0]+1] = pair[1]
|
99
|
-
pair[1].index = pair[0]+1 # (Item gets updated with its new index)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
else
|
103
|
-
# Set the index value one higher than the already existing max value:
|
104
|
-
options[:index] = @tags.length
|
105
|
-
end
|
106
|
-
#,Add the new Item and set its index:
|
107
|
-
@tags[options[:index]] = item
|
108
|
-
item.index = options[:index]
|
109
|
-
else
|
110
|
-
raise ArgumentError, "The specified index (#{options[:index]}) is out of range (Must be a positive integer)."
|
111
|
-
end
|
112
|
-
else
|
113
|
-
# Add the existing Item to this Sequence:
|
114
|
-
index = @tags.length
|
115
|
-
@tags[index] = item
|
116
|
-
# Let the Item know what index key it's got in it's parent's Hash:
|
117
|
-
item.index = index
|
118
|
-
end
|
119
|
-
# Set ourself as this item's new parent:
|
120
|
-
item.set_parent(self) unless options[:no_follow]
|
121
|
-
else
|
122
|
-
raise ArgumentError, "The specified parameter is not an Item. Only Items are allowed to be added to a Sequence."
|
123
|
-
end
|
124
|
-
else
|
125
|
-
# Create an empty Item with self as parent.
|
126
|
-
index = @tags.length
|
127
|
-
item = Item.new(:parent => self)
|
128
|
-
end
|
129
|
-
else
|
130
|
-
raise "An Item #{item} was attempted added to a DObject instance #{self}, which is not allowed."
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
64
|
# Retrieves all (immediate) child elementals in an array (sorted by element tag).
|
135
65
|
#
|
136
66
|
# @return [Array<Element, Item, Sequence>] the parent's child elementals (an empty array if childless)
|
@@ -196,12 +126,7 @@ module DICOM
|
|
196
126
|
# dcm["3006,0020"].delete(1)
|
197
127
|
#
|
198
128
|
def delete(tag_or_index, options={})
|
199
|
-
|
200
|
-
raise ArgumentError, "Argument (#{tag_or_index}) is not a valid tag string." if tag_or_index.is_a?(String) && !tag_or_index.tag?
|
201
|
-
raise ArgumentError, "Negative Integer argument (#{tag_or_index}) is not allowed." if tag_or_index.is_a?(Integer) && tag_or_index < 0
|
202
|
-
else
|
203
|
-
raise ArgumentError, "Expected String or Integer, got #{tag_or_index.class}."
|
204
|
-
end
|
129
|
+
check_key(tag_or_index, :delete)
|
205
130
|
# We need to delete the specified child element's parent reference in addition to removing it from the tag Hash.
|
206
131
|
element = self[tag_or_index]
|
207
132
|
if element
|
@@ -528,13 +453,15 @@ module DICOM
|
|
528
453
|
# @param [Symbol] sym a method name
|
529
454
|
#
|
530
455
|
def method_missing(sym, *args, &block)
|
456
|
+
s = sym.to_s
|
457
|
+
action = s[-1]
|
531
458
|
# Try to match the method against a tag from the dictionary:
|
532
|
-
tag = LIBRARY.as_tag(
|
459
|
+
tag = LIBRARY.as_tag(s) || LIBRARY.as_tag(s[0..-2])
|
533
460
|
if tag
|
534
|
-
if
|
461
|
+
if action == '?'
|
535
462
|
# Query:
|
536
463
|
return self.exists?(tag)
|
537
|
-
elsif
|
464
|
+
elsif action == '='
|
538
465
|
# Assignment:
|
539
466
|
unless args.length==0 || args[0].nil?
|
540
467
|
# What kind of element to create?
|
@@ -550,7 +477,7 @@ module DICOM
|
|
550
477
|
end
|
551
478
|
else
|
552
479
|
# Retrieval:
|
553
|
-
return self[tag]
|
480
|
+
return self[tag]
|
554
481
|
end
|
555
482
|
end
|
556
483
|
# Forward to Object#method_missing:
|
@@ -595,6 +522,16 @@ module DICOM
|
|
595
522
|
return elements
|
596
523
|
end
|
597
524
|
|
525
|
+
# Gives a string which represents this DICOM parent. The DOBject is
|
526
|
+
# is represented by its class name, whereas elemental parents (Sequence,
|
527
|
+
# Item) is represented by their tags.
|
528
|
+
#
|
529
|
+
# @return [String] a representation of the DICOM parent
|
530
|
+
#
|
531
|
+
def representation
|
532
|
+
self.is_a?(DObject) ? 'DObject' : self.tag
|
533
|
+
end
|
534
|
+
|
598
535
|
# Resets the length of a Sequence or Item to -1, which is the number used for 'undefined' length.
|
599
536
|
#
|
600
537
|
def reset_length
|
@@ -701,12 +638,7 @@ module DICOM
|
|
701
638
|
# uid = dcm["3006,0010"][0].value("0020,0052")
|
702
639
|
#
|
703
640
|
def value(tag)
|
704
|
-
|
705
|
-
raise ArgumentError, "Argument (#{tag}) is not a valid tag string." if tag.is_a?(String) && !tag.tag?
|
706
|
-
raise ArgumentError, "Negative Integer argument (#{tag}) is not allowed." if tag.is_a?(Integer) && tag < 0
|
707
|
-
else
|
708
|
-
raise ArgumentError, "Expected String or Integer, got #{tag.class}."
|
709
|
-
end
|
641
|
+
check_key(tag, :value)
|
710
642
|
if exists?(tag)
|
711
643
|
if self[tag].is_parent?
|
712
644
|
raise ArgumentError, "Illegal parameter '#{tag}'. Parent elements, like the referenced '#{@tags[tag].class}', have no value. Only Element tags are valid."
|
@@ -722,6 +654,22 @@ module DICOM
|
|
722
654
|
private
|
723
655
|
|
724
656
|
|
657
|
+
# Checks the given key argument and logs a warning if an obviously
|
658
|
+
# incorrect key argument is used.
|
659
|
+
#
|
660
|
+
# @param [String, Integer] tag_or_index the tag string or item index indentifying a given elemental
|
661
|
+
# @param [Symbol] method a representation of the method calling this method
|
662
|
+
#
|
663
|
+
def check_key(tag_or_index, method)
|
664
|
+
if tag_or_index.is_a?(String)
|
665
|
+
logger.warn("Parent##{method} called with an invalid tag argument: #{tag_or_index}") unless tag_or_index.tag?
|
666
|
+
elsif tag_or_index.is_a?(Integer)
|
667
|
+
logger.warn("Parent##{method} called with a negative Integer argument: #{tag_or_index}") if tag_or_index < 0
|
668
|
+
else
|
669
|
+
logger.warn("Parent##{method} called with an unexpected argument. Expected String or Integer, got: #{tag_or_index.class}")
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
725
673
|
# Re-encodes the value of a child Element (but only if the
|
726
674
|
# Element encoding is influenced by a shift in endianness).
|
727
675
|
#
|