Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions python/python/async_tiff/_tiff.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from typing import Protocol
from ._tile import Tile
from ._ifd import ImageFileDirectory
from .store import ObjectStore

# Fix exports
from obspec._get import GetRangeAsync, GetRangesAsync

from ._ifd import ImageFileDirectory
from ._tile import Tile
from .enums import Endianness
from .store import ObjectStore

class ObspecInput(GetRangeAsync, GetRangesAsync, Protocol):
"""Supported obspec input to reader."""

Expand Down Expand Up @@ -33,6 +35,10 @@ class TIFF:
Returns:
A TIFF instance.
"""

@property
def endianness(self) -> Endianness:
"""The endianness of this TIFF file."""
@property
def ifds(self) -> list[ImageFileDirectory]:
"""Access the underlying IFDs of this TIFF.
Expand Down
5 changes: 5 additions & 0 deletions python/python/async_tiff/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class CompressionMethod(IntEnum):
PackBits = 0x8005


class Endianness(IntEnum):
LittleEndian = 0
BigEndian = 1


class PhotometricInterpretation(IntEnum):
WhiteIsZero = 0
BlackIsZero = 1
Expand Down
26 changes: 26 additions & 0 deletions python/src/enums.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use async_tiff::reader::Endianness;
use async_tiff::tiff::tags::{
CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Predictor, ResolutionUnit,
SampleFormat,
Expand Down Expand Up @@ -39,6 +40,30 @@ impl<'py> IntoPyObject<'py> for PyCompressionMethod {
}
}

pub(crate) struct PyEndianness(Endianness);

impl From<Endianness> for PyEndianness {
fn from(value: Endianness) -> Self {
Self(value)
}
}

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<Self::Output, Self::Error> {
let enums_mod = py.import(intern!(py, "async_tiff.enums"))?;
let endianness_enum = enums_mod.getattr(intern!(py, "Endianness"))?;

match self.0 {
Endianness::LittleEndian => endianness_enum.getattr("LittleEndian"),
Endianness::BigEndian => endianness_enum.getattr("BigEndian"),
}
}
}

pub(crate) struct PyPhotometricInterpretation(PhotometricInterpretation);

impl From<PhotometricInterpretation> for PyPhotometricInterpretation {
Expand Down Expand Up @@ -132,6 +157,7 @@ impl<'py> IntoPyObject<'py> for PySampleFormat {
to_py_enum_variant(py, intern!(py, "SampleFormat"), self.0.to_u16())
}
}

fn to_py_enum_variant<'py>(
py: Python<'py>,
enum_name: &Bound<'py, PyString>,
Expand Down
9 changes: 7 additions & 2 deletions python/src/tiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use pyo3::prelude::*;
use pyo3::types::PyType;
use pyo3_async_runtimes::tokio::future_into_py;

use crate::enums::PyEndianness;
use crate::error::PyAsyncTiffResult;
use crate::reader::StoreInput;
use crate::tile::PyTile;
Expand All @@ -29,8 +30,7 @@ async fn open(
.with_initial_size(prefetch)
.with_multiplier(multiplier);
let mut metadata_reader = TiffMetadataReader::try_open(&metadata_fetch).await?;
let ifds = metadata_reader.read_all_ifds(&metadata_fetch).await?;
let tiff = TIFF::new(ifds);
let tiff = metadata_reader.read(&metadata_fetch).await?;
Ok(PyTIFF { tiff, reader })
}

Expand All @@ -56,6 +56,11 @@ impl PyTIFF {
Ok(cog_reader)
}

#[getter]
fn endianness(&self) -> PyEndianness {
self.tiff.endianness().into()
}

#[getter]
fn ifds(&self) -> Vec<PyImageFileDirectory> {
let ifds = self.tiff.ifds();
Expand Down
2 changes: 2 additions & 0 deletions python/tests/test_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ async def test_cog_s3():
store = S3Store("sentinel-cogs", region="us-west-2", skip_signature=True)
tiff = await TIFF.open(path=path, store=store)

assert tiff.endianness == enums.Endianness.LittleEndian

ifds = tiff.ifds
assert len(ifds) == 5

Expand Down
13 changes: 10 additions & 3 deletions src/cog.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
use crate::ifd::ImageFileDirectory;
use crate::reader::Endianness;

/// A TIFF file.
#[derive(Debug, Clone)]
pub struct TIFF {
endianness: Endianness,
ifds: Vec<ImageFileDirectory>,
}

impl TIFF {
/// Create a new TIFF from existing IFDs.
pub fn new(ifds: Vec<ImageFileDirectory>) -> Self {
Self { ifds }
pub fn new(ifds: Vec<ImageFileDirectory>, endianness: Endianness) -> Self {
Self { ifds, endianness }
}

/// Access the underlying Image File Directories.
pub fn ifds(&self) -> &[ImageFileDirectory] {
&self.ifds
}

/// Get the endianness of the TIFF file.
pub fn endianness(&self) -> Endianness {
self.endianness
}
}

#[cfg(test)]
Expand All @@ -41,7 +48,7 @@ mod test {
let cached_reader = ReadaheadMetadataCache::new(reader.clone());
let mut metadata_reader = TiffMetadataReader::try_open(&cached_reader).await.unwrap();
let ifds = metadata_reader.read_all_ifds(&cached_reader).await.unwrap();
let tiff = TIFF::new(ifds);
let tiff = TIFF::new(ifds, metadata_reader.endianness());

let ifd = &tiff.ifds[1];
let tile = ifd.fetch_tile(0, 0, reader.as_ref()).await.unwrap();
Expand Down
8 changes: 7 additions & 1 deletion src/metadata/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::metadata::MetadataFetch;
use crate::reader::Endianness;
use crate::tiff::tags::{Tag, Type};
use crate::tiff::{TiffError, TiffFormatError, Value};
use crate::ImageFileDirectory;
use crate::{ImageFileDirectory, TIFF};

/// Entry point to reading TIFF metadata.
///
Expand Down Expand Up @@ -135,6 +135,12 @@ impl TiffMetadataReader {
}
Ok(ifds)
}

/// Read all IFDs from the file and return a complete TIFF structure.
pub async fn read<F: MetadataFetch>(&mut self, fetch: &F) -> AsyncTiffResult<TIFF> {
let ifds = self.read_all_ifds(fetch).await?;
Ok(TIFF::new(ifds, self.endianness))
}
}

/// Reads the [`ImageFileDirectory`] metadata.
Expand Down
3 changes: 1 addition & 2 deletions tests/image_tiff/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ pub(crate) async fn open_tiff(filename: &str) -> TIFF {
let reader = Arc::new(ObjectReader::new(store.clone(), path.as_str().into()))
as Arc<dyn AsyncFileReader>;
let mut metadata_reader = TiffMetadataReader::try_open(&reader).await.unwrap();
let ifds = metadata_reader.read_all_ifds(&reader).await.unwrap();
TIFF::new(ifds)
metadata_reader.read(&reader).await.unwrap()
}
3 changes: 1 addition & 2 deletions tests/ome_tiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ async fn open_remote_tiff(url: &str) -> TIFF {
let reader = Arc::new(ObjectReader::new(Arc::new(store), path)) as Arc<dyn AsyncFileReader>;
let cached_reader = ReadaheadMetadataCache::new(reader.clone());
let mut metadata_reader = TiffMetadataReader::try_open(&cached_reader).await.unwrap();
let ifds = metadata_reader.read_all_ifds(&cached_reader).await.unwrap();
TIFF::new(ifds)
metadata_reader.read(&cached_reader).await.unwrap()
}

#[tokio::test]
Expand Down