dicom 0.9.5 → 0.9.6
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.
- 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
|
#
|