nifti 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nifti (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.2)
10
+ mocha (0.9.10)
11
+ rake
12
+ narray (0.5.9.9)
13
+ rake (0.8.7)
14
+ rspec (2.4.0)
15
+ rspec-core (~> 2.4.0)
16
+ rspec-expectations (~> 2.4.0)
17
+ rspec-mocks (~> 2.4.0)
18
+ rspec-core (2.4.0)
19
+ rspec-expectations (2.4.0)
20
+ diff-lcs (~> 1.1.2)
21
+ rspec-mocks (2.4.0)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ mocha
28
+ narray
29
+ nifti!
30
+ rspec
data/README.markdown ADDED
@@ -0,0 +1,126 @@
1
+ RUBY NIfTI
2
+ ==========
3
+
4
+ Ruby NIfTI is a pure-ruby library for handling NIfTI data in Ruby. NIfTI
5
+ [(Neuroimaging Informatics Technology Initiative)](http://nifti.nimh.nih.gov/)
6
+ is an image format designed primarily for storing and analyzing MRI & PET
7
+ imaging data.
8
+
9
+ Ruby NIfTI currently only supports basic access to NIfTI files, including
10
+ basic and extended header information, as well as image information. It
11
+ doesn't attempt to touch the image data (rotate it, etc.), but it does provide
12
+ access to qform and sform orientation matrices. Nonetheless it does provide a
13
+ nice interface to get at NIfTI info from within ruby. Since Ruby isn't as
14
+ widely seen as a quantitative scripting language yet (Python is more well
15
+ known, and PyNifti is more mature than NumericalRuby / NArray) I don't know
16
+ how widely this will be used, but hopefully it will be useful for somebody.
17
+
18
+ INSTALLATION
19
+ ------------
20
+
21
+ gem install nifti
22
+
23
+
24
+ BASIC USAGE
25
+ -----------
26
+
27
+ require "nifti"
28
+ # Read file:
29
+ obj = NIFTI::NObject.new("some_file.nii")
30
+ # Display some key information about the file:
31
+ puts obj.header['sform_code_descr']
32
+ => "NIFTI_XFORM_SCANNER_ANAT"
33
+ # Retrieve the pixel data in a Ruby Array:
34
+ image = obj.get_image
35
+ # Load the pixel data to an NArray image object and display it on the screen:
36
+ image = obj.get_image_narray
37
+
38
+ LIMITATIONS
39
+ -----------
40
+
41
+ There are plenty of NIfTI libraries around (the canonical
42
+ [nifticlib](http://niftilib.sourceforge.net/), which includes c, python and
43
+ matlab interfaces, and Matlab interfaces in the Mathworks image processing
44
+ toolbox (IPT) and [Toolbox for
45
+ NIfTI](http://www.mathworks.com/matlabcentral/fileexchange/8797-tools-for-nifti-and-analyze-image)
46
+ by Jimmy Shen.
47
+
48
+ This library does not intend to replace them, but rather to provide a few ruby
49
+ convenience methods for quickly accessing imaging data from ruby without
50
+ having to call out to external programs, as well as write custom extensions to
51
+ the NIfTI header. At current, it doesn't do much more than byte parsing and
52
+ providing access to the header, and its quite slow when compared to existing
53
+ libraries. However, [narray](http://narray.rubyforge.org/) is picking up and
54
+ its possible that people would want to have some easy way to access NIfTI info
55
+ using custom ruby libraries.
56
+
57
+
58
+ CREDIT
59
+ ------
60
+
61
+ Ruby NIfTI is highly derivative of the very good library [Ruby
62
+ DICOM](http://dicom.rubyforge.org/), from which all of the design and most of
63
+ the code has been cold-heartedly stolen. Many thanks to Chris Lervag - this
64
+ wouldn't exist without his examples.
65
+
66
+
67
+ RESOURCES
68
+ ---------
69
+
70
+ * [Official home page](http://brainmap.wisc.edu/pages/10-RUBY-NIFTI)
71
+ * [Development / Source code repository](https://github.com/brainmap/ruby-nifti)
72
+ * [Documentation](http://rdoc.info/github/brainmap/ruby-nifti/master/frames)
73
+
74
+
75
+ Examples
76
+ --------
77
+
78
+ ### Using Extended Headers ###
79
+
80
+ Each NObject that is successfully read has an array of extended_header hashes.
81
+ Each extended_header hash has 3 keys, :esize, :ecode, and :data corresponding
82
+ to the available fields in the nifti header extension.
83
+
84
+ Here's a silly example (since you'd probably want to read do this using
85
+ something that's designed for it, like 3dinfo). Suppose you wanted to collect
86
+ the history of an image from inside the AFNI extended header. Since the data
87
+ of the AFNI extended header is just xml, you could easily parse it with an xml
88
+ parser like nokogiri (using the AFNI ecode of 4 to select it from the list of
89
+ extended headers, and assuming that there's only 1 AFNI header per file):
90
+
91
+ require 'nifti'; require 'nokogiri'
92
+ obj = NIFTI::NObject.new('./T1.nii')
93
+ afni_extended_header = obj.extended_header.select{|ext| ext[:ecode] == 4 }[:data]
94
+ afni_xml = Nokogiri::XML(xml)
95
+ history = afni_xml.xpath("//AFNI_atr[@atr_name='HISTORY_NOTE']").first.children.first.text
96
+
97
+ ### Image Summary Statistics ###
98
+
99
+ Again, this is a trivial example, but shows one usage of the library. Say you
100
+ want to take find the mean and std dev of the entire image.
101
+
102
+ obj = NIFTI::NObject.new('./T1.nii', :narray => true)
103
+ mean = obj.image.mean
104
+ stddev = obj.image.stddev
105
+
106
+ If you don't have narray installed, you could still use obj.image as a ruby
107
+ array, but you'd have to collect the summary stats yourself.
108
+
109
+
110
+ COPYRIGHT
111
+ ---------
112
+
113
+ Copyright 2011 Erik Kastman
114
+
115
+ This program is free software: you can redistribute it and/or modify
116
+ it under the terms of the GNU General Public License as published by
117
+ the Free Software Foundation, either version 3 of the License, or
118
+ (at your option) any later version.
119
+
120
+ This program is distributed in the hope that it will be useful,
121
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
122
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
123
+ GNU General Public License for more details.
124
+
125
+ You should have received a copy of the GNU General Public License
126
+ along with this program. If not, see http://www.gnu.org/licenses/ .
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,223 @@
1
+ module NIFTI
2
+ # Variables used to determine endianness.
3
+ x = 0xdeadbeef
4
+ endian_type = {
5
+ Array(x).pack("V*") => false, # Little
6
+ Array(x).pack("N*") => true # Big
7
+ }
8
+ # System (CPU) Endianness.
9
+ CPU_ENDIAN = endian_type[Array(x).pack("L*")]
10
+
11
+ # Custom string used for (un)packing big endian signed short.
12
+ CUSTOM_SS = "k*"
13
+ # Custom string used for (un)packing big endian signed long.
14
+ CUSTOM_SL = "r*"
15
+
16
+ # Q/S Form Transform codes defined in the nifti header
17
+ # Reference: http://nifti.nimh.nih.gov/nifti-1/documentation/nifti1fields/nifti1fields_pages/qsform.html
18
+ XFORM_CODES = {
19
+ 0 => 'NIFTI_XFORM_UNKNOWN', # Arbitrary coordinates (Method 1).
20
+ 1 => 'NIFTI_XFORM_SCANNER_ANAT', # Scanner-based anatomical coordinates
21
+ 2 => 'NIFTI_XFORM_ALIGNED_ANAT', # Coordinates aligned to another file's, or to anatomical "truth".
22
+ 3 => 'NIFTI_XFORM_TALAIRACH', # Coordinates aligned to Talairach-Tournoux Atlas; (0,0,0)=AC, etc.
23
+ 4 => 'NIFTI_XFORM_MNI_152' # MNI 152 normalized coordinates
24
+ }
25
+
26
+ # Take a NIFTI TypeCode and return datatype and bitpix
27
+ #
28
+ # From Jimmy Shen:
29
+ # Set bitpix according to datatype
30
+ # /*Acceptable values for datatype are*/
31
+ #
32
+ # 0 None (Unknown bit per voxel) % DT_NONE, DT_UNKNOWN
33
+ # 1 Binary (ubit1, bitpix=1) % DT_BINARY
34
+ # 2 Unsigned char (uchar or uint8, bitpix=8) % DT_UINT8, NIFTI_TYPE_UINT8
35
+ # 4 Signed short (int16, bitpix=16) % DT_INT16, NIFTI_TYPE_INT16
36
+ # 8 Signed integer (int32, bitpix=32) % DT_INT32, NIFTI_TYPE_INT32
37
+ # 16 Floating point (single or float32, bitpix=32) % DT_FLOAT32, NIFTI_TYPE_FLOAT32
38
+ # 32 Complex, 2 float32 (Use float32, bitpix=64) % DT_COMPLEX64, NIFTI_TYPE_COMPLEX64
39
+ # 64 Double precision (double or float64, bitpix=64) % DT_FLOAT64, NIFTI_TYPE_FLOAT64
40
+ # 128 uint8 RGB (Use uint8, bitpix=24) % DT_RGB24, NIFTI_TYPE_RGB24
41
+ # 256 Signed char (schar or int8, bitpix=8) % DT_INT8, NIFTI_TYPE_INT8
42
+ # 511 Single RGB (Use float32, bitpix=96) % DT_RGB96, NIFTI_TYPE_RGB96
43
+ # 512 Unsigned short (uint16, bitpix=16) % DT_UNINT16, NIFTI_TYPE_UNINT16
44
+ # 768 Unsigned integer (uint32, bitpix=32) % DT_UNINT32, NIFTI_TYPE_UNINT32
45
+ # 1024 Signed long long (int64, bitpix=64) % DT_INT64, NIFTI_TYPE_INT64
46
+ # 1280 Unsigned long long (uint64, bitpix=64) % DT_UINT64, NIFTI_TYPE_UINT64
47
+ # 1536 Long double, float128 (Unsupported, bitpix=128) % DT_FLOAT128, NIFTI_TYPE_FLOAT128
48
+ # 1792 Complex128, 2 float64 (Use float64, bitpix=128) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
49
+ # 2048 Complex256, 2 float128 (Unsupported, bitpix=256) % DT_COMPLEX128, NIFTI_TYPE_COMPLEX128
50
+ NIFTI_DATATYPES = {
51
+ 0 => "Unknown",
52
+ # 1 => "", Can't find a single bit encoding in ruby's unpack method?
53
+ 2 => "OB",
54
+ 4 => "SS",
55
+ 8 => "SL",
56
+ 16 => "FL",
57
+ 32 => "FD",
58
+ 64 => "FD",
59
+ 128 => "RGBUnknown",
60
+ 256 => "BY",
61
+ 511 => "RGBUnknown",
62
+ 512 => "US",
63
+ 768 => "UL"
64
+ # 1024 => "",
65
+ # 1280 => "",
66
+ # 1536 => "",
67
+ # 1792 => "",
68
+ # 2048 => ""
69
+ }
70
+
71
+ # The NIFTI signature is hardcoded by bytes. This consists of arrays for
72
+ # each item in the signature, where item[0] is the name of the item,
73
+ # item[1] is the length in bytes of the item, and dim[2] is the Format
74
+ # string to use in packing/unpacking the item.
75
+ HEADER_SIGNATURE = [
76
+ # /**********************/ /**********************/ /***************/
77
+ # struct nifti_1_header { /* NIFTI-1 usage */ /*ANALYZE 7.5 field(s)*/ /* Byte offset */
78
+ # /**********************/ /**********************/ /***************/
79
+ # int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ /* 0 */
80
+ ['sizeof_hdr', 4, 'SL'],
81
+
82
+ # char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ /* 4 */
83
+ ['data_type', 10, 'STR'],
84
+
85
+ # char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ /* 14 */
86
+ ['db_name', 18, 'STR'],
87
+
88
+ # int extents; /*!< ++UNUSED++ */ /* int extents; */ /* 32 */
89
+ ['extents', 4, "SL"],
90
+
91
+ # short session_error; /*!< ++UNUSED++ */ /* short session_error; */ /* 36 */
92
+ ['session_error', 2, "SS"],
93
+
94
+ # char regular; /*!< ++UNUSED++ */ /* char regular; */ /* 38 */
95
+ ['regular', 1, "STR"],
96
+
97
+ # char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /* 39 */
98
+ ['dim_info', 1, "BY"],
99
+
100
+
101
+ # /*--- was image_dimension substruct ---*/
102
+ # short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ /* 40 */
103
+ ['dim', 16, "US"],
104
+
105
+ # float intent_p1; /*!< 1st intent parameter. */ /* short unused8; */ /* 56 */
106
+ ['intent_p1', 4, "FL"],
107
+
108
+ # float intent_p2; /*!< 2nd intent parameter. */ /* short unused10; */ /* 60 */
109
+ ['intent_p2', 4, "FL"],
110
+ # /* short unused11; */
111
+ # float intent_p3; /*!< 3rd intent parameter. */ /* short unused12; */ /* 64 */
112
+ ['intent_p3', 4, "FL"],
113
+
114
+ # short intent_code; /*!< NIFTIINTENT code. */ /* short unused14; */ /* 68 */
115
+ ['intent_code', 2, "US"],
116
+
117
+ # short datatype; /*!< Defines data type! */ /* short datatype; */ /* 70 */
118
+ ['datatype', 2, "US"],
119
+
120
+ # short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ /* 72 */
121
+ ['bitpix', 2, "US"],
122
+
123
+ # short slice_start; /*!< First slice index. */ /* short dim_un0; */ /* 74 */
124
+ ['slice_start', 2, "US"],
125
+
126
+ # float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ /* 76 */
127
+ ['pixdim', 32, "FL"],
128
+
129
+ # float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ /* 108 */
130
+ ['vox_offset', 4, "FL"],
131
+
132
+ # float scl_slope; /*!< Data scaling: slope. */ /* float funused1; */ /* 112 */
133
+ ['scl_slope', 4, "FL"],
134
+
135
+ # float scl_inter; /*!< Data scaling: offset. */ /* float funused2; */ /* 116 */
136
+ ['scl_inter', 4, "FL"],
137
+
138
+ # short slice_end; /*!< Last slice index. */ /* float funused3; */ /* 120 */
139
+ ['slice_end', 2, "US"],
140
+
141
+ # char slice_code; /*!< Slice timing order. */ /* 122 */
142
+ ['slice_code', 1, "BY"],
143
+
144
+ # char xyzt_units; /*!< Units of pixdim[1..4] */ /* 123 */
145
+ ['xyzt_units', 1, "BY"],
146
+
147
+ # float cal_max; /*!< Max display intensity */ /* float cal_max; */ /* 124 */
148
+ ['cal_max', 4, "FL"],
149
+
150
+ # float cal_min; /*!< Min display intensity */ /* float cal_min; */ /* 128 */
151
+ ['cal_min', 4, "FL"],
152
+
153
+ # float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ /* 132 */
154
+ ['slice_duration', 4, "FL"],
155
+
156
+ # float toffset; /*!< Time axis shift. */ /* float verified; */ /* 136 */
157
+ ['toffset', 4, "FL"],
158
+
159
+ # int glmax; /*!< ++UNUSED++ */ /* int glmax; */ /* 140 */
160
+ ['glmax', 4, "UL"],
161
+
162
+ # int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /* 144 */
163
+ ['glmin', 4, "UL"],
164
+
165
+ # /*--- was data_history substruct ---*/
166
+ # char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ /* 148 */
167
+ ['descrip', 80, "STR"],
168
+
169
+ # char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ /* 228 */
170
+ ['aux_file', 24, "STR"],
171
+
172
+ #
173
+ # short qform_code; /*!< NIFTIXFORM code. */ /*-- all ANALYZE 7.5 ---*/ /* 252 */
174
+ ['qform_code', 2, "US"], # /* fields below here */
175
+ # /* are replaced */
176
+ # short sform_code; /*!< NIFTIXFORM code. */ /* 254 */
177
+ ['sform_code', 2, "US"],
178
+ #
179
+ # float quatern_b; /*!< Quaternion b param. */ /* 256 */
180
+ ['quatern_b', 4, "FL"],
181
+
182
+ # float quatern_c; /*!< Quaternion c param. */ /* 260 */
183
+ ['quatern_c', 4, "FL"],
184
+
185
+ # float quatern_d; /*!< Quaternion d param. */ /* 264 */
186
+ ['quatern_d', 4, "FL"],
187
+
188
+
189
+ # float qoffset_x; /*!< Quaternion x shift. */ /* 268 */
190
+ ['qoffset_x', 4, "FL"],
191
+
192
+ # float qoffset_y; /*!< Quaternion y shift. */ /* 272 */
193
+ ['qoffset_y', 4, "FL"],
194
+
195
+ # float qoffset_z; /*!< Quaternion z shift. */ /* 276 */
196
+ ['qoffset_z', 4, "FL"],
197
+
198
+ # float srow_x[4]; /*!< 1st row affine transform. */ /* 280 */
199
+ ['srow_x', 16, "FL"],
200
+
201
+ # float srow_y[4]; /*!< 2nd row affine transform. */ /* 296 */
202
+ ['srow_y', 16, "FL"],
203
+
204
+ # float srow_z[4]; /*!< 3rd row affine transform. */ /* 312 */
205
+ ['srow_z', 16, "FL"],
206
+
207
+ #
208
+ #
209
+ # char intent_name[16];/*!< name or meaning of data. */ /* 328 */
210
+ ['intent_name', 16, "STR"],
211
+
212
+ #
213
+ #
214
+ # char magic[4]; /*!< MUST be "ni1\0" or "n+1\0". */ /* 344 */
215
+ ['magic', 4, "STR"]
216
+
217
+ # } ; /** 348 bytes total **/
218
+ #
219
+ #
220
+
221
+
222
+ ]
223
+ end
@@ -0,0 +1,155 @@
1
+ module NIFTI
2
+ # The NObject class is the main class for interacting with the NIFTI object.
3
+ # Reading from and writing to files is executed from instances of this class.
4
+ #
5
+ class NObject
6
+ # An array which contain any notices/warnings/errors that have been recorded for the NObject instance.
7
+ attr_reader :errors
8
+ # A boolean which is set as true if a NIFTI file has been successfully read & parsed from a file (or binary string).
9
+ attr_reader :read_success
10
+ # The Stream instance associated with this DObject instance (this attribute is mostly used internally).
11
+ attr_reader :stream
12
+ # A boolean which is set as true if a DObject instance has been successfully written to file (or successfully encoded).
13
+ attr_reader :write_success
14
+ # A hash of header information
15
+ attr_accessor :header
16
+ # A hash of extended attributes
17
+ attr_accessor :extended_header
18
+ # An array or narray of image values
19
+ attr_accessor :image
20
+
21
+ # Creates an NObject instance (NObject is an abbreviation for "NIFTI object").
22
+ #
23
+ # The NObject instance holds references to the NIFTI Header and Image
24
+ # A NObject is typically built by reading and parsing a file or a
25
+ # binary string, but can also be built from an empty state by the user.
26
+ #
27
+ # === Parameters
28
+ #
29
+ # * <tt>string</tt> -- A string which specifies either the path of a DICOM file to be loaded, or a binary DICOM string to be parsed. The parameter defaults to nil, in which case an empty DObject instance is created.
30
+ # * <tt>options</tt> -- A hash of parameters.
31
+ #
32
+ # === Options
33
+ #
34
+ # * <tt>:bin</tt> -- Boolean. If set to true, string parameter will be interpreted as a binary DICOM string, and not a path string, which is the default behaviour.
35
+ # * <tt>:syntax</tt> -- String. If a syntax string is specified, the DRead class will be forced to use this transfer syntax when decoding the file/binary string.
36
+ # * <tt>:verbose</tt> -- Boolean. If set to false, the NObject instance will run silently and not output warnings and error messages to the screen. Defaults to true.
37
+ # * <tt>:image</tt> -- Boolean. If set to true, automatically load the image into @image, otherwise only a header is collected and you can get an image from #get_image
38
+ # * <tt>:narray</tt> -- Boolean. If set to true, the NObject will build a properly shaped narray from the image data.
39
+ #
40
+ # === Examples
41
+ #
42
+ # # Load a NIFTI file's header information:
43
+ # require 'nifti'
44
+ # obj = NIFTI::NObject.new("test.nii")
45
+ # # Read a NIFTI header and image into a numerical-ruby narray:
46
+ # obj = Nfiti::NObject.new("test.nii", :image => true, :narray => true)
47
+ # # Create an empty NIfTI object & choose non-verbose behaviour:
48
+ # obj = NIFTI::NObject.new(nil, :verbose => false)
49
+ #
50
+ def initialize(string=nil, options={})
51
+ # Process option values, setting defaults for the ones that are not specified:
52
+ # Default verbosity is true if verbosity hasn't been specified (nil):
53
+ @verbose = (options[:verbose] == false ? false : true)
54
+ # Messages (errors, warnings or notices) will be accumulated in an array:
55
+ @errors = Array.new
56
+ # Structural information (default values):
57
+ @file_endian = false
58
+ # Control variables:
59
+ @read_success = nil
60
+
61
+ # Call the read method if a string has been supplied:
62
+ if string.is_a?(String)
63
+ @file = string unless options[:bin]
64
+ read(string, options)
65
+ elsif not string == nil
66
+ raise ArgumentError, "Invalid argument. Expected String (or nil), got #{string.class}."
67
+ end
68
+
69
+ end
70
+
71
+ # Reopen the NIFTI File and retrieve image data
72
+ def get_image
73
+ r = NRead.new(@string, :image => true)
74
+ if r.success
75
+ @image = r.image_rubyarray
76
+ end
77
+ end
78
+
79
+ # Passes the NObject to the DWrite class, which writes out the header and image to the specified file.
80
+ #
81
+ # === Parameters
82
+ #
83
+ # * <tt>file_name</tt> -- A string which identifies the path & name of the NIfTI file which is to be written to disk.
84
+ # * <tt>options</tt> -- A hash of parameters.
85
+ #
86
+ # === Options
87
+ #
88
+ # === Examples
89
+ #
90
+ # obj.write(path + "test.dcm")
91
+ #
92
+ def write(file_name, options={})
93
+ if file_name.is_a?(String)
94
+ w = NWrite.new(self, file_name, options)
95
+ w.write
96
+ # Write process succesful?
97
+ @write_success = w.success
98
+ # If any messages has been recorded, send these to the message handling method:
99
+ add_msg(w.msg) if w.msg.length > 0
100
+ else
101
+ raise ArgumentError, "Invalid file_name. Expected String, got #{file_name.class}."
102
+ end
103
+ end
104
+
105
+ # Following methods are private:
106
+ private
107
+
108
+ # Returns a NIFTI object by reading and parsing the specified file.
109
+ # This is accomplished by initializing the NRead class, which loads NIFTI information.
110
+ #
111
+ # === Notes
112
+ #
113
+ # This method is called automatically when initializing the NObject class with a file parameter,
114
+ # and in practice should not be called by users.
115
+ #
116
+ def read(string, options={})
117
+ if string.is_a?(String)
118
+ @string = string
119
+ r = NRead.new(string, options)
120
+ # Store the data to the instance variables if the readout was a success:
121
+ if r.success
122
+ @read_success = true
123
+ # Update instance variables based on the properties of the NRead object:
124
+ @header = r.hdr
125
+ @extended_header = r.extended_header
126
+ if r.image_narray
127
+ @image = r.image_narray
128
+ elsif r.image_rubyarray
129
+ @image = r.image_rubyarray
130
+ end
131
+ else
132
+ @read_success = false
133
+ end
134
+ # If any messages have been recorded, send these to the message handling method:
135
+ add_msg(r.msg) if r.msg.length > 0
136
+ else
137
+ raise ArgumentError, "Invalid argument. Expected String, got #{string.class}."
138
+ end
139
+ end
140
+
141
+ # Adds one or more status messages to the instance array holding messages, and if the verbose instance variable
142
+ # is true, the status message(s) are printed to the screen as well.
143
+ #
144
+ # === Parameters
145
+ #
146
+ # * <tt>msg</tt> -- Status message string, or an array containing one or more status message strings.
147
+ #
148
+ def add_msg(msg)
149
+ puts msg if @verbose
150
+ @errors << msg
151
+ @errors.flatten
152
+ end
153
+
154
+ end
155
+ end