/*
* This file is part of libplacebo.
*
* libplacebo is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* libplacebo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with libplacebo. If not, see .
*/
#ifndef LIBPLACEBO_GAMUT_MAPPING_H_
#define LIBPLACEBO_GAMUT_MAPPING_H_
#include
#include
PL_API_BEGIN
struct pl_gamut_map_params;
struct pl_gamut_map_function {
const char *name; // Identifier
const char *description; // Friendly / longer name
// The gamut-mapping function itself. Iterates over all values in `lut`,
// and adapts them as needed.
void (*map)(float *lut, const struct pl_gamut_map_params *params);
// Returns true if `map` supports both stretching and contracting the
// gamut. In this case, `map` is always executed, even if the output gamut
// is larger than the input gamut.
bool bidirectional;
// Private data. Unused by libplacebo, but may be accessed by `map`.
void *priv;
};
struct pl_gamut_map_constants {
// (Relative) chromaticity protection zone for perceptual mapping [0,1]
float perceptual_deadzone;
// Strength of the perceptual saturation mapping component [0,1]
float perceptual_strength;
// I vs C curve gamma to use for colorimetric clipping [0,10]
float colorimetric_gamma;
// Knee point to use for softclipping methods (perceptual, softclip) [0,1]
float softclip_knee;
// Desaturation strength (for softclip only) [0,1]
float softclip_desat;
};
#define PL_GAMUT_MAP_CONSTANTS \
.colorimetric_gamma = 1.80f, \
.softclip_knee = 0.70f, \
.softclip_desat = 0.35f, \
.perceptual_deadzone = 0.30f, \
.perceptual_strength = 0.80f,
struct pl_gamut_map_params {
// If `function` is NULL, defaults to `pl_gamut_map_clip`.
const struct pl_gamut_map_function *function;
// The desired input/output primaries. This affects the subjective color
// volume in which the desired mapping shall take place.
struct pl_raw_primaries input_gamut;
struct pl_raw_primaries output_gamut;
// Minimum/maximum luminance (PQ) of the target display. Note that the same
// value applies to both the input and output, since it's assumed that tone
// mapping has already happened by this stage. This effectively defines the
// legal gamut boundary in RGB space.
//
// This also defines the I channel value range, for `pl_gamut_map_generate`
float min_luma;
float max_luma;
// Common constants, should be initialized to PL_GAMUT_MAP_CONSTANTS if
// not intending to override them further.
struct pl_gamut_map_constants constants;
// -- LUT generation options (for `pl_gamut_map_generate` only)
// The size of the resulting LUT, per channel.
//
// Note: For quality, it's generally best to increase h > I > C
int lut_size_I;
int lut_size_C;
int lut_size_h;
// The stride (in number of floats) between elements in the resulting LUT.
int lut_stride;
// -- Removed parameters
PL_DEPRECATED_IN(v6.289) float chroma_margin; // non-functional
};
#define pl_gamut_map_params(...) (&(struct pl_gamut_map_params) { \
.constants = { PL_GAMUT_MAP_CONSTANTS }, \
__VA_ARGS__ \
})
// Note: Only does pointer equality testing on `function`
PL_API bool pl_gamut_map_params_equal(const struct pl_gamut_map_params *a,
const struct pl_gamut_map_params *b);
// Returns true if the given gamut mapping configuration effectively represents
// a no-op configuration. Gamut mapping can be skipped in this case.
PL_API bool pl_gamut_map_params_noop(const struct pl_gamut_map_params *params);
// Generate a gamut-mapping LUT for a given configuration. LUT samples are
// stored as IPTPQc4 values, but the LUT itself is indexed by IChPQc4,spanning
// the effective range [min_luma, max_luma] × [0, 0.5] × [-pi,pi].
//
// This ordering is designed to keep frequently co-occurring values close in
// memory, while permitting simple wrapping of the 'h' component.
PL_API void pl_gamut_map_generate(float *out, const struct pl_gamut_map_params *params);
// Samples a gamut mapping function for a single IPTPQc4 value. The input
// values are updated in-place.
PL_API void pl_gamut_map_sample(float x[3], const struct pl_gamut_map_params *params);
// Performs no gamut-mapping, just hard clips out-of-range colors per-channel.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_clip;
// Performs a perceptually balanced (saturation) gamut mapping, using a soft
// knee function to preserve in-gamut colors, followed by a final softclip
// operation. This works bidirectionally, meaning it can both compress and
// expand the gamut. Behaves similar to a blend of `saturation` and `softclip`.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_perceptual;
// Performs a perceptually balanced gamut mapping using a soft knee function to
// roll-off clipped regions, and a hue shifting function to preserve saturation.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_softclip;
// Performs relative colorimetric clipping, while maintaining an exponential
// relationship between brightness and chromaticity.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_relative;
// Performs simple RGB->RGB saturation mapping. The input R/G/B channels are
// mapped directly onto the output R/G/B channels. Will never clip, but will
// distort all hues and/or result in a faded look.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_saturation;
// Performs absolute colorimetric clipping. Like pl_gamut_map_relative, but
// does not adapt the white point.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_absolute;
// Performs constant-luminance colorimetric clipping, desaturing colors
// towards white until they're in-range.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_desaturate;
// Uniformly darkens the input slightly to prevent clipping on blown-out
// highlights, then clamps colorimetrically to the input gamut boundary,
// biased slightly to preserve chromaticity over luminance.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_darken;
// Performs no gamut mapping, but simply highlights out-of-gamut pixels.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_highlight;
// Linearly/uniformly desaturates the image in order to bring the entire
// image into the target gamut.
PL_API extern const struct pl_gamut_map_function pl_gamut_map_linear;
// A list of built-in gamut mapping functions, terminated by NULL
PL_API extern const struct pl_gamut_map_function * const pl_gamut_map_functions[];
PL_API extern const int pl_num_gamut_map_functions; // excluding trailing NULL
// Find the gamut mapping function with the given name, or NULL on failure.
PL_API const struct pl_gamut_map_function *pl_find_gamut_map_function(const char *name);
PL_API_END
#endif // LIBPLACEBO_GAMUT_MAPPING_H_