tests: shared color processing functions

Added pixel pipeline processing as following:
tone curve(EOTF) + 3x3 matrix + tone curve(INV_EOTF)

Co-authored-by: Pekka Paalanen <pekka.paalanen@collabora.com>
Signed-off-by: Vitaly Prosyak <vitaly.prosyak@amd.com>
dev
Vitaly Prosyak 3 years ago
parent 6099c0e24b
commit 264a18f01a
  1. 174
      tests/color_util.c
  2. 48
      tests/color_util.h

@ -23,18 +23,90 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <math.h>
#include "color_util.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "shared/helpers.h"
struct color_tone_curve {
enum transfer_fn fn;
enum transfer_fn inv_fn;
/* LCMS2 API */
int internal_type;
double param[5];
};
const struct color_tone_curve arr_curves[] = {
{
.fn = TRANSFER_FN_SRGB_EOTF,
.inv_fn = TRANSFER_FN_SRGB_EOTF_INVERSE,
.internal_type = 4,
.param = { 2.4, 1. / 1.055, 0.055 / 1.055, 1. / 12.92, 0.04045 } ,
},
{
.fn = TRANSFER_FN_ADOBE_RGB_EOTF,
.inv_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE,
.internal_type = 1,
.param = { 563./256., 0.0, 0.0, 0.0 , 0.0 } ,
},
{
.fn = TRANSFER_FN_POWER2_4_EOTF,
.inv_fn = TRANSFER_FN_POWER2_4_EOTF_INVERSE,
.internal_type = 1,
.param = { 2.4, 0.0, 0.0, 0.0 , 0.0 } ,
}
};
bool
find_tone_curve_type(enum transfer_fn fn, int *type, double params[5])
{
const int size_arr = ARRAY_LENGTH(arr_curves);
const struct color_tone_curve *curve;
for (curve = &arr_curves[0]; curve < &arr_curves[size_arr]; curve++ ) {
if (curve->fn == fn )
*type = curve->internal_type;
else if (curve->inv_fn == fn)
*type = -curve->internal_type;
else
continue;
memcpy(params, curve->param, sizeof(curve->param));
return true;
}
return false;
}
/**
* NaN comes out as is
*This function is not intended for hiding NaN.
*/
static float
sRGB_EOTF(float e)
ensure_unit_range(float v)
{
assert(e >= 0.0f);
assert(e <= 1.0f);
const float tol = 1e-5f;
const float lim_lo = -tol;
const float lim_hi = 1.0f + tol;
assert(v >= lim_lo);
if (v < 0.0f)
return 0.0f;
assert(v <= lim_hi);
if (v > 1.0f)
return 1.0f;
return v;
}
static float
sRGB_EOTF(float e)
{
e = ensure_unit_range(e);
if (e <= 0.04045)
return e / 12.92;
else
@ -44,15 +116,40 @@ sRGB_EOTF(float e)
static float
sRGB_EOTF_inv(float o)
{
assert(o >= 0.0f);
assert(o <= 1.0f);
o = ensure_unit_range(o);
if (o <= 0.04045 / 12.92)
return o * 12.92;
else
return pow(o, 1.0 / 2.4) * 1.055 - 0.055;
}
static float
AdobeRGB_EOTF(float e)
{
e = ensure_unit_range(e);
return pow(e, 563./256.);
}
static float
AdobeRGB_EOTF_inv(float o)
{
o = ensure_unit_range(o);
return pow(o, 256./563.);
}
static float
Power2_4_EOTF(float e)
{
e = ensure_unit_range(e);
return pow(e, 2.4);
}
static float
Power2_4_EOTF_inv(float o)
{
o = ensure_unit_range(o);
return pow(o, 1./2.4);
}
void
sRGB_linearize(struct color_float *cf)
@ -62,6 +159,35 @@ sRGB_linearize(struct color_float *cf)
cf->b = sRGB_EOTF(cf->b);
}
static float
apply_tone_curve(enum transfer_fn fn, float r)
{
float ret = 0;
switch(fn) {
case TRANSFER_FN_SRGB_EOTF:
ret = sRGB_EOTF(r);
break;
case TRANSFER_FN_SRGB_EOTF_INVERSE:
ret = sRGB_EOTF_inv(r);
break;
case TRANSFER_FN_ADOBE_RGB_EOTF:
ret = AdobeRGB_EOTF(r);
break;
case TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE:
ret = AdobeRGB_EOTF_inv(r);
break;
case TRANSFER_FN_POWER2_4_EOTF:
ret = Power2_4_EOTF(r);
break;
case TRANSFER_FN_POWER2_4_EOTF_INVERSE:
ret = Power2_4_EOTF_inv(r);
break;
}
return ret;
}
void
sRGB_delinearize(struct color_float *cf)
{
@ -82,3 +208,37 @@ a8r8g8b8_to_float(uint32_t v)
return cf;
}
void
process_pixel_using_pipeline(enum transfer_fn pre_curve,
const struct lcmsMAT3 *mat,
enum transfer_fn post_curve,
const struct color_float *in,
struct color_float *out)
{
int i, j;
float rgb_in[3];
float out_blend[3];
float tmp;
rgb_in[0] = in->r;
rgb_in[1] = in->g;
rgb_in[2] = in->b;
for (i = 0; i < 3; i++)
rgb_in[i] = apply_tone_curve(pre_curve, rgb_in[i]);
for (i = 0; i < 3; i++) {
tmp = 0.0f;
for (j = 0; j < 3; j++)
tmp += rgb_in[j] * mat->v[j].n[i];
out_blend[i] = tmp;
}
for (i = 0; i < 3; i++)
out_blend[i] = apply_tone_curve(post_curve, out_blend[i]);
out->r = out_blend[0];
out->g = out_blend[1];
out->b = out_blend[2];
}

@ -25,18 +25,62 @@
*/
#include <stdint.h>
#include <stdbool.h>
struct color_float {
float r, g, b, a;
};
struct lcmsVEC3 {
float n[3];
};
struct lcmsMAT3 {
struct lcmsVEC3 v[3];
};
enum transfer_fn {
TRANSFER_FN_SRGB_EOTF,
TRANSFER_FN_SRGB_EOTF_INVERSE,
TRANSFER_FN_ADOBE_RGB_EOTF,
TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE,
TRANSFER_FN_POWER2_4_EOTF,
TRANSFER_FN_POWER2_4_EOTF_INVERSE,
};
/*
* A helper to lay out a matrix in the natural writing order in code
* instead of needing to transpose in your mind every time you read it.
* The matrix is laid out as written:
* a11 a12 a13
* a21 a22 a23
* a31 a32 a33
* where the first digit is row and the second digit is column.
*/
#define LCMSMAT3(a11, a12, a13, \
a21, a22, a23, \
a31, a32, a33) ((struct lcmsMAT3) \
{ /* Each vector is a column => looks like a transpose */ \
.v[0] = { .n = { a11, a21, a31} }, \
.v[1] = { .n = { a12, a22, a32} }, \
.v[2] = { .n = { a13, a23, a33} }, \
})
void
sRGB_linearize(struct color_float *cf);
void
sRGB_delinearize(struct color_float *cf);
struct color_float
a8r8g8b8_to_float(uint32_t v);
bool
find_tone_curve_type(enum transfer_fn fn, int *type, double params[5]);
void
process_pixel_using_pipeline(enum transfer_fn pre_curve,
const struct lcmsMAT3 *mat,
enum transfer_fn post_curve,
const struct color_float *in,
struct color_float *out);

Loading…
Cancel
Save