dicom 0.6.1 → 0.7
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 +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
|