def _validDM(self): ''' Test whether a file is a valid DM3 or DM4 file, and verify that it's written in Little Endian format ''' output = True #output will stay == 1 if the file is a true DM4 file self.dmType = self.fromfile( self.fid, dtype=np.dtype('>u4'), count=1)[0] #file type: == 3 for DM3 or == 4 for DM4 if self.v: print('validDM: DM file type numer = {}'.format(self.dmType)) if self.dmType == 3: self.specialType = np.dtype('>u4') #uint32 elif self.dmType == 4: self.specialType = np.dtype('>u8') #uint64 else: raise IOError('File is not a valid DM3 or DM4') output = False self.fileSize = self.fromfile( self.fid, dtype=self.specialType, count=1)[0] #file size: real size - 24 bytes self.endianType = self.fromfile( self.fid, dtype=np.dtype('>u4'), count=1 )[0] #endian type: 1 == little endian (Intel), 2 == big endian (old powerPC Mac) if self.endianType != 1: #print('File is not written Little Endian (PC) format and can not be read by this program.') raise IOError( 'File is not written Little Endian (PC) format and can not be read by this program.' ) output = False #Test file size for corruption. Note that DM3/DM4 file size is always off by 20/24 bytes from what is written in the header osSize = fileStats(self.filename).st_size if self.dmType == 3: if self.fileSize != osSize - 20: pass #raise IOError('File size on disk ({}) does not match expected file size in header ({}). Invalid file.'.format(osSize, self.fileSize)) #output = False #print('Warning: file size on disk ({}) does not match expected file size in header ({}).'.format(osSize, self.fileSize)) elif self.dmType == 4: if self.fileSize != osSize - 24: pass #raise IOError('File size on disk ({}) does not match expected file size in header ({}). Invalid file.'.format(osSize, self.fileSize)) #output = False #print('Warning: file size on disk ({}) does not match expected file size in header ({}).'.format(osSize, self.fileSize)) return output
def __init__(self, filename, verbose=False, on_memory=False): self.filename = filename # necessary declarations, if something fails self.fid = None self._on_memory = on_memory # check for string if not isinstance(filename, str): raise TypeError('Filename is supposed to be a string') #Add a top level variable to indicate verbosee output for debugging self.v = verbose # try opening the file try: if not self._on_memory: self.fid = open(filename, 'rb') if self._on_memory: self._buffer_offset = 0 # Pre-load the file as a memory map that supports operations # similar to a file. with open(filename, 'rb') as _fid: if os.name == 'nt': self.fid = mmap.mmap(_fid.fileno(), 0, access=mmap.ACCESS_READ) else: self.fid = mmap.mmap( _fid.fileno(), 0, prot=mmap.PROT_READ) #, flags=mmap.MAP_PRIVATE) self._buffer_size = fileStats(filename).st_size except IOError: print('Error reading file: "{}"'.format(filename)) raise except: raise if not self._validDM(): #print('Not a valid DM3 or DM4 file: "{}"'.format(filename)) raise IOError('Can not read file: {}'.format(filename)) #Lists that will contain information about binary data arrays self.xSize = [] self.ySize = [] self.zSize = [] self.zSize2 = [] #only used for 4D datasets in DM4 files self.dataType = [] self.dataSize = [] self.dataOffset = [] self.dataShape = [ ] #1,2,3, or 4. The total number of dimensions in a data set #The number of objects found in the DM3 file self.numObjects = 0 #Indicator that a thumbnail exists (tested for later) self.thumbnail = False self.curGroupLevel = 0 #track how deep we currently are in a group self.maxDepth = 64 #maximum number of group levels allowed self.curGroupAtLevelX = np.zeros( (self.maxDepth, ), dtype=np.int8) #track group at current level self.curGroupNameAtLevelX = '' #set the name of the root group self.curTagAtLevelX = np.zeros( (self.maxDepth, ), dtype=np.int8) #track tag number at the current level self.curTagName = '' #string of the current tag #lists that will contain scale information (pixel size) self.scale = [] self.scaleUnit = [] self.origin = [] #Temporary variables to keep in case a tag entry shows useful information in an array self.scale_temp = 0 self.origin_temp = 0 self.allTags = {} self._encodedTypeSizes = { 0: 0, 8: 1, 9: 1, 10: 1, 2: 2, 4: 2, 3: 4, 5: 4, 6: 4, 7: 8, 12: 8 } self._DM2NPDataTypes = { 1: np.int16, 2: np.float32, 3: np.complex64, 6: np.uint8, 7: np.int32, 9: np.int8, 10: np.uint16, 11: np.uint32, 12: np.float64, 13: np.complex128 } self._TagType2NPDataTypes = { 2: np.int16, 3: np.int32, 4: np.uint16, 5: np.uint32, 6: np.float32, 7: np.float64, 8: np.uint8, 9: np.int8, 10: np.int8, 11: np.uint64, 12: np.uint64 } self._EncodedTypeDTypes = { 2: np.int16, 3: np.int32, 4: np.uint16, 5: np.uint32, 6: np.float32, 7: np.float64, 8: np.uint8, 9: np.uint8, 10: np.uint8, 12: np.uint64 } self.parseHeader()
def __init__(self, filename, verbose=False, on_memory=False): ''' Opens the file and reads its header. Accepts: filename: (str) the file path. verbose: (bool) if True, debug information is printed. on_memory: (bool) if True, file data is pre-loaded in memory and all data parsing is performed against memory. Use this mode if the file is in a network based or paralle file system. ''' self.filename = filename # necessary declarations, if something fails self.fid = None self.fidOut = None self._on_memory = on_memory # check for string if not isinstance(filename, str): raise TypeError('Filename is supposed to be a string ;D') #Add a top level variable to indicate verbose output for debugging self.v = verbose # try opening the file try: if not self._on_memory: self.fid = open(filename, 'rb') if self._on_memory: self._buffer_offset = 0 # Pre-load the file as a memory map that supports operations # similar to a file. with open(filename, 'rb') as _fid: if os.name == 'nt': self.fid = mmap.mmap(_fid.fileno(), 0, access=mmap.ACCESS_READ) else: self.fid = mmap.mmap( _fid.fileno(), 0, prot=mmap.PROT_READ) #, flags=mmap.MAP_PRIVATE) self._buffer_size = fileStats(filename).st_size except IOError: print('Error reading file: "{}"'.format(filename)) raise except: raise if not self._validDM(): #print('Not a valid DM3 or DM4 file: "{}"'.format(filename)) raise IOError('Can not read file: {}'.format(filename)) #Lists that will contain information about binary data arrays self.xSize = [] self.ySize = [] self.zSize = [] self.zSize2 = [] #only used for 4D datasets in DM4 files self.dataType = [] self.dataSize = [] self.dataOffset = [] self.dataShape = [ ] #1,2,3, or 4. The total number of dimensions in a data set #The number of objects found in the DM3 file self.numObjects = 0 #Indicator that a thumbnail exists (tested for later) self.thumbnail = False self.curGroupLevel = 0 #track how deep we currently are in a group self.maxDepth = 64 #maximum number of group levels allowed self.curGroupAtLevelX = np.zeros( (self.maxDepth, ), dtype=np.int8) #track group at current level self.curGroupNameAtLevelX = '' #set the name of the root group self.curTagAtLevelX = np.zeros( (self.maxDepth, ), dtype=np.int8) #track tag number at the current level self.curTagName = '' #string of the current tag #lists that will contain scale information (pixel size) self.scale = [] self.scaleUnit = [] self.origin = [] self.dataType = [] #Temporary variables to keep in case a tag entry shows useful information in an array self.scale_temp = 0 self.origin_temp = 0 self.outputDic = {} self.allTags = {}