// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include #include #include "JFJochReaderDataset.h" #include "HDF5ImageSource.h" #include "../common/JFJochMessages.h" #include "../common/SpotToSave.h" #include "../common/GoniometerAxis.h" #include "../common/DiffractionExperiment.h" #include "../common/DiffractionGeometry.h" #include "../image_analysis/IntegrationOutcome.h" // Metadata side of the reader: everything read from one master file that is NOT raw pixels - // dataset-level metadata (geometry, mask, ROI definitions, azimuthal mapping, the per-image plot // arrays) and per-image metadata (spots, reflections, MX scalars, azimuthal profile, lattice). // // This is the swappable part: a dataset can have several metadata sources over the same images // (the original _master.h5 plus reprocessing _process.h5 snapshots). Per-image metadata is // located either through the shared image source (original file: metadata sits in the same files // as the pixels) or in this master at the global index (integrated _process.h5 snapshot). // // HDF5 is not thread-safe; all calls must be made with the global hdf5_mutex held by the caller. class HDF5MetadataSource { public: struct OpenResult { HDF5ImageLocator::Layout image_layout; // layout implied by this master (for the image source) uint64_t number_of_images = 0; }; // Parse a master file's dataset-level metadata into a JFJochReaderDataset. default_experiment // seeds the dataset's experiment. Returns the image layout it implies; the caller decides // whether to use it to configure the shared image source. OpenResult Open(const std::string &filename, const DiffractionExperiment &default_experiment); // How per-image metadata is located: with image_source set, metadata is co-located with the // pixels (original file); when null it lives in this master at the global index. void UseImageSourceForMetadata(const HDF5ImageSource *image_source) { image_source_ = image_source; } std::shared_ptr Dataset() const { return dataset_; } uint64_t NumberOfImages() const { return number_of_images; } // Per-image metadata (spots, azimuthal profile, MX scalars, lattice, reflections) into msg. void FillPerImage(DataMessage &message, int64_t image_number, const std::shared_ptr &dataset) const; std::vector ReadSpots(int64_t image) const; std::vector ReadReflections(size_t start_image, std::optional end_image) const; CompressedImage ReadCalibration(std::vector &tmp, const std::string &name) const; private: std::shared_ptr master_file; std::string master_filename; std::shared_ptr dataset_; DiffractionGeometry cached_geom; uint64_t number_of_images = 0; const HDF5ImageSource *image_source_ = nullptr; // Inverse of dataset_->source_image_number (original image number -> local index in this // master). Empty for a 1:1 source; populated when this metadata covers a subset of images. std::unordered_map image_to_local_; // Translate a global/original image number to the local index in this metadata source, or // nullopt if this source does not cover that image. Identity for a 1:1 source. std::optional ToLocalIndex(int64_t image_number) const; HDF5ImageLocator::Location ResolveMeta(int64_t global) const; std::optional ReadAxis(HDF5Object *file, const std::string &name); void ReadROIMetadata(HDF5ReadOnlyFile &file, JFJochReaderDataset &dataset) const; };