dcm_dict 0.29.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +156 -0
- data/COPYING +674 -0
- data/LICENSE +22 -0
- data/README.md +327 -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 +135 -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 +4945 -0
- data/lib/dcm_dict/source_data/detached_data.rb +67 -0
- data/lib/dcm_dict/source_data/uid_values_data.rb +467 -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 +60 -0
- data/lib/dcm_dict/xml/xml_tool.rb +47 -0
- data/spec/data_element_sample_spec_helper.rb +203 -0
- data/spec/data_element_shared_example_spec_helper.rb +57 -0
- data/spec/dcm_dict/dictionary/data_element_dictionary_spec.rb +76 -0
- data/spec/dcm_dict/dictionary/data_element_record_spec.rb +138 -0
- data/spec/dcm_dict/dictionary/uid_dictionary_spec.rb +82 -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 +60 -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 +228 -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 +567 -0
- 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.
|
data/README.md
ADDED
@@ -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.">↩︎</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
|
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-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
|