dicom 0.6 → 0.6.1
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.
- data/CHANGELOG +11 -0
- data/DOCUMENTATION +214 -214
- data/lib/DClient.rb +18 -14
- data/lib/DLibrary.rb +32 -32
- data/lib/DObject.rb +40 -39
- data/lib/DRead.rb +0 -0
- data/lib/DServer.rb +0 -0
- data/lib/DWrite.rb +15 -15
- data/lib/Link.rb +0 -0
- data/lib/Stream.rb +6 -3
- data/lib/dicom.rb +0 -0
- data/lib/ruby_extensions.rb +0 -0
- metadata +3 -3
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
= 0.6.1
|
|
2
|
+
|
|
3
|
+
=== 23rd August, 2009
|
|
4
|
+
|
|
5
|
+
* Fixed a bug (introduced in version 0.6) where the creation of new data elements caused an error.
|
|
6
|
+
* Fixed a bug (introduced in version 0.6) where compressed pixel data were no longer detected correctly.
|
|
7
|
+
* Fixed a bug where writing a DICOM file with no path prefix failed.
|
|
8
|
+
* Fixed a bug where creating a new data element in a DICOM file with tag hierarchies gave an invalid DICOM file.
|
|
9
|
+
* Fixed a bug where retrieving a RMagick image from DICOM files containing two sets of image data failed.
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
= 0.6
|
|
2
13
|
|
|
3
14
|
=== 13th August, 2009
|
data/DOCUMENTATION
CHANGED
|
@@ -16,240 +16,240 @@ CLASS DLibrary
|
|
|
16
16
|
|
|
17
17
|
PUBLIC CLASS METHODS
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
new()
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
Initialize a new Library (dictionary) object.
|
|
22
|
+
Useful if you want to make a script that reads hundreds or thousands of DICOM files,
|
|
23
|
+
because you can save time by loading the library one time at startup instead of
|
|
24
|
+
having the library being loaded for each DICOM file being read.
|
|
25
|
+
Example:
|
|
26
|
+
myLib = DICOM::DLibrary.new
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
CLASS DObject
|
|
30
30
|
|
|
31
31
|
PUBLIC CLASS METHODS
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
new(filename, options={})
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
Initialize a new DICOM object.
|
|
36
|
+
Example 1: (The simplest way)
|
|
37
|
+
require 'dicom'
|
|
38
|
+
obj = DICOM::DObject.new("myFile.dcm")
|
|
39
|
+
Example 2: (Using a pre-loaded library to speed up reading when reading multiple files)
|
|
40
|
+
obj = DICOM::DObject.new("myFile.dcm", :verbose => false, :lib => myLib)
|
|
41
|
+
Example 3: (Open an empty DICOM object)
|
|
42
|
+
obj = DICOM::DObject.new(nil)
|
|
43
43
|
|
|
44
44
|
ACCESSORS (read only)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
45
|
+
:read_success
|
|
46
|
+
A boolean that is true if DICOM object was read successfully, and false if not.
|
|
47
|
+
:write_success
|
|
48
|
+
A boolean that is true if DICOM object was written successfully, and false if not.
|
|
49
|
+
:errors
|
|
50
|
+
An array holding any error messages, warnings or notices that have been logged
|
|
51
|
+
during your interaction with DObject.
|
|
52
|
+
:modality
|
|
53
|
+
A string which holds the description of the modality of the DICOM object that has been read.
|
|
54
|
+
Example of use:
|
|
55
|
+
obj = DICOM::DObject.new("myFile.dcm")
|
|
56
|
+
if obj.read_success
|
|
57
|
+
puts obj.modality
|
|
58
|
+
end
|
|
59
|
+
The following accessors are the arrays that hold all the information gathered on the DICOM object.
|
|
60
|
+
As such, their length is equal to the number of tags in a DICOM object.
|
|
61
|
+
:names
|
|
62
|
+
:tags
|
|
63
|
+
:types
|
|
64
|
+
:lengths
|
|
65
|
+
:values
|
|
66
|
+
:raw
|
|
67
|
+
:levels
|
|
68
68
|
|
|
69
69
|
PUBLIC INSTANCE METHODS
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
71
|
+
children(element, options={})
|
|
72
|
+
Returns the positions of all data elements inside the hierarchy of a sequence or an item.
|
|
73
|
+
This is useful if you later want to get the position(s) of a certain element,
|
|
74
|
+
restricted to the positions inside the given sequence or item.
|
|
75
|
+
Element may be an array index, element name or element tag.
|
|
76
|
+
Example 1: (Return all element positions that is contained in the following sequence)
|
|
77
|
+
pos = obj.children("3006,0082")
|
|
78
|
+
Example 2: (Return all element positions that is contained only directly beneath the following sequence)
|
|
79
|
+
pos = obj.children("3006,0082", :next_only => true)
|
|
80
|
+
|
|
81
|
+
get_frames
|
|
82
|
+
Returns the number of frames present in the image data in the DICOM file.
|
|
83
|
+
|
|
84
|
+
get_image_magick
|
|
85
|
+
Returns an array of RMagick image objects, where the size of the array corresponds
|
|
86
|
+
with the number of frames in the image data.
|
|
87
|
+
To call this method the user needs to have loaded the RMagick bindings in advance (require 'RMagick').
|
|
88
|
+
Example (retrieve object and display first frame):
|
|
89
|
+
require 'RMagick'
|
|
90
|
+
data = dicom.get_image_magick()
|
|
91
|
+
data[0].display
|
|
92
|
+
|
|
93
|
+
get_image_narray
|
|
94
|
+
Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
|
|
95
|
+
To call this method the user needs to have loaded the NArray library in advance (require 'narray').
|
|
96
|
+
Example (retrieve object and display first frame):
|
|
97
|
+
require 'narray'
|
|
98
|
+
require 'nimage'
|
|
99
|
+
data = obj.get_image_narray()
|
|
100
|
+
NImage.show data[0,true,true]
|
|
101
|
+
|
|
102
|
+
get_image_pos
|
|
103
|
+
Returns the index(es) of the data element(s) that contain image data.
|
|
104
|
+
|
|
105
|
+
get_pos(string, options={})
|
|
106
|
+
Returns the index(es) of the data element(s) in the DICOM file that match
|
|
107
|
+
the supplied element tag or name.
|
|
108
|
+
Example 1: (Find all occurences of the specified tag in the object)
|
|
109
|
+
pos = obj.get_pos("3006,0080")
|
|
110
|
+
Example 2: (Find all occurences of the specified tag inside the specified sequence)
|
|
111
|
+
selection = obj.children("3006,0082")
|
|
112
|
+
pos = obj.get_pos("3006,0080", :array => selection)
|
|
113
|
+
Example 3: (Using the :partial argument to find position of all elements containing a specific string)
|
|
114
|
+
pos = obj.get_pos("0010", :partial => true)
|
|
115
|
+
pos = obj.get_pos("Name", :partial => true)
|
|
116
|
+
|
|
117
|
+
get_raw(element, options={})
|
|
118
|
+
Returns the raw data of the requested DICOM data element.
|
|
119
|
+
Element may be an array index, element name or element tag.
|
|
120
|
+
If you wish to return multiple data values of a tag that occurs several times in the file,
|
|
121
|
+
use the keyword :array => true .
|
|
122
|
+
Example: (Returns all data values in a array)
|
|
123
|
+
contour_data = obj.get_raw("3006,0050", :array => true)
|
|
124
|
+
|
|
125
|
+
get_value(element)
|
|
126
|
+
Returns the value (processed raw data) of the requested DICOM data element.
|
|
127
|
+
Element may be an array index, element name or element tag.
|
|
128
|
+
If you wish to return multiple values of a tag that occurs several times in the file,
|
|
129
|
+
use the keyword :array => true .
|
|
130
|
+
Example: (Returns all data values in a array)
|
|
131
|
+
contour_data = obj.get_value("3006,0050", :array => true)
|
|
132
|
+
|
|
133
|
+
image_to_file(file)
|
|
134
|
+
Dumps the pixel data of the DICOM object directly to the specified file.
|
|
135
|
+
This is useful if you wish to extract this data to process it with another program.
|
|
136
|
+
|
|
137
|
+
parents(element)
|
|
138
|
+
Returns the positions of all parents of this tag in the hierarchy.
|
|
139
|
+
This is useful if you want to know the position of the items or sequence tags that 'hold' your tag.
|
|
140
|
+
Element may be an array index, element name or element tag.
|
|
141
|
+
Example:
|
|
142
|
+
pos = obj.parents("300C,0006")
|
|
143
|
+
|
|
144
|
+
print(pos, options={})
|
|
145
|
+
Prints the information gathered on one or several/all tag(s) in the DICOM object:
|
|
146
|
+
(index, [hierarchy level,] label, name, type, length, value)
|
|
147
|
+
The method can print to both screen or to a text file. If print to file is chosen,
|
|
148
|
+
the text file will be put in the folder of the original DICOM file with a '.txt' extension.
|
|
149
|
+
The argument pos may be a number (array position), an array of numbers, or true.
|
|
150
|
+
Example 1: (Print all tags to file, with both tree visualization and level numbers)
|
|
151
|
+
obj.print(true, :levels => true, :tree => true, :file => true)
|
|
152
|
+
Example 2: (Print an array of tags to screen, no level or tree visualization)
|
|
153
|
+
obj.print([4,5,6])
|
|
154
|
+
|
|
155
|
+
print_all
|
|
156
|
+
Prints information of all tags stored in the DICOM object to the screen.
|
|
157
|
+
|
|
158
|
+
print_properties
|
|
159
|
+
Prints the key structural properties of the DICOM file to the screen.
|
|
160
|
+
|
|
161
|
+
remove(element)
|
|
162
|
+
Removes the specified data element from the DICOM object. You can use this method
|
|
163
|
+
if you are editing a DICOM object and wants to get rid of one or more elements.
|
|
164
|
+
Element may be an array index, element name or element tag.
|
|
165
|
+
|
|
166
|
+
set_value(value, element, options={})
|
|
167
|
+
This method can be used both to edit an existing data element, or to create
|
|
168
|
+
new data elements in your DICOM object.
|
|
169
|
+
Element may be an array index, element name or element tag.
|
|
170
|
+
Example 1: (Edit patient name)
|
|
171
|
+
obj.set_value("Anonymous", "0010,0010", :create => false)
|
|
172
|
+
Example 2: (Insert binary data for a specific tag)
|
|
173
|
+
obj.set_value(data, 52, :bin => true, :create => false)
|
|
174
|
+
|
|
175
|
+
set_image_magick(object)
|
|
176
|
+
Inserts a RMagick image object to the pixel data tag of your DICOM object.
|
|
177
|
+
|
|
178
|
+
set_image_file(file)
|
|
179
|
+
Inserts the binary content of a file to the Pixel Data tag in your DICOM object.
|
|
180
|
+
This can be useful if you have processed some image data using a custom program
|
|
181
|
+
and just wants to put that data back into a DICOM object.
|
|
182
|
+
|
|
183
|
+
write(file)
|
|
184
|
+
Writes the DICOM object to the specified file.
|
|
185
|
+
Example:
|
|
186
|
+
obj.write(myPath + "test_file.dcm")
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
CLASS Anonymizer
|
|
190
190
|
|
|
191
191
|
PUBLIC CLASS METHODS
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
new()
|
|
194
|
+
Initialize a new Anonymizer instance.
|
|
195
|
+
Example:
|
|
196
|
+
a = DICOM::Anonymizer.new
|
|
197
197
|
|
|
198
198
|
ACCESSORS (Read & write)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
199
|
+
:blank
|
|
200
|
+
A boolean that you can set if you want to all anonymization tags to be blank
|
|
201
|
+
instead of having some generic value.
|
|
202
|
+
:enumeration
|
|
203
|
+
A boolean that if set will make the script set enumerated values on anonymized tags,
|
|
204
|
+
such that you are able to separate the DICOM files of unique individuals after anonymization.
|
|
205
|
+
Example of fictious result:
|
|
206
|
+
"Joe Sixpack" => "Person1" and "Joe Schmoe" => "Person2"
|
|
207
|
+
:identity_file
|
|
208
|
+
If you request enumeration, you can specify an identity file which will enable you to reidentify
|
|
209
|
+
the anonymized DICOM files at a later stage. The relationship between original names and
|
|
210
|
+
enumerated values is stored in a text file which you can keep for yourself, while handing out
|
|
211
|
+
the anonymized DICOM files to a third party.
|
|
212
|
+
|
|
213
|
+
:write_path
|
|
214
|
+
You may set a different path for where the anonymized DICOM files will be stored. If this
|
|
215
|
+
value is not set, the Anonymizer script will overwrite the old DICOM files.
|
|
216
|
+
Example:
|
|
217
|
+
a.write_path = "C:/temp/"
|
|
218
218
|
|
|
219
219
|
PUBLIC INSTANCE METHODS
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
221
|
+
add_folder(path)
|
|
222
|
+
Adds a folder who's files (including all files in subfolders) will be anonymized.
|
|
223
|
+
Example:
|
|
224
|
+
a.add_folder("/home/dicom")
|
|
225
225
|
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
add_exception(path)
|
|
227
|
+
Adds a folder who's files (including all files in its subfolders) will be excluded from anonymization.
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
add_tag(tag, options={})
|
|
230
|
+
Adds a tag to the list of tags that will be anonymized. As options you can specify value to be used
|
|
231
|
+
and whether the tag should be included for enumeration if this feature has been activated.
|
|
232
|
+
Example:
|
|
233
|
+
a.add_tag("0010,0010, :value => "MrAnonymous", :enum => true)
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
change_enum(tag, status)
|
|
236
|
+
Sets enumeration status for a specific tag. Status = true means the selected tag will get
|
|
237
|
+
an enumerated value, false means it will not.
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
execute(verbose)
|
|
240
|
+
Executes the anonymization process. Run this method when you are finished choosing all your settings.
|
|
241
|
+
Verbose (=true/false) will apply to the read/update/write process that takes place in DObject, and not
|
|
242
|
+
the messages of the Anonymization script itself.
|
|
243
243
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
print
|
|
245
|
+
Prints the list of tags that have been selected for anonymization, along with the values
|
|
246
|
+
that the original tags will be replaced with. If enumeration is selected, this method will also
|
|
247
|
+
print which tags have been selected for enumeration.
|
|
248
248
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
remove_tag(tag)
|
|
250
|
+
Removes a tag from the list of tags that will be anonymized.
|
|
251
|
+
Example:
|
|
252
|
+
a.remove_tag("0010,0010")
|
|
253
253
|
|
|
254
254
|
|
|
255
255
|
CLASS DClient
|
|
@@ -289,7 +289,7 @@ ACCESSORS (Read only)
|
|
|
289
289
|
PUBLIC INSTANCE METHODS
|
|
290
290
|
|
|
291
291
|
get_image(path, options={})
|
|
292
|
-
Retrieve a DICOM image file from a server (C-GET-RQ) (this method is
|
|
292
|
+
Retrieve a DICOM image file from a server (C-GET-RQ) (this method is untested (might not work)).
|
|
293
293
|
Accepted options:
|
|
294
294
|
"0008,0018" (SOP Instance UID)
|
|
295
295
|
"0008,0052" (Query/Retrieve Level)
|
|
@@ -307,7 +307,7 @@ PUBLIC INSTANCE METHODS
|
|
|
307
307
|
"0020,000E" (Series Instance UID)
|
|
308
308
|
"0020,0013" (Instance Number)
|
|
309
309
|
Example:
|
|
310
|
-
find_images("0010,0020" => patient_id, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
310
|
+
result = node.find_images("0010,0020" => patient_id, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
311
311
|
|
|
312
312
|
find_patients(options={})
|
|
313
313
|
Query a server for patients that matches your specified criteria.
|
|
@@ -318,7 +318,7 @@ PUBLIC INSTANCE METHODS
|
|
|
318
318
|
"0010,0030" (Patient's Birth Date)
|
|
319
319
|
"0010,0040" (Patient's Sex)
|
|
320
320
|
Example:
|
|
321
|
-
find_patients("0010,0010" => "James*")
|
|
321
|
+
result = node.find_patients("0010,0010" => "James*")
|
|
322
322
|
|
|
323
323
|
find_series(options={})
|
|
324
324
|
Query a server for series that matches your specified criteria.
|
|
@@ -330,7 +330,7 @@ PUBLIC INSTANCE METHODS
|
|
|
330
330
|
"0020,000E" (Series Instance UID)
|
|
331
331
|
"0020,0011" (Series Number)
|
|
332
332
|
Example:
|
|
333
|
-
find_series("0010,0020" => patient_id, "0020,000D" => study_uid)
|
|
333
|
+
result = node.find_series("0010,0020" => patient_id, "0020,000D" => study_uid)
|
|
334
334
|
|
|
335
335
|
find_studies(options={})
|
|
336
336
|
Query a server for studies that matches your specified criteria.
|
|
@@ -349,7 +349,7 @@ PUBLIC INSTANCE METHODS
|
|
|
349
349
|
"0020,000D" (Study Instance UID)
|
|
350
350
|
"0020,0010" (Study ID)
|
|
351
351
|
Example:
|
|
352
|
-
find_studies("0008,0020" => study_date, "0010,000D" => patient_id)
|
|
352
|
+
result = node.find_studies("0008,0020" => study_date, "0010,000D" => patient_id)
|
|
353
353
|
|
|
354
354
|
move_image(destination, options={})
|
|
355
355
|
Move an image to a dicom node other than yourself.
|
|
@@ -359,7 +359,7 @@ PUBLIC INSTANCE METHODS
|
|
|
359
359
|
"0020,000D" (Study Instance UID)
|
|
360
360
|
"0020,000E" (Series Instance UID)
|
|
361
361
|
Example:
|
|
362
|
-
move_image("MYDICOM", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
362
|
+
node.move_image("MYDICOM", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
363
363
|
|
|
364
364
|
move_study(destination, options={})
|
|
365
365
|
Move an entire study to a dicom node other than yourself.
|
|
@@ -368,12 +368,12 @@ PUBLIC INSTANCE METHODS
|
|
|
368
368
|
"0010,0020" (Patient ID)
|
|
369
369
|
"0020,000D" (Study Instance UID)
|
|
370
370
|
Example:
|
|
371
|
-
move_study("MYDICOM", "0010,0020" => patient_id, "0020,000D" => study_uid)
|
|
371
|
+
node.move_study("MYDICOM", "0010,0020" => patient_id, "0020,000D" => study_uid)
|
|
372
372
|
|
|
373
373
|
send(file_path)
|
|
374
374
|
Send a DICOM file to a service class provider (SCP/PACS).
|
|
375
375
|
Example:
|
|
376
|
-
send("myFile.dcm")
|
|
376
|
+
node.send("myFile.dcm")
|
|
377
377
|
|
|
378
378
|
test
|
|
379
379
|
Tests a connection with your DICOM server by trying a simple association.
|
|
@@ -386,7 +386,7 @@ PUBLIC CLASS METHODS
|
|
|
386
386
|
new(port, options={})
|
|
387
387
|
Initialize a new DServer instance.
|
|
388
388
|
Example:
|
|
389
|
-
|
|
389
|
+
server = DICOM::DServer.new(104)
|
|
390
390
|
|
|
391
391
|
ACCESSORS (Read & write)
|
|
392
392
|
:host_ae
|
|
@@ -420,4 +420,4 @@ PUBLIC INSTANCE METHODS
|
|
|
420
420
|
Completely clears the list of syntaxes that the server instance will accept.
|
|
421
421
|
|
|
422
422
|
start_scp(path)
|
|
423
|
-
Launch the simple storage server (Storage Content Provider - SCP)
|
|
423
|
+
Launch the simple storage server (Storage Content Provider - SCP).
|
data/lib/DClient.rb
CHANGED
|
@@ -42,20 +42,6 @@ module DICOM
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
# Retrieve a dicom file from a service class provider (SCP/PACS).
|
|
46
|
-
# Example: get_image("c:/dicom/", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
47
|
-
def get_image(path, options={})
|
|
48
|
-
# Study Root Query/Retrieve Information Model - GET:
|
|
49
|
-
@abstract_syntax = "1.2.840.10008.5.1.4.1.2.2.3"
|
|
50
|
-
# Transfer the current options to the data_elements hash:
|
|
51
|
-
set_command_fragment_get
|
|
52
|
-
# Prepare data elements for this operation:
|
|
53
|
-
set_data_fragment_get_image
|
|
54
|
-
set_data_options(options)
|
|
55
|
-
perform_get(path)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
|
|
59
45
|
# Query a service class provider for images that match the specified criteria.
|
|
60
46
|
# Example: find_images("0010,0020" => "123456789", "0020,000D" => "1.2.840.1145.342", "0020,000E" => "1.3.6.1.4.1.2452.6.687844") # (Patient ID, Study Instance UID & Series Instance UID)
|
|
61
47
|
def find_images(options={})
|
|
@@ -65,6 +51,7 @@ module DICOM
|
|
|
65
51
|
set_data_fragment_find_images
|
|
66
52
|
set_data_options(options)
|
|
67
53
|
perform_find
|
|
54
|
+
return @data_results
|
|
68
55
|
end
|
|
69
56
|
|
|
70
57
|
|
|
@@ -77,6 +64,7 @@ module DICOM
|
|
|
77
64
|
set_data_fragment_find_patients
|
|
78
65
|
set_data_options(options)
|
|
79
66
|
perform_find
|
|
67
|
+
return @data_results
|
|
80
68
|
end
|
|
81
69
|
|
|
82
70
|
|
|
@@ -89,6 +77,7 @@ module DICOM
|
|
|
89
77
|
set_data_fragment_find_series
|
|
90
78
|
set_data_options(options)
|
|
91
79
|
perform_find
|
|
80
|
+
return @data_results
|
|
92
81
|
end
|
|
93
82
|
|
|
94
83
|
|
|
@@ -101,6 +90,21 @@ module DICOM
|
|
|
101
90
|
set_data_fragment_find_studies
|
|
102
91
|
set_data_options(options)
|
|
103
92
|
perform_find
|
|
93
|
+
return @data_results
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
# Retrieve a dicom file from a service class provider (SCP/PACS).
|
|
98
|
+
# Example: get_image("c:/dicom/", "0008,0018" => sop_uid, "0020,000D" => study_uid, "0020,000E" => series_uid)
|
|
99
|
+
def get_image(path, options={})
|
|
100
|
+
# Study Root Query/Retrieve Information Model - GET:
|
|
101
|
+
@abstract_syntax = "1.2.840.10008.5.1.4.1.2.2.3"
|
|
102
|
+
# Transfer the current options to the data_elements hash:
|
|
103
|
+
set_command_fragment_get
|
|
104
|
+
# Prepare data elements for this operation:
|
|
105
|
+
set_data_fragment_get_image
|
|
106
|
+
set_data_options(options)
|
|
107
|
+
perform_get(path)
|
|
104
108
|
end
|
|
105
109
|
|
|
106
110
|
|
data/lib/DLibrary.rb
CHANGED
|
@@ -26,6 +26,36 @@ module DICOM
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
# Checks whether a given string is a valid transfer syntax or not.
|
|
30
|
+
def check_ts_validity(uid)
|
|
31
|
+
result = false
|
|
32
|
+
value = @uid[uid.rstrip]
|
|
33
|
+
if value != nil
|
|
34
|
+
if value[1] == "Transfer Syntax"
|
|
35
|
+
# Proved valid:
|
|
36
|
+
result = true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
return result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Checks if the supplied transfer syntax indicates the presence of pixel compression or not.
|
|
44
|
+
def get_compression(uid)
|
|
45
|
+
result = false
|
|
46
|
+
if uid
|
|
47
|
+
value = @uid[uid.rstrip]
|
|
48
|
+
if value != nil
|
|
49
|
+
if value[1] == "Transfer Syntax" and not value[0].include?("Endian")
|
|
50
|
+
# It seems we have compression:
|
|
51
|
+
result = true
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
return result
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
29
59
|
# Returns data element name and value representation from the dictionary if the data element
|
|
30
60
|
# is recognized, else it returns "Unknown Name" and "UN".
|
|
31
61
|
def get_name_vr(tag)
|
|
@@ -91,20 +121,6 @@ module DICOM
|
|
|
91
121
|
end
|
|
92
122
|
|
|
93
123
|
|
|
94
|
-
# Checks whether a given string is a valid transfer syntax or not.
|
|
95
|
-
def check_ts_validity(uid)
|
|
96
|
-
result = false
|
|
97
|
-
value = @uid[uid.rstrip]
|
|
98
|
-
if value != nil
|
|
99
|
-
if value[1] == "Transfer Syntax"
|
|
100
|
-
# Proved valid:
|
|
101
|
-
result = true
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
return result
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
|
|
108
124
|
# Returns the name/description corresponding to a given UID.
|
|
109
125
|
def get_uid(uid)
|
|
110
126
|
value = @uid[uid.rstrip]
|
|
@@ -118,22 +134,6 @@ module DICOM
|
|
|
118
134
|
end
|
|
119
135
|
|
|
120
136
|
|
|
121
|
-
# Checks if the supplied transfer syntax indicates the presence of pixel compression or not.
|
|
122
|
-
def get_compression(uid)
|
|
123
|
-
result = false
|
|
124
|
-
if uid
|
|
125
|
-
value = @uid[uid.rstrip]
|
|
126
|
-
if value != nil
|
|
127
|
-
if value[1] == "Transfer Syntax" and not value[0].include?("Endian")
|
|
128
|
-
# It seems we have compression:
|
|
129
|
-
res = true
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
return result
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
|
|
137
137
|
# Checks the Transfer Syntax UID and return the encoding settings associated with this value.
|
|
138
138
|
def process_transfer_syntax(value)
|
|
139
139
|
valid = check_ts_validity(value)
|
|
@@ -160,8 +160,8 @@ module DICOM
|
|
|
160
160
|
# For everything else, assume compressed pixel data, with Explicit VR, Little Endian:
|
|
161
161
|
explicit = true
|
|
162
162
|
endian = false
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
end
|
|
164
|
+
return [valid, explicit, endian]
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
|
data/lib/DObject.rb
CHANGED
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
# -Support for color image data to get_image_narray and get_image_magick.
|
|
25
25
|
# -Complete support for Big endian (basic support is already featured).
|
|
26
26
|
# -Complete support for multiple frame image data to NArray and RMagick objects (partial support already featured).
|
|
27
|
-
# -
|
|
27
|
+
# -Make the image handling more intelligent with respect to interpreting data elements that hold information on the image and its properties.
|
|
28
28
|
|
|
29
29
|
module DICOM
|
|
30
30
|
|
|
31
|
-
# Class for
|
|
31
|
+
# Class for interacting with the DICOM object.
|
|
32
32
|
class DObject
|
|
33
33
|
|
|
34
34
|
attr_reader :read_success, :write_success, :modality, :errors, :segments,
|
|
@@ -172,9 +172,9 @@ module DICOM
|
|
|
172
172
|
add_msg("Error: Method read_image_magick does not have enough data available to build an image object.")
|
|
173
173
|
return false
|
|
174
174
|
end
|
|
175
|
-
|
|
175
|
+
unless @compression
|
|
176
176
|
# Non-compressed, just return the array contained on the particular element:
|
|
177
|
-
image_data=get_pixels(pos)
|
|
177
|
+
image_data = get_pixels(pos)
|
|
178
178
|
image = Magick::Image.new(columns,rows)
|
|
179
179
|
image.import_pixels(0, 0, columns, rows, "I", image_data)
|
|
180
180
|
return image
|
|
@@ -192,7 +192,7 @@ module DICOM
|
|
|
192
192
|
|
|
193
193
|
|
|
194
194
|
# Returns a 3d NArray object where the array dimensions are related to [frames, columns, rows].
|
|
195
|
-
|
|
195
|
+
# To call this method the user needs to have performed " require 'narray' " in advance.
|
|
196
196
|
def get_image_narray
|
|
197
197
|
# Does pixel data exist at all in the DICOM object?
|
|
198
198
|
if @compression == nil
|
|
@@ -256,48 +256,46 @@ module DICOM
|
|
|
256
256
|
end # of get_image_narray
|
|
257
257
|
|
|
258
258
|
|
|
259
|
-
# Returns an array of RMagick image objects, where the size of the array corresponds
|
|
260
|
-
|
|
259
|
+
# Returns an array of RMagick image objects, where the size of the array corresponds to the number of frames in the image data.
|
|
260
|
+
# To call this method the user needs to have loaded the ImageMagick library in advance (require 'RMagick').
|
|
261
261
|
def get_image_magick
|
|
262
262
|
# Does pixel data exist at all in the DICOM object?
|
|
263
263
|
if @compression == nil
|
|
264
|
-
add_msg("It seems pixel data is not present in this DICOM object:
|
|
264
|
+
add_msg("It seems pixel data is not present in this DICOM object: Returning false.")
|
|
265
265
|
return false
|
|
266
266
|
end
|
|
267
267
|
# No support yet for color pixel data:
|
|
268
268
|
if @color
|
|
269
|
-
add_msg("Warning: Unpacking color pixel data is not supported yet for this method:
|
|
269
|
+
add_msg("Warning: Unpacking color pixel data is not supported yet for this method: Aborting.")
|
|
270
270
|
return false
|
|
271
271
|
end
|
|
272
272
|
# Gather information about the dimensions of the image data:
|
|
273
|
-
rows = get_value("0028,0010")
|
|
274
|
-
columns = get_value("0028,0011")
|
|
273
|
+
rows = get_value("0028,0010", :array => true)
|
|
274
|
+
columns = get_value("0028,0011", :array => true)
|
|
275
|
+
rows = [rows] unless rows.is_a?(Array)
|
|
276
|
+
columns = [columns] unless columns.is_a?(Array)
|
|
275
277
|
frames = get_frames
|
|
276
278
|
image_pos = get_image_pos
|
|
277
279
|
# Array that will hold the RMagick image objects, one image object for each frame:
|
|
278
280
|
image_arr = Array.new(frames)
|
|
281
|
+
# A hack for the special case (some MR files), where two images are stored (one is a smaller thumbnail image):
|
|
282
|
+
if image_pos.length > 1 and columns.length > 1
|
|
283
|
+
image_pos = [image_pos.last]
|
|
284
|
+
columns = [columns[0]]
|
|
285
|
+
rows = [rows[0]]
|
|
286
|
+
end
|
|
279
287
|
# Handling of image data will depend on whether we have one or more frames,
|
|
280
288
|
if image_pos.size == 1
|
|
281
|
-
# All of the image data is located in one element:
|
|
282
|
-
#image_data = get_image_data(image_pos[0])
|
|
283
|
-
#(0..frames-1).each do |i|
|
|
284
|
-
# image = Magick::Image.new(columns,rows)
|
|
285
|
-
# image.import_pixels(0, 0, columns, rows, "I", image_data)
|
|
286
|
-
# image_arr[i] = image
|
|
287
|
-
#end
|
|
289
|
+
# All of the image data is located in one data element:
|
|
288
290
|
if frames > 1
|
|
289
291
|
add_msg("Unfortunately, this method only supports reading the first image frame as of now.")
|
|
290
292
|
end
|
|
291
|
-
image = read_image_magick(image_pos[0], columns, rows)
|
|
293
|
+
image = read_image_magick(image_pos[0], columns[0], rows[0])
|
|
292
294
|
image_arr[0] = image
|
|
293
|
-
#image_arr[i] = image
|
|
294
295
|
else
|
|
295
296
|
# Image data is encapsulated in items:
|
|
296
297
|
(0..frames-1).each do |i|
|
|
297
|
-
|
|
298
|
-
#image = Magick::Image.new(columns,rows)
|
|
299
|
-
#image.import_pixels(0, 0, columns, rows, "I", image_data)
|
|
300
|
-
image = read_image_magick(image_pos[i], columns, rows)
|
|
298
|
+
image = read_image_magick(image_pos[i], columns[0], rows[0])
|
|
301
299
|
image_arr[i] = image
|
|
302
300
|
end
|
|
303
301
|
end
|
|
@@ -307,11 +305,9 @@ module DICOM
|
|
|
307
305
|
|
|
308
306
|
# Returns the number of frames present in the image data in the DICOM file.
|
|
309
307
|
def get_frames
|
|
310
|
-
frames = get_value("0028,0008")
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
frames = 1
|
|
314
|
-
end
|
|
308
|
+
frames = get_value("0028,0008", :silent => true)
|
|
309
|
+
# If the DICOM object does not specify the number of frames explicitly, assume 1 image frame:
|
|
310
|
+
frames = 1 unless frames
|
|
315
311
|
return frames.to_i
|
|
316
312
|
end
|
|
317
313
|
|
|
@@ -320,10 +316,11 @@ module DICOM
|
|
|
320
316
|
def get_pixels(pos)
|
|
321
317
|
pixels = false
|
|
322
318
|
# We need to know what kind of bith depth the pixel data is saved with:
|
|
323
|
-
bit_depth = get_value("0028,0100")
|
|
324
|
-
|
|
319
|
+
bit_depth = get_value("0028,0100", :array => true)
|
|
320
|
+
unless bit_depth == false
|
|
325
321
|
# Load the binary pixel data to the Stream instance:
|
|
326
322
|
@stream.set_string(get_raw(pos))
|
|
323
|
+
bit_depth = bit_depth.first if bit_depth.is_a?(Array)
|
|
327
324
|
# Number of bytes used per pixel will determine how to unpack this:
|
|
328
325
|
case bit_depth
|
|
329
326
|
when 8
|
|
@@ -774,7 +771,8 @@ module DICOM
|
|
|
774
771
|
compression = "No"
|
|
775
772
|
end
|
|
776
773
|
# Bits per pixel (allocated):
|
|
777
|
-
bits = get_value("0028,0100")
|
|
774
|
+
bits = get_value("0028,0100", :array => true)
|
|
775
|
+
bits = bits[0].to_s if bits
|
|
778
776
|
# Print the file properties:
|
|
779
777
|
puts "Key properties of DICOM object:"
|
|
780
778
|
puts "-------------------------------"
|
|
@@ -890,7 +888,7 @@ module DICOM
|
|
|
890
888
|
add_msg("Warning: Method set_value could not create data element, either because data element name was not recognized in the library, or data element tag is invalid (Expected format of tags is 'GGGG,EEEE').")
|
|
891
889
|
else
|
|
892
890
|
# As we wish to create a new data element, we need to find out where to insert it in the element arrays:
|
|
893
|
-
# We will do this by finding the
|
|
891
|
+
# We will do this by finding the array position of the last element that will (alphabetically/numerically) stay in front of this element.
|
|
894
892
|
if @tags.size > 0
|
|
895
893
|
# Search the array:
|
|
896
894
|
index = -1
|
|
@@ -898,7 +896,7 @@ module DICOM
|
|
|
898
896
|
while quit != true do
|
|
899
897
|
if index+1 >= @tags.length # We have reached end of array.
|
|
900
898
|
quit = true
|
|
901
|
-
elsif tag < @tags[index+1] # We are past the correct position.
|
|
899
|
+
elsif tag < @tags[index+1] and @levels[index+1] == 0 # We are past the correct position (only match against top level tags).
|
|
902
900
|
quit = true
|
|
903
901
|
else # Increase index in anticipation of a 'hit'.
|
|
904
902
|
index += 1
|
|
@@ -1005,19 +1003,21 @@ module DICOM
|
|
|
1005
1003
|
end # of create_element
|
|
1006
1004
|
|
|
1007
1005
|
|
|
1008
|
-
# Encodes a value to binary (used for inserting values
|
|
1006
|
+
# Encodes a value to binary (used for inserting values into a DICOM object).
|
|
1009
1007
|
def encode(value, vr)
|
|
1010
|
-
# Our value needs to be inside an array to be encoded:
|
|
1011
|
-
value = [value] if not value.is_a?(Array)
|
|
1012
1008
|
# VR will decide how to encode this value:
|
|
1013
1009
|
case vr
|
|
1014
1010
|
when "AT" # (Data element tag: Assume it has the format "GGGG,EEEE"
|
|
1015
|
-
|
|
1011
|
+
if value.is_a_tag?
|
|
1012
|
+
bin = @stream.encode_tag(value)
|
|
1013
|
+
else
|
|
1014
|
+
add_msg("Invalid tag format (#{value}). Expected format: 'GGGG,EEEE'")
|
|
1015
|
+
end
|
|
1016
1016
|
# We have a number of VRs that are encoded as string:
|
|
1017
1017
|
when 'AE','AS','CS','DA','DS','DT','IS','LO','LT','PN','SH','ST','TM','UI','UT'
|
|
1018
1018
|
# In case we are dealing with a number string element, the supplied value might be a number
|
|
1019
1019
|
# instead of a string, and as such, we convert to string just to make sure this will work nicely:
|
|
1020
|
-
value
|
|
1020
|
+
value = value.to_s
|
|
1021
1021
|
bin = @stream.encode_value(value, "STR")
|
|
1022
1022
|
# Image related value representations:
|
|
1023
1023
|
when "OW"
|
|
@@ -1049,6 +1049,7 @@ module DICOM
|
|
|
1049
1049
|
return bin
|
|
1050
1050
|
end # of encode
|
|
1051
1051
|
|
|
1052
|
+
|
|
1052
1053
|
# Modifies existing data element:
|
|
1053
1054
|
def modify_element(value, pos, options={})
|
|
1054
1055
|
bin_only = options[:bin]
|
data/lib/DRead.rb
CHANGED
|
File without changes
|
data/lib/DServer.rb
CHANGED
|
File without changes
|
data/lib/DWrite.rb
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
# Please contact the author if you discover any issues with file creation.
|
|
11
11
|
|
|
12
12
|
module DICOM
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
# Class for writing the data from a DObject to a valid DICOM file.
|
|
14
15
|
class DWrite
|
|
15
16
|
|
|
16
17
|
attr_writer :tags, :types, :lengths, :raw, :rest_endian, :rest_explicit
|
|
@@ -309,7 +310,8 @@ module DICOM
|
|
|
309
310
|
end
|
|
310
311
|
|
|
311
312
|
|
|
312
|
-
# Tests if the file is writable
|
|
313
|
+
# Tests if the file/path is writable, creates any folders
|
|
314
|
+
# if necessary, and opens the file for writing.
|
|
313
315
|
def open_file(file)
|
|
314
316
|
# Two cases: File already exists or it does not.
|
|
315
317
|
# Check if file exists:
|
|
@@ -323,22 +325,20 @@ module DICOM
|
|
|
323
325
|
end
|
|
324
326
|
else
|
|
325
327
|
# File does not exist.
|
|
326
|
-
# Check if this file's path contains a
|
|
327
|
-
|
|
328
|
-
if
|
|
328
|
+
# Check if this file's path contains a folder that does not exist, and therefore needs to be created:
|
|
329
|
+
folders = file.split(File::SEPARATOR)
|
|
330
|
+
if folders.length > 1
|
|
329
331
|
# Remove last element (which should be the file string):
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
FileUtils.mkdir_p path
|
|
338
|
-
end
|
|
332
|
+
folders.pop
|
|
333
|
+
path = folders.join(File::SEPARATOR)
|
|
334
|
+
# Check if this path exists:
|
|
335
|
+
unless File.directory?(path)
|
|
336
|
+
# We need to create (parts of) this path:
|
|
337
|
+
require 'fileutils'
|
|
338
|
+
FileUtils.mkdir_p path
|
|
339
339
|
end
|
|
340
340
|
end
|
|
341
|
-
# The path to this non-existing file should now be prepared, and we
|
|
341
|
+
# The path to this non-existing file should now be prepared, and we proceed to creating the file:
|
|
342
342
|
@file = File.new(file, "wb")
|
|
343
343
|
end
|
|
344
344
|
end
|
data/lib/Link.rb
CHANGED
|
File without changes
|
data/lib/Stream.rb
CHANGED
|
@@ -96,14 +96,16 @@ module DICOM
|
|
|
96
96
|
|
|
97
97
|
# Encodes content (string, number, array of numbers) and returns the binary string.
|
|
98
98
|
def encode(value, type)
|
|
99
|
-
|
|
99
|
+
value = [value] unless value.is_a?(Array)
|
|
100
|
+
return value.pack(vr_to_str(type))
|
|
100
101
|
end
|
|
101
102
|
|
|
102
103
|
|
|
103
104
|
# Encodes content (string, number, array of numbers) to a binary string and pastes it to
|
|
104
105
|
# the beginning of the @string variable of this instance.
|
|
105
106
|
def encode_first(value, type)
|
|
106
|
-
|
|
107
|
+
value = [value] unless value.is_a?(Array)
|
|
108
|
+
bin = value.pack(vr_to_str(type))
|
|
107
109
|
@string = bin + @string
|
|
108
110
|
end
|
|
109
111
|
|
|
@@ -111,7 +113,8 @@ module DICOM
|
|
|
111
113
|
# Encodes content (string, number, array of numbers) to a binary string and pastes it to
|
|
112
114
|
# the end of the @string variable of this instance.
|
|
113
115
|
def encode_last(value, type)
|
|
114
|
-
|
|
116
|
+
value = [value] unless value.is_a?(Array)
|
|
117
|
+
bin = value.pack(vr_to_str(type))
|
|
115
118
|
@string = @string + bin
|
|
116
119
|
end
|
|
117
120
|
|
data/lib/dicom.rb
CHANGED
|
File without changes
|
data/lib/ruby_extensions.rb
CHANGED
|
File without changes
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dicom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christoffer Lervag
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-08-
|
|
12
|
+
date: 2009-08-23 00:00:00 +02:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|
|
@@ -65,6 +65,6 @@ rubyforge_project: dicom
|
|
|
65
65
|
rubygems_version: 1.3.3
|
|
66
66
|
signing_key:
|
|
67
67
|
specification_version: 3
|
|
68
|
-
summary: Library for handling DICOM files and network communication.
|
|
68
|
+
summary: Library for handling DICOM files and DICOM network communication.
|
|
69
69
|
test_files: []
|
|
70
70
|
|