dicom 0.9.7 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c471922e97e22ce893a34540e6e329f1bfb758ab
4
- data.tar.gz: 9772c5dc74910531dbc740dda4966ac7056f36e3
3
+ metadata.gz: f91db23166e9a16c8cd6b4d694b7aa530e39b143
4
+ data.tar.gz: 76edf3567fb40346cc0ab81d2c6dced7efcdd556
5
5
  SHA512:
6
- metadata.gz: e87bde50743b0ab641bd6087a43ef8da3adaac446baf2f0c14c1f439475a05e7df0c5af4b6d96d5668f60fd0ad651e49a4309e89c7c90536564d353505f8e62d
7
- data.tar.gz: 01239e3b7957ebcc2f663427889057c158bf3247f00868ac2045cc6ab0a1f7e8aa218f2395c77f3a88ee6ca7807ddca0bc553a2f1d22e5053ee9a2157ced0d73
6
+ metadata.gz: c39d93a981235ff3e63d80108d18c043ebd7ba12f161eb5791a5807ae297bb6f5a0f5b8aca364c6a0bdfd1e5036172553ebb3d2c0a609cddb43831ad0b92500a
7
+ data.tar.gz: 6be61b879bf566c73285f370da46241576ee3231d4b3e446c90512d7740c74564bcb6f312fa64dcb8a24df95ef43542736595a844ab6f34b95b0555e9272349e
@@ -1,3 +1,12 @@
1
+ # 0.9.8
2
+
3
+ ## 24th March, 2018
4
+
5
+ * Changed: Replaced Fixnum with Integer to avoid deprecation warning in Ruby 2.4.
6
+ * Changed: Replaced NArray with Numo/Narray.
7
+ * Fixed: Improved compatibility with Japanese string encoding.
8
+
9
+
1
10
  # 0.9.7
2
11
 
3
12
  ## 4th January, 2017
@@ -1,49 +1,49 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dicom (0.9.7)
4
+ dicom (0.9.8)
5
5
 
6
6
  GEM
7
7
  remote: http://www.rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.2.5)
10
10
  metaclass (0.0.4)
11
- mini_magick (4.4.0)
12
- mocha (1.1.0)
11
+ mini_magick (4.8.0)
12
+ mocha (1.4.0)
13
13
  metaclass (~> 0.0.1)
14
- narray (0.6.1.1)
15
- rake (10.5.0)
16
- redcarpet (3.3.3)
14
+ numo-narray (0.9.1.1)
15
+ rake (12.3.1)
16
+ redcarpet (3.4.0)
17
17
  rmagick (2.15.4)
18
- rspec (3.4.0)
19
- rspec-core (~> 3.4.0)
20
- rspec-expectations (~> 3.4.0)
21
- rspec-mocks (~> 3.4.0)
22
- rspec-core (3.4.1)
23
- rspec-support (~> 3.4.0)
24
- rspec-expectations (3.4.0)
18
+ rspec (3.7.0)
19
+ rspec-core (~> 3.7.0)
20
+ rspec-expectations (~> 3.7.0)
21
+ rspec-mocks (~> 3.7.0)
22
+ rspec-core (3.7.1)
23
+ rspec-support (~> 3.7.0)
24
+ rspec-expectations (3.7.0)
25
25
  diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.4.0)
27
- rspec-mocks (3.4.0)
26
+ rspec-support (~> 3.7.0)
27
+ rspec-mocks (3.7.0)
28
28
  diff-lcs (>= 1.2.0, < 2.0)
29
- rspec-support (~> 3.4.0)
30
- rspec-support (3.4.0)
31
- yard (0.8.7.6)
29
+ rspec-support (~> 3.7.0)
30
+ rspec-support (3.7.1)
31
+ yard (0.9.12)
32
32
 
33
33
  PLATFORMS
34
34
  x86-mingw32
35
35
 
36
36
  DEPENDENCIES
37
- bundler (~> 1.11)
37
+ bundler (~> 1.16)
38
38
  dicom!
39
- mini_magick (~> 4.4)
40
- mocha (~> 1.1)
41
- narray (~> 0.6, >= 0.6.1)
42
- rake (~> 10.5)
43
- redcarpet (~> 3.3)
39
+ mini_magick (~> 4.8)
40
+ mocha (~> 1.4)
41
+ numo-narray (~> 0.9, >= 0.9.1.1)
42
+ rake (~> 12.3)
43
+ redcarpet (~> 3.4)
44
44
  rmagick (~> 2.15)
45
- rspec (~> 3.4)
46
- yard (~> 0.8, >= 0.8.7)
45
+ rspec (~> 3.7)
46
+ yard (~> 0.9, >= 0.9.12)
47
47
 
48
48
  BUNDLED WITH
49
- 1.11.2
49
+ 1.16.1
data/README.md CHANGED
@@ -111,7 +111,7 @@ Example:
111
111
 
112
112
  ## COPYRIGHT
113
113
 
114
- Copyright 2008-2017 Christoffer Lervåg
114
+ Copyright 2008-2018 Christoffer Lervåg
115
115
 
116
116
  This program is free software: you can redistribute it and/or modify
117
117
  it under the terms of the GNU General Public License as published by
@@ -150,5 +150,6 @@ Please don't hesitate to email me if you have any feedback related to this proje
150
150
  * [Steven Bedrick](https://github.com/stevenbedrick)
151
151
  * [Lars Benner](https://github.com/Maturin)
152
152
  * [Brett Goulder](https://github.com/brettgoulder)
153
+ * [Satoshi Funayama](https://github.com/akchan)
153
154
  * André Wuttke
154
155
  * Thomas Koschel
@@ -19,13 +19,13 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.required_ruby_version = '>= 2.2.2'
21
21
 
22
- s.add_development_dependency('bundler', '~> 1.11')
23
- s.add_development_dependency('mini_magick', '~> 4.4')
24
- s.add_development_dependency('mocha', '~> 1.1')
25
- s.add_development_dependency('narray', '~> 0.6', '>= 0.6.1')
26
- s.add_development_dependency('rake', '~> 10.5')
27
- s.add_development_dependency('redcarpet', '~> 3.3')
22
+ s.add_development_dependency('bundler', '~> 1.16')
23
+ s.add_development_dependency('mini_magick', '~> 4.8')
24
+ s.add_development_dependency('mocha', '~> 1.4')
25
+ s.add_development_dependency('numo-narray', '~> 0.9', '>= 0.9.1.1')
26
+ s.add_development_dependency('rake', '~> 12.3')
27
+ s.add_development_dependency('redcarpet', '~> 3.4')
28
28
  s.add_development_dependency('rmagick', '~> 2.15')
29
- s.add_development_dependency('rspec', '~> 3.4')
30
- s.add_development_dependency('yard', '~> 0.8', '>= 0.8.7')
29
+ s.add_development_dependency('rspec', '~> 3.7')
30
+ s.add_development_dependency('yard', '~> 0.9', '>= 0.9.12')
31
31
  end
@@ -50,7 +50,7 @@ module DICOM
50
50
  # @option options [Boolean] :delete_private toggles whether private elements are to be deleted
51
51
  # @option options [TrueClass, Digest::Class] :encryption if set as true, the default hash function (MD5) will be used for representing DICOM values in an audit file. Otherwise a Digest class can be given, e.g. Digest::SHA256
52
52
  # @option options [Boolean] :enumeration toggles whether (some) elements get enumerated values (to enable post-anonymization re-identification)
53
- # @option options [Fixnum] :logger_level the logger level which is applied to DObject operations during anonymization (defaults to Logger::FATAL)
53
+ # @option options [Integer] :logger_level the logger level which is applied to DObject operations during anonymization (defaults to Logger::FATAL)
54
54
  # @option options [Boolean] :random_file_name toggles whether anonymized files will be given random file names when rewritten (in combination with the :write_path option)
55
55
  # @option options [Boolean] :recursive toggles whether to anonymize on all sub-levels of the DICOM object tag hierarchies
56
56
  # @option options [Boolean] :uid toggles whether UIDs will be replaced with custom generated UIDs (beware that to preserve UID relations in studies/series, the audit_trail feature must be used)
@@ -210,7 +210,7 @@ module DICOM
210
210
  #
211
211
  # @note Two objects with the same attributes will have the same hash code.
212
212
  #
213
- # @return [Fixnum] the object's hash code
213
+ # @return [Integer] the object's hash code
214
214
  #
215
215
  def hash
216
216
  state.hash
@@ -471,7 +471,7 @@ module DICOM
471
471
  # a new enumerated replacement value is found by increasing an index by 1.
472
472
  #
473
473
  # @param [String, Integer, Float] original the original value of the tag to be anonymized
474
- # @param [Fixnum] j the index of this tag in the tag-related instance arrays
474
+ # @param [Integer] j the index of this tag in the tag-related instance arrays
475
475
  # @return [String, Integer, Float] the replacement value which is used for the anonymization of the tag
476
476
  #
477
477
  def enumerated_value(original, j)
@@ -1,4 +1,4 @@
1
- # Copyright 2008-2017 Christoffer Lervag
1
+ # Copyright 2008-2018 Christoffer Lervag
2
2
  #
3
3
  # This program is free software: you can redistribute it and/or modify
4
4
  # it under the terms of the GNU General Public License as published by
@@ -238,7 +238,7 @@ module DICOM
238
238
  #
239
239
  # @note Two objects with the same attributes will have the same hash code.
240
240
  #
241
- # @return [Fixnum] the object's hash code
241
+ # @return [Integer] the object's hash code
242
242
  #
243
243
  def hash
244
244
  state.hash
@@ -1,278 +1,278 @@
1
- module DICOM
2
-
3
- # The Element class handles information related to ordinary (non-parent) elementals (data elements).
4
- #
5
- class Element
6
-
7
- # Include the Elemental mix-in module:
8
- include Elemental
9
-
10
- # Creates an Element instance.
11
- #
12
- # @note In the case where the Element is given a binary instead of value,
13
- # the Element will not have a formatted value (value = nil).
14
- # @note Private data elements are named as 'Private'.
15
- # @note Non-private data elements that are not found in the dictionary are named as 'Unknown'.
16
- #
17
- # @param [String] tag a ruby-dicom type element tag string
18
- # @param [String, Integer, Float, Array, NilClass] value a custom value to be encoded as the data element binary string, or in some cases (specified by options), a pre-encoded binary string
19
- # @param [Hash] options the options to use for creating the element
20
- #
21
- # @option options [String] :bin 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
22
- # @option options [Boolean] :encoded if the value parameter contains a pre-encoded binary, this boolean must to be set as true
23
- # @option options [String] :name the name of the Element (if not specified, the name is retrieved from the dictionary)
24
- # @option options [DObject, Item, NilClass] :parent a parent instance (Item or DObject) which the element belongs to
25
- # @option options [String] :vr if a private element is created with a custom value, this must be specified to enable the encoding of the value (if not specified, the vr is retrieved from the dictionary)
26
- #
27
- # @example Create a new data element and connect it to a DObject instance
28
- # patient_name = Element.new('0010,0010', 'John Doe', :parent => dcm)
29
- # @example Create a "Pixel Data" element and insert image data that you have already encoded elsewhere
30
- # pixel_data = Element.new('7FE0,0010', processed_pixel_data, :encoded => true, :parent => dcm)
31
- # @example Create a private data element
32
- # private = Element.new('0011,2102', some_data, :parent => dcm, :vr => 'LO')
33
- #
34
- def initialize(tag, value, options={})
35
- 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?
36
- # Set instance variables:
37
- @tag = tag.upcase
38
- # We may need to retrieve name and vr from the library:
39
- if options[:name] and options[:vr]
40
- @name = options[:name]
41
- @vr = options[:vr].upcase
42
- else
43
- name, vr = LIBRARY.name_and_vr(tag)
44
- @name = options[:name] || name
45
- @vr = (options[:vr] ? options[:vr].upcase : vr)
46
- end
47
- # Manage the parent relation if specified:
48
- if options[:parent]
49
- @parent = options[:parent]
50
- # FIXME: Because of some implementation problems, attaching the special
51
- # Data Set Trailing Padding element to a parent is not supported yet!
52
- @parent.add(self, :no_follow => true) unless @tag == 'FFFC,FFFC' && @parent.is_a?(Sequence)
53
- end
54
- # Value may in some cases be the binary string:
55
- unless options[:encoded]
56
- # The Data Element may have a value, have no value and no binary, or have no value and only binary:
57
- if value
58
- # Is binary value provided or do we need to encode it?
59
- if options[:bin]
60
- @value = value
61
- @bin = options[:bin]
62
- else
63
- if value == ''
64
- @value = value
65
- @bin = ''
66
- else
67
- # Set the value with our custom setter method to get proper encoding:
68
- self.value = value
69
- end
70
- end
71
- else
72
- # When no value is present, we set the binary as an empty string, unless the binary is specified:
73
- @bin = options[:bin] || ''
74
- end
75
- else
76
- @bin = value
77
- end
78
- # Let the binary decide the length:
79
- @length = @bin.length
80
- end
81
-
82
- # Checks for equality.
83
- #
84
- # Other and self are considered equivalent if they are
85
- # of compatible types and their attributes are equivalent.
86
- #
87
- # @param other an object to be compared with self.
88
- # @return [Boolean] true if self and other are considered equivalent
89
- #
90
- def ==(other)
91
- if other.respond_to?(:to_element)
92
- other.send(:state) == state
93
- end
94
- end
95
-
96
- alias_method :eql?, :==
97
-
98
- # Sets the binary string of a Element.
99
- #
100
- # @note if the specified binary has an odd length, a proper pad byte will automatically be appended
101
- # to give it an even length (which is needed to conform with the DICOM standard).
102
- #
103
- # @param [String] new_bin a binary string of encoded data
104
- #
105
- def bin=(new_bin)
106
- raise ArgumentError, "Expected String, got #{new_bin.class}." unless new_bin.is_a?(String)
107
- # Add a zero byte at the end if the length of the binary is odd:
108
- if new_bin.length.odd?
109
- @bin = new_bin + stream.pad_byte[@vr]
110
- else
111
- @bin = new_bin
112
- end
113
- @value = nil
114
- @length = @bin.length
115
- end
116
-
117
- # Checks if the Element actually has any child elementals.
118
- #
119
- # @return [FalseClass] always returns false, as Element instances by definition can't have children
120
- #
121
- def children?
122
- return false
123
- end
124
-
125
- # Gives the endianness of the encoded binary value of this element.
126
- #
127
- # @return [Boolean] false if little endian, true if big endian
128
- #
129
- def endian
130
- return stream.str_endian
131
- end
132
-
133
- # Computes a hash code for this object.
134
- #
135
- # @note Two objects with the same attributes will have the same hash code.
136
- #
137
- # @return [Fixnum] the object's hash code
138
- #
139
- def hash
140
- state.hash
141
- end
142
-
143
- # Gives a string containing a human-readable hash representation of the Element.
144
- #
145
- # @return [String] a hash representation string of the element
146
- #
147
- def inspect
148
- to_hash.inspect
149
- end
150
-
151
- # Checks if the Element is a parent.
152
- #
153
- # @return [FalseClass] always returns false, as Element instances by definition are not parents
154
- #
155
- def is_parent?
156
- return false
157
- end
158
-
159
- # Creates a hash representation of the element instance.
160
- #
161
- # @note The key representation in this hash is configurable
162
- # (refer to the DICOM module methods documentation for more details).
163
- # @return [Hash] a hash containing a key & value pair (e.g. {"Modality"=>"MR"})
164
- #
165
- def to_hash
166
- return {self.send(DICOM.key_representation) => value}
167
- end
168
-
169
- # Returns self.
170
- #
171
- # @return [Element] self
172
- #
173
- def to_element
174
- self
175
- end
176
-
177
- # Gives a json string containing a human-readable representation of the Element.
178
- #
179
- # @return [String] a string containing a key & value pair (e.g. "{\"Modality\":\"MR\"}")
180
- #
181
- def to_json
182
- to_hash.to_json
183
- end
184
-
185
- # Gives a yaml string containing a human-readable representation of the Element.
186
- #
187
- # @return [String] a string containing a key & value pair (e.g. "---\nModality: MR\n")
188
- #
189
- def to_yaml
190
- to_hash.to_yaml
191
- end
192
-
193
- # Gives the (decoded) value of the data element.
194
- #
195
- # @note Returned string values are automatically converted from their originally
196
- # encoding (e.g. ISO8859-1 or ASCII-8BIT) to UTF-8 for convenience reasons.
197
- # If the value string is wanted in its original encoding, extract the data
198
- # element's bin attribute instead.
199
- #
200
- # @note Note that according to the DICOM Standard PS 3.5 C.12.1.1.2, the Character Set only applies
201
- # to values of data elements of type SH, LO, ST, PN, LT or UT. Currently in ruby-dicom, all
202
- # string values are encoding converted regardless of VR, but whether this causes any problems is uknown.
203
- #
204
- # @return [String, Integer, Float] the formatted element value
205
- #
206
- def value
207
- if @value.is_a?(String)
208
- # Unless this is actually the Character Set data element,
209
- # get the character set (note that it may not be available):
210
- character_set = (@tag != '0008,0005' && top_parent.is_a?(DObject)) ? top_parent.value('0008,0005') : nil
211
- # Convert to UTF-8 from [original encoding]:
212
- # In most cases the original encoding is IS0-8859-1 (ISO_IR 100), but if
213
- # it is not specified in the DICOM object, or if the specified string
214
- # is not recognized, ASCII-8BIT is assumed.
215
- @value.encode('UTF-8', ENCODING_NAME[character_set])
216
- # If unpleasant encoding exceptions occur, the below version may be considered:
217
- #@value.encode('UTF-8', ENCODING_NAME[character_set], :invalid => :replace, :undef => :replace)
218
- else
219
- @value
220
- end
221
- end
222
-
223
- # Sets the value of the Element instance.
224
- #
225
- # In addition to updating the value attribute, the specified value is encoded to binary
226
- # and used to update the Element's bin and length attributes too.
227
- #
228
- # @note The specified value must be of a type that is compatible with the Element's value representation (vr).
229
- # @param [String, Integer, Float, Array] new_value a formatted value that is assigned to the element
230
- #
231
- def value=(new_value)
232
- if VALUE_CONVERSION[@vr] == :to_s
233
- # Unless this is actually the Character Set data element,
234
- # get the character set (note that it may not be available):
235
- character_set = (@tag != '0008,0005' && top_parent.is_a?(DObject)) ? top_parent.value('0008,0005') : nil
236
- # Convert to [DObject encoding] from [input string encoding]:
237
- # In most cases the DObject encoding is IS0-8859-1 (ISO_IR 100), but if
238
- # it is not specified in the DICOM object, or if the specified string
239
- # is not recognized, ASCII-8BIT is assumed.
240
- @value = new_value.to_s.encode(ENCODING_NAME[character_set], new_value.to_s.encoding.name)
241
- @bin = encode(@value)
242
- else
243
- # We may have an array (of numbers) which needs to be passed directly to
244
- # the encode method instead of being forced into a numerical:
245
- if new_value.is_a?(Array)
246
- @value = new_value
247
- @bin = encode(@value)
248
- else
249
- @value = new_value.send(VALUE_CONVERSION[@vr])
250
- @bin = encode(@value)
251
- end
252
- end
253
- @length = @bin.length
254
- end
255
-
256
-
257
- private
258
-
259
-
260
- # Encodes a formatted value to a binary string.
261
- #
262
- # @param [String, Integer, Float, Array] formatted_value a formatted value
263
- # @return [String] the encoded, binary string
264
- #
265
- def encode(formatted_value)
266
- stream.encode_value(formatted_value, @vr)
267
- end
268
-
269
- # Collects the attributes of this instance.
270
- #
271
- # @return [Array<String>] an array of attributes
272
- #
273
- def state
274
- [@tag, @vr, @value, @bin]
275
- end
276
-
277
- end
278
- end
1
+ module DICOM
2
+
3
+ # The Element class handles information related to ordinary (non-parent) elementals (data elements).
4
+ #
5
+ class Element
6
+
7
+ # Include the Elemental mix-in module:
8
+ include Elemental
9
+
10
+ # Creates an Element instance.
11
+ #
12
+ # @note In the case where the Element is given a binary instead of value,
13
+ # the Element will not have a formatted value (value = nil).
14
+ # @note Private data elements are named as 'Private'.
15
+ # @note Non-private data elements that are not found in the dictionary are named as 'Unknown'.
16
+ #
17
+ # @param [String] tag a ruby-dicom type element tag string
18
+ # @param [String, Integer, Float, Array, NilClass] value a custom value to be encoded as the data element binary string, or in some cases (specified by options), a pre-encoded binary string
19
+ # @param [Hash] options the options to use for creating the element
20
+ #
21
+ # @option options [String] :bin 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
22
+ # @option options [Boolean] :encoded if the value parameter contains a pre-encoded binary, this boolean must to be set as true
23
+ # @option options [String] :name the name of the Element (if not specified, the name is retrieved from the dictionary)
24
+ # @option options [DObject, Item, NilClass] :parent a parent instance (Item or DObject) which the element belongs to
25
+ # @option options [String] :vr if a private element is created with a custom value, this must be specified to enable the encoding of the value (if not specified, the vr is retrieved from the dictionary)
26
+ #
27
+ # @example Create a new data element and connect it to a DObject instance
28
+ # patient_name = Element.new('0010,0010', 'John Doe', :parent => dcm)
29
+ # @example Create a "Pixel Data" element and insert image data that you have already encoded elsewhere
30
+ # pixel_data = Element.new('7FE0,0010', processed_pixel_data, :encoded => true, :parent => dcm)
31
+ # @example Create a private data element
32
+ # private = Element.new('0011,2102', some_data, :parent => dcm, :vr => 'LO')
33
+ #
34
+ def initialize(tag, value, options={})
35
+ 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?
36
+ # Set instance variables:
37
+ @tag = tag.upcase
38
+ # We may need to retrieve name and vr from the library:
39
+ if options[:name] and options[:vr]
40
+ @name = options[:name]
41
+ @vr = options[:vr].upcase
42
+ else
43
+ name, vr = LIBRARY.name_and_vr(tag)
44
+ @name = options[:name] || name
45
+ @vr = (options[:vr] ? options[:vr].upcase : vr)
46
+ end
47
+ # Manage the parent relation if specified:
48
+ if options[:parent]
49
+ @parent = options[:parent]
50
+ # FIXME: Because of some implementation problems, attaching the special
51
+ # Data Set Trailing Padding element to a parent is not supported yet!
52
+ @parent.add(self, :no_follow => true) unless @tag == 'FFFC,FFFC' && @parent.is_a?(Sequence)
53
+ end
54
+ # Value may in some cases be the binary string:
55
+ unless options[:encoded]
56
+ # The Data Element may have a value, have no value and no binary, or have no value and only binary:
57
+ if value
58
+ # Is binary value provided or do we need to encode it?
59
+ if options[:bin]
60
+ @value = value
61
+ @bin = options[:bin]
62
+ else
63
+ if value == ''
64
+ @value = value
65
+ @bin = ''
66
+ else
67
+ # Set the value with our custom setter method to get proper encoding:
68
+ self.value = value
69
+ end
70
+ end
71
+ else
72
+ # When no value is present, we set the binary as an empty string, unless the binary is specified:
73
+ @bin = options[:bin] || ''
74
+ end
75
+ else
76
+ @bin = value
77
+ end
78
+ # Let the binary decide the length:
79
+ @length = @bin.length
80
+ end
81
+
82
+ # Checks for equality.
83
+ #
84
+ # Other and self are considered equivalent if they are
85
+ # of compatible types and their attributes are equivalent.
86
+ #
87
+ # @param other an object to be compared with self.
88
+ # @return [Boolean] true if self and other are considered equivalent
89
+ #
90
+ def ==(other)
91
+ if other.respond_to?(:to_element)
92
+ other.send(:state) == state
93
+ end
94
+ end
95
+
96
+ alias_method :eql?, :==
97
+
98
+ # Sets the binary string of a Element.
99
+ #
100
+ # @note if the specified binary has an odd length, a proper pad byte will automatically be appended
101
+ # to give it an even length (which is needed to conform with the DICOM standard).
102
+ #
103
+ # @param [String] new_bin a binary string of encoded data
104
+ #
105
+ def bin=(new_bin)
106
+ raise ArgumentError, "Expected String, got #{new_bin.class}." unless new_bin.is_a?(String)
107
+ # Add a zero byte at the end if the length of the binary is odd:
108
+ if new_bin.length.odd?
109
+ @bin = new_bin + stream.pad_byte[@vr]
110
+ else
111
+ @bin = new_bin
112
+ end
113
+ @value = nil
114
+ @length = @bin.length
115
+ end
116
+
117
+ # Checks if the Element actually has any child elementals.
118
+ #
119
+ # @return [FalseClass] always returns false, as Element instances by definition can't have children
120
+ #
121
+ def children?
122
+ return false
123
+ end
124
+
125
+ # Gives the endianness of the encoded binary value of this element.
126
+ #
127
+ # @return [Boolean] false if little endian, true if big endian
128
+ #
129
+ def endian
130
+ return stream.str_endian
131
+ end
132
+
133
+ # Computes a hash code for this object.
134
+ #
135
+ # @note Two objects with the same attributes will have the same hash code.
136
+ #
137
+ # @return [Integer] the object's hash code
138
+ #
139
+ def hash
140
+ state.hash
141
+ end
142
+
143
+ # Gives a string containing a human-readable hash representation of the Element.
144
+ #
145
+ # @return [String] a hash representation string of the element
146
+ #
147
+ def inspect
148
+ to_hash.inspect
149
+ end
150
+
151
+ # Checks if the Element is a parent.
152
+ #
153
+ # @return [FalseClass] always returns false, as Element instances by definition are not parents
154
+ #
155
+ def is_parent?
156
+ return false
157
+ end
158
+
159
+ # Creates a hash representation of the element instance.
160
+ #
161
+ # @note The key representation in this hash is configurable
162
+ # (refer to the DICOM module methods documentation for more details).
163
+ # @return [Hash] a hash containing a key & value pair (e.g. {"Modality"=>"MR"})
164
+ #
165
+ def to_hash
166
+ return {self.send(DICOM.key_representation) => value}
167
+ end
168
+
169
+ # Returns self.
170
+ #
171
+ # @return [Element] self
172
+ #
173
+ def to_element
174
+ self
175
+ end
176
+
177
+ # Gives a json string containing a human-readable representation of the Element.
178
+ #
179
+ # @return [String] a string containing a key & value pair (e.g. "{\"Modality\":\"MR\"}")
180
+ #
181
+ def to_json
182
+ to_hash.to_json
183
+ end
184
+
185
+ # Gives a yaml string containing a human-readable representation of the Element.
186
+ #
187
+ # @return [String] a string containing a key & value pair (e.g. "---\nModality: MR\n")
188
+ #
189
+ def to_yaml
190
+ to_hash.to_yaml
191
+ end
192
+
193
+ # Gives the (decoded) value of the data element.
194
+ #
195
+ # @note Returned string values are automatically converted from their originally
196
+ # encoding (e.g. ISO8859-1 or ASCII-8BIT) to UTF-8 for convenience reasons.
197
+ # If the value string is wanted in its original encoding, extract the data
198
+ # element's bin attribute instead.
199
+ #
200
+ # @note Note that according to the DICOM Standard PS 3.5 C.12.1.1.2, the Character Set only applies
201
+ # to values of data elements of type SH, LO, ST, PN, LT or UT. Currently in ruby-dicom, all
202
+ # string values are encoding converted regardless of VR, but whether this causes any problems is uknown.
203
+ #
204
+ # @return [String, Integer, Float] the formatted element value
205
+ #
206
+ def value
207
+ if @value.is_a?(String)
208
+ # Unless this is actually the Character Set data element,
209
+ # get the character set (note that it may not be available):
210
+ character_set = (@tag != '0008,0005' && top_parent.is_a?(DObject)) ? top_parent.value('0008,0005') : nil
211
+ # Convert to UTF-8 from [original encoding]:
212
+ # In most cases the original encoding is IS0-8859-1 (ISO_IR 100), but if
213
+ # it is not specified in the DICOM object, or if the specified string
214
+ # is not recognized, ASCII-8BIT is assumed.
215
+ @value.encode('UTF-8', ENCODING_NAME[character_set])
216
+ # If unpleasant encoding exceptions occur, the below version may be considered:
217
+ #@value.encode('UTF-8', ENCODING_NAME[character_set], :invalid => :replace, :undef => :replace)
218
+ else
219
+ @value
220
+ end
221
+ end
222
+
223
+ # Sets the value of the Element instance.
224
+ #
225
+ # In addition to updating the value attribute, the specified value is encoded to binary
226
+ # and used to update the Element's bin and length attributes too.
227
+ #
228
+ # @note The specified value must be of a type that is compatible with the Element's value representation (vr).
229
+ # @param [String, Integer, Float, Array] new_value a formatted value that is assigned to the element
230
+ #
231
+ def value=(new_value)
232
+ if VALUE_CONVERSION[@vr] == :to_s
233
+ # Unless this is actually the Character Set data element,
234
+ # get the character set (note that it may not be available):
235
+ character_set = (@tag != '0008,0005' && top_parent.is_a?(DObject)) ? top_parent.value('0008,0005') : nil
236
+ # Convert to [DObject encoding] from [input string encoding]:
237
+ # In most cases the DObject encoding is IS0-8859-1 (ISO_IR 100), but if
238
+ # it is not specified in the DICOM object, or if the specified string
239
+ # is not recognized, ASCII-8BIT is assumed.
240
+ @value = new_value.to_s.encode(ENCODING_NAME[character_set], new_value.to_s.encoding.name)
241
+ @bin = encode(@value)
242
+ else
243
+ # We may have an array (of numbers) which needs to be passed directly to
244
+ # the encode method instead of being forced into a numerical:
245
+ if new_value.is_a?(Array)
246
+ @value = new_value
247
+ @bin = encode(@value)
248
+ else
249
+ @value = new_value.send(VALUE_CONVERSION[@vr])
250
+ @bin = encode(@value)
251
+ end
252
+ end
253
+ @length = @bin.length
254
+ end
255
+
256
+
257
+ private
258
+
259
+
260
+ # Encodes a formatted value to a binary string.
261
+ #
262
+ # @param [String, Integer, Float, Array] formatted_value a formatted value
263
+ # @return [String] the encoded, binary string
264
+ #
265
+ def encode(formatted_value)
266
+ stream.encode_value(formatted_value, @vr)
267
+ end
268
+
269
+ # Collects the attributes of this instance.
270
+ #
271
+ # @return [Array<String>] an array of attributes
272
+ #
273
+ def state
274
+ [@tag, @vr, @value, @bin]
275
+ end
276
+
277
+ end
278
+ end