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
13 changes: 10 additions & 3 deletions src/cpp/interface/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,21 @@ PYBIND11_MODULE(libbfiocpp, m) {

py::enum_<bfiocpp::FileType>(m, "FileType")
.value("OmeTiff", bfiocpp::FileType::OmeTiff)
.value("OmeZarr", bfiocpp::FileType::OmeZarr)
.value("OmeZarrV2", bfiocpp::FileType::OmeZarrV2)
.value("OmeZarrV3", bfiocpp::FileType::OmeZarrV3)
.export_values();

m.def("get_ome_xml", &bfiocpp::GetOmeXml);


// Writer class
py::class_<bfiocpp::TsWriterCPP, std::shared_ptr<bfiocpp::TsWriterCPP>>(m, "TsWriterCPP")
.def(py::init<const std::string&, const std::vector<std::int64_t>&, const std::vector<std::int64_t>&, const std::string&, const std::string&>())
py::class_<bfiocpp::TsWriterCPP, std::shared_ptr<bfiocpp::TsWriterCPP>>(m, "TsWriterCPP")
.def(py::init<const std::string&, const std::vector<std::int64_t>&, const std::vector<std::int64_t>&, const std::string&, const std::string&, bfiocpp::FileType>(),
py::arg("filename"),
py::arg("image_shape"),
py::arg("chunk_shape"),
py::arg("dtype"),
py::arg("dimension_order"),
py::arg("file_type") = bfiocpp::FileType::OmeZarrV2)
.def("write_image_data", &bfiocpp::TsWriterCPP::WriteImageData);
}
2 changes: 1 addition & 1 deletion src/cpp/reader/tsreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ TsReaderCPP::TsReaderCPP(const std::string& fname, FileType ft, const std::strin
if (ft == FileType::OmeTiff){
return GetOmeTiffSpecToRead(fname);
} else {
return GetZarrSpecToRead(fname);
return GetZarrSpecToRead(fname, ft);
}
}();

Expand Down
7 changes: 1 addition & 6 deletions src/cpp/reader/tsreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
#include <memory>
#include <vector>
#include <variant>
#include <iostream>
#include <tuple>
#include <optional>
#include <unordered_map>
#include "tensorstore/tensorstore.h"
#include "../utilities/sequence.h"
#include "../utilities/utilities.h"
using image_data = std::variant<std::vector<std::uint8_t>,
std::vector<std::uint16_t>,
std::vector<std::uint32_t>,
Expand All @@ -26,9 +24,6 @@ using iter_indicies = std::tuple<std::int64_t,std::int64_t,std::int64_t,std::int

namespace bfiocpp{


enum class FileType {OmeTiff, OmeZarr};

class TsReaderCPP{
public:
TsReaderCPP(const std::string& fname, FileType ft, const std::string& axes_list );
Expand Down
92 changes: 68 additions & 24 deletions src/cpp/utilities/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ tensorstore::Spec GetOmeTiffSpecToRead(const std::string& filename){
}).value();
}

tensorstore::Spec GetZarrSpecToRead(const std::string& filename){
return tensorstore::Spec::FromJson({{"driver", "zarr"},
tensorstore::Spec GetZarrSpecToRead(const std::string& filename, FileType ft){
std::string driver = (ft == FileType::OmeZarrV3) ? "zarr3" : "zarr";
return tensorstore::Spec::FromJson({{"driver", driver},
{"kvstore", {{"driver", "file"},
{"path", filename}}
}
Expand Down Expand Up @@ -152,28 +153,71 @@ std::string GetOmeXml(const std::string& file_path){
return OmeXmlInfo;
}

tensorstore::Spec GetZarrSpecToWrite( const std::string& filename,
const std::vector<std::int64_t>& image_shape,
const std::vector<std::int64_t>& chunk_shape,
const std::string& dtype){
std::string GetZarrV3DataType(uint16_t data_type_code) {
// Zarr v3 uses plain dtype names instead of encoded format like "<u2"
switch (data_type_code) {
case 1: return "uint8";
case 2: return "uint16";
case 4: return "uint32";
case 8: return "uint64";
case 16: return "int8";
case 32: return "int16";
case 64: return "int32";
case 128: return "int64";
case 256: return "float32";
case 512: return "float64";
default: return "uint16";
}
}

// valid values for dtype are subset of
// https://google.github.io/tensorstore/spec.html#json-dtype
return tensorstore::Spec::FromJson({{"driver", "zarr"},
{"kvstore", {{"driver", "file"},
{"path", filename}}
},
{"context", {
{"cache_pool", {{"total_bytes_limit", 1000000000}}},
{"data_copy_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
{"file_io_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
}},
{"metadata", {
{"zarr_format", 2},
{"shape", image_shape},
{"chunks", chunk_shape},
{"dtype", dtype},
},
}}).value();
tensorstore::Spec GetZarrSpecToWrite( const std::string& filename,
const std::vector<std::int64_t>& image_shape,
const std::vector<std::int64_t>& chunk_shape,
const std::string& dtype,
FileType ft){

if (ft == FileType::OmeZarrV3) {
// Zarr v3 spec
return tensorstore::Spec::FromJson({{"driver", "zarr3"},
{"kvstore", {{"driver", "file"},
{"path", filename}}
},
{"context", {
{"cache_pool", {{"total_bytes_limit", 1000000000}}},
{"data_copy_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
{"file_io_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
}},
{"metadata", {
{"shape", image_shape},
{"chunk_grid", {
{"name", "regular"},
{"configuration", {{"chunk_shape", chunk_shape}}}
}},
{"chunk_key_encoding", {{"name", "default"}}},
{"data_type", dtype},
{"codecs", {{{"name", "bytes"}, {"configuration", {{"endian", "little"}}}}}}
},
}}).value();
} else {
// Zarr v2 spec (existing)
// valid values for dtype are subset of
// https://google.github.io/tensorstore/spec.html#json-dtype
return tensorstore::Spec::FromJson({{"driver", "zarr"},
{"kvstore", {{"driver", "file"},
{"path", filename}}
},
{"context", {
{"cache_pool", {{"total_bytes_limit", 1000000000}}},
{"data_copy_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
{"file_io_concurrency", {{"limit", std::thread::hardware_concurrency()}}},
}},
{"metadata", {
{"zarr_format", 2},
{"shape", image_shape},
{"chunks", chunk_shape},
{"dtype", dtype},
},
}}).value();
}
}
} // ns bfiocpp
12 changes: 8 additions & 4 deletions src/cpp/utilities/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@

namespace bfiocpp {

enum class FileType {OmeTiff, OmeZarrV2, OmeZarrV3};

tensorstore::Spec GetOmeTiffSpecToRead(const std::string& filename);
tensorstore::Spec GetZarrSpecToRead(const std::string& filename);
tensorstore::Spec GetZarrSpecToRead(const std::string& filename, FileType ft);

uint16_t GetDataTypeCode (std::string_view type_name);
std::string GetEncodedType(uint16_t data_type_code);
std::string GetUTCString();
std::string GetOmeXml(const std::string& file_path);
std::tuple<std::optional<int>, std::optional<int>, std::optional<int>>ParseMultiscaleMetadata(const std::string& axes_list, int len);
tensorstore::Spec GetZarrSpecToWrite(const std::string& filename,
const std::vector<std::int64_t>& image_shape,
tensorstore::Spec GetZarrSpecToWrite(const std::string& filename,
const std::vector<std::int64_t>& image_shape,
const std::vector<std::int64_t>& chunk_shape,
const std::string& dtype);
const std::string& dtype,
FileType ft);
std::string GetZarrV3DataType(uint16_t data_type_code);
} // ns bfiocpp
11 changes: 8 additions & 3 deletions src/cpp/writer/tswriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@ TsWriterCPP::TsWriterCPP(
const std::vector<std::int64_t>& image_shape,
const std::vector<std::int64_t>& chunk_shape,
const std::string& dtype_str,
const std::string& dimension_order
const std::string& dimension_order,
FileType file_type
): _filename(fname),
_image_shape(image_shape),
_chunk_shape(chunk_shape),
_dtype_code(GetDataTypeCode(dtype_str)) {


// Use appropriate dtype encoding based on file type
std::string encoded_dtype = (file_type == FileType::OmeZarrV3)
? GetZarrV3DataType(_dtype_code)
: GetEncodedType(_dtype_code);

TENSORSTORE_CHECK_OK_AND_ASSIGN(_source, tensorstore::Open(
GetZarrSpecToWrite(_filename, _image_shape, _chunk_shape, GetEncodedType(_dtype_code)),
GetZarrSpecToWrite(_filename, _image_shape, _chunk_shape, encoded_dtype, file_type),
tensorstore::OpenMode::create |
tensorstore::OpenMode::delete_existing,
tensorstore::ReadWriteMode::write).result()
Expand Down
9 changes: 6 additions & 3 deletions src/cpp/writer/tswriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

#include <string>
#include <vector>
#include <optional>
#include "tensorstore/tensorstore.h"
#include "../utilities/sequence.h"
#include "../utilities/utilities.h"
#include <pybind11/numpy.h>

namespace py = pybind11;
Expand All @@ -13,11 +15,12 @@ namespace bfiocpp{
class TsWriterCPP{
public:
TsWriterCPP (
const std::string& fname,
const std::vector<std::int64_t>& image_shape,
const std::string& fname,
const std::vector<std::int64_t>& image_shape,
const std::vector<std::int64_t>& chunk_shape,
const std::string& dtype_str,
const std::string& dimension_order
const std::string& dimension_order,
FileType file_type = FileType::OmeZarrV2
);

void WriteImageData (
Expand Down
10 changes: 8 additions & 2 deletions src/python/bfiocpp/tswriter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
from typing import Optional
from .libbfiocpp import TsWriterCPP, Seq
from .libbfiocpp import TsWriterCPP, Seq, FileType


class TSWriter:
Expand All @@ -12,14 +12,20 @@ def __init__(
chunk_shape: list,
dtype: np.dtype,
dimension_order: str,
file_type: FileType = FileType.OmeZarrV2,
):
"""Initialize tensorstore Zarr writer

file_name: Path to write file to
image_shape: Shape of the image [T, C, Z, Y, X]
chunk_shape: Shape of chunks [T, C, Z, Y, X]
dtype: Data type of the image
dimension_order: Order of dimensions (e.g., "TCZYX")
file_type: FileType.OmeZarrV2 (default) or FileType.OmeZarrV3
"""

self._image_writer: TsWriterCPP = TsWriterCPP(
file_name, image_shape, chunk_shape, str(dtype), dimension_order
file_name, image_shape, chunk_shape, str(dtype), dimension_order, file_type
)

def write_image_data(
Expand Down
4 changes: 2 additions & 2 deletions tests/test_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def test_read_zarr_2d_slice(self):
"""test_read_zarr_2d_slice - Read tiff using TSReader"""
br = TSReader(
str(TEST_DIR.joinpath("5025551.zarr/0")),
FileType.OmeZarr,
FileType.OmeZarrV2,
"",
)
assert br._X == 2702
Expand All @@ -235,7 +235,7 @@ def test_read_zarr_4d_slice(self):
"""test_read_zarr_4d_slice - Read tiff using TSReader"""
br = TSReader(
str(TEST_DIR.joinpath("5025551.zarr/0")),
FileType.OmeZarr,
FileType.OmeZarrV2,
"",
)

Expand Down
Loading
Loading