/* vim: set ts=8 sw=8 noexpandtab: */ // qcms // Copyright (C) 2009 Mozilla Corporation // Copyright (C) 1998-2007 Marti Maria // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <stdlib.h> #include <math.h> #include <assert.h> #include <string.h> //memcpy #include "qcmsint.h" #include "transform_util.h" #include "matrix.h" #ifdef USE_LIBFUZZER #define ASSERT … #else #define ASSERT(x) … #endif static struct matrix build_lut_matrix(struct lutType *lut) { … } static struct matrix build_mAB_matrix(struct lutmABType *lut) { … } //Based on lcms cmsLab2XYZ #define f(t) … #define f_1(t) … static void qcms_transform_module_LAB_to_XYZ(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } //Based on lcms cmsXYZ2Lab static void qcms_transform_module_XYZ_to_LAB(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static void qcms_transform_module_clut_only(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static void qcms_transform_module_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } /* NOT USED static void qcms_transform_module_tetra_clut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { size_t i; int xy_len = 1; int x_len = transform->grid_size; int len = x_len * x_len; float* r_table = transform->r_clut; float* g_table = transform->g_clut; float* b_table = transform->b_clut; float c0_r, c1_r, c2_r, c3_r; float c0_g, c1_g, c2_g, c3_g; float c0_b, c1_b, c2_b, c3_b; float clut_r, clut_g, clut_b; float pcs_r, pcs_g, pcs_b; for (i = 0; i < length; i++) { float device_r = *src++; float device_g = *src++; float device_b = *src++; float linear_r = lut_interp_linear_float(device_r, transform->input_clut_table_r, transform->input_clut_table_length); float linear_g = lut_interp_linear_float(device_g, transform->input_clut_table_g, transform->input_clut_table_length); float linear_b = lut_interp_linear_float(device_b, transform->input_clut_table_b, transform->input_clut_table_length); int x = floor(linear_r * (transform->grid_size-1)); int y = floor(linear_g * (transform->grid_size-1)); int z = floor(linear_b * (transform->grid_size-1)); int x_n = ceil(linear_r * (transform->grid_size-1)); int y_n = ceil(linear_g * (transform->grid_size-1)); int z_n = ceil(linear_b * (transform->grid_size-1)); float rx = linear_r * (transform->grid_size-1) - x; float ry = linear_g * (transform->grid_size-1) - y; float rz = linear_b * (transform->grid_size-1) - z; c0_r = CLU(r_table, x, y, z); c0_g = CLU(g_table, x, y, z); c0_b = CLU(b_table, x, y, z); if( rx >= ry ) { if (ry >= rz) { //rx >= ry && ry >= rz c1_r = CLU(r_table, x_n, y, z) - c0_r; c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z); c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); c1_g = CLU(g_table, x_n, y, z) - c0_g; c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z); c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); c1_b = CLU(b_table, x_n, y, z) - c0_b; c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z); c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); } else { if (rx >= rz) { //rx >= rz && rz >= ry c1_r = CLU(r_table, x_n, y, z) - c0_r; c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); c3_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x_n, y, z); c1_g = CLU(g_table, x_n, y, z) - c0_g; c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); c3_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x_n, y, z); c1_b = CLU(b_table, x_n, y, z) - c0_b; c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); c3_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x_n, y, z); } else { //rz > rx && rx >= ry c1_r = CLU(r_table, x_n, y, z_n) - CLU(r_table, x, y, z_n); c2_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y, z_n); c3_r = CLU(r_table, x, y, z_n) - c0_r; c1_g = CLU(g_table, x_n, y, z_n) - CLU(g_table, x, y, z_n); c2_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y, z_n); c3_g = CLU(g_table, x, y, z_n) - c0_g; c1_b = CLU(b_table, x_n, y, z_n) - CLU(b_table, x, y, z_n); c2_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y, z_n); c3_b = CLU(b_table, x, y, z_n) - c0_b; } } } else { if (rx >= rz) { //ry > rx && rx >= rz c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z); c2_r = CLU(r_table, x_n, y_n, z) - c0_r; c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z); c2_g = CLU(g_table, x_n, y_n, z) - c0_g; c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z); c2_b = CLU(b_table, x_n, y_n, z) - c0_b; c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); } else { if (ry >= rz) { //ry >= rz && rz > rx c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); c2_r = CLU(r_table, x, y_n, z) - c0_r; c3_r = CLU(r_table, x, y_n, z_n) - CLU(r_table, x, y_n, z); c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); c2_g = CLU(g_table, x, y_n, z) - c0_g; c3_g = CLU(g_table, x, y_n, z_n) - CLU(g_table, x, y_n, z); c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); c2_b = CLU(b_table, x, y_n, z) - c0_b; c3_b = CLU(b_table, x, y_n, z_n) - CLU(b_table, x, y_n, z); } else { //rz > ry && ry > rx c1_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x, y_n, z_n); c2_r = CLU(r_table, x, y_n, z) - c0_r; c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table, x_n, y_n, z); c1_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x, y_n, z_n); c2_g = CLU(g_table, x, y_n, z) - c0_g; c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table, x_n, y_n, z); c1_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x, y_n, z_n); c2_b = CLU(b_table, x, y_n, z) - c0_b; c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table, x_n, y_n, z); } } } clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz; clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz; clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz; pcs_r = lut_interp_linear_float(clut_r, transform->output_clut_table_r, transform->output_clut_table_length); pcs_g = lut_interp_linear_float(clut_g, transform->output_clut_table_g, transform->output_clut_table_length); pcs_b = lut_interp_linear_float(clut_b, transform->output_clut_table_b, transform->output_clut_table_length); *dest++ = clamp_float(pcs_r); *dest++ = clamp_float(pcs_g); *dest++ = clamp_float(pcs_b); } } */ static void qcms_transform_module_gamma_table(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static void qcms_transform_module_gamma_lut(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static void qcms_transform_module_matrix_translate(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static void qcms_transform_module_matrix(struct qcms_modular_transform *transform, float *src, float *dest, size_t length) { … } static struct qcms_modular_transform* qcms_modular_transform_alloc() { … } static void qcms_modular_transform_release(struct qcms_modular_transform *transform) { … } /* Set transform to be the next element in the linked list. */ static void append_transform(struct qcms_modular_transform *transform, struct qcms_modular_transform ***next_transform) { … } /* reverse the transformation list (used by mBA) */ static struct qcms_modular_transform* reverse_transform(struct qcms_modular_transform *transform) { … } #define EMPTY_TRANSFORM_LIST … static struct qcms_modular_transform* qcms_modular_transform_create_mAB(struct lutmABType *lut) { … } static struct qcms_modular_transform* qcms_modular_transform_create_lut(struct lutType *lut) { … } struct qcms_modular_transform* qcms_modular_transform_create_input(qcms_profile *in) { … } static struct qcms_modular_transform* qcms_modular_transform_create_output(qcms_profile *out) { … } /* Not Completed // Simplify the transformation chain to an equivalent transformation chain static struct qcms_modular_transform* qcms_modular_transform_reduce(struct qcms_modular_transform *transform) { struct qcms_modular_transform *first_transform = NULL; struct qcms_modular_transform *curr_trans = transform; struct qcms_modular_transform *prev_trans = NULL; while (curr_trans) { struct qcms_modular_transform *next_trans = curr_trans->next_transform; if (curr_trans->transform_module_fn == qcms_transform_module_matrix) { if (next_trans && next_trans->transform_module_fn == qcms_transform_module_matrix) { curr_trans->matrix = matrix_multiply(curr_trans->matrix, next_trans->matrix); goto remove_next; } } if (curr_trans->transform_module_fn == qcms_transform_module_gamma_table) { bool isLinear = true; uint16_t i; for (i = 0; isLinear && i < 256; i++) { isLinear &= (int)(curr_trans->input_clut_table_r[i] * 255) == i; isLinear &= (int)(curr_trans->input_clut_table_g[i] * 255) == i; isLinear &= (int)(curr_trans->input_clut_table_b[i] * 255) == i; } goto remove_current; } next_transform: if (!next_trans) break; prev_trans = curr_trans; curr_trans = next_trans; continue; remove_current: if (curr_trans == transform) { //Update head transform = next_trans; } else { prev_trans->next_transform = next_trans; } curr_trans->next_transform = NULL; qcms_modular_transform_release(curr_trans); //return transform; return qcms_modular_transform_reduce(transform); remove_next: curr_trans->next_transform = next_trans->next_transform; next_trans->next_transform = NULL; qcms_modular_transform_release(next_trans); continue; } return transform; } */ static struct qcms_modular_transform* qcms_modular_transform_create(qcms_profile *in, qcms_profile *out) { … } static float* qcms_modular_transform_data(struct qcms_modular_transform *transform, float *src, float *dest, size_t len) { … } float* qcms_chain_transform(qcms_profile *in, qcms_profile *out, float *src, float *dest, size_t lutSize) { … } qcms_bool qcms_profile_white_transform(qcms_profile *profile, float XYZ[3]) { … }