/tomo/pyhst

To get this branch, use:
bzr branch http://darksoft.org/webbzr/tomo/pyhst
4 by csa
Initial import
1
"""
2
    EdfFile.py
3
    Generic class for Edf files manipulation.    
4
5
    Interface:
6
    ===========================
7
    class EdfFile:          
8
        __init__(self,FileName)	
9
        GetNumImages(self)
10
        def GetData(self,Index, DataType="",Pos=None,Size=None):
11
        GetPixel(self,Index,Position)
12
        GetHeader(self,Index)
13
        GetStaticHeader(self,Index)
14
        WriteImage (self,Header,Data,Append=1,DataType="",WriteAsUnsigened=0,ByteOrder="")
15
16
17
    Edf format assumptions:
18
    ===========================
19
    The following details were assumed for this implementation:
20
    - Each Edf file contains a certain number of data blocks.
21
    - Each data block represents data stored in an one, two or three-dimensional array.
22
    - Each data block contains a header section, written in ASCII, and a data section of
23
      binary information.
24
    - The size of the header section in bytes is a multiple of 1024. The header is
25
      padded with spaces (0x20). If the header is not padded to a multiple of 1024,
26
      the file is recognized, but the output is always made in this format.
27
    - The header section starts by '{' and finishes by '}'. It is composed by several
28
      pairs 'keyword = value;'. The keywords are case insensitive, but the values are case
29
      sensitive. Each pair is put in a new line (they are separeted by 0x0A). In the
30
      end of each line, a semicolon (;) separes the pair of a comment, not interpreted.
31
      Exemple:
32
        {
33
        ; Exemple Header
34
        HeaderID = EH:000001:000000:000000    ; automatically generated
35
        ByteOrder = LowByteFirst              ; 
36
        DataType = FloatValue                 ; 4 bytes per pixel
37
        Size = 4000000                        ; size of data section
38
        Dim_1= 1000                           ; x coordinates
39
        Dim_2 = 1000                          ; y coordinates
40
        
41
        (padded with spaces to complete 1024 bytes)
42
        }
43
    - There are some fields in the header that are required for this implementation. If any of
44
      these is missing, or inconsistent, it will be generated an error:
45
        Size: Represents size of data block
46
        Dim_1: size of x coordinates (Dim_2 for 2-dimentional images, and also Dim_3 for 3d)
47
        DataType
48
        ByteOrder
49
    - For the written images, these fields are automatically genereted:
50
        Size,Dim_1 (Dim_2 and Dim_3, if necessary), Byte Order, DataType, HeaderID and Image
51
      These fields are called here "static header", and can be retrieved by the method
52
      GetStaticHeader. Other header components are taken by GetHeader. Both methods returns
53
      a dictionary in which the key is the keyword of the pair. When writting an image through
54
      WriteImage method, the Header parameter should not contain the static header information,
55
      which is automatically generated.
56
    - The indexing of images through these functions is based just on the 0-based position in
57
      the file, the header items HeaderID and Image are not considered for referencing the
58
      images.
59
    - The data section contais a number of bytes equal to the value of Size keyword. Data
60
      section is going to be translated into an 1D, 2D or 3D Numaric Array, and accessed
61
      through GetData method call.      
62
63
64
    IMPORTANT - READ THIS
65
    ===========================
66
    If you are going to use EdfFile, you have to care about the type of your data.
67
    The EdfFile class stores data in a Numeric Python array, very efficient
68
    way for doing matrix operations.
69
70
    However, for an unknow reason (to us), Numeric Python doesn't handle the following
71
    types:
72
    - unsigned short
73
    - unsigned integer
74
    - unsigned long
75
    Which are supported by Edf file specification.
76
    So if you use these formats, pay attention to the type parameters when reading
77
    from or writing to a file (when using other Edf types, the convertions are direct,
78
    and you don't need to mention the type, unless you really want to change it).
79
80
    By default, if no type is mentioned, the EdfFile class stores, when reading a file:
81
    - UnsignedShort data into an short array
82
    - UnsignedInteger data into an integer array
83
    - UnsignedLong data into a long array
84
85
    This keeps the size of storage in memory, but can imply in loss of information.
86
87
    Taking "unsigned short" as an exemple:
88
    1) Supposing you get data with: "array=obj.GetData(0)", this array is going to be
89
       created as signed short. If you write it then as: 'obj2.WriteImage({},array)',
90
       the edf image created is going to be of signed short type, different from the
91
       original. To save in the same way as the former image, you must be explicit
92
       about the data type: 'obj2.WriteImage({},array,DataType="UnsignedShort")'
93
    2) If you intend to make operations, or even just read properly the values of an
94
       image, you should read this image as 'array=obj.GetData(0),DataType="Long")'.
95
       This will require two times the storage space but will assure correct values.
96
       If you intend to save it again, you should include the correct data type you
97
       are saving to.
98
    3) When you are saving an unsigned short array into a long, float or double
99
       format, you should be explicit to the fact you want this array to be
100
       considered a signed or unsigned (through the parameter WriteAsUnsigened).
101
       Suppose an hexa value of FFFF in this array. This means -1 if the array
102
       comes from signed data, or 65535 if it cames from unsigned data. If you save
103
       the array as this: 'obj2.WriteImage({},array,DataType="FloatValue")' it is
104
       going to be considered unsigned, and a value of FFFF is going to be
105
       translated into a float -1. If you want to consider the array as unsigned
106
       you should do:
107
       'obj2.WriteImage({},array,DataType="FloatValue", WriteAsUnsigened=1 )'
108
       In this way, a FFFF value is going to be translated into a float 65535.
109
110
111
"""
112
113
__author__ =  'Alexandre Gobbo (gobbo@esrf.fr)'
114
__version__=  '$Revision: 1.5 $'
115
116
################################################################################  
117
import sys, string
34 by csa
Migration to numpy
118
import numpy as Numeric
4 by csa
Initial import
119
import os.path , tempfile, shutil
7 by csa
more consistent logging
120
from logger import logger
121
4 by csa
Initial import
122
try:
123
    from FastEdf import extended_fread
124
    CAN_USE_FASTEDF = 1
7 by csa
more consistent logging
125
    logger.info(" imported the fast binary for edffile readings ")
4 by csa
Initial import
126
except:
127
    CAN_USE_FASTEDF = 0
7 by csa
more consistent logging
128
    logger.warning(" WARNING, the FastEDF is not imported (extended_fread is missing)")
4 by csa
Initial import
129
130
################################################################################
131
# constants
132
HEADER_BLOCK_SIZE = 1024
133
STATIC_HEADER_ELEMENTS=("HeaderID","Image","ByteOrder","DataType","Dim_1","Dim_2","Dim_3","Size")
134
STATIC_HEADER_ELEMENTS_CAPS=("HEADERID","IMAGE","BYTEORDER","DATATYPE","DIM_1","DIM_2","DIM_3","SIZE")
135
136
LOWER_CASE=0
137
UPPER_CASE=1
138
139
KEYS=1
140
VALUES=2
141
142
###############################################################################
143
class Image:
144
    """
145
    """
146
    def __init__(self):
147
        """ Constructor
148
        """
149
        self.Header={}
150
        self.StaticHeader={}
151
        self.HeaderPosition=0
152
        self.DataPosition=0
153
        self.Size=0
154
        self.NumDim=1
155
        self.Dim1=0
156
        self.Dim2=0
157
        self.Dim3=0
158
        self.DataType=""
159
        #for i in STATIC_HEADER_ELEMENTS: self.StaticHeader[i]=""
160
   
161
################################################################################
162
163
class  EdfFile:    
164
    """
165
    """
166
    ############################################################################
167
    #Interface
168
    def __init__(self,FileName,fastedf=None):
169
        """ Constructor
170
            FileName:   Name of the file (either existing or to be created)  
171
        """
172
        self.Images=[]
173
        self.NumImages=0
174
        self.FileName=FileName
175
        self.File = 0
176
        if fastedf is None:fastedf=0
177
        self.fastedf=fastedf
178
        
179
        if sys.byteorder=="big": self.SysByteOrder="HighByteFirst"
180
        else: self.SysByteOrder="LowByteFirst"
181
        try:
182
            if os.path.isfile(self.FileName)==0:                
183
                self.File = open(self.FileName, "wb")
184
                self.File.close()    
185
186
            if (os.access(self.FileName,os.W_OK)):
187
                self.File=open(self.FileName, "r+b")
188
            else : 
189
                self.File=open(self.FileName, "rb")
190
191
            self.File.seek(0, 0)
37 by csa
Optimizations of EDF reading
192
        except None:
4 by csa
Initial import
193
            try:
194
                self.File.close()
195
            except:
196
                pass
197
            print "filename ", FileName
198
            raise Exception, "EdfFile: Error opening file"
199
200
        self.File.seek(0, 0)
201
        
202
        Index=0
203
        line = self.File.readline()        
204
        while line != "":           
205
            if string.count(line, "{\n") >= 1 or string.count(line, "{\r\n")>=1:
206
                Index=self.NumImages
207
                self.NumImages = self.NumImages + 1                
208
                self.Images.append(Image())
209
                self.Images[Index].HeaderPosition=self.File.tell()    
210
                
211
            if string.count(line, "=") >= 1:
212
                listItems = string.split(line, "=", 1)
213
                typeItem = string.strip(listItems[0])
214
                listItems = string.split(listItems[1], ";", 1)
215
                valueItem = string.strip(listItems[0])
216
217
                #if typeItem in self.Images[Index].StaticHeader.keys():          
218
                if (string.upper(typeItem)) in STATIC_HEADER_ELEMENTS_CAPS:          
219
                    self.Images[Index].StaticHeader[typeItem]=valueItem                    
220
                else:
221
                    self.Images[Index].Header[typeItem]=valueItem
222
            if string.count(line, "}\n") >= 1:
223
                #for i in STATIC_HEADER_ELEMENTS_CAPS:
224
                #    if self.Images[Index].StaticHeader[i]=="":
225
                #        raise Exception, "Bad File Format"
226
                self.Images[Index].DataPosition=self.File.tell()
227
                #self.File.seek(string.atoi(self.Images[Index].StaticHeader["Size"]), 1)
228
                StaticPar = SetDictCase(self.Images[Index].StaticHeader,UPPER_CASE,KEYS)
229
                if "SIZE" in StaticPar.keys():
230
                    self.Images[Index].Size = string.atoi(StaticPar["SIZE"])
231
                else:
232
                    raise Exception, "EdfFile: Image doesn't have size information"                
233
                if "DIM_1" in StaticPar.keys():
234
                    self.Images[Index].Dim1 = string.atoi(StaticPar["DIM_1"])
235
                else:
236
                    raise Exception, "EdfFile: Image doesn't have dimension information"
237
                if "DIM_2" in StaticPar.keys():
238
                    self.Images[Index].NumDim=2
239
                    self.Images[Index].Dim2 = string.atoi(StaticPar["DIM_2"])
240
                if "DIM_3" in StaticPar.keys():
241
                    self.Images[Index].NumDim=3
242
                    self.Images[Index].Dim3 = string.atoi(StaticPar["DIM_3"])
243
                if "DATATYPE" in StaticPar.keys():
244
                    self.Images[Index].DataType=StaticPar["DATATYPE"]
245
                else:
246
                    raise Exception, "EdfFile: Image doesn't have datatype information"
247
                if "BYTEORDER" in StaticPar.keys():
248
                    self.Images[Index].ByteOrder=StaticPar["BYTEORDER"]
249
                else:
250
                    raise Exception, "EdfFile: Image doesn't have byteorder information"
251
                    
252
253
                                
254
                self.File.seek(self.Images[Index].Size, 1)
255
                
256
            line = self.File.readline()
257
    
258
        
259
    def GetNumImages(self):
260
        """ Returns number of images of the object (and associated file)
261
        """
262
        return self.NumImages
263
264
        
265
    
266
    def GetData(self,Index, DataType="",Pos=None,Size=None):
267
        """ Returns numeric array with image data
268
            Index:          The zero-based index of the image in the file
269
            DataType:       The edf type of the array to be returnd
270
                            If ommited, it is used the default one for the type
271
                            indicated in the image header
272
                            Attention to the absence of UnsignedShort,
273
                            UnsignedInteger and UnsignedLong types in
274
                            Numeric Python
275
                            Default relation between Edf types and NumPy's typecodes:
276
                                SignedByte          1
277
                                UnsignedByte        b       
278
                                SignedShort         s
279
                                UnsignedShort       w
280
                                SignedInteger       i
281
                                UnsignedInteger     u
282
                                SignedLong          l
283
                                UnsignedLong        u
284
                                FloatValue          f
285
                                DoubleValue         d
286
            Pos:            Tuple (x) or (x,y) or (x,y,z) that indicates the begining
287
                            of data to be read. If ommited, set to the origin (0),
288
                            (0,0) or (0,0,0)
289
            Size:           Tuple, size of the data to be returned as x) or (x,y) or
290
                            (x,y,z) if ommited, is the distance from Pos to the end.
291
292
            If Pos and Size not mentioned, returns the whole data.                         
293
        """
294
        fastedf = self.fastedf
295
        if Index < 0 or Index >= self.NumImages: raise Exception, "EdfFile: Index(%i) is out of %i available images" % (Index, self.NumImages)
296
        if fastedf is None:fastedf = 0
297
        if Pos is None and Size is None:
298
            self.File.seek(self.Images[Index].DataPosition,0)
299
            Data = Numeric.fromstring(self.File.read(self.Images[Index].Size), self.__GetDefaultNumericType__(self.Images[Index].DataType))
300
            if self.Images[Index].NumDim==3:
301
                Data = Numeric.reshape(Data, (self.Images[Index].Dim3,self.Images[Index].Dim2, self.Images[Index].Dim1))            
302
            elif self.Images[Index].NumDim==2:
303
                Data = Numeric.reshape(Data, (self.Images[Index].Dim2, self.Images[Index].Dim1)) 
304
        elif fastedf and CAN_USE_FASTEDF:
305
            type= self.__GetDefaultNumericType__(self.Images[Index].DataType)
306
            size_pixel=self.__GetSizeNumericType__(type)
307
            Data=Numeric.array([],type)
308
            if self.Images[Index].NumDim==1:
309
                if Pos==None: Pos=(0,)
310
                if Size==None: Size=(0,)
311
                sizex=self.Images[Index].Dim1
312
                Size=list(Size)                
313
                if Size[0]==0:Size[0]=sizex-Pos[0]
314
                self.File.seek((Pos[0]*size_pixel)+self.Images[Index].DataPosition,0)
315
                Data = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type)
316
            elif self.Images[Index].NumDim==2:                
317
                if Pos==None: Pos=(0,0)
318
                if Size==None: Size=(0,0)
319
                Size=list(Size)
320
                sizex,sizey=self.Images[Index].Dim1,self.Images[Index].Dim2
321
                if Size[0]==0:Size[0]=sizex-Pos[0]
322
                if Size[1]==0:Size[1]=sizey-Pos[1]
323
                Data=Numeric.zeros([Size[1],Size[0]],type)
324
                self.File.seek((((Pos[1]*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0)
36 by csa
Fix usage of fast EDF reader
325
		#print Size[0], Size[1], sizex, size_pixel
326
                extended_fread(Data, Size[0]*size_pixel , Numeric.array([Size[1]],"i"), Numeric.array([sizex*size_pixel],"i"), self.File)
4 by csa
Initial import
327
328
            elif self.Images[Index].NumDim==3:
329
                if Pos==None: Pos=(0,0,0)
330
                if Size==None: Size=(0,0,0)
331
                Size=list(Size)
332
                sizex,sizey,sizez=self.Images[Index].Dim1,self.Images[Index].Dim2,self.Images[Index].Dim3
333
                if Size[0]==0:Size[0]=sizex-Pos[0]
334
                if Size[1]==0:Size[1]=sizey-Pos[1]
335
                if Size[2]==0:Size[2]=sizez-Pos[2]
336
                Data=Numeric.zeros([Size[2],Size[1],Size[0]],type)
337
                self.File.seek(((((Pos[2]*sizey+Pos[1])*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0)
36 by csa
Fix usage of fast EDF reader
338
                extended_fread(Data, Size[0]*size_pixel , Numeric.array([Size[2],Size[1]], "i"),
339
                        Numeric.array([ sizey*sizex*size_pixel , sizex*size_pixel], "i") ,self.File)
4 by csa
Initial import
340
341
        else:
342
            if fastedf:print "I could not use fast routines"
343
            type= self.__GetDefaultNumericType__(self.Images[Index].DataType)
344
            size_pixel=self.__GetSizeNumericType__(type)
345
            Data=Numeric.array([],type)
346
            if self.Images[Index].NumDim==1:
347
                if Pos==None: Pos=(0,)
348
                if Size==None: Size=(0,)
349
                sizex=self.Images[Index].Dim1
350
                Size=list(Size)                
351
                if Size[0]==0:Size[0]=sizex-Pos[0]
352
                self.File.seek((Pos[0]*size_pixel)+self.Images[Index].DataPosition,0)
353
                Data = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type)
354
            elif self.Images[Index].NumDim==2:                
355
                if Pos==None: Pos=(0,0)
356
                if Size==None: Size=(0,0)
357
                Size=list(Size)
358
                sizex,sizey=self.Images[Index].Dim1,self.Images[Index].Dim2
359
                if Size[0]==0:Size[0]=sizex-Pos[0]
360
                if Size[1]==0:Size[1]=sizey-Pos[1]
361
                for y in range(Pos[1],Pos[1]+Size[1]):
362
                    self.File.seek((((y*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0)
363
                    line = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type)
364
                    Data=Numeric.concatenate((Data,line))
365
                Data = Numeric.reshape(Data, (Size[1],Size[0]))                            
366
            elif self.Images[Index].NumDim==3:
367
                if Pos==None: Pos=(0,0,0)
368
                if Size==None: Size=(0,0,0)
369
                Size=list(Size)
370
                sizex,sizey,sizez=self.Images[Index].Dim1,self.Images[Index].Dim2,self.Images[Index].Dim3
371
                if Size[0]==0:Size[0]=sizex-Pos[0]
372
                if Size[1]==0:Size[1]=sizey-Pos[1]
373
                if Size[2]==0:Size[2]=sizez-Pos[2]
374
                for z in range(Pos[2],Pos[2]+Size[2]):
375
                    for y in range(Pos[1],Pos[1]+Size[1]):
376
                        self.File.seek(((((z*sizey+y)*sizex)+Pos[0])*size_pixel)+self.Images[Index].DataPosition,0)
377
                        line = Numeric.fromstring(self.File.read(Size[0]*size_pixel), type)
378
                        Data=Numeric.concatenate((Data,line))                
379
                Data = Numeric.reshape(Data, (Size[2],Size[1],Size[0]))
380
381
        if string.upper(self.SysByteOrder)!=string.upper(self.Images[Index].ByteOrder):
34 by csa
Migration to numpy
382
            Data=Data.byteswap(False)
4 by csa
Initial import
383
        if DataType != "":
384
            Data=self.__SetDataType__ (Data,DataType)
385
        return Data
386
387
388
389
    def GetPixel(self,Index, Position):
390
        """ Returns double value of the pixel, regardless the format of the array
391
            Index:      The zero-based index of the image in the file
392
            Position:   Tuple with the coordinete (x), (x,y) or (x,y,z)
393
        """
394
        if Index < 0 or Index >= self.NumImages: raise Exception, "EdfFile: Index out of limit"
395
        if len(Position)!= self.Images[Index].NumDim: raise Exception, "EdfFile: coordinate with wrong dimension "
396
        
397
        size_pixel=self.__GetSizeNumericType__(self.__GetDefaultNumericType__(self.Images[Index].DataType))
398
        offset=Position[0]*size_pixel
399
        if self.Images[Index].NumDim>1:
400
            size_row=size_pixel * self.Images[Index].Dim1
401
            offset=offset+ (Position[1]* size_row)
402
            if self.Images[Index].NumDim==3:
403
                size_img=size_row * self.Images[Index].Dim2
404
                offset=offset+ (Position[2]* size_img)
405
        self.File.seek(self.Images[Index].DataPosition + offset,0)
406
        Data = Numeric.fromstring(self.File.read(size_pixel), self.__GetDefaultNumericType__(self.Images[Index].DataType))
407
        if string.upper(self.SysByteOrder)!=string.upper(self.Images[Index].ByteOrder):
408
            Data=Data.byteswapped() 
409
        Data=self.__SetDataType__ (Data,"DoubleValue")
410
        return Data[0]
411
         
412
        
413
    def GetHeader(self,Index):
414
        """ Returns dictionary with image header fields.
415
            Does not include the basic fields (static) defined by data shape, 
416
            type and file position. These are get with GetStaticHeader
417
            method.
418
            Index:          The zero-based index of the image in the file
419
        """
420
        if Index < 0 or Index >= self.NumImages: raise Exception, "Index out of limit"
421
        #return self.Images[Index].Header
422
        ret={}
423
        for i in self.Images[Index].Header.keys():
424
            ret[i]=self.Images[Index].Header[i]        
425
        return ret
426
427
        
428
    def GetStaticHeader(self,Index):
429
        """ Returns dictionary with static parameters
430
            Data format and file position dependent information
431
            (dim1,dim2,size,datatype,byteorder,headerId,Image)
432
            Index:          The zero-based index of the image in the file
433
        """ 
434
        if Index < 0 or Index >= self.NumImages: raise Exception, "Index out of limit"
435
        #return self.Images[Index].StaticHeader
436
        ret={}
437
        for i in self.Images[Index].StaticHeader.keys():
438
            ret[i]=self.Images[Index].StaticHeader[i]        
439
        return ret
440
441
442
    def WriteImage (self,Header,Data,Append=1,DataType="",ByteOrder=""):
443
        """ Writes image to the file. 
444
            Header:         Dictionary containing the non-static header
445
                            information (static information is generated
446
                            according to position of image and data format
447
            Append:         If equals to 0, overwrites the file. Otherwise, appends
448
                            to the end of the file
449
            DataType:       The data type to be saved to the file:
450
                                SignedByte          
451
                                UnsignedByte               
452
                                SignedShort         
453
                                UnsignedShort       
454
                                SignedInteger       
455
                                UnsignedInteger     
456
                                SignedLong          
457
                                UnsignedLong        
458
                                FloatValue          
459
                                DoubleValue         
460
                            Default: according to Data array typecode:
461
                                    1:  SignedByte
462
                                    b:  UnsignedByte
463
                                    s:  SignedShort       
464
				    w:  UnsignedShort
465
                                    i:  SignedInteger
466
                                    l:  SignedLong          
467
				    u:  UnsignedLong
468
                                    f:  FloatValue       
469
                                    d:  DoubleValue
470
            ByteOrder:      Byte order of the data in file:
471
                                HighByteFirst
472
                                LowByteFirst
473
                            Default: system's byte order
474
        """
475
        if Append==0:
476
            self.File.truncate(0)
477
            self.Images=[]
478
            self.NumImages=0
479
        Index=self.NumImages
480
        self.NumImages = self.NumImages + 1                
481
        self.Images.append(Image())
482
483
        #self.Images[Index].StaticHeader["Dim_1"] = "%d" % Data.shape[1]
484
        #self.Images[Index].StaticHeader["Dim_2"] = "%d" % Data.shape[0]
485
        if len(Data.shape)==1:
486
            self.Images[Index].Dim1=Data.shape[0]
487
            self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
34 by csa
Migration to numpy
488
            self.Images[Index].Size=(Data.shape[0]*self.__GetSizeNumericType__(Data.dtype.char))
4 by csa
Initial import
489
        elif len(Data.shape)==2:
490
            self.Images[Index].Dim1=Data.shape[1]
491
            self.Images[Index].Dim2=Data.shape[0]
492
            self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
493
            self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2
34 by csa
Migration to numpy
494
            self.Images[Index].Size=(Data.shape[0]*Data.shape[1]*self.__GetSizeNumericType__(Data.dtype.char))
4 by csa
Initial import
495
            self.Images[Index].NumDim=2
496
        elif len(Data.shape)==3:
497
            self.Images[Index].Dim1=Data.shape[2]
498
            self.Images[Index].Dim2=Data.shape[1]
499
            self.Images[Index].Dim3=Data.shape[0]
500
            self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
501
            self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2
502
            self.Images[Index].StaticHeader["Dim_3"] = "%d" % self.Images[Index].Dim3
34 by csa
Migration to numpy
503
            self.Images[Index].Size=(Data.shape[0]*Data.shape[1]*Data.shape[2]*self.__GetSizeNumericType__(Data.dtype.char))
4 by csa
Initial import
504
            self.Images[Index].NumDim=3
505
        elif len(Data.shape)>3:
506
            raise Exception, "EdfFile: Data dimension not suported"
507
        
508
509
        if DataType=="":
34 by csa
Migration to numpy
510
            self.Images[Index].DataType=self.__GetDefaultEdfType__(Data.dtype.char)
4 by csa
Initial import
511
        else:
512
            self.Images[Index].DataType=DataType
513
            Data=self.__SetDataType__ (Data,DataType)
514
                            
515
        if ByteOrder=="":
516
            self.Images[Index].ByteOrder=self.SysByteOrder
517
        else:
518
            self.Images[Index].ByteOrder=ByteOrder
519
                
520
        self.Images[Index].StaticHeader["Size"]  = "%d" % self.Images[Index].Size
521
        self.Images[Index].StaticHeader["Image"] = Index+1
522
        self.Images[Index].StaticHeader["HeaderID"] = "EH:%06d:000000:000000" % self.Images[Index].StaticHeader["Image"]
523
        self.Images[Index].StaticHeader["ByteOrder"]=self.Images[Index].ByteOrder
524
        self.Images[Index].StaticHeader["DataType"]=self.Images[Index].DataType
525
526
        
527
        self.Images[Index].Header={}            
528
        self.File.seek(0,2)
529
        StrHeader = "{\n"
530
        for i in STATIC_HEADER_ELEMENTS:
531
            if i in self.Images[Index].StaticHeader.keys():
532
                StrHeader = StrHeader + ("%s = %s ;\n" % (i , self.Images[Index].StaticHeader[i]))
533
        for i in Header.keys():
534
            StrHeader = StrHeader + ("%s = %s ;\n" % (i,Header[i]))
535
            self.Images[Index].Header[i]=Header[i]
536
        newsize=(((len(StrHeader)+1)/HEADER_BLOCK_SIZE)+1)*HEADER_BLOCK_SIZE -2                   
537
        StrHeader = string.ljust(StrHeader,newsize)
538
        StrHeader = StrHeader+"}\n"
539
540
        self.Images[Index].HeaderPosition=self.File.tell()    
541
        self.File.write(StrHeader)
542
        self.Images[Index].DataPosition=self.File.tell()
543
544
        #if self.Images[Index].StaticHeader["ByteOrder"] != self.SysByteOrder:
545
        if string.upper(self.Images[Index].ByteOrder) != string.upper(self.SysByteOrder):
546
            self.File.write((Data.byteswapped()).tostring())  
547
        else:
548
            self.File.write(Data.tostring())
549
        
550
        
551
552
    ############################################################################
553
    #Internal Methods
554
        
555
    def __GetDefaultNumericType__(self, EdfType):
556
        """ Internal method: returns NumPy type according to Edf type
557
        """
558
        return GetDefaultNumericType(EdfType)
559
560
    def __GetDefaultEdfType__(self, NumericType):
561
        """ Internal method: returns Edf type according Numpy type
562
        """
563
        if  NumericType  == "1":            return "SignedByte"
564
        elif NumericType == "b":            return "UnsignedByte"
565
        elif NumericType == "s":            return "SignedShort"          
566
        elif NumericType == "w":            return "UnsignedShort"          
567
        elif NumericType == "i":            return "SignedInteger"  
568
        elif NumericType == "l":            return "SignedLong"           
569
	elif NumericType == "u":	    return "UnsignedLong"
570
        elif NumericType == "f":            return "FloatValue"         
571
        elif NumericType == "d":            return "DoubleValue"
572
        else: raise Exception, "__GetDefaultEdfType__: unknown NumericType"
573
574
575
    def __GetSizeNumericType__(self, NumericType):
576
        """ Internal method: returns size of NumPy's Array Types
577
        """
578
        if  NumericType  == "1":            return 1
579
        elif NumericType == "b":            return 1
580
        elif NumericType == "s":            return 2         
581
	elif NumericType == "w":	    return 2
582
        elif NumericType == "i":            return 4  
583
        elif NumericType == "l":            return 4           
584
        elif NumericType == "u":	    return 4
585
        elif NumericType == "f":            return 4         
586
        elif NumericType == "d":            return 8
587
        else: raise Exception, "__GetSizeNumericType__: unknown NumericType"
588
589
590
    def __SetDataType__ (self,Array,DataType):
591
        """ Internal method: array type convertion
592
        """
34 by csa
Migration to numpy
593
        FromEdfType= Array.dtype.char
4 by csa
Initial import
594
        ToEdfType= self.__GetDefaultNumericType__(DataType)
595
        if ToEdfType != FromEdfType:
596
            aux=Array.astype(self.__GetDefaultNumericType__(DataType))    
597
            return aux
598
        return Array
599
600
    def __del__(self):
601
        try:
602
            self.File.close()
603
        except:
604
            pass
605
        
606
607
def GetDefaultNumericType(EdfType):
608
    """ Returns NumPy type according Edf type
609
    """
610
    EdfType=string.upper(EdfType)
611
    if   EdfType == "SIGNEDBYTE":       return "1"
612
    elif EdfType == "UNSIGNEDBYTE":     return "b"       
613
    elif EdfType == "SIGNEDSHORT":      return "s"
614
    elif EdfType == "UNSIGNEDSHORT":    return "w"
615
    elif EdfType == "SIGNEDINTEGER":    return "i"
616
    elif EdfType == "UNSIGNEDINTEGER":  return "u"
617
    elif EdfType == "SIGNEDLONG":       return "l"
618
    elif EdfType == "UNSIGNEDLONG":     return "u"
619
    elif EdfType == "FLOATVALUE":       return "f"
620
    elif EdfType == "FLOAT":            return "f"
621
    elif EdfType == "DOUBLEVALUE":      return "d"
622
    else: raise Exception, "__GetDefaultNumericType__: unknown EdfType"
623
624
625
def SetDictCase(Dict, Case, Flag):
626
    """ Returns dictionary with keys and/or values converted into upper or lowercase
627
        Dict:   input dictionary
628
        Case:   LOWER_CASE, UPPER_CASE
629
        Flag:   KEYS, VALUES or KEYS | VALUES        
630
    """
631
    newdict={}
632
    for i in Dict.keys():
633
        newkey=i
634
        newvalue=Dict[i]
635
        if Flag & KEYS:
636
            if Case == LOWER_CASE:  newkey = string.lower(newkey)
637
            else:                   newkey = string.upper(newkey)
638
        if Flag & VALUES:
639
            if Case == LOWER_CASE:  newvalue = string.lower(newvalue)
640
            else:                   newvalue = string.upper(newvalue)
641
        newdict[newkey]=newvalue
642
    return newdict    
643
644
645
def GetRegion(Arr,Pos,Size):
646
    """Returns array with refion of Arr.
647
       Arr must be 1d, 2d or 3d
648
       Pos and Size are tuples in the format (x) or (x,y) or (x,y,z)
649
       Both parameters must have the same size as the dimention of Arr
650
    """
651
    Dim=len(Arr.shape)
652
    if len(Pos) != Dim:  return None
653
    if len(Size) != Dim: return None
654
    
655
    if (Dim==1):
656
        SizeX=Size[0]
657
        if SizeX==0: SizeX=Arr.shape[0]-Pos[0]
658
        ArrRet=Numeric.take(Arr, range(Pos[0],Pos[0]+SizeX))
659
    elif (Dim==2):
660
        SizeX=Size[0]
661
        SizeY=Size[1]
662
        if SizeX==0: SizeX=Arr.shape[1]-Pos[0]
663
        if SizeY==0: SizeY=Arr.shape[0]-Pos[1]
664
        ArrRet=Numeric.take(Arr, range(Pos[1],Pos[1]+SizeY))
665
        ArrRet=Numeric.take(ArrRet, range(Pos[0],Pos[0]+SizeX),1)
666
    elif (Dim==3):
667
        SizeX=Size[0]
668
        SizeY=Size[1]
669
        SizeZ=Size[2]
670
        if SizeX==0: SizeX=Arr.shape[2]-Pos[0]
671
        if SizeY==0: SizeX=Arr.shape[1]-Pos[1]
672
        if SizeZ==0: SizeZ=Arr.shape[0]-Pos[2]
673
        ArrRet=Numeric.take(Arr, range(Pos[2],Pos[2]+SizeZ))
674
        ArrRet=Numeric.take(ArrRet, range(Pos[1],Pos[1]+SizeY),1)
675
        ArrRet=Numeric.take(ArrRet, range(Pos[0],Pos[0]+SizeX),2)
676
    else:
677
        ArrRet=None
678
    return ArrRet
679
680
#EXEMPLE CODE:        
681
if __name__ == "__main__":    
682
    #Creates object based on file exe.edf
683
    exe=EdfFile("images/test_image.edf")
684
    x=EdfFile("images/test_getdata.edf")
685
    #Gets unsigned short data, storing in an signed long
686
    arr=exe.GetData(0,Pos=(100,200),Size=(200,400))
687
    x.WriteImage({},arr,0)
688
689
    arr=exe.GetData(0,Pos=(100,200))
690
    x.WriteImage({},arr)
691
692
    arr=exe.GetData(0,Size=(200,400))
693
    x.WriteImage({},arr)
694
695
    arr=exe.GetData(0)
696
    x.WriteImage({},arr)
697
    
698
    sys.exit()
699
        
700
    #Creates object based on file exe.edf
701
    exe=EdfFile("images/.edf")
702
703
    #Creates long array , filled with 0xFFFFFFFF(-1)
704
    la=Numeric.zeros((100,100))
705
    la=la-1
706
    
707
    #Creates a short array, filled with 0xFFFF
708
    sa=Numeric.zeros((100,100))
709
    sa=sa+0xFFFF
710
    sa=sa.astype("s")
711
712
    #Writes long array, initializing file (append=0)
713
    exe.WriteImage({},la,0,"")
714
    
715
    #Appends short array with new header items
716
    exe.WriteImage({'Name': 'Alexandre', 'Date': '16/07/2001'},sa)    
717
718
    #Appends short array, in Edf type unsigned
719
    exe.WriteImage({},sa,DataType="UnsignedShort")    
720
721
    #Appends short array, in Edf type unsigned
722
    exe.WriteImage({},sa,DataType="UnsignedLong")    
723
724
    #Appends long array as a double, considering unsigned
725
    exe.WriteImage({},la,DataType="DoubleValue",WriteAsUnsigened=1)
726
727
    #Gets unsigned short data, storing in an signed long
728
    ushort=exe.GetData(2,"SignedLong")
729
730
    #Makes an operation
731
    ushort=ushort-0x10
732
733
    #Saves Result as signed long
734
    exe.WriteImage({},ushort)
735
736
    #Saves in the original format (unsigned short)
737
    OldHeader=exe.GetStaticHeader(2)
738
    exe.WriteImage({},ushort,1,OldHeader["DataType"] )
739