diff --git a/python/python/async_tiff/_decoder.pyi b/python/python/async_tiff/_decoder.pyi index d69b27e..7f032e9 100644 --- a/python/python/async_tiff/_decoder.pyi +++ b/python/python/async_tiff/_decoder.pyi @@ -5,6 +5,7 @@ from .enums import CompressionMethod class Decoder(Protocol): """A custom Python-provided decompression algorithm.""" + # In the future, we could pass in photometric interpretation and jpeg tables as # well. @staticmethod @@ -13,6 +14,7 @@ class Decoder(Protocol): class DecoderRegistry: """A registry holding multiple decoder methods.""" + def __init__( self, custom_decoders: dict[CompressionMethod | int, Decoder] | None = None ) -> None: diff --git a/python/python/async_tiff/_ifd.pyi b/python/python/async_tiff/_ifd.pyi index 5bf173c..dc3f5f9 100644 --- a/python/python/async_tiff/_ifd.pyi +++ b/python/python/async_tiff/_ifd.pyi @@ -1,4 +1,5 @@ from .enums import ( + Endianness, CompressionMethod, PhotometricInterpretation, PlanarConfiguration, @@ -11,6 +12,8 @@ from ._geo import GeoKeyDirectory Value = int | float | str | tuple[int, int] | list[Value] class ImageFileDirectory: + @property + def endianness(self) -> Endianness: ... @property def new_subfile_type(self) -> int | None: ... @property @@ -30,6 +33,7 @@ class ImageFileDirectory: An `int` will be returned if the compression is not one of the values in `CompressionMethod`. """ + @property def photometric_interpretation(self) -> PhotometricInterpretation: ... @property diff --git a/python/python/async_tiff/_thread_pool.pyi b/python/python/async_tiff/_thread_pool.pyi index aa1165a..3f60446 100644 --- a/python/python/async_tiff/_thread_pool.pyi +++ b/python/python/async_tiff/_thread_pool.pyi @@ -1,4 +1,5 @@ class ThreadPool: """A Rust-managed thread pool.""" + def __init__(self, num_threads: int) -> None: """Construct a new ThreadPool with the given number of threads.""" diff --git a/python/python/async_tiff/_tiff.pyi b/python/python/async_tiff/_tiff.pyi index dcc0f67..e703642 100644 --- a/python/python/async_tiff/_tiff.pyi +++ b/python/python/async_tiff/_tiff.pyi @@ -28,6 +28,7 @@ class TIFF: Returns: A TIFF instance. """ + @property def ifds(self) -> list[ImageFileDirectory]: """Access the underlying IFDs of this TIFF. @@ -35,6 +36,7 @@ class TIFF: Each ImageFileDirectory (IFD) represents one of the internal "sub images" of this file. """ + async def fetch_tile(self, x: int, y: int, z: int) -> Tile: """Fetch a single tile. @@ -46,6 +48,7 @@ class TIFF: Returns: Tile response. """ + async def fetch_tiles(self, x: list[int], y: list[int], z: int) -> list[Tile]: """Fetch multiple tiles concurrently. diff --git a/python/python/async_tiff/_tile.pyi b/python/python/async_tiff/_tile.pyi index 6dc072a..2f47380 100644 --- a/python/python/async_tiff/_tile.pyi +++ b/python/python/async_tiff/_tile.pyi @@ -6,18 +6,23 @@ from ._thread_pool import ThreadPool class Tile: """A representation of a TIFF image tile.""" + @property def x(self) -> int: """The column index this tile represents.""" + @property def y(self) -> int: """The row index this tile represents.""" + @property def compressed_bytes(self) -> Buffer: """The compressed bytes underlying this tile.""" + @property def compression_method(self) -> CompressionMethod | int: """The compression method used by this tile.""" + async def decode_async( self, *, diff --git a/python/python/async_tiff/enums.py b/python/python/async_tiff/enums.py index 724b77b..0d17701 100644 --- a/python/python/async_tiff/enums.py +++ b/python/python/async_tiff/enums.py @@ -1,5 +1,24 @@ +import sys from enum import IntEnum +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + from enum import Enum + + class StrEnum(str, Enum): + def __str__(self): + return str(self.value) + + +class Endianness(StrEnum): + """ + endianness of the underlying tiff file + """ + + LittleEndian = "LittleEndian" + BigEndian = "BigEndian" + class CompressionMethod(IntEnum): """ diff --git a/python/src/enums.rs b/python/src/enums.rs index 14656bd..416d4c9 100644 --- a/python/src/enums.rs +++ b/python/src/enums.rs @@ -1,3 +1,4 @@ +use async_tiff::reader::Endianness; use async_tiff::tiff::tags::{ CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Predictor, ResolutionUnit, SampleFormat, @@ -6,6 +7,38 @@ use pyo3::prelude::*; use pyo3::types::{PyString, PyTuple}; use pyo3::{intern, IntoPyObjectExt}; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct PyEndianness(Endianness); + +impl From for PyEndianness { + fn from(value: Endianness) -> Self { + Self(value) + } +} + +impl From for Endianness { + fn from(value: PyEndianness) -> Self { + value.0 + } +} + +impl<'py> IntoPyObject<'py> for PyEndianness { + type Target = PyAny; + type Output = Bound<'py, PyAny>; + type Error = PyErr; + + fn into_pyobject(self, py: Python<'py>) -> Result { + // import the python module + let enums_mod = py.import(intern!(py, "async_tiff.enums"))?; + // get our python enum + let enum_cls = enums_mod.getattr(intern!(py, "Endianness"))?; + match self.0 { + Endianness::LittleEndian => enum_cls.getattr(intern!(py, "LittleEndian")), + Endianness::BigEndian => enum_cls.getattr(intern!(py, "BigEndian")), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct PyCompressionMethod(CompressionMethod); diff --git a/python/src/ifd.rs b/python/src/ifd.rs index c8c59c6..dcbccde 100644 --- a/python/src/ifd.rs +++ b/python/src/ifd.rs @@ -4,8 +4,8 @@ use async_tiff::ImageFileDirectory; use pyo3::prelude::*; use crate::enums::{ - PyCompressionMethod, PyPhotometricInterpretation, PyPlanarConfiguration, PyPredictor, - PyResolutionUnit, PySampleFormat, + PyCompressionMethod, PyEndianness, PyPhotometricInterpretation, PyPlanarConfiguration, + PyPredictor, PyResolutionUnit, PySampleFormat, }; use crate::geo::PyGeoKeyDirectory; use crate::value::PyValue; @@ -15,6 +15,11 @@ pub(crate) struct PyImageFileDirectory(ImageFileDirectory); #[pymethods] impl PyImageFileDirectory { + #[getter] + pub fn endianness(&self) -> PyEndianness { + self.0.endianness().into() + } + #[getter] pub fn new_subfile_type(&self) -> Option { self.0.new_subfile_type() diff --git a/src/ifd.rs b/src/ifd.rs index f0da9c1..0dfc6e1 100644 --- a/src/ifd.rs +++ b/src/ifd.rs @@ -402,6 +402,11 @@ impl ImageFileDirectory { }) } + /// The Endianness of the file + pub fn endianness(&self) -> Endianness { + self.endianness + } + /// A general indication of the kind of data contained in this subfile. /// pub fn new_subfile_type(&self) -> Option { diff --git a/src/reader.rs b/src/reader.rs index 06520ec..94090e0 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -228,7 +228,7 @@ impl AsyncFileReader for ReqwestReader { } /// Endianness -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Endianness { /// Little Endian LittleEndian,