dicom 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
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