././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/.gitattributes0000664000000000000000000000016715215230701014462 0ustar00rootrootsandbox/* export-ignore .github/* export-ignore #ci/* export-ignore package/* export-ignore build-deb.sh export-ignore ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/.gitignore0000664000000000000000000000066115215230701013556 0ustar00rootroot*.py[cod] # C extensions *.so #testimages test/testimages # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject .settings # generated c files, i.e. all except the ones in the src directory *.c !fabio/ext/src/*.c ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/.pre-commit-config.yaml0000664000000000000000000000122715215230701016046 0ustar00rootroot# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-json - id: check-toml - id: check-added-large-files repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. rev: v0.14.1 hooks: # Run the linter. - id: ruff-check types_or: [ python, pyi ] args: [ --fix ] files: ^src/ # Run the formatter. #- id: ruff-format # types_or: [ python, pyi ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/.readthedocs.yaml0000664000000000000000000000124615215230701015015 0ustar00rootroot# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-22.04 tools: python: "3.12" # Build documentation in the docs/ directory with Sphinx sphinx: builder: html configuration: doc/source/conf.py # Optionally build your docs in additional formats such as PDF #formats: # - pdf # Optionally declare the Python requirements required to build your docs python: install: - requirements: requirements.txt - requirements: ci/requirements_rtd.txt - method: pip path: . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/CHANGELOG.rst0000664000000000000000000000004315215230701013601 0ustar00rootrootPlease see doc/sources/Changlog.rst././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/README.rst0000664000000000000000000001475315215230701013264 0ustar00rootrootFabIO: Fable Input/Output library ================================= Main websites: * https://github.com/silx-kit/fabio * http://fable.sf.net (historical) |Build Status| |Appveyor Status| ---- FabIO is an I/O library for images produced by 2D X-ray detectors and written in Python. FabIO supports detector images from a dozen companies (including Mar, Dectris, ADSC, Hamamatsu, Oxford, ...), for a total of 30 different file formats (like CBF, EDF, TIFF, ...) and offers a unified interface to their headers (as a Python dictionary) and datasets (as a numpy ndarray of integers or floats) .. contents:: :depth: 1 Installation ------------ FabIO is available from `PyPI `_: ``pip install fabio`` `Debian/Ubuntu packages `_, and `wheels `_ are available for Windows, Linux and MacOSX from the silx repository. See the `installation instructions `_ for more information. Usage ----- Open an image ............. >>> import fabio >>> obj = fabio.open("mydata0000.edf") >>> obj.data.shape (2048, 2048) >>> obj.header["Omega"] 23.5 >>> obj.data array([...]) Save an image (ex: EDF) ....................... >>> import fabio >>> obj = fabio.edfimage.EdfImage(data=[...]) >>> obj.write("mydata0000.edf") Documentation ------------- See the `latest release documentation `_ for further details. Documentation of previous versions is available on `silx `_. Changelog --------- See http://www.silx.org/doc/fabio/latest/Changelog.html Citation -------- The general philosophy of the library is described in: `FabIO: easy access to two-dimensional X-ray detector images in Python; E. B. Knudsen, H. O. Sørensen, J. P. Wright, G. Goret and J. Kieffer Journal of Applied Crystallography, Volume 46, Part 2, pages 537-539. `_ Transparent handling of compressed files ---------------------------------------- For FabIO to handle gzip and bzip2 compressed files transparently, ``bzip`` and ``gzip`` modules must be present when installing/building Python (e.g. ``libbz2-dev`` package for Ubuntu). Benchmarking details have been collected at http://www.silx.org/doc/fabio/latest/performances.html. Supported file formats ---------------------- * ADSC: + AdscImage * Bruker: + BrukerImage + Bruker100Image + KcdImage: Nonius KappaCCD diffractometer * D3M + D3mImage * Dectris: + CbfImage (implements a fast byte offset de/compression scheme in Python/Cython) + PilatusImage (file format derived from Tiff) + EigerImage (derived from HDF5/NeXus format, depends on `h5py`) * ESRF: + EdfImage: The ESRF data Format + XsdImage: XML serialized image from EDNA + Fit2dImage: Fit2d binary format + Fit2dmaskImage: Fit2d Mask format + Fit2dSpreadsheetImage: Fit2d ascii tables (spread-sheet) + LimaImage: image stacks written by the LImA acquisition system + SparseImage: single crystal diffractions images written by pyFAI * General Electric + GEimage (including support for variant used at APS) * Hamamatsu + HiPiCImage * HDF5: generic format for stack of images based on h5py + Hdf5Image + EigerImage + LimaImage + SparseImage * JPEG image format: + JPEG using PIL + JPEG 2000 using Glymur * Mar Research: + MarccdImage (file format derived from Tiff) + Mar345Image imaging plate with PCK compression * MPA multiwire + MpaImage * Medical Research Council file format for 3D electron density and 2D images + MrcImage * Nonius -> now owned by Bruker + KcdImage * Numpy: generic reader for 2D arrays saved + NumpyImage * Oxford Diffraction Sapphire 3 + OXDimage uncompressed or with TY1 or TY5 compression scheme + Esperanto format (with bitfield compression) * Pixirad Imaging + PixiImage * PNM + PnmImage * Princeton Instrument SPE + SpeImage * Raw Binary without compression * Rigaku + RaxisImage + DtrekImage * Tiff + TifImage using either: - Pillow (external dependency) - TiffIO taken from PyMca Design Specifications --------------------- Name: ..... FabIO = Fable Input/Output Idea: ..... Have a base class for all our 2D diffraction greyscale images. This consists of a 2D array (numpy ndarray) and a python dictionary (actually an ordered dict) of header information in (string key, string value) pairs. Class FabioImage ................ Needs a name which will not to be confused with an RGB color image. Class attributes, often exposed as properties: * data -> 2D array * header -> ordered dictionary * rows, columns, dim1, dim2 -> data.shape (property) * header_keys -> property for list(header.keys()), formerly used to retain the order of the header * bytecode -> data.typecode() (property) * m, minval, maxval, stddev -> image statistics, could add others, eg roi[slice] Class methods (functions): * integrate_area() -> return sum(self.data) within slice * rebin(fact) -> rebins data, adjusts dims * toPIL16() -> returns a PILimage * getheader() -> returns self.header * resetvals() -> resets the statistics * getmean() -> (computes) returns self.m * getmin() -> (computes) returns self.minval * getmax() -> (computes) returns self.maxval * getstddev() -> (computes) returns self.stddev * read() -> read image from file [or stream, or shared memory] * write() -> write image to file [or stream, or shared memory] * readheader() -> read only the header [much faster for scanning files] Each individual file format would then inherit all the functionality of this class and just make new read and write methods. There are also fileseries related methods (next(), previous(), ...) which returns a FabioImage instance of the next/previous frame in a file series Other features: * possibility for using on-the-fly external compression - i.e. if files are stored as something as .gz, .bz2 etc could decompress them, using an external compression mechanism (if available). .. |Build Status| image:: https://travis-ci.org/silx-kit/fabio.svg?branch=master :target: https://travis-ci.org/silx-kit/fabio .. |Appveyor Status| image:: https://ci.appveyor.com/api/projects/status/4k6lol1vq30qhf66/branch/master?svg=true :target: https://ci.appveyor.com/project/ESRF/fabio/branch/master ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1781871041.0 fabio-2026.6.0/bootstrap.py0000775000000000000000000002233115215230701014156 0ustar00rootroot#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Bootstrap helps you to test scripts without installing them by patching your PYTHONPATH on the fly example: ./bootstrap.py ipython """ __authors__ = ["Frédéric-Emmanuel Picca", "Jérôme Kieffer"] __contact__ = "jerome.kieffer@esrf.eu" __license__ = "MIT" __date__ = "12/03/2026" import sys import os import subprocess import argparse import logging if sys.version_info[:2] < (3, 11): import tomli else: import tomllib as tomli logging.basicConfig() logger = logging.getLogger("bootstrap") def get_project_name(root_dir): """Retrieve project name by running python setup.py --name in root_dir. :param str root_dir: Directory where to run the command. :return: The name of the project stored in root_dir """ logger.debug("Getting project name in %s", root_dir) with open("pyproject.toml") as f: pyproject = tomli.loads(f.read()) return pyproject.get("project", {}).get("name") def is_debug_python(): """Returns True if the Python interpreter is in debug mode.""" try: import sysconfig except ImportError: # pragma nocover # Python < 2.7 import distutils.sysconfig as sysconfig if sysconfig.get_config_var("Py_DEBUG"): return True return hasattr(sys, "gettotalrefcount") def build_project(name, root_dir): """Build locally the project using meson :param str name: Name of the project. :param str root_dir: Root directory of the project :return: The path to the directory were build was performed """ extra = [] libdir = "lib" if sys.platform == "win32": libdir = "Lib" extra = ["-Dbuildtype=plain"] build = os.path.join(root_dir, "build") if not(os.path.isdir(build) and os.path.isdir(os.path.join(build, name))): cmd = ["meson", "setup", "build"] + extra print(" ".join(cmd)) p = subprocess.Popen(cmd, shell=False, cwd=root_dir, env=os.environ) print(f"`meson setup` ended with rc= {p.wait()}") cmd = ["meson", "configure", "--prefix", "/"] + extra print(" ".join(cmd)) p = subprocess.Popen(cmd, shell=False, cwd=build, env=os.environ) print(f"`meson configure` ended with rc= {p.wait()}") cmd = ["meson", "install", "--destdir", "."] print(" ".join(cmd)) p = subprocess.Popen(cmd, shell=False, cwd=build, env=os.environ) print(f"`meson install` ended with rc= {p.wait()}") home = None if os.environ.get("PYBUILD_NAME") == name: # we are in the debian packaging way home = os.environ.get("PYTHONPATH", "").split(os.pathsep)[-1] if not home: if os.environ.get("BUILDPYTHONPATH"): home = os.path.abspath(os.environ.get("BUILDPYTHONPATH", "")) else: if sys.platform == "win32": home = os.path.join(build, libdir, "site-packages") else: python_version = f"python{sys.version_info.major}.{sys.version_info.minor}" home = os.path.join(build, libdir, python_version, "site-packages") home = os.path.abspath(home) cnt = 0 while not os.path.isdir(home): cnt += 1 home = os.path.split(home)[0] for _ in range(cnt): n = os.listdir(home)[0] home = os.path.join(home, n) logger.warning("Building %s to %s", name, home) return home def execfile(fullpath, globals=None, locals=None): "Python3 implementation for execfile" with open(fullpath) as f: try: data = f.read() except UnicodeDecodeError: raise SyntaxError("Not a Python script") code = compile(data, fullpath, 'exec') exec(code, globals, locals) def run_file(filename, argv): """ Execute a script trying first to use execfile, then a subprocess :param str filename: Script to execute :param list[str] argv: Arguments passed to the filename """ full_args = [filename] full_args.extend(argv) try: logger.info("Execute target using exec") # execfile is considered as a local call. # Providing globals() as locals will force to feed the file into # globals() (for examples imports). # Without this any function call from the executed file loses imports try: old_argv = sys.argv sys.argv = full_args logger.info("Patch the sys.argv: %s", sys.argv) logger.info("Executing %s.main()", filename) print("########### EXECFILE ###########") module_globals = globals().copy() module_globals['__file__'] = filename execfile(filename, module_globals, module_globals) finally: sys.argv = old_argv except SyntaxError as error: logger.error(error) logger.info("Execute target using subprocess") env = os.environ.copy() env.update({"PYTHONPATH": LIBPATH + os.pathsep + os.environ.get("PYTHONPATH", ""), "PATH": os.environ.get("PATH", "")}) print("########### SUBPROCESS ###########") run = subprocess.Popen(full_args, shell=False, env=env) run.wait() def run_entry_point(target_name, entry_point, argv): """ Execute an entry_point using the current python context :param str entry_point: A string identifying a function from a module (NAME = PACKAGE.MODULE:FUNCTION) :param argv: list of arguments """ import importlib elements = entry_point.split(":") module_name = elements[0].strip() function_name = elements[1].strip() logger.info("Execute target %s (function %s from module %s) using importlib", target_name, function_name, module_name) full_args = [target_name] full_args.extend(argv) try: old_argv = sys.argv sys.argv = full_args print("########### IMPORTLIB ###########") module = importlib.import_module(module_name) if hasattr(module, function_name): func = getattr(module, function_name) func() else: logger.info("Function %s not found", function_name) finally: sys.argv = old_argv def find_executable(target): """Find a filename from a script name. - Check the script name as file path, - Then checks if the name is a target of the setup.py - Then search the script from the PATH environment variable. :param str target: Name of the script :returns: Returns a tuple: (kind, name) or (kind, name, entry_point). """ if os.path.isfile(target): return ("path", os.path.abspath(target)) # search the executable in pyproject.toml with open(os.path.join(PROJECT_DIR, "pyproject.toml")) as f: pyproject = tomli.loads(f.read()) scripts = {} scripts.update(pyproject.get("project", {}).get("scripts", {})) scripts.update(pyproject.get("project", {}).get("gui-scripts", {})) for script, entry_point in scripts.items(): if script == target: print(script, entry_point) return ("entry_point", target, entry_point) return None, None def main(argv): parser = argparse.ArgumentParser( prog="bootstrap", usage="./bootstrap.py