dicom 0.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 +24 -0
- data/COPYING +674 -0
- data/DOCUMENTATION +66 -0
- data/README +57 -0
- data/lib/DObject.rb +439 -0
- data/lib/DRead.rb +1204 -0
- data/lib/dicom.rb +2 -0
- metadata +52 -0
data/lib/DRead.rb
ADDED
@@ -0,0 +1,1204 @@
|
|
1
|
+
module DICOM
|
2
|
+
# Class for reading the data from a DICOM file:
|
3
|
+
class DRead
|
4
|
+
|
5
|
+
# Initialize the DRead instance.
|
6
|
+
def initialize(file_name)
|
7
|
+
# Variables that hold data that will be returned to the person/procedure using this class:
|
8
|
+
# Arrays that will hold information from the DICOM file:
|
9
|
+
@names = Array.new()
|
10
|
+
@labels = Array.new()
|
11
|
+
@types = Array.new()
|
12
|
+
@lengths = Array.new()
|
13
|
+
@values = Array.new()
|
14
|
+
@raw = Array.new()
|
15
|
+
# Explicitness (explicit (true) by default):
|
16
|
+
@explicit = true
|
17
|
+
# Explicitness of the remaining groups after the first group:
|
18
|
+
@rest_explicit = true
|
19
|
+
# Variable to keep track of whether the current sequence being read have length specified or not:
|
20
|
+
@sq_length = false
|
21
|
+
# Variable to keep track of whether the image pixel data in this file are compressed or not, and if it exists at all:
|
22
|
+
@compression = false
|
23
|
+
# Pixel data is color or greyscale?
|
24
|
+
@color = false
|
25
|
+
# Default endianness of start of DICOM files is little endian:
|
26
|
+
@file_endian=false
|
27
|
+
|
28
|
+
# Variables used internally when reading the dicom file:
|
29
|
+
# If tag does not exist in the library it is unknown:
|
30
|
+
@unknown = false
|
31
|
+
# Does the particular tag contain any information?
|
32
|
+
@content = true
|
33
|
+
# Check endianness of the system (false if little endian):
|
34
|
+
@sys_endian=check_sys_endian()
|
35
|
+
# Endianness of the remaining groups after the first group:
|
36
|
+
@rest_endian=false
|
37
|
+
# Use a "relationship endian" variable to guide reading of file (true if they are equal):
|
38
|
+
if @sys_endian == @file_endian
|
39
|
+
@endian = true
|
40
|
+
else
|
41
|
+
@endian = false
|
42
|
+
end
|
43
|
+
|
44
|
+
# Open file for binary reading:
|
45
|
+
@file = File.new(file_name, "rb")
|
46
|
+
|
47
|
+
# Establish relationship between tag adress and name:
|
48
|
+
load_library()
|
49
|
+
|
50
|
+
# Read the initial header of the file:
|
51
|
+
header=check_header()
|
52
|
+
if header == false
|
53
|
+
@file.close()
|
54
|
+
@file = File.new(file_name, "rb")
|
55
|
+
end
|
56
|
+
|
57
|
+
# Initiate the process to read tags:
|
58
|
+
tag = true
|
59
|
+
temp_check=true
|
60
|
+
while tag != false and temp_check== true do
|
61
|
+
tag=process_tag()
|
62
|
+
# Store the tag information in arrays:
|
63
|
+
if tag != false and @content == true
|
64
|
+
@names+=[tag[0]]
|
65
|
+
@labels+=[tag[1]]
|
66
|
+
@types+=[tag[2]]
|
67
|
+
@lengths+=[tag[3]]
|
68
|
+
@values+=[tag[4]]
|
69
|
+
@raw+=[tag[5]]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
# Check the status of the pixel data:
|
73
|
+
check_pixel_status()
|
74
|
+
# Index of last element in tag arrays:
|
75
|
+
@lastIndex=@names.length-1
|
76
|
+
# Close the file as we are finished reading it:
|
77
|
+
@file.close()
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Returns the relevant information gathered from the read dicom procedure.
|
82
|
+
def return_data()
|
83
|
+
return [@names,@labels,@types,@lengths,@values,@raw,@compression,@color,@explicit, @file_endian]
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Checks the initial header of the DICOM file.
|
88
|
+
def check_header()
|
89
|
+
# According to the official DICOM standard, a DICOM file shall contain 128
|
90
|
+
# consequtive zero bytes followed by 4 bytes that spell the string 'DICM'.
|
91
|
+
# Apparently, some providers seems to skip this in their DICOM files.
|
92
|
+
# First 128 bytes should be zeroes:
|
93
|
+
bin1=@file.read(128)
|
94
|
+
str_header1=bin1.unpack('a' * 128).to_s
|
95
|
+
# Next 4 bytes should spell 'DICM':
|
96
|
+
bin2=@file.read(4)
|
97
|
+
str_header2=bin2.unpack('a' * 4).to_s
|
98
|
+
# If we dont have this expected header, we will still try to read it is a DICOM file.
|
99
|
+
if str_header2 != 'DICM' then
|
100
|
+
puts "Warning: The specified file does not contain the official DICOM header."
|
101
|
+
puts "Will try to read the file anyway, as some sources are known to skip the formal DICOM header."
|
102
|
+
# Some DICOM files skips group 2, which defines the structure of the DICOM file.
|
103
|
+
# This has only been observed in files that also skips the above part of the DICOM header.
|
104
|
+
# Check for skipped group 0002:
|
105
|
+
group_label=bin1.unpack('h4').to_s.reverse.upcase
|
106
|
+
if (group_label.include? "2")
|
107
|
+
#Assume the file starts with a group 0002 tag, as "normal".
|
108
|
+
# Assume a default transfer syntax: Implicit, Little Endian.
|
109
|
+
@explicit = false
|
110
|
+
@rest_explicit = false
|
111
|
+
@file_endian = false
|
112
|
+
@rest_endian = false
|
113
|
+
@compression = false
|
114
|
+
else
|
115
|
+
# Assume a default transfer syntax: Implicit, Little Endian.
|
116
|
+
# (Turns out I use the same settings as above, which makes this somewhat silly, but I'll leave it like this for now in case of any changes later)
|
117
|
+
@explicit = false
|
118
|
+
@rest_explicit = false
|
119
|
+
@file_endian = false
|
120
|
+
@rest_endian = false
|
121
|
+
@compression = false
|
122
|
+
puts "Warning: Group '0002' Transfer Syntax does not exist. Assuming Implicit, Little Endian."
|
123
|
+
end
|
124
|
+
return false
|
125
|
+
else
|
126
|
+
return true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
# Checks the status of the pixel data that has been read from the DICOM file: whether it exists at all and if its greyscale or color.
|
132
|
+
# Modifies instance variable @color if color image is detected and instance variable @compression if no pixel data is detected.
|
133
|
+
def check_pixel_status()
|
134
|
+
# Check if pixel data is present:
|
135
|
+
pixel_pos = @labels.index("7FE0.0010")
|
136
|
+
if pixel_pos == nil
|
137
|
+
@compression = nil
|
138
|
+
return
|
139
|
+
end
|
140
|
+
# Check for color image:
|
141
|
+
col_string = get_value("0028.0004")
|
142
|
+
if col_string != false
|
143
|
+
if (col_string.include? "RGB") or (col_string.include? "COLOR") or (col_string.include? "COLOUR")
|
144
|
+
@color = true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Governs the process of reading tags in the DICOM file.
|
151
|
+
def process_tag()
|
152
|
+
#STEP 1:
|
153
|
+
# Read the tag label, but do stop reading if indicated by this method.
|
154
|
+
@content = true
|
155
|
+
res=read_label()
|
156
|
+
if res == false
|
157
|
+
return false
|
158
|
+
end
|
159
|
+
if @content == false
|
160
|
+
return
|
161
|
+
end
|
162
|
+
# As we have a valid tag, extract the two pieces of information:
|
163
|
+
label=res[0]
|
164
|
+
pos=res[1]
|
165
|
+
# STEP 2:
|
166
|
+
# Continue reading the tag information: Byte type and length.
|
167
|
+
res=read_type_length(pos,label)
|
168
|
+
type=res[0]
|
169
|
+
length=res[1]
|
170
|
+
# For sequence type tag, check if the tag have length specified:
|
171
|
+
if type == "SQ"
|
172
|
+
if length == "UNDEFINED" or length.to_i == 0
|
173
|
+
@sq_length = false
|
174
|
+
else
|
175
|
+
@sq_length = true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
# If length is undefined, do not continue to read tag data:
|
179
|
+
if length == "UNDEFINED"
|
180
|
+
if label == "7FE0.0010"
|
181
|
+
data = "(Encapsulated pixel data)"
|
182
|
+
name = "Encapsulated image"
|
183
|
+
else
|
184
|
+
data = "(Encapsulated data)"
|
185
|
+
name = "Encapsulated information"
|
186
|
+
end
|
187
|
+
return [name,label,type,length,data]
|
188
|
+
end
|
189
|
+
# Item related tags:
|
190
|
+
if type == "()"
|
191
|
+
# Get name ("Item"):
|
192
|
+
name = get_name(pos)
|
193
|
+
# If length is zero, just return:
|
194
|
+
if length == 0
|
195
|
+
type = ""
|
196
|
+
data = nil
|
197
|
+
return [name,label,type,length,data]
|
198
|
+
else
|
199
|
+
# If there is content, this may, in the case of an image, be the image data.
|
200
|
+
# Must insert the image's type here.
|
201
|
+
# Some times when this tag has a length, it does not have content in itself, but instead
|
202
|
+
# have content in a number of subtags.
|
203
|
+
if @sq_length == true
|
204
|
+
# Do nothing (keep the type as "()")
|
205
|
+
else
|
206
|
+
# Treat the item as containing image data:
|
207
|
+
type = "OW" # A more general approach should be implemented here.
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
# STEP 3:
|
212
|
+
# Finally read the tag data.
|
213
|
+
if @content == true
|
214
|
+
res=read_data(type,length,pos)
|
215
|
+
value = res[0]
|
216
|
+
raw = res[1]
|
217
|
+
name=get_name(pos)
|
218
|
+
# Check for the Transfer Syntax UID tag, and process it:
|
219
|
+
if label == "0002.0010"
|
220
|
+
process_syntax(value)
|
221
|
+
end
|
222
|
+
return [name,label,type,length,value,raw]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
# END READ TAG
|
226
|
+
|
227
|
+
|
228
|
+
# Reads and returns TAG LABEL (4 first bytes of tag).
|
229
|
+
def read_label()
|
230
|
+
bin1=@file.read(2)
|
231
|
+
bin2=@file.read(2)
|
232
|
+
# Check if we have reached end of file before proceeding:
|
233
|
+
if bin1 == nil
|
234
|
+
return false
|
235
|
+
end
|
236
|
+
label1=bin1.unpack('h*').to_s.reverse.upcase
|
237
|
+
label2=bin2.unpack('h*').to_s.reverse.upcase
|
238
|
+
# Special treatment of tags that are of the first "0002" group:
|
239
|
+
if @sys_endian
|
240
|
+
# Rearrange the numbers:
|
241
|
+
label1 = label1[2..3]+label1[0..1]
|
242
|
+
label2 = label2[2..3]+label2[0..1]
|
243
|
+
# Has this been verified? Suspect unintended consequence.
|
244
|
+
end
|
245
|
+
# Process the label, by considering the endian-ness relationship, if are past the initial "0002" group:
|
246
|
+
if label1 != "0002"
|
247
|
+
# As we are past the initial little endian part of the file, update the file properties:
|
248
|
+
@file_endian = @rest_endian
|
249
|
+
@explicit = @rest_explicit
|
250
|
+
#Update the endian-relationship variable:
|
251
|
+
if @sys_endian == @file_endian
|
252
|
+
@endian = true
|
253
|
+
else
|
254
|
+
@endian = false
|
255
|
+
end
|
256
|
+
# Do we need to rearrange?
|
257
|
+
if @endian
|
258
|
+
# No action needed
|
259
|
+
else
|
260
|
+
# Need to rearrange the first and second part of each string:
|
261
|
+
label1 = label1[2..3]+label1[0..1]
|
262
|
+
label2 = label2[2..3]+label2[0..1]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
# Join the label group and label element together to the final string:
|
266
|
+
label=label1+'.'+label2
|
267
|
+
# Find the position of this label in the array of library labels:
|
268
|
+
pos=@lib_labels.index(label)
|
269
|
+
# If no match found, this is an unknown header type. Inform the user:
|
270
|
+
if pos == nil
|
271
|
+
@unknown = true
|
272
|
+
# For identifying additions needed in the library:
|
273
|
+
#puts "Unknown header element: "+label
|
274
|
+
else
|
275
|
+
@unknown = false
|
276
|
+
end
|
277
|
+
# Return the label as well as the position of this label in the library:
|
278
|
+
return [label,pos]
|
279
|
+
end
|
280
|
+
# END TAG LABEL
|
281
|
+
|
282
|
+
|
283
|
+
# Reads and returns TAG TYPE (2 bytes) and TAG LENGTH (Varying length).
|
284
|
+
def read_type_length(pos,label)
|
285
|
+
# Structure will differ, dependent on whether we have explicit or implicit type of file:
|
286
|
+
# Explicit:
|
287
|
+
if @explicit == true
|
288
|
+
# Unfortunately, it seems we need to have a special case for item labels in the explicit scenario:
|
289
|
+
if label == "FFFE.E000" or label == "FFFE.E00D" or label == "FFFE.E0DD"
|
290
|
+
# For the item related tag, get the special type from library, then read the 4 byte length:
|
291
|
+
type = @lib_types[pos]
|
292
|
+
bin=@file.read(4)
|
293
|
+
length = get_SL(bin)
|
294
|
+
else
|
295
|
+
# Read tag type field (2 bytes), as long as we are not dealing with an item related tag:
|
296
|
+
bin=@file.read(2)
|
297
|
+
type=bin.unpack('a*').to_s
|
298
|
+
end
|
299
|
+
# Two (three) possible structures for value length here, dependent on tag type:
|
300
|
+
case type
|
301
|
+
when "OB","OW","SQ","UN"
|
302
|
+
# Two empty bytes should occur here, according to the standard:
|
303
|
+
bin=@file.read(2)
|
304
|
+
#length=bin.unpack('S*')[0]
|
305
|
+
# However, it may occur (??) that the length appears in this slot, and subsequently,
|
306
|
+
# the following 4 byte slot is not utilized:
|
307
|
+
#if length != 0
|
308
|
+
# Read value length (4 bytes):
|
309
|
+
bin=@file.read(4)
|
310
|
+
length=get_SL(bin)
|
311
|
+
#end
|
312
|
+
when "()"
|
313
|
+
#An empty entry for the item related tags (As it has already been processed).
|
314
|
+
# Do nothing.
|
315
|
+
# For all the other tag types:
|
316
|
+
else
|
317
|
+
# Read value length (2 bytes):
|
318
|
+
bin=@file.read(2)
|
319
|
+
length=get_US(bin)
|
320
|
+
end
|
321
|
+
else
|
322
|
+
#Implicit:
|
323
|
+
# If it is unknown, use the identifier "UN":
|
324
|
+
if pos == nil
|
325
|
+
type = "UN"
|
326
|
+
else
|
327
|
+
# Tag type is not specified in the file, try to retrieve it from the library:
|
328
|
+
type = @lib_types[pos]
|
329
|
+
end
|
330
|
+
# Read value length (4 bytes):
|
331
|
+
bin=@file.read(4)
|
332
|
+
length = get_SL(bin)
|
333
|
+
end
|
334
|
+
# For encapsulated data, the tag length will not be defined. To convey this,
|
335
|
+
# the hex sequence 'ff ff ff ff' is used (-1 converted to signed long).
|
336
|
+
if length == -1
|
337
|
+
length = "UNDEFINED"
|
338
|
+
elsif length%2 >0
|
339
|
+
# According to the DICOM standard, all tag lengths should be an even number.
|
340
|
+
# If it is not, there has probably been an error in the readout:
|
341
|
+
puts "Warning: Odd number of bytes occured. This is a violation of the DICOM standard."
|
342
|
+
end
|
343
|
+
return [type,length]
|
344
|
+
end
|
345
|
+
# END BYTE TYPE and TAG LENGTH
|
346
|
+
|
347
|
+
|
348
|
+
# Reads and returns TAG DATA (Varying length - determined at an earlier stage).
|
349
|
+
def read_data(type, length, pos)
|
350
|
+
# Treatment dependent on what type of information we are dealing with.
|
351
|
+
case type
|
352
|
+
|
353
|
+
# Normally these numbers tags will contain just one number, but in some cases,
|
354
|
+
# they contain multiple numbers. In such cases we will read each number and store
|
355
|
+
# them all in a string separated by "/".
|
356
|
+
# Unsigned long: (4 bytes)
|
357
|
+
when "UL"
|
358
|
+
if length <= 4
|
359
|
+
bin = @file.read(length)
|
360
|
+
data = get_UL(bin)
|
361
|
+
else
|
362
|
+
data = process_numbers(length, type, 4)
|
363
|
+
end
|
364
|
+
|
365
|
+
# Signed long: (4 bytes)
|
366
|
+
when "SL"
|
367
|
+
if length <= 4
|
368
|
+
bin = @file.read(length)
|
369
|
+
data = get_SL(bin)
|
370
|
+
else
|
371
|
+
data = process_numbers(length, type, 4)
|
372
|
+
end
|
373
|
+
|
374
|
+
# Unsigned short: (2 bytes)
|
375
|
+
when 'US'
|
376
|
+
if length <= 2
|
377
|
+
bin = @file.read(length)
|
378
|
+
data = get_US(bin)
|
379
|
+
else
|
380
|
+
data = process_numbers(length, type, 2)
|
381
|
+
end
|
382
|
+
|
383
|
+
# Signed short: (2 bytes)
|
384
|
+
when 'SS'
|
385
|
+
if length <= 2
|
386
|
+
bin = @file.read(length)
|
387
|
+
data = get_SS(bin)
|
388
|
+
else
|
389
|
+
data = process_numbers(length, type, 2)
|
390
|
+
end
|
391
|
+
|
392
|
+
# Floating point double: (8 bytes)
|
393
|
+
when "FD"
|
394
|
+
if length <= 8
|
395
|
+
bin = @file.read(length)
|
396
|
+
data = get_FD(bin)
|
397
|
+
else
|
398
|
+
data = process_numbers(length, type, 8)
|
399
|
+
end
|
400
|
+
|
401
|
+
# Unknown information, header element is not recognised from local database:
|
402
|
+
when 'UN'
|
403
|
+
bin=@file.read(length)
|
404
|
+
data=bin.unpack('H*')[0]
|
405
|
+
|
406
|
+
# A tag that contains items/elements (sequence of elements):
|
407
|
+
when 'SQ'
|
408
|
+
# The tag has no content in itself, the file starts directly on a new tag adress.
|
409
|
+
data="(sequence of elements)"
|
410
|
+
|
411
|
+
# Item tag:
|
412
|
+
when '()'
|
413
|
+
# Tag may have a length, but no content belonging to this tag itself. They are to be read
|
414
|
+
# for this item's subtags.
|
415
|
+
data = "(Sequence of tags)"
|
416
|
+
|
417
|
+
# The tag contains a tag adress (4 bytes):
|
418
|
+
when 'AT'
|
419
|
+
if length != 4
|
420
|
+
puts "warning: Unexpected tag length, expected 4 bytes for tag type 'AT'!"
|
421
|
+
end
|
422
|
+
temp=Array.new(4)
|
423
|
+
4.times do |i|
|
424
|
+
bin=@file.read(1)
|
425
|
+
temp[i]=bin.unpack('H*')[0]
|
426
|
+
end
|
427
|
+
# Put together, mix up the order to get it correct:
|
428
|
+
data=temp[1].to_s+temp[0].to_s+"."+temp[3].to_s+temp[2].to_s
|
429
|
+
# This has not been tested with other than Little endian system/file:
|
430
|
+
if @file_endian or @system_endian
|
431
|
+
puts "Warning: Handling for tag type 'AT' has not been verified for other than default endianness."
|
432
|
+
end
|
433
|
+
|
434
|
+
# Binary data, used sometimes when we have encapsulated images:
|
435
|
+
when 'OB'
|
436
|
+
bin=@file.read(length)
|
437
|
+
data=bin.unpack('H*')[0]
|
438
|
+
|
439
|
+
# Image data:
|
440
|
+
when 'OW'
|
441
|
+
# We need to know what kind of bith depth the pixel data is saved with:
|
442
|
+
bit_depth=get_value('0028.0100')
|
443
|
+
# Proceed to read the image binary data:
|
444
|
+
bin=@file.read(length)
|
445
|
+
# Number of bytes used per pixel will determine how to unpack this:
|
446
|
+
case bit_depth
|
447
|
+
when 8
|
448
|
+
data=get_BYTE(bin) # Byte/Character/Fixnum (1 byte)
|
449
|
+
when 16
|
450
|
+
data=get_US(bin) # Unsigned short (2 bytes)
|
451
|
+
when 12
|
452
|
+
# 12 BIT SIMPLY NOT WORKING YET!
|
453
|
+
# This one is a bit more tricky to extract.
|
454
|
+
# Unknown if really working.
|
455
|
+
puts "Warning: Bit depth 12 is not working correctly at this time!"
|
456
|
+
data=Array.new(length)
|
457
|
+
(length).times do |i|
|
458
|
+
hex=bin.unpack('H3')
|
459
|
+
hex4="0"+hex[0]
|
460
|
+
num=hex[0].unpack('v')
|
461
|
+
data[i]=num
|
462
|
+
end
|
463
|
+
else
|
464
|
+
raise "Bit depth "+bit_depth.to_s+" has not received implementation in this procedure yet."
|
465
|
+
end
|
466
|
+
|
467
|
+
# For everything else, assume string type information:
|
468
|
+
when 'AE','AS','CS','DA','DS','IS','LO','LT','PN','SH','ST','TM','UI','VR'
|
469
|
+
bin=@file.read(length)
|
470
|
+
data=bin.unpack('a*').to_s
|
471
|
+
else
|
472
|
+
puts "Warning: Tag type "+type+" does not have a reading method assigned to it. Please update the source code."
|
473
|
+
bin=@file.read(length)
|
474
|
+
data=bin.unpack('H*')[0]
|
475
|
+
end
|
476
|
+
return [data,bin]
|
477
|
+
end
|
478
|
+
# END TAG DATA
|
479
|
+
|
480
|
+
|
481
|
+
# Returns tag name from library if tag is recognised, else returns 'Unknown Name'.
|
482
|
+
def get_name(pos)
|
483
|
+
if not @unknown
|
484
|
+
str_name=@lib_names[pos]
|
485
|
+
else
|
486
|
+
str_name='Unknown Name'
|
487
|
+
end
|
488
|
+
return str_name
|
489
|
+
end
|
490
|
+
|
491
|
+
|
492
|
+
# Returns the (processed) value of a DICOM tag based on an input tag label, category name or array index.
|
493
|
+
def get_value(id)
|
494
|
+
# Assume we have been fed a tag label:
|
495
|
+
pos=@labels.index(id)
|
496
|
+
# If this does not give a hit, assume we have been fed a tag name:
|
497
|
+
if pos==nil
|
498
|
+
pos=@names.index(id)
|
499
|
+
end
|
500
|
+
# If we still dont have a hit, check if it is a valid number within the array range:
|
501
|
+
if pos == nil
|
502
|
+
if (id.is_a? Integer)
|
503
|
+
if id >= 0 and id <= @lastIndex
|
504
|
+
# The id supplied is a valid position, return its corresponding value:
|
505
|
+
return @values[id]
|
506
|
+
else
|
507
|
+
return false
|
508
|
+
end
|
509
|
+
else
|
510
|
+
return false
|
511
|
+
end
|
512
|
+
else
|
513
|
+
# We have a valid position, return the value:
|
514
|
+
return @values[pos]
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
|
519
|
+
# Loads the library which links tag label with tag name and tag type.
|
520
|
+
# (Note that this library is not complete, it is based on information from the DICOM files I have available.)
|
521
|
+
# (TNV means type not verified with external source for the particular tag that these letters appear behind)
|
522
|
+
def load_library()
|
523
|
+
a=Array.new()
|
524
|
+
b=Array.new()
|
525
|
+
c=Array.new()
|
526
|
+
a+=['0002.0000'] and b+=['UL'] and c+=['Group Length']
|
527
|
+
a+=['0002.0001'] and b+=['OB'] and c+=['File Meta Information']
|
528
|
+
a+=['0002.0002'] and b+=['UI'] and c+=['Media Storage SOP Class UID']
|
529
|
+
a+=['0002.0003'] and b+=['UI'] and c+=['Media Storage SOP Instance UID']
|
530
|
+
a+=['0002.0010'] and b+=['UI'] and c+=['Transfer Syntax UID']
|
531
|
+
a+=['0002.0012'] and b+=['UI'] and c+=['Implementation Class UID']
|
532
|
+
a+=['0002.0013'] and b+=['SH'] and c+=['Implementation Version Name']
|
533
|
+
a+=['0002.0016'] and b+=['AE'] and c+=['Source Application Entity Title']
|
534
|
+
a+=['0008.0000'] and b+=['UL'] and c+=['Group Length']
|
535
|
+
a+=['0008.0005'] and b+=['CS'] and c+=['Specific Character Set']
|
536
|
+
a+=['0008.0008'] and b+=['CS'] and c+=['Image Type']
|
537
|
+
a+=['0008.0010'] and b+=['LO'] and c+=['Recognition Code'] #TNV
|
538
|
+
a+=['0008.0012'] and b+=['DA'] and c+=['Instance Creation Date']
|
539
|
+
a+=['0008.0013'] and b+=['TM'] and c+=['Instance Creation Time']
|
540
|
+
a+=['0008.0014'] and b+=['UI'] and c+=['Instance Creator UID']
|
541
|
+
a+=['0008.0016'] and b+=['UI'] and c+=['SOP Class UID']
|
542
|
+
a+=['0008.0018'] and b+=['UI'] and c+=['SOP Instance UID']
|
543
|
+
a+=['0008.0020'] and b+=['DA'] and c+=['Study Date']
|
544
|
+
a+=['0008.0021'] and b+=['DA'] and c+=['Series Date']
|
545
|
+
a+=['0008.0022'] and b+=['DA'] and c+=['Acquisition Date']
|
546
|
+
a+=['0008.0023'] and b+=['DA'] and c+=['Image Date']
|
547
|
+
a+=['0008.0030'] and b+=['TM'] and c+=['Study Time']
|
548
|
+
a+=['0008.0031'] and b+=['TM'] and c+=['Series Time']
|
549
|
+
a+=['0008.0032'] and b+=['TM'] and c+=['Acquisition Time']
|
550
|
+
a+=['0008.0033'] and b+=['TM'] and c+=['Image Time']
|
551
|
+
a+=['0008.0040'] and b+=['US'] and c+=['Data Set Type'] #TNV
|
552
|
+
a+=['0008.0041'] and b+=['LO'] and c+=['Data Set Subtype'] #TNV
|
553
|
+
a+=['0008.0050'] and b+=['SH'] and c+=['Accession Number']
|
554
|
+
a+=['0008.0060'] and b+=['CS'] and c+=['Modality']
|
555
|
+
a+=['0008.0064'] and b+=['CS'] and c+=['Conversion Type']
|
556
|
+
a+=['0008.0070'] and b+=['LO'] and c+=['Manufacturer']
|
557
|
+
a+=['0008.0080'] and b+=['LO'] and c+=['Institution Name']
|
558
|
+
a+=['0008.0081'] and b+=['ST'] and c+=['Institution Address']
|
559
|
+
a+=['0008.0090'] and b+=['PN'] and c+=['Referring Physician`s name']
|
560
|
+
a+=['0008.0201'] and b+=['SH'] and c+=['Timezone Offset From UTC']
|
561
|
+
a+=['0008.1010'] and b+=['SH'] and c+=['Station Name']
|
562
|
+
a+=['0008.1030'] and b+=['LO'] and c+=['Study Description']
|
563
|
+
a+=['0008.103E'] and b+=['LO'] and c+=['Series Description']
|
564
|
+
a+=['0008.1040'] and b+=['LO'] and c+=['Institutional Department Name']
|
565
|
+
a+=['0008.1050'] and b+=['PN'] and c+=['Performing Physician`s Name']
|
566
|
+
a+=['0008.1060'] and b+=['PN'] and c+=['Name of Physician(s) Reading Study']
|
567
|
+
a+=['0008.1070'] and b+=['PN'] and c+=['Operator`s name']
|
568
|
+
a+=['0008.1080'] and b+=['LO'] and c+=['Admitting Diagnoses Description']
|
569
|
+
a+=['0008.1090'] and b+=['LO'] and c+=['Manufacturer`s Model Name']
|
570
|
+
a+=['0008.1140'] and b+=['SQ'] and c+=['Referenced Image Sequence']
|
571
|
+
a+=['0008.1150'] and b+=['UI'] and c+=['Referenced SOP Class UID']
|
572
|
+
a+=['0008.1155'] and b+=['UI'] and c+=['Referenced SOP Instance UID']
|
573
|
+
a+=['0008.2120'] and b+=['SH'] and c+=['Stage Name']
|
574
|
+
a+=['0008.2122'] and b+=['IS'] and c+=['Stage Number']
|
575
|
+
a+=['0008.2124'] and b+=['IS'] and c+=['Number of Stages']
|
576
|
+
a+=['0008.2128'] and b+=['IS'] and c+=['View Number']
|
577
|
+
a+=['0008.212A'] and b+=['IS'] and c+=['Number of Views in Stage']
|
578
|
+
a+=['0008.2204'] and b+=['CS'] and c+=['Transducer Orientation']
|
579
|
+
a+=['0009.0000'] and b+=['UL'] and c+=['Group Length']
|
580
|
+
a+=['0010.0000'] and b+=['UL'] and c+=['Group Length']
|
581
|
+
a+=['0010.0010'] and b+=['PN'] and c+=['Patient`s Name']
|
582
|
+
a+=['0010.0020'] and b+=['LO'] and c+=['Patient ID']
|
583
|
+
a+=['0010.0030'] and b+=['DA'] and c+=['Patient`s Birth Date']
|
584
|
+
a+=['0010.0040'] and b+=['CS'] and c+=['Patient`s Sex']
|
585
|
+
a+=['0010.1000'] and b+=['LO'] and c+=['Other Patient IDs']
|
586
|
+
a+=['0010.1005'] and b+=['PN'] and c+=['Patient`s Birth Name']
|
587
|
+
a+=['0010.1010'] and b+=['AS'] and c+=['Patient`s Age']
|
588
|
+
a+=['0010.1020'] and b+=['DS'] and c+=['Patient`s Size']
|
589
|
+
a+=['0010.1030'] and b+=['DS'] and c+=['Patient`s Weight']
|
590
|
+
a+=['0010.2160'] and b+=['SH'] and c+=['Ethnic Group']
|
591
|
+
a+=['0010.21B0'] and b+=['LT'] and c+=['Additional Patient History']
|
592
|
+
a+=['0010.4000'] and b+=['LT'] and c+=['Patient Comments']
|
593
|
+
a+=['0018.0000'] and b+=['UL'] and c+=['Group Length']
|
594
|
+
a+=['0018.0010'] and b+=['LO'] and c+=['Contrast/Bolus Agent']
|
595
|
+
a+=['0018.0015'] and b+=['CS'] and c+=['Body Part Examined']
|
596
|
+
a+=['0018.0020'] and b+=['CS'] and c+=['Scanning Sequence']
|
597
|
+
a+=['0018.0021'] and b+=['CS'] and c+=['Sequence Variant']
|
598
|
+
a+=['0018.0022'] and b+=['CS'] and c+=['Scan Options']
|
599
|
+
a+=['0018.0023'] and b+=['CS'] and c+=['MR Acquisition Type']
|
600
|
+
a+=['0018.0024'] and b+=['SH'] and c+=['Sequence Name']
|
601
|
+
a+=['0018.0025'] and b+=['CS'] and c+=['Angio Flag']
|
602
|
+
a+=['0018.0050'] and b+=['DS'] and c+=['Slice Thickness']
|
603
|
+
a+=['0018.0060'] and b+=['DS'] and c+=['KVP']
|
604
|
+
a+=['0018.0070'] and b+=['IS'] and c+=['Counts Accumulated']
|
605
|
+
a+=['0018.0071'] and b+=['CS'] and c+=['Acquisition Termination Condition']
|
606
|
+
a+=['0018.0080'] and b+=['DS'] and c+=['Repetition Time']
|
607
|
+
a+=['0018.0081'] and b+=['DS'] and c+=['Echo Time']
|
608
|
+
a+=['0018.0082'] and b+=['DS'] and c+=['Inversion Time']
|
609
|
+
a+=['0018.0083'] and b+=['DS'] and c+=['Number of Averages']
|
610
|
+
a+=['0018.0084'] and b+=['DS'] and c+=['Imaging Frequency']
|
611
|
+
a+=['0018.0085'] and b+=['SH'] and c+=['Imaged Nucleus']
|
612
|
+
a+=['0018.0086'] and b+=['IS'] and c+=['Echo Number(s)']
|
613
|
+
a+=['0018.0087'] and b+=['DS'] and c+=['Magnetic Field Strength']
|
614
|
+
a+=['0018.0088'] and b+=['DS'] and c+=['Spacing Between Slices']
|
615
|
+
a+=['0018.0089'] and b+=['IS'] and c+=['Number of Phase Encoding Steps']
|
616
|
+
a+=['0018.0090'] and b+=['DS'] and c+=['Data Collection Diameter']
|
617
|
+
a+=['0018.0091'] and b+=['IS'] and c+=['Echo Train Length']
|
618
|
+
a+=['0018.0093'] and b+=['DS'] and c+=['Percent Sampling']
|
619
|
+
a+=['0018.0094'] and b+=['DS'] and c+=['Percent Phase Field of View']
|
620
|
+
a+=['0018.0095'] and b+=['DS'] and c+=['Pixel Bandwidth']
|
621
|
+
a+=['0018.1000'] and b+=['LO'] and c+=['Device Serial Number']
|
622
|
+
a+=['0018.1004'] and b+=['LO'] and c+=['Plate ID']
|
623
|
+
a+=['0018.1010'] and b+=['LO'] and c+=['Secondary Capture Device ID']
|
624
|
+
a+=['0018.1012'] and b+=['DA'] and c+=['Date of Secondary Capture']
|
625
|
+
a+=['0018.1014'] and b+=['TM'] and c+=['Time of Secondary Capture']
|
626
|
+
a+=['0018.1018'] and b+=['LO'] and c+=['Secondary Capture Device Manufacturer`s Model Name']
|
627
|
+
a+=['0018.1019'] and b+=['LO'] and c+=['Secondary Capture Device Software Version(s)']
|
628
|
+
a+=['0018.1020'] and b+=['LO'] and c+=['Software Version(s)']
|
629
|
+
a+=['0018.1030'] and b+=['LO'] and c+=['Protocol Name']
|
630
|
+
a+=['0018.1041'] and b+=['DS'] and c+=['Contrast/Bolus Volume']
|
631
|
+
a+=['0018.1044'] and b+=['DS'] and c+=['Contrast/Bolus Total Dose']
|
632
|
+
a+=['0018.1050'] and b+=['DS'] and c+=['Spatial Resolution']
|
633
|
+
a+=['0018.1062'] and b+=['IS'] and c+=['Nominal Interval']
|
634
|
+
a+=['0018.1063'] and b+=['DS'] and c+=['Frame Time']
|
635
|
+
a+=['0018.1081'] and b+=['IS'] and c+=['Low R-R Value']
|
636
|
+
a+=['0018.1082'] and b+=['IS'] and c+=['High R-R Value']
|
637
|
+
a+=['0018.1083'] and b+=['IS'] and c+=['Intervals Acquired']
|
638
|
+
a+=['0018.1084'] and b+=['IS'] and c+=['Intervals Rejected']
|
639
|
+
a+=['0018.1088'] and b+=['IS'] and c+=['Heart Rate']
|
640
|
+
a+=['0018.1090'] and b+=['IS'] and c+=['Cardiac Number of Images']
|
641
|
+
a+=['0018.1094'] and b+=['IS'] and c+=['Trigger Window']
|
642
|
+
a+=['0018.1100'] and b+=['DS'] and c+=['Reconstruction Diameter']
|
643
|
+
a+=['0018.1110'] and b+=['DS'] and c+=['Distance Source to Detector']
|
644
|
+
a+=['0018.1111'] and b+=['DS'] and c+=['Distance Source to Patient']
|
645
|
+
a+=['0018.1120'] and b+=['DS'] and c+=['Gantry/Detector Tilt']
|
646
|
+
a+=['0018.1130'] and b+=['DS'] and c+=['Table Height']
|
647
|
+
a+=['0018.1140'] and b+=['CS'] and c+=['Rotation Direction']
|
648
|
+
a+=['0018.1149'] and b+=['IS'] and c+=['Field of View Dimension(s)']
|
649
|
+
a+=['0018.1150'] and b+=['IS'] and c+=['Exposure Time']
|
650
|
+
a+=['0018.1151'] and b+=['IS'] and c+=['X-ray Tube Current']
|
651
|
+
a+=['0018.1152'] and b+=['IS'] and c+=['Exposure']
|
652
|
+
a+=['0018.1155'] and b+=['CS'] and c+=['Radiation Setting']
|
653
|
+
a+=['0018.1160'] and b+=['SH'] and c+=['Filter Type']
|
654
|
+
a+=['0018.1164'] and b+=['DS'] and c+=['Image Pixel Spacing']
|
655
|
+
a+=['0018.1170'] and b+=['IS'] and c+=['Generator Power']
|
656
|
+
a+=['0018.1190'] and b+=['DS'] and c+=['Focal Spot(s)']
|
657
|
+
a+=['0018.1200'] and b+=['DA'] and c+=['Date of Last Calibration']
|
658
|
+
a+=['0018.1201'] and b+=['TM'] and c+=['Time of Last Calibration']
|
659
|
+
a+=['0018.1210'] and b+=['SH'] and c+=['Convolution Kernel']
|
660
|
+
a+=['0018.1250'] and b+=['SH'] and c+=['Receiving Coil']
|
661
|
+
a+=['0018.1251'] and b+=['SH'] and c+=['Transmitting Coil']
|
662
|
+
a+=['0018.1260'] and b+=['SH'] and c+=['Plate Type']
|
663
|
+
a+=['0018.1261'] and b+=['LO'] and c+=['Phosphor Type']
|
664
|
+
a+=['0018.1310'] and b+=['US'] and c+=['Acquisition Matrix']
|
665
|
+
a+=['0018.1312'] and b+=['CS'] and c+=['Phase Encoding Direction']
|
666
|
+
a+=['0018.1314'] and b+=['DS'] and c+=['Flip Angle']
|
667
|
+
a+=['0018.1315'] and b+=['CS'] and c+=['Variable Flip Angle Flag']
|
668
|
+
a+=['0018.1316'] and b+=['DS'] and c+=['SAR']
|
669
|
+
a+=['0018.1318'] and b+=['DS'] and c+=['dB/dt']
|
670
|
+
a+=['0018.1400'] and b+=['LO'] and c+=['Acquisition Device Processing Description']
|
671
|
+
a+=['0018.1401'] and b+=['LO'] and c+=['Acquisition Device Processing Code']
|
672
|
+
a+=['0018.1402'] and b+=['CS'] and c+=['Cassette Orientation']
|
673
|
+
a+=['0018.1403'] and b+=['CS'] and c+=['Cassette Size']
|
674
|
+
a+=['0018.1404'] and b+=['CS'] and c+=['Exposures on Plate']
|
675
|
+
a+=['0018.1500'] and b+=['CS'] and c+=['Positioner Motion']
|
676
|
+
a+=['0018.1510'] and b+=['DS'] and c+=['Positioner Primary Angle']
|
677
|
+
a+=['0018.1511'] and b+=['DS'] and c+=['Positioner Secondary Angle']
|
678
|
+
a+=['0018.5020'] and b+=['LO'] and c+=['Processing Function']
|
679
|
+
a+=['0018.5100'] and b+=['CS'] and c+=['Patient Position']
|
680
|
+
a+=['0018.5101'] and b+=['CS'] and c+=['View Position']
|
681
|
+
a+=['0018.6000'] and b+=['DS'] and c+=['Sensitivity']
|
682
|
+
a+=['0019.0000'] and b+=['UL'] and c+=['Group Length']
|
683
|
+
a+=['0020.0000'] and b+=['UL'] and c+=['Group Length']
|
684
|
+
a+=['0020.000D'] and b+=['UI'] and c+=['Study Instance UID']
|
685
|
+
a+=['0020.000E'] and b+=['UI'] and c+=['Series Instance UID']
|
686
|
+
a+=['0020.0010'] and b+=['SH'] and c+=['Study ID']
|
687
|
+
a+=['0020.0011'] and b+=['IS'] and c+=['Series Number']
|
688
|
+
a+=['0020.0012'] and b+=['IS'] and c+=['Acquisition Number']
|
689
|
+
a+=['0020.0013'] and b+=['IS'] and c+=['Instance Number']
|
690
|
+
a+=['0020.0020'] and b+=['CS'] and c+=['Patient Orientation']
|
691
|
+
a+=['0020.0030'] and b+=['LO'] and c+=['Image Position'] #TNV
|
692
|
+
a+=['0020.0035'] and b+=['LO'] and c+=['Image Orientation'] #TNV
|
693
|
+
a+=['0020.0032'] and b+=['DS'] and c+=['Image Position (Patient)']
|
694
|
+
a+=['0020.0037'] and b+=['DS'] and c+=['Image Orientation (Patient)']
|
695
|
+
a+=['0020.0050'] and b+=['LO'] and c+=['Location'] #TNV
|
696
|
+
a+=['0020.0052'] and b+=['UI'] and c+=['Frame of Reference UID']
|
697
|
+
a+=['0020.0060'] and b+=['CS'] and c+=['Laterality']
|
698
|
+
a+=['0020.0070'] and b+=['LO'] and c+=['Image Geometry Type'] #TNV
|
699
|
+
a+=['0020.1001'] and b+=['LO'] and c+=['Acquisitions in Series'] #TNV
|
700
|
+
a+=['0020.1002'] and b+=['IS'] and c+=['Images in Acquisition']
|
701
|
+
a+=['0020.1020'] and b+=['LO'] and c+=['Reference'] #TNV
|
702
|
+
a+=['0020.1040'] and b+=['LO'] and c+=['Position Reference Indicator']
|
703
|
+
a+=['0020.1041'] and b+=['DS'] and c+=['Slice Location']
|
704
|
+
a+=['0020.4000'] and b+=['LT'] and c+=['Image Comments']
|
705
|
+
a+=['0020.5000'] and b+=['UL'] and c+=['Original Image Identification'] #TNV
|
706
|
+
a+=['0020.5002'] and b+=['LO'] and c+=['Original Image Identification Nomenclature'] #TNV
|
707
|
+
a+=['0021.0000'] and b+=['UL'] and c+=['Group Length']
|
708
|
+
a+=['0023.0000'] and b+=['UL'] and c+=['Group Length']
|
709
|
+
a+=['0027.0000'] and b+=['UL'] and c+=['Group Length']
|
710
|
+
a+=['0028.0000'] and b+=['UL'] and c+=['Group Length']
|
711
|
+
a+=['0028.0002'] and b+=['US'] and c+=['Samples per Pixel']
|
712
|
+
a+=['0028.0004'] and b+=['CS'] and c+=['Photometric Interpretation']
|
713
|
+
a+=['0028.0006'] and b+=['US'] and c+=['Planar Configuration']
|
714
|
+
a+=['0028.0005'] and b+=['US'] and c+=['Image Dimensions'] #TNV
|
715
|
+
a+=['0028.0008'] and b+=['IS'] and c+=['Number of Frames']
|
716
|
+
a+=['0028.0009'] and b+=['AT'] and c+=['Frame Increment Pointer']
|
717
|
+
a+=['0028.0010'] and b+=['US'] and c+=['Rows']
|
718
|
+
a+=['0028.0011'] and b+=['US'] and c+=['Columns']
|
719
|
+
a+=['0028.0030'] and b+=['DS'] and c+=['Pixel Spacing']
|
720
|
+
a+=['0028.0034'] and b+=['IS'] and c+=['Pixel Aspect Ratio']
|
721
|
+
a+=['0028.0040'] and b+=['LO'] and c+=['Image Format'] #TNV
|
722
|
+
a+=['0028.0060'] and b+=['LO'] and c+=['Compression Code'] #TNV
|
723
|
+
a+=['0028.0100'] and b+=['US'] and c+=['Bits Allocated']
|
724
|
+
a+=['0028.0101'] and b+=['US'] and c+=['Bits Stored']
|
725
|
+
a+=['0028.0102'] and b+=['US'] and c+=['High Bit']
|
726
|
+
a+=['0028.0103'] and b+=['US'] and c+=['Pixel Representation']
|
727
|
+
a+=['0028.0104'] and b+=['US'] and c+=['Smallest Valid Pixel Value'] #TNV
|
728
|
+
a+=['0028.0105'] and b+=['US'] and c+=['Largest Valid Pixel Value'] #TNV
|
729
|
+
a+=['0028.0106'] and b+=['US'] and c+=['Smallest Image Pixel Value'] # 'SS' also possible
|
730
|
+
a+=['0028.0107'] and b+=['US'] and c+=['Largest Image Pixel Value'] # 'SS' also possible
|
731
|
+
a+=['0028.0108'] and b+=['US'] and c+=['Smallest Pixel Value in Series']
|
732
|
+
a+=['0028.0109'] and b+=['US'] and c+=['Largest Pixel Value in Series']
|
733
|
+
a+=['0028.0120'] and b+=['US'] and c+=['Pixel Padding Value'] # 'SS' also possible
|
734
|
+
a+=['0028.0200'] and b+=['US'] and c+=['Image Location'] #TNV
|
735
|
+
a+=['0028.0300'] and b+=['CS'] and c+=['Quality Control Image']
|
736
|
+
a+=['0028.0301'] and b+=['CS'] and c+=['Burned In Annotation']
|
737
|
+
a+=['0028.1040'] and b+=['CS'] and c+=['Pixel Intensity Relationship']
|
738
|
+
a+=['0028.1050'] and b+=['DS'] and c+=['Window Center']
|
739
|
+
a+=['0028.1051'] and b+=['DS'] and c+=['Window Width']
|
740
|
+
a+=['0028.1052'] and b+=['DS'] and c+=['Rescale Intercept']
|
741
|
+
a+=['0028.1053'] and b+=['US'] and c+=['Rescale Slope']
|
742
|
+
a+=['0028.1054'] and b+=['LO'] and c+=['Rescale Type']
|
743
|
+
a+=['0028.1055'] and b+=['LO'] and c+=['Window Center & Width Explanation']
|
744
|
+
a+=['0028.1101'] and b+=['US'] and c+=['Red Palette Color Lookup Table Descriptor']
|
745
|
+
a+=['0028.1102'] and b+=['US'] and c+=['Green Palette Color Lookup Table Descriptor']
|
746
|
+
a+=['0028.1103'] and b+=['US'] and c+=['Blue Palette Color Lookup Table Descriptor']
|
747
|
+
a+=['0028.1199'] and b+=['UI'] and c+=['Palette Color Lookup Table UID']
|
748
|
+
a+=['0028.1201'] and b+=['US'] and c+=['Red Palette Color Lookup Table Data']
|
749
|
+
a+=['0028.1202'] and b+=['US'] and c+=['Green Palette Color Lookup Table Data']
|
750
|
+
a+=['0028.1203'] and b+=['US'] and c+=['Blue Palette Color Lookup Table Data']
|
751
|
+
a+=['0028.2110'] and b+=['CS'] and c+=['Lossy Image Compression']
|
752
|
+
a+=['0028.3003'] and b+=['LO'] and c+=['LUT Explanation']
|
753
|
+
a+=['0029.0000'] and b+=['UL'] and c+=['Group Length']
|
754
|
+
a+=['0032.0000'] and b+=['UL'] and c+=['Group Length']
|
755
|
+
a+=['0032.1060'] and b+=['LO'] and c+=['Requested Procedure Description']
|
756
|
+
a+=['0040.0000'] and b+=['UL'] and c+=['Group Length']
|
757
|
+
a+=['0040.0244'] and b+=['DA'] and c+=['Performed Procedure Step Start Date']
|
758
|
+
a+=['0040.0245'] and b+=['TM'] and c+=['Performed Procedure Step Start Time']
|
759
|
+
a+=['0040.0253'] and b+=['SH'] and c+=['Performed Procedure Step ID']
|
760
|
+
a+=['0040.0254'] and b+=['LO'] and c+=['Performed Procedure Step Description']
|
761
|
+
a+=['0043.0000'] and b+=['UL'] and c+=['Group Length']
|
762
|
+
a+=['0045.0000'] and b+=['UL'] and c+=['Group Length']
|
763
|
+
a+=['0051.0000'] and b+=['UL'] and c+=['Group Length']
|
764
|
+
a+=['0054.0000'] and b+=['UL'] and c+=['Group Length']
|
765
|
+
a+=['0054.0011'] and b+=['US'] and c+=['Number of Energy Windows']
|
766
|
+
a+=['0054.0021'] and b+=['US'] and c+=['Number of Detectors']
|
767
|
+
a+=['0054.0051'] and b+=['US'] and c+=['Number of Rotations']
|
768
|
+
a+=['0054.0080'] and b+=['US'] and c+=['Slice Vector']
|
769
|
+
a+=['0054.0081'] and b+=['US'] and c+=['Number of Slices']
|
770
|
+
a+=['0054.0202'] and b+=['CS'] and c+=['Type of Detector Motion']
|
771
|
+
a+=['0054.0400'] and b+=['SH'] and c+=['Image ID']
|
772
|
+
a+=['0088.0000'] and b+=['UL'] and c+=['Group Length']
|
773
|
+
a+=['0088.0140'] and b+=['UI'] and c+=['Storage Media File-set UID']
|
774
|
+
a+=['0088.0200'] and b+=['SQ'] and c+=['Icon Image Sequence']
|
775
|
+
a+=['2010.0000'] and b+=['UL'] and c+=['Group Length']
|
776
|
+
a+=['2010.0100'] and b+=['CS'] and c+=['Border Density']
|
777
|
+
a+=['2020.0000'] and b+=['UL'] and c+=['Group Length']
|
778
|
+
a+=['2020.0020'] and b+=['CS'] and c+=['Polarity']
|
779
|
+
a+=['3002.0000'] and b+=['UL'] and c+=['Group Length']
|
780
|
+
a+=['3002.0002'] and b+=['SH'] and c+=['RT Image Label']
|
781
|
+
a+=['3002.0003'] and b+=['LO'] and c+=['RT Image Name']
|
782
|
+
a+=['3002.0004'] and b+=['ST'] and c+=['RT Image Description']
|
783
|
+
a+=['3002.000A'] and b+=['CS'] and c+=['Reported Values Origin']
|
784
|
+
a+=['3002.000C'] and b+=['CS'] and c+=['RT Image Plane']
|
785
|
+
a+=['3002.000D'] and b+=['DS'] and c+=['X-Ray Image Receptor Translation']
|
786
|
+
a+=['3002.000E'] and b+=['DS'] and c+=['X-Ray Image Receptor Angle']
|
787
|
+
a+=['3002.0011'] and b+=['DS'] and c+=['Image Plane Pixel Spacing']
|
788
|
+
a+=['3002.0012'] and b+=['DS'] and c+=['RT Image Position']
|
789
|
+
a+=['3002.0020'] and b+=['SH'] and c+=['Radiation Machine Name']
|
790
|
+
a+=['3002.0022'] and b+=['DS'] and c+=['Radiation Machine SAD']
|
791
|
+
a+=['3002.0026'] and b+=['DS'] and c+=['RT Image SID']
|
792
|
+
a+=['3002.0030'] and b+=['SQ'] and c+=['Exposure Sequence']
|
793
|
+
a+=['3002.0032'] and b+=['DS'] and c+=['Meterset Exposure']
|
794
|
+
a+=['3002.0034'] and b+=['DS'] and c+=['Diaphragm Position']
|
795
|
+
a+=['3004.0000'] and b+=['UL'] and c+=['Group Length']
|
796
|
+
a+=['3004.0002'] and b+=['CS'] and c+=['Dose Units']
|
797
|
+
a+=['3004.0004'] and b+=['CS'] and c+=['Dose Type']
|
798
|
+
a+=['3004.0006'] and b+=['LO'] and c+=['Dose Comment']
|
799
|
+
a+=['3004.000A'] and b+=['CS'] and c+=['Dose Summation Type']
|
800
|
+
a+=['3004.000C'] and b+=['DS'] and c+=['Grid Frame Offset Vector']
|
801
|
+
a+=['3004.000E'] and b+=['DS'] and c+=['Dose Grid Scaling']
|
802
|
+
a+=['3004.0010'] and b+=['SQ'] and c+=['RT Dose ROI Sequence']
|
803
|
+
a+=['3004.0012'] and b+=['DS'] and c+=['Dose Value']
|
804
|
+
a+=['3005.0000'] and b+=['UL'] and c+=['Group Length']
|
805
|
+
a+=['3006.0000'] and b+=['UL'] and c+=['Group Length']
|
806
|
+
a+=['3006.0002'] and b+=['SH'] and c+=['Structure Set Label']
|
807
|
+
a+=['3006.0004'] and b+=['LO'] and c+=['Structure Set Name']
|
808
|
+
a+=['3006.0008'] and b+=['DA'] and c+=['Structure Set Date']
|
809
|
+
a+=['3006.0009'] and b+=['TM'] and c+=['Structure Set Time']
|
810
|
+
a+=['3006.0010'] and b+=['SQ'] and c+=['Referenced Frame of Reference Sequence']
|
811
|
+
a+=['3006.0012'] and b+=['SQ'] and c+=['RT Referenced Study Sequence']
|
812
|
+
a+=['3006.0014'] and b+=['SQ'] and c+=['RT Referenced Series Sequence']
|
813
|
+
a+=['3006.0020'] and b+=['SQ'] and c+=['Structure Set ROI Sequence']
|
814
|
+
a+=['3006.0022'] and b+=['IS'] and c+=['ROI Number']
|
815
|
+
a+=['3006.0024'] and b+=['UI'] and c+=['Referenced Frame of Reference UID']
|
816
|
+
a+=['3006.0026'] and b+=['LO'] and c+=['ROI Name']
|
817
|
+
a+=['3006.002A'] and b+=['IS'] and c+=['ROI Display Color']
|
818
|
+
a+=['3006.0016'] and b+=['SQ'] and c+=['Contour Image Sequence']
|
819
|
+
a+=['3006.0036'] and b+=['CS'] and c+=['ROI Generation Algorithm']
|
820
|
+
a+=['3006.0039'] and b+=['SQ'] and c+=['ROI Contour Sequence']
|
821
|
+
a+=['3006.0040'] and b+=['SQ'] and c+=['Contour Sequence']
|
822
|
+
a+=['3006.0042'] and b+=['CS'] and c+=['Contour Geometric Type']
|
823
|
+
a+=['3006.0046'] and b+=['IS'] and c+=['Number of Contour Points']
|
824
|
+
a+=['3006.0048'] and b+=['IS'] and c+=['Contour Number']
|
825
|
+
a+=['3006.0050'] and b+=['DS'] and c+=['Contour Data']
|
826
|
+
a+=['3006.0080'] and b+=['SQ'] and c+=['RT ROI Observations Sequence']
|
827
|
+
a+=['3006.0082'] and b+=['IS'] and c+=['Observation Number']
|
828
|
+
a+=['3006.0084'] and b+=['IS'] and c+=['Referenced ROI Number']
|
829
|
+
a+=['3006.00A4'] and b+=['CS'] and c+=['RT ROI Interpreted Type']
|
830
|
+
a+=['3006.00A6'] and b+=['PN'] and c+=['ROI Interpreter']
|
831
|
+
a+=['3006.00C0'] and b+=['SQ'] and c+=['Frame of Reference Relationship Sequence']
|
832
|
+
a+=['3006.00C2'] and b+=['UI'] and c+=['Related Frame of Reference UID']
|
833
|
+
a+=['3006.00C4'] and b+=['CS'] and c+=['Frame of Reference Transformation Type']
|
834
|
+
a+=['3006.00C6'] and b+=['DS'] and c+=['Frame of Reference Transformation Matrix']
|
835
|
+
a+=['3006.00C8'] and b+=['LO'] and c+=['Frame of Reference Transformation Comment']
|
836
|
+
a+=['3007.0000'] and b+=['UL'] and c+=['Group Length']
|
837
|
+
a+=['300A.0000'] and b+=['UL'] and c+=['Group Length']
|
838
|
+
a+=['300A.0002'] and b+=['SH'] and c+=['RT Plan Label']
|
839
|
+
a+=['300A.0003'] and b+=['LO'] and c+=['RT Plan Name']
|
840
|
+
a+=['300A.0004'] and b+=['ST'] and c+=['RT Plan Description']
|
841
|
+
a+=['300A.0006'] and b+=['DA'] and c+=['RT Plan Date']
|
842
|
+
a+=['300A.0007'] and b+=['TM'] and c+=['RT Plan Time']
|
843
|
+
a+=['300A.000C'] and b+=['CS'] and c+=['RT Plan Geometry']
|
844
|
+
a+=['300A.0070'] and b+=['SQ'] and c+=['Fraction Group Sequence']
|
845
|
+
a+=['300A.0071'] and b+=['IS'] and c+=['Fraction Group Number']
|
846
|
+
a+=['300A.0078'] and b+=['IS'] and c+=['Number of Fractions Planned']
|
847
|
+
a+=['300A.0080'] and b+=['IS'] and c+=['Number of Beams']
|
848
|
+
a+=['300A.0086'] and b+=['DS'] and c+=['Beam Meterset']
|
849
|
+
a+=['300A.00A0'] and b+=['IS'] and c+=['Number of Brachy Application Setups']
|
850
|
+
a+=['300A.00B0'] and b+=['SQ'] and c+=['Beam Sequence']
|
851
|
+
a+=['300A.00B2'] and b+=['SH'] and c+=['Treatment Machine Name']
|
852
|
+
a+=['300A.00B3'] and b+=['CS'] and c+=['Primary Dosimeter Unit']
|
853
|
+
a+=['300A.00B4'] and b+=['DS'] and c+=['Source-Axis Distance']
|
854
|
+
a+=['300A.00B6'] and b+=['SQ'] and c+=['Beam Limiting Device Sequence']
|
855
|
+
a+=['300A.00B8'] and b+=['CS'] and c+=['RT Beam Limiting Device Type']
|
856
|
+
a+=['300A.00BC'] and b+=['IS'] and c+=['Number of Leaf/Jaw Pairs']
|
857
|
+
a+=['300A.00BE'] and b+=['DS'] and c+=['Leaf Position Boundaries']
|
858
|
+
a+=['300A.00C0'] and b+=['IS'] and c+=['Beam Number']
|
859
|
+
a+=['300A.00C2'] and b+=['LO'] and c+=['Beam Name']
|
860
|
+
a+=['300A.00C3'] and b+=['ST'] and c+=['Beam Description']
|
861
|
+
a+=['300A.00C4'] and b+=['CS'] and c+=['Beam Type']
|
862
|
+
a+=['300A.00C6'] and b+=['CS'] and c+=['Radiation Type']
|
863
|
+
a+=['300A.00C8'] and b+=['IS'] and c+=['Reference Image Number']
|
864
|
+
a+=['300A.00CE'] and b+=['CS'] and c+=['Treatment Delivery Type']
|
865
|
+
a+=['300A.00D0'] and b+=['IS'] and c+=['Number of Wedges']
|
866
|
+
a+=['300A.00D1'] and b+=['SQ'] and c+=['Wedge Sequence']
|
867
|
+
a+=['300A.00D2'] and b+=['IS'] and c+=['Wedge Number']
|
868
|
+
a+=['300A.00D3'] and b+=['CS'] and c+=['Wedge Type']
|
869
|
+
a+=['300A.00D4'] and b+=['SH'] and c+=['Wedge Id']
|
870
|
+
a+=['300A.00D5'] and b+=['IS'] and c+=['Wedge Angle']
|
871
|
+
a+=['300A.00D6'] and b+=['DS'] and c+=['Wedge Factor']
|
872
|
+
a+=['300A.00D8'] and b+=['DS'] and c+=['Wedge Orientation']
|
873
|
+
a+=['300A.00E0'] and b+=['IS'] and c+=['Number of Compensators']
|
874
|
+
a+=['300A.00E1'] and b+=['SH'] and c+=['Material Id']
|
875
|
+
a+=['300A.00ED'] and b+=['IS'] and c+=['Number of Boli']
|
876
|
+
a+=['300A.00F0'] and b+=['IS'] and c+=['Number of Blocks']
|
877
|
+
a+=['300A.00F2'] and b+=['DS'] and c+=['Total Block Tray Factor']
|
878
|
+
a+=['300A.00F4'] and b+=['SQ'] and c+=['Block Sequence']
|
879
|
+
a+=['300A.00F5'] and b+=['SH'] and c+=['Block Tray Id']
|
880
|
+
a+=['300A.00F6'] and b+=['DS'] and c+=['Source to Block Tray Distance']
|
881
|
+
a+=['300A.00F8'] and b+=['CS'] and c+=['Block Type']
|
882
|
+
a+=['300A.00FA'] and b+=['CS'] and c+=['Block Divergence']
|
883
|
+
a+=['300A.00FC'] and b+=['IS'] and c+=['Block Number']
|
884
|
+
a+=['300A.00FE'] and b+=['LO'] and c+=['Block Name']
|
885
|
+
a+=['300A.0100'] and b+=['DS'] and c+=['Block Thickness']
|
886
|
+
a+=['300A.0102'] and b+=['DS'] and c+=['Block Transmission']
|
887
|
+
a+=['300A.0104'] and b+=['IS'] and c+=['Block Number of Points']
|
888
|
+
a+=['300A.0106'] and b+=['DS'] and c+=['Block Data']
|
889
|
+
a+=['300A.010E'] and b+=['DS'] and c+=['Final Cumulative Meterset Weight']
|
890
|
+
a+=['300A.0110'] and b+=['IS'] and c+=['Number of Control Points']
|
891
|
+
a+=['300A.0111'] and b+=['SQ'] and c+=['Control Point Sequence']
|
892
|
+
a+=['300A.0112'] and b+=['IS'] and c+=['Control Point Index']
|
893
|
+
a+=['300A.0114'] and b+=['DS'] and c+=['Nominal Beam Energy']
|
894
|
+
a+=['300A.011A'] and b+=['SQ'] and c+=['Beam Limiting Device Position Sequence']
|
895
|
+
a+=['300A.011C'] and b+=['DS'] and c+=['Leaf/Jaw Positions']
|
896
|
+
a+=['300A.011E'] and b+=['DS'] and c+=['Gantry Angle']
|
897
|
+
a+=['300A.011F'] and b+=['CS'] and c+=['Gantry Rotation Direction']
|
898
|
+
a+=['300A.0120'] and b+=['DS'] and c+=['Beam Limiting Device Angle']
|
899
|
+
a+=['300A.0121'] and b+=['CS'] and c+=['Beam Limiting Device Rotation Direction']
|
900
|
+
a+=['300A.0122'] and b+=['DS'] and c+=['Patient Support Angle']
|
901
|
+
a+=['300A.0123'] and b+=['CS'] and c+=['Patient Support Rotation Direction']
|
902
|
+
a+=['300A.0125'] and b+=['DS'] and c+=['Table Top Eccentric Angle']
|
903
|
+
a+=['300A.0126'] and b+=['CS'] and c+=['Table Top Eccentric Rotation Direction']
|
904
|
+
a+=['300A.0128'] and b+=['DS'] and c+=['Table Top Vertical Position']
|
905
|
+
a+=['300A.0129'] and b+=['DS'] and c+=['Table Top Longitudinal Position']
|
906
|
+
a+=['300A.012A'] and b+=['DS'] and c+=['Table Top Lateral Position']
|
907
|
+
a+=['300A.012C'] and b+=['DS'] and c+=['Isocenter Position']
|
908
|
+
a+=['300A.0130'] and b+=['DS'] and c+=['Source to Surface Distance']
|
909
|
+
a+=['300A.0134'] and b+=['DS'] and c+=['Cumulative Meterset Weight']
|
910
|
+
a+=['300A.0180'] and b+=['SQ'] and c+=['Patient Setup Sequence']
|
911
|
+
a+=['300A.0182'] and b+=['IS'] and c+=['Patient Setup Number']
|
912
|
+
a+=['300A.01D2'] and b+=['DS'] and c+=['Table Top Vertical Setup Displacement']
|
913
|
+
a+=['300A.01D4'] and b+=['DS'] and c+=['Table Top Longitudinal Setup Displacement']
|
914
|
+
a+=['300A.01D6'] and b+=['DS'] and c+=['Table Top Lateral Setup Displacement']
|
915
|
+
a+=['300A.0212'] and b+=['IS'] and c+=['Source Number']
|
916
|
+
a+=['300A.0214'] and b+=['CS'] and c+=['Source Type']
|
917
|
+
a+=['300C.0000'] and b+=['UL'] and c+=['Group Length']
|
918
|
+
a+=['300C.0002'] and b+=['SQ'] and c+=['Referenced RT Plan Sequence']
|
919
|
+
a+=['300C.0004'] and b+=['SQ'] and c+=['Referenced Beam Sequence']
|
920
|
+
a+=['300C.0006'] and b+=['IS'] and c+=['Referenced Beam Number']
|
921
|
+
a+=['300C.0020'] and b+=['SQ'] and c+=['Referenced Fraction Group Sequence']
|
922
|
+
a+=['300C.0022'] and b+=['IS'] and c+=['Referenced Fraction Group Number']
|
923
|
+
a+=['300C.0042'] and b+=['SQ'] and c+=['Referenced Reference Image Sequence']
|
924
|
+
a+=['300C.0060'] and b+=['SQ'] and c+=['Referenced Structure Set Sequence']
|
925
|
+
a+=['300C.006A'] and b+=['IS'] and c+=['Referenced Patient Setup Number']
|
926
|
+
a+=['300C.0080'] and b+=['SQ'] and c+=['Referenced Dose Sequence']
|
927
|
+
a+=['300E.0000'] and b+=['UL'] and c+=['Group Length']
|
928
|
+
a+=['300E.0002'] and b+=['CS'] and c+=['Approval Status']
|
929
|
+
a+=['3241.0000'] and b+=['UL'] and c+=['Group Length']
|
930
|
+
a+=['5000.0000'] and b+=['UL'] and c+=['Group Length']
|
931
|
+
a+=['5000.0005'] and b+=['US'] and c+=['Curve Dimensions']
|
932
|
+
a+=['5000.0010'] and b+=['US'] and c+=['Number of Points']
|
933
|
+
a+=['5000.0020'] and b+=['CS'] and c+=['Type of Data']
|
934
|
+
a+=['5000.0030'] and b+=['SH'] and c+=['Axis Units']
|
935
|
+
a+=['5000.0103'] and b+=['US'] and c+=['Data Value Representation']
|
936
|
+
a+=['5000.3000'] and b+=['OB'] and c+=['Curve Data']
|
937
|
+
a+=['5001.0000'] and b+=['UL'] and c+=['Group Length']
|
938
|
+
a+=['5001.0010'] and b+=['US'] and c+=['Number of Points'] # ?? check with other sources
|
939
|
+
a+=['5002.0000'] and b+=['UL'] and c+=['Group Length']
|
940
|
+
a+=['5002.0005'] and b+=['US'] and c+=['Curve Dimensions']
|
941
|
+
a+=['5002.0010'] and b+=['US'] and c+=['Number of Points']
|
942
|
+
a+=['5002.0020'] and b+=['CS'] and c+=['Type of Data']
|
943
|
+
a+=['5002.0030'] and b+=['SH'] and c+=['Axis Units']
|
944
|
+
a+=['5002.0103'] and b+=['US'] and c+=['Data Value Representation']
|
945
|
+
a+=['5002.3000'] and b+=['OB'] and c+=['Curve Data']
|
946
|
+
a+=['7FE0.0000'] and b+=['UL'] and c+=['Group Length']
|
947
|
+
a+=['7FE0.0010'] and b+=['OW'] and c+=['Pixel Data']
|
948
|
+
a+=['FFFC.FFFC'] and b+=['OB'] and c+=['Data Set Trailing Padding']
|
949
|
+
a+=['FFFE.E000'] and b+=['()'] and c+=['Item']
|
950
|
+
a+=['FFFE.E00D'] and b+=['()'] and c+=['Sequence Delimitation Item']
|
951
|
+
a+=['FFFE.E0DD'] and b+=['()'] and c+=['Sequence Delimitation Item']
|
952
|
+
a+=['dumm.dumm'] and b+=['SS'] and c+=['Dummy entry 1'] # To get the 'SS' type in the list.
|
953
|
+
|
954
|
+
@lib_labels=a
|
955
|
+
@lib_types=b
|
956
|
+
@lib_names=c
|
957
|
+
end
|
958
|
+
|
959
|
+
|
960
|
+
# Process a series of numbers to return a string containing all the numbers separated with the separator "/" between the numbers.
|
961
|
+
def process_numbers(length, type, size)
|
962
|
+
bin = @file.read(size)
|
963
|
+
data=""
|
964
|
+
case type
|
965
|
+
when "UL"
|
966
|
+
temp1 = get_UL(bin)
|
967
|
+
when "SL"
|
968
|
+
temp1 = get_SL(bin)
|
969
|
+
when "US"
|
970
|
+
temp1 = get_US(bin)
|
971
|
+
when "SS"
|
972
|
+
temp1 = get_SS(bin)
|
973
|
+
when "FD"
|
974
|
+
temp1 = get_FD(bin)
|
975
|
+
else
|
976
|
+
puts "Warning: Type "+type+"not supported in method process_numbers()."
|
977
|
+
end
|
978
|
+
remain = (length-size)/size
|
979
|
+
remain.times do
|
980
|
+
bin = @file.read(size)
|
981
|
+
case type
|
982
|
+
when "UL"
|
983
|
+
temp2 = get_UL(bin)
|
984
|
+
when "SL"
|
985
|
+
temp2 = get_SL(bin)
|
986
|
+
when "US"
|
987
|
+
temp2 = get_US(bin)
|
988
|
+
when "SS"
|
989
|
+
temp2 = get_SS(bin)
|
990
|
+
when "FD"
|
991
|
+
temp2 = get_FD(bin)
|
992
|
+
else
|
993
|
+
puts "Warning: Type "+type+"not supported in method process_numbers()."
|
994
|
+
end
|
995
|
+
data = temp1.to_s+"/"+temp2.to_s
|
996
|
+
temp1 = data
|
997
|
+
end
|
998
|
+
return data
|
999
|
+
end
|
1000
|
+
|
1001
|
+
# Returns a byte integer (1 byte), from the supplied variable.
|
1002
|
+
def get_BYTE(bin)
|
1003
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1004
|
+
elements = bin.size
|
1005
|
+
if @endian
|
1006
|
+
# Native byte order:
|
1007
|
+
if elements > 1
|
1008
|
+
num=bin.unpack('C*')
|
1009
|
+
else
|
1010
|
+
num=bin.unpack('C*')[0]
|
1011
|
+
end
|
1012
|
+
else
|
1013
|
+
# Network byte order: (Unknown what to use here)
|
1014
|
+
puts "Warning: Method get_BYTE not tested with this endian yet!"
|
1015
|
+
if elements > 1
|
1016
|
+
num=bin.unpack('C*')
|
1017
|
+
else
|
1018
|
+
num=bin.unpack('C*')[0]
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
return num
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
|
1025
|
+
# Returns a unsigned short (2 bytes), from the supplied variable.
|
1026
|
+
def get_US(bin)
|
1027
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1028
|
+
elements = bin.size/2
|
1029
|
+
if @endian
|
1030
|
+
# Native byte order:
|
1031
|
+
if elements > 1
|
1032
|
+
num=bin.unpack('S*') # or v (little endian (?))
|
1033
|
+
else
|
1034
|
+
num=bin.unpack('S*')[0]
|
1035
|
+
end
|
1036
|
+
else
|
1037
|
+
# Network byte order:
|
1038
|
+
if elements > 1
|
1039
|
+
num=bin.unpack('n*')
|
1040
|
+
else
|
1041
|
+
num=bin.unpack('n*')[0]
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
return num
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
|
1048
|
+
# Returns a signed short (2 bytes), from the supplied variable.
|
1049
|
+
def get_SS(bin)
|
1050
|
+
elements = bin.size/2
|
1051
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1052
|
+
if @endian
|
1053
|
+
# Native byte order
|
1054
|
+
if elements > 1
|
1055
|
+
num=bin.unpack('s*')
|
1056
|
+
else
|
1057
|
+
num=bin.unpack('s*')[0]
|
1058
|
+
end
|
1059
|
+
else
|
1060
|
+
# Unknown what unpack code to use here:
|
1061
|
+
if elements > 1
|
1062
|
+
num=bin.unpack('s*')
|
1063
|
+
else
|
1064
|
+
num=bin.unpack('s*')[0]
|
1065
|
+
end
|
1066
|
+
puts "Warning: Oppositve endian for signed short is not working yet!"
|
1067
|
+
end
|
1068
|
+
return num
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
|
1072
|
+
# Returns an unsigned long (4 bytes), from the supplied variable.
|
1073
|
+
def get_UL(bin)
|
1074
|
+
elements = bin.size/4
|
1075
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1076
|
+
if @endian
|
1077
|
+
# Unsigned native integer:
|
1078
|
+
if elements > 1
|
1079
|
+
num=bin.unpack('I*')
|
1080
|
+
else
|
1081
|
+
num=bin.unpack('I*')[0]
|
1082
|
+
end
|
1083
|
+
else
|
1084
|
+
# Unsigned long in network byte order:
|
1085
|
+
if elements > 1
|
1086
|
+
num=bin.unpack('N*')
|
1087
|
+
else
|
1088
|
+
num=bin.unpack('N*')[0]
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
return num
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
|
1095
|
+
# Returns a signed long (4 bytes), from the supplied variable.
|
1096
|
+
def get_SL(bin)
|
1097
|
+
elements = bin.size/4
|
1098
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1099
|
+
if @endian
|
1100
|
+
# Signed native long integer:
|
1101
|
+
if elements > 1
|
1102
|
+
num=bin.unpack('l*')
|
1103
|
+
else
|
1104
|
+
num=bin.unpack('l*')[0]
|
1105
|
+
end
|
1106
|
+
else
|
1107
|
+
puts "Warning: Oppositve endian for signed long is not working yet!"
|
1108
|
+
if elements > 1
|
1109
|
+
num=bin.unpack('l*')
|
1110
|
+
else
|
1111
|
+
num=bin.unpack('l*')[0]
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
return num
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
|
1118
|
+
# Returns a floating point double (8 bytes), from the supplied variable.
|
1119
|
+
def get_FD(bin)
|
1120
|
+
elements = bin.size/8
|
1121
|
+
# If bin contains several numbers, unpack and return in an array. If just one number, return the number:
|
1122
|
+
if @endian
|
1123
|
+
# Double in little-endian byte order:
|
1124
|
+
if elements > 1
|
1125
|
+
num=bin.unpack('E*')
|
1126
|
+
else
|
1127
|
+
num=bin.unpack('E*')[0]
|
1128
|
+
end
|
1129
|
+
else
|
1130
|
+
# Double in network byte order:
|
1131
|
+
if elements > 1
|
1132
|
+
num=bin.unpack('G*')
|
1133
|
+
else
|
1134
|
+
num=bin.unpack('G*')[0]
|
1135
|
+
end
|
1136
|
+
end
|
1137
|
+
return num
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
|
1141
|
+
# Checks the Transfer Syntax UID tag and updates class variables to prepare for correct reading of DICOM file.
|
1142
|
+
def process_syntax(value)
|
1143
|
+
case value.rstrip
|
1144
|
+
# Some variations with uncompressed pixel data:
|
1145
|
+
when "1.2.840.10008.1.2"
|
1146
|
+
# Implicit VR, Little Endian
|
1147
|
+
@rest_explicit = false
|
1148
|
+
@rest_endian = false
|
1149
|
+
@compression = false
|
1150
|
+
when "1.2.840.10008.1.2.1"
|
1151
|
+
# Explicit VR, Little Endian
|
1152
|
+
@rest_explicit = true
|
1153
|
+
@rest_endian = false
|
1154
|
+
@compression = false
|
1155
|
+
when "1.2.840.10008.1.2.2"
|
1156
|
+
# Explicit VR, Big Endian
|
1157
|
+
@rest_explicit = true
|
1158
|
+
@rest_endian = true
|
1159
|
+
@compression = false
|
1160
|
+
# Compressed pixel data, using various compression algorithms:
|
1161
|
+
when "1.2.840.10008.1.2.4.50"
|
1162
|
+
@rest_explicit = true
|
1163
|
+
@rest_endian = false
|
1164
|
+
@compression = "JPEG Baseline"
|
1165
|
+
when "1.2.840.10008.1.2.4.51"
|
1166
|
+
@rest_explicit = true
|
1167
|
+
@rest_endian = false
|
1168
|
+
@compression = "JPEG Extended (Process 2 & 4)"
|
1169
|
+
when "1.2.840.10008.1.2.4.70"
|
1170
|
+
@rest_explicit = true
|
1171
|
+
@rest_endian = false
|
1172
|
+
@compression = "JPEG Lossless, Non-Hierarchical"
|
1173
|
+
when "1.2.840.10008.1.2.4.90"
|
1174
|
+
@rest_explicit = true
|
1175
|
+
@rest_endian = false
|
1176
|
+
@compression = "JPEG 2000, Lossless Only"
|
1177
|
+
when "1.2.840.10008.1.2.4.91"
|
1178
|
+
@rest_explicit = true
|
1179
|
+
@rest_endian = false
|
1180
|
+
@compression = "JPEG 2000, Lossy"
|
1181
|
+
else
|
1182
|
+
# For everything else, assume unknown compression algorithm, with Explicit VR, Little Endian:
|
1183
|
+
puts "Warning: Unknown Transfer Syntax UID: "+ value.to_s
|
1184
|
+
puts "Handling for this data type has not been implemented, errors may occur."
|
1185
|
+
@rest_explicit = true
|
1186
|
+
@rest_endian = false
|
1187
|
+
@compression = "Unknown"
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
|
1192
|
+
# Checks the endianness of the system. Returns false if little endian, true if big endian.
|
1193
|
+
def check_sys_endian()
|
1194
|
+
x = 0xdeadbeef
|
1195
|
+
endian_type = {
|
1196
|
+
Array(x).pack("V*") => false, #:little
|
1197
|
+
Array(x).pack("N*") => true #:big
|
1198
|
+
}
|
1199
|
+
return endian_type[Array(x).pack("L*")]
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
|
1203
|
+
end # End of class.
|
1204
|
+
end # End of module.
|