blob: e0ecff3af4dc5edc6122a7fde7b976c2054009aa [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the Chromium LICENSE file.
#include "qcms_test_util.h"
#include <math.h>
#include <stdlib.h>
#define MAX_FLOAT_ERROR 0.000001f
// Store random pixel data in the source.
void generate_source_uint8_t(unsigned char *src, const size_t length, const size_t pixel_size)
{
size_t bytes = length * pixel_size;
size_t i;
for (i = 0; i < bytes; ++i) {
*src++ = rand() & 255;
}
}
// Parametric Fn using floating point <from lcms/src/cmsgamma.c>: DefaultEvalParametricFn
float evaluate_parametric_curve(int type, const float params[], float r)
{
float e, val, disc;
switch (type) {
// X = Y ^ Gamma
case 1:
if (r < 0) {
if (fabs(params[0] - 1.0) < MAX_FLOAT_ERROR)
val = r;
else
val = 0;
}
else
val = pow(r, params[0]);
break;
// Type 1 Reversed: X = Y ^1/gamma
case -1:
if (r < 0) {
if (fabs(params[0] - 1.0) < MAX_FLOAT_ERROR)
val = r;
else
val = 0;
}
else
val = pow(r, 1/params[0]);
break;
// CIE 122-1966
// Y = (aX + b)^Gamma | X >= -b/a
// Y = 0 | else
case 2:
disc = -params[2] / params[1];
if (r >= disc ) {
e = params[1]*r + params[2];
if (e > 0)
val = pow(e, params[0]);
else
val = 0;
}
else
val = 0;
break;
// Type 2 Reversed
// X = (Y ^1/g - b) / a
case -2:
if (r < 0)
val = 0;
else
val = (pow(r, 1.0/params[0]) - params[2]) / params[1];
if (val < 0)
val = 0;
break;
// IEC 61966-3
// Y = (aX + b)^Gamma | X <= -b/a
// Y = c | else
case 3:
disc = -params[2] / params[1];
if (disc < 0)
disc = 0;
if (r >= disc) {
e = params[1]*r + params[2];
if (e > 0)
val = pow(e, params[0]) + params[3];
else
val = 0;
}
else
val = params[3];
break;
// Type 3 reversed
// X=((Y-c)^1/g - b)/a | (Y>=c)
// X=-b/a | (Y<c)
case -3:
if (r >= params[3]) {
e = r - params[3];
if (e > 0)
val = (pow(e, 1/params[0]) - params[2]) / params[1];
else
val = 0;
}
else {
val = -params[2] / params[1];
}
break;
// IEC 61966-2.1 (sRGB)
// Y = (aX + b)^Gamma | X >= d
// Y = cX | X < d
case 4:
if (r >= params[4]) {
e = params[1]*r + params[2];
if (e > 0)
val = pow(e, params[0]);
else
val = 0;
}
else
val = r * params[3];
break;
// Type 4 reversed
// X=((Y^1/g-b)/a) | Y >= (ad+b)^g
// X=Y/c | Y< (ad+b)^g
case -4:
e = params[1] * params[4] + params[2];
if (e < 0)
disc = 0;
else
disc = pow(e, params[0]);
if (r >= disc) {
val = (pow(r, 1.0/params[0]) - params[2]) / params[1];
}
else {
val = r / params[3];
}
break;
// Y = (aX + b)^Gamma + e | X >= d
// Y = cX + f | X < d
case 5:
if (r >= params[4]) {
e = params[1]*r + params[2];
if (e > 0)
val = pow(e, params[0]) + params[5];
else
val = params[5];
}
else
val = r*params[3] + params[6];
break;
// Reversed type 5
// X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f
// X=(Y-f)/c | else
case -5:
disc = params[3] * params[4] + params[6];
if (r >= disc) {
e = r - params[5];
if (e < 0)
val = 0;
else
val = (pow(e, 1.0/params[0]) - params[2]) / params[1];
}
else {
val = (r - params[6]) / params[3];
}
break;
// Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
// Type 6 is basically identical to type 5 without d
// Y = (a * X + b) ^ Gamma + c
case 6:
e = params[1]*r + params[2];
if (e < 0)
val = params[3];
else
val = pow(e, params[0]) + params[3];
break;
// ((Y - c) ^1/Gamma - b) / a
case -6:
e = r - params[3];
if (e < 0)
val = 0;
else
val = (pow(e, 1.0/params[0]) - params[2]) / params[1];
break;
// Y = a * log (b * X^Gamma + c) + d
case 7:
e = params[2] * pow(r, params[0]) + params[3];
if (e <= 0)
val = params[4];
else
val = params[1]*log10(e) + params[4];
break;
// (Y - d) / a = log(b * X ^Gamma + c)
// pow(10, (Y-d) / a) = b * X ^Gamma + c
// pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
case -7:
val = pow((pow(10.0, (r-params[4]) / params[1]) - params[3]) / params[2], 1.0 / params[0]);
break;
//Y = a * b^(c*X+d) + e
case 8:
val = (params[0] * pow(params[1], params[2] * r + params[3]) + params[4]);
break;
// Y = (log((y-e) / a) / log(b) - d ) / c
// a=0, b=1, c=2, d=3, e=4,
case -8:
disc = r - params[4];
if (disc < 0) val = 0;
else
val = (log(disc / params[0]) / log(params[1]) - params[3]) / params[2];
break;
// S-Shaped: (1 - (1-x)^1/g)^1/g
case 108:
val = pow(1.0 - pow(1 - r, 1/params[0]), 1/params[0]);
break;
// y = (1 - (1-x)^1/g)^1/g
// y^g = (1 - (1-x)^1/g)
// 1 - y^g = (1-x)^1/g
// (1 - y^g)^g = 1 - x
// 1 - (1 - y^g)^g
case -108:
val = 1 - pow(1 - pow(r, params[0]), params[0]);
break;
default:
// Unsupported parametric curve. Should never reach here
return 0;
}
return val;
}