// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include "ColorScale.h" #include "JFJochException.h" float luminance(rgb input) { return 0.2126f * input.r + 0.7152f * input.g + 0.0722f * input.b; } ColorScale::ColorScale() : lut_(kLutSize) { CalcLUT(); } void ColorScale::Select(ColorScaleEnum val) { current = val; CalcLUT(); } const std::vector &ColorScale::LUTData() const { return lut_; } void ColorScale::CalcLUT() const { const std::vector* map = nullptr; switch (current) { case ColorScaleEnum::Viridis: map = &viridis_colormap; break; case ColorScaleEnum::Heat: map = &heat_colormap; break; case ColorScaleEnum::Indigo: map = &white_to_indigo_colormap; break; case ColorScaleEnum::BW: map = &white_to_black_colormap; break; default: throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Color scale unknown"); } for (size_t i = 0; i < kLutSize; ++i) { const float f = static_cast(i) / static_cast(kLutSize - 1); lut_[i] = Apply(f, *map); } } rgb ColorScale::Apply(float input, const std::vector &map) { size_t num_colors = map.size(); if (num_colors < 2) { throw std::invalid_argument("Colormap must have at least two colors."); } float scaled_value = input * (num_colors - 1); size_t lower_idx = static_cast(scaled_value); size_t upper_idx = std::min(lower_idx + 1, num_colors - 1); float t = scaled_value - lower_idx; // Fraction for interpolation rgb lower = map[lower_idx]; rgb upper = map[upper_idx]; return { .r = static_cast(lower.r + t * (upper.r - lower.r)), .g = static_cast(lower.g + t * (upper.g - lower.g)), .b = static_cast(lower.b + t * (upper.b - lower.b)) }; } rgb ColorScale::Apply(ColorScaleSpecial input) const { switch (input) { case ColorScaleSpecial::Gap: return gap; default: case ColorScaleSpecial::BadPixel: return bad; } } rgb ColorScale::Apply(float input, float min, float max) const { if (!std::isfinite(input)) return gap; float f; if (input <= min) f = 0.0f; else if (input >= max) f = 1.0f; else f = (input - min) / (max - min); const size_t idx = static_cast(f * static_cast(kLutSize - 1)); return lut_[idx]; } rgb ColorScale::ApplyLUTIndex(size_t idx) const { if (idx >= kLutSize) return lut_[kLutSize-1]; return lut_[idx]; } ColorScale &ColorScale::Gap(rgb input) { gap = input; return *this; } ColorScale &ColorScale::BadPixel(rgb input) { bad = input; return *this; }