Commit 517ca646 authored by creis's avatar creis Committed by Commit bot

Revert of Reland: [qcms] Fix build_output_lut to return correct data for...

Revert of Reland: [qcms] Fix build_output_lut to return correct data for parametric curves (patchset #14 id:260001 of https://codereview.chromium.org/1862053002/ )

Reason for revert:
This broke the Windows compile (again).
https://build.chromium.org/p/chromium/builders/Win/builds/42772

Original issue's description:
> [qcms] Fix build_output_lut to return correct data for parametric curves
>
> build_output_lut() does not invert a parametric gamma curve when
> computing the output curve data. The effect has not been visible
> since Chrome only uses the output gamma values from the precache
> table (which is inverted).
>
> Make build_output_lut() return inverted data for parametric gamma
> curves. Add a test to write the inverted data, and the output of
> LCMS function DefaultEvalParametricFn, to a file for comparison.
>
> For now the size of input and output gamma table for parametric
> curves is hard-coded to 256; assert this in the test code. See
> compute_curve_gamma_table_type_parametric for details. Future
> implementations might return an arbitrary-sized table.
>
> BUG=600338
>
> Committed: https://crrev.com/a89370950f514a3df77ed84240d4b8e3abbee801
> Cr-Commit-Position: refs/heads/master@{#389754}
>
> Committed: https://crrev.com/3a4a913c1de915ef228a35b4f85603662719c49f
> Cr-Commit-Position: refs/heads/master@{#389866}

TBR=noel@chromium.org,radu.velea@intel.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=600338

Review URL: https://codereview.chromium.org/1920253003

Cr-Commit-Position: refs/heads/master@{#389877}
parent ac7bdb6c
......@@ -59,9 +59,7 @@ if (!disable_qcms) {
"src/tests/qcms_test_main.c",
"src/tests/qcms_test_munsell.c",
"src/tests/qcms_test_ntsc_gamut.c",
"src/tests/qcms_test_output_trc.c",
"src/tests/qcms_test_tetra_clut_rgba.c",
"src/tests/qcms_test_util.c",
]
deps = [
......
......@@ -149,8 +149,6 @@ The following changes have been made since qcms was imported:
- https://code.google.com/p/chromium/issues/detail?id=580917
- Add more internal sRGB profile tests
- https://code.google.com/p/chromium/issues/detail?id=580917
- Fix build_output_lut to return correct data for parametric curves
- https://bugs.chromium.org/p/chromium/issues/detail?id=600338
For the Chromium changes, since the import, in a patch format run:
git diff b8456f38 src
......@@ -96,9 +96,7 @@
'src/tests/qcms_test_internal_srgb.c',
'src/tests/qcms_test_munsell.c',
'src/tests/qcms_test_ntsc_gamut.c',
'src/tests/qcms_test_output_trc.c',
'src/tests/qcms_test_tetra_clut_rgba.c',
'src/tests/qcms_test_util.c',
],
},
],
......
......@@ -9,7 +9,7 @@ OBJS=$(QCMS:.c=.o)
all: qcms_tests
qcms_tests: qcms_test_*.c $(OBJS)
qcms_tests: qcms_test_main.c qcms_test_munsell.c qcms_test_tetra_clut_rgba.c qcms_test_internal_srgb.c qcms_test_ntsc_gamut.c $(OBJS)
$(CC) $(CFLAGS) $(INCLUDE) $^ -o $@ $(LDFLAGS)
clean:
......
......@@ -16,9 +16,8 @@ extern struct qcms_test_case qcms_test_tetra_clut_rgba_info;
extern struct qcms_test_case qcms_test_munsell_info;
extern struct qcms_test_case qcms_test_internal_srgb_info;
extern struct qcms_test_case qcms_test_ntsc_gamut_info;
extern struct qcms_test_case qcms_test_output_trc_info;
struct qcms_test_case qcms_test[5];
struct qcms_test_case qcms_test[4];
#define TEST_CASES (sizeof(qcms_test) / sizeof(qcms_test[0]))
static void initialize_tests()
......@@ -27,7 +26,6 @@ static void initialize_tests()
qcms_test[1] = qcms_test_munsell_info;
qcms_test[2] = qcms_test_internal_srgb_info;
qcms_test[3] = qcms_test_ntsc_gamut_info;
qcms_test[4] = qcms_test_output_trc_info;
}
static void list_tests()
......@@ -75,6 +73,16 @@ int enable_test(const char *args)
return 0;
}
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;
}
}
int main(int argc, const char **argv)
{
int iterations = 1;
......
// 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.h"
#include "qcms_test_util.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para'
static const float inverse65535 = (float) (1.0 / 65535.0);
extern float clamp_float(float a);
static int get_output_gamma_table(const char *profile_path, uint16_t **table, size_t *size)
{
qcms_transform *transform;
qcms_profile *sRGB;
qcms_profile *target;
target = qcms_profile_from_path(profile_path);
if (!target) {
fprintf(stderr, "Invalid input profile\n");
return EXIT_FAILURE;
}
sRGB = qcms_profile_sRGB();
transform = qcms_transform_create(sRGB, QCMS_DATA_RGBA_8, target, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT);
if (!transform) {
fprintf(stderr, "Failed to create colour transform\n");
qcms_profile_release(sRGB);
qcms_profile_release(target);
return EXIT_FAILURE;
}
*size = qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, NULL);
assert(*size == 256);
*table = malloc(*size * sizeof(uint16_t) * 4);
qcms_transform_get_output_trc_rgba(transform, target, QCMS_TRC_USHORT, *table);
qcms_transform_release(transform);
qcms_profile_release(sRGB);
qcms_profile_release(target);
return 0;
}
static int get_input_gamma_table(const char *profile_path, uint16_t **table, size_t *size)
{
qcms_transform *transform;
qcms_profile *source;
qcms_profile *sRGB;
source = qcms_profile_from_path(profile_path);
if (!source) {
fprintf(stderr, "Invalid input profile\n");
return EXIT_FAILURE;
}
sRGB = qcms_profile_sRGB();
transform = qcms_transform_create(source, QCMS_DATA_RGBA_8, sRGB, QCMS_DATA_RGBA_8, QCMS_INTENT_DEFAULT);
if (!transform) {
fprintf(stderr, "Failed to create colour transform\n");
qcms_profile_release(sRGB);
qcms_profile_release(source);
return EXIT_FAILURE;
}
*size = qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, NULL);
assert(*size == 256);
*table = calloc(*size, sizeof(uint16_t) * 4);
qcms_transform_get_input_trc_rgba(transform, source, QCMS_TRC_USHORT, *table);
qcms_transform_release(transform);
qcms_profile_release(sRGB);
qcms_profile_release(source);
return 0;
}
static int qcms_test_output_trc(size_t width,
size_t height,
int iterations,
const char *in_path,
const char *out_path,
const int force_software)
{
qcms_profile *profile;
uint16_t *gamma_table_out;
size_t gamma_table_size;
int i;
printf("Test qcms output gamma curve table integrity.\n");
if (!in_path) {
fprintf(stderr, "%s: please provide valid ICC profiles via -i option\n", __FUNCTION__);
return EXIT_FAILURE;
}
// Create profiles and transforms, get table and then free resources to make sure none
// of the internal tables are initialized by previous calls.
gamma_table_out = NULL;
gamma_table_size = 0;
if (get_output_gamma_table(in_path, &gamma_table_out, &gamma_table_size) != 0) {
fprintf(stderr, "Unable to extract output gamma table\n");
return EXIT_FAILURE;
}
printf("LUT size = %zu\n", gamma_table_size);
profile = qcms_profile_from_path(in_path);
if (!profile) {
fprintf(stderr, "Invalid input profile\n");
free(gamma_table_out);
return EXIT_FAILURE;
}
// Check only for red curve for now.
if (profile->redTRC->type == PARAMETRIC_CURVE_TYPE) {
int type = - (int)(profile->redTRC->count + 1);
FILE *gamma_file;
uint16_t *gamma_table_in = NULL;
uint16_t *p_table_out, *p_table_in;
char file_name[256] = {0,};
size_t input_size = 0;
printf("Detected parametric curve type = %d\n", profile->redTRC->count);
sprintf(file_name, "qcms-test-%ld-parametric-gamma-%s.csv", (long int)time(NULL), profile->description);
printf("Writing input and output gamma tables to %s\n", file_name);
printf("gamma = %.6f, a = %.6f, b = %.6f, c = %.6f, d = %.6f, e = %.6f, f = %.6f\n",
profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2],
profile->redTRC->parameter[3], profile->redTRC->parameter[4], profile->redTRC->parameter[5],
profile->redTRC->parameter[6]);
// Write output to stdout and tables into a csv file.
gamma_file = fopen(file_name, "w");
fprintf(gamma_file, "Parametric gamma values for %s\n", profile->description);
fprintf(gamma_file, "gamma, a, b, c, d, e, f\n");
fprintf(gamma_file, "%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f\n",
profile->redTRC->parameter[0], profile->redTRC->parameter[1], profile->redTRC->parameter[2],
profile->redTRC->parameter[3], profile->redTRC->parameter[4], profile->redTRC->parameter[5],
profile->redTRC->parameter[6]);
get_input_gamma_table(in_path, &gamma_table_in, &input_size);
assert(input_size == gamma_table_size);
if (!gamma_table_in) {
fprintf(stderr, "Unable to compute input trc. Aborting\n");
fclose(gamma_file);
qcms_profile_release(profile);
free(gamma_table_out);
return EXIT_FAILURE;
}
fprintf(gamma_file, "\n\nInput gamma, Output gamma, LCMS Output gamma, Output gamma error\n");
p_table_out = gamma_table_out;
p_table_in = gamma_table_in;
for (i = 0; i < gamma_table_size; ++i) {
float p = i / (gamma_table_size * 1.0);
float reference_out = clamp_float(evaluate_parametric_curve(type, profile->redTRC->parameter, p));
float actual_out = *p_table_out * inverse65535;
float error_out = fabs(actual_out - reference_out);
float input = *p_table_in * inverse65535;
fprintf(gamma_file, "%.6f, %.6f, %6f, %6f\n",input, actual_out, reference_out, error_out);
p_table_out += 4; // Skip other channels.
p_table_in += 4; // Skip other channels.
}
free(gamma_table_in);
fclose(gamma_file);
}
qcms_profile_release(profile);
free(gamma_table_out);
return 0;
}
struct qcms_test_case qcms_test_output_trc_info = {
"qcms_test_output_trc",
qcms_test_output_trc,
QCMS_TEST_DISABLED
};
// 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;
}
......@@ -24,4 +24,3 @@ struct qcms_test_case {
};
void generate_source_uint8_t(unsigned char *src, const size_t length, const size_t pixel_size);
float evaluate_parametric_curve(int type, const float params[], float r);
......@@ -600,8 +600,6 @@ void build_output_lut(struct curveType *trc,
float gamma_table[256];
uint16_t i;
uint16_t *output = malloc(sizeof(uint16_t)*256);
uint16_t *inverted;
int inverted_size = 256;
if (!output) {
*output_gamma_lut = NULL;
......@@ -609,24 +607,11 @@ void build_output_lut(struct curveType *trc,
}
compute_curve_gamma_table_type_parametric(gamma_table, trc->parameter, trc->count);
*output_gamma_lut_length = 256;
for(i = 0; i < 256; i++) {
output[i] = (uint16_t)(gamma_table[i] * 65535);
}
//XXX: the choice of a minimum of 256 here is not backed by any theory,
// measurement or data, however it is what lcms uses.
// the maximum number we would need is 65535 because that's the
// accuracy used for computing the pre cache table
if (inverted_size < 256)
inverted_size = 256;
inverted = invert_lut(output, 256, inverted_size);
if (!inverted)
return;
*output_gamma_lut = inverted;
*output_gamma_lut_length = inverted_size;
free(output);
*output_gamma_lut = output;
} else {
if (trc->count == 0) {
*output_gamma_lut = build_linear_table(4096);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment