summaryrefslogtreecommitdiff
path: root/silx/third_party/EdfFile.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/third_party/EdfFile.py')
-rw-r--r--silx/third_party/EdfFile.py1225
1 files changed, 0 insertions, 1225 deletions
diff --git a/silx/third_party/EdfFile.py b/silx/third_party/EdfFile.py
deleted file mode 100644
index 0606d1c..0000000
--- a/silx/third_party/EdfFile.py
+++ /dev/null
@@ -1,1225 +0,0 @@
-# /*##########################################################################
-#
-# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
-#
-# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
-# the ESRF by the Software group.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-__author__ = "Alexandre Gobbo, V.A. Sole - ESRF Data Analysis"
-__contact__ = "sole@esrf.fr"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-"""
- EdfFile.py
- Generic class for Edf files manipulation.
-
- Interface:
- ===========================
- class EdfFile:
- __init__(self,FileName)
- GetNumImages(self)
- def GetData(self,Index, DataType="",Pos=None,Size=None):
- GetPixel(self,Index,Position)
- GetHeader(self,Index)
- GetStaticHeader(self,Index)
- WriteImage (self,Header,Data,Append=1,DataType="",WriteAsUnsigened=0,ByteOrder="")
-
-
- Edf format assumptions:
- ===========================
- The following details were assumed for this implementation:
- - Each Edf file contains a certain number of data blocks.
- - Each data block represents data stored in an one, two or three-dimensional array.
- - Each data block contains a header section, written in ASCII, and a data section of
- binary information.
- - The size of the header section in bytes is a multiple of 1024. The header is
- padded with spaces (0x20). If the header is not padded to a multiple of 1024,
- the file is recognized, but the output is always made in this format.
- - The header section starts by '{' and finishes by '}'. It is composed by several
- pairs 'keyword = value;'. The keywords are case insensitive, but the values are case
- sensitive. Each pair is put in a new line (they are separeted by 0x0A). In the
- end of each line, a semicolon (;) separes the pair of a comment, not interpreted.
- Exemple:
- {
- ; Exemple Header
- HeaderID = EH:000001:000000:000000 ; automatically generated
- ByteOrder = LowByteFirst ;
- DataType = FloatValue ; 4 bytes per pixel
- Size = 4000000 ; size of data section
- Dim_1= 1000 ; x coordinates
- Dim_2 = 1000 ; y coordinates
-
- (padded with spaces to complete 1024 bytes)
- }
- - There are some fields in the header that are required for this implementation. If any of
- these is missing, or inconsistent, it will be generated an error:
- Size: Represents size of data block
- Dim_1: size of x coordinates (Dim_2 for 2-dimentional images, and also Dim_3 for 3d)
- DataType
- ByteOrder
- - For the written images, these fields are automatically genereted:
- Size,Dim_1 (Dim_2 and Dim_3, if necessary), Byte Order, DataType, HeaderID and Image
- These fields are called here "static header", and can be retrieved by the method
- GetStaticHeader. Other header components are taken by GetHeader. Both methods returns
- a dictionary in which the key is the keyword of the pair. When writting an image through
- WriteImage method, the Header parameter should not contain the static header information,
- which is automatically generated.
- - The indexing of images through these functions is based just on the 0-based position in
- the file, the header items HeaderID and Image are not considered for referencing the
- images.
- - The data section contais a number of bytes equal to the value of Size keyword. Data
- section is going to be translated into an 1D, 2D or 3D Numpy Array, and accessed
- through GetData method call.
-"""
-DEBUG = 0
-################################################################################
-import sys
-import numpy
-import os.path
-try:
- import gzip
- GZIP = True
-except:
- GZIP = False
-try:
- import bz2
- BZ2 = True
-except:
- BZ2 = False
-
-MARCCD_SUPPORT = False
-PILATUS_CBF_SUPPORT = False
-CAN_USE_FASTEDF = False
-
-# Using local TiffIO
-from . import TiffIO
-TIFF_SUPPORT = True
-
-# Constants
-
-HEADER_BLOCK_SIZE = 1024
-STATIC_HEADER_ELEMENTS = (
- "HeaderID",
- "Image",
- "ByteOrder",
- "DataType",
- "Dim_1",
- "Dim_2",
- "Dim_3",
- "Offset_1",
- "Offset_2",
- "Offset_3",
- "Size")
-
-STATIC_HEADER_ELEMENTS_CAPS = (
- "HEADERID",
- "IMAGE",
- "BYTEORDER",
- "DATATYPE",
- "DIM_1",
- "DIM_2",
- "DIM_3",
- "OFFSET_1",
- "OFFSET_2",
- "OFFSET_3",
- "SIZE")
-
-LOWER_CASE = 0
-UPPER_CASE = 1
-
-KEYS = 1
-VALUES = 2
-
-
-class Image(object):
- """
- """
- def __init__(self):
- """ Constructor
- """
- self.Header = {}
- self.StaticHeader = {}
- self.HeaderPosition = 0
- self.DataPosition = 0
- self.Size = 0
- self.NumDim = 1
- self.Dim1 = 0
- self.Dim2 = 0
- self.Dim3 = 0
- self.DataType = ""
-
-
-class EdfFile(object):
- """
- """
- def __init__(self, FileName, access=None, fastedf=None):
- """ Constructor
-
- :param FileName: Name of the file (either existing or to be created)
- :type FileName: string
- :param access: access mode "r" for reading (the file should exist) or
- "w" for writing (if the file does not exist, it does not matter).
- :type access: string
- :type fastedf: True to use the fastedf module
- :param fastedf: bool
- """
- self.Images = []
- self.NumImages = 0
- self.FileName = FileName
- self.File = 0
- if fastedf is None:
- fastedf = 0
- self.fastedf = fastedf
- self.ADSC = False
- self.MARCCD = False
- self.TIFF = False
- self.PILATUS_CBF = False
- self.SPE = False
- if sys.byteorder == "big":
- self.SysByteOrder = "HighByteFirst"
- else:
- self.SysByteOrder = "LowByteFirst"
-
- if hasattr(FileName, "seek") and\
- hasattr(FileName, "read"):
- # this looks like a file descriptor ...
- self.__ownedOpen = False
- self.File = FileName
- try:
- self.FileName = self.File.name
- except AttributeError:
- self.FileName = self.File.filename
- elif FileName.lower().endswith('.gz'):
- if GZIP:
- self.__ownedOpen = False
- self.File = gzip.GzipFile(FileName)
- else:
- raise IOError("No gzip module support in this system")
- elif FileName.lower().endswith('.bz2'):
- if BZ2:
- self.__ownedOpen = False
- self.File = bz2.BZ2File(FileName)
- else:
- raise IOError("No bz2 module support in this system")
- else:
- self.__ownedOpen = True
-
- if self.File in [0, None]:
- if access is not None:
- if access[0].upper() == "R":
- if not os.path.isfile(self.FileName):
- raise IOError("File %s not found" % FileName)
- if 'b' not in access:
- access += 'b'
- if 1:
- if not os.path.isfile(self.FileName):
- # write access
- if access is None:
- # allow writing and reading
- access = "ab+"
- self.File = open(self.FileName, access)
- self.File.seek(0, 0)
- return
- if 'b' not in access:
- access += 'b'
- self.File = open(self.FileName, access)
- return
- else:
- if access is None:
- if (os.access(self.FileName, os.W_OK)):
- access = "r+b"
- else:
- access = "rb"
- self.File = open(self.FileName, access)
- self.File.seek(0, 0)
- twoChars = self.File.read(2)
- tiff = False
- if sys.version < '3.0':
- if twoChars in ["II", "MM"]:
- tiff = True
- elif twoChars in [eval('b"II"'), eval('b"MM"')]:
- tiff = True
- if tiff:
- fileExtension = os.path.splitext(self.FileName)[-1]
- if fileExtension.lower() in [".tif", ".tiff"] or\
- sys.version > '2.9':
- if not TIFF_SUPPORT:
- raise IOError("TIFF support not implemented")
- else:
- self.TIFF = True
- elif not MARCCD_SUPPORT:
- if not TIFF_SUPPORT:
- raise IOError("MarCCD support not implemented")
- else:
- self.TIFF = True
- else:
- self.MARCCD = True
- basename = os.path.basename(FileName).upper()
- if basename.endswith('.CBF'):
- if not PILATUS_CBF_SUPPORT:
- raise IOError("CBF support not implemented")
- if twoChars[0] != "{":
- self.PILATUS_CBF = True
- elif basename.endswith('.SPE'):
- if twoChars[0] != "$":
- self.SPE = True
- elif basename.endswith('EDF.GZ') or basename.endswith('CCD.GZ'):
- self.GZIP = True
- else:
- try:
- self.File.close()
- except:
- pass
- raise IOError("EdfFile: Error opening file")
-
- self.File.seek(0, 0)
- if self.TIFF:
- self._wrapTIFF()
- self.File.close()
- return
- if self.MARCCD:
- self._wrapMarCCD()
- self.File.close()
- return
- if self.PILATUS_CBF:
- self._wrapPilatusCBF()
- self.File.close()
- return
- if self.SPE:
- self._wrapSPE()
- self.File.close()
- return
-
- Index = 0
- line = self.File.readline()
- selectedLines = [""]
- if sys.version > '2.6':
- selectedLines.append(eval('b""'))
- parsingHeader = False
- while line not in selectedLines:
- # decode to make sure I have character string
- # str to make sure python 2.x sees it as string and not unicode
- if sys.version < '3.0':
- if type(line) != type(str("")):
- line = "%s" % line
- else:
- try:
- line = str(line.decode())
- except UnicodeDecodeError:
- try:
- line = str(line.decode('utf-8'))
- except UnicodeDecodeError:
- try:
- line = str(line.decode('latin-1'))
- except UnicodeDecodeError:
- line = "%s" % line
- if (line.count("{\n") >= 1) or (line.count("{\r\n") >= 1):
- parsingHeader = True
- Index = self.NumImages
- self.NumImages = self.NumImages + 1
- self.Images.append(Image())
-
- if line.count("=") >= 1:
- listItems = line.split("=", 1)
- typeItem = listItems[0].strip()
- listItems = listItems[1].split(";", 1)
- valueItem = listItems[0].strip()
- if (typeItem == "HEADER_BYTES") and (Index == 0):
- self.ADSC = True
- break
-
- # if typeItem in self.Images[Index].StaticHeader.keys():
- if typeItem.upper() in STATIC_HEADER_ELEMENTS_CAPS:
- self.Images[Index].StaticHeader[typeItem] = valueItem
- else:
- self.Images[Index].Header[typeItem] = valueItem
- if ((line.count("}\n") >= 1) or (line.count("}\r") >= 1)) and (parsingHeader):
- parsingHeader = False
- # for i in STATIC_HEADER_ELEMENTS_CAPS:
- # if self.Images[Index].StaticHeader[i]=="":
- # raise "Bad File Format"
- self.Images[Index].DataPosition = self.File.tell()
- # self.File.seek(int(self.Images[Index].StaticHeader["Size"]), 1)
- StaticPar = SetDictCase(self.Images[Index].StaticHeader, UPPER_CASE, KEYS)
- if "SIZE" in StaticPar.keys():
- self.Images[Index].Size = int(StaticPar["SIZE"])
- if self.Images[Index].Size <= 0:
- self.NumImages = Index
- line = self.File.readline()
- continue
- else:
- raise TypeError("EdfFile: Image doesn't have size information")
- if "DIM_1" in StaticPar.keys():
- self.Images[Index].Dim1 = int(StaticPar["DIM_1"])
- self.Images[Index].Offset1 = int(StaticPar.get("Offset_1", "0"))
- else:
- raise TypeError("EdfFile: Image doesn't have dimension information")
- if "DIM_2" in StaticPar.keys():
- self.Images[Index].NumDim = 2
- self.Images[Index].Dim2 = int(StaticPar["DIM_2"])
- self.Images[Index].Offset2 = int(StaticPar.get("Offset_2", "0"))
- if "DIM_3" in StaticPar.keys():
- self.Images[Index].NumDim = 3
- self.Images[Index].Dim3 = int(StaticPar["DIM_3"])
- self.Images[Index].Offset3 = int(StaticPar.get("Offset_3", "0"))
- if "DATATYPE" in StaticPar.keys():
- self.Images[Index].DataType = StaticPar["DATATYPE"]
- else:
- raise TypeError("EdfFile: Image doesn't have datatype information")
- if "BYTEORDER" in StaticPar.keys():
- self.Images[Index].ByteOrder = StaticPar["BYTEORDER"]
- else:
- raise TypeError("EdfFile: Image doesn't have byteorder information")
-
- self.File.seek(self.Images[Index].Size, 1)
-
- line = self.File.readline()
-
- if self.ADSC:
- self.File.seek(0, 0)
- self.NumImages = 1
- # this is a bad implementation of fabio adscimage
- # please take a look at the fabio module of fable at sourceforge
- infile = self.File
- header_keys = []
- header = {}
- try:
- """ read an adsc header """
- line = infile.readline()
- bytesread = len(line)
- while '}' not in line:
- if '=' in line:
- (key, val) = line.split('=')
- header_keys.append(key.strip())
- header[key.strip()] = val.strip(' ;\n')
- line = infile.readline()
- bytesread = bytesread + len(line)
- except:
- raise Exception("Error processing adsc header")
- # banned by bzip/gzip???
- try:
- infile.seek(int(header['HEADER_BYTES']), 0)
- except TypeError:
- # Gzipped does not allow a seek and read header is not
- # promising to stop in the right place
- infile.close()
- infile = self._open(fname, "rb")
- infile.read(int(header['HEADER_BYTES']))
- binary = infile.read()
- infile.close()
-
- # now read the data into the array
- self.Images[Index].Dim1 = int(header['SIZE1'])
- self.Images[Index].Dim2 = int(header['SIZE2'])
- self.Images[Index].NumDim = 2
- self.Images[Index].DataType = 'UnsignedShort'
- try:
- self.__data = numpy.reshape(
- numpy.copy(numpy.frombuffer(binary, numpy.uint16)),
- (self.Images[Index].Dim2, self.Images[Index].Dim1))
- except ValueError:
- msg = 'Size spec in ADSC-header does not match size of image data field'
- raise IOError(msg)
- if 'little' in header['BYTE_ORDER']:
- self.Images[Index].ByteOrder = 'LowByteFirst'
- else:
- self.Images[Index].ByteOrder = 'HighByteFirst'
- if self.SysByteOrder.upper() != self.Images[Index].ByteOrder.upper():
- self.__data = self.__data.byteswap()
- self.Images[Index].ByteOrder = self.SysByteOrder
-
- self.Images[Index].StaticHeader['Dim_1'] = self.Images[Index].Dim1
- self.Images[Index].StaticHeader['Dim_2'] = self.Images[Index].Dim2
- self.Images[Index].StaticHeader['Offset_1'] = 0
- self.Images[Index].StaticHeader['Offset_2'] = 0
- self.Images[Index].StaticHeader['DataType'] = self.Images[Index].DataType
-
- self.__makeSureFileIsClosed()
-
- def _wrapTIFF(self):
- self._wrappedInstance = TiffIO.TiffIO(self.File, cache_length=0, mono_output=True)
- self.NumImages = self._wrappedInstance.getNumberOfImages()
- if self.NumImages < 1:
- return
-
- # wrapped image objects have to provide getInfo and getData
- # info = self._wrappedInstance.getInfo( index)
- # data = self._wrappedInstance.getData( index)
- # for the time being I am going to assume all the images
- # in the file have the same data type type
- data = None
-
- for Index in range(self.NumImages):
- info = self._wrappedInstance.getInfo(Index)
- self.Images.append(Image())
- self.Images[Index].Dim1 = info['nRows']
- self.Images[Index].Dim2 = info['nColumns']
- self.Images[Index].NumDim = 2
- if data is None:
- data = self._wrappedInstance.getData(0)
- self.Images[Index].DataType = self.__GetDefaultEdfType__(data.dtype)
- self.Images[Index].StaticHeader['Dim_1'] = self.Images[Index].Dim1
- self.Images[Index].StaticHeader['Dim_2'] = self.Images[Index].Dim2
- self.Images[Index].StaticHeader['Offset_1'] = 0
- self.Images[Index].StaticHeader['Offset_2'] = 0
- self.Images[Index].StaticHeader['DataType'] = self.Images[Index].DataType
- self.Images[Index].Header.update(info)
-
- def _wrapMarCCD(self):
- raise NotImplementedError("Look at the module EdfFile from PyMca")
-
- def _wrapPilatusCBF(self):
- raise NotImplementedError("Look at the module EdfFile from PyMca")
-
- def _wrapSPE(self):
- if 0 and sys.version < '3.0':
- self.File.seek(42)
- xdim = numpy.int64(numpy.fromfile(self.File, numpy.int16, 1)[0])
- self.File.seek(656)
- ydim = numpy.int64(numpy.fromfile(self.File, numpy.int16, 1))
- self.File.seek(4100)
- self.__data = numpy.fromfile(self.File, numpy.uint16, int(xdim * ydim))
- else:
- import struct
- self.File.seek(0)
- a = self.File.read()
- xdim = numpy.int64(struct.unpack('<h', a[42:44])[0])
- ydim = numpy.int64(struct.unpack('<h', a[656:658])[0])
- fmt = '<%dH' % int(xdim * ydim)
- self.__data = numpy.array(struct.unpack(fmt, a[4100:int(4100 + int(2 * xdim * ydim))])).astype(numpy.uint16)
- self.__data.shape = ydim, xdim
- Index = 0
- self.Images.append(Image())
- self.NumImages = 1
- self.Images[Index].Dim1 = ydim
- self.Images[Index].Dim2 = xdim
- self.Images[Index].NumDim = 2
- self.Images[Index].DataType = 'UnsignedShort'
- self.Images[Index].ByteOrder = 'LowByteFirst'
- if self.SysByteOrder.upper() != self.Images[Index].ByteOrder.upper():
- self.__data = self.__data.byteswap()
- self.Images[Index].StaticHeader['Dim_1'] = self.Images[Index].Dim1
- self.Images[Index].StaticHeader['Dim_2'] = self.Images[Index].Dim2
- self.Images[Index].StaticHeader['Offset_1'] = 0
- self.Images[Index].StaticHeader['Offset_2'] = 0
- self.Images[Index].StaticHeader['DataType'] = self.Images[Index].DataType
-
- def GetNumImages(self):
- """ Returns number of images of the object (and associated file)
- """
- return self.NumImages
-
- def GetData(self, *var, **kw):
- try:
- self.__makeSureFileIsOpen()
- return self._GetData(*var, **kw)
- finally:
- self.__makeSureFileIsClosed()
-
- def _GetData(self, Index, DataType="", Pos=None, Size=None):
- """ Returns numpy array with image data
- Index: The zero-based index of the image in the file
- DataType: The edf type of the array to be returnd
- If ommited, it is used the default one for the type
- indicated in the image header
- Attention to the absence of UnsignedShort,
- UnsignedInteger and UnsignedLong types in
- Numpy Python
- Default relation between Edf types and NumPy's typecodes:
- SignedByte int8 b
- UnsignedByte uint8 B
- SignedShort int16 h
- UnsignedShort uint16 H
- SignedInteger int32 i
- UnsignedInteger uint32 I
- SignedLong int32 i
- UnsignedLong uint32 I
- Signed64 int64 (l in 64bit, q in 32 bit)
- Unsigned64 uint64 (L in 64bit, Q in 32 bit)
- FloatValue float32 f
- DoubleValue float64 d
- Pos: Tuple (x) or (x,y) or (x,y,z) that indicates the begining
- of data to be read. If ommited, set to the origin (0),
- (0,0) or (0,0,0)
- Size: Tuple, size of the data to be returned as x) or (x,y) or
- (x,y,z) if ommited, is the distance from Pos to the end.
-
- If Pos and Size not mentioned, returns the whole data.
- """
- fastedf = self.fastedf
- if Index < 0 or Index >= self.NumImages:
- raise ValueError("EdfFile: Index out of limit")
- if fastedf is None:
- fastedf = 0
- if Pos is None and Size is None:
- if self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- return self.__data
- elif self.TIFF:
- data = self._wrappedInstance.getData(Index)
- return data
- else:
- self.File.seek(self.Images[Index].DataPosition, 0)
- datatype = self.__GetDefaultNumpyType__(self.Images[Index].DataType, index=Index)
- try:
- datasize = self.__GetSizeNumpyType__(datatype)
- except TypeError:
- print("What is the meaning of this error?")
- datasize = 8
- if self.Images[Index].NumDim == 3:
- image = self.Images[Index]
- sizeToRead = image.Dim1 * image.Dim2 * image.Dim3 * datasize
- Data = numpy.copy(numpy.frombuffer(self.File.read(sizeToRead), datatype))
- Data = numpy.reshape(Data, (self.Images[Index].Dim3, self.Images[Index].Dim2, self.Images[Index].Dim1))
- elif self.Images[Index].NumDim == 2:
- image = self.Images[Index]
- sizeToRead = image.Dim1 * image.Dim2 * datasize
- Data = numpy.copy(numpy.frombuffer(self.File.read(sizeToRead), datatype))
- # print "datatype = ",datatype
- # print "Data.type = ", Data.dtype.char
- # print "self.Images[Index].DataType ", self.Images[Index].DataType
- # print "Data.shape",Data.shape
- # print "datasize = ",datasize
- # print "sizeToRead ",sizeToRead
- # print "lenData = ", len(Data)
- Data = numpy.reshape(Data, (self.Images[Index].Dim2, self.Images[Index].Dim1))
- elif self.Images[Index].NumDim == 1:
- sizeToRead = self.Images[Index].Dim1 * datasize
- Data = numpy.copy(numpy.frombuffer(self.File.read(sizeToRead), datatype))
- elif self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- return self.__data[Pos[1]:(Pos[1] + Size[1]),
- Pos[0]:(Pos[0] + Size[0])]
- elif self.TIFF:
- data = self._wrappedInstance.getData(Index)
- return data[Pos[1]:(Pos[1] + Size[1]), Pos[0]:(Pos[0] + Size[0])]
- elif fastedf and CAN_USE_FASTEDF:
- raise NotImplementedError("Look at the module EdfFile from PyMCA")
- else:
- if fastedf:
- print("It could not use fast routines")
- type_ = self.__GetDefaultNumpyType__(self.Images[Index].DataType, index=Index)
- size_pixel = self.__GetSizeNumpyType__(type_)
- Data = numpy.array([], type_)
- if self.Images[Index].NumDim == 1:
- if Pos is None:
- Pos = (0,)
- if Size is None:
- Size = (0,)
- sizex = self.Images[Index].Dim1
- Size = list(Size)
- if Size[0] == 0:
- Size[0] = sizex - Pos[0]
- self.File.seek((Pos[0] * size_pixel) + self.Images[Index].DataPosition, 0)
- Data = numpy.copy(numpy.frombuffer(self.File.read(Size[0] * size_pixel), type_))
- elif self.Images[Index].NumDim == 2:
- if Pos is None:
- Pos = (0, 0)
- if Size is None:
- Size = (0, 0)
- Size = list(Size)
- sizex, sizey = self.Images[Index].Dim1, self.Images[Index].Dim2
- if Size[0] == 0:
- Size[0] = sizex - Pos[0]
- if Size[1] == 0:
- Size[1] = sizey - Pos[1]
- # print len(range(Pos[1],Pos[1]+Size[1])), "LECTURES OF ", Size[0], "POINTS"
- # print "sizex = ", sizex, "sizey = ", sizey
- Data = numpy.zeros((Size[1], Size[0]), type_)
- dataindex = 0
- for y in range(Pos[1], Pos[1] + Size[1]):
- self.File.seek((((y * sizex) + Pos[0]) * size_pixel) + self.Images[Index].DataPosition, 0)
- line = numpy.copy(numpy.frombuffer(self.File.read(Size[0] * size_pixel), type_))
- Data[dataindex, :] = line[:]
- # Data=numpy.concatenate((Data,line))
- dataindex += 1
- # print "DataSize = ",Data.shape
- # print "Requested reshape = ",Size[1],'x',Size[0]
- # Data = numpy.reshape(Data, (Size[1],Size[0]))
- elif self.Images[Index].NumDim == 3:
- if Pos is None:
- Pos = (0, 0, 0)
- if Size is None:
- Size = (0, 0, 0)
- Size = list(Size)
- sizex, sizey, sizez = self.Images[Index].Dim1, self.Images[Index].Dim2, self.Images[Index].Dim3
- if Size[0] == 0:
- Size[0] = sizex - Pos[0]
- if Size[1] == 0:
- Size[1] = sizey - Pos[1]
- if Size[2] == 0:
- Size[2] = sizez - Pos[2]
- for z in range(Pos[2], Pos[2] + Size[2]):
- for y in range(Pos[1], Pos[1] + Size[1]):
- self.File.seek(((((z * sizey + y) * sizex) + Pos[0]) * size_pixel) + self.Images[Index].DataPosition, 0)
- line = numpy.copy(numpy.frombuffer(self.File.read(Size[0] * size_pixel), type_))
- Data = numpy.concatenate((Data, line))
- Data = numpy.reshape(Data, (Size[2], Size[1], Size[0]))
-
- if self.SysByteOrder.upper() != self.Images[Index].ByteOrder.upper():
- Data = Data.byteswap()
- if DataType != "":
- Data = self.__SetDataType__(Data, DataType)
- return Data
-
- def GetPixel(self, Index, Position):
- """ Returns double value of the pixel, regardless the format of the array
- Index: The zero-based index of the image in the file
- Position: Tuple with the coordinete (x), (x,y) or (x,y,z)
- """
- if Index < 0 or Index >= self.NumImages:
- raise ValueError("EdfFile: Index out of limit")
- if len(Position) != self.Images[Index].NumDim:
- raise ValueError("EdfFile: coordinate with wrong dimension ")
-
- size_pixel = self.__GetSizeNumpyType__(self.__GetDefaultNumpyType__(self.Images[Index].DataType, index=Index))
- offset = Position[0] * size_pixel
- if self.Images[Index].NumDim > 1:
- size_row = size_pixel * self.Images[Index].Dim1
- offset = offset + (Position[1] * size_row)
- if self.Images[Index].NumDim == 3:
- size_img = size_row * self.Images[Index].Dim2
- offset = offset + (Position[2] * size_img)
- self.File.seek(self.Images[Index].DataPosition + offset, 0)
- Data = numpy.copy(numpy.frombuffer(self.File.read(size_pixel),
- self.__GetDefaultNumpyType__(self.Images[Index].DataType,
- index=Index)))
- if self.SysByteOrder.upper() != self.Images[Index].ByteOrder.upper():
- Data = Data.byteswap()
- Data = self.__SetDataType__(Data, "DoubleValue")
- return Data[0]
-
- def GetHeader(self, Index):
- """ Returns dictionary with image header fields.
- Does not include the basic fields (static) defined by data shape,
- type and file position. These are get with GetStaticHeader
- method.
- Index: The zero-based index of the image in the file
- """
- if Index < 0 or Index >= self.NumImages:
- raise ValueError("Index out of limit")
- # return self.Images[Index].Header
- ret = {}
- for i in self.Images[Index].Header.keys():
- ret[i] = self.Images[Index].Header[i]
- return ret
-
- def GetStaticHeader(self, Index):
- """ Returns dictionary with static parameters
- Data format and file position dependent information
- (dim1,dim2,size,datatype,byteorder,headerId,Image)
- Index: The zero-based index of the image in the file
- """
- if Index < 0 or Index >= self.NumImages:
- raise ValueError("Index out of limit")
- # return self.Images[Index].StaticHeader
- ret = {}
- for i in self.Images[Index].StaticHeader.keys():
- ret[i] = self.Images[Index].StaticHeader[i]
- return ret
-
- def WriteImage(self, *var, **kw):
- try:
- self.__makeSureFileIsOpen()
- return self._WriteImage(*var, **kw)
- finally:
- self.__makeSureFileIsClosed()
-
- def _WriteImage(self, Header, Data, Append=1, DataType="", ByteOrder=""):
- """ Writes image to the file.
- Header: Dictionary containing the non-static header
- information (static information is generated
- according to position of image and data format
- Append: If equals to 0, overwrites the file. Otherwise, appends
- to the end of the file
- DataType: The data type to be saved to the file:
- SignedByte
- UnsignedByte
- SignedShort
- UnsignedShort
- SignedInteger
- UnsignedInteger
- SignedLong
- UnsignedLong
- FloatValue
- DoubleValue
- Default: according to Data array typecode:
- 1: SignedByte
- b: UnsignedByte
- s: SignedShort
- w: UnsignedShort
- i: SignedInteger
- l: SignedLong
- u: UnsignedLong
- f: FloatValue
- d: DoubleValue
- ByteOrder: Byte order of the data in file:
- HighByteFirst
- LowByteFirst
- Default: system's byte order
- """
- if Append == 0:
- self.File.truncate(0)
- self.Images = []
- self.NumImages = 0
- Index = self.NumImages
- self.NumImages = self.NumImages + 1
- self.Images.append(Image())
-
- # self.Images[Index].StaticHeader["Dim_1"] = "%d" % Data.shape[1]
- # self.Images[Index].StaticHeader["Dim_2"] = "%d" % Data.shape[0]
- scalarSize = self.__GetSizeNumpyType__(Data.dtype)
- if len(Data.shape) == 1:
- self.Images[Index].Dim1 = Data.shape[0]
- self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
- self.Images[Index].Size = Data.shape[0] * scalarSize
- elif len(Data.shape) == 2:
- self.Images[Index].Dim1 = Data.shape[1]
- self.Images[Index].Dim2 = Data.shape[0]
- self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
- self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2
- self.Images[Index].Size = Data.shape[0] * Data.shape[1] * scalarSize
- self.Images[Index].NumDim = 2
- elif len(Data.shape) == 3:
- self.Images[Index].Dim1 = Data.shape[2]
- self.Images[Index].Dim2 = Data.shape[1]
- self.Images[Index].Dim3 = Data.shape[0]
- self.Images[Index].StaticHeader["Dim_1"] = "%d" % self.Images[Index].Dim1
- self.Images[Index].StaticHeader["Dim_2"] = "%d" % self.Images[Index].Dim2
- self.Images[Index].StaticHeader["Dim_3"] = "%d" % self.Images[Index].Dim3
- self.Images[Index].Size = Data.shape[0] * Data.shape[1] * Data.shape[2] * scalarSize
- self.Images[Index].NumDim = 3
- elif len(Data.shape) > 3:
- raise TypeError("EdfFile: Data dimension not suported")
-
- if DataType == "":
- self.Images[Index].DataType = self.__GetDefaultEdfType__(Data.dtype)
- else:
- self.Images[Index].DataType = DataType
- Data = self.__SetDataType__(Data, DataType)
-
- if ByteOrder == "":
- self.Images[Index].ByteOrder = self.SysByteOrder
- else:
- self.Images[Index].ByteOrder = ByteOrder
-
- self.Images[Index].StaticHeader["Size"] = "%d" % self.Images[Index].Size
- self.Images[Index].StaticHeader["Image"] = Index + 1
- self.Images[Index].StaticHeader["HeaderID"] = "EH:%06d:000000:000000" % self.Images[Index].StaticHeader["Image"]
- self.Images[Index].StaticHeader["ByteOrder"] = self.Images[Index].ByteOrder
- self.Images[Index].StaticHeader["DataType"] = self.Images[Index].DataType
-
- self.Images[Index].Header = {}
- self.File.seek(0, 2)
- StrHeader = "{\n"
- for i in STATIC_HEADER_ELEMENTS:
- if i in self.Images[Index].StaticHeader.keys():
- StrHeader = StrHeader + ("%s = %s ;\n" % (i, self.Images[Index].StaticHeader[i]))
- for i in Header.keys():
- StrHeader = StrHeader + ("%s = %s ;\n" % (i, Header[i]))
- self.Images[Index].Header[i] = Header[i]
- newsize = (((len(StrHeader) + 1) // HEADER_BLOCK_SIZE) + 1) * HEADER_BLOCK_SIZE - 2
- newsize = int(newsize)
- StrHeader = StrHeader.ljust(newsize)
- StrHeader = StrHeader + "}\n"
-
- self.Images[Index].HeaderPosition = self.File.tell()
- self.File.write(StrHeader.encode())
- self.Images[Index].DataPosition = self.File.tell()
-
- # if self.Images[Index].StaticHeader["ByteOrder"] != self.SysByteOrder:
- if self.Images[Index].ByteOrder.upper() != self.SysByteOrder.upper():
- self.File.write((Data.byteswap()).tobytes())
- else:
- self.File.write(Data.tobytes())
-
- def __makeSureFileIsOpen(self):
- if DEBUG:
- print("Making sure file is open")
- if not self.__ownedOpen:
- return
- if self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- if DEBUG:
- print("Special case. Image is buffered")
- return
- if self.File in [0, None]:
- if DEBUG:
- print("File is None")
- elif self.File.closed:
- if DEBUG:
- print("Reopening closed file")
- accessMode = self.File.mode
- fileName = self.File.name
- newFile = open(fileName, accessMode)
- self.File = newFile
- return
-
- def __makeSureFileIsClosed(self):
- if DEBUG:
- print("Making sure file is closed")
- if not self.__ownedOpen:
- return
- if self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- if DEBUG:
- print("Special case. Image is buffered")
- return
- if self.File in [0, None]:
- if DEBUG:
- print("File is None")
- elif not self.File.closed:
- if DEBUG:
- print("Closing file")
- self.File.close()
- return
-
- def __GetDefaultNumpyType__(self, EdfType, index=None):
- """ Internal method: returns NumPy type according to Edf type
- """
- return self.GetDefaultNumpyType(EdfType, index)
-
- def __GetDefaultEdfType__(self, NumpyType):
- """ Internal method: returns Edf type according Numpy type
- """
- if NumpyType in ["b", numpy.int8]:
- return "SignedByte"
- elif NumpyType in ["B", numpy.uint8]:
- return "UnsignedByte"
- elif NumpyType in ["h", numpy.int16]:
- return "SignedShort"
- elif NumpyType in ["H", numpy.uint16]:
- return "UnsignedShort"
- elif NumpyType in ["i", numpy.int32]:
- return "SignedInteger"
- elif NumpyType in ["I", numpy.uint32]:
- return "UnsignedInteger"
- elif NumpyType == "l":
- if sys.platform == 'linux2':
- return "Signed64"
- else:
- return "SignedLong"
- elif NumpyType == "L":
- if sys.platform == 'linux2':
- return "Unsigned64"
- else:
- return "UnsignedLong"
- elif NumpyType == numpy.int64:
- return "Signed64"
- elif NumpyType == numpy.uint64:
- return "Unsigned64"
- elif NumpyType in ["f", numpy.float32]:
- return "FloatValue"
- elif NumpyType in ["d", numpy.float64]:
- return "DoubleValue"
- else:
- raise TypeError("unknown NumpyType %s" % NumpyType)
-
- def __GetSizeNumpyType__(self, NumpyType):
- """ Internal method: returns size of NumPy's Array Types
- """
- if NumpyType in ["b", numpy.int8]:
- return 1
- elif NumpyType in ["B", numpy.uint8]:
- return 1
- elif NumpyType in ["h", numpy.int16]:
- return 2
- elif NumpyType in ["H", numpy.uint16]:
- return 2
- elif NumpyType in ["i", numpy.int32]:
- return 4
- elif NumpyType in ["I", numpy.uint32]:
- return 4
- elif NumpyType == "l":
- if sys.platform == 'linux2':
- return 8 # 64 bit
- else:
- return 4 # 32 bit
- elif NumpyType == "L":
- if sys.platform == 'linux2':
- return 8 # 64 bit
- else:
- return 4 # 32 bit
- elif NumpyType in ["f", numpy.float32]:
- return 4
- elif NumpyType in ["d", numpy.float64]:
- return 8
- elif NumpyType == "Q":
- return 8 # unsigned 64 in 32 bit
- elif NumpyType == "q":
- return 8 # signed 64 in 32 bit
- elif NumpyType == numpy.uint64:
- return 8
- elif NumpyType == numpy.int64:
- return 8
- else:
- raise TypeError("unknown NumpyType %s" % NumpyType)
-
- def __SetDataType__(self, Array, DataType):
- """ Internal method: array type convertion
- """
- # AVOID problems not using FromEdfType= Array.dtype.char
- FromEdfType = Array.dtype
- ToEdfType = self.__GetDefaultNumpyType__(DataType)
- if ToEdfType != FromEdfType:
- aux = Array.astype(self.__GetDefaultNumpyType__(DataType))
- return aux
- return Array
-
- def __del__(self):
- try:
- self.__makeSureFileIsClosed()
- except:
- pass
-
- def GetDefaultNumpyType(self, EdfType, index=None):
- """ Returns NumPy type according Edf type
- """
- if index is None:
- return GetDefaultNumpyType(EdfType)
- EdfType = EdfType.upper()
- if EdfType in ['SIGNED64']:
- return numpy.int64
- if EdfType in ['UNSIGNED64']:
- return numpy.uint64
- if EdfType in ["SIGNEDLONG", "UNSIGNEDLONG"]:
- dim1 = 1
- dim2 = 1
- dim3 = 1
- if hasattr(self.Images[index], "Dim1"):
- dim1 = self.Images[index].Dim1
- if hasattr(self.Images[index], "Dim2"):
- dim2 = self.Images[index].Dim2
- if dim2 <= 0:
- dim2 = 1
- if hasattr(self.Images[index], "Dim3"):
- dim3 = self.Images[index].Dim3
- if dim3 <= 0:
- dim3 = 1
- if hasattr(self.Images[index], "Size"):
- size = self.Images[index].Size
- if size / (dim1 * dim2 * dim3) == 8:
- if EdfType == "UNSIGNEDLONG":
- return numpy.uint64
- else:
- return numpy.int64
- if EdfType == "UNSIGNEDLONG":
- return numpy.uint32
- else:
- return numpy.int32
-
- return GetDefaultNumpyType(EdfType)
-
-
-def GetDefaultNumpyType(EdfType):
- """ Returns NumPy type according Edf type
- """
- EdfType = EdfType.upper()
- if EdfType == "SIGNEDBYTE":
- return numpy.int8 # "b"
- elif EdfType == "UNSIGNEDBYTE":
- return numpy.uint8 # "B"
- elif EdfType == "SIGNEDSHORT":
- return numpy.int16 # "h"
- elif EdfType == "UNSIGNEDSHORT":
- return numpy.uint16 # "H"
- elif EdfType == "SIGNEDINTEGER":
- return numpy.int32 # "i"
- elif EdfType == "UNSIGNEDINTEGER":
- return numpy.uint32 # "I"
- elif EdfType == "SIGNEDLONG":
- return numpy.int32 # "i" #ESRF acquisition is made in 32bit
- elif EdfType == "UNSIGNEDLONG":
- return numpy.uint32 # "I" #ESRF acquisition is made in 32bit
- elif EdfType == "SIGNED64":
- return numpy.int64 # "l"
- elif EdfType == "UNSIGNED64":
- return numpy.uint64 # "L"
- elif EdfType == "FLOATVALUE":
- return numpy.float32 # "f"
- elif EdfType == "FLOAT":
- return numpy.float32 # "f"
- elif EdfType == "DOUBLEVALUE":
- return numpy.float64 # "d"
- else:
- raise TypeError("unknown EdfType %s" % EdfType)
-
-
-def SetDictCase(Dict, Case, Flag):
- """ Returns dictionary with keys and/or values converted into upper or lowercase
- Dict: input dictionary
- Case: LOWER_CASE, UPPER_CASE
- Flag: KEYS, VALUES or KEYS | VALUES
- """
- newdict = {}
- for i in Dict.keys():
- newkey = i
- newvalue = Dict[i]
- if Flag & KEYS:
- if Case == LOWER_CASE:
- newkey = newkey.lower()
- else:
- newkey = newkey.upper()
- if Flag & VALUES:
- if Case == LOWER_CASE:
- newvalue = newvalue.lower()
- else:
- newvalue = newvalue.upper()
- newdict[newkey] = newvalue
- return newdict
-
-
-def GetRegion(Arr, Pos, Size):
- """Returns array with refion of Arr.
- Arr must be 1d, 2d or 3d
- Pos and Size are tuples in the format (x) or (x,y) or (x,y,z)
- Both parameters must have the same size as the dimention of Arr
- """
- Dim = len(Arr.shape)
- if len(Pos) != Dim:
- return None
- if len(Size) != Dim:
- return None
-
- if (Dim == 1):
- SizeX = Size[0]
- if SizeX == 0:
- SizeX = Arr.shape[0] - Pos[0]
- ArrRet = numpy.take(Arr, range(Pos[0], Pos[0] + SizeX))
- elif (Dim == 2):
- SizeX = Size[0]
- SizeY = Size[1]
- if SizeX == 0:
- SizeX = Arr.shape[1] - Pos[0]
- if SizeY == 0:
- SizeY = Arr.shape[0] - Pos[1]
- ArrRet = numpy.take(Arr, range(Pos[1], Pos[1] + SizeY))
- ArrRet = numpy.take(ArrRet, range(Pos[0], Pos[0] + SizeX), 1)
- elif (Dim == 3):
- SizeX = Size[0]
- SizeY = Size[1]
- SizeZ = Size[2]
- if SizeX == 0:
- SizeX = Arr.shape[2] - Pos[0]
- if SizeY == 0:
- SizeX = Arr.shape[1] - Pos[1]
- if SizeZ == 0:
- SizeZ = Arr.shape[0] - Pos[2]
- ArrRet = numpy.take(Arr, range(Pos[2], Pos[2] + SizeZ))
- ArrRet = numpy.take(ArrRet, range(Pos[1], Pos[1] + SizeY), 1)
- ArrRet = numpy.take(ArrRet, range(Pos[0], Pos[0] + SizeX), 2)
- else:
- ArrRet = None
- return ArrRet
-
-
-if __name__ == "__main__":
- if 1:
- a = numpy.zeros((5, 10))
- for i in range(5):
- for j in range(10):
- a[i, j] = 10 * i + j
- edf = EdfFile("armando.edf", access="ab+")
- edf.WriteImage({}, a)
- del edf # force to close the file
- inp = EdfFile("armando.edf")
- b = inp.GetData(0)
- out = EdfFile("armando2.edf")
- out.WriteImage({}, b)
- del out # force to close the file
- inp2 = EdfFile("armando2.edf")
- c = inp2.GetData(0)
- print("A SHAPE = ", a.shape)
- print("B SHAPE = ", b.shape)
- print("C SHAPE = ", c.shape)
- for i in range(5):
- print("A", a[i, :])
- print("B", b[i, :])
- print("C", c[i, :])
-
- x = numpy.arange(100)
- x.shape = 5, 20
- for item in ["SignedByte", "UnsignedByte",
- "SignedShort", "UnsignedShort",
- "SignedLong", "UnsignedLong",
- "Signed64", "Unsigned64",
- "FloatValue", "DoubleValue"]:
- fname = item + ".edf"
- if os.path.exists(fname):
- os.remove(fname)
- towrite = EdfFile(fname)
- towrite.WriteImage({}, x, DataType=item, Append=0)
- sys.exit(0)
-
- # Creates object based on file exe.edf
- exe = EdfFile("images/test_image.edf")
- x = EdfFile("images/test_getdata.edf")
- # Gets unsigned short data, storing in an signed long
- arr = exe.GetData(0, Pos=(100, 200), Size=(200, 400))
- x.WriteImage({}, arr, 0)
-
- arr = exe.GetData(0, Pos=(100, 200))
- x.WriteImage({}, arr)
-
- arr = exe.GetData(0, Size=(200, 400))
- x.WriteImage({}, arr)
-
- arr = exe.GetData(0)
- x.WriteImage({}, arr)
-
- sys.exit()
-
- # Creates object based on file exe.edf
- exe = EdfFile("images/.edf")
-
- # Creates long array , filled with 0xFFFFFFFF(-1)
- la = numpy.zeros((100, 100))
- la = la - 1
-
- # Creates a short array, filled with 0xFFFF
- sa = numpy.zeros((100, 100))
- sa = sa + 0xFFFF
- sa = sa.astype("s")
-
- # Writes long array, initializing file (append=0)
- exe.WriteImage({}, la, 0, "")
-
- # Appends short array with new header items
- exe.WriteImage({'Name': 'Alexandre', 'Date': '16/07/2001'}, sa)
-
- # Appends short array, in Edf type unsigned
- exe.WriteImage({}, sa, DataType="UnsignedShort")
-
- # Appends short array, in Edf type unsigned
- exe.WriteImage({}, sa, DataType="UnsignedLong")
-
- # Appends long array as a double, considering unsigned
- exe.WriteImage({}, la, DataType="DoubleValue", WriteAsUnsigened=1)
-
- # Gets unsigned short data, storing in an signed long
- ushort = exe.GetData(2, "SignedLong")
-
- # Makes an operation
- ushort = ushort - 0x10
-
- # Saves Result as signed long
- exe.WriteImage({}, ushort)
-
- # Saves in the original format (unsigned short)
- OldHeader = exe.GetStaticHeader(2)
- exe.WriteImage({}, ushort, 1, OldHeader["DataType"])