dicom 0.8 → 0.9
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 → CHANGELOG.rdoc} +100 -52
- data/README.rdoc +126 -0
- data/lib/dicom.rb +13 -7
- data/lib/dicom/anonymizer.rb +129 -111
- data/lib/dicom/constants.rb +60 -10
- data/lib/dicom/d_client.rb +230 -157
- data/lib/dicom/d_library.rb +88 -8
- data/lib/dicom/d_object.rb +141 -149
- data/lib/dicom/d_read.rb +42 -36
- data/lib/dicom/d_server.rb +8 -10
- data/lib/dicom/d_write.rb +25 -46
- data/lib/dicom/dictionary.rb +1 -3
- data/lib/dicom/{data_element.rb → element.rb} +61 -49
- data/lib/dicom/elemental.rb +126 -0
- data/lib/dicom/file_handler.rb +18 -17
- data/lib/dicom/image_item.rb +844 -0
- data/lib/dicom/image_processor.rb +69 -0
- data/lib/dicom/image_processor_mini_magick.rb +74 -0
- data/lib/dicom/image_processor_r_magick.rb +102 -0
- data/lib/dicom/item.rb +21 -19
- data/lib/dicom/link.rb +64 -82
- data/lib/dicom/{super_parent.rb → parent.rb} +270 -39
- data/lib/dicom/ruby_extensions.rb +175 -3
- data/lib/dicom/sequence.rb +5 -6
- data/lib/dicom/stream.rb +37 -25
- data/lib/dicom/variables.rb +51 -0
- data/lib/dicom/version.rb +6 -0
- metadata +97 -29
- data/README +0 -100
- data/init.rb +0 -1
- data/lib/dicom/elements.rb +0 -82
- data/lib/dicom/super_item.rb +0 -696
@@ -0,0 +1,69 @@
|
|
1
|
+
module DICOM
|
2
|
+
module ImageProcessor
|
3
|
+
|
4
|
+
# Creates image objects from one or more compressed, binary string blobs.
|
5
|
+
# Returns an array of images. If decompression fails, returns false.
|
6
|
+
#
|
7
|
+
# === Parameters
|
8
|
+
#
|
9
|
+
# * <tt>blobs</tt> -- Binary string blob(s) containing compressed pixel data.
|
10
|
+
#
|
11
|
+
def decompress(blobs)
|
12
|
+
raise ArgumentError, "Expected Array or String, got #{blobs.class}." unless [String, Array].include?(blobs.class)
|
13
|
+
blobs = [blobs] unless blobs.is_a?(Array)
|
14
|
+
begin
|
15
|
+
return image_module.decompress(blobs)
|
16
|
+
rescue
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Extracts an array of pixels (integers) from an image object.
|
22
|
+
#
|
23
|
+
# === Parameters
|
24
|
+
#
|
25
|
+
# * <tt>image</tt> -- An Rmagick image object.
|
26
|
+
#
|
27
|
+
def export_pixels(image, photometry)
|
28
|
+
raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
|
29
|
+
image_module.export_pixels(image, photometry)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates an image object from a binary string blob.
|
33
|
+
#
|
34
|
+
# === Parameters
|
35
|
+
#
|
36
|
+
# * <tt>blob</tt> -- Binary string blob containing raw pixel data.
|
37
|
+
# * <tt>columns</tt> -- Number of columns.
|
38
|
+
# * <tt>rows</tt> -- Number of rows.
|
39
|
+
# * <tt>depth</tt> -- Bit depth of the encoded pixel data.
|
40
|
+
# * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data. Example: 'MONOCHROME1', 'RGB'.
|
41
|
+
#
|
42
|
+
def import_pixels(blob, columns, rows, depth, photometry)
|
43
|
+
raise ArgumentError, "Expected String, got #{blob.class}." unless blob.is_a?(String)
|
44
|
+
image_module.import_pixels(blob, columns, rows, depth, photometry)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns an array containing the image objects that are supported by the image processor.
|
48
|
+
#
|
49
|
+
def valid_image_objects
|
50
|
+
return [Magick::Image, MiniMagick::Image]
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
|
57
|
+
def image_module
|
58
|
+
case DICOM.image_processor
|
59
|
+
when :mini_magick
|
60
|
+
DcmMiniMagick
|
61
|
+
when :rmagick
|
62
|
+
DcmRMagick
|
63
|
+
else
|
64
|
+
raise "Uknown image processor #{DICOM.image_processor}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module DICOM
|
2
|
+
module ImageProcessor
|
3
|
+
module DcmMiniMagick
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Creates image objects from an array of compressed, binary string blobs.
|
8
|
+
# Returns an array of images. If decompression fails, returns false.
|
9
|
+
#
|
10
|
+
# === Parameters
|
11
|
+
#
|
12
|
+
# * <tt>blobs</tt> -- An array of binary string blobs containing compressed pixel data.
|
13
|
+
#
|
14
|
+
def decompress(blobs)
|
15
|
+
images = Array.new
|
16
|
+
# We attempt to decompress the pixels using ImageMagick:
|
17
|
+
blobs.each do |string|
|
18
|
+
images << MiniMagick::Image.read(string)
|
19
|
+
end
|
20
|
+
return images
|
21
|
+
end
|
22
|
+
|
23
|
+
# Extracts an array of pixels (integers) from an image object.
|
24
|
+
#
|
25
|
+
# === Notes
|
26
|
+
#
|
27
|
+
# * This feature is not available as of yet in the mini_magick image processor. If this feature is needed, please try another image processor (RMagick).
|
28
|
+
#
|
29
|
+
# === Parameters
|
30
|
+
#
|
31
|
+
# * <tt>image</tt> -- An MiniMagick image object.
|
32
|
+
#
|
33
|
+
def export_pixels(image, photometry)
|
34
|
+
raise ArgumentError, "Expected MiniMagick::Image, got #{image.class}." unless image.is_a?(MiniMagick::Image)
|
35
|
+
raise "Exporting pixels is not yet available with the mini_magick processor. Please try another image processor (RMagick)."
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates an image object from a binary string blob which contains raw pixel data.
|
39
|
+
#
|
40
|
+
# === Parameters
|
41
|
+
#
|
42
|
+
# * <tt>blob</tt> -- Binary string blob containing raw pixel data.
|
43
|
+
# * <tt>columns</tt> -- Number of columns.
|
44
|
+
# * <tt>rows</tt> -- Number of rows.
|
45
|
+
# * <tt>depth</tt> -- Bit depth of the encoded pixel data.
|
46
|
+
# * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data.
|
47
|
+
# * <tt>format</tt> -- String describing the image format to be used when creating the image object. Defaults to 'png'.
|
48
|
+
#
|
49
|
+
def import_pixels(blob, columns, rows, depth, photometry, format="png")
|
50
|
+
image = MiniMagick::Image.import_pixels(blob, columns, rows, depth, im_map(photometry), format)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns an ImageMagick pixel map string based on the input DICOM photometry string.
|
54
|
+
#
|
55
|
+
# === Parameters
|
56
|
+
#
|
57
|
+
# * <tt>photometry</tt> -- String describing the photometry of the pixel data. Example: 'MONOCHROME1' or 'COLOR'.
|
58
|
+
#
|
59
|
+
def im_map(photometry)
|
60
|
+
raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
|
61
|
+
if photometry.include?("COLOR") or photometry.include?("RGB")
|
62
|
+
return "rgb"
|
63
|
+
elsif photometry.include?("YBR")
|
64
|
+
return "ybr"
|
65
|
+
else
|
66
|
+
return "gray" # (Assuming monochromeX - greyscale)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module DICOM
|
2
|
+
module ImageProcessor
|
3
|
+
module DcmRMagick
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# Creates image objects from an array of compressed, binary string blobs.
|
8
|
+
# Returns an array of images. If decompression fails, returns false.
|
9
|
+
#
|
10
|
+
# === Notes
|
11
|
+
#
|
12
|
+
# The method tries to use RMagick of unpacking, but it seems that ImageMagick is not able to handle most of the
|
13
|
+
# compressed image variants used in the DICOM standard. To get a more robust implementation which is able to handle
|
14
|
+
# most types of compressed DICOM files, something else is needed.
|
15
|
+
#
|
16
|
+
# Probably a good candidate to use is the PVRG-JPEG library, which seems to be able to handle everything that is jpeg.
|
17
|
+
# It exists in the Ubuntu repositories, where it can be installed and run through terminal. For source code, and some
|
18
|
+
# additional information, check this link: http://www.panix.com/~eli/jpeg/
|
19
|
+
#
|
20
|
+
# Another idea would be to study how other open source libraries, like GDCM handle these files.
|
21
|
+
#
|
22
|
+
# === Parameters
|
23
|
+
#
|
24
|
+
# * <tt>blobs</tt> -- An array of binary string blobs containing compressed pixel data.
|
25
|
+
#
|
26
|
+
#--
|
27
|
+
# The following transfer syntaxes have been verified as failing with ImageMagick:
|
28
|
+
# TXS_JPEG_LOSSLESS_NH is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
|
29
|
+
# TXS_JPEG_LOSSLESS_NH_FOP is not supported by (my) ImageMagick version: "Unsupported JPEG process: SOF type 0xc3"
|
30
|
+
# TXS_JPEG_2000_PART1_LOSSLESS is not supported by (my) ImageMagick version: "jpc_dec_decodepkts failed"
|
31
|
+
#
|
32
|
+
def decompress(blobs)
|
33
|
+
images = Array.new
|
34
|
+
# We attempt to decompress the pixels using ImageMagick:
|
35
|
+
blobs.each do |string|
|
36
|
+
images << Magick::Image.from_blob(string).first
|
37
|
+
end
|
38
|
+
return images
|
39
|
+
end
|
40
|
+
|
41
|
+
# Extracts an array of pixels (integers) from an image object.
|
42
|
+
#
|
43
|
+
# === Parameters
|
44
|
+
#
|
45
|
+
# * <tt>image</tt> -- An Rmagick image object.
|
46
|
+
#
|
47
|
+
def export_pixels(image, photometry)
|
48
|
+
raise ArgumentError, "Expected Magick::Image, got #{image.class}." unless image.is_a?(Magick::Image)
|
49
|
+
pixels = image.export_pixels(0, 0, image.columns, image.rows, rm_map(photometry))
|
50
|
+
return pixels
|
51
|
+
end
|
52
|
+
|
53
|
+
# Creates an image object from a binary string blob which contains raw pixel data.
|
54
|
+
#
|
55
|
+
# === Parameters
|
56
|
+
#
|
57
|
+
# * <tt>blob</tt> -- Binary string blob containing raw pixel data.
|
58
|
+
# * <tt>columns</tt> -- Number of columns.
|
59
|
+
# * <tt>rows</tt> -- Number of rows.
|
60
|
+
# * <tt>depth</tt> -- Bit depth of the encoded pixel data.
|
61
|
+
# * <tt>photometry</tt> -- String describing the DICOM photometry of the pixel data.
|
62
|
+
# * <tt>format</tt> -- String describing the image format to be used when creating the image object. Defaults to 'png'.
|
63
|
+
#
|
64
|
+
def import_pixels(blob, columns, rows, depth, photometry, format="png")
|
65
|
+
image = Magick::Image.new(columns,rows).import_pixels(0, 0, columns, rows, rm_map(photometry), blob, rm_data_type(depth))
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the RMagick StorageType pixel value corresponding to the given bit length.
|
69
|
+
#
|
70
|
+
def rm_data_type(bit_depth)
|
71
|
+
return case bit_depth
|
72
|
+
when 8
|
73
|
+
Magick::CharPixel
|
74
|
+
when 16
|
75
|
+
Magick::ShortPixel
|
76
|
+
else
|
77
|
+
raise ArgumentError, "Unsupported bit depth: #{bit_depth}."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns an RMagick pixel map string based on the input DICOM photometry string.
|
82
|
+
#
|
83
|
+
# === Parameters
|
84
|
+
#
|
85
|
+
# * <tt>photometry</tt> -- String describing the photometry of the pixel data. Example: 'MONOCHROME1' or 'COLOR'.
|
86
|
+
#
|
87
|
+
def rm_map(photometry)
|
88
|
+
raise ArgumentError, "Expected String, got #{photometry.class}." unless photometry.is_a?(String)
|
89
|
+
if photometry.include?("COLOR") or photometry.include?("RGB")
|
90
|
+
return "RGB"
|
91
|
+
elsif photometry.include?("YBR")
|
92
|
+
return "YBR"
|
93
|
+
else
|
94
|
+
return "I" # (Assuming monochromeX - greyscale)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/dicom/item.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
|
-
# Copyright 2010 Christoffer Lervag
|
2
|
-
|
3
1
|
module DICOM
|
4
2
|
|
5
3
|
# The Item class handles information related to items - the elements contained in sequences.
|
6
4
|
#
|
7
|
-
|
5
|
+
# === Inheritance
|
6
|
+
#
|
7
|
+
# As the Item class inherits from the ImageItem class, which itself inherits from the Parent class,
|
8
|
+
# all ImageItem and Parent methods are also available to instances of Item.
|
9
|
+
#
|
10
|
+
class Item < ImageItem
|
8
11
|
|
9
|
-
# Include the
|
10
|
-
include
|
12
|
+
# Include the Elemental mix-in module:
|
13
|
+
include Elemental
|
11
14
|
|
12
15
|
# The index of this Item in the group of items belonging to its parent. If the Item is without parent, index is nil.
|
13
16
|
attr_accessor :index
|
@@ -47,13 +50,15 @@ module DICOM
|
|
47
50
|
@value = nil
|
48
51
|
@name = options[:name] || "Item"
|
49
52
|
@vr = options[:vr] || ITEM_VR
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
+
if options[:bin]
|
54
|
+
self.bin = options[:bin]
|
55
|
+
else
|
56
|
+
@length = options[:length] || -1
|
57
|
+
end
|
53
58
|
if options[:parent]
|
54
59
|
@parent = options[:parent]
|
55
60
|
@index = options[:index] if options[:index]
|
56
|
-
@parent.add_item(self, :index => options[:index])
|
61
|
+
@parent.add_item(self, :index => options[:index], :no_follow => true)
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
@@ -69,18 +74,15 @@ module DICOM
|
|
69
74
|
# obj["7FE0,0010"][1].children.first.bin = jpeg_binary_string
|
70
75
|
#
|
71
76
|
def bin=(new_bin)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
else
|
77
|
-
@bin = new_bin
|
78
|
-
end
|
79
|
-
@value = nil
|
80
|
-
@length = @bin.length
|
77
|
+
raise ArgumentError, "Invalid parameter type. String was expected, got #{new_bin.class}." unless new_bin.is_a?(String)
|
78
|
+
# Add an empty byte at the end if the length of the binary is odd:
|
79
|
+
if new_bin.length[0] == 1
|
80
|
+
@bin = new_bin + "\x00"
|
81
81
|
else
|
82
|
-
|
82
|
+
@bin = new_bin
|
83
83
|
end
|
84
|
+
@value = nil
|
85
|
+
@length = @bin.length
|
84
86
|
end
|
85
87
|
|
86
88
|
end
|
data/lib/dicom/link.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# Copyright 2009-2010 Christoffer Lervag
|
2
|
-
|
3
1
|
module DICOM
|
4
2
|
|
5
3
|
# This class handles the construction and interpretation of network packages as well as network communication.
|
@@ -8,7 +6,7 @@ module DICOM
|
|
8
6
|
|
9
7
|
# A customized FileHandler class to use instead of the default FileHandler included with Ruby DICOM.
|
10
8
|
attr_accessor :file_handler
|
11
|
-
# The maximum allowed size of network packages (in bytes).
|
9
|
+
# The maximum allowed size of network packages (in bytes).
|
12
10
|
attr_accessor :max_package_size
|
13
11
|
# A hash which keeps track of the relationship between context ID and chosen transfer syntax.
|
14
12
|
attr_accessor :presentation_contexts
|
@@ -32,7 +30,7 @@ module DICOM
|
|
32
30
|
# * <tt>:ae</tt> -- String. The name of the client (application entity).
|
33
31
|
# * <tt>:file_handler</tt> -- A customized FileHandler class to use instead of the default FileHandler.
|
34
32
|
# * <tt>:host_ae</tt> -- String. The name of the server (application entity).
|
35
|
-
# * <tt>:max_package_size</tt> -- Fixnum. The maximum allowed size of network packages (in bytes).
|
33
|
+
# * <tt>:max_package_size</tt> -- Fixnum. The maximum allowed size of network packages (in bytes).
|
36
34
|
# * <tt>:timeout</tt> -- Fixnum. The maximum period to wait for an answer before aborting the communication.
|
37
35
|
# * <tt>:verbose</tt> -- Boolean. If set to false, the DLink instance will run silently and not output warnings and error messages to the screen. Defaults to true.
|
38
36
|
#
|
@@ -121,17 +119,19 @@ module DICOM
|
|
121
119
|
# encodes the presentation context, we pass on a one-element array containing nil).
|
122
120
|
abstract_syntaxes = Array.new(1, nil)
|
123
121
|
# Note: The order of which these components are built is not arbitrary.
|
124
|
-
append_application_context
|
122
|
+
append_application_context
|
125
123
|
# Reset the presentation context instance variable:
|
126
124
|
@presentation_contexts = Hash.new
|
125
|
+
# Create the presentation context hash object that will be passed to the builder method:
|
126
|
+
p_contexts = Hash.new
|
127
127
|
# Build the presentation context strings, one by one:
|
128
128
|
info[:pc].each do |pc|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
append_presentation_contexts(abstract_syntaxes, ITEM_PRESENTATION_CONTEXT_RESPONSE, transfer_syntax, context_id, result)
|
129
|
+
@presentation_contexts[pc[:presentation_context_id]] = pc[:selected_transfer_syntax]
|
130
|
+
# Add the information from this pc item to the p_contexts hash:
|
131
|
+
p_contexts[pc[:abstract_syntax]] = Hash.new unless p_contexts[pc[:abstract_syntax]]
|
132
|
+
p_contexts[pc[:abstract_syntax]][pc[:presentation_context_id]] = {:transfer_syntaxes => [pc[:selected_transfer_syntax]], :result => pc[:result]}
|
134
133
|
end
|
134
|
+
append_presentation_contexts(p_contexts, ITEM_PRESENTATION_CONTEXT_RESPONSE)
|
135
135
|
append_user_information(@user_information)
|
136
136
|
# Header must be built last, because we need to know the length of the other components.
|
137
137
|
append_association_header(PDU_ASSOCIATION_ACCEPT, info[:called_ae])
|
@@ -170,20 +170,18 @@ module DICOM
|
|
170
170
|
#
|
171
171
|
# === Parameters
|
172
172
|
#
|
173
|
-
# * <tt>
|
174
|
-
# * <tt>as</tt> -- An array of abstract syntax strings.
|
175
|
-
# * <tt>ts</tt> -- An array of transfer syntax strings.
|
173
|
+
# * <tt>presentation_contexts</tt> -- A hash containing abstract_syntaxes, presentation context ids and transfer syntaxes.
|
176
174
|
# * <tt>user_info</tt> -- A user information items array.
|
177
175
|
#
|
178
|
-
def build_association_request(
|
176
|
+
def build_association_request(presentation_contexts, user_info)
|
179
177
|
# Big endian encoding:
|
180
178
|
@outgoing.endian = @net_endian
|
181
179
|
# Clear the outgoing binary string:
|
182
180
|
@outgoing.reset
|
183
181
|
# Note: The order of which these components are built is not arbitrary.
|
184
182
|
# (The first three are built 'in order of appearance', the header is built last, but is put first in the message)
|
185
|
-
append_application_context
|
186
|
-
append_presentation_contexts(
|
183
|
+
append_application_context
|
184
|
+
append_presentation_contexts(presentation_contexts, ITEM_PRESENTATION_CONTEXT_REQUEST, request=true)
|
187
185
|
append_user_information(user_info)
|
188
186
|
# Header must be built last, because we need to know the length of the other components.
|
189
187
|
append_association_header(PDU_ASSOCIATION_REQUEST, @host_ae)
|
@@ -1136,19 +1134,15 @@ module DICOM
|
|
1136
1134
|
|
1137
1135
|
# Builds the application context (which is part of the association request/response).
|
1138
1136
|
#
|
1139
|
-
|
1140
|
-
#
|
1141
|
-
# * <tt>ac_uid</tt> -- Application context UID string.
|
1142
|
-
#
|
1143
|
-
def append_application_context(ac_uid)
|
1137
|
+
def append_application_context
|
1144
1138
|
# Application context item type (1 byte)
|
1145
1139
|
@outgoing.encode_last(ITEM_APPLICATION_CONTEXT, "HEX")
|
1146
1140
|
# Reserved (1 byte)
|
1147
1141
|
@outgoing.encode_last("00", "HEX")
|
1148
1142
|
# Application context item length (2 bytes)
|
1149
|
-
@outgoing.encode_last(
|
1143
|
+
@outgoing.encode_last(APPLICATION_CONTEXT.length, "US")
|
1150
1144
|
# Application context (variable length)
|
1151
|
-
@outgoing.encode_last(
|
1145
|
+
@outgoing.encode_last(APPLICATION_CONTEXT, "STR")
|
1152
1146
|
end
|
1153
1147
|
|
1154
1148
|
# Builds the binary string that makes up the header part the association request/response.
|
@@ -1202,70 +1196,58 @@ module DICOM
|
|
1202
1196
|
#
|
1203
1197
|
# === Parameters
|
1204
1198
|
#
|
1205
|
-
# * <tt>
|
1206
|
-
# * <tt>
|
1207
|
-
# * <tt>
|
1208
|
-
#
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
else # (String)
|
1223
|
-
ts_length = 4 + ts.length
|
1224
|
-
end
|
1225
|
-
if as
|
1226
|
-
items_length = 4 + (4 + as.length) + ts_length
|
1227
|
-
else
|
1199
|
+
# * <tt>presentation_contexts</tt> -- A nested hash object with abstract syntaxes, presentation context ids, transfer syntaxes and result codes.
|
1200
|
+
# * <tt>item_type</tt> -- Presentation context item (request or response).
|
1201
|
+
# * <tt>request</tt> -- Boolean. If true, an ossociate request message is generated, if false, an asoociate accept message is generated.
|
1202
|
+
#
|
1203
|
+
def append_presentation_contexts(presentation_contexts, item_type, request=false)
|
1204
|
+
# Iterate the abstract syntaxes:
|
1205
|
+
presentation_contexts.each_pair do |abstract_syntax, context_ids|
|
1206
|
+
# Iterate the context ids:
|
1207
|
+
context_ids.each_pair do |context_id, syntax|
|
1208
|
+
# PRESENTATION CONTEXT:
|
1209
|
+
# Presentation context item type (1 byte)
|
1210
|
+
@outgoing.encode_last(item_type, "HEX")
|
1211
|
+
# Reserved (1 byte)
|
1212
|
+
@outgoing.encode_last("00", "HEX")
|
1213
|
+
# Presentation context item length (2 bytes)
|
1214
|
+
ts_length = 4*syntax[:transfer_syntaxes].length + syntax[:transfer_syntaxes].join.length
|
1215
|
+
# Abstract syntax item only included in requests, not accepts:
|
1228
1216
|
items_length = 4 + ts_length
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
# (NB! This number should be odd, and in the range 1..255)
|
1234
|
-
if context_id
|
1235
|
-
presentation_context_id = context_id
|
1236
|
-
else
|
1237
|
-
presentation_context_id = index*2 + 1
|
1238
|
-
end
|
1239
|
-
@outgoing.encode_last(presentation_context_id, "BY")
|
1240
|
-
# Reserved (1 byte)
|
1241
|
-
@outgoing.encode_last("00", "HEX")
|
1242
|
-
# (1 byte) Reserved (for association request) & Result/reason (for association accept response)
|
1243
|
-
@outgoing.encode_last(result, "BY")
|
1244
|
-
# Reserved (1 byte)
|
1245
|
-
@outgoing.encode_last("00", "HEX")
|
1246
|
-
## ABSTRACT SYNTAX SUB-ITEM: (only for request, not response)
|
1247
|
-
if as
|
1248
|
-
# Abstract syntax item type (1 byte)
|
1249
|
-
@outgoing.encode_last(ITEM_ABSTRACT_SYNTAX, "HEX")
|
1217
|
+
items_length += 4 + abstract_syntax.length if request
|
1218
|
+
@outgoing.encode_last(items_length, "US")
|
1219
|
+
# Presentation context ID (1 byte)
|
1220
|
+
@outgoing.encode_last(context_id, "BY")
|
1250
1221
|
# Reserved (1 byte)
|
1251
1222
|
@outgoing.encode_last("00", "HEX")
|
1252
|
-
#
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
# Transfer syntax item type (1 byte)
|
1262
|
-
@outgoing.encode_last(ITEM_TRANSFER_SYNTAX, "HEX")
|
1223
|
+
# (1 byte) Reserved (for association request) & Result/reason (for association accept response)
|
1224
|
+
result = (syntax[:result] ? syntax[:result] : 0)
|
1225
|
+
@outgoing.encode_last(result, "BY")
|
1226
|
+
# Reserved (1 byte)
|
1227
|
+
@outgoing.encode_last("00", "HEX")
|
1228
|
+
## ABSTRACT SYNTAX SUB-ITEM: (only for request, not response)
|
1229
|
+
if request
|
1230
|
+
# Abstract syntax item type (1 byte)
|
1231
|
+
@outgoing.encode_last(ITEM_ABSTRACT_SYNTAX, "HEX")
|
1263
1232
|
# Reserved (1 byte)
|
1264
1233
|
@outgoing.encode_last("00", "HEX")
|
1265
|
-
#
|
1266
|
-
@outgoing.encode_last(
|
1267
|
-
#
|
1268
|
-
@outgoing.encode_last(
|
1234
|
+
# Abstract syntax item length (2 bytes)
|
1235
|
+
@outgoing.encode_last(abstract_syntax.length, "US")
|
1236
|
+
# Abstract syntax (variable length)
|
1237
|
+
@outgoing.encode_last(abstract_syntax, "STR")
|
1238
|
+
end
|
1239
|
+
## TRANSFER SYNTAX SUB-ITEM (not included if result indicates error):
|
1240
|
+
if result == ACCEPTANCE
|
1241
|
+
syntax[:transfer_syntaxes].each do |t|
|
1242
|
+
# Transfer syntax item type (1 byte)
|
1243
|
+
@outgoing.encode_last(ITEM_TRANSFER_SYNTAX, "HEX")
|
1244
|
+
# Reserved (1 byte)
|
1245
|
+
@outgoing.encode_last("00", "HEX")
|
1246
|
+
# Transfer syntax item length (2 bytes)
|
1247
|
+
@outgoing.encode_last(t.length, "US")
|
1248
|
+
# Transfer syntax (variable length)
|
1249
|
+
@outgoing.encode_last(t, "STR")
|
1250
|
+
end
|
1269
1251
|
end
|
1270
1252
|
end
|
1271
1253
|
end
|