@@ -61,15 +61,18 @@ def determine_bit_depth(fp, dims):
6161 logging .warning (f"Unable to determine bit-depth of volume '{ fp } '. Expected at <{ expected_filesize } > bytes but found <{ file_size } > bytes. Defaulting to unsigned 16-bit." )
6262 return 'uint16'
6363
64- def __parse_object_filename (line ):
65- pattern = r"^ObjectFileName\:\s+(?P<filename>.*\.raw)$"
64+ def __parse_object_filename (line , dat_format ):
65+ if (dat_format == "Dragonfly" ):
66+ pattern = r"<ObjectFileName>(?P<filename>.*\.raw)<\/ObjectFileName>"
67+ elif (dat_format == "NSI" ):
68+ pattern = r"^ObjectFileName\:\s+(?P<filename>.*\.raw)$"
6669
6770 match = re .match (pattern , line , flags = re .IGNORECASE )
6871 if match is not None :
6972 logging .debug (f"Match: { match } " )
7073 return match .group ('filename' )
7174
72- def __parse_resolution (line ):
75+ def __parse_resolution (line , dat_format ):
7376 """Get the x, y, z dimensions of a volume.
7477
7578 Args:
@@ -80,13 +83,16 @@ def __parse_resolution(line):
8083
8184 """
8285 # logging.debug(line.strip())
83- pattern_old = r'\s+<Resolution X="(?P<x>\d+)"\s+Y="(?P<y>\d+)"\s+Z="(?P<z>\d+)"'
84- pattern = r'Resolution\:\s+(?P<x>\d+)\s+(?P<y>\d+)\s+(?P<z>\d+)'
86+ if (dat_format == "Dragonfly" ):
87+ pattern = r'<Resolution X="(?P<x>\d+)"\s+Y="(?P<y>\d+)"\s+Z="(?P<z>\d+)"'
88+ elif (dat_format == "NSI" ):
89+ pattern_old = r'\s+<Resolution X="(?P<x>\d+)"\s+Y="(?P<y>\d+)"\s+Z="(?P<z>\d+)"'
90+ pattern = r'Resolution\:\s+(?P<x>\d+)\s+(?P<y>\d+)\s+(?P<z>\d+)'
8591
8692 # See if the DAT file is the newer version
8793 match = re .match (pattern , line , flags = re .IGNORECASE )
8894 # Otherwise, check the old version (XML)
89- if match is None :
95+ if match is None and dat_format == "NSI" :
9096 match = re .match (pattern_old , line , flags = re .IGNORECASE )
9197 if match is not None :
9298 logging .debug (f"XML format detected for '{ line } '" )
@@ -103,7 +109,7 @@ def __parse_resolution(line):
103109 raise Exception (f"Unable to extract dimensions from DAT file. Found dimensions: '{ dims } '." )
104110 return dims
105111
106- def __parse_slice_thickness (line ):
112+ def __parse_slice_thickness (line , dat_format ):
107113 """Get the x, y, z dimensions of a volume.
108114
109115 Args:
@@ -113,31 +119,56 @@ def __parse_slice_thickness(line):
113119 (float, float, float): x, y, z real-world thickness in mm. Otherwise, returns None.
114120
115121 """
116- pattern = r'\w+\:\s+(?P<xth>\d+\.\d+)\s+(?P<yth>\d+\.\d+)\s+(?P<zth>\d+\.\d+)'
122+ if (dat_format == "Dragonfly" ):
123+ pattern = r"<Spacing\s+X=\"(?P<xth>\d+\.\d+)\"\s+Y=\"(?P<yth>\d+\.\d+)\"\s+Z=\"(?P<zth>\d+\.\d+)\""
124+ elif (dat_format == "NSI" ):
125+ pattern = r'\w+\:\s+(?P<xth>\d+\.\d+)\s+(?P<yth>\d+\.\d+)\s+(?P<zth>\d+\.\d+)'
126+
117127 match = re .match (pattern , line , flags = re .IGNORECASE )
118128 if match is not None :
119129 logging .debug (f"Match: { match } " )
120- df = match .groupdict ()
121130 dims = [ match .group ('xth' ), match .group ('yth' ), match .group ('zth' ) ]
122- dims = [ float (s ) for s in dims ]
131+ if (dat_format == "Dragonfly" ):
132+ # Change Dragonfly thickness units to match NSI format
133+ dims = [ (float (s )* 1000 ) for s in dims ]
134+ elif (dat_format == "NSI" ):
135+ dims = [ float (s ) for s in dims ]
123136 if not dims or len (dims ) != 3 :
124137 raise Exception (f"Unable to extract slice thickness from DAT file: '{ line } '. Found slice thickness: '{ dims } '." )
125138 return dims
126139
127- def __parse_format (line ):
128- pattern = r"^Format\:\s+(?P<format>\w+)$"
140+ def __parse_format (line , dat_format ):
141+ if (dat_format == "Dragonfly" ):
142+ pattern = r"<Format>(?P<format>\w+)<\/Format>"
143+ elif (dat_format == "NSI" ):
144+ pattern = r"Format\:\s+(?P<format>\w+)$"
145+
129146 match = re .match (pattern , line , flags = re .IGNORECASE )
130147 if match is not None :
131148 logging .debug (f"Match: { match } " )
132149 return match .group ('format' )
133150
134- def __parse_object_model (line ):
135- pattern = r"^ObjectModel\:\s+(?P<object_model>\w+)$"
151+ def __parse_object_model (line , dat_format ):
152+ if (dat_format == "Dragonfly" ):
153+ pattern = r"<Unit>(?P<object_model>\w+)<\/Unit>"
154+ elif (dat_format == "NSI" ):
155+ pattern = r"^ObjectModel\:\s+(?P<object_model>\w+)$"
156+
136157 match = re .match (pattern , line , flags = re .IGNORECASE )
137158 if match is not None :
138159 logging .debug (f"Match: { match } " )
139160 return match .group ('object_model' )
140161
162+ def __is_dragonfly_dat_format (line ):
163+ pattern = r"<\?xml\sversion=\"1\.0\"\?>"
164+ match = re .match (pattern , line , flags = re .IGNORECASE )
165+ if match is not None :
166+ logging .debug (f"Match: { match } " )
167+ return True
168+
169+
170+
171+
141172def read (fp ):
142173 """Read a .DAT file
143174 Args:
@@ -146,24 +177,30 @@ def read(fp):
146177 dict: contents of .DAT file
147178 """
148179 data = {}
180+ dat_format = "NSI"
149181 with open (fp , 'r' ) as ifp :
150182 # Parse the individual lines
151183 for line in ifp .readlines ():
152184 line = line .strip ()
153- if (object_filename := __parse_object_filename (line )) is not None :
185+ # Determine if format is NSI .dat or Dragonfly .dat
186+ if (__is_dragonfly_dat_format (line )):
187+ dat_format = "Dragonfly"
188+
189+ if (object_filename := __parse_object_filename (line , dat_format )) is not None :
154190 data ['ObjectFileName' ] = object_filename
191+
155192
156- if (resolution := __parse_resolution (line )) is not None :
193+ if (resolution := __parse_resolution (line , dat_format )) is not None :
157194 data ['xdim' ], data ['ydim' ], data ['zdim' ] = resolution
158195 data ['dimensions' ] = resolution
159196
160- if (thicknesses := __parse_slice_thickness (line )) is not None :
197+ if (thicknesses := __parse_slice_thickness (line , dat_format )) is not None :
161198 data ['x_thickness' ], data ['y_thickness' ], data ['z_thickness' ] = thicknesses
162199
163- if (file_format := __parse_format (line )) is not None :
200+ if (file_format := __parse_format (line , dat_format )) is not None :
164201 data ['Format' ] = file_format
165202
166- if (object_model := __parse_object_model (line )) is not None :
203+ if (object_model := __parse_object_model (line , dat_format )) is not None :
167204 data ['model' ] = object_model
168205
169206
0 commit comments