dicom 0.6.1 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +42 -20
- data/DOCUMENTATION +117 -71
- data/README +3 -3
- data/lib/dicom.rb +23 -12
- data/lib/{Anonymizer.rb → dicom/Anonymizer.rb} +101 -79
- data/lib/{DClient.rb → dicom/DClient.rb} +12 -11
- data/lib/{DLibrary.rb → dicom/DLibrary.rb} +53 -31
- data/lib/dicom/DObject.rb +1579 -0
- data/lib/{DRead.rb → dicom/DRead.rb} +42 -43
- data/lib/{DServer.rb → dicom/DServer.rb} +34 -20
- data/lib/{DWrite.rb → dicom/DWrite.rb} +27 -31
- data/lib/{Dictionary.rb → dicom/Dictionary.rb} +434 -32
- data/lib/dicom/FileHandler.rb +50 -0
- data/lib/{Link.rb → dicom/Link.rb} +312 -167
- data/lib/{Stream.rb → dicom/Stream.rb} +1 -1
- data/lib/dicom/ruby_extensions.rb +47 -0
- metadata +16 -15
- data/lib/DObject.rb +0 -1194
- data/lib/ruby_extensions.rb +0 -36
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2008-
|
1
|
+
# Copyright 2008-2010 Christoffer Lervag
|
2
2
|
|
3
3
|
# Some notes about this DICOM file reading class:
|
4
4
|
# In addition to reading files that are compliant to DICOM 3 Part 10, the philosophy of this library
|
@@ -11,20 +11,19 @@ module DICOM
|
|
11
11
|
# Class for reading the data from a DICOM file:
|
12
12
|
class DRead
|
13
13
|
|
14
|
-
attr_reader :success, :names, :tags, :
|
14
|
+
attr_reader :success, :names, :tags, :vr, :lengths, :values, :bin, :levels, :explicit, :file_endian, :msg
|
15
15
|
|
16
16
|
# Initialize the DRead instance.
|
17
17
|
def initialize(string=nil, options={})
|
18
18
|
# Process option values, setting defaults for the ones that are not specified:
|
19
|
-
@lib = options[:lib] || DLibrary.new
|
20
19
|
@sys_endian = options[:sys_endian] || false
|
21
|
-
@
|
20
|
+
@bin_string = options[:bin]
|
22
21
|
@transfer_syntax = options[:syntax]
|
23
22
|
# Initiate the variables that are used during file reading:
|
24
23
|
init_variables
|
25
24
|
|
26
25
|
# Are we going to read from a file, or read from a binary string:
|
27
|
-
if @
|
26
|
+
if @bin_string
|
28
27
|
# Read from the provided binary string:
|
29
28
|
@str = string
|
30
29
|
else
|
@@ -43,7 +42,7 @@ module DICOM
|
|
43
42
|
# Create a Stream instance to handle the decoding of content from this binary string:
|
44
43
|
@stream = Stream.new(@str, @file_endian, @explicit)
|
45
44
|
# Do not check for header information when supplied a (network) binary string:
|
46
|
-
unless @
|
45
|
+
unless @bin_string
|
47
46
|
# Read and verify the DICOM header:
|
48
47
|
header = check_header
|
49
48
|
# If the file didnt have the expected header, we will attempt to read
|
@@ -66,11 +65,11 @@ module DICOM
|
|
66
65
|
# Post processing:
|
67
66
|
# Assume file has been read successfully:
|
68
67
|
@success = true
|
69
|
-
# Check if the last element was read out correctly (that the length of its data (@
|
68
|
+
# Check if the last element was read out correctly (that the length of its data (@bin.last.length)
|
70
69
|
# corresponds to that expected by the length specified in the DICOM file (@lengths.last)).
|
71
70
|
# We only run this test if the last element has a positive expectation value, obviously.
|
72
71
|
if @lengths.last.to_i > 0
|
73
|
-
if @
|
72
|
+
if @bin.last.length != @lengths.last
|
74
73
|
@msg << "Error! The data content read from file does not match the length specified for the tag #{@tags.last}. It seems this is either an invalid or corrupt DICOM file. Returning."
|
75
74
|
@success = false
|
76
75
|
return
|
@@ -176,17 +175,17 @@ module DICOM
|
|
176
175
|
return false
|
177
176
|
end
|
178
177
|
# STEP 2: ------------------------------------------------------
|
179
|
-
# Access library to retrieve the data element name and
|
180
|
-
lib_data =
|
178
|
+
# Access library to retrieve the data element name and VR from the tag we just read:
|
179
|
+
lib_data = LIBRARY.get_name_vr(tag)
|
181
180
|
name = lib_data[0]
|
182
181
|
vr = lib_data[1]
|
183
182
|
# (Note: VR will be overwritten if the DICOM file contains VR)
|
184
183
|
|
185
184
|
# STEP 3: ----------------------------------------------------
|
186
|
-
# Read
|
187
|
-
tag_info =
|
188
|
-
|
189
|
-
|
185
|
+
# Read VR (if it exists) and the length value:
|
186
|
+
tag_info = read_vr_length(vr,tag)
|
187
|
+
vr = tag_info[0]
|
188
|
+
level_vr = vr
|
190
189
|
length = tag_info[1]
|
191
190
|
|
192
191
|
# STEP 4: ----------------------------------------
|
@@ -195,37 +194,37 @@ module DICOM
|
|
195
194
|
if @enc_image and tag == "FFFE,E000"
|
196
195
|
# The first item appearing after the image element is a 'normal' item, the rest hold image data.
|
197
196
|
# Note that the first item will contain data if there are multiple images, and so must be read.
|
198
|
-
|
197
|
+
vr = "OW" # how about alternatives like OB?
|
199
198
|
# Modify name of item if this is an item that holds pixel data:
|
200
199
|
if @tags.last != "7FE0,0010"
|
201
200
|
name = "Pixel Data Item"
|
202
201
|
end
|
203
202
|
end
|
204
203
|
# Read the value of the element (if it contains data, and it is not a sequence or ordinary item):
|
205
|
-
if length.to_i > 0 and
|
204
|
+
if length.to_i > 0 and vr != "SQ" and vr != "()"
|
206
205
|
# Read the element's value (data):
|
207
|
-
data = read_value(
|
206
|
+
data = read_value(vr,length)
|
208
207
|
value = data[0]
|
209
|
-
|
208
|
+
bin = data[1]
|
210
209
|
else
|
211
210
|
# Data element has no value (data).
|
212
211
|
# Special case: Check if pixel data element is sequenced:
|
213
212
|
if tag == "7FE0,0010"
|
214
|
-
# Change name and
|
213
|
+
# Change name and vr of pixel data element if it does not contain data itself:
|
215
214
|
name = "Encapsulated Pixel Data"
|
216
|
-
|
215
|
+
level_vr = "SQ"
|
217
216
|
@enc_image = true
|
218
217
|
end
|
219
218
|
end # of if length.to_i > 0
|
220
219
|
# Set the hiearchy level of this data element:
|
221
|
-
set_level(
|
220
|
+
set_level(level_vr, length, tag, name)
|
222
221
|
# Transfer the gathered data to arrays and return true:
|
223
222
|
@names << name
|
224
223
|
@tags << tag
|
225
|
-
@
|
224
|
+
@vr << vr
|
226
225
|
@lengths << length
|
227
226
|
@values << value
|
228
|
-
@
|
227
|
+
@bin << bin
|
229
228
|
return true
|
230
229
|
end # of process_data_element
|
231
230
|
|
@@ -252,8 +251,8 @@ module DICOM
|
|
252
251
|
end
|
253
252
|
|
254
253
|
|
255
|
-
# Reads and returns data element
|
256
|
-
def
|
254
|
+
# Reads and returns data element VR (2 bytes) and data element LENGTH (Varying length; 2-6 bytes).
|
255
|
+
def read_vr_length(vr,tag)
|
257
256
|
# Structure will differ, dependent on whether we have explicit or implicit encoding:
|
258
257
|
pre_skip = 0
|
259
258
|
bytes = 0
|
@@ -261,14 +260,14 @@ module DICOM
|
|
261
260
|
if @explicit == true
|
262
261
|
# Step 1: Read VR (if it exists)
|
263
262
|
unless tag == "FFFE,E000" or tag == "FFFE,E00D" or tag == "FFFE,E0DD"
|
264
|
-
# Read the element's
|
265
|
-
|
263
|
+
# Read the element's vr (2 bytes - since we are not dealing with an item related element):
|
264
|
+
vr = @stream.decode(2, "STR")
|
266
265
|
@integrated_lengths[@integrated_lengths.length-1] += 2
|
267
266
|
end
|
268
267
|
# Step 2: Read length
|
269
|
-
# Three possible structures for value length here, dependent on element
|
270
|
-
case
|
271
|
-
when "OB","OW","SQ","UN"
|
268
|
+
# Three possible structures for value length here, dependent on element vr:
|
269
|
+
case vr
|
270
|
+
when "OB","OW","SQ","UN","UT"
|
272
271
|
# 6 bytes total:
|
273
272
|
# Two empty bytes first:
|
274
273
|
pre_skip = 2
|
@@ -276,11 +275,11 @@ module DICOM
|
|
276
275
|
bytes = 4
|
277
276
|
when "()"
|
278
277
|
# 4 bytes:
|
279
|
-
# For elements "FFFE,E000", "FFFE,E00D" and "FFFE,E0DD"
|
278
|
+
# For elements "FFFE,E000", "FFFE,E00D" and "FFFE,E0DD":
|
280
279
|
bytes = 4
|
281
280
|
else
|
282
281
|
# 2 bytes:
|
283
|
-
# For all the other element
|
282
|
+
# For all the other element vr, value length is 2 bytes:
|
284
283
|
bytes = 2
|
285
284
|
end
|
286
285
|
else
|
@@ -306,23 +305,23 @@ module DICOM
|
|
306
305
|
# If it is not, it may indicate a file that is not standards compliant or it might even not be a DICOM file.
|
307
306
|
@msg += ["Warning: Odd number of bytes in data element's length occured. This is a violation of the DICOM standard, but program will attempt to read the rest of the file anyway."]
|
308
307
|
end
|
309
|
-
return [
|
310
|
-
end # of
|
308
|
+
return [vr, length]
|
309
|
+
end # of read_vr_length
|
311
310
|
|
312
311
|
|
313
312
|
# Reads and returns data element VALUE (Of varying length - which is determined at an earlier stage).
|
314
|
-
def read_value(
|
313
|
+
def read_value(vr, length)
|
315
314
|
# Extract the binary data:
|
316
315
|
bin = @stream.extract(length)
|
317
316
|
@integrated_lengths[@integrated_lengths.size-1] += length
|
318
317
|
# Decode data?
|
319
318
|
# Some data elements (like those containing image data, compressed data or unknown data),
|
320
319
|
# will not be decoded here.
|
321
|
-
unless
|
320
|
+
unless vr == "OW" or vr == "OB" or vr == "OF" or vr == "UN"
|
322
321
|
# "Rewind" and extract the value from this binary data:
|
323
322
|
@stream.skip(-length)
|
324
323
|
# Decode data:
|
325
|
-
value = @stream.decode(length,
|
324
|
+
value = @stream.decode(length, vr)
|
326
325
|
if not value.is_a?(Array)
|
327
326
|
data = value
|
328
327
|
else
|
@@ -341,7 +340,7 @@ module DICOM
|
|
341
340
|
|
342
341
|
# Sets the level of the current element in the hiearchy.
|
343
342
|
# The default (top) level is zero.
|
344
|
-
def set_level(
|
343
|
+
def set_level(vr, length, tag, name)
|
345
344
|
# Set the level of this element:
|
346
345
|
@levels += [@current_level]
|
347
346
|
# Determine if there is a level change for the following element:
|
@@ -350,7 +349,7 @@ module DICOM
|
|
350
349
|
# Note the following exception:
|
351
350
|
# If data element is an "Item", and it contains data (image fragment) directly, which is to say,
|
352
351
|
# not in its sub-elements, we should not increase the level. (This is fixed in the process_data_element method.)
|
353
|
-
if
|
352
|
+
if vr == "SQ"
|
354
353
|
increase = true
|
355
354
|
elsif name == "Item"
|
356
355
|
increase = true
|
@@ -363,7 +362,7 @@ module DICOM
|
|
363
362
|
if length.to_i != 0
|
364
363
|
@hierarchy << [length, @integrated_lengths.last]
|
365
364
|
else
|
366
|
-
@hierarchy <<
|
365
|
+
@hierarchy << vr
|
367
366
|
end
|
368
367
|
end
|
369
368
|
# Need to check whether a previous sequence or item has ended, if so the level must be decreased by one:
|
@@ -448,7 +447,7 @@ module DICOM
|
|
448
447
|
end
|
449
448
|
end
|
450
449
|
# Query the library with our particular transfer syntax string:
|
451
|
-
result =
|
450
|
+
result = LIBRARY.process_transfer_syntax(@transfer_syntax)
|
452
451
|
# Result is a 3-element array: [Validity of ts, explicitness, endianness]
|
453
452
|
unless result[0]
|
454
453
|
@msg+=["Warning: Invalid/unknown transfer syntax! Will try reading the file, but errors may occur."]
|
@@ -487,10 +486,10 @@ module DICOM
|
|
487
486
|
# Arrays that will hold information from the elements of the DICOM file:
|
488
487
|
@names = Array.new
|
489
488
|
@tags = Array.new
|
490
|
-
@
|
489
|
+
@vr = Array.new
|
491
490
|
@lengths = Array.new
|
492
491
|
@values = Array.new
|
493
|
-
@
|
492
|
+
@bin = Array.new
|
494
493
|
@levels = Array.new
|
495
494
|
# Array that will holde any messages generated while reading the DICOM file:
|
496
495
|
@msg = Array.new
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2009 Christoffer Lervag
|
1
|
+
# Copyright 2009-2010 Christoffer Lervag
|
2
2
|
|
3
3
|
module DICOM
|
4
4
|
|
@@ -6,16 +6,25 @@ module DICOM
|
|
6
6
|
# which will act as a simple storage node (a server that receives images).
|
7
7
|
class DServer
|
8
8
|
|
9
|
-
|
9
|
+
|
10
|
+
# Run the server and take a block for initializing.
|
11
|
+
def self.run(port=104, path='./received/', &block)
|
12
|
+
server = DServer.new(port)
|
13
|
+
server.instance_eval(&block)
|
14
|
+
server.start_scp(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Accessible attributes:
|
18
|
+
attr_accessor :host_ae, :max_package_size, :port, :timeout, :verbose, :file_handler
|
10
19
|
attr_reader :errors, :notices
|
11
20
|
|
12
21
|
# Initialize the instance with a host adress and a port number.
|
13
|
-
def initialize(port, options={})
|
22
|
+
def initialize(port=104, options={})
|
14
23
|
require 'socket'
|
15
24
|
# Required parameters:
|
16
25
|
@port = port
|
17
26
|
# Optional parameters (and default values):
|
18
|
-
@
|
27
|
+
@file_handler = options[:file_handler] || FileHandler
|
19
28
|
@host_ae = options[:host_ae] || "RUBY_DICOM"
|
20
29
|
@max_package_size = options[:max_package_size] || 32768 # 16384
|
21
30
|
@timeout = options[:timeout] || 10 # seconds
|
@@ -70,10 +79,9 @@ module DICOM
|
|
70
79
|
@valid_abstract_syntaxes = Array.new
|
71
80
|
end
|
72
81
|
|
73
|
-
|
74
|
-
# Start a Storage Content Provider (SCP).
|
82
|
+
# Start a Service Class Provider (SCP).
|
75
83
|
# This service will receive and store DICOM files in a specified folder.
|
76
|
-
def start_scp(path)
|
84
|
+
def start_scp(path='./received/')
|
77
85
|
add_notice("Starting SCP server...")
|
78
86
|
add_notice("*********************************")
|
79
87
|
# Initiate server:
|
@@ -82,16 +90,17 @@ module DICOM
|
|
82
90
|
loop do
|
83
91
|
Thread.start(@scp.accept) do |session|
|
84
92
|
# Initialize the network package handler for this session:
|
85
|
-
link = Link.new(:host_ae => @host_ae, :max_package_size => @max_package_size, :timeout => @timeout, :verbose => @verbose)
|
93
|
+
link = Link.new(:host_ae => @host_ae, :max_package_size => @max_package_size, :timeout => @timeout, :verbose => @verbose, :file_handler => @file_handler)
|
86
94
|
add_notice("Connection established (name: #{session.peeraddr[2]}, ip: #{session.peeraddr[3]})")
|
87
95
|
# Receive an incoming message:
|
88
|
-
segments = link.receive_single_transmission(session)
|
96
|
+
#segments = link.receive_single_transmission(session)
|
97
|
+
segments = link.receive_multiple_transmissions(session)
|
89
98
|
info = segments.first
|
90
99
|
# Interpret the received message:
|
91
100
|
if info[:valid]
|
92
101
|
association_error = check_association_request(info)
|
93
102
|
unless association_error
|
94
|
-
syntax_result = check_syntax_requests(info)
|
103
|
+
syntax_result = check_syntax_requests(link, info)
|
95
104
|
link.handle_association_accept(session, info, syntax_result)
|
96
105
|
if syntax_result == "00" # Normal (no error)
|
97
106
|
add_notice("An incoming association request and its abstract syntax has been accepted.")
|
@@ -100,10 +109,15 @@ module DICOM
|
|
100
109
|
link.handle_release(session)
|
101
110
|
else
|
102
111
|
# Process the incoming data:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
112
|
+
success, message = link.handle_incoming_data(session, path)
|
113
|
+
if success
|
114
|
+
add_notice(message)
|
115
|
+
# Send a receipt for received data:
|
116
|
+
link.handle_response(session)
|
117
|
+
else
|
118
|
+
# Something has gone wrong:
|
119
|
+
add_error(message)
|
120
|
+
end
|
107
121
|
# Release the connection:
|
108
122
|
link.handle_release(session)
|
109
123
|
end
|
@@ -171,17 +185,17 @@ module DICOM
|
|
171
185
|
|
172
186
|
# Check if the requested abstract syntax & transfer syntax are supported:
|
173
187
|
# Error codes are given in the official dicom document, part 08_08, page 39
|
174
|
-
def check_syntax_requests(info)
|
188
|
+
def check_syntax_requests(link, info)
|
175
189
|
result = "00" # (no error)
|
176
190
|
# We will accept any transfer syntax (as long as it is recognized in the library):
|
177
191
|
# (Weakness: Only checking the first occuring transfer syntax for now)
|
178
|
-
transfer_syntax = info
|
179
|
-
unless
|
192
|
+
transfer_syntax = link.extract_transfer_syntax(info)
|
193
|
+
unless LIBRARY.check_ts_validity(transfer_syntax)
|
180
194
|
result = "04" # transfer syntax not supported
|
181
195
|
add_error("Warning: Unsupported transfer syntax received in incoming association request. (#{transfer_syntax})")
|
182
196
|
end
|
183
197
|
# Check that abstract syntax is among the ones that have been set as valid for this server instance:
|
184
|
-
abstract_syntax = info
|
198
|
+
abstract_syntax = link.extract_abstract_syntax(info)
|
185
199
|
unless @valid_abstract_syntaxes.include?(abstract_syntax)
|
186
200
|
result = "03" # abstract syntax not supported
|
187
201
|
end
|
@@ -286,5 +300,5 @@ module DICOM
|
|
286
300
|
end
|
287
301
|
|
288
302
|
|
289
|
-
end
|
290
|
-
end
|
303
|
+
end # of class
|
304
|
+
end # of module
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2008-
|
1
|
+
# Copyright 2008-2010 Christoffer Lervag
|
2
2
|
|
3
3
|
# Some notes about this DICOM file writing class:
|
4
4
|
# In its current state, this class will always try to write the file such that it is compliant to the
|
@@ -14,22 +14,21 @@ module DICOM
|
|
14
14
|
# Class for writing the data from a DObject to a valid DICOM file.
|
15
15
|
class DWrite
|
16
16
|
|
17
|
-
attr_writer :tags, :
|
17
|
+
attr_writer :tags, :vr, :lengths, :bin, :rest_endian, :rest_explicit
|
18
18
|
attr_reader :success, :msg
|
19
19
|
|
20
20
|
# Initialize the DWrite instance.
|
21
21
|
def initialize(file_name=nil, options={})
|
22
22
|
# Process option values, setting defaults for the ones that are not specified:
|
23
|
-
@lib = options[:lib] || DLibrary.new
|
24
23
|
@sys_endian = options[:sys_endian] || false
|
25
24
|
@file_name = file_name
|
26
25
|
@transfer_syntax = options[:transfer_syntax] || "1.2.840.10008.1.2" # Implicit, little endian
|
27
26
|
|
28
27
|
# Create arrays used for storing data element information:
|
29
28
|
@tags = Array.new
|
30
|
-
@
|
29
|
+
@vr = Array.new
|
31
30
|
@lengths = Array.new
|
32
|
-
@
|
31
|
+
@bin = Array.new
|
33
32
|
# Array for storing error/warning messages:
|
34
33
|
@msg = Array.new
|
35
34
|
# Default values that may be overwritten by the user:
|
@@ -99,12 +98,12 @@ module DICOM
|
|
99
98
|
if value_length > size
|
100
99
|
# Start writing content from this data element,
|
101
100
|
# then continue writing its content in the next segments.
|
102
|
-
# Write tag &
|
101
|
+
# Write tag & vr/length:
|
103
102
|
write_tag(i)
|
104
|
-
|
103
|
+
write_vr_length(i)
|
105
104
|
# Find out how much of this element's value we can write, then add it:
|
106
105
|
available = size - @stream.length
|
107
|
-
value_first_part = @
|
106
|
+
value_first_part = @bin[i].slice(0, available)
|
108
107
|
@stream.add_last(value_first_part)
|
109
108
|
# Add segment and reset:
|
110
109
|
segments << @stream.string
|
@@ -114,7 +113,7 @@ module DICOM
|
|
114
113
|
index = available
|
115
114
|
# Iterate through the data element's value until we have added it entirely:
|
116
115
|
remaining_segments.times do
|
117
|
-
value = @
|
116
|
+
value = @bin[i].slice(index, size)
|
118
117
|
index = index + size
|
119
118
|
@stream.add_last(value)
|
120
119
|
# Add segment and reset:
|
@@ -183,14 +182,14 @@ module DICOM
|
|
183
182
|
tag = @stream.encode_tag("0002,0012")
|
184
183
|
@stream.add_last(tag)
|
185
184
|
@stream.encode_last("UI", "STR")
|
186
|
-
value = @stream.encode_value(
|
185
|
+
value = @stream.encode_value(UID, "STR")
|
187
186
|
@stream.encode_last(value.length, "US")
|
188
187
|
@stream.add_last(value)
|
189
188
|
# Implementation Version Name:
|
190
189
|
tag = @stream.encode_tag("0002,0013")
|
191
190
|
@stream.add_last(tag)
|
192
191
|
@stream.encode_last("SH", "STR")
|
193
|
-
value = @stream.encode_value(
|
192
|
+
value = @stream.encode_value(NAME, "STR")
|
194
193
|
@stream.encode_last(value.length, "US")
|
195
194
|
@stream.add_last(value)
|
196
195
|
# Group length:
|
@@ -201,9 +200,9 @@ module DICOM
|
|
201
200
|
# Length:
|
202
201
|
length = @stream.encode(4, "US")
|
203
202
|
@stream.add_first(length)
|
204
|
-
#
|
205
|
-
|
206
|
-
@stream.add_first(
|
203
|
+
# VR:
|
204
|
+
vr = @stream.encode("UL", "STR")
|
205
|
+
@stream.add_first(vr)
|
207
206
|
# Tag:
|
208
207
|
tag = @stream.encode_tag("0002,0000")
|
209
208
|
@stream.add_first(tag)
|
@@ -216,8 +215,8 @@ module DICOM
|
|
216
215
|
def write_data_element(i)
|
217
216
|
# Step 1: Write tag:
|
218
217
|
write_tag(i)
|
219
|
-
# Step 2: Write [
|
220
|
-
|
218
|
+
# Step 2: Write [vr] and value length:
|
219
|
+
write_vr_length(i)
|
221
220
|
# Step 3: Write value:
|
222
221
|
write_value(i)
|
223
222
|
# If DICOM object contains encapsulated pixel data, we need some special handling for its items:
|
@@ -242,9 +241,9 @@ module DICOM
|
|
242
241
|
end
|
243
242
|
|
244
243
|
|
245
|
-
# Writes the
|
244
|
+
# Writes the VR (if it is to be written) and length value
|
246
245
|
# (these two are the middle part of the data element):
|
247
|
-
def
|
246
|
+
def write_vr_length(i)
|
248
247
|
# First some preprocessing:
|
249
248
|
# Set length value:
|
250
249
|
if @lengths[i] == nil
|
@@ -265,14 +264,14 @@ module DICOM
|
|
265
264
|
if @explicit == true
|
266
265
|
# Step 1: Write VR (if it is to be written)
|
267
266
|
unless @tags[i] == "FFFE,E000" or @tags[i] == "FFFE,E00D" or @tags[i] == "FFFE,E0DD"
|
268
|
-
# Write data element
|
269
|
-
vr = @stream.encode(@
|
267
|
+
# Write data element VR (2 bytes - since we are not dealing with an item related element):
|
268
|
+
vr = @stream.encode(@vr[i], "STR")
|
270
269
|
add(vr)
|
271
270
|
end
|
272
271
|
# Step 2: Write length
|
273
|
-
# Three possible structures for value length here, dependent on data element
|
274
|
-
case @
|
275
|
-
when "OB","OW","SQ","UN"
|
272
|
+
# Three possible structures for value length here, dependent on data element vr:
|
273
|
+
case @vr[i]
|
274
|
+
when "OB","OW","SQ","UN","UT"
|
276
275
|
if @enc_image
|
277
276
|
# Item under an encapsulated Pixel Data (7FE0,0010):
|
278
277
|
# 4 bytes:
|
@@ -291,22 +290,22 @@ module DICOM
|
|
291
290
|
add(length4)
|
292
291
|
else
|
293
292
|
# 2 bytes:
|
294
|
-
# For all the other data element
|
293
|
+
# For all the other data element vr, value length is 2 bytes:
|
295
294
|
add(length2)
|
296
|
-
end
|
295
|
+
end
|
297
296
|
else
|
298
297
|
# *****IMPLICIT*****:
|
299
298
|
# No VR written.
|
300
299
|
# Writing value length (4 bytes):
|
301
300
|
add(length4)
|
302
301
|
end
|
303
|
-
end # of
|
302
|
+
end # of write_vr_length
|
304
303
|
|
305
304
|
|
306
305
|
# Writes the value (last part of the data element):
|
307
306
|
def write_value(i)
|
308
307
|
# This is pretty straightforward, just dump the binary data to the file/string:
|
309
|
-
add(@
|
308
|
+
add(@bin[i])
|
310
309
|
end
|
311
310
|
|
312
311
|
|
@@ -347,7 +346,7 @@ module DICOM
|
|
347
346
|
# Changes encoding variables as the file writing proceeds past the initial 0002 group of the DICOM file.
|
348
347
|
def switch_syntax
|
349
348
|
# The information from the Transfer syntax element (if present), needs to be processed:
|
350
|
-
result =
|
349
|
+
result = LIBRARY.process_transfer_syntax(@transfer_syntax.rstrip)
|
351
350
|
# Result is a 3-element array: [Validity of ts, explicitness, endianness]
|
352
351
|
unless result[0]
|
353
352
|
@msg << "Warning: Invalid/unknown transfer syntax! Will still write the file, but you should give this a closer look."
|
@@ -405,9 +404,6 @@ module DICOM
|
|
405
404
|
end
|
406
405
|
# Items contained under the Pixel Data element needs some special attention to write correctly:
|
407
406
|
@enc_image = false
|
408
|
-
# Version information:
|
409
|
-
@implementation_uid = "1.2.826.0.1.3680043.8.641"
|
410
|
-
@implementation_name = "RUBY_DICOM_0.6"
|
411
407
|
end
|
412
408
|
|
413
409
|
end # of class
|