dcm_dict 0.1.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.
- checksums.yaml +7 -0
- data/COPYING +674 -0
- data/LICENSE +22 -0
- data/README.md +296 -0
- data/Rakefile +36 -0
- data/bin/dcm_dict_converter.rb +194 -0
- data/lib/dcm_dict.rb +46 -0
- data/lib/dcm_dict/dictionary/base_dictionary.rb +47 -0
- data/lib/dcm_dict/dictionary/base_record.rb +62 -0
- data/lib/dcm_dict/dictionary/data_element_dictionary.rb +117 -0
- data/lib/dcm_dict/dictionary/data_element_record.rb +93 -0
- data/lib/dcm_dict/dictionary/uid_dictionary.rb +82 -0
- data/lib/dcm_dict/dictionary/uid_record.rb +48 -0
- data/lib/dcm_dict/encoder/data_to_code.rb +79 -0
- data/lib/dcm_dict/error/dictionary_error.rb +30 -0
- data/lib/dcm_dict/ext/object_extension.rb +38 -0
- data/lib/dcm_dict/refine/array_refine.rb +34 -0
- data/lib/dcm_dict/refine/data_element_refine.rb +37 -0
- data/lib/dcm_dict/refine/internal/array_refine_internal.rb +97 -0
- data/lib/dcm_dict/refine/internal/hash_refine_internal.rb +71 -0
- data/lib/dcm_dict/refine/internal/string_refine_internal.rb +119 -0
- data/lib/dcm_dict/refine/string_refine.rb +35 -0
- data/lib/dcm_dict/refine/symbol_refine.rb +34 -0
- data/lib/dcm_dict/refine/uid_refine.rb +36 -0
- data/lib/dcm_dict/rubies/rb_ext.rb +32 -0
- data/lib/dcm_dict/source_data/data_elements_data.rb +3937 -0
- data/lib/dcm_dict/source_data/detached_data.rb +67 -0
- data/lib/dcm_dict/source_data/uid_values_data.rb +382 -0
- data/lib/dcm_dict/version.rb +27 -0
- data/lib/dcm_dict/xml/constant.rb +38 -0
- data/lib/dcm_dict/xml/field_data.rb +47 -0
- data/lib/dcm_dict/xml/nokogiri_tool.rb +108 -0
- data/lib/dcm_dict/xml/rexml_tool.rb +105 -0
- data/lib/dcm_dict/xml/tag_field_data.rb +96 -0
- data/lib/dcm_dict/xml/uid_field_data.rb +49 -0
- data/lib/dcm_dict/xml/xml_tool.rb +47 -0
- data/spec/data_element_sample_spec_helper.rb +110 -0
- data/spec/data_element_shared_example_spec_helper.rb +57 -0
- data/spec/dcm_dict/dictionary/data_element_dictionary_spec.rb +75 -0
- data/spec/dcm_dict/dictionary/data_element_record_spec.rb +117 -0
- data/spec/dcm_dict/dictionary/uid_dictionary_spec.rb +60 -0
- data/spec/dcm_dict/dictionary/uid_record_spec.rb +53 -0
- data/spec/dcm_dict/encoder/data_to_code_spec.rb +109 -0
- data/spec/dcm_dict/ext/object_extension_spec.rb +53 -0
- data/spec/dcm_dict/refine/array_refine_spec.rb +61 -0
- data/spec/dcm_dict/refine/internal/array_refine_internal_spec.rb +98 -0
- data/spec/dcm_dict/refine/internal/hash_refine_internal_spec.rb +64 -0
- data/spec/dcm_dict/refine/internal/string_refine_internal_spec.rb +214 -0
- data/spec/dcm_dict/refine/string_refine_spec.rb +87 -0
- data/spec/dcm_dict/refine/symbol_refine_spec.rb +41 -0
- data/spec/dcm_dict/rubies/rb_ext_spec.rb +46 -0
- data/spec/dcm_dict/source_data/data_elements_data_spec.rb +40 -0
- data/spec/dcm_dict/source_data/detached_data_spec.rb +55 -0
- data/spec/dcm_dict/source_data/uid_values_data_spec.rb +37 -0
- data/spec/dcm_dict/version_spec.rb +30 -0
- data/spec/dcm_dict/xml/tag_field_data_spec.rb +62 -0
- data/spec/dcm_dict/xml/uid_field_data_spec.rb +60 -0
- data/spec/dictionary_shared_example_spec_helper.rb +118 -0
- data/spec/refine_shared_example_spec_helper.rb +54 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/xml_sample_spec_helper.rb +533 -0
- metadata +212 -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 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.
|
data/README.md
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# What's *DcmDict*
|
2
|
+
**DcmDict** is a Ruby gem (*dcm\_dict*) to handle in a simple way the Data defined within the [DICOM(r)][1] Standard such as DICOM Data Elements or DICOM Unique Identifiers.
|
3
|
+
|
4
|
+
# Why *DcmDict*
|
5
|
+
With the latest releases in this year (2014) DICOM documents are available in different format including one particularly interesting, the *DocBook* XML version.
|
6
|
+
As written by D. Clunie on [its web site][2]:
|
7
|
+
> "... other formats (such as DocBook, HTML, Word and ODT) are also made available for the convenience of implementors who may need to extract machine-readable content, ..."
|
8
|
+
|
9
|
+
This is great news for anyone involved in the study of the standard !
|
10
|
+
|
11
|
+
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.
|
12
|
+
|
13
|
+
# *DcmDict* features
|
14
|
+
The library involve *String*, *Array* and *Symbol* class as *refinements* to access to DICOM information. In this way is possible to *play* with the 'Patient's Birth Date' tag defined as (0010,0030) by:
|
15
|
+
```ruby
|
16
|
+
> "(0010,0030)".tag_name
|
17
|
+
=> "Patient's Birth Date"
|
18
|
+
> 'PatientBirthDate'.tag_vr
|
19
|
+
=> [:DA]
|
20
|
+
> "Patient's Birth Date".tag_vm
|
21
|
+
=> ["1"]
|
22
|
+
> :patient_birth_date.tag
|
23
|
+
=> [16, 48]
|
24
|
+
> [16,48].tag_key
|
25
|
+
=> "PatientBirthDate"
|
26
|
+
> [16, 48].tag_group
|
27
|
+
=> 16
|
28
|
+
> '00100030'.tag_element
|
29
|
+
=> 48
|
30
|
+
> :patient_birth_date.tag_group
|
31
|
+
=> 16
|
32
|
+
> "Patient's Birth Date".tag_element
|
33
|
+
=> 48
|
34
|
+
```
|
35
|
+
as well for UIDs
|
36
|
+
```ruby
|
37
|
+
> '1.2.840.10008.1.2'.uid_name
|
38
|
+
=> "Implicit VR Little Endian: Default Transfer Syntax for DICOM"
|
39
|
+
> '1.2.840.10008.1.2'.uid_type
|
40
|
+
=> :transfer_syntax
|
41
|
+
> "Implicit VR Little Endian: Default Transfer Syntax for DICOM".uid_value
|
42
|
+
=> "1.2.840.10008.1.2"
|
43
|
+
```
|
44
|
+
|
45
|
+
let see all features in detail:
|
46
|
+
|
47
|
+
## Library usage
|
48
|
+
The library involve **Ruby Refinements** so use it is simple, it is necessary to include the specific *using directive*:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
using DcmDict::Refine::StringRefine
|
52
|
+
```
|
53
|
+
for the String object,
|
54
|
+
```ruby
|
55
|
+
using DcmDict::Refine::ArrayRefine
|
56
|
+
```
|
57
|
+
for the Array object and
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
using DcmDict::Refine::SymbolRefine
|
61
|
+
```
|
62
|
+
for the Symbol object.
|
63
|
+
|
64
|
+
That's it.
|
65
|
+
|
66
|
+
**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* into the class you want to use as "keyword": there are two base modules *DcmDict::Refine::DataElementRefine* and *DcmDict::Refine::UidRefine*.
|
67
|
+
|
68
|
+
For example in the String class will have the code:
|
69
|
+
```ruby
|
70
|
+
class String
|
71
|
+
include DcmDict::Refine::DataElementRefine
|
72
|
+
include DcmDict::Refine::UidRefine
|
73
|
+
end
|
74
|
+
```
|
75
|
+
*The main way remains **Ruby Refinements***.
|
76
|
+
|
77
|
+
**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 through [refine gem][5] and add the required *bit_length* method to *Fixnum* class through [backports gem][6].
|
78
|
+
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.
|
79
|
+
|
80
|
+
## Data Element data in detail
|
81
|
+
Any Data Element features can be accessed from a *String*, *Array* or *Symbol* objects.
|
82
|
+
|
83
|
+
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.
|
84
|
+
|
85
|
+
The main methods supported are:
|
86
|
+
|
87
|
+
|Method | Note| Type||
|
88
|
+
|:------|:------------:|:---:|:---:|
|
89
|
+
|**tag** | tag as Array| Array of two Fixnum|(alias of *tag_ary*)|
|
90
|
+
|**tag_name** | name of tag| String|
|
91
|
+
|**tag_keyword** | keyword| String|
|
92
|
+
|**tag_key** | keyword| String|
|
93
|
+
|**tag_vr** | Value Representation| Array of Symbol|
|
94
|
+
|**tag_vm** | Value Multiplicity| Array of Symbol|
|
95
|
+
|**tag_ps** | tag as string (as standard doc)| String|
|
96
|
+
|**tag_ary** | tag as Array|Array of two Fixnum|
|
97
|
+
|**tag_sym** | tag as Symbol|Symbol|
|
98
|
+
|**tag_ndm** | tag as in Native DICOM Model|String|
|
99
|
+
|**tag_str** | tag as string (similar to tag_ps)|String|
|
100
|
+
|**tag_note** | tag note|String|
|
101
|
+
|**tag_multiple?** | is a multiple tag ? |boolean|
|
102
|
+
||useful for 'multi tag' attribute|
|
103
|
+
|
104
|
+
each data element is indexed by these fields:
|
105
|
+
|
106
|
+
|Field|Type|
|
107
|
+
|:----|:-----:|
|
108
|
+
|**tag_key** | String|
|
109
|
+
|**tag_ps** | String|
|
110
|
+
|**tag_ary** | Array|
|
111
|
+
|**tag_sym** | Symbol|
|
112
|
+
|**tag_ndm** | String|
|
113
|
+
|**tag_str** | String|
|
114
|
+
|**tag_name** | String|
|
115
|
+
|
116
|
+
Through these fields is possible to access to data element informations.
|
117
|
+
Consider the case of the tag (0010,1005) (*Patient's Birth Name*), the primary fields are:
|
118
|
+
**'(0010,1005)'**, **"Patient's Birth Name"**, **'PatientBirthName'**, **:patient_birth_name**, **'00101005'** and **[0x0010,0x1005]**
|
119
|
+
|
120
|
+
- 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'**
|
121
|
+
- As Array key you may use the numeric array **[0x0010,0x1005]**
|
122
|
+
- As Symbol key you may use **:patient_birth_name**
|
123
|
+
|
124
|
+
### example:
|
125
|
+
Consider the previous case of tag (0010,1005), the code:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
puts "Patient's Birth Name".tag_ps.inspect
|
129
|
+
puts [0x0010,0x1005].tag_name.inspect
|
130
|
+
puts '(0010,1005)'.tag_key.inspect
|
131
|
+
puts :patient_birth_name.tag_vr.inspect
|
132
|
+
puts 'PatientBirthName'.tag_vm.inspect
|
133
|
+
puts '00101005'.tag.inspect
|
134
|
+
puts '(0010,1005)'.tag_ary.inspect
|
135
|
+
puts '00101005'.tag_sym.inspect
|
136
|
+
puts 'PatientBirthName'.tag_ndm.inspect
|
137
|
+
puts "Patient's Birth Name".tag_str.inspect
|
138
|
+
puts [0x0010,0x1005].tag_note.inspect
|
139
|
+
puts [0x0010,0x1005].tag_group.inspect
|
140
|
+
puts :patient_birth_name.tag_element.inspect
|
141
|
+
```
|
142
|
+
|
143
|
+
will produce
|
144
|
+
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
"(0010,1005)"
|
148
|
+
"Patient's Birth Name"
|
149
|
+
"PatientBirthName"
|
150
|
+
[:PN]
|
151
|
+
["1"]
|
152
|
+
[16, 4101]
|
153
|
+
[16, 4101]
|
154
|
+
:patient_birth_name
|
155
|
+
"00101005"
|
156
|
+
"(0010,1005)"
|
157
|
+
""
|
158
|
+
16
|
159
|
+
4101
|
160
|
+
```
|
161
|
+
|
162
|
+
### Multiple Tag
|
163
|
+
The library also manage 'multiple tags' such as *(0020,31XX)* (*Source Image IDs*).
|
164
|
+
As an example for this data element the default tag in array form is [0x0020,0x3122] and all fields are expressed as:
|
165
|
+
|
166
|
+
|Method/field | Value|
|
167
|
+
|:------|:------------:|
|
168
|
+
|**tag** | [0x0020,0x3122]|
|
169
|
+
|**tag_name** | "Source Image IDs"|
|
170
|
+
|**tag_keyword** | 'SourceImageIDs'|
|
171
|
+
|**tag_key** | 'SourceImageIDs'|
|
172
|
+
|**tag_vr** | [:CS]|
|
173
|
+
|**tag_vm** | ["1-n"]|
|
174
|
+
|**tag_ps** | '(0020,31XX)'|
|
175
|
+
|**tag_ary** | [0x0020,0x3122]|
|
176
|
+
|**tag_sym** | :source_image_ids|
|
177
|
+
|**tag_ndm** | '00203122'
|
178
|
+
|**tag_str** | '(0020,3122)'|
|
179
|
+
|**tag_note** | 'RET'|
|
180
|
+
|**tag_multiple?** | true|
|
181
|
+
|
182
|
+
[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:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
> '(0020,31XX)'.tag_name
|
186
|
+
=> "Source Image IDs"
|
187
|
+
> '(0020,31XX)'.tag_ndm
|
188
|
+
=> "00203122"
|
189
|
+
> "SourceImageIDs".tag_ary
|
190
|
+
=> [32, 12578]
|
191
|
+
> '(0020,3178)'.tag_name
|
192
|
+
=> "Source Image IDs"
|
193
|
+
[0x0020,0x3146].tag_sym
|
194
|
+
=> :source_image_ids
|
195
|
+
> '00203120'.tag_key
|
196
|
+
=> "SourceImageIDs"
|
197
|
+
> [0x0020,0x3138].tag_vr
|
198
|
+
=> [:CS]
|
199
|
+
> '(0020,3144)'.tag_note
|
200
|
+
=> "RET"
|
201
|
+
```
|
202
|
+
and so on.
|
203
|
+
|
204
|
+
## UID data in detail
|
205
|
+
Any UID features can be accessed from a *String* object.
|
206
|
+
|
207
|
+
### UID Values
|
208
|
+
For these objects is possible to access to value, name and type values for any single uid.
|
209
|
+
Main methods supported are:
|
210
|
+
|
211
|
+
|Method | Note| Type||
|
212
|
+
|:------|:------------:|:---:|:---:|
|
213
|
+
|**uid** | value of uid| String|(alias of *uid_value*)|
|
214
|
+
|**uid_value** | value of uid| String|
|
215
|
+
|**uid_name** | name of uid| String|
|
216
|
+
|**uid_type** | type of uid| Symbol|
|
217
|
+
|
218
|
+
each uid is indexed by:
|
219
|
+
|
220
|
+
|Field|Type|
|
221
|
+
|:----|:-----|
|
222
|
+
|**uid_value** | String|
|
223
|
+
|**uid_name** | String|
|
224
|
+
|
225
|
+
From these fields is possible to access to all uid informations.
|
226
|
+
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"**.
|
227
|
+
- As String key you may use the standard value **'1.2.840.10008.1.1'** and the uid name **"Verification SOP Class"**
|
228
|
+
|
229
|
+
For this uid all fields are expressed as:
|
230
|
+
|
231
|
+
|Method/field | Value|
|
232
|
+
|:------|:------------:|
|
233
|
+
|**uid** | '1.2.840.10008.1.1'|
|
234
|
+
|**uid_value** | '1.2.840.10008.1.1'|
|
235
|
+
|**uid_name** | "Verification SOP Class"|
|
236
|
+
|**uid_type** | :sop_class|
|
237
|
+
|
238
|
+
### example:
|
239
|
+
```ruby
|
240
|
+
> "Verification SOP Class".uid_value
|
241
|
+
=> "1.2.840.10008.1.1"
|
242
|
+
> "1.2.840.10008.1.1".uid_type
|
243
|
+
=> :sop_class
|
244
|
+
> "1.2.840.10008.1.1".uid_name
|
245
|
+
=> "Verification SOP Class"
|
246
|
+
> "Verification SOP Class".uid
|
247
|
+
=> "1.2.840.10008.1.1"
|
248
|
+
```
|
249
|
+
|
250
|
+
## How data is extracted
|
251
|
+
The library also contains a script (*dcm_dict_converter.rb* into *bin* folder) able to download the xml documents and extracts the source data in a *Ruby compatible format*.
|
252
|
+
The script produces the conversion in the *stdout* so for example is possible to extract the Tag Values by:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
dcm_dict_converter.rb tag > /tmp/tag-dict.rb
|
256
|
+
```
|
257
|
+
|
258
|
+
Note: the script use the [Nokogiri][3] as XML parser if installed as gem, otherwise the standard *REXML*.
|
259
|
+
|
260
|
+
Check the file for other details.
|
261
|
+
|
262
|
+
## Install
|
263
|
+
|
264
|
+
$ gem install dcm_dict
|
265
|
+
|
266
|
+
*Note for Windows users*: may be that it is installed a previous version of Ruby 2.1, at the moment [RubyInstaller][7] does not provide the official release for this version. It is still possible to make it manually by clone/download the ['git' version of RubyInstaller][8] and execute the rake command ```rake ruby21``` (see RubyInstaller doc for details).
|
267
|
+
|
268
|
+
## What's next
|
269
|
+
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.
|
270
|
+
There are many possible *candidates* for inclusion in the *dictionary*, here are some *"ideas"*:
|
271
|
+
- Directory Record type data
|
272
|
+
- Well-known Frames of Reference UID Values
|
273
|
+
- Context Group UID Values
|
274
|
+
- Standard Color Palettes UID Values
|
275
|
+
- IOD definition data
|
276
|
+
- ...
|
277
|
+
|
278
|
+
## Contributing
|
279
|
+
TBD
|
280
|
+
|
281
|
+
## License
|
282
|
+
Copyright (C) 2014 Enrico Rivarola.
|
283
|
+
See the `LICENSE` and `COPYING` files for license details.
|
284
|
+
|
285
|
+
## Source Code
|
286
|
+
Main source code repository on github at [henrythebuilder/dcm_dict](https://github.com/henrythebuilder/dcm_dict)
|
287
|
+
|
288
|
+
|
289
|
+
[1]: http://medical.nema.org/dicom/ "DICOM Homepage"
|
290
|
+
[2]: http://www.dclunie.com/dicom-status/status.html "DICOM Standard Status"
|
291
|
+
[3]: http://nokogiri.org/ "Nokogiri"
|
292
|
+
[4]: http://rubini.us/ "Rubinius"
|
293
|
+
[5]: https://rubygems.org/gems/refine "Refine gem at RubyGems.org"
|
294
|
+
[6]: https://rubygems.org/gems/backports "Backports gem at RubyGems.org"
|
295
|
+
[7]: http://rubyinstaller.org/ "The easy way to install Ruby on Windows"
|
296
|
+
[8]: https://github.com/oneclick/rubyinstaller "RubyInstaller for Windows"
|
data/Rakefile
ADDED
@@ -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 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 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/2014a/source/docbook/part06/part06.xml"
|
58
|
+
Part7XmlUrl="http://dicom.nema.org/medical/dicom/2014a/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
|
+
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
|