diff --git a/src/ome_arrow/ingest.py b/src/ome_arrow/ingest.py index 070d2d7..91a8083 100644 --- a/src/ome_arrow/ingest.py +++ b/src/ome_arrow/ingest.py @@ -1213,6 +1213,9 @@ def from_tiff( channel_names: Optional[Sequence[str]] = None, acquisition_datetime: Optional[datetime] = None, clamp_to_uint16: bool = True, + chunk_encoding: Literal["list", "bytes"] = "list", + chunk_compression: str | None = None, + chunk_compression_level: int | None = None, ) -> pa.StructScalar: """ Read a TIFF and return a typed OME-Arrow StructScalar. @@ -1228,6 +1231,11 @@ def from_tiff( channel_names: Optional channel names; defaults to C0..C{n-1}. acquisition_datetime: Optional acquisition time (UTC now if None). clamp_to_uint16: If True, clamp/cast planes to uint16. + chunk_encoding: ``"list"`` stores historical numeric pixel lists. + ``"bytes"`` stores compact typed chunk byte buffers. + chunk_compression: Optional leaf-level compression for byte chunks, + such as ``"zstd"`` or ``"lz4"``. + chunk_compression_level: Optional codec compression level. Returns: pa.StructScalar validated against `struct`. @@ -1307,6 +1315,9 @@ def from_tiff( physical_size_unit=psize_unit, channels=channels, planes=planes, + chunk_encoding=chunk_encoding, + chunk_compression=chunk_compression, + chunk_compression_level=chunk_compression_level, masks=None, ) @@ -1631,6 +1642,9 @@ def from_ome_zarr( channel_names: Optional[Sequence[str]] = None, acquisition_datetime: Optional[datetime] = None, clamp_to_uint16: bool = True, + chunk_encoding: Literal["list", "bytes"] = "list", + chunk_compression: str | None = None, + chunk_compression_level: int | None = None, ) -> pa.StructScalar: """ Read an OME-Zarr directory and return a typed OME-Arrow StructScalar. @@ -1654,6 +1668,14 @@ def from_ome_zarr( Optional datetime (defaults to UTC now). clamp_to_uint16: If True, cast pixels to uint16. + chunk_encoding: + ``"list"`` stores historical numeric pixel lists. ``"bytes"`` + stores compact typed chunk byte buffers. + chunk_compression: + Optional leaf-level compression for byte chunks, such as + ``"zstd"`` or ``"lz4"``. + chunk_compression_level: + Optional codec compression level. Returns: pa.StructScalar: Validated OME-Arrow struct for this image. @@ -1742,6 +1764,9 @@ def from_ome_zarr( physical_size_unit=psize_unit, channels=channels, planes=planes, + chunk_encoding=chunk_encoding, + chunk_compression=chunk_compression, + chunk_compression_level=chunk_compression_level, masks=None, ) diff --git a/tests/test_ingest.py b/tests/test_ingest.py new file mode 100644 index 0000000..e0a5019 --- /dev/null +++ b/tests/test_ingest.py @@ -0,0 +1,64 @@ +"""Tests for image-file ingestion helpers.""" + +from pathlib import Path +from types import SimpleNamespace +from typing import Callable + +import numpy as np +import pytest + +import ome_arrow.ingest as ingest_mod +from ome_arrow import OME_ARROW_BYTE_STRUCT +from ome_arrow.export import to_numpy + + +@pytest.mark.parametrize( + ("converter", "path"), + [ + (ingest_mod.from_tiff, Path("image.tiff")), + (ingest_mod.from_ome_zarr, Path("image.ome.zarr")), + ], +) +def test_file_ingest_forwards_byte_chunk_options( + monkeypatch: pytest.MonkeyPatch, + converter: Callable[..., object], + path: Path, +) -> None: + """Encode and compress chunks requested through file ingest helpers.""" + arr = np.zeros((1, 1, 1, 32, 32), dtype=np.uint16) + image = SimpleNamespace( + data=arr, + dims=SimpleNamespace(T=1, C=1, Z=1, Y=32, X=32), + physical_pixel_sizes=SimpleNamespace(X=1.0, Y=1.0, Z=1.0, unit="µm"), + channel_names=["C0"], + ) + monkeypatch.setattr(ingest_mod, "BioImage", lambda **_kwargs: image) + + scalar = converter( + path, + chunk_encoding="bytes", + chunk_compression="zstd", + chunk_compression_level=1, + ) + + assert scalar.type == OME_ARROW_BYTE_STRUCT + assert scalar.as_py()["chunks"][0]["compression"] == "zstd" + np.testing.assert_array_equal(to_numpy(scalar), arr) + + +def test_file_ingest_keeps_list_chunks_by_default( + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Preserve the historical list encoding for existing callers.""" + arr = np.arange(12, dtype=np.uint16).reshape(1, 1, 1, 3, 4) + image = SimpleNamespace( + data=arr, + dims=SimpleNamespace(T=1, C=1, Z=1, Y=3, X=4), + physical_pixel_sizes=SimpleNamespace(X=1.0, Y=1.0, Z=1.0, unit="µm"), + ) + monkeypatch.setattr(ingest_mod, "BioImage", lambda **_kwargs: image) + + scalar = ingest_mod.from_tiff("image.tiff") + + assert "pixels" in scalar.as_py()["chunks"][0] + np.testing.assert_array_equal(to_numpy(scalar), arr)