0f5271f14c
PUT /config/user_mask.tiff only accepted 32-bit unsigned TIFF, so masks exported by tools like PyFAI (8-bit) failed. Route the upload through the universal ReadTIFF reader and let PixelMask take a CompressedImage directly: it validates the 2D shape against the detector's converted/raw layouts, binarizes any 8/16/32-bit integer image (non-zero == masked), and rejects float/multi-channel images. Also dedupe the TIFF readers: ReadTIFFFromString16 is now a thin wrapper over ReadTIFF, and the now-unused ReadTIFFFromString32 is removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
143 lines
4.3 KiB
C++
143 lines
4.3 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <catch2/catch_all.hpp>
|
|
|
|
#include <fstream>
|
|
|
|
#include "../preview/JFJochTIFF.h"
|
|
#include "../preview/PreviewImage.h"
|
|
#include "../writer/HDF5Objects.h"
|
|
#include "../common/RawToConvertedGeometry.h"
|
|
#include <iostream>
|
|
|
|
TEST_CASE("TIFFTest","[TIFF]") {
|
|
std::vector<uint16_t> values(512*1024);
|
|
CompressedImage image(values, 1024, 512);
|
|
REQUIRE_NOTHROW(WriteTIFFToString(image));
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_Write_Read","[TIFF]") {
|
|
std::vector<uint32_t> values(512*1024);
|
|
for (int i = 0; i < values.size(); i++)
|
|
values[i] = (i * 17 + 2);
|
|
|
|
CompressedImage image(values, 1024, 512);
|
|
|
|
std::string s;
|
|
REQUIRE_NOTHROW(s = WriteTIFFToString(image));
|
|
|
|
std::vector<uint8_t> buffer;
|
|
CompressedImage out = ReadTIFF(s, buffer);
|
|
REQUIRE(out.GetMode() == CompressedImageMode::Uint32);
|
|
REQUIRE(out.GetWidth() == 1024);
|
|
REQUIRE(out.GetHeight() == 512);
|
|
REQUIRE(buffer.size() == values.size() * sizeof(uint32_t));
|
|
REQUIRE(memcmp(values.data(), buffer.data(), buffer.size()) == 0);
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_Write_Read_8bit","[TIFF]") {
|
|
std::vector<uint8_t> values(512*1024);
|
|
for (int i = 0; i < values.size(); i++)
|
|
values[i] = static_cast<uint8_t>(i * 17 + 2);
|
|
|
|
CompressedImage image(values, 1024, 512, CompressedImageMode::Uint8);
|
|
|
|
std::string s;
|
|
REQUIRE_NOTHROW(s = WriteTIFFToString(image));
|
|
|
|
std::vector<uint8_t> buffer;
|
|
CompressedImage out = ReadTIFF(s, buffer);
|
|
REQUIRE(out.GetMode() == CompressedImageMode::Uint8);
|
|
REQUIRE(out.GetWidth() == 1024);
|
|
REQUIRE(out.GetHeight() == 512);
|
|
REQUIRE(buffer == values);
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_Write_Read_16bit","[TIFF]") {
|
|
std::vector<uint16_t> values(512*1024);
|
|
for (int i = 0; i < values.size(); i++)
|
|
values[i] = static_cast<uint16_t>(i * 17 + 2);
|
|
|
|
CompressedImage image(values, 1024, 512);
|
|
|
|
std::string s;
|
|
REQUIRE_NOTHROW(s = WriteTIFFToString(image));
|
|
|
|
std::vector<uint8_t> buffer;
|
|
CompressedImage out = ReadTIFF(s, buffer);
|
|
REQUIRE(out.GetMode() == CompressedImageMode::Uint16);
|
|
REQUIRE(out.GetWidth() == 1024);
|
|
REQUIRE(out.GetHeight() == 512);
|
|
REQUIRE(buffer.size() == values.size() * sizeof(uint16_t));
|
|
REQUIRE(memcmp(values.data(), buffer.data(), buffer.size()) == 0);
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_File","[TIFF]") {
|
|
std::vector<uint16_t> values(512*1024);
|
|
|
|
for (auto &i: values)
|
|
i = 345;
|
|
|
|
CompressedImage image(values, 1024, 512);
|
|
|
|
REQUIRE_NOTHROW(WriteTIFFToFile("test_image.tiff", image));
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_File_signed","[TIFF]") {
|
|
std::vector<int16_t> values(512 * 1024);
|
|
|
|
for (int i = 0; i < values.size(); i++)
|
|
values[i] = static_cast<int16_t>(((i % 2 == 0) ? 1 : -1) * i);
|
|
|
|
CompressedImage image(values, 1024, 512);
|
|
|
|
REQUIRE_NOTHROW(WriteTIFFToFile("test_image_signed.tiff", image));
|
|
}
|
|
|
|
rgb rainbowColor(float t) {
|
|
// Ensure t is in [0,1]
|
|
t = std::max(0.0f, std::min(1.0f, t));
|
|
|
|
// Convert to hue (0 to 6)
|
|
float hue = t * 6.0f;
|
|
|
|
int phase = static_cast<int>(hue);
|
|
float fract = hue - phase;
|
|
|
|
uint8_t p = static_cast<uint8_t>(255 * (1.0f - fract));
|
|
uint8_t q = static_cast<uint8_t>(255 * fract);
|
|
uint8_t full = 255;
|
|
|
|
switch (phase) {
|
|
case 0: return {full, q, 0}; // Red to Yellow
|
|
case 1: return {p, full, 0}; // Yellow to Green
|
|
case 2: return {0, full, q}; // Green to Cyan
|
|
case 3: return {0, p, full}; // Cyan to Blue
|
|
case 4: return {q, 0, full}; // Blue to Magenta
|
|
case 5: return {full, 0, p}; // Magenta to Red
|
|
default: return {full, 0, 0}; // Fallback (red)
|
|
}
|
|
}
|
|
|
|
TEST_CASE("TIFFTest_File_rgb","[TIFF]") {
|
|
std::vector<rgb> values(512 * 1024);
|
|
|
|
for (int i = 0; i < values.size(); i++) {
|
|
float t = static_cast<float>(i % 1024) / (1024 - 1);
|
|
values[i] = rainbowColor(t);
|
|
}
|
|
CompressedImage image(values, 1024, 512);
|
|
|
|
REQUIRE_NOTHROW(WriteTIFFToFile("test_image_rgb.tiff", image));
|
|
}
|
|
|
|
|
|
TEST_CASE("TIFFTest_File_float","[TIFF]") {
|
|
std::vector<float> values(512 * 1024);
|
|
for (int i = 0; i < values.size(); i++)
|
|
values[i] = i / 100.0;
|
|
CompressedImage image(values, 1024, 512);
|
|
REQUIRE_NOTHROW(WriteTIFFToFile("test_image_float.tiff", image));
|
|
}
|