From 8dc7254624a74a90d775c84eb1bad4df7fcdd738 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Jul 2026 10:57:33 +0200 Subject: [PATCH] reader: the stored images are int32, so say so b81c6f00b took the container depth from bit_depth_image in the file, which fixed 32-bit EIGER2 files but got the general case wrong: the reader converts every image to SIGNED int32 (PixelSigned(true) a few lines up), while bit_depth_image describes an unsigned container, and GetOverflow() combines the two. So a 16-bit file still capped at INT16_MAX rather than 65535, and an 8-bit file newly capped at 127 - flagging counts 127..254 as saturated, which drops the whole reflection at the integration accept gate. Declare 32 bits, matching what the reader actually hands out. The saturation cap then comes from the file's own saturation_value, which is what it is for, and the error value reported for a read dataset becomes INT32_MIN - the sentinel the reader really uses. A file whose bit_depth_image is not 8/16/32 also stops throwing on open. Co-Authored-By: Claude Opus 5 (1M context) --- reader/HDF5MetadataSource.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/reader/HDF5MetadataSource.cpp b/reader/HDF5MetadataSource.cpp index 2a3ca7ea..ab09ef50 100644 --- a/reader/HDF5MetadataSource.cpp +++ b/reader/HDF5MetadataSource.cpp @@ -661,15 +661,17 @@ HDF5MetadataSource::OpenResult HDF5MetadataSource::Open(const std::string &filen if (master_file->Exists("/entry/instrument/detector/sensor_material")) detector.SensorMaterial(master_file->GetString("/entry/instrument/detector/sensor_material")); detector.SaturationLimit(master_file->GetInt("/entry/instrument/detector/saturation_value")); - // The container depth of the stored images, NOT the detector's counter depth. DetectorSetup - // defaults DECTRIS to 16 bits, and GetByteDepthImage() prefers that over the value the image - // format carries - so without this an EIGER2 file that stores 32-bit images has its overflow - // computed as a 16-bit one and every count above 32767 is called saturated. The integration - // accept gate then drops the WHOLE reflection, which silently removes the strongest - // reflections of a strong crystal (measured on a lysozyme set: max accepted pixel 32738 - // against a declared saturation of 108833). - if (master_file->Exists("/entry/instrument/detector/bit_depth_image")) - detector.BitDepthImage(master_file->GetInt("/entry/instrument/detector/bit_depth_image")); + // The reader hands every image out as signed int32 whatever the file stored (see PixelSigned + // below), so that is the container depth the rest of the code has to see. DetectorSetup defaults + // DECTRIS to 16 bits and GetByteDepthImage() prefers the detector's value over the image + // format's, so leaving it at the default computed the overflow as a 16-bit one and called every + // count above 32767 saturated - the integration accept gate then dropped the WHOLE reflection, + // silently removing the strongest reflections of a strong crystal (measured on a lysozyme set: + // max accepted pixel 32738 against a declared saturation of 108833). Taking bit_depth_image from + // the file instead does not work either: it describes an UNSIGNED container, so pairing it with + // signed pixels halves the range (a 16-bit file capped at 32767, an 8-bit one at 127). The real + // cap is the file's own saturation_value, set just above. + detector.BitDepthImage(32); detector.MinFrameTime(std::chrono::microseconds(0)); detector.MinCountTime(std::chrono::microseconds(0)); detector.ReadOutTime(std::chrono::nanoseconds(0));