nifti 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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