fabio 0.1.1__zip

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.
Files changed (67) hide show
  1. Library/Python/2.7/site-packages/fabio/GEimage.py +334 -0
  2. Library/Python/2.7/site-packages/fabio/GEimage.pyc +0 -0
  3. Library/Python/2.7/site-packages/fabio/GEimage_old.py +501 -0
  4. Library/Python/2.7/site-packages/fabio/GEimage_old.pyc +0 -0
  5. Library/Python/2.7/site-packages/fabio/HiPiCimage.py +106 -0
  6. Library/Python/2.7/site-packages/fabio/HiPiCimage.pyc +0 -0
  7. Library/Python/2.7/site-packages/fabio/OXDimage.py +442 -0
  8. Library/Python/2.7/site-packages/fabio/OXDimage.pyc +0 -0
  9. Library/Python/2.7/site-packages/fabio/TiffIO.py +1197 -0
  10. Library/Python/2.7/site-packages/fabio/TiffIO.pyc +0 -0
  11. Library/Python/2.7/site-packages/fabio/__init__.py +10 -0
  12. Library/Python/2.7/site-packages/fabio/__init__.pyc +0 -0
  13. Library/Python/2.7/site-packages/fabio/adscimage.py +137 -0
  14. Library/Python/2.7/site-packages/fabio/adscimage.pyc +0 -0
  15. Library/Python/2.7/site-packages/fabio/binaryimage.py +87 -0
  16. Library/Python/2.7/site-packages/fabio/binaryimage.pyc +0 -0
  17. Library/Python/2.7/site-packages/fabio/bruker100image.py +96 -0
  18. Library/Python/2.7/site-packages/fabio/bruker100image.pyc +0 -0
  19. Library/Python/2.7/site-packages/fabio/brukerimage.py +195 -0
  20. Library/Python/2.7/site-packages/fabio/brukerimage.pyc +0 -0
  21. Library/Python/2.7/site-packages/fabio/byte_offset.so +0 -0
  22. Library/Python/2.7/site-packages/fabio/cbfimage.py +758 -0
  23. Library/Python/2.7/site-packages/fabio/cbfimage.pyc +0 -0
  24. Library/Python/2.7/site-packages/fabio/cf_io.so +0 -0
  25. Library/Python/2.7/site-packages/fabio/compression.py +388 -0
  26. Library/Python/2.7/site-packages/fabio/compression.pyc +0 -0
  27. Library/Python/2.7/site-packages/fabio/converters.py +54 -0
  28. Library/Python/2.7/site-packages/fabio/converters.pyc +0 -0
  29. Library/Python/2.7/site-packages/fabio/datIO.py +60 -0
  30. Library/Python/2.7/site-packages/fabio/datIO.pyc +0 -0
  31. Library/Python/2.7/site-packages/fabio/dm3image.py +219 -0
  32. Library/Python/2.7/site-packages/fabio/dm3image.pyc +0 -0
  33. Library/Python/2.7/site-packages/fabio/edfimage.py +924 -0
  34. Library/Python/2.7/site-packages/fabio/edfimage.pyc +0 -0
  35. Library/Python/2.7/site-packages/fabio/fabioimage.py +556 -0
  36. Library/Python/2.7/site-packages/fabio/fabioimage.pyc +0 -0
  37. Library/Python/2.7/site-packages/fabio/fabioutils.py +491 -0
  38. Library/Python/2.7/site-packages/fabio/fabioutils.pyc +0 -0
  39. Library/Python/2.7/site-packages/fabio/file_series.py +313 -0
  40. Library/Python/2.7/site-packages/fabio/file_series.pyc +0 -0
  41. Library/Python/2.7/site-packages/fabio/fit2dmaskimage.py +94 -0
  42. Library/Python/2.7/site-packages/fabio/fit2dmaskimage.pyc +0 -0
  43. Library/Python/2.7/site-packages/fabio/fit2dspreadsheetimage.py +85 -0
  44. Library/Python/2.7/site-packages/fabio/fit2dspreadsheetimage.pyc +0 -0
  45. Library/Python/2.7/site-packages/fabio/kcdimage.py +131 -0
  46. Library/Python/2.7/site-packages/fabio/kcdimage.pyc +0 -0
  47. Library/Python/2.7/site-packages/fabio/mar345_IO.so +0 -0
  48. Library/Python/2.7/site-packages/fabio/mar345image.py +320 -0
  49. Library/Python/2.7/site-packages/fabio/mar345image.pyc +0 -0
  50. Library/Python/2.7/site-packages/fabio/marccdimage.py +309 -0
  51. Library/Python/2.7/site-packages/fabio/marccdimage.pyc +0 -0
  52. Library/Python/2.7/site-packages/fabio/openimage.py +162 -0
  53. Library/Python/2.7/site-packages/fabio/openimage.pyc +0 -0
  54. Library/Python/2.7/site-packages/fabio/pilatusimage.py +81 -0
  55. Library/Python/2.7/site-packages/fabio/pilatusimage.pyc +0 -0
  56. Library/Python/2.7/site-packages/fabio/pnmimage.py +165 -0
  57. Library/Python/2.7/site-packages/fabio/pnmimage.pyc +0 -0
  58. Library/Python/2.7/site-packages/fabio/readbytestream.py +86 -0
  59. Library/Python/2.7/site-packages/fabio/readbytestream.pyc +0 -0
  60. Library/Python/2.7/site-packages/fabio/tifimage.py +283 -0
  61. Library/Python/2.7/site-packages/fabio/tifimage.pyc +0 -0
  62. Library/Python/2.7/site-packages/fabio/xsdimage.py +134 -0
  63. Library/Python/2.7/site-packages/fabio/xsdimage.pyc +0 -0
  64. Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/PKG-INFO +11 -0
  65. Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/SOURCES.txt +114 -0
  66. Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/dependency_links.txt +1 -0
  67. Library/Python/2.7/site-packages/fabio-0.1.1-py2.7.egg-info/top_level.txt +4 -0
@@ -0,0 +1,924 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf8 -*-
3
+ """
4
+
5
+ License: GPLv2+
6
+
7
+ Authors: Henning O. Sorensen & Erik Knudsen
8
+ Center for Fundamental Research: Metal Structures in Four Dimensions
9
+ Risoe National Laboratory
10
+ Frederiksborgvej 399
11
+ DK-4000 Roskilde
12
+ email:erik.knudsen@risoe.dk
13
+
14
+ + Jon Wright, ESRF
15
+
16
+ 2011-02-11: Mostly rewritten by Jérôme Kieffer (Jerome.Kieffer@esrf.eu)
17
+ European Synchrotron Radiation Facility
18
+ Grenoble (France)
19
+ 2012-08-20: laisy read of data in EDF
20
+ """
21
+ from __future__ import with_statement
22
+ import os, logging, types
23
+ logger = logging.getLogger("edfimage")
24
+ import numpy
25
+ from fabioimage import fabioimage
26
+ from fabioutils import isAscii, toAscii, nice_int
27
+ from compression import decBzip2, decGzip, decZlib
28
+
29
+
30
+ BLOCKSIZE = 512
31
+ DATA_TYPES = { "SignedByte" : numpy.int8,
32
+ "Signed8" : numpy.int8,
33
+ "UnsignedByte" : numpy.uint8,
34
+ "Unsigned8" : numpy.uint8,
35
+ "SignedShort" : numpy.int16,
36
+ "Signed16" : numpy.int16,
37
+ "UnsignedShort" : numpy.uint16,
38
+ "Unsigned16" : numpy.uint16,
39
+ "UnsignedShortInteger" : numpy.uint16,
40
+ "SignedInteger" : numpy.int32,
41
+ "Signed32" : numpy.int32,
42
+ "UnsignedInteger": numpy.uint32,
43
+ "Unsigned32" : numpy.uint32,
44
+ "SignedLong" : numpy.int32,
45
+ "UnsignedLong" : numpy.uint32,
46
+ "Signed64" : numpy.int64,
47
+ "Unsigned64" : numpy.uint64,
48
+ "FloatValue" : numpy.float32,
49
+ "FLOATVALUE" : numpy.float32,
50
+ "FLOAT" : numpy.float32, # fit2d
51
+ "Float" : numpy.float32, # fit2d
52
+ "FloatIEEE32" : numpy.float32,
53
+ "Float32" : numpy.float32,
54
+ "Double" : numpy.float64,
55
+ "DoubleValue" : numpy.float64,
56
+ "FloatIEEE64" : numpy.float64,
57
+ "DoubleIEEE64" : numpy.float64}
58
+ try:
59
+ DATA_TYPES["FloatIEEE128" ] = numpy.float128
60
+ DATA_TYPES["DoubleIEEE128" ] = numpy.float128
61
+ DATA_TYPES["QuadrupleValue" ] = numpy.float128
62
+
63
+ except AttributeError:
64
+ # not in your numpy
65
+ pass
66
+
67
+ NUMPY_EDF_DTYPE = {"int8" :"SignedByte",
68
+ "int16" :"SignedShort",
69
+ "int32" :"SignedInteger",
70
+ "int64" :"Signed64",
71
+ "uint8" :"UnsignedByte",
72
+ "uint16" :"UnsignedShort",
73
+ "uint32" :"UnsignedInteger",
74
+ "uint64" :"Unsigned64",
75
+ "float32" :"FloatValue",
76
+ "float64" :"DoubleValue",
77
+ "float128" :"QuadrupleValue",
78
+ }
79
+
80
+ MINIMUM_KEYS = ['HEADERID',
81
+ 'IMAGE',
82
+ 'BYTEORDER',
83
+ 'DATATYPE',
84
+ 'DIM_1',
85
+ 'DIM_2',
86
+ 'SIZE'] # Size is thought to be essential for writing at least
87
+
88
+ DEFAULT_VALUES = {
89
+ # I do not define default values as they will be calculated at write time
90
+ # JK20110415
91
+ }
92
+
93
+ class Frame(object):
94
+ """
95
+ A class representing a single frame in an EDF file
96
+ """
97
+ def __init__(self, data=None, header=None, header_keys=None, number=None):
98
+ if header is None:
99
+ self.header = {}
100
+ else:
101
+ self.header = dict(header)
102
+
103
+ if header_keys is None:
104
+ self.header_keys = self.header.keys()
105
+ else:
106
+ self.header_keys = header_keys[:]
107
+ for key in header_keys:
108
+ if key not in self.header:
109
+ logger.warning("Header key %s, in header_keys is not in header dictionary, poping !!!" % key)
110
+ self.header_keys.remove(key)
111
+
112
+ self.capsHeader = {}
113
+ for key in self.header_keys:
114
+ try:
115
+ self.capsHeader[key.upper()] = key
116
+ except AttributeError:
117
+ logger.warning("Header key %s is not a string" % key)
118
+ self._data = data
119
+ self.dims = []
120
+ self.dim1 = 0
121
+ self.dim2 = 0
122
+ self.start = None # Position of start of raw data in file
123
+ self.size = None # size of raw data in file
124
+ self.file = None # opened file object with locking capabilities !!!
125
+ self.bpp = None
126
+ self._bytecode = None
127
+ if (number is not None) and isinstance(number, int):
128
+ self.iFrame = number
129
+ else:
130
+ self.iFrame = 0
131
+
132
+ def parseheader(self, block):
133
+ """
134
+ Parse the header in some EDF format from an already open file
135
+
136
+ @param block: string representing the header block
137
+ @type block: string, should be full ascii
138
+ @return: size of the binary blob
139
+ """
140
+ #reset values ...
141
+ self.header = {}
142
+ self.capsHeader = {}
143
+ self.header_keys = []
144
+ self.size = None
145
+ calcsize = 1
146
+ self.dims = []
147
+
148
+ for line in block.split(';'):
149
+ if '=' in line:
150
+ key, val = line.split('=' , 1)
151
+ # Why would someone put null bytes in a header?
152
+ key = key.replace("\x00"," ").strip()
153
+ self.header[key] = val.replace("\x00"," ").strip()
154
+ self.capsHeader[key.upper()] = key
155
+ self.header_keys.append(key)
156
+
157
+ # Compute image size
158
+ if "SIZE" in self.capsHeader:
159
+ try:
160
+ self.size = nice_int(self.header[self.capsHeader["SIZE"]])
161
+ except ValueError:
162
+ logger.warning("Unable to convert to integer : %s %s " % (self.capsHeader["SIZE"], self.header[self.capsHeader["SIZE"]]))
163
+ if "DIM_1" in self.capsHeader:
164
+ try:
165
+ dim1 = nice_int(self.header[self.capsHeader['DIM_1']])
166
+ except ValueError:
167
+ logger.error("Unable to convert to integer Dim_1: %s %s" % (self.capsHeader["DIM_1"], self.header[self.capsHeader["DIM_1"]]))
168
+ else:
169
+ calcsize *= dim1
170
+ self.dims.append(dim1)
171
+ else:
172
+ logger.error("No Dim_1 in headers !!!")
173
+ if "DIM_2" in self.capsHeader:
174
+ try:
175
+ dim2 = nice_int(self.header[self.capsHeader['DIM_2']])
176
+ except ValueError:
177
+ logger.error("Unable to convert to integer Dim_3: %s %s" % (self.capsHeader["DIM_2"], self.header[self.capsHeader["DIM_2"]]))
178
+ else:
179
+ calcsize *= dim2
180
+ self.dims.append(dim2)
181
+ else:
182
+ logger.error("No Dim_2 in headers !!!")
183
+ iDim = 3
184
+ # JON: this appears to be for nD images, but we don't treat those
185
+ while iDim is not None:
186
+ strDim = "DIM_%i" % iDim
187
+ if strDim in self.capsHeader:
188
+ try:
189
+ dim3 = nice_int(self.header[self.capsHeader[strDim]])
190
+ except ValueError:
191
+ logger.error("Unable to convert to integer %s: %s %s"
192
+ % (strDim, self.capsHeader[strDim], self.header[self.capsHeader[strDim]]))
193
+ dim3 = None
194
+ iDim = None
195
+ else:
196
+ if dim3 > 1:
197
+ # Otherwise treat dim3==1 as a 2D image
198
+ calcsize *= dim3
199
+ self.dims.append(dim3)
200
+ iDim += 1
201
+
202
+ else:
203
+ logger.debug("No Dim_3 -> it is a 2D image")
204
+ iDim = None
205
+ if self._bytecode is None:
206
+ if "DATATYPE" in self.capsHeader:
207
+ self._bytecode = DATA_TYPES[self.header[self.capsHeader['DATATYPE']]]
208
+ else:
209
+ self._bytecode = numpy.uint16
210
+ logger.warning("Defaulting type to uint16")
211
+ self.bpp = len(numpy.array(0, self._bytecode).tostring())
212
+ calcsize *= self.bpp
213
+ if (self.size is None):
214
+ self.size = calcsize
215
+ elif (self.size != calcsize):
216
+ if ("COMPRESSION" in self.capsHeader) and (self.header[self.capsHeader['COMPRESSION']].upper().startswith("NO")):
217
+ logger.info("Mismatch between the expected size %s and the calculated one %s" % (self.size, calcsize))
218
+ self.size = calcsize
219
+
220
+ for i, n in enumerate(self.dims):
221
+ setattr(self, "dim%i" % (i + 1), n)
222
+
223
+ return self.size
224
+
225
+
226
+ def swap_needed(self):
227
+ """
228
+ Decide if we need to byteswap
229
+ """
230
+ if ('Low' in self.header[self.capsHeader['BYTEORDER']] and numpy.little_endian) or \
231
+ ('High' in self.header[self.capsHeader['BYTEORDER']] and not numpy.little_endian):
232
+ return False
233
+ if ('High' in self.header[self.capsHeader['BYTEORDER']] and numpy.little_endian) or \
234
+ ('Low' in self.header[self.capsHeader['BYTEORDER']] and not numpy.little_endian):
235
+ if self.bpp in [2, 4, 8]:
236
+ return True
237
+ else:
238
+ return False
239
+
240
+
241
+ def getData(self):
242
+ """
243
+ Unpack a binary blob according to the specification given in the header
244
+
245
+ @return: dataset as numpy.ndarray
246
+ """
247
+ data = None
248
+ if self._data is not None:
249
+ data = self._data
250
+ elif self.file is None:
251
+ data = self._data
252
+ else:
253
+ if self._bytecode is None:
254
+ if "DATATYPE" in self.capsHeader:
255
+ self._bytecode = DATA_TYPES[self.header[self.capsHeader["DATATYPE"]]]
256
+ else:
257
+ self._bytecode = numpy.uint16
258
+ dims = self.dims[:]
259
+ dims.reverse()
260
+ with self.file.lock:
261
+ if self.file.closed:
262
+ logger.error("file: %s from %s is closed. Cannot read data." % (self.file, self.file.filename))
263
+ return
264
+ else:
265
+ self.file.seek(self.start)
266
+ fileData = self.file.read(self.size)
267
+
268
+ if ("COMPRESSION" in self.capsHeader):
269
+ compression = self.header[self.capsHeader["COMPRESSION"]].upper()
270
+ uncompressed_size = self.bpp
271
+ for i in dims:
272
+ uncompressed_size *= i
273
+ if "OFFSET" in compression :
274
+ try:
275
+ import byte_offset#IGNORE:F0401
276
+ except ImportError, error:
277
+ logger.error("Unimplemented compression scheme: %s (%s)" % (compression, error))
278
+ else:
279
+ myData = byte_offset.analyseCython(fileData, size=uncompressed_size)
280
+ rawData = myData.astype(self._bytecode).tostring()
281
+ self.size = uncompressed_size
282
+ elif compression == "NONE":
283
+ rawData = fileData
284
+ elif "GZIP" in compression:
285
+ rawData = decGzip(fileData)
286
+ self.size = uncompressed_size
287
+ elif "BZ" in compression :
288
+ rawData = decBzip2(fileData)
289
+ self.size = uncompressed_size
290
+ elif "Z" in compression :
291
+ rawData = decZlib(fileData)
292
+ self.size = uncompressed_size
293
+ else:
294
+ logger.warning("Unknown compression scheme %s" % compression)
295
+ rawData = fileData
296
+
297
+ else:
298
+ rawData = fileData
299
+
300
+ expected = self.size
301
+ obtained = len(rawData)
302
+ if expected > obtained:
303
+ logger.error("Data stream is incomplete: %s < expected %s bytes" % (obtained, expected))
304
+ rawData += "\x00" * (expected - obtained)
305
+ elif expected < len(rawData):
306
+ logger.info("Data stream contains trailing junk : %s > expected %s bytes" % (obtained, expected))
307
+ rawData = rawData[:expected]
308
+ if self.swap_needed():
309
+ data = numpy.fromstring(rawData, self._bytecode).byteswap().reshape(tuple(dims))
310
+ else:
311
+ data = numpy.fromstring(rawData, self._bytecode).reshape(tuple(dims))
312
+ self._data = data
313
+ self._bytecode = data.dtype.type
314
+ return data
315
+ def setData(self, npa=None):
316
+ """Setter for data in edf frame"""
317
+ self._data = npa
318
+ data = property(getData, setData, "property: (edf)frame.data, uncompress the datablock when needed")
319
+ def getByteCode(self):
320
+ if self._bytecode is None:
321
+ self._bytecode = self.data.dtype.type
322
+
323
+ return self._bytecode
324
+ def setByteCode(self, _iVal):
325
+ self._bytecode = _iVal
326
+ bytecode = property(getByteCode, setByteCode)
327
+
328
+ def getEdfBlock(self, force_type=None, fit2dMode=False):
329
+ """
330
+ @param force_type: type of the dataset to be enforced like "float64" or "uint16"
331
+ @type force_type: string or numpy.dtype
332
+ @param fit2dMode: enforce compatibility with fit2d and starts countimg number of images at 1
333
+ @type fit2dMode: boolean
334
+ @return: ascii header block
335
+ @rtype: python string with the concatenation of the ascii header and the binary data block
336
+ """
337
+ if force_type is not None:
338
+ data = self.data.astype(force_type)
339
+ else:
340
+ data = self.data
341
+ fit2dMode = bool(fit2dMode)
342
+ for key in self.header:
343
+ KEY = key.upper()
344
+ if KEY not in self.capsHeader:
345
+ self.capsHeader[KEY] = key
346
+ if key not in self.header_keys:
347
+ self.header_keys.append(key)
348
+
349
+ header = self.header.copy()
350
+ header_keys = self.header_keys[:]
351
+ capsHeader = self.capsHeader.copy()
352
+
353
+ listHeader = ["{\n"]
354
+ # First of all clean up the headers:
355
+ for i in capsHeader:
356
+ if "DIM_" in i:
357
+ header.pop(capsHeader[i])
358
+ header_keys.remove(capsHeader[i])
359
+ for KEY in ["SIZE", "EDF_BINARYSIZE", "EDF_HEADERSIZE", "BYTEORDER", "DATATYPE", "HEADERID", "IMAGE"]:
360
+ if KEY in capsHeader:
361
+ header.pop(capsHeader[KEY])
362
+ header_keys.remove(capsHeader[KEY])
363
+ if "EDF_DATABLOCKID" in capsHeader:
364
+ header_keys.remove(capsHeader["EDF_DATABLOCKID"])
365
+ #but do not remove the value from dict, instead reset the key ...
366
+ if capsHeader["EDF_DATABLOCKID"] != "EDF_DataBlockID":
367
+ header["EDF_DataBlockID"] = header.pop(capsHeader["EDF_DATABLOCKID"])
368
+ capsHeader["EDF_DATABLOCKID"] = "EDF_DataBlockID"
369
+
370
+ # Then update static headers freshly deleted
371
+ header_keys.insert(0, "Size")
372
+ header["Size"] = len(data.tostring())
373
+ header_keys.insert(0, "HeaderID")
374
+ header["HeaderID"] = "EH:%06d:000000:000000" % (self.iFrame + fit2dMode)
375
+ header_keys.insert(0, "Image")
376
+ header["Image"] = str(self.iFrame + fit2dMode)
377
+
378
+ dims = list(data.shape)
379
+ nbdim = len(dims)
380
+ for i in dims:
381
+ key = "Dim_%i" % nbdim
382
+ header[key] = i
383
+ header_keys.insert(0, key)
384
+ nbdim -= 1
385
+ header_keys.insert(0, "DataType")
386
+ header["DataType"] = NUMPY_EDF_DTYPE[str(numpy.dtype(data.dtype))]
387
+ header_keys.insert(0, "ByteOrder")
388
+ if numpy.little_endian:
389
+ header["ByteOrder"] = "LowByteFirst"
390
+ else:
391
+ header["ByteOrder"] = "HighByteFirst"
392
+ approxHeaderSize = 100
393
+ for key in header:
394
+ approxHeaderSize += 7 + len(key) + len(str(header[key]))
395
+ approxHeaderSize = BLOCKSIZE * (approxHeaderSize // BLOCKSIZE + 1)
396
+ header_keys.insert(0, "EDF_HeaderSize")
397
+ header["EDF_HeaderSize"] = str(BLOCKSIZE * (approxHeaderSize // BLOCKSIZE + 1))
398
+ header_keys.insert(0, "EDF_BinarySize")
399
+ header["EDF_BinarySize"] = len(data.tostring())
400
+ header_keys.insert(0, "EDF_DataBlockID")
401
+ if not "EDF_DataBlockID" in header:
402
+ header["EDF_DataBlockID"] = "%i.Image.Psd" % (self.iFrame + fit2dMode)
403
+ preciseSize = 4 #2 before {\n 2 after }\n
404
+ for key in header_keys:
405
+ #Escape keys or values that are no ascii
406
+ strKey = str(key)
407
+ if not isAscii(strKey, listExcluded=["}", "{"]):
408
+ logger.warning("Non ascii key %s, skipping" % strKey)
409
+ continue
410
+ strValue = str(header[key])
411
+ if not isAscii(strValue, listExcluded=["}", "{"]):
412
+ logger.warning("Non ascii value %s, skipping" % strValue)
413
+ continue
414
+ line = strKey + " = " + strValue + " ;\n"
415
+ preciseSize += len(line)
416
+ listHeader.append(line)
417
+ if preciseSize > approxHeaderSize:
418
+ logger.error("I expected the header block only at %s in fact it is %s" % (approxHeaderSize, preciseSize))
419
+ for idx, line in enumerate(listHeader[:]):
420
+ if line.startswith("EDF_HeaderSize"):
421
+ headerSize = BLOCKSIZE * (preciseSize // BLOCKSIZE + 1)
422
+ newline = "EDF_HeaderSize = %s ;\n" % headerSize
423
+ delta = len(newline) - len(line)
424
+ if (preciseSize // BLOCKSIZE) != ((preciseSize + delta) // BLOCKSIZE):
425
+ headerSize = BLOCKSIZE * ((preciseSize + delta) // BLOCKSIZE + 1)
426
+ newline = "EDF_HeaderSize = %s ;\n" % headerSize
427
+ preciseSize = preciseSize + delta
428
+ listHeader[idx] = newline
429
+ break
430
+ else:
431
+ headerSize = approxHeaderSize
432
+ listHeader.append(" "*(headerSize - preciseSize) + "}\n")
433
+ return "".join(listHeader) + data.tostring()
434
+
435
+
436
+
437
+ class edfimage(fabioimage):
438
+ """ Read and try to write the ESRF edf data format """
439
+
440
+ def __init__(self, data=None , header=None, header_keys=None, frames=None):
441
+ self.currentframe = 0
442
+ self.filesize = None
443
+ try:
444
+ dim = len(data.shape)
445
+ except Exception, error: #IGNORE:W0703
446
+ logger.debug("Data don't look like a numpy array (%s), resetting all!!" % error)
447
+ data = None
448
+ dim = 0
449
+ fabioimage.__init__(self, data, header)
450
+ if dim == 2:
451
+ fabioimage.__init__(self, data, header)
452
+ elif dim == 1 :
453
+ data.shape = (0, len(data))
454
+ fabioimage.__init__(self, data, header)
455
+ elif dim == 3 :
456
+ fabioimage.__init__(self, data[0, :, :], header)
457
+ elif dim == 4 :
458
+ fabioimage.__init__(self, data[0, 0, :, :], header)
459
+ elif dim == 5 :
460
+ fabioimage.__init__(self, data[0, 0, 0, :, :], header)
461
+
462
+ if frames is None:
463
+ frame = Frame(data=self.data, header=self.header,
464
+ header_keys=header_keys ,
465
+ number=self.currentframe)
466
+ self.__frames = [frame]
467
+ else:
468
+ self.__frames = frames
469
+
470
+ @staticmethod
471
+ def checkHeader(header=None):
472
+ """
473
+ Empty for fabioimage but may be populated by others classes
474
+ """
475
+ if type(header) != types.DictionaryType:
476
+ return {}
477
+ new = {}
478
+ for key, value in header.items():
479
+ new[toAscii(key, ";{}")] = toAscii(value, ";{}")
480
+ return new
481
+
482
+ @staticmethod
483
+ def _readHeaderBlock(infile):
484
+ """
485
+ Read in a header in some EDF format from an already open file
486
+
487
+ @param infile: file object open in read mode
488
+ @return: string (or None if no header was found.
489
+ """
490
+
491
+ block = infile.read(BLOCKSIZE)
492
+ if len(block) < BLOCKSIZE:
493
+ logger.debug("Under-short header: only %i bytes in %s" % (len(block), infile.name))
494
+ return
495
+ if (block.find("{") < 0) :
496
+ # This does not look like an edf file
497
+ logger.warning("no opening {. Corrupt header of EDF file %s" % infile.name)
498
+ return
499
+ while '}' not in block:
500
+ block = block + infile.read(BLOCKSIZE)
501
+ if len(block) > BLOCKSIZE * 20:
502
+ logger.warning("Runaway header in EDF file")
503
+ return
504
+ start = block.find("{") + 1
505
+ end = block.find("}")
506
+
507
+ # Now it is essential to go to the start of the binary part
508
+ if block[end: end + 3] == "}\r\n":
509
+ offset = end + 3 - len(block)
510
+ elif block[end: end + 2] == "}\n":
511
+ offset = end + 2 - len(block)
512
+ else:
513
+ logger.error("Unable to locate start of the binary section")
514
+ offset = None
515
+ if offset is not None:
516
+ infile.seek(offset, os.SEEK_CUR)
517
+ return block[start:end]
518
+
519
+
520
+ def _readheader(self, infile):
521
+ """
522
+ Read all headers in a file and populate self.header
523
+ data is not yet populated
524
+ @type infile: file object open in read mode
525
+ """
526
+ self.__frames = []
527
+ bContinue = True
528
+ while bContinue:
529
+ block = self._readHeaderBlock(infile)
530
+ if block is None:
531
+ bContinue = False
532
+ break
533
+ frame = Frame(number=self.nframes)
534
+ size = frame.parseheader(block)
535
+ frame.file = infile
536
+ frame.start = infile.tell()
537
+ frame.size = size
538
+ self.__frames += [frame]
539
+ try:
540
+ infile.seek(size, os.SEEK_CUR)
541
+ except Exception, error:
542
+ logger.warning("infile is %s" % infile)
543
+ logger.warning("Position is %s" % infile.tell())
544
+ logger.warning("size is %s" % size)
545
+ logger.error("It seams this error occurs under windows when reading a (large-) file over network: %s ", error)
546
+ raise Exception(error)
547
+
548
+ if frame.start + size > infile.size:
549
+ logger.warning("Non complete datablock: got %s, expected %s" % (infile.size - frame.start, size))
550
+ bContinue = False
551
+ break
552
+
553
+ for i, frame in enumerate(self.__frames):
554
+ missing = []
555
+ for item in MINIMUM_KEYS:
556
+ if item not in frame.capsHeader:
557
+ missing.append(item)
558
+ if len(missing) > 0:
559
+ logger.info("EDF file %s frame %i misses mandatory keys: %s " % (self.filename, i, " ".join(missing)))
560
+ self.currentframe = 0
561
+
562
+
563
+ def read(self, fname, frame=None):
564
+ """
565
+ Read in header into self.header and
566
+ the data into self.data
567
+ """
568
+ self.resetvals()
569
+ self.filename = fname
570
+
571
+ infile = self._open(fname, "rb")
572
+ self._readheader(infile)
573
+ if frame is None:
574
+ pass
575
+ elif frame < self.nframes:
576
+ self = self.getframe(frame)
577
+ else:
578
+ logger.error("Reading file %s You requested frame %s but only %s frames are available", fname, frame, self.nframes)
579
+ self.resetvals()
580
+ # ensure the PIL image is reset
581
+ self.pilimage = None
582
+ return self
583
+
584
+ def swap_needed(self):
585
+ """
586
+ Decide if we need to byteswap
587
+ """
588
+ if ('Low' in self.header[self.capsHeader['BYTEORDER']] and numpy.little_endian) or \
589
+ ('High' in self.header[self.capsHeader['BYTEORDER']] and not numpy.little_endian):
590
+ return False
591
+ if ('High' in self.header[self.capsHeader['BYTEORDER']] and numpy.little_endian) or \
592
+ ('Low' in self.header[self.capsHeader['BYTEORDER']] and not numpy.little_endian):
593
+ if self.bpp in [2, 4, 8]:
594
+ return True
595
+ else:
596
+ return False
597
+
598
+ def unpack(self):
599
+ """
600
+ Unpack a binary blob according to the specification given in the header and return the dataset
601
+
602
+ @return: dataset as numpy.ndarray
603
+ """
604
+ return self.__frames[self.currentframe].getData()
605
+
606
+
607
+ def getframe(self, num):
608
+ """ returns the file numbered 'num' in the series as a fabioimage """
609
+ newImage = None
610
+ if self.nframes == 1:
611
+ logger.debug("Single frame EDF; having fabioimage default behavour: %s" % num)
612
+ newImage = fabioimage.getframe(self, num)
613
+ elif num in xrange(self.nframes):
614
+ logger.debug("Multi frame EDF; having edfimage specific behavour: %s/%s" % (num, self.nframes))
615
+ newImage = edfimage(frames=self.__frames)
616
+ newImage.currentframe = num
617
+ newImage.filename = self.filename
618
+ else:
619
+ txt = "Cannot access frame: %s/%s" % (num, self.nframes)
620
+ logger.error(txt)
621
+ raise ValueError("edfimage.getframe:" + txt)
622
+ return newImage
623
+
624
+
625
+ def previous(self):
626
+ """ returns the previous file in the series as a fabioimage """
627
+ newImage = None
628
+ if self.nframes == 1:
629
+ newImage = fabioimage.previous(self)
630
+ else:
631
+ newFrameId = self.currentframe - 1
632
+ newImage = self.getframe(newFrameId)
633
+ return newImage
634
+
635
+
636
+ def next(self):
637
+ """ returns the next file in the series as a fabioimage """
638
+ newImage = None
639
+ if self.nframes == 1:
640
+ newImage = fabioimage.next(self)
641
+ else:
642
+ newFrameId = self.currentframe + 1
643
+ newImage = self.getframe(newFrameId)
644
+ return newImage
645
+
646
+
647
+ def write(self, fname, force_type=None, fit2dMode=False):
648
+ """
649
+ Try to write a file
650
+ check we can write zipped also
651
+ mimics that fabian was writing uint16 (we sometimes want floats)
652
+
653
+ @param force_type: can be numpy.uint16 or simply "float"
654
+ @return: None
655
+
656
+ """
657
+
658
+ outfile = self._open(fname, mode="wb")
659
+ for i, frame in enumerate(self.__frames):
660
+ frame.iFrame = i
661
+ outfile.write(frame.getEdfBlock(force_type=force_type, fit2dMode=fit2dMode))
662
+ outfile.close()
663
+
664
+
665
+ def appendFrame(self, frame=None, data=None, header=None):
666
+ """
667
+ Method used add a frame to an EDF file
668
+ @param frame: frame to append to edf image
669
+ @type frame: instance of Frame
670
+ @return: None
671
+ """
672
+ if isinstance(frame, Frame):
673
+ self.__frames.append(frame)
674
+ else:
675
+ self.__frames.append(Frame(data, header))
676
+
677
+
678
+ def deleteFrame(self, frameNb=None):
679
+ """
680
+ Method used to remove a frame from an EDF image. by default the last one is removed.
681
+ @param frameNb: frame number to remove, by default the last.
682
+ @type frameNb: integer
683
+ @return: None
684
+ """
685
+ if frameNb is None:
686
+ self.__frames.pop()
687
+ else:
688
+ self.__frames.pop(frameNb)
689
+
690
+ def fastReadData(self, filename=None):
691
+ """
692
+ This is a special method that will read and return the data from another file ...
693
+ The aim is performances, ... but only supports uncompressed files.
694
+
695
+ @return: data from another file using positions from current edfimage
696
+ """
697
+ if (filename is None) or not os.path.isfile(filename):
698
+ raise RuntimeError("edfimage.fastReadData is only valid with another file: %s does not exist" % (filename))
699
+ data = None
700
+ frame = self.__frames[self.currentframe]
701
+ with open(filename, "rb")as f:
702
+ f.seek(frame.start)
703
+ raw = f.read(frame.size)
704
+ try:
705
+ data = numpy.fromstring(raw, dtype=self.bytecode)
706
+ data.shape = self.data.shape
707
+ except Exception, err :
708
+ logger.error("unable to convert file content to numpy array: %s", err)
709
+ return data
710
+
711
+ def fastReadROI(self, filename, coords=None):
712
+ """
713
+ Method reading Region of Interest of another file based on metadata available in current edfimage.
714
+ The aim is performances, ... but only supports uncompressed files.
715
+
716
+ @return: ROI-data from another file using positions from current edfimage
717
+ @rtype: numpy 2darray
718
+ """
719
+ if (filename is None) or not os.path.isfile(filename):
720
+ raise RuntimeError("edfimage.fastReadData is only valid with another file: %s does not exist" % (filename))
721
+ data = None
722
+ frame = self.__frames[self.currentframe]
723
+
724
+ if len(coords) == 4:
725
+ slice1 = self.make_slice(coords)
726
+ elif len(coords) == 2 and isinstance(coords[0], slice) and \
727
+ isinstance(coords[1], slice):
728
+ slice1 = coords
729
+ else:
730
+ logger.warning('readROI: Unable to understand Region Of Interest: got %s', coords)
731
+ return
732
+ d1 = self.data.shape[-1]
733
+ start0 = slice1[0].start
734
+ start1 = slice1[1].start
735
+ slice2 = (slice(0, slice1[0].stop - start0, slice1[0].step),
736
+ slice(0, slice1[1].stop - start1, slice1[1].step))
737
+ start = frame.start + self.bpp * (d1 * start0 + start1)
738
+ size = self.bpp * ((slice2[0].stop) * d1)
739
+ with open(filename, "rb")as f:
740
+ f.seek(start)
741
+ raw = f.read(size)
742
+ try:
743
+ data = numpy.fromstring(raw, dtype=self.bytecode)
744
+ data.shape = -1, d1
745
+ except Exception, err :
746
+ logger.error("unable to convert file content to numpy array: %s", err)
747
+ return data[slice2]
748
+
749
+
750
+ ################################################################################
751
+ # Properties definition for header, data, header_keys and capsHeader
752
+ ################################################################################
753
+ def getNbFrames(self):
754
+ """
755
+ Getter for number of frames
756
+ """
757
+ return len(self.__frames)
758
+ def setNbFrames(self, val):
759
+ """
760
+ Setter for number of frames ... should do nothing. Here just to avoid bugs
761
+ """
762
+ if val != len(self.__frames):
763
+ logger.warning("trying to set the number of frames ")
764
+ nframes = property(getNbFrames, setNbFrames, "property: number of frames in EDF file")
765
+
766
+
767
+ def getHeader(self):
768
+ """
769
+ Getter for the headers. used by the property header,
770
+ """
771
+ return self.__frames[self.currentframe].header
772
+ def setHeader(self, _dictHeader):
773
+ """
774
+ Enforces the propagation of the header to the list of frames
775
+ """
776
+ try:
777
+ self.__frames[self.currentframe].header = _dictHeader
778
+ except AttributeError:
779
+ self.__frames = [Frame(header=_dictHeader)]
780
+ except IndexError:
781
+ if self.currentframe < len(self.__frames):
782
+ self.__frames.append(Frame(header=_dictHeader))
783
+ def delHeader(self):
784
+ """
785
+ Deleter for edf header
786
+ """
787
+ self.__frames[self.currentframe].header = {}
788
+ header = property(getHeader, setHeader, delHeader, "property: header of EDF file")
789
+
790
+ def getHeaderKeys(self):
791
+ """
792
+ Getter for edf header_keys
793
+ """
794
+ return self.__frames[self.currentframe].header_keys
795
+ def setHeaderKeys(self, _listtHeader):
796
+ """
797
+ Enforces the propagation of the header_keys to the list of frames
798
+ @param _listtHeader: list of the (ordered) keys in the header
799
+ @type _listtHeader: python list
800
+ """
801
+ try:
802
+ self.__frames[self.currentframe].header_keys = _listtHeader
803
+ except AttributeError:
804
+ self.__frames = [Frame(header_keys=_listtHeader)]
805
+ except IndexError:
806
+ if self.currentframe < len(self.__frames):
807
+ self.__frames.append(Frame(header_keys=_listtHeader))
808
+ def delHeaderKeys(self):
809
+ """
810
+ Deleter for edf header_keys
811
+ """
812
+ self.__frames[self.currentframe].header_keys = []
813
+ header_keys = property(getHeaderKeys, setHeaderKeys, delHeaderKeys, "property: header_keys of EDF file")
814
+
815
+ def getData(self):
816
+ """
817
+ getter for edf Data
818
+ @return: data for current frame
819
+ @rtype: numpy.ndarray
820
+ """
821
+ npaData = None
822
+ try:
823
+ npaData = self.__frames[self.currentframe].data
824
+ except AttributeError:
825
+ self.__frames = [Frame()]
826
+ npaData = self.__frames[self.currentframe].data
827
+ except IndexError:
828
+ if self.currentframe < len(self.__frames):
829
+ self.__frames.append(Frame())
830
+ npaData = self.__frames[self.currentframe].data
831
+ return npaData
832
+
833
+ def setData(self, _data):
834
+ """
835
+ Enforces the propagation of the data to the list of frames
836
+ @param _data: numpy array representing data
837
+ """
838
+ try:
839
+ self.__frames[self.currentframe].data = _data
840
+ except AttributeError:
841
+ self.__frames = [Frame(data=_data)]
842
+ except IndexError:
843
+ if self.currentframe < len(self.__frames):
844
+ self.__frames.append(Frame(data=_data))
845
+ def delData(self):
846
+ """
847
+ deleter for edf Data
848
+ """
849
+ self.__frames[self.currentframe].data = None
850
+ data = property(getData, setData, delData, "property: data of EDF file")
851
+
852
+ def getCapsHeader(self):
853
+ """
854
+ getter for edf headers keys in upper case
855
+ @return: data for current frame
856
+ @rtype: dict
857
+ """
858
+ return self.__frames[self.currentframe].capsHeader
859
+ def setCapsHeader(self, _data):
860
+ """
861
+ Enforces the propagation of the header_keys to the list of frames
862
+ @param _data: numpy array representing data
863
+ """
864
+ self.__frames[self.currentframe].capsHeader = _data
865
+ def delCapsHeader(self):
866
+ """
867
+ deleter for edf capsHeader
868
+ """
869
+ self.__frames[self.currentframe].capsHeader = {}
870
+ capsHeader = property(getCapsHeader, setCapsHeader, delCapsHeader, "property: capsHeader of EDF file, i.e. the keys of the header in UPPER case.")
871
+
872
+ def getDim1(self):
873
+ return self.__frames[self.currentframe].dim1
874
+ def setDim1(self, _iVal):
875
+ try:
876
+ self.__frames[self.currentframe].dim1 = _iVal
877
+ except AttributeError:
878
+ self.__frames = [Frame()]
879
+ except IndexError:
880
+ if self.currentframe < len(self.__frames):
881
+ self.__frames.append(Frame())
882
+ self.__frames[self.currentframe].dim1 = _iVal
883
+ dim1 = property(getDim1, setDim1)
884
+ def getDim2(self):
885
+ return self.__frames[self.currentframe].dim2
886
+ def setDim2(self, _iVal):
887
+ try:
888
+ self.__frames[self.currentframe].dim2 = _iVal
889
+ except AttributeError:
890
+ self.__frames = [Frame()]
891
+ except IndexError:
892
+ if self.currentframe < len(self.__frames):
893
+ self.__frames.append(Frame())
894
+ self.__frames[self.currentframe].dim2 = _iVal
895
+ dim2 = property(getDim2, setDim2)
896
+
897
+ def getDims(self):
898
+ return self.__frames[self.currentframe].dims
899
+ dims = property(getDims)
900
+ def getByteCode(self):
901
+ return self.__frames[self.currentframe].bytecode
902
+ def setByteCode(self, _iVal):
903
+ try:
904
+ self.__frames[self.currentframe].bytecode = _iVal
905
+ except AttributeError:
906
+ self.__frames = [Frame()]
907
+ except IndexError:
908
+ if self.currentframe < len(self.__frames):
909
+ self.__frames.append(Frame())
910
+ self.__frames[self.currentframe].bytecode = _iVal
911
+ bytecode = property(getByteCode, setByteCode)
912
+ def getBpp(self):
913
+ return self.__frames[self.currentframe].bpp
914
+ def setBpp(self, _iVal):
915
+ try:
916
+ self.__frames[self.currentframe].bpp = _iVal
917
+ except AttributeError:
918
+ self.__frames = [Frame()]
919
+ except IndexError:
920
+ if self.currentframe < len(self.__frames):
921
+ self.__frames.append(Frame())
922
+ self.__frames[self.currentframe].bpp = _iVal
923
+ bpp = property(getBpp, setBpp)
924
+