dcm_dict 0.29.0

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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +156 -0
  3. data/COPYING +674 -0
  4. data/LICENSE +22 -0
  5. data/README.md +327 -0
  6. data/Rakefile +36 -0
  7. data/bin/dcm_dict_converter.rb +194 -0
  8. data/lib/dcm_dict.rb +46 -0
  9. data/lib/dcm_dict/dictionary/base_dictionary.rb +47 -0
  10. data/lib/dcm_dict/dictionary/base_record.rb +62 -0
  11. data/lib/dcm_dict/dictionary/data_element_dictionary.rb +117 -0
  12. data/lib/dcm_dict/dictionary/data_element_record.rb +93 -0
  13. data/lib/dcm_dict/dictionary/uid_dictionary.rb +82 -0
  14. data/lib/dcm_dict/dictionary/uid_record.rb +48 -0
  15. data/lib/dcm_dict/encoder/data_to_code.rb +79 -0
  16. data/lib/dcm_dict/error/dictionary_error.rb +30 -0
  17. data/lib/dcm_dict/ext/object_extension.rb +38 -0
  18. data/lib/dcm_dict/refine/array_refine.rb +34 -0
  19. data/lib/dcm_dict/refine/data_element_refine.rb +37 -0
  20. data/lib/dcm_dict/refine/internal/array_refine_internal.rb +97 -0
  21. data/lib/dcm_dict/refine/internal/hash_refine_internal.rb +71 -0
  22. data/lib/dcm_dict/refine/internal/string_refine_internal.rb +135 -0
  23. data/lib/dcm_dict/refine/string_refine.rb +35 -0
  24. data/lib/dcm_dict/refine/symbol_refine.rb +34 -0
  25. data/lib/dcm_dict/refine/uid_refine.rb +36 -0
  26. data/lib/dcm_dict/rubies/rb_ext.rb +32 -0
  27. data/lib/dcm_dict/source_data/data_elements_data.rb +4945 -0
  28. data/lib/dcm_dict/source_data/detached_data.rb +67 -0
  29. data/lib/dcm_dict/source_data/uid_values_data.rb +467 -0
  30. data/lib/dcm_dict/version.rb +27 -0
  31. data/lib/dcm_dict/xml/constant.rb +38 -0
  32. data/lib/dcm_dict/xml/field_data.rb +47 -0
  33. data/lib/dcm_dict/xml/nokogiri_tool.rb +108 -0
  34. data/lib/dcm_dict/xml/rexml_tool.rb +105 -0
  35. data/lib/dcm_dict/xml/tag_field_data.rb +96 -0
  36. data/lib/dcm_dict/xml/uid_field_data.rb +60 -0
  37. data/lib/dcm_dict/xml/xml_tool.rb +47 -0
  38. data/spec/data_element_sample_spec_helper.rb +203 -0
  39. data/spec/data_element_shared_example_spec_helper.rb +57 -0
  40. data/spec/dcm_dict/dictionary/data_element_dictionary_spec.rb +76 -0
  41. data/spec/dcm_dict/dictionary/data_element_record_spec.rb +138 -0
  42. data/spec/dcm_dict/dictionary/uid_dictionary_spec.rb +82 -0
  43. data/spec/dcm_dict/dictionary/uid_record_spec.rb +53 -0
  44. data/spec/dcm_dict/encoder/data_to_code_spec.rb +109 -0
  45. data/spec/dcm_dict/ext/object_extension_spec.rb +53 -0
  46. data/spec/dcm_dict/refine/array_refine_spec.rb +60 -0
  47. data/spec/dcm_dict/refine/internal/array_refine_internal_spec.rb +98 -0
  48. data/spec/dcm_dict/refine/internal/hash_refine_internal_spec.rb +64 -0
  49. data/spec/dcm_dict/refine/internal/string_refine_internal_spec.rb +228 -0
  50. data/spec/dcm_dict/refine/string_refine_spec.rb +87 -0
  51. data/spec/dcm_dict/refine/symbol_refine_spec.rb +41 -0
  52. data/spec/dcm_dict/rubies/rb_ext_spec.rb +46 -0
  53. data/spec/dcm_dict/source_data/data_elements_data_spec.rb +40 -0
  54. data/spec/dcm_dict/source_data/detached_data_spec.rb +55 -0
  55. data/spec/dcm_dict/source_data/uid_values_data_spec.rb +37 -0
  56. data/spec/dcm_dict/version_spec.rb +30 -0
  57. data/spec/dcm_dict/xml/tag_field_data_spec.rb +62 -0
  58. data/spec/dcm_dict/xml/uid_field_data_spec.rb +60 -0
  59. data/spec/dictionary_shared_example_spec_helper.rb +118 -0
  60. data/spec/refine_shared_example_spec_helper.rb +54 -0
  61. data/spec/spec_helper.rb +42 -0
  62. data/spec/xml_sample_spec_helper.rb +567 -0
  63. metadata +216 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ DcmDict is a Ruby gem (dcm_dict) to handle
2
+ in a simple way the Data defined within the DICOM Standard.
3
+
4
+ Copyright (C) 2014-2020 Enrico Rivarola
5
+
6
+ DcmDict is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ DcmDict is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with DcmDict (file 'COPYING'). If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ This software has neither been tested nor approved for clinical use
20
+ or for incorporation in a medical device.
21
+ It is the redistributor's or user's responsibility to comply with any
22
+ applicable local, state, national or international regulations.
@@ -0,0 +1,327 @@
1
+ # What's *DcmDict*
2
+ **DcmDict** is a Ruby gem [(*dcm\_dict*)][12] to handle in a simple way the *Data Dictionary* defined within the DICOM<sup>®</sup> Standard <sup id='fn-dcm-trademark'>[1]</sup> such as DICOM Data Elements or DICOM Unique Identifiers.
3
+
4
+ # Why *DcmDict*
5
+ With the new releases from year 2014 DICOM documents are available in different format including one particularly interesting, the *DocBook* XML version.
6
+
7
+ As confirmed in the DICOM<sup>®</sup> Standard [web site][10] where each part is published in [multiple formats][11] and XML format is defined by:
8
+ >"... XML – good for machine readability, e.g. self-updating validators ..."
9
+
10
+ This is great news for anyone involved in the study of the standard !
11
+
12
+ Starting from this thing was born the idea of trying to automate the extraction of data from XML documents to make available the information in a simple way that simplifies the study of the DICOM standard, in the hope this idea will be useful and inspiration.
13
+
14
+ # *DcmDict* features
15
+ The library involve *String*, *Array* and *Symbol* class as *refinements* to access to DICOM information.
16
+
17
+ In this way is possible to *play* with the 'Patient's Birth Date' tag defined as (0010,0030) by:
18
+
19
+ ```ruby
20
+ > "(0010,0030)".tag_name
21
+ => "Patient's Birth Date"
22
+ > 'PatientBirthDate'.tag_vr
23
+ => [:DA]
24
+ > "Patient's Birth Date".tag_vm
25
+ => ["1"]
26
+ > :patient_birth_date.tag
27
+ => [16, 48]
28
+ > [16,48].tag_key
29
+ => "PatientBirthDate"
30
+ > [16, 48].tag_group
31
+ => 16
32
+ > '00100030'.tag_element
33
+ => 48
34
+ > :patient_birth_date.tag_group
35
+ => 16
36
+ > "Patient's Birth Date".tag_element
37
+ => 48
38
+ ```
39
+
40
+ as well for UIDs
41
+
42
+ ```ruby
43
+ > '1.2.840.10008.1.2'.uid_name
44
+ => "Implicit VR Little Endian: Default Transfer Syntax for DICOM"
45
+ > '1.2.840.10008.1.2'.uid_type
46
+ => :transfer_syntax
47
+ > "Implicit VR Little Endian: Default Transfer Syntax for DICOM".uid_value
48
+ => "1.2.840.10008.1.2"
49
+ ```
50
+
51
+ let see all features in detail:
52
+
53
+ ## Library usage
54
+ The library involve **Ruby Refinements** so use it is simple, it is necessary to include the specific *using directive*:
55
+
56
+ ```ruby
57
+ using DcmDict::Refine::StringRefine
58
+ ```
59
+ for the String object,
60
+ ```ruby
61
+ using DcmDict::Refine::ArrayRefine
62
+ ```
63
+ for the Array object and
64
+
65
+ ```ruby
66
+ using DcmDict::Refine::SymbolRefine
67
+ ```
68
+ for the Symbol object.
69
+
70
+ That's it.
71
+
72
+ **Note**: It is possible to use also the the *monkey patching* way, this is a *deprecated* utilization but possible, and, may be, useful technique in certain contexts or for some particular test. For the *monkey patching* is possible to include some specific *common modules* in the class you want to use as "keyword": there are two base modules *DcmDict::Refine::DataElementRefine* and *DcmDict::Refine::UidRefine*.
73
+
74
+ For example in the String class will have the code:
75
+
76
+ ```ruby
77
+ class String
78
+ include DcmDict::Refine::DataElementRefine
79
+ include DcmDict::Refine::UidRefine
80
+ end
81
+ ```
82
+
83
+ *The main way remains **Ruby Refinements***.
84
+
85
+ **Rubies compatibility**: at this moment the other considered rubies is only [Rubinius][4] (>= v2.2.10). In order to try to ensure a minimum compatibility there is a file under *lib/dcm_dict/rubies/* called *rb_ext.rb* able to *mask*/*simulates* the refinements by [refine gem][5] and add the required *bit_length* method to *Fixnum* class by [backports gem][6].
86
+ This sort of extension is not loaded by default but only into *spec files* for the *'rbx' Ruby Engine*. See *spec_helper.rb* and *rb_ext.rb* for details.
87
+
88
+ ## Data Element data in detail
89
+ Any Data Element feature can be accessed from a *String*, *Array* or *Symbol* objects.
90
+
91
+ For these objects is possible to access to Tag (group/element), Name, Keyword, Value Representation (VR) and Value Multiplicity (VM) for any single Data Element.
92
+
93
+ The main methods supported are:
94
+
95
+ |Method | Note| Type||
96
+ |:------|:------------:|:---:|:---:|
97
+ |**tag** | tag as Array| Array of two Fixnum|(alias of *tag_ary*)|
98
+ |**tag_name** | name of tag| String|
99
+ |**tag_keyword** | keyword| String|
100
+ |**tag_key** | keyword| String|
101
+ |**tag_vr** | Value Representation| Array of Symbol|
102
+ |**tag_vm** | Value Multiplicity| Array of Symbol|
103
+ |**tag_ps** | tag as string (as standard doc)| String|
104
+ |**tag_ary** | tag as Array|Array of two Fixnum|
105
+ |**tag_sym** | tag as Symbol|Symbol|
106
+ |**tag_ndm** | tag as in Native DICOM Model|String|
107
+ |**tag_str** | tag as string (similar to tag_ps)|String|
108
+ |**tag_note** | tag note|String|
109
+ |**tag_multiple?** | is a multiple tag ? |boolean|(useful for 'multi tag' attribute)|
110
+
111
+ each data element is indexed by these fields:
112
+
113
+ |Field|Type|
114
+ |:----|:-----:|
115
+ |**tag_key** | String|
116
+ |**tag_ps** | String|
117
+ |**tag_ary** | Array|
118
+ |**tag_sym** | Symbol|
119
+ |**tag_ndm** | String|
120
+ |**tag_str** | String|
121
+ |**tag_name** | String|
122
+
123
+ By these fields is possible to access to data element informations.
124
+ Consider the case of the tag (0010,1005) (*Patient's Birth Name*), the primary fields are:
125
+ **'(0010,1005)'**, **"Patient's Birth Name"**, **'PatientBirthName'**, **:patient_birth_name**, **'00101005'** and **[0x0010,0x1005]**
126
+
127
+ - As String key you may use the standard tag format **'(0010,1005)'**, the tag name **'Patient's Birth Name'**, the tag keyword **'PatientBirthName'** or the Native DICOM Format tag **'00101005'**
128
+ - As Array key you may use the numeric array **[0x0010,0x1005]**
129
+ - As Symbol key you may use **:patient_birth_name**
130
+
131
+ ### example:
132
+ Consider the previous case of tag (0010,1005), the code:
133
+
134
+ ```ruby
135
+ puts "Patient's Birth Name".tag_ps.inspect
136
+ puts [0x0010,0x1005].tag_name.inspect
137
+ puts '(0010,1005)'.tag_key.inspect
138
+ puts :patient_birth_name.tag_vr.inspect
139
+ puts 'PatientBirthName'.tag_vm.inspect
140
+ puts '00101005'.tag.inspect
141
+ puts '(0010,1005)'.tag_ary.inspect
142
+ puts '00101005'.tag_sym.inspect
143
+ puts 'PatientBirthName'.tag_ndm.inspect
144
+ puts "Patient's Birth Name".tag_str.inspect
145
+ puts [0x0010,0x1005].tag_note.inspect
146
+ puts [0x0010,0x1005].tag_group.inspect
147
+ puts :patient_birth_name.tag_element.inspect
148
+ ```
149
+
150
+ will produce
151
+
152
+
153
+ ```ruby
154
+ "(0010,1005)"
155
+ "Patient's Birth Name"
156
+ "PatientBirthName"
157
+ [:PN]
158
+ ["1"]
159
+ [16, 4101]
160
+ [16, 4101]
161
+ :patient_birth_name
162
+ "00101005"
163
+ "(0010,1005)"
164
+ ""
165
+ 16
166
+ 4101
167
+ ```
168
+
169
+ ### Multiple Tag
170
+ The library also manage 'multiple tags' such as *(0020,31XX)* (*Source Image IDs*).
171
+ As an example for this data element the default tag in array form is [0x0020,0x3122] and all fields are expressed as:
172
+
173
+ |Method/field | Value|
174
+ |:------|:------------:|
175
+ |**tag** | [0x0020,0x3122]|
176
+ |**tag_name** | "Source Image IDs"|
177
+ |**tag_keyword** | 'SourceImageIDs'|
178
+ |**tag_key** | 'SourceImageIDs'|
179
+ |**tag_vr** | [:CS]|
180
+ |**tag_vm** | ["1-n"]|
181
+ |**tag_ps** | '(0020,31XX)'|
182
+ |**tag_ary** | [0x0020,0x3122]|
183
+ |**tag_sym** | :source_image_ids|
184
+ |**tag_ndm** | '00203122'
185
+ |**tag_str** | '(0020,3122)'|
186
+ |**tag_note** | 'RET'|
187
+ |**tag_multiple?** | true|
188
+
189
+ [0x0020,0x3122] is the default value for group/element pair (*[32, 12578]*), but any valid pair of numbers for this tag will be refers that information:
190
+
191
+ ```ruby
192
+ > '(0020,31XX)'.tag_name
193
+ => "Source Image IDs"
194
+ > '(0020,31XX)'.tag_ndm
195
+ => "00203122"
196
+ > "SourceImageIDs".tag_ary
197
+ => [32, 12578]
198
+ > '(0020,3178)'.tag_name
199
+ => "Source Image IDs"
200
+ [0x0020,0x3146].tag_sym
201
+ => :source_image_ids
202
+ > '00203120'.tag_key
203
+ => "SourceImageIDs"
204
+ > [0x0020,0x3138].tag_vr
205
+ => [:CS]
206
+ > '(0020,3144)'.tag_note
207
+ => "RET"
208
+ ```
209
+
210
+ and so on.
211
+
212
+ ## UID data in detail
213
+ Any UID features can be accessed from a *String* object.
214
+
215
+ ### UID Values
216
+ For these objects is possible to access to value, name and type values for any single uid.
217
+ Main methods supported are:
218
+
219
+ |Method | Note| Type||
220
+ |:------|:------------:|:---:|:---:|
221
+ |**uid** | value of uid| String|(alias of *uid_value*)|
222
+ |**uid_value** | value of uid| String|
223
+ |**uid_name** | name of uid| String|
224
+ |**uid_type** | type of uid| Symbol|
225
+
226
+ each uid is indexed by:
227
+
228
+ |Field|Type|
229
+ |:----|:-----|
230
+ |**uid_value** | String|
231
+ |**uid_name** | String|
232
+
233
+ From these fields is possible to access to all uid informations.
234
+ Consider the case of the uid *1.2.840.10008.1.1* (*Verification SOP Class*), the primary fields are the strings **'1.2.840.10008.1.1'** and **"Verification SOP Class"**.
235
+ - As String key you may use the standard value **'1.2.840.10008.1.1'** and the uid name **"Verification SOP Class"**
236
+
237
+ For this uid all fields are expressed as:
238
+
239
+ |Method/field | Value|
240
+ |:------|:------------:|
241
+ |**uid** | '1.2.840.10008.1.1'|
242
+ |**uid_value** | '1.2.840.10008.1.1'|
243
+ |**uid_name** | "Verification SOP Class"|
244
+ |**uid_type** | :sop_class|
245
+
246
+ ### example:
247
+
248
+ ```ruby
249
+ > "Verification SOP Class".uid_value
250
+ => "1.2.840.10008.1.1"
251
+ > "1.2.840.10008.1.1".uid_type
252
+ => :sop_class
253
+ > "1.2.840.10008.1.1".uid_name
254
+ => "Verification SOP Class"
255
+ > "Verification SOP Class".uid
256
+ => "1.2.840.10008.1.1"
257
+ ```
258
+
259
+ ## How data is extracted
260
+ The library also contains a script (*dcm_dict_converter.rb* in the *bin* folder) able to download the xml documents and extracts the source data in a *Ruby compatible format*.
261
+ The script produces the conversion in the *stdout* so for example is possible to extract the Tag Values by:
262
+
263
+ ```ruby
264
+ dcm_dict_converter.rb tag > /tmp/tag-dict.rb
265
+ ```
266
+
267
+ Note: the script use the [Nokogiri][3] as XML parser if installed as gem, otherwise the standard *REXML*.
268
+
269
+ Check the file for other details.
270
+
271
+ ## Note
272
+ Current library version is aligned to *DICOM Base Standard* **2020c**
273
+
274
+ ## Install
275
+
276
+ $ gem install dcm_dict
277
+
278
+ *Note for Windows users*: may be that it is installed a previous version of Ruby 2.1, if [RubyInstaller][7] does not provide the official release for the supported version it's still possible to make it manually by clone/download the ['git' version of RubyInstaller][8] and execute the rake command ```rake ruby21``` or equivalent (see RubyInstaller doc for details).
279
+
280
+ ## What's next
281
+ The main idea is that *dictionary* should include only fixed data defined in the DICOM standard to encode and then make it available in easy way.
282
+ There are many possible *candidates* for inclusion in the *dictionary*, here are some *"ideas"*:
283
+
284
+ - Directory Record type data
285
+ - Well-known Frames of Reference UID Values
286
+ - Context Group UID Values
287
+ - Standard Color Palettes UID Values
288
+ - IOD definition data
289
+ - ...
290
+
291
+ ## Contributing
292
+ TBD
293
+
294
+ ## License
295
+ Copyright (C) 2014-2020 Enrico Rivarola.
296
+ See the `LICENSE` and `COPYING` files for license details.
297
+
298
+ ## Ruby Gem
299
+ Ruby gem **dcm\_dict** on [RubyGems][9] at [rubygems.org/gems/dcm_dict](https://rubygems.org/gems/dcm_dict)
300
+
301
+ ## Source Code
302
+ Main source code repository on github at [henrythebuilder/dcm_dict](https://github.com/henrythebuilder/dcm_dict)
303
+
304
+ <div class="footnotes">
305
+ <hr />
306
+ <ol>
307
+ <li id="fn1-dcm-trademark">
308
+ <p><a href="http://www.dicomstandard.org/" title="DICOM Standard">DICOM<sup>®</sup></a> is the registered trademark of the National Electrical Manufacturers Association for its standards publications relating to digital communications of medical information.
309
+ <a href="#fn-dcm-trademark" class='footnoteBackLink' title="Jump back to footnote 1 in the text.">&#x21A9;&#xFE0E;</a></p>
310
+ </li>
311
+ </ol>
312
+ </div>
313
+
314
+ [1]: #fn1-dcm-trademark
315
+
316
+ [dcm1]: http://medical.nema.org/dicom/ "DICOM Homepage"
317
+ [2]: http://www.dclunie.com/dicom-status/status.html "DICOM Standard Status"
318
+ [3]: http://nokogiri.org/ "Nokogiri"
319
+ [4]: http://rubini.us/ "Rubinius"
320
+ [5]: https://rubygems.org/gems/refine "Refine gem at RubyGems.org"
321
+ [6]: https://rubygems.org/gems/backports "Backports gem at RubyGems.org"
322
+ [7]: http://rubyinstaller.org/ "The easy way to install Ruby on Windows"
323
+ [8]: https://github.com/oneclick/rubyinstaller "RubyInstaller for Windows"
324
+ [9]: https://rubygems.org/
325
+ [10]: http://www.dicomstandard.org/
326
+ [11]: http://www.dicomstandard.org/current/
327
+ [12]: https://rubygems.org/gems/dcm_dict
@@ -0,0 +1,36 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "dcm_dict/version"
3
+ require 'rake'
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc "Check all spec"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ t.ruby_opts = "-w"
10
+ t.rspec_opts = '--color --format documentation'
11
+ end
12
+
13
+ desc "Check all spec with code coverage"
14
+ task :coverage do
15
+ ENV['COVERAGE'] = "true"
16
+ Rake::Task["spec"].execute
17
+ end
18
+
19
+ desc(task(:coverage).comment)
20
+ task :default => :coverage
21
+
22
+ desc "Build dcm_dict v#{DcmDict::VERSION} gem"
23
+ task :build do
24
+ system "gem build dcm_dict.gemspec"
25
+ FileUtils.mkdir_p "pkg"
26
+ FileUtils.mv "dcm_dict-#{DcmDict::VERSION}.gem", "pkg"
27
+ end
28
+
29
+ desc "Open IRB with DcmDict support"
30
+ task :console do
31
+ require 'irb'
32
+ require 'irb/completion'
33
+ require 'dcm_dict'
34
+ ARGV.clear
35
+ IRB.start
36
+ end
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+ #
4
+ # Copyright (C) 2014-2020 Enrico Rivarola
5
+ #
6
+ # This file is part of DcmDict gem (dcm_dict).
7
+ #
8
+ # DcmDict is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # DcmDict is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with DcmDict. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+ # This software has neither been tested nor approved for clinical use
22
+ # or for incorporation in a medical device.
23
+ # It is the redistributor's or user's responsibility to comply with any
24
+ # applicable local, state, national or international regulations.
25
+ #
26
+ require 'open-uri'
27
+ require 'tempfile'
28
+ require 'dcm_dict'
29
+ require 'dcm_dict/xml/xml_tool'
30
+
31
+ LICENSE_TEXT=<<END_LICENSE
32
+ Copyright (C) 2014-2020 Enrico Rivarola
33
+
34
+ This file is part of DcmDict gem (dcm_dict).
35
+
36
+ DcmDict is free software: you can redistribute it and/or modify
37
+ it under the terms of the GNU General Public License as published by
38
+ the Free Software Foundation, either version 3 of the License, or
39
+ (at your option) any later version.
40
+
41
+ DcmDict is distributed in the hope that it will be useful,
42
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
43
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44
+ GNU General Public License for more details.
45
+
46
+ You should have received a copy of the GNU General Public License
47
+ along with DcmDict. If not, see <http://www.gnu.org/licenses/>.
48
+
49
+ This software has neither been tested nor approved for clinical use
50
+ or for incorporation in a medical device.
51
+ It is the redistributor's or user's responsibility to comply with any
52
+ applicable local, state, national or international regulations
53
+
54
+ END_LICENSE
55
+
56
+ class DcmDictConverter
57
+ Part6XmlUrl="http://dicom.nema.org/medical/dicom/current/source/docbook/part06/part06.xml"
58
+ Part7XmlUrl="http://dicom.nema.org/medical/dicom/current/source/docbook/part07/part07.xml"
59
+ DataElementSource={
60
+ Part7XmlUrl => ["table_E.1-1", "table_E.2-1"],
61
+ Part6XmlUrl => ["table_7-1", "table_8-1", "table_6-1"]
62
+ }
63
+
64
+ UidSource={
65
+ Part6XmlUrl => ["table_A-1"]
66
+ }
67
+
68
+ DataElementFix = {
69
+ "table_E.2-1" => {:tag_note => 'RET'}
70
+ }
71
+
72
+ def initialize
73
+
74
+ end
75
+
76
+ def print_out_tag
77
+ trace("Print out data to stdout\n")
78
+ print_out_data_elements()
79
+ trace("Print out done.\n")
80
+ end
81
+
82
+ def print_out_uid
83
+ trace("Print out data to stdout\n")
84
+ print_out_uid_data()
85
+ trace("Print out done.\n")
86
+ end
87
+
88
+ private
89
+ def pull_standard_draft(url, output)
90
+ buffer_size = 256 * 1_024
91
+ trace("Downloading #{url}\n")
92
+ URI.open(url, "r",
93
+ :content_length_proc => lambda {|content_length| trace("Content Length: #{content_length} bytes\n.") },
94
+ :progress_proc => lambda { |size| trace(".") }) do |src|
95
+ while (buffer = src.read(buffer_size))
96
+ output.write(buffer)
97
+ end
98
+ end
99
+ trace("Done.\n")
100
+ output.flush
101
+ output.rewind
102
+ end
103
+
104
+ def extract_node_set(xml_file, table_to_map)
105
+ xml_doc = DcmDict::XML::XmlTool.create_xml_doc(File.read(xml_file))
106
+ table_to_map.each do |table|
107
+ trace("Extracting data from '#{table}':")
108
+ xpath="//xmlns:table[@xml:id=\"#{table}\"]//xmlns:tbody/xmlns:tr"
109
+ DcmDict::XML::XmlTool.each_tr_set(xml_doc, xpath) do |tdset|
110
+ yield(table, tdset)
111
+ end
112
+ trace("Done.\n")
113
+ end
114
+ end
115
+
116
+ def extract_data_element(xml_file, table_to_map)
117
+ extract_node_set(xml_file, table_to_map) do |table, td|
118
+ data = DcmDict::XML::XmlTool.extract_data_element_field_from_tr_set(td)
119
+ check_data_element_data(data, table)
120
+ yield(data) if block_given?
121
+ end
122
+ end
123
+
124
+ def check_data_element_data(data, table)
125
+ if (DataElementFix.has_key?(table))
126
+ DataElementFix[table].each{|key, val| data[key]=val if data[key].empty?}
127
+ end
128
+ end
129
+
130
+ def print_out_data_elements()
131
+ print_out(DcmDict::Encoder::DataToCode.data_element_header)
132
+ DataElementSource.each do |url, table_to_map|
133
+ Tempfile.create('dcmps') do |xml_file|
134
+ pull_standard_draft(url, xml_file)
135
+ extract_data_element(xml_file, table_to_map) do |data|
136
+ print_out(DcmDict::Encoder::DataToCode.data_element_data_to_code(data, 6))
137
+ print_out("\r\n")
138
+ trace('.')
139
+ end
140
+ end
141
+ end
142
+ print_out(DcmDict::Encoder::DataToCode.data_element_footer)
143
+ end
144
+
145
+ def extract_uid(xml_file, table_to_map)
146
+ extract_node_set(xml_file, table_to_map) do |table, td|
147
+ data = DcmDict::XML::XmlTool.extract_uid_field_from_tr_set(td)
148
+ yield(data) if block_given?
149
+ end
150
+ end
151
+
152
+ def print_out_uid_data()
153
+ print_out(DcmDict::Encoder::DataToCode.uid_header)
154
+ UidSource.each do |url, table_to_map|
155
+ Tempfile.create('dcmps') do |xml_file|
156
+ pull_standard_draft(url, xml_file)
157
+ extract_uid(xml_file, table_to_map) do |data|
158
+ print_out(DcmDict::Encoder::DataToCode.uid_data_to_code(data, 6))
159
+ print_out("\r\n")
160
+ trace('.')
161
+ end
162
+ end
163
+ end
164
+ print_out(DcmDict::Encoder::DataToCode.uid_footer)
165
+ end
166
+
167
+ def print_out(string)
168
+ $stdout.print(string)
169
+ end
170
+
171
+ def trace(msg)
172
+ $stderr.print(msg)
173
+ end
174
+
175
+ end
176
+
177
+ STDERR << LICENSE_TEXT
178
+ STDERR << "\nAny key to continue or Ctrl-C to break.\n"
179
+ STDIN.getc
180
+
181
+ if (DcmDict::XML.nokogiri_enable?)
182
+ STDERR << "Parsing XML data with Nokogiri.\n\n"
183
+ else
184
+ STDERR << "Parsing XML data with REXML.\n\n"
185
+ end
186
+
187
+ case ARGV[0]
188
+ when "tag"
189
+ DcmDictConverter.new.print_out_tag
190
+ when "uid"
191
+ DcmDictConverter.new.print_out_uid
192
+ else
193
+ STDERR << "\nwrong option: use 'tag' or 'uid' (ie dcm_dict_converter.rb tag > uid_values.rb)\n"
194
+ end