Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e994e70
Initial read implementation. Single failed test for offsets outside o…
hsidky Apr 12, 2025
11b46e3
Tiff dir cache.
hsidky Apr 12, 2025
6481868
Added TIFF details.
hsidky Apr 12, 2025
a95d554
Added image directory parsing.
hsidky Apr 12, 2025
46b7eec
Added parsing into tiff dir cache.
hsidky Apr 12, 2025
648aece
Eager loading of external arrays.
hsidky Apr 13, 2025
e0c7d06
Updated tiff KVstore to use new cache.
hsidky Apr 14, 2025
9050dd7
Moved byte range request to its proper location.
hsidky Apr 14, 2025
5737b6e
Multi IFD parsing in tiff cache checkpoint. Tests failing.
hsidky Apr 16, 2025
ca4a562
Fixed bugs. Multi-IFD cache working.
hsidky Apr 16, 2025
90d962d
Added test for multi-ifd + external arrays.
hsidky Apr 16, 2025
a5d1144
Tiff KVStore testing
hsidky Apr 16, 2025
63190d7
Added more tags + more external arrays + tests.
hsidky Apr 16, 2025
4da1f4a
Code formatting update.
hsidky Apr 16, 2025
919cade
Cleaned up tests + consolidated tiff builder
hsidky Apr 17, 2025
8947819
General cleanup
hsidky Apr 17, 2025
43b1fd7
Added index.rst and schema.yml
hsidky Apr 17, 2025
9d6bcee
moved raw data to buffer + sorted EstimateHeapUsage
hsidky Apr 17, 2025
1970a86
tiff driver metadata initial buildout.
hsidky Apr 19, 2025
0c5f078
Tiff metadata schema validation + fixes + tests
hsidky Apr 19, 2025
1fab2b8
Refactor of resolvemetadata + new tests
hsidky Apr 20, 2025
c5b477c
Missed formatting on metadata.
hsidky Apr 20, 2025
c010a31
Initial TIFF Compressor
hsidky Apr 20, 2025
1aff8ac
TIFF CodecSpec and tests.
hsidky Apr 20, 2025
ad16397
Implemented tiff decodechunk + tests.
hsidky Apr 20, 2025
836f3e9
Added GetParseResult to tiff kvstore.
hsidky Apr 21, 2025
c3d977e
Metadata fixes + enhancements.
hsidky Apr 21, 2025
ad93dc7
Added supported data types to metadata.
hsidky Apr 26, 2025
c7c5530
Added missed garbage collection to tiff dir cache
hsidky Apr 26, 2025
66f0f5c
tiff driver buildout checkpoint. lots to do still.
hsidky Apr 26, 2025
7c7c700
Add GetTiffGridMappingInfo to tiff metadata files.
hsidky Apr 26, 2025
bb0b713
Clean build. Testing begins.
hsidky Apr 27, 2025
059d180
Initial tests + associated fixes. Still failing.
hsidky Apr 27, 2025
dd6e8b3
More testing. More fixing. Fixed inner order issue too.
hsidky Apr 27, 2025
5e428a8
More fixes. All basic testing passes.
hsidky Apr 27, 2025
34ca3de
Cleanup.
hsidky Apr 27, 2025
f2589d1
Updated tiff details to chunks.
hsidky May 1, 2025
2d666b2
Fully linearized tiff kvstore.
hsidky May 1, 2025
1c74faf
mid tiff metadata refactor checkpoint
hsidky May 1, 2025
701c974
Finished metadata refactor. Cleanup necessary. Tests pass.
hsidky May 2, 2025
58769df
Finished first pass refactor of driver + supporting metadata changes.…
hsidky May 3, 2025
efe26dc
fixed decode chunk logic. old tests passing.
hsidky May 3, 2025
066cd48
sneaky bug fix
hsidky May 4, 2025
42d528c
golden file tests + bug fixes.
hsidky May 4, 2025
316f6ab
code clean up + fixed label tests.
hsidky May 4, 2025
55e55c0
GetChunkStorageKey optimization.
hsidky May 4, 2025
4d7856f
Comment + code cleanup.
hsidky May 4, 2025
5292db1
Fixed dangling reference in stacking info order.
hsidky May 4, 2025
a603025
Added proper compression + refactor + bug fixes
hsidky May 4, 2025
9544989
added zlib compressor
hsidky May 5, 2025
d4f808c
fixed tiff driver schema validation + metadata comrpessor test.
hsidky May 5, 2025
5150abe
updated golden file test files path.
hsidky May 5, 2025
61087ad
Added schema and index rst + updated build files.
hsidky May 5, 2025
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
1 change: 1 addition & 0 deletions tensorstore/driver/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ DRIVERS = [
"virtual_chunked",
"zarr",
"zarr3",
"tiff",
]

DOCTEST_SOURCES = glob([
Expand Down
1 change: 1 addition & 0 deletions tensorstore/driver/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Chunked storage drivers
zarr3/index
n5/index
neuroglancer_precomputed/index
tiff/index

.. json:schema:: KeyValueStoreBackedChunkDriver

Expand Down
219 changes: 219 additions & 0 deletions tensorstore/driver/tiff/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
load("//bazel:tensorstore.bzl", "tensorstore_cc_library", "tensorstore_cc_test")
load("//docs:doctest.bzl", "doctest_test")

package(default_visibility = ["//visibility:public"])

licenses(["notice"])

DOCTEST_SOURCES = glob([
"**/*.rst",
"**/*.yml",
])

doctest_test(
name = "doctest_test",
srcs = DOCTEST_SOURCES,
)

filegroup(
name = "doc_sources",
srcs = DOCTEST_SOURCES,
)

tensorstore_cc_library(
name = "tiff",
deps = [
":driver",
":zlib_compressor",
":zstd_compressor",
],
)

tensorstore_cc_library(
name = "driver",
srcs = ["driver.cc"],
deps = [
":metadata",
"//tensorstore:array",
"//tensorstore:chunk_layout",
"//tensorstore:index",
"//tensorstore/driver",
"//tensorstore/driver:chunk_cache_driver",
"//tensorstore/driver:kvs_backed_chunk_driver",
"//tensorstore/internal/cache:async_cache",
"//tensorstore/internal/cache:kvs_backed_chunk_cache",
"//tensorstore/internal/json_binding:staleness_bound",
"//tensorstore/kvstore",
"//tensorstore/kvstore:generation",
"//tensorstore/kvstore/tiff:tiff_key_value_store",
"//tensorstore/util:result",
"//tensorstore/util:status",
"//tensorstore/util:str_cat",
"//tensorstore/util/execution",
"//tensorstore/util/execution:any_receiver",
"//tensorstore/util/garbage_collection",
"@com_github_nlohmann_json//:json",
"@com_google_absl//absl/log:absl_log",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:cord",
],
alwayslink = 1,
)

tensorstore_cc_library(
name = "metadata",
srcs = ["metadata.cc"],
hdrs = ["metadata.h"],
deps = [
":compressor",
":zlib_compressor",
":zstd_compressor",
"//tensorstore:chunk_layout",
"//tensorstore:codec_spec",
"//tensorstore:data_type",
"//tensorstore:index",
"//tensorstore:schema",
"//tensorstore/index_space:dimension_units",
"//tensorstore/internal/log:verbose_flag",
"//tensorstore/internal/riegeli:array_endian_codec",
"//tensorstore/kvstore/tiff:tiff_details",
"//tensorstore/kvstore/tiff:tiff_dir_cache",
"//tensorstore/util/garbage_collection",
"@com_github_nlohmann_json//:json",
"@com_google_absl//absl/log:absl_log",
"@com_google_riegeli//riegeli/bytes:cord_reader",
],
alwayslink = 1,
)

tensorstore_cc_test(
name = "metadata_test",
size = "small",
srcs = ["metadata_test.cc"],
deps = [
":compressor",
":metadata",
"//tensorstore:array",
"//tensorstore:codec_spec",
"//tensorstore:data_type",
"//tensorstore:index",
"//tensorstore/internal:json_gtest",
"//tensorstore/internal/json_binding:gtest",
"//tensorstore/internal/riegeli:array_endian_codec",
"//tensorstore/kvstore/tiff:tiff_details",
"//tensorstore/kvstore/tiff:tiff_dir_cache",
"//tensorstore/util:status_testutil",
"@com_github_nlohmann_json//:json",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:cord",
"@com_google_googletest//:gtest_main",
"@com_google_riegeli//riegeli/bytes:cord_reader",
"@com_google_riegeli//riegeli/bytes:cord_writer",
],
)

tensorstore_cc_library(
name = "compressor",
srcs = ["compressor.cc"],
hdrs = [
"compressor.h",
"compressor_registry.h",
],
deps = [
"//tensorstore/internal:json_registry",
"//tensorstore/internal/compression:json_specified_compressor",
"//tensorstore/kvstore/tiff:tiff_details",
"@com_google_absl//absl/container:flat_hash_map",
],
)

tensorstore_cc_test(
name = "driver_test",
size = "small",
srcs = ["driver_test.cc"],
deps = [
":driver",
":metadata",
"//tensorstore:array",
"//tensorstore:codec_spec",
"//tensorstore:data_type",
"//tensorstore:index",
"//tensorstore/driver:driver_testutil",
"//tensorstore/internal:global_initializer",
"//tensorstore/internal:json_gtest",
"//tensorstore/internal/json_binding:gtest",
"//tensorstore/internal/riegeli:array_endian_codec",
"//tensorstore/kvstore",
"//tensorstore/kvstore:test_matchers",
"//tensorstore/kvstore:test_util",
"//tensorstore/kvstore/memory",
"//tensorstore/kvstore/tiff:tiff_details",
"//tensorstore/kvstore/tiff:tiff_dir_cache",
"//tensorstore/kvstore/tiff:tiff_test_util",
"//tensorstore/util:status_testutil",
"@com_github_nlohmann_json//:json",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:cord",
"@com_google_googletest//:gtest_main",
"@com_google_riegeli//riegeli/bytes:cord_reader",
"@com_google_riegeli//riegeli/bytes:cord_writer",
],
)

tensorstore_cc_test(
name = "golden_file_test",
size = "small",
srcs = ["golden_file_test.cc"],
args = [
"--tensorstore_test_data_dir=" +
package_name() + "/testdata",
],
data = [":testdata"],
deps = [
":driver",
"//tensorstore",
"//tensorstore:array",
"//tensorstore:context",
"//tensorstore:index",
"//tensorstore:open",
"//tensorstore:open_mode",
"//tensorstore/internal:path",
"//tensorstore/kvstore/file",
"//tensorstore/util:status_testutil",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:absl_log",
"@com_google_googletest//:gtest_main",
],
)

filegroup(
name = "testdata",
srcs = glob(
include = [
"testdata/**",
],
exclude = ["testdata/*.py"],
),
)

tensorstore_cc_library(
name = "zstd_compressor",
srcs = ["zstd_compressor.cc"],
deps = [
":compressor",
"//tensorstore/internal/compression:zstd_compressor",
"//tensorstore/internal/json_binding",
],
alwayslink = 1,
)

tensorstore_cc_library(
name = "zlib_compressor",
srcs = ["zlib_compressor.cc"],
deps = [
":compressor",
"//tensorstore/internal/compression:zlib_compressor",
"//tensorstore/internal/json_binding",
],
alwayslink = 1,
)
72 changes: 72 additions & 0 deletions tensorstore/driver/tiff/compressor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2025 The TensorStore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "tensorstore/driver/tiff/compressor.h" // For Compressor alias declaration

#include <string>
#include <string_view>
#include <utility>

#include "absl/base/no_destructor.h"
#include "absl/container/flat_hash_map.h"
#include "tensorstore/driver/tiff/compressor_registry.h"
#include "tensorstore/internal/compression/json_specified_compressor.h"
#include "tensorstore/internal/json_binding/bindable.h"
#include "tensorstore/internal/json_binding/enum.h"
#include "tensorstore/internal/json_binding/json_binding.h"
#include "tensorstore/internal/json_registry.h"
#include "tensorstore/kvstore/tiff/tiff_details.h"

namespace tensorstore {
namespace internal_tiff {

namespace jb = tensorstore::internal_json_binding;
using ::tensorstore::internal_tiff_kvstore::CompressionType;

internal::JsonSpecifiedCompressor::Registry& GetTiffCompressorRegistry() {
static absl::NoDestructor<internal::JsonSpecifiedCompressor::Registry>
registry;
return *registry;
}

// Defines the mapping from TIFF numeric tag values to the string IDs used
// for compressor registration and CodecSpec JSON representation.
const static auto* const kCompressionTypeToStringIdMap =
new absl::flat_hash_map<CompressionType, std::string_view>{
{CompressionType::kNone, "raw"}, // No compression
{CompressionType::kZStd, "zstd"}, // Zstandard compression
{CompressionType::kDeflate, "zlib"}, // Deflate/Zlib compression.
// { CompressionType::kPackBits, "packbits" },
};

const absl::flat_hash_map<CompressionType, std::string_view>&
GetTiffCompressionMap() {
return *kCompressionTypeToStringIdMap;
}

TENSORSTORE_DEFINE_JSON_DEFAULT_BINDER(Compressor, [](auto is_loading,
const auto& options,
auto* obj, auto* j) {
auto& registry = GetTiffCompressorRegistry();
return jb::Object(
jb::Member("type",
jb::MapValue(
registry.KeyBinder(),
// Map "raw" to a default-constructed Compressor (nullptr)
std::make_pair(Compressor{}, std::string("raw")))),
registry.RegisteredObjectBinder())(is_loading, options, obj, j);
})

} // namespace internal_tiff
} // namespace tensorstore
34 changes: 34 additions & 0 deletions tensorstore/driver/tiff/compressor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2025 The TensorStore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef TENSORSTORE_DRIVER_TIFF_COMPRESSOR_H_
#define TENSORSTORE_DRIVER_TIFF_COMPRESSOR_H_

// Include the base class required by the JsonSpecifiedCompressor registry
#include "tensorstore/internal/compression/json_specified_compressor.h"
#include "tensorstore/internal/json_binding/bindable.h" // For binder macro

namespace tensorstore {
namespace internal_tiff {

class Compressor : public internal::JsonSpecifiedCompressor::Ptr {
public:
TENSORSTORE_DECLARE_JSON_DEFAULT_BINDER(
Compressor, internal::JsonSpecifiedCompressor::FromJsonOptions,
internal::JsonSpecifiedCompressor::ToJsonOptions)
};
} // namespace internal_tiff
} // namespace tensorstore

#endif // TENSORSTORE_DRIVER_TIFF_COMPRESSOR_H_
46 changes: 46 additions & 0 deletions tensorstore/driver/tiff/compressor_registry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2025 The TensorStore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef TENSORSTORE_DRIVER_TIFF_COMPRESSOR_REGISTRY_H_
#define TENSORSTORE_DRIVER_TIFF_COMPRESSOR_REGISTRY_H_

#include <string_view>

#include "absl/container/flat_hash_map.h"
#include "tensorstore/internal/compression/json_specified_compressor.h"
#include "tensorstore/internal/json_registry.h"
#include "tensorstore/kvstore/tiff/tiff_details.h"

namespace tensorstore {
namespace internal_tiff {

// Returns the global registry instance for TIFF compressors.
// This registry maps string IDs (like "lzw", "deflate") to factories/binders
// capable of creating JsonSpecifiedCompressor instances.
internal::JsonSpecifiedCompressor::Registry& GetTiffCompressorRegistry();

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems unlikely that we need to register tiff compressor to start with, also the tiff tag value could map directly to a compressor instance (via an enum, or similar).

// Returns the map from TIFF Compression tag enum to string ID.
const absl::flat_hash_map<internal_tiff_kvstore::CompressionType,
std::string_view>&
GetTiffCompressionMap();

template <typename T, typename Binder>
void RegisterCompressor(std::string_view id, Binder binder) {
GetTiffCompressorRegistry().Register<T>(id, binder);
}

} // namespace internal_tiff
} // namespace tensorstore

#endif // TENSORSTORE_DRIVER_TIFF_COMPRESSOR_REGISTRY_H_
Loading