gfx/qcms/transform_util.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 #define _ISOC99_SOURCE /* for INFINITY */
michael@0 2
michael@0 3 #include <math.h>
michael@0 4 #include <assert.h>
michael@0 5 #include <string.h> //memcpy
michael@0 6 #include "qcmsint.h"
michael@0 7 #include "transform_util.h"
michael@0 8 #include "matrix.h"
michael@0 9
michael@0 10 #if !defined(INFINITY)
michael@0 11 #define INFINITY HUGE_VAL
michael@0 12 #endif
michael@0 13
michael@0 14 #define PARAMETRIC_CURVE_TYPE 0x70617261 //'para'
michael@0 15
michael@0 16 /* value must be a value between 0 and 1 */
michael@0 17 //XXX: is the above a good restriction to have?
michael@0 18 // the output range of this functions is 0..1
michael@0 19 float lut_interp_linear(double input_value, uint16_t *table, int length)
michael@0 20 {
michael@0 21 int upper, lower;
michael@0 22 float value;
michael@0 23 input_value = input_value * (length - 1); // scale to length of the array
michael@0 24 upper = ceil(input_value);
michael@0 25 lower = floor(input_value);
michael@0 26 //XXX: can we be more performant here?
michael@0 27 value = table[upper]*(1. - (upper - input_value)) + table[lower]*(upper - input_value);
michael@0 28 /* scale the value */
michael@0 29 return value * (1.f/65535.f);
michael@0 30 }
michael@0 31
michael@0 32 /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
michael@0 33 uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
michael@0 34 {
michael@0 35 /* Start scaling input_value to the length of the array: 65535*(length-1).
michael@0 36 * We'll divide out the 65535 next */
michael@0 37 uint32_t value = (input_value * (length - 1));
michael@0 38 uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65535) */
michael@0 39 uint32_t lower = value / 65535; /* equivalent to floor(value/65535) */
michael@0 40 /* interp is the distance from upper to value scaled to 0..65535 */
michael@0 41 uint32_t interp = value % 65535;
michael@0 42
michael@0 43 value = (table[upper]*(interp) + table[lower]*(65535 - interp))/65535; // 0..65535*65535
michael@0 44
michael@0 45 return value;
michael@0 46 }
michael@0 47
michael@0 48 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
michael@0 49 * and returns a uint8_t value representing a range from 0..1 */
michael@0 50 static
michael@0 51 uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
michael@0 52 {
michael@0 53 /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT_MAX*(length-1).
michael@0 54 * We'll divide out the PRECACHE_OUTPUT_MAX next */
michael@0 55 uint32_t value = (input_value * (length - 1));
michael@0 56
michael@0 57 /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
michael@0 58 uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
michael@0 59 /* equivalent to floor(value/PRECACHE_OUTPUT_MAX) */
michael@0 60 uint32_t lower = value / PRECACHE_OUTPUT_MAX;
michael@0 61 /* interp is the distance from upper to value scaled to 0..PRECACHE_OUTPUT_MAX */
michael@0 62 uint32_t interp = value % PRECACHE_OUTPUT_MAX;
michael@0 63
michael@0 64 /* the table values range from 0..65535 */
michael@0 65 value = (table[upper]*(interp) + table[lower]*(PRECACHE_OUTPUT_MAX - interp)); // 0..(65535*PRECACHE_OUTPUT_MAX)
michael@0 66
michael@0 67 /* round and scale */
michael@0 68 value += (PRECACHE_OUTPUT_MAX*65535/255)/2;
michael@0 69 value /= (PRECACHE_OUTPUT_MAX*65535/255); // scale to 0..255
michael@0 70 return value;
michael@0 71 }
michael@0 72
michael@0 73 /* value must be a value between 0 and 1 */
michael@0 74 //XXX: is the above a good restriction to have?
michael@0 75 float lut_interp_linear_float(float value, float *table, int length)
michael@0 76 {
michael@0 77 int upper, lower;
michael@0 78 value = value * (length - 1);
michael@0 79 upper = ceilf(value);
michael@0 80 lower = floorf(value);
michael@0 81 //XXX: can we be more performant here?
michael@0 82 value = table[upper]*(1. - (upper - value)) + table[lower]*(upper - value);
michael@0 83 /* scale the value */
michael@0 84 return value;
michael@0 85 }
michael@0 86
michael@0 87 #if 0
michael@0 88 /* if we use a different representation i.e. one that goes from 0 to 0x1000 we can be more efficient
michael@0 89 * because we can avoid the divisions and use a shifting instead */
michael@0 90 /* same as above but takes and returns a uint16_t value representing a range from 0..1 */
michael@0 91 uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
michael@0 92 {
michael@0 93 uint32_t value = (input_value * (length - 1));
michael@0 94 uint32_t upper = (value + 4095) / 4096; /* equivalent to ceil(value/4096) */
michael@0 95 uint32_t lower = value / 4096; /* equivalent to floor(value/4096) */
michael@0 96 uint32_t interp = value % 4096;
michael@0 97
michael@0 98 value = (table[upper]*(interp) + table[lower]*(4096 - interp))/4096; // 0..4096*4096
michael@0 99
michael@0 100 return value;
michael@0 101 }
michael@0 102 #endif
michael@0 103
michael@0 104 void compute_curve_gamma_table_type1(float gamma_table[256], uint16_t gamma)
michael@0 105 {
michael@0 106 unsigned int i;
michael@0 107 float gamma_float = u8Fixed8Number_to_float(gamma);
michael@0 108 for (i = 0; i < 256; i++) {
michael@0 109 // 0..1^(0..255 + 255/256) will always be between 0 and 1
michael@0 110 gamma_table[i] = pow(i/255., gamma_float);
michael@0 111 }
michael@0 112 }
michael@0 113
michael@0 114 void compute_curve_gamma_table_type2(float gamma_table[256], uint16_t *table, int length)
michael@0 115 {
michael@0 116 unsigned int i;
michael@0 117 for (i = 0; i < 256; i++) {
michael@0 118 gamma_table[i] = lut_interp_linear(i/255., table, length);
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 void compute_curve_gamma_table_type_parametric(float gamma_table[256], float parameter[7], int count)
michael@0 123 {
michael@0 124 size_t X;
michael@0 125 float interval;
michael@0 126 float a, b, c, e, f;
michael@0 127 float y = parameter[0];
michael@0 128 if (count == 0) {
michael@0 129 a = 1;
michael@0 130 b = 0;
michael@0 131 c = 0;
michael@0 132 e = 0;
michael@0 133 f = 0;
michael@0 134 interval = -INFINITY;
michael@0 135 } else if(count == 1) {
michael@0 136 a = parameter[1];
michael@0 137 b = parameter[2];
michael@0 138 c = 0;
michael@0 139 e = 0;
michael@0 140 f = 0;
michael@0 141 interval = -1 * parameter[2] / parameter[1];
michael@0 142 } else if(count == 2) {
michael@0 143 a = parameter[1];
michael@0 144 b = parameter[2];
michael@0 145 c = 0;
michael@0 146 e = parameter[3];
michael@0 147 f = parameter[3];
michael@0 148 interval = -1 * parameter[2] / parameter[1];
michael@0 149 } else if(count == 3) {
michael@0 150 a = parameter[1];
michael@0 151 b = parameter[2];
michael@0 152 c = parameter[3];
michael@0 153 e = -c;
michael@0 154 f = 0;
michael@0 155 interval = parameter[4];
michael@0 156 } else if(count == 4) {
michael@0 157 a = parameter[1];
michael@0 158 b = parameter[2];
michael@0 159 c = parameter[3];
michael@0 160 e = parameter[5] - c;
michael@0 161 f = parameter[6];
michael@0 162 interval = parameter[4];
michael@0 163 } else {
michael@0 164 assert(0 && "invalid parametric function type.");
michael@0 165 a = 1;
michael@0 166 b = 0;
michael@0 167 c = 0;
michael@0 168 e = 0;
michael@0 169 f = 0;
michael@0 170 interval = -INFINITY;
michael@0 171 }
michael@0 172 for (X = 0; X < 256; X++) {
michael@0 173 if (X >= interval) {
michael@0 174 // XXX The equations are not exactly as definied in the spec but are
michael@0 175 // algebraic equivilent.
michael@0 176 // TODO Should division by 255 be for the whole expression.
michael@0 177 gamma_table[X] = clamp_float(pow(a * X / 255. + b, y) + c + e);
michael@0 178 } else {
michael@0 179 gamma_table[X] = clamp_float(c * X / 255. + f);
michael@0 180 }
michael@0 181 }
michael@0 182 }
michael@0 183
michael@0 184 void compute_curve_gamma_table_type0(float gamma_table[256])
michael@0 185 {
michael@0 186 unsigned int i;
michael@0 187 for (i = 0; i < 256; i++) {
michael@0 188 gamma_table[i] = i/255.;
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 float *build_input_gamma_table(struct curveType *TRC)
michael@0 193 {
michael@0 194 float *gamma_table;
michael@0 195
michael@0 196 if (!TRC) return NULL;
michael@0 197 gamma_table = malloc(sizeof(float)*256);
michael@0 198 if (gamma_table) {
michael@0 199 if (TRC->type == PARAMETRIC_CURVE_TYPE) {
michael@0 200 compute_curve_gamma_table_type_parametric(gamma_table, TRC->parameter, TRC->count);
michael@0 201 } else {
michael@0 202 if (TRC->count == 0) {
michael@0 203 compute_curve_gamma_table_type0(gamma_table);
michael@0 204 } else if (TRC->count == 1) {
michael@0 205 compute_curve_gamma_table_type1(gamma_table, TRC->data[0]);
michael@0 206 } else {
michael@0 207 compute_curve_gamma_table_type2(gamma_table, TRC->data, TRC->count);
michael@0 208 }
michael@0 209 }
michael@0 210 }
michael@0 211 return gamma_table;
michael@0 212 }
michael@0 213
michael@0 214 struct matrix build_colorant_matrix(qcms_profile *p)
michael@0 215 {
michael@0 216 struct matrix result;
michael@0 217 result.m[0][0] = s15Fixed16Number_to_float(p->redColorant.X);
michael@0 218 result.m[0][1] = s15Fixed16Number_to_float(p->greenColorant.X);
michael@0 219 result.m[0][2] = s15Fixed16Number_to_float(p->blueColorant.X);
michael@0 220 result.m[1][0] = s15Fixed16Number_to_float(p->redColorant.Y);
michael@0 221 result.m[1][1] = s15Fixed16Number_to_float(p->greenColorant.Y);
michael@0 222 result.m[1][2] = s15Fixed16Number_to_float(p->blueColorant.Y);
michael@0 223 result.m[2][0] = s15Fixed16Number_to_float(p->redColorant.Z);
michael@0 224 result.m[2][1] = s15Fixed16Number_to_float(p->greenColorant.Z);
michael@0 225 result.m[2][2] = s15Fixed16Number_to_float(p->blueColorant.Z);
michael@0 226 result.invalid = false;
michael@0 227 return result;
michael@0 228 }
michael@0 229
michael@0 230 /* The following code is copied nearly directly from lcms.
michael@0 231 * I think it could be much better. For example, Argyll seems to have better code in
michael@0 232 * icmTable_lookup_bwd and icmTable_setup_bwd. However, for now this is a quick way
michael@0 233 * to a working solution and allows for easy comparing with lcms. */
michael@0 234 uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int length)
michael@0 235 {
michael@0 236 int l = 1;
michael@0 237 int r = 0x10000;
michael@0 238 int x = 0, res; // 'int' Give spacing for negative values
michael@0 239 int NumZeroes, NumPoles;
michael@0 240 int cell0, cell1;
michael@0 241 double val2;
michael@0 242 double y0, y1, x0, x1;
michael@0 243 double a, b, f;
michael@0 244
michael@0 245 // July/27 2001 - Expanded to handle degenerated curves with an arbitrary
michael@0 246 // number of elements containing 0 at the begining of the table (Zeroes)
michael@0 247 // and another arbitrary number of poles (FFFFh) at the end.
michael@0 248 // First the zero and pole extents are computed, then value is compared.
michael@0 249
michael@0 250 NumZeroes = 0;
michael@0 251 while (LutTable[NumZeroes] == 0 && NumZeroes < length-1)
michael@0 252 NumZeroes++;
michael@0 253
michael@0 254 // There are no zeros at the beginning and we are trying to find a zero, so
michael@0 255 // return anything. It seems zero would be the less destructive choice
michael@0 256 /* I'm not sure that this makes sense, but oh well... */
michael@0 257 if (NumZeroes == 0 && Value == 0)
michael@0 258 return 0;
michael@0 259
michael@0 260 NumPoles = 0;
michael@0 261 while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1)
michael@0 262 NumPoles++;
michael@0 263
michael@0 264 // Does the curve belong to this case?
michael@0 265 if (NumZeroes > 1 || NumPoles > 1)
michael@0 266 {
michael@0 267 int a, b;
michael@0 268
michael@0 269 // Identify if value fall downto 0 or FFFF zone
michael@0 270 if (Value == 0) return 0;
michael@0 271 // if (Value == 0xFFFF) return 0xFFFF;
michael@0 272
michael@0 273 // else restrict to valid zone
michael@0 274
michael@0 275 a = ((NumZeroes-1) * 0xFFFF) / (length-1);
michael@0 276 b = ((length-1 - NumPoles) * 0xFFFF) / (length-1);
michael@0 277
michael@0 278 l = a - 1;
michael@0 279 r = b + 1;
michael@0 280 }
michael@0 281
michael@0 282
michael@0 283 // Seems not a degenerated case... apply binary search
michael@0 284
michael@0 285 while (r > l) {
michael@0 286
michael@0 287 x = (l + r) / 2;
michael@0 288
michael@0 289 res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
michael@0 290
michael@0 291 if (res == Value) {
michael@0 292
michael@0 293 // Found exact match.
michael@0 294
michael@0 295 return (uint16_fract_t) (x - 1);
michael@0 296 }
michael@0 297
michael@0 298 if (res > Value) r = x - 1;
michael@0 299 else l = x + 1;
michael@0 300 }
michael@0 301
michael@0 302 // Not found, should we interpolate?
michael@0 303
michael@0 304
michael@0 305 // Get surrounding nodes
michael@0 306
michael@0 307 val2 = (length-1) * ((double) (x - 1) / 65535.0);
michael@0 308
michael@0 309 cell0 = (int) floor(val2);
michael@0 310 cell1 = (int) ceil(val2);
michael@0 311
michael@0 312 if (cell0 == cell1) return (uint16_fract_t) x;
michael@0 313
michael@0 314 y0 = LutTable[cell0] ;
michael@0 315 x0 = (65535.0 * cell0) / (length-1);
michael@0 316
michael@0 317 y1 = LutTable[cell1] ;
michael@0 318 x1 = (65535.0 * cell1) / (length-1);
michael@0 319
michael@0 320 a = (y1 - y0) / (x1 - x0);
michael@0 321 b = y0 - a * x0;
michael@0 322
michael@0 323 if (fabs(a) < 0.01) return (uint16_fract_t) x;
michael@0 324
michael@0 325 f = ((Value - b) / a);
michael@0 326
michael@0 327 if (f < 0.0) return (uint16_fract_t) 0;
michael@0 328 if (f >= 65535.0) return (uint16_fract_t) 0xFFFF;
michael@0 329
michael@0 330 return (uint16_fract_t) floor(f + 0.5);
michael@0 331
michael@0 332 }
michael@0 333
michael@0 334 /*
michael@0 335 The number of entries needed to invert a lookup table should not
michael@0 336 necessarily be the same as the original number of entries. This is
michael@0 337 especially true of lookup tables that have a small number of entries.
michael@0 338
michael@0 339 For example:
michael@0 340 Using a table like:
michael@0 341 {0, 3104, 14263, 34802, 65535}
michael@0 342 invert_lut will produce an inverse of:
michael@0 343 {3, 34459, 47529, 56801, 65535}
michael@0 344 which has an maximum error of about 9855 (pixel difference of ~38.346)
michael@0 345
michael@0 346 For now, we punt the decision of output size to the caller. */
michael@0 347 static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
michael@0 348 {
michael@0 349 int i;
michael@0 350 /* for now we invert the lut by creating a lut of size out_length
michael@0 351 * and attempting to lookup a value for each entry using lut_inverse_interp16 */
michael@0 352 uint16_t *output = malloc(sizeof(uint16_t)*out_length);
michael@0 353 if (!output)
michael@0 354 return NULL;
michael@0 355
michael@0 356 for (i = 0; i < out_length; i++) {
michael@0 357 double x = ((double) i * 65535.) / (double) (out_length - 1);
michael@0 358 uint16_fract_t input = floor(x + .5);
michael@0 359 output[i] = lut_inverse_interp16(input, table, length);
michael@0 360 }
michael@0 361 return output;
michael@0 362 }
michael@0 363
michael@0 364 static void compute_precache_pow(uint8_t *output, float gamma)
michael@0 365 {
michael@0 366 uint32_t v = 0;
michael@0 367 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
michael@0 368 //XXX: don't do integer/float conversion... and round?
michael@0 369 output[v] = 255. * pow(v/(double)PRECACHE_OUTPUT_MAX, gamma);
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 void compute_precache_lut(uint8_t *output, uint16_t *table, int length)
michael@0 374 {
michael@0 375 uint32_t v = 0;
michael@0 376 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
michael@0 377 output[v] = lut_interp_linear_precache_output(v, table, length);
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 void compute_precache_linear(uint8_t *output)
michael@0 382 {
michael@0 383 uint32_t v = 0;
michael@0 384 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
michael@0 385 //XXX: round?
michael@0 386 output[v] = v / (PRECACHE_OUTPUT_SIZE/256);
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 qcms_bool compute_precache(struct curveType *trc, uint8_t *output)
michael@0 391 {
michael@0 392
michael@0 393 if (trc->type == PARAMETRIC_CURVE_TYPE) {
michael@0 394 float gamma_table[256];
michael@0 395 uint16_t gamma_table_uint[256];
michael@0 396 uint16_t i;
michael@0 397 uint16_t *inverted;
michael@0 398 int inverted_size = 256;
michael@0 399
michael@0 400 compute_curve_gamma_table_type_parametric(gamma_table, trc->parameter, trc->count);
michael@0 401 for(i = 0; i < 256; i++) {
michael@0 402 gamma_table_uint[i] = (uint16_t)(gamma_table[i] * 65535);
michael@0 403 }
michael@0 404
michael@0 405 //XXX: the choice of a minimum of 256 here is not backed by any theory,
michael@0 406 // measurement or data, howeve r it is what lcms uses.
michael@0 407 // the maximum number we would need is 65535 because that's the
michael@0 408 // accuracy used for computing the pre cache table
michael@0 409 if (inverted_size < 256)
michael@0 410 inverted_size = 256;
michael@0 411
michael@0 412 inverted = invert_lut(gamma_table_uint, 256, inverted_size);
michael@0 413 if (!inverted)
michael@0 414 return false;
michael@0 415 compute_precache_lut(output, inverted, inverted_size);
michael@0 416 free(inverted);
michael@0 417 } else {
michael@0 418 if (trc->count == 0) {
michael@0 419 compute_precache_linear(output);
michael@0 420 } else if (trc->count == 1) {
michael@0 421 compute_precache_pow(output, 1./u8Fixed8Number_to_float(trc->data[0]));
michael@0 422 } else {
michael@0 423 uint16_t *inverted;
michael@0 424 int inverted_size = trc->count;
michael@0 425 //XXX: the choice of a minimum of 256 here is not backed by any theory,
michael@0 426 // measurement or data, howeve r it is what lcms uses.
michael@0 427 // the maximum number we would need is 65535 because that's the
michael@0 428 // accuracy used for computing the pre cache table
michael@0 429 if (inverted_size < 256)
michael@0 430 inverted_size = 256;
michael@0 431
michael@0 432 inverted = invert_lut(trc->data, trc->count, inverted_size);
michael@0 433 if (!inverted)
michael@0 434 return false;
michael@0 435 compute_precache_lut(output, inverted, inverted_size);
michael@0 436 free(inverted);
michael@0 437 }
michael@0 438 }
michael@0 439 return true;
michael@0 440 }
michael@0 441
michael@0 442
michael@0 443 static uint16_t *build_linear_table(int length)
michael@0 444 {
michael@0 445 int i;
michael@0 446 uint16_t *output = malloc(sizeof(uint16_t)*length);
michael@0 447 if (!output)
michael@0 448 return NULL;
michael@0 449
michael@0 450 for (i = 0; i < length; i++) {
michael@0 451 double x = ((double) i * 65535.) / (double) (length - 1);
michael@0 452 uint16_fract_t input = floor(x + .5);
michael@0 453 output[i] = input;
michael@0 454 }
michael@0 455 return output;
michael@0 456 }
michael@0 457
michael@0 458 static uint16_t *build_pow_table(float gamma, int length)
michael@0 459 {
michael@0 460 int i;
michael@0 461 uint16_t *output = malloc(sizeof(uint16_t)*length);
michael@0 462 if (!output)
michael@0 463 return NULL;
michael@0 464
michael@0 465 for (i = 0; i < length; i++) {
michael@0 466 uint16_fract_t result;
michael@0 467 double x = ((double) i) / (double) (length - 1);
michael@0 468 x = pow(x, gamma); //XXX turn this conversion into a function
michael@0 469 result = floor(x*65535. + .5);
michael@0 470 output[i] = result;
michael@0 471 }
michael@0 472 return output;
michael@0 473 }
michael@0 474
michael@0 475 void build_output_lut(struct curveType *trc,
michael@0 476 uint16_t **output_gamma_lut, size_t *output_gamma_lut_length)
michael@0 477 {
michael@0 478 if (trc->type == PARAMETRIC_CURVE_TYPE) {
michael@0 479 float gamma_table[256];
michael@0 480 uint16_t i;
michael@0 481 uint16_t *output = malloc(sizeof(uint16_t)*256);
michael@0 482
michael@0 483 if (!output) {
michael@0 484 *output_gamma_lut = NULL;
michael@0 485 return;
michael@0 486 }
michael@0 487
michael@0 488 compute_curve_gamma_table_type_parametric(gamma_table, trc->parameter, trc->count);
michael@0 489 *output_gamma_lut_length = 256;
michael@0 490 for(i = 0; i < 256; i++) {
michael@0 491 output[i] = (uint16_t)(gamma_table[i] * 65535);
michael@0 492 }
michael@0 493 *output_gamma_lut = output;
michael@0 494 } else {
michael@0 495 if (trc->count == 0) {
michael@0 496 *output_gamma_lut = build_linear_table(4096);
michael@0 497 *output_gamma_lut_length = 4096;
michael@0 498 } else if (trc->count == 1) {
michael@0 499 float gamma = 1./u8Fixed8Number_to_float(trc->data[0]);
michael@0 500 *output_gamma_lut = build_pow_table(gamma, 4096);
michael@0 501 *output_gamma_lut_length = 4096;
michael@0 502 } else {
michael@0 503 //XXX: the choice of a minimum of 256 here is not backed by any theory,
michael@0 504 // measurement or data, however it is what lcms uses.
michael@0 505 *output_gamma_lut_length = trc->count;
michael@0 506 if (*output_gamma_lut_length < 256)
michael@0 507 *output_gamma_lut_length = 256;
michael@0 508
michael@0 509 *output_gamma_lut = invert_lut(trc->data, trc->count, *output_gamma_lut_length);
michael@0 510 }
michael@0 511 }
michael@0 512
michael@0 513 }
michael@0 514

mercurial