summaryrefslogtreecommitdiff
path: root/silx/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'silx/third_party')
-rw-r--r--silx/third_party/EdfFile.py1225
-rw-r--r--silx/third_party/TiffIO.py1268
-rw-r--r--silx/third_party/__init__.py33
-rw-r--r--silx/third_party/scipy_spatial.py51
-rw-r--r--silx/third_party/setup.py49
5 files changed, 0 insertions, 2626 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"])
diff --git a/silx/third_party/TiffIO.py b/silx/third_party/TiffIO.py
deleted file mode 100644
index 7526a75..0000000
--- a/silx/third_party/TiffIO.py
+++ /dev/null
@@ -1,1268 +0,0 @@
-# /*##########################################################################
-#
-# The PyMca X-Ray Fluorescence Toolkit
-#
-# 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__ = "V.A. Sole - ESRF Data Analysis"
-__contact__ = "sole@esrf.fr"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-
-import sys
-import os
-import struct
-import numpy
-
-DEBUG = 0
-ALLOW_MULTIPLE_STRIPS = False
-
-TAG_ID = { 256:"NumberOfColumns", # S or L ImageWidth
- 257:"NumberOfRows", # S or L ImageHeight
- 258:"BitsPerSample", # S Number of bits per component
- 259:"Compression", # SHORT (1 - NoCompression, ...
- 262:"PhotometricInterpretation", # SHORT (0 - WhiteIsZero, 1 -BlackIsZero, 2 - RGB, 3 - Palette color
- 270:"ImageDescription", # ASCII
- 273:"StripOffsets", # S or L, for each strip, the byte offset of the strip
- 277:"SamplesPerPixel", # SHORT (>=3) only for RGB images
- 278:"RowsPerStrip", # S or L, number of rows in each back may be not for the last
- 279:"StripByteCounts", # S or L, The number of bytes in the strip AFTER any compression
- 305:"Software", # ASCII
- 306:"Date", # ASCII
- 320:"Colormap", # Colormap of Palette-color Images
- 339:"SampleFormat", # SHORT Interpretation of data in each pixel
- }
-
-#TILES ARE TO BE SUPPORTED TOO ...
-TAG_NUMBER_OF_COLUMNS = 256
-TAG_NUMBER_OF_ROWS = 257
-TAG_BITS_PER_SAMPLE = 258
-TAG_PHOTOMETRIC_INTERPRETATION = 262
-TAG_COMPRESSION = 259
-TAG_IMAGE_DESCRIPTION = 270
-TAG_STRIP_OFFSETS = 273
-TAG_SAMPLES_PER_PIXEL = 277
-TAG_ROWS_PER_STRIP = 278
-TAG_STRIP_BYTE_COUNTS = 279
-TAG_SOFTWARE = 305
-TAG_DATE = 306
-TAG_COLORMAP = 320
-TAG_SAMPLE_FORMAT = 339
-
-FIELD_TYPE = {1:('BYTE', "B"),
- 2:('ASCII', "s"), #string ending with binary zero
- 3:('SHORT', "H"),
- 4:('LONG', "I"),
- 5:('RATIONAL',"II"),
- 6:('SBYTE', "b"),
- 7:('UNDEFINED',"B"),
- 8:('SSHORT', "h"),
- 9:('SLONG', "i"),
- 10:('SRATIONAL',"ii"),
- 11:('FLOAT', "f"),
- 12:('DOUBLE', "d")}
-
-FIELD_TYPE_OUT = { 'B': 1,
- 's': 2,
- 'H': 3,
- 'I': 4,
- 'II': 5,
- 'b': 6,
- 'h': 8,
- 'i': 9,
- 'ii': 10,
- 'f': 11,
- 'd': 12}
-
-#sample formats (http://www.awaresystems.be/imaging/tiff/tiffflags/sampleformat.html)
-SAMPLE_FORMAT_UINT = 1
-SAMPLE_FORMAT_INT = 2
-SAMPLE_FORMAT_FLOAT = 3 #floating point
-SAMPLE_FORMAT_VOID = 4 #undefined data, usually assumed UINT
-SAMPLE_FORMAT_COMPLEXINT = 5
-SAMPLE_FORMAT_COMPLEXIEEEFP = 6
-
-
-
-class TiffIO(object):
- def __init__(self, filename, mode=None, cache_length=20, mono_output=False):
- if mode is None:
- mode = 'rb'
- if 'b' not in mode:
- mode = mode + 'b'
- if 'a' in mode.lower():
- raise IOError("Mode %s makes no sense on TIFF files. Consider 'rb+'" % mode)
- if ('w' in mode):
- if '+' not in mode:
- mode += '+'
-
- if hasattr(filename, "seek") and\
- hasattr(filename, "read"):
- fd = filename
- self._access = None
- else:
- #the b is needed for windows and python 3
- fd = open(filename, mode)
- self._access = mode
-
- self._initInternalVariables(fd)
- self._maxImageCacheLength = cache_length
- self._forceMonoOutput = mono_output
-
- def _initInternalVariables(self, fd=None):
- if fd is None:
- fd = self.fd
- else:
- self.fd = fd
- # read the order
- fd.seek(0)
- order = fd.read(2).decode()
- if len(order):
- if order == "II":
- #intel, little endian
- fileOrder = "little"
- self._structChar = '<'
- elif order == "MM":
- #motorola, high endian
- fileOrder = "big"
- self._structChar = '>'
- else:
- raise IOError("File is not a Mar CCD file, nor a TIFF file")
- a = fd.read(2)
- fortyTwo = struct.unpack(self._structChar+"H",a)[0]
- if fortyTwo != 42:
- raise IOError("Invalid TIFF version %d" % fortyTwo)
- else:
- if DEBUG:
- print("VALID TIFF VERSION")
- if sys.byteorder != fileOrder:
- swap = True
- else:
- swap = False
- else:
- if sys.byteorder == "little":
- self._structChar = '<'
- else:
- self._structChar = '>'
- swap = False
- self._swap = swap
- self._IFD = []
- self._imageDataCacheIndex = []
- self._imageDataCache = []
- self._imageInfoCacheIndex = []
- self._imageInfoCache = []
- self.getImageFileDirectories(fd)
-
- def __makeSureFileIsOpen(self):
- if not self.fd.closed:
- return
- if DEBUG:
- print("Reopening closed file")
- fileName = self.fd.name
- if self._access is None:
- #we do not own the file
- #open in read mode
- newFile = open(fileName,'rb')
- else:
- newFile = open(fileName, self._access)
- self.fd = newFile
-
- def __makeSureFileIsClosed(self):
- if self._access is None:
- #we do not own the file
- if DEBUG:
- print("Not closing not owned file")
- return
-
- if not self.fd.closed:
- self.fd.close()
-
- def close(self):
- return self.__makeSureFileIsClosed()
-
- def getNumberOfImages(self):
- #update for the case someone has done anything?
- self._updateIFD()
- return len(self._IFD)
-
- def _updateIFD(self):
- self.__makeSureFileIsOpen()
- self.getImageFileDirectories()
- self.__makeSureFileIsClosed()
-
- def getImageFileDirectories(self, fd=None):
- if fd is None:
- fd = self.fd
- else:
- self.fd = fd
- st = self._structChar
- fd.seek(4)
- self._IFD = []
- nImages = 0
- fmt = st + 'I'
- inStr = fd.read(struct.calcsize(fmt))
- if not len(inStr):
- offsetToIFD = 0
- else:
- offsetToIFD = struct.unpack(fmt, inStr)[0]
- if DEBUG:
- print("Offset to first IFD = %d" % offsetToIFD)
- while offsetToIFD != 0:
- self._IFD.append(offsetToIFD)
- nImages += 1
- fd.seek(offsetToIFD)
- fmt = st + 'H'
- numberOfDirectoryEntries = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Number of directory entries = %d" % numberOfDirectoryEntries)
-
- fmt = st + 'I'
- fd.seek(offsetToIFD + 2 + 12 * numberOfDirectoryEntries)
- offsetToIFD = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Next Offset to IFD = %d" % offsetToIFD)
- #offsetToIFD = 0
- if DEBUG:
- print("Number of images found = %d" % nImages)
- return nImages
-
- def _parseImageFileDirectory(self, nImage):
- offsetToIFD = self._IFD[nImage]
- st = self._structChar
- fd = self.fd
- fd.seek(offsetToIFD)
- fmt = st + 'H'
- numberOfDirectoryEntries = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Number of directory entries = %d" % numberOfDirectoryEntries)
-
- fmt = st + 'HHI4s'
- tagIDList = []
- fieldTypeList = []
- nValuesList = []
- valueOffsetList = []
- for i in range(numberOfDirectoryEntries):
- tagID, fieldType, nValues, valueOffset = struct.unpack(fmt, fd.read(12))
- tagIDList.append(tagID)
- fieldTypeList.append(fieldType)
- nValuesList.append(nValues)
- if nValues == 1:
- ftype, vfmt = FIELD_TYPE[fieldType]
- if ftype not in ['ASCII', 'RATIONAL', 'SRATIONAL']:
- vfmt = st + vfmt
- actualValue = struct.unpack(vfmt, valueOffset[0: struct.calcsize(vfmt)])[0]
- valueOffsetList.append(actualValue)
- else:
- valueOffsetList.append(valueOffset)
- elif (nValues < 5) and (fieldType == 2):
- ftype, vfmt = FIELD_TYPE[fieldType]
- vfmt = st + "%d%s" % (nValues,vfmt)
- actualValue = struct.unpack(vfmt, valueOffset[0: struct.calcsize(vfmt)])[0]
- valueOffsetList.append(actualValue)
- else:
- valueOffsetList.append(valueOffset)
- if DEBUG:
- if tagID in TAG_ID:
- print("tagID = %s" % TAG_ID[tagID])
- else:
- print("tagID = %d" % tagID)
- print("fieldType = %s" % FIELD_TYPE[fieldType][0])
- print("nValues = %d" % nValues)
- #if nValues == 1:
- # print("valueOffset = %s" % valueOffset)
- return tagIDList, fieldTypeList, nValuesList, valueOffsetList
-
-
-
- def _readIFDEntry(self, tag, tagIDList, fieldTypeList, nValuesList, valueOffsetList):
- fd = self.fd
- st = self._structChar
- idx = tagIDList.index(tag)
- nValues = nValuesList[idx]
- output = []
- ftype, vfmt = FIELD_TYPE[fieldTypeList[idx]]
- vfmt = st + "%d%s" % (nValues, vfmt)
- requestedBytes = struct.calcsize(vfmt)
- if nValues == 1:
- output.append(valueOffsetList[idx])
- elif requestedBytes < 5:
- output.append(valueOffsetList[idx])
- else:
- fd.seek(struct.unpack(st+"I", valueOffsetList[idx])[0])
- output = struct.unpack(vfmt, fd.read(requestedBytes))
- return output
-
- def getData(self, nImage, **kw):
- if nImage >= len(self._IFD):
- #update prior to raise an index error error
- self._updateIFD()
- return self._readImage(nImage, **kw)
-
- def getImage(self, nImage):
- return self.getData(nImage)
-
- def getInfo(self, nImage, **kw):
- if nImage >= len(self._IFD):
- #update prior to raise an index error error
- self._updateIFD()
- # current = self._IFD[nImage]
- return self._readInfo(nImage)
-
- def _readInfo(self, nImage, close=True):
- if nImage in self._imageInfoCacheIndex:
- if DEBUG:
- print("Reading info from cache")
- return self._imageInfoCache[self._imageInfoCacheIndex.index(nImage)]
-
- #read the header
- self.__makeSureFileIsOpen()
- tagIDList, fieldTypeList, nValuesList, valueOffsetList = self._parseImageFileDirectory(nImage)
-
- #rows and columns
- nColumns = valueOffsetList[tagIDList.index(TAG_NUMBER_OF_COLUMNS)]
- nRows = valueOffsetList[tagIDList.index(TAG_NUMBER_OF_ROWS)]
-
- #bits per sample
- idx = tagIDList.index(TAG_BITS_PER_SAMPLE)
- nBits = valueOffsetList[idx]
- if nValuesList[idx] != 1:
- #this happens with RGB and friends, nBits is not a single value
- nBits = self._readIFDEntry(TAG_BITS_PER_SAMPLE,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
-
-
- if TAG_COLORMAP in tagIDList:
- idx = tagIDList.index(TAG_COLORMAP)
- tmpColormap = self._readIFDEntry(TAG_COLORMAP,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- if max(tmpColormap) > 255:
- tmpColormap = numpy.array(tmpColormap, dtype=numpy.uint16)
- tmpColormap = (tmpColormap/256.).astype(numpy.uint8)
- else:
- tmpColormap = numpy.array(tmpColormap, dtype=numpy.uint8)
- tmpColormap.shape = 3, -1
- colormap = numpy.zeros((tmpColormap.shape[-1], 3), tmpColormap.dtype)
- colormap[:,:] = tmpColormap.T
- tmpColormap = None
- else:
- colormap = None
-
- #sample format
- if TAG_SAMPLE_FORMAT in tagIDList:
- sampleFormat = valueOffsetList[tagIDList.index(TAG_SAMPLE_FORMAT)]
- else:
- #set to unknown
- sampleFormat = SAMPLE_FORMAT_VOID
-
- # compression
- compression = False
- compression_type = 1
- if TAG_COMPRESSION in tagIDList:
- compression_type = valueOffsetList[tagIDList.index(TAG_COMPRESSION)]
- if compression_type == 1:
- compression = False
- else:
- compression = True
-
- #photometric interpretation
- interpretation = 1
- if TAG_PHOTOMETRIC_INTERPRETATION in tagIDList:
- interpretation = valueOffsetList[tagIDList.index(TAG_PHOTOMETRIC_INTERPRETATION)]
- else:
- print("WARNING: Non standard TIFF. Photometric interpretation TAG missing")
- helpString = ""
- if sys.version > '2.6':
- helpString = eval('b""')
-
- if TAG_IMAGE_DESCRIPTION in tagIDList:
- imageDescription = self._readIFDEntry(TAG_IMAGE_DESCRIPTION,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- if type(imageDescription) in [type([1]), type((1,))]:
- imageDescription =helpString.join(imageDescription)
- else:
- imageDescription = "%d/%d" % (nImage+1, len(self._IFD))
-
- if sys.version < '3.0':
- defaultSoftware = "Unknown Software"
- else:
- defaultSoftware = bytes("Unknown Software",
- encoding='utf-8')
- if TAG_SOFTWARE in tagIDList:
- software = self._readIFDEntry(TAG_SOFTWARE,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- if type(software) in [type([1]), type((1,))]:
- software =helpString.join(software)
- else:
- software = defaultSoftware
-
- if software == defaultSoftware:
- try:
- if sys.version < '3.0':
- if imageDescription.upper().startswith("IMAGEJ"):
- software = imageDescription.split("=")[0]
- else:
- tmpString = imageDescription.decode()
- if tmpString.upper().startswith("IMAGEJ"):
- software = bytes(tmpString.split("=")[0],
- encoding='utf-8')
- except:
- pass
-
- if TAG_DATE in tagIDList:
- date = self._readIFDEntry(TAG_DATE,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- if type(date) in [type([1]), type((1,))]:
- date =helpString.join(date)
- else:
- date = "Unknown Date"
-
- stripOffsets = self._readIFDEntry(TAG_STRIP_OFFSETS,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- if TAG_ROWS_PER_STRIP in tagIDList:
- rowsPerStrip = self._readIFDEntry(TAG_ROWS_PER_STRIP,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)[0]
- else:
- rowsPerStrip = nRows
- print("WARNING: Non standard TIFF. Rows per strip TAG missing")
-
- if TAG_STRIP_BYTE_COUNTS in tagIDList:
- stripByteCounts = self._readIFDEntry(TAG_STRIP_BYTE_COUNTS,
- tagIDList, fieldTypeList, nValuesList, valueOffsetList)
- else:
- print("WARNING: Non standard TIFF. Strip byte counts TAG missing")
- if hasattr(nBits, 'index'):
- expectedSum = 0
- for n in nBits:
- expectedSum += int(nRows * nColumns * n / 8)
- else:
- expectedSum = int(nRows * nColumns * nBits / 8)
- stripByteCounts = [expectedSum]
-
- if close:
- self.__makeSureFileIsClosed()
-
- if self._forceMonoOutput and (interpretation > 1):
- #color image but asked monochrome output
- nBits = 32
- colormap = None
- sampleFormat = SAMPLE_FORMAT_FLOAT
- interpretation = 1
- #we cannot rely on any cache in this case
- useInfoCache = False
- if DEBUG:
- print("FORCED MONO")
- else:
- useInfoCache = True
-
- info = {}
- info["nRows"] = nRows
- info["nColumns"] = nColumns
- info["nBits"] = nBits
- info["compression"] = compression
- info["compression_type"] = compression_type
- info["imageDescription"] = imageDescription
- info["stripOffsets"] = stripOffsets #This contains the file offsets to the data positions
- info["rowsPerStrip"] = rowsPerStrip
- info["stripByteCounts"] = stripByteCounts #bytes in strip since I do not support compression
- info["software"] = software
- info["date"] = date
- info["colormap"] = colormap
- info["sampleFormat"] = sampleFormat
- info["photometricInterpretation"] = interpretation
- infoDict = {}
- if sys.version < '3.0':
- testString = 'PyMca'
- else:
- testString = eval('b"PyMca"')
- if software.startswith(testString):
- #str to make sure python 2.x sees it as string and not unicode
- if sys.version < '3.0':
- descriptionString = imageDescription
- else:
- descriptionString = str(imageDescription.decode())
- #interpret the image description in terms of supplied
- #information at writing time
- items = descriptionString.split('=')
- for i in range(int(len(items)/2)):
- key = "%s" % items[i*2]
- #get rid of the \n at the end of the value
- value = "%s" % items[i*2+1][:-1]
- infoDict[key] = value
- info['info'] = infoDict
-
- if (self._maxImageCacheLength > 0) and useInfoCache:
- self._imageInfoCacheIndex.insert(0,nImage)
- self._imageInfoCache.insert(0, info)
- if len(self._imageInfoCacheIndex) > self._maxImageCacheLength:
- self._imageInfoCacheIndex = self._imageInfoCacheIndex[:self._maxImageCacheLength]
- self._imageInfoCache = self._imageInfoCache[:self._maxImageCacheLength]
- return info
-
- def _readImage(self, nImage, **kw):
- if DEBUG:
- print("Reading image %d" % nImage)
- if 'close' in kw:
- close = kw['close']
- else:
- close = True
- rowMin = kw.get('rowMin', None)
- rowMax = kw.get('rowMax', None)
- if nImage in self._imageDataCacheIndex:
- if DEBUG:
- print("Reading image data from cache")
- return self._imageDataCache[self._imageDataCacheIndex.index(nImage)]
-
- self.__makeSureFileIsOpen()
- if self._forceMonoOutput:
- oldMono = True
- else:
- oldMono = False
- try:
- self._forceMonoOutput = False
- info = self._readInfo(nImage, close=False)
- self._forceMonoOutput = oldMono
- except:
- self._forceMonoOutput = oldMono
- raise
- compression = info['compression']
- compression_type = info['compression_type']
- if compression:
- if compression_type != 32773:
- raise IOError("Compressed TIFF images not supported except packbits")
- else:
- #PackBits compression
- if DEBUG:
- print("Using PackBits compression")
-
- interpretation = info["photometricInterpretation"]
- if interpretation == 2:
- #RGB
- pass
- #raise IOError("RGB Image. Only grayscale images supported")
- elif interpretation == 3:
- #Palette Color Image
- pass
- #raise IOError("Palette-color Image. Only grayscale images supported")
- elif interpretation > 2:
- #Palette Color Image
- raise IOError("Only grayscale images supported")
-
- nRows = info["nRows"]
- nColumns = info["nColumns"]
- nBits = info["nBits"]
- colormap = info["colormap"]
- sampleFormat = info["sampleFormat"]
-
- if rowMin is None:
- rowMin = 0
-
- if rowMax is None:
- rowMax = nRows - 1
-
- if rowMin < 0:
- rowMin = nRows - rowMin
-
- if rowMax < 0:
- rowMax = nRows - rowMax
-
- if rowMax < rowMin:
- txt = "Max Row smaller than Min Row. Reverse selection not supported"
- raise NotImplementedError(txt)
-
- if rowMin >= nRows:
- raise IndexError("Image only has %d rows" % nRows)
-
- if rowMax >= nRows:
- raise IndexError("Image only has %d rows" % nRows)
-
- if sampleFormat == SAMPLE_FORMAT_FLOAT:
- if nBits == 32:
- dtype = numpy.float32
- elif nBits == 64:
- dtype = numpy.float64
- else:
- raise ValueError("Unsupported number of bits for a float: %d" % nBits)
- elif sampleFormat in [SAMPLE_FORMAT_UINT, SAMPLE_FORMAT_VOID]:
- if nBits in [8, (8, 8, 8), [8, 8, 8]]:
- dtype = numpy.uint8
- elif nBits in [16, (16, 16, 16), [16, 16, 16]]:
- dtype = numpy.uint16
- elif nBits in [32, (32, 32, 32), [32, 32, 32]]:
- dtype = numpy.uint32
- elif nBits in [64, (64, 64, 64), [64, 64, 64]]:
- dtype = numpy.uint64
- else:
- raise ValueError("Unsupported number of bits for unsigned int: %s" % (nBits,))
- elif sampleFormat == SAMPLE_FORMAT_INT:
- if nBits in [8, (8, 8, 8), [8, 8, 8]]:
- dtype = numpy.int8
- elif nBits in [16, (16, 16, 16), [16, 16, 16]]:
- dtype = numpy.int16
- elif nBits in [32, (32, 32, 32), [32, 32, 32]]:
- dtype = numpy.int32
- elif nBits in [64, (64, 64, 64), [64, 64, 64]]:
- dtype = numpy.int64
- else:
- raise ValueError("Unsupported number of bits for signed int: %s" % (nBits,))
- else:
- raise ValueError("Unsupported combination. Bits = %s Format = %d" % (nBits, sampleFormat))
- if hasattr(nBits, 'index'):
- image = numpy.zeros((nRows, nColumns, len(nBits)), dtype=dtype)
- elif colormap is not None:
- #should I use colormap dtype?
- image = numpy.zeros((nRows, nColumns, 3), dtype=dtype)
- else:
- image = numpy.zeros((nRows, nColumns), dtype=dtype)
-
- fd = self.fd
- st = self._structChar
- stripOffsets = info["stripOffsets"] #This contains the file offsets to the data positions
- rowsPerStrip = info["rowsPerStrip"]
- stripByteCounts = info["stripByteCounts"] #bytes in strip since I do not support compression
-
- rowStart = 0
- if len(stripOffsets) == 1:
- bytesPerRow = int(stripByteCounts[0]/rowsPerStrip)
- if nRows == rowsPerStrip:
- actualBytesPerRow = int(image.nbytes/nRows)
- if actualBytesPerRow != bytesPerRow:
- print("Warning: Bogus StripByteCounts information")
- bytesPerRow = actualBytesPerRow
- fd.seek(stripOffsets[0] + rowMin * bytesPerRow)
- nBytes = (rowMax-rowMin+1) * bytesPerRow
- if self._swap:
- readout = numpy.copy(numpy.frombuffer(fd.read(nBytes), dtype)).byteswap()
- else:
- readout = numpy.copy(numpy.frombuffer(fd.read(nBytes), dtype))
- if hasattr(nBits, 'index'):
- readout.shape = -1, nColumns, len(nBits)
- elif info['colormap'] is not None:
- readout = colormap[readout]
- else:
- readout.shape = -1, nColumns
- image[rowMin:rowMax+1, :] = readout
- else:
- for i in range(len(stripOffsets)):
- #the amount of rows
- nRowsToRead = rowsPerStrip
- rowEnd = int(min(rowStart+nRowsToRead, nRows))
- if rowEnd < rowMin:
- rowStart += nRowsToRead
- continue
- if (rowStart > rowMax):
- break
- #we are in position
- fd.seek(stripOffsets[i])
- #the amount of bytes to read
- nBytes = stripByteCounts[i]
- if compression_type == 32773:
- try:
- bufferBytes = bytes()
- except:
- #python 2.5 ...
- bufferBytes = ""
- #packBits
- readBytes = 0
- #intermediate buffer
- tmpBuffer = fd.read(nBytes)
- while readBytes < nBytes:
- n = struct.unpack('b', tmpBuffer[readBytes:(readBytes+1)])[0]
- readBytes += 1
- if n >= 0:
- #should I prevent reading more than the
- #length of the chain? Let's python raise
- #the exception...
- bufferBytes += tmpBuffer[readBytes:\
- readBytes+(n+1)]
- readBytes += (n+1)
- elif n > -128:
- bufferBytes += (-n+1) * tmpBuffer[readBytes:(readBytes+1)]
- readBytes += 1
- else:
- #if read -128 ignore the byte
- continue
- if self._swap:
- readout = numpy.copy(numpy.frombuffer(bufferBytes, dtype)).byteswap()
- else:
- readout = numpy.copy(numpy.frombuffer(bufferBytes, dtype))
- if hasattr(nBits, 'index'):
- readout.shape = -1, nColumns, len(nBits)
- elif info['colormap'] is not None:
- readout = colormap[readout]
- readout.shape = -1, nColumns, 3
- else:
- readout.shape = -1, nColumns
- image[rowStart:rowEnd, :] = readout
- else:
- if 1:
- #use numpy
- if self._swap:
- readout = numpy.copy(numpy.frombuffer(fd.read(nBytes), dtype)).byteswap()
- else:
- readout = numpy.copy(numpy.frombuffer(fd.read(nBytes), dtype))
- if hasattr(nBits, 'index'):
- readout.shape = -1, nColumns, len(nBits)
- elif colormap is not None:
- readout = colormap[readout]
- readout.shape = -1, nColumns, 3
- else:
- readout.shape = -1, nColumns
- image[rowStart:rowEnd, :] = readout
- else:
- #using struct
- readout = numpy.array(struct.unpack(st+"%df" % int(nBytes/4), fd.read(nBytes)),
- dtype=dtype)
- if hasattr(nBits, 'index'):
- readout.shape = -1, nColumns, len(nBits)
- elif colormap is not None:
- readout = colormap[readout]
- readout.shape = -1, nColumns, 3
- else:
- readout.shape = -1, nColumns
- image[rowStart:rowEnd, :] = readout
- rowStart += nRowsToRead
- if close:
- self.__makeSureFileIsClosed()
-
- if len(image.shape) == 3:
- #color image
- if self._forceMonoOutput:
- #color image, convert to monochrome
- image = (image[:,:,0] * 0.114 +\
- image[:,:,1] * 0.587 +\
- image[:,:,2] * 0.299).astype(numpy.float32)
-
- if (rowMin == 0) and (rowMax == (nRows-1)):
- self._imageDataCacheIndex.insert(0,nImage)
- self._imageDataCache.insert(0, image)
- if len(self._imageDataCacheIndex) > self._maxImageCacheLength:
- self._imageDataCacheIndex = self._imageDataCacheIndex[:self._maxImageCacheLength]
- self._imageDataCache = self._imageDataCache[:self._maxImageCacheLength]
-
- return image
-
- def writeImage(self, image0, info=None, software=None, date=None):
- if software is None:
- software = 'PyMca.TiffIO'
- #if date is None:
- # date = time.ctime()
-
- self.__makeSureFileIsOpen()
- fd = self.fd
- #prior to do anything, perform some tests
- if not len(image0.shape):
- raise ValueError("Empty image")
- if len(image0.shape) == 1:
- #get a different view
- image = image0[:]
- image.shape = 1, -1
- else:
- image = image0
-
- if image.dtype == numpy.float64:
- image = image.astype(numpy.float32)
- fd.seek(0)
- mode = fd.mode
- name = fd.name
- if 'w' in mode:
- #we have to overwrite the file
- self.__makeSureFileIsClosed()
- fd = None
- if os.path.exists(name):
- os.remove(name)
- fd = open(name, mode='wb+')
- self._initEmptyFile(fd)
- self.fd = fd
-
- #read the file size
- self.__makeSureFileIsOpen()
- fd = self.fd
- fd.seek(0, os.SEEK_END)
- endOfFile = fd.tell()
- if fd.tell() == 0:
- self._initEmptyFile(fd)
- fd.seek(0, os.SEEK_END)
- endOfFile = fd.tell()
-
- #init internal variables
- self._initInternalVariables(fd)
- st = self._structChar
-
- #get the image file directories
- nImages = self.getImageFileDirectories()
- if DEBUG:
- print("File contains %d images" % nImages)
- if nImages == 0:
- fd.seek(4)
- fmt = st + 'I'
- fd.write(struct.pack(fmt, endOfFile))
- else:
- fd.seek(self._IFD[-1])
- fmt = st + 'H'
- numberOfDirectoryEntries = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- fmt = st + 'I'
- pos = self._IFD[-1] + 2 + 12 * numberOfDirectoryEntries
- fd.seek(pos)
- fmt = st + 'I'
- fd.write(struct.pack(fmt, endOfFile))
- fd.flush()
-
- #and we can write at the end of the file, find out the file length
- fd.seek(0, os.SEEK_END)
-
- #get the description information from the input information
- if info is None:
- description = info
- else:
- description = "%s" % ""
- for key in info.keys():
- description += "%s=%s\n" % (key, info[key])
-
- #get the image file directory
- outputIFD = self._getOutputIFD(image, description=description,
- software=software,
- date=date)
-
- #write the new IFD
- fd.write(outputIFD)
-
- #write the image
- if self._swap:
- fd.write(image.byteswap().tobytes())
- else:
- fd.write(image.tobytes())
-
- fd.flush()
- self.fd=fd
- self.__makeSureFileIsClosed()
-
- def _initEmptyFile(self, fd=None):
- if fd is None:
- fd = self.fd
- if sys.byteorder == "little":
- order = "II"
- #intel, little endian
- fileOrder = "little"
- self._structChar = '<'
- else:
- order = "MM"
- #motorola, high endian
- fileOrder = "big"
- self._structChar = '>'
- st = self._structChar
- if fileOrder == sys.byteorder:
- self._swap = False
- else:
- self._swap = True
- fd.seek(0)
- if sys.version < '3.0':
- fd.write(struct.pack(st+'2s', order))
- fd.write(struct.pack(st+'H', 42))
- fd.write(struct.pack(st+'I', 0))
- else:
- fd.write(struct.pack(st+'2s', bytes(order,'utf-8')))
- fd.write(struct.pack(st+'H', 42))
- fd.write(struct.pack(st+'I', 0))
- fd.flush()
-
- def _getOutputIFD(self, image, description=None, software=None, date=None):
- #the tags have to be in order
- #the very minimum is
- #256:"NumberOfColumns", # S or L ImageWidth
- #257:"NumberOfRows", # S or L ImageHeight
- #258:"BitsPerSample", # S Number of bits per component
- #259:"Compression", # SHORT (1 - NoCompression, ...
- #262:"PhotometricInterpretation", # SHORT (0 - WhiteIsZero, 1 -BlackIsZero, 2 - RGB, 3 - Palette color
- #270:"ImageDescription", # ASCII
- #273:"StripOffsets", # S or L, for each strip, the byte offset of the strip
- #277:"SamplesPerPixel", # SHORT (>=3) only for RGB images
- #278:"RowsPerStrip", # S or L, number of rows in each back may be not for the last
- #279:"StripByteCounts", # S or L, The number of bytes in the strip AFTER any compression
- #305:"Software", # ASCII
- #306:"Date", # ASCII
- #339:"SampleFormat", # SHORT Interpretation of data in each pixel
-
- nDirectoryEntries = 9
- imageDescription = None
- if description is not None:
- descriptionLength = len(description)
- while descriptionLength < 4:
- description = description + " "
- descriptionLength = len(description)
- if sys.version >= '3.0':
- description = bytes(description, 'utf-8')
- elif type(description) != type(""):
- try:
- description = description.decode('utf-8')
- except UnicodeDecodeError:
- try:
- description = description.decode('latin-1')
- except UnicodeDecodeError:
- description = "%s" % description
- if sys.version > '2.6':
- description=description.encode('utf-8', errors="ignore")
- description = "%s" % description
- descriptionLength = len(description)
- imageDescription = struct.pack("%ds" % descriptionLength, description)
- nDirectoryEntries += 1
-
- #software
- if software is not None:
- softwareLength = len(software)
- while softwareLength < 4:
- software = software + " "
- softwareLength = len(software)
- if sys.version >= '3.0':
- software = bytes(software, 'utf-8')
- softwarePackedString = struct.pack("%ds" % softwareLength, software)
- nDirectoryEntries += 1
- else:
- softwareLength = 0
-
- if date is not None:
- dateLength = len(date)
- if sys.version >= '3.0':
- date = bytes(date, 'utf-8')
- datePackedString = struct.pack("%ds" % dateLength, date)
- dateLength = len(datePackedString)
- nDirectoryEntries += 1
- else:
- dateLength = 0
-
- if len(image.shape) == 2:
- nRows, nColumns = image.shape
- nChannels = 1
- elif len(image.shape) == 3:
- nRows, nColumns, nChannels = image.shape
- else:
- raise RuntimeError("Image does not have the right shape")
- dtype = image.dtype
- bitsPerSample = int(dtype.str[-1]) * 8
-
- #only uncompressed data
- compression = 1
-
- #interpretation, black is zero
- if nChannels == 1:
- interpretation = 1
- bitsPerSampleLength = 0
- elif nChannels == 3:
- interpretation = 2
- bitsPerSampleLength = 3 * 2 # To store 3 shorts
- nDirectoryEntries += 1 # For SamplesPerPixel
- else:
- raise RuntimeError(
- "Image with %d color channel(s) not supported" % nChannels)
-
- #image description
- if imageDescription is not None:
- descriptionLength = len(imageDescription)
- else:
- descriptionLength = 0
-
- #strip offsets
- #we are putting them after the directory and the directory is
- #at the end of the file
- self.fd.seek(0, os.SEEK_END)
- endOfFile = self.fd.tell()
- if endOfFile == 0:
- #empty file
- endOfFile = 8
-
- #rows per strip
- if ALLOW_MULTIPLE_STRIPS:
- #try to segment the image in several pieces
- if not (nRows % 4):
- rowsPerStrip = int(nRows/4)
- elif not (nRows % 10):
- rowsPerStrip = int(nRows/10)
- elif not (nRows % 8):
- rowsPerStrip = int(nRows/8)
- elif not (nRows % 4):
- rowsPerStrip = int(nRows/4)
- elif not (nRows % 2):
- rowsPerStrip = int(nRows/2)
- else:
- rowsPerStrip = nRows
- else:
- rowsPerStrip = nRows
-
- #stripByteCounts
- stripByteCounts = int(nColumns * rowsPerStrip *
- bitsPerSample * nChannels / 8)
-
- if descriptionLength > 4:
- stripOffsets0 = endOfFile + dateLength + descriptionLength +\
- 2 + 12 * nDirectoryEntries + 4
- else:
- stripOffsets0 = endOfFile + dateLength + \
- 2 + 12 * nDirectoryEntries + 4
-
- if softwareLength > 4:
- stripOffsets0 += softwareLength
-
- stripOffsets0 += bitsPerSampleLength
-
- stripOffsets = [stripOffsets0]
- stripOffsetsLength = 0
- stripOffsetsString = None
-
- st = self._structChar
-
- if rowsPerStrip != nRows:
- nStripOffsets = int(nRows/rowsPerStrip)
- fmt = st + 'I'
- stripOffsetsLength = struct.calcsize(fmt) * nStripOffsets
- stripOffsets0 += stripOffsetsLength
- #the length for the stripByteCounts will be the same
- stripOffsets0 += stripOffsetsLength
- stripOffsets = []
- for i in range(nStripOffsets):
- value = stripOffsets0 + i * stripByteCounts
- stripOffsets.append(value)
- if i == 0:
- stripOffsetsString = struct.pack(fmt, value)
- stripByteCountsString = struct.pack(fmt, stripByteCounts)
- else:
- stripOffsetsString += struct.pack(fmt, value)
- stripByteCountsString += struct.pack(fmt, stripByteCounts)
-
- if DEBUG:
- print("IMAGE WILL START AT %d" % stripOffsets[0])
-
- #sample format
- if dtype in [numpy.float32, numpy.float64] or\
- dtype.str[-2] == 'f':
- sampleFormat = SAMPLE_FORMAT_FLOAT
- elif dtype in [numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64]:
- sampleFormat = SAMPLE_FORMAT_UINT
- elif dtype in [numpy.int8, numpy.int16, numpy.int32, numpy.int64]:
- sampleFormat = SAMPLE_FORMAT_INT
- else:
- raise ValueError("Unsupported data type %s" % dtype)
-
- info = {}
- info["nColumns"] = nColumns
- info["nRows"] = nRows
- info["nBits"] = bitsPerSample
- info["compression"] = compression
- info["photometricInterpretation"] = interpretation
- info["stripOffsets"] = stripOffsets
- if interpretation == 2:
- info["samplesPerPixel"] = 3 # No support for extra samples
- info["rowsPerStrip"] = rowsPerStrip
- info["stripByteCounts"] = stripByteCounts
- info["date"] = date
- info["sampleFormat"] = sampleFormat
-
- outputIFD = ""
- if sys.version > '2.6':
- outputIFD = eval('b""')
-
- fmt = st + "H"
- outputIFD += struct.pack(fmt, nDirectoryEntries)
-
- fmt = st + "HHII"
- outputIFD += struct.pack(fmt, TAG_NUMBER_OF_COLUMNS,
- FIELD_TYPE_OUT['I'],
- 1,
- info["nColumns"])
- outputIFD += struct.pack(fmt, TAG_NUMBER_OF_ROWS,
- FIELD_TYPE_OUT['I'],
- 1,
- info["nRows"])
-
- if info["photometricInterpretation"] == 1:
- fmt = st + 'HHIHH'
- outputIFD += struct.pack(fmt, TAG_BITS_PER_SAMPLE,
- FIELD_TYPE_OUT['H'],
- 1,
- info["nBits"], 0)
- elif info["photometricInterpretation"] == 2:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_BITS_PER_SAMPLE,
- FIELD_TYPE_OUT['H'],
- 3,
- info["stripOffsets"][0] - \
- 2 * stripOffsetsLength - \
- descriptionLength - \
- dateLength - \
- softwareLength - \
- bitsPerSampleLength)
- else:
- raise RuntimeError("Unsupported photometric interpretation")
-
- fmt = st + 'HHIHH'
- outputIFD += struct.pack(fmt, TAG_COMPRESSION,
- FIELD_TYPE_OUT['H'],
- 1,
- info["compression"],0)
- fmt = st + 'HHIHH'
- outputIFD += struct.pack(fmt, TAG_PHOTOMETRIC_INTERPRETATION,
- FIELD_TYPE_OUT['H'],
- 1,
- info["photometricInterpretation"],0)
-
- if imageDescription is not None:
- descriptionLength = len(imageDescription)
- if descriptionLength > 4:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_IMAGE_DESCRIPTION,
- FIELD_TYPE_OUT['s'],
- descriptionLength,
- info["stripOffsets"][0]-\
- 2*stripOffsetsLength-\
- descriptionLength)
- else:
- #it has to have length 4
- fmt = st + 'HHI%ds' % descriptionLength
- outputIFD += struct.pack(fmt, TAG_IMAGE_DESCRIPTION,
- FIELD_TYPE_OUT['s'],
- descriptionLength,
- description)
-
- if len(stripOffsets) == 1:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_STRIP_OFFSETS,
- FIELD_TYPE_OUT['I'],
- 1,
- info["stripOffsets"][0])
- else:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_STRIP_OFFSETS,
- FIELD_TYPE_OUT['I'],
- len(stripOffsets),
- info["stripOffsets"][0]-2*stripOffsetsLength)
-
- if info["photometricInterpretation"] == 2:
- fmt = st + 'HHIHH'
- outputIFD += struct.pack(fmt, TAG_SAMPLES_PER_PIXEL,
- FIELD_TYPE_OUT['H'],
- 1,
- info["samplesPerPixel"], 0)
-
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_ROWS_PER_STRIP,
- FIELD_TYPE_OUT['I'],
- 1,
- info["rowsPerStrip"])
-
- if len(stripOffsets) == 1:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_STRIP_BYTE_COUNTS,
- FIELD_TYPE_OUT['I'],
- 1,
- info["stripByteCounts"])
- else:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_STRIP_BYTE_COUNTS,
- FIELD_TYPE_OUT['I'],
- len(stripOffsets),
- info["stripOffsets"][0]-stripOffsetsLength)
-
- if software is not None:
- if softwareLength > 4:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_SOFTWARE,
- FIELD_TYPE_OUT['s'],
- softwareLength,
- info["stripOffsets"][0]-\
- 2*stripOffsetsLength-\
- descriptionLength-softwareLength-dateLength)
- else:
- #it has to have length 4
- fmt = st + 'HHI%ds' % softwareLength
- outputIFD += struct.pack(fmt, TAG_SOFTWARE,
- FIELD_TYPE_OUT['s'],
- softwareLength,
- softwarePackedString)
-
- if date is not None:
- fmt = st + 'HHII'
- outputIFD += struct.pack(fmt, TAG_DATE,
- FIELD_TYPE_OUT['s'],
- dateLength,
- info["stripOffsets"][0]-\
- 2*stripOffsetsLength-\
- descriptionLength-dateLength)
-
- fmt = st + 'HHIHH'
- outputIFD += struct.pack(fmt, TAG_SAMPLE_FORMAT,
- FIELD_TYPE_OUT['H'],
- 1,
- info["sampleFormat"],0)
- fmt = st + 'I'
- outputIFD += struct.pack(fmt, 0)
-
- if info["photometricInterpretation"] == 2:
- outputIFD += struct.pack('HHH', info["nBits"],
- info["nBits"], info["nBits"])
-
- if softwareLength > 4:
- outputIFD += softwarePackedString
-
- if date is not None:
- outputIFD += datePackedString
-
- if imageDescription is not None:
- if descriptionLength > 4:
- outputIFD += imageDescription
-
- if stripOffsetsString is not None:
- outputIFD += stripOffsetsString
- outputIFD += stripByteCountsString
-
- return outputIFD
-
-
-if __name__ == "__main__":
- filename = sys.argv[1]
- dtype = numpy.uint16
- if not os.path.exists(filename):
- print("Testing file creation")
- tif = TiffIO(filename, mode = 'wb+')
- data = numpy.arange(10000).astype(dtype)
- data.shape = 100, 100
- tif.writeImage(data, info={'Title':'1st'})
- tif = None
- if os.path.exists(filename):
- print("Testing image appending")
- tif = TiffIO(filename, mode = 'rb+')
- tif.writeImage((data*2).astype(dtype), info={'Title':'2nd'})
- tif = None
- tif = TiffIO(filename)
- print("Number of images = %d" % tif.getNumberOfImages())
- for i in range(tif.getNumberOfImages()):
- info = tif.getInfo(i)
- for key in info:
- if key not in ["colormap"]:
- print("%s = %s" % (key, info[key]))
- elif info['colormap'] is not None:
- print("RED %s = %s" % (key, info[key][0:10, 0]))
- print("GREEN %s = %s" % (key, info[key][0:10, 1]))
- print("BLUE %s = %s" % (key, info[key][0:10, 2]))
- data = tif.getImage(i)[0, 0:10]
- print("data [0, 0:10] = ", data)
-
diff --git a/silx/third_party/__init__.py b/silx/third_party/__init__.py
deleted file mode 100644
index 156563c..0000000
--- a/silx/third_party/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
-#
-# 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.
-#
-# ###########################################################################*/
-"""This package embeds a few dependency of silx.
-
-This is meant for internal use.
-"""
-
-
-__authors__ = ["Jérôme Kieffer"]
-__license__ = "MIT"
-__date__ = "09/10/2015"
diff --git a/silx/third_party/scipy_spatial.py b/silx/third_party/scipy_spatial.py
deleted file mode 100644
index 9885154..0000000
--- a/silx/third_party/scipy_spatial.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
-#
-# 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.
-#
-# ###########################################################################*/
-"""Wrapper module for `scipy.spatial.Delaunay` class.
-
-Uses a local copy of `scipy.spatial.Delaunay` if available,
-else it loads it from `scipy`.
-
-It should be used like that:
-
-.. code-block::
-
- from silx.third_party.scipy_spatial import Delaunay
-
-"""
-
-from __future__ import absolute_import
-
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "07/11/2017"
-
-try:
- # try to import silx local copy of Delaunay
- from ._local.scipy_spatial import Delaunay # noqa
-except ImportError:
- # else import it from the python path
- from scipy.spatial import Delaunay # noqa
-
-__all__ = ['Delaunay']
diff --git a/silx/third_party/setup.py b/silx/third_party/setup.py
deleted file mode 100644
index dd3d302..0000000
--- a/silx/third_party/setup.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# coding: ascii
-#
-# JK: Numpy.distutils which imports this does not handle utf-8 in version<1.12
-#
-# /*##########################################################################
-#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
-#
-# 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.
-#
-# ###########################################################################*/
-
-__authors__ = ["Valentin Valls"]
-__license__ = "MIT"
-__date__ = "23/04/2018"
-
-import os
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('third_party', parent_package, top_path)
- # includes _local only if it is available
- local_path = os.path.join(top_path, "silx", "third_party", "_local")
- if os.path.exists(local_path):
- config.add_subpackage('_local')
- config.add_subpackage('_local.scipy_spatial')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)