// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include "JFJochReader.h" #include "MarCCD.h" // Reads a rotation sweep straight from a directory of marCCD files - what Rayonix MX-series and mar // Mosaic detectors write, and what a decade of deposited CCD data is archived as - with no // conversion step. // // The same shape as JFJochCBFReader: the sweep's geometry comes from the first file's header, the // rotation angle of each image from its own, and images are decoded on demand so any number of // workers can read at once. A raw marCCD file carries no analysis results, so there are no spots // and no reflections here either. // // The one thing a CCD needs that a pixel detector does not: its pixels are unsigned 16-bit with no // negative marker for untrusted ones, so the mask is what the header calls saturated and nothing // else. A CCD's point spread and read-out noise are left to the analysis, which measures the // background from the image rather than assuming a detector. class JFJochMarCCDReader : public JFJochReader { std::vector files_; std::shared_ptr dataset_; marccd::Header header0_; bool LoadImage_i(std::shared_ptr &dataset, DataMessage &message, std::vector &buffer, int64_t image_number, bool update_dataset) override; // Decodes one image into the caller's byte buffer and returns the image that points at it. The // stored 16-bit strip is read through scratch, which the caller keeps between frames. template CompressedImage DecodeInto(int64_t image_number, Buffer &buffer, std::vector &scratch) const; public: ~JFJochMarCCDReader() override = default; // True if the path names something this reader can open: a marCCD file, or a directory holding // at least one. Cheap - it reads a few kB at most. static bool CanRead(const std::string &path); // path is a directory of marCCD frames, or one frame inside the sweep to take the whole sweep // from. void ReadFiles(const std::string &path); [[nodiscard]] uint64_t GetNumberOfImages() const override; void Close() override; // Whether the sweep really has an image at this point. A deposited series can be missing frames, // and they are kept as gaps so that every image keeps the spindle angle its own header states; // ReadRawImage hands such a slot back as "nothing to read". [[nodiscard]] bool HasImage(int64_t image_number) const; bool ReadRawImage(int64_t image_number, JFJochReaderRawImage &image) override; [[nodiscard]] std::vector ReadSpots(int64_t image) const override; };