1 /* vim: set ts=8 sw=8 noexpandtab: */ 2 // qcms 3 // Copyright (C) 2009 Mozilla Foundation 4 // Copyright (C) 1998-2007 Marti Maria 5 // 6 // Permission is hereby granted, free of charge, to any person obtaining 7 // a copy of this software and associated documentation files (the "Software"), 8 // to deal in the Software without restriction, including without limitation 9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 // and/or sell copies of the Software, and to permit persons to whom the Software 11 // is furnished to do so, subject to the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be included in 14 // all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #include <math.h> 25 #include <assert.h> 26 #include <stdlib.h> 27 #include <string.h> //memset 28 #include "qcmsint.h" 29 30 /* It might be worth having a unified limit on content controlled 31 * allocation per profile. This would remove the need for many 32 * of the arbitrary limits that we used */ 33 34 typedef uint32_t be32; 35 typedef uint16_t be16; 36 37 #if 0 38 not used yet 39 /* __builtin_bswap isn't available in older gccs 40 * so open code it for now */ 41 static be32 cpu_to_be32(int32_t v) 42 { 43 #ifdef IS_LITTLE_ENDIAN 44 return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); 45 //return __builtin_bswap32(v); 46 return v; 47 #endif 48 } 49 #endif 50 51 static uint32_t be32_to_cpu(be32 v) 52 { 53 #ifdef IS_LITTLE_ENDIAN 54 return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24); 55 //return __builtin_bswap32(v); 56 #else 57 return v; 58 #endif 59 } 60 61 static uint16_t be16_to_cpu(be16 v) 62 { 63 #ifdef IS_LITTLE_ENDIAN 64 return ((v & 0xff) << 8) | ((v & 0xff00) >> 8); 65 #else 66 return v; 67 #endif 68 } 69 70 /* a wrapper around the memory that we are going to parse 71 * into a qcms_profile */ 72 struct mem_source 73 { 74 const unsigned char *buf; 75 size_t size; 76 qcms_bool valid; 77 const char *invalid_reason; 78 }; 79 80 static void invalid_source(struct mem_source *mem, const char *reason) 81 { 82 mem->valid = false; 83 mem->invalid_reason = reason; 84 } 85 86 static uint32_t read_u32(struct mem_source *mem, size_t offset) 87 { 88 /* Subtract from mem->size instead of the more intuitive adding to offset. 89 * This avoids overflowing offset. The subtraction is safe because 90 * mem->size is guaranteed to be > 4 */ 91 if (offset > mem->size - 4) { 92 invalid_source(mem, "Invalid offset"); 93 return 0; 94 } else { 95 be32 k; 96 memcpy(&k, mem->buf + offset, sizeof(k)); 97 return be32_to_cpu(k); 98 } 99 } 100 101 static uint16_t read_u16(struct mem_source *mem, size_t offset) 102 { 103 if (offset > mem->size - 2) { 104 invalid_source(mem, "Invalid offset"); 105 return 0; 106 } else { 107 be16 k; 108 memcpy(&k, mem->buf + offset, sizeof(k)); 109 return be16_to_cpu(k); 110 } 111 } 112 113 static uint8_t read_u8(struct mem_source *mem, size_t offset) 114 { 115 if (offset > mem->size - 1) { 116 invalid_source(mem, "Invalid offset"); 117 return 0; 118 } else { 119 return *(uint8_t*)(mem->buf + offset); 120 } 121 } 122 123 static s15Fixed16Number read_s15Fixed16Number(struct mem_source *mem, size_t offset) 124 { 125 return read_u32(mem, offset); 126 } 127 128 static uInt8Number read_uInt8Number(struct mem_source *mem, size_t offset) 129 { 130 return read_u8(mem, offset); 131 } 132 133 static uInt16Number read_uInt16Number(struct mem_source *mem, size_t offset) 134 { 135 return read_u16(mem, offset); 136 } 137 138 #define BAD_VALUE_PROFILE NULL 139 #define INVALID_PROFILE NULL 140 #define NO_MEM_PROFILE NULL 141 142 /* An arbitrary 4MB limit on profile size */ 143 #define MAX_PROFILE_SIZE 1024*1024*4 144 #define MAX_TAG_COUNT 1024 145 146 static void check_CMM_type_signature(struct mem_source *src) 147 { 148 //uint32_t CMM_type_signature = read_u32(src, 4); 149 //TODO: do the check? 150 151 } 152 153 static void check_profile_version(struct mem_source *src) 154 { 155 156 /* 157 uint8_t major_revision = read_u8(src, 8 + 0); 158 uint8_t minor_revision = read_u8(src, 8 + 1); 159 */ 160 uint8_t reserved1 = read_u8(src, 8 + 2); 161 uint8_t reserved2 = read_u8(src, 8 + 3); 162 /* Checking the version doesn't buy us anything 163 if (major_revision != 0x4) { 164 if (major_revision > 0x2) 165 invalid_source(src, "Unsupported major revision"); 166 if (minor_revision > 0x40) 167 invalid_source(src, "Unsupported minor revision"); 168 } 169 */ 170 if (reserved1 != 0 || reserved2 != 0) 171 invalid_source(src, "Invalid reserved bytes"); 172 } 173 174 #define INPUT_DEVICE_PROFILE 0x73636e72 // 'scnr' 175 #define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr' 176 #define OUTPUT_DEVICE_PROFILE 0x70727472 // 'prtr' 177 #define DEVICE_LINK_PROFILE 0x6c696e6b // 'link' 178 #define COLOR_SPACE_PROFILE 0x73706163 // 'spac' 179 #define ABSTRACT_PROFILE 0x61627374 // 'abst' 180 #define NAMED_COLOR_PROFILE 0x6e6d636c // 'nmcl' 181 182 static void read_class_signature(qcms_profile *profile, struct mem_source *mem) 183 { 184 profile->class = read_u32(mem, 12); 185 switch (profile->class) { 186 case DISPLAY_DEVICE_PROFILE: 187 case INPUT_DEVICE_PROFILE: 188 case OUTPUT_DEVICE_PROFILE: 189 case COLOR_SPACE_PROFILE: 190 break; 191 default: 192 invalid_source(mem, "Invalid Profile/Device Class signature"); 193 } 194 } 195 196 static void read_color_space(qcms_profile *profile, struct mem_source *mem) 197 { 198 profile->color_space = read_u32(mem, 16); 199 switch (profile->color_space) { 200 case RGB_SIGNATURE: 201 case GRAY_SIGNATURE: 202 break; 203 default: 204 invalid_source(mem, "Unsupported colorspace"); 205 } 206 } 207 208 static void read_pcs(qcms_profile *profile, struct mem_source *mem) 209 { 210 profile->pcs = read_u32(mem, 20); 211 switch (profile->pcs) { 212 case XYZ_SIGNATURE: 213 case LAB_SIGNATURE: 214 break; 215 default: 216 invalid_source(mem, "Unsupported pcs"); 217 } 218 } 219 220 struct tag 221 { 222 uint32_t signature; 223 uint32_t offset; 224 uint32_t size; 225 }; 226 227 struct tag_index { 228 uint32_t count; 229 struct tag *tags; 230 }; 231 232 static struct tag_index read_tag_table(qcms_profile *profile, struct mem_source *mem) 233 { 234 struct tag_index index = {0, NULL}; 235 unsigned int i; 236 237 index.count = read_u32(mem, 128); 238 if (index.count > MAX_TAG_COUNT) { 239 invalid_source(mem, "max number of tags exceeded"); 240 return index; 241 } 242 243 index.tags = malloc(sizeof(struct tag)*index.count); 244 if (index.tags) { 245 for (i = 0; i < index.count; i++) { 246 index.tags[i].signature = read_u32(mem, 128 + 4 + 4*i*3); 247 index.tags[i].offset = read_u32(mem, 128 + 4 + 4*i*3 + 4); 248 index.tags[i].size = read_u32(mem, 128 + 4 + 4*i*3 + 8); 249 } 250 } 251 252 return index; 253 } 254 255 // Checks a profile for obvious inconsistencies and returns 256 // true if the profile looks bogus and should probably be 257 // ignored. 258 qcms_bool qcms_profile_is_bogus(qcms_profile *profile) 259 { 260 float sum[3], target[3], tolerance[3]; 261 float rX, rY, rZ, gX, gY, gZ, bX, bY, bZ; 262 bool negative; 263 unsigned i; 264 265 // We currently only check the bogosity of RGB profiles 266 if (profile->color_space != RGB_SIGNATURE) 267 return false; 268 269 if (qcms_supports_iccv4 && (profile->A2B0 || profile->B2A0)) 270 return false; 271 272 rX = s15Fixed16Number_to_float(profile->redColorant.X); 273 rY = s15Fixed16Number_to_float(profile->redColorant.Y); 274 rZ = s15Fixed16Number_to_float(profile->redColorant.Z); 275 276 gX = s15Fixed16Number_to_float(profile->greenColorant.X); 277 gY = s15Fixed16Number_to_float(profile->greenColorant.Y); 278 gZ = s15Fixed16Number_to_float(profile->greenColorant.Z); 279 280 bX = s15Fixed16Number_to_float(profile->blueColorant.X); 281 bY = s15Fixed16Number_to_float(profile->blueColorant.Y); 282 bZ = s15Fixed16Number_to_float(profile->blueColorant.Z); 283 284 // Check if any of the XYZ values are negative (see mozilla bug 498245) 285 // CIEXYZ tristimulus values cannot be negative according to the spec. 286 negative = 287 (rX < 0) || (rY < 0) || (rZ < 0) || 288 (gX < 0) || (gY < 0) || (gZ < 0) || 289 (bX < 0) || (bY < 0) || (bZ < 0); 290 291 if (negative) 292 return true; 293 294 295 // Sum the values; they should add up to something close to white 296 sum[0] = rX + gX + bX; 297 sum[1] = rY + gY + bY; 298 sum[2] = rZ + gZ + bZ; 299 300 #if defined (_MSC_VER) 301 #pragma warning(push) 302 /* Disable double to float truncation warning 4305 */ 303 #pragma warning(disable:4305) 304 #endif 305 // Build our target vector (see mozilla bug 460629) 306 target[0] = 0.96420; 307 target[1] = 1.00000; 308 target[2] = 0.82491; 309 310 // Our tolerance vector - Recommended by Chris Murphy based on 311 // conversion from the LAB space criterion of no more than 3 in any one 312 // channel. This is similar to, but slightly more tolerant than Adobe's 313 // criterion. 314 tolerance[0] = 0.02; 315 tolerance[1] = 0.02; 316 tolerance[2] = 0.04; 317 318 #if defined (_MSC_VER) 319 /* Restore warnings */ 320 #pragma warning(pop) 321 #endif 322 // Compare with our tolerance 323 for (i = 0; i < 3; ++i) { 324 if (!(((sum[i] - tolerance[i]) <= target[i]) && 325 ((sum[i] + tolerance[i]) >= target[i]))) 326 return true; 327 } 328 329 // All Good 330 return false; 331 } 332 333 #define TAG_bXYZ 0x6258595a 334 #define TAG_gXYZ 0x6758595a 335 #define TAG_rXYZ 0x7258595a 336 #define TAG_rTRC 0x72545243 337 #define TAG_bTRC 0x62545243 338 #define TAG_gTRC 0x67545243 339 #define TAG_kTRC 0x6b545243 340 #define TAG_A2B0 0x41324230 341 #define TAG_B2A0 0x42324130 342 #define TAG_CHAD 0x63686164 343 344 static struct tag *find_tag(struct tag_index index, uint32_t tag_id) 345 { 346 unsigned int i; 347 struct tag *tag = NULL; 348 for (i = 0; i < index.count; i++) { 349 if (index.tags[i].signature == tag_id) { 350 return &index.tags[i]; 351 } 352 } 353 return tag; 354 } 355 356 #define XYZ_TYPE 0x58595a20 // 'XYZ ' 357 #define CURVE_TYPE 0x63757276 // 'curv' 358 #define PARAMETRIC_CURVE_TYPE 0x70617261 // 'para' 359 #define LUT16_TYPE 0x6d667432 // 'mft2' 360 #define LUT8_TYPE 0x6d667431 // 'mft1' 361 #define LUT_MAB_TYPE 0x6d414220 // 'mAB ' 362 #define LUT_MBA_TYPE 0x6d424120 // 'mBA ' 363 #define CHROMATIC_TYPE 0x73663332 // 'sf32' 364 365 static struct matrix read_tag_s15Fixed16ArrayType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 366 { 367 struct tag *tag = find_tag(index, tag_id); 368 struct matrix matrix; 369 if (tag) { 370 uint8_t i; 371 uint32_t offset = tag->offset; 372 uint32_t type = read_u32(src, offset); 373 374 // Check mandatory type signature for s16Fixed16ArrayType 375 if (type != CHROMATIC_TYPE) { 376 invalid_source(src, "unexpected type, expected 'sf32'"); 377 } 378 379 for (i = 0; i < 9; i++) { 380 matrix.m[i/3][i%3] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset+8+i*4)); 381 } 382 matrix.invalid = false; 383 } else { 384 matrix.invalid = true; 385 invalid_source(src, "missing sf32tag"); 386 } 387 return matrix; 388 } 389 390 static struct XYZNumber read_tag_XYZType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 391 { 392 struct XYZNumber num = {0, 0, 0}; 393 struct tag *tag = find_tag(index, tag_id); 394 if (tag) { 395 uint32_t offset = tag->offset; 396 397 uint32_t type = read_u32(src, offset); 398 if (type != XYZ_TYPE) 399 invalid_source(src, "unexpected type, expected XYZ"); 400 num.X = read_s15Fixed16Number(src, offset+8); 401 num.Y = read_s15Fixed16Number(src, offset+12); 402 num.Z = read_s15Fixed16Number(src, offset+16); 403 } else { 404 invalid_source(src, "missing xyztag"); 405 } 406 return num; 407 } 408 409 // Read the tag at a given offset rather then the tag_index. 410 // This method is used when reading mAB tags where nested curveType are 411 // present that are not part of the tag_index. 412 static struct curveType *read_curveType(struct mem_source *src, uint32_t offset, uint32_t *len) 413 { 414 static const uint32_t COUNT_TO_LENGTH[5] = {1, 3, 4, 5, 7}; 415 struct curveType *curve = NULL; 416 uint32_t type = read_u32(src, offset); 417 uint32_t count; 418 int i; 419 420 if (type != CURVE_TYPE && type != PARAMETRIC_CURVE_TYPE) { 421 invalid_source(src, "unexpected type, expected CURV or PARA"); 422 return NULL; 423 } 424 425 if (type == CURVE_TYPE) { 426 count = read_u32(src, offset+8); 427 428 #define MAX_CURVE_ENTRIES 40000 //arbitrary 429 if (count > MAX_CURVE_ENTRIES) { 430 invalid_source(src, "curve size too large"); 431 return NULL; 432 } 433 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*count); 434 if (!curve) 435 return NULL; 436 437 curve->count = count; 438 curve->type = type; 439 440 for (i=0; i<count; i++) { 441 curve->data[i] = read_u16(src, offset + 12 + i*2); 442 } 443 *len = 12 + count * 2; 444 } else { //PARAMETRIC_CURVE_TYPE 445 count = read_u16(src, offset+8); 446 447 if (count > 4) { 448 invalid_source(src, "parametric function type not supported."); 449 return NULL; 450 } 451 452 curve = malloc(sizeof(struct curveType)); 453 if (!curve) 454 return NULL; 455 456 curve->count = count; 457 curve->type = type; 458 459 for (i=0; i < COUNT_TO_LENGTH[count]; i++) { 460 curve->parameter[i] = s15Fixed16Number_to_float(read_s15Fixed16Number(src, offset + 12 + i*4)); 461 } 462 *len = 12 + COUNT_TO_LENGTH[count] * 4; 463 464 if ((count == 1 || count == 2)) { 465 /* we have a type 1 or type 2 function that has a division by 'a' */ 466 float a = curve->parameter[1]; 467 if (a == 0.f) 468 invalid_source(src, "parametricCurve definition causes division by zero."); 469 } 470 } 471 472 return curve; 473 } 474 475 static struct curveType *read_tag_curveType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 476 { 477 struct tag *tag = find_tag(index, tag_id); 478 struct curveType *curve = NULL; 479 if (tag) { 480 uint32_t len; 481 return read_curveType(src, tag->offset, &len); 482 } else { 483 invalid_source(src, "missing curvetag"); 484 } 485 486 return curve; 487 } 488 489 #define MAX_CLUT_SIZE 500000 // arbitrary 490 #define MAX_CHANNELS 10 // arbitrary 491 static void read_nested_curveType(struct mem_source *src, struct curveType *(*curveArray)[MAX_CHANNELS], uint8_t num_channels, uint32_t curve_offset) 492 { 493 uint32_t channel_offset = 0; 494 int i; 495 for (i = 0; i < num_channels; i++) { 496 uint32_t tag_len; 497 498 (*curveArray)[i] = read_curveType(src, curve_offset + channel_offset, &tag_len); 499 if (!(*curveArray)[i]) { 500 invalid_source(src, "invalid nested curveType curve"); 501 } 502 503 channel_offset += tag_len; 504 // 4 byte aligned 505 if ((tag_len % 4) != 0) 506 channel_offset += 4 - (tag_len % 4); 507 } 508 509 } 510 511 static void mAB_release(struct lutmABType *lut) 512 { 513 uint8_t i; 514 515 for (i = 0; i < lut->num_in_channels; i++){ 516 free(lut->a_curves[i]); 517 } 518 for (i = 0; i < lut->num_out_channels; i++){ 519 free(lut->b_curves[i]); 520 free(lut->m_curves[i]); 521 } 522 free(lut); 523 } 524 525 /* See section 10.10 for specs */ 526 static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 527 { 528 struct tag *tag = find_tag(index, tag_id); 529 uint32_t offset = tag->offset; 530 uint32_t a_curve_offset, b_curve_offset, m_curve_offset; 531 uint32_t matrix_offset; 532 uint32_t clut_offset; 533 uint32_t clut_size = 1; 534 uint8_t clut_precision; 535 uint32_t type = read_u32(src, offset); 536 uint8_t num_in_channels, num_out_channels; 537 struct lutmABType *lut; 538 int i; 539 540 if (type != LUT_MAB_TYPE && type != LUT_MBA_TYPE) { 541 return NULL; 542 } 543 544 num_in_channels = read_u8(src, offset + 8); 545 num_out_channels = read_u8(src, offset + 8); 546 if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS) 547 return NULL; 548 549 // We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB) 550 // XXX: If we remove this restriction make sure that the number of channels 551 // is less or equal to the maximum number of mAB curves in qcmsint.h 552 // also check for clut_size overflow. 553 if (num_in_channels != 3 || num_out_channels != 3) 554 return NULL; 555 556 // some of this data is optional and is denoted by a zero offset 557 // we also use this to track their existance 558 a_curve_offset = read_u32(src, offset + 28); 559 clut_offset = read_u32(src, offset + 24); 560 m_curve_offset = read_u32(src, offset + 20); 561 matrix_offset = read_u32(src, offset + 16); 562 b_curve_offset = read_u32(src, offset + 12); 563 564 // Convert offsets relative to the tag to relative to the profile 565 // preserve zero for optional fields 566 if (a_curve_offset) 567 a_curve_offset += offset; 568 if (clut_offset) 569 clut_offset += offset; 570 if (m_curve_offset) 571 m_curve_offset += offset; 572 if (matrix_offset) 573 matrix_offset += offset; 574 if (b_curve_offset) 575 b_curve_offset += offset; 576 577 if (clut_offset) { 578 assert (num_in_channels == 3); 579 // clut_size can not overflow since lg(256^num_in_channels) = 24 bits. 580 for (i = 0; i < num_in_channels; i++) { 581 clut_size *= read_u8(src, clut_offset + i); 582 } 583 } else { 584 clut_size = 0; 585 } 586 587 // 24bits * 3 won't overflow either 588 clut_size = clut_size * num_out_channels; 589 590 if (clut_size > MAX_CLUT_SIZE) 591 return NULL; 592 593 lut = malloc(sizeof(struct lutmABType) + (clut_size) * sizeof(float)); 594 if (!lut) 595 return NULL; 596 // we'll fill in the rest below 597 memset(lut, 0, sizeof(struct lutmABType)); 598 lut->clut_table = &lut->clut_table_data[0]; 599 600 for (i = 0; i < num_in_channels; i++) { 601 lut->num_grid_points[i] = read_u8(src, clut_offset + i); 602 } 603 604 // Reverse the processing of transformation elements for mBA type. 605 lut->reversed = (type == LUT_MBA_TYPE); 606 607 lut->num_in_channels = num_in_channels; 608 lut->num_out_channels = num_out_channels; 609 610 if (matrix_offset) { 611 // read the matrix if we have it 612 lut->e00 = read_s15Fixed16Number(src, matrix_offset+4*0); 613 lut->e01 = read_s15Fixed16Number(src, matrix_offset+4*1); 614 lut->e02 = read_s15Fixed16Number(src, matrix_offset+4*2); 615 lut->e10 = read_s15Fixed16Number(src, matrix_offset+4*3); 616 lut->e11 = read_s15Fixed16Number(src, matrix_offset+4*4); 617 lut->e12 = read_s15Fixed16Number(src, matrix_offset+4*5); 618 lut->e20 = read_s15Fixed16Number(src, matrix_offset+4*6); 619 lut->e21 = read_s15Fixed16Number(src, matrix_offset+4*7); 620 lut->e22 = read_s15Fixed16Number(src, matrix_offset+4*8); 621 lut->e03 = read_s15Fixed16Number(src, matrix_offset+4*9); 622 lut->e13 = read_s15Fixed16Number(src, matrix_offset+4*10); 623 lut->e23 = read_s15Fixed16Number(src, matrix_offset+4*11); 624 } 625 626 if (a_curve_offset) { 627 read_nested_curveType(src, &lut->a_curves, num_in_channels, a_curve_offset); 628 } 629 if (m_curve_offset) { 630 read_nested_curveType(src, &lut->m_curves, num_out_channels, m_curve_offset); 631 } 632 if (b_curve_offset) { 633 read_nested_curveType(src, &lut->b_curves, num_out_channels, b_curve_offset); 634 } else { 635 invalid_source(src, "B curves required"); 636 } 637 638 if (clut_offset) { 639 clut_precision = read_u8(src, clut_offset + 16); 640 if (clut_precision == 1) { 641 for (i = 0; i < clut_size; i++) { 642 lut->clut_table[i] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + 20 + i*1)); 643 } 644 } else if (clut_precision == 2) { 645 for (i = 0; i < clut_size; i++) { 646 lut->clut_table[i] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + 20 + i*2)); 647 } 648 } else { 649 invalid_source(src, "Invalid clut precision"); 650 } 651 } 652 653 if (!src->valid) { 654 mAB_release(lut); 655 return NULL; 656 } 657 658 return lut; 659 } 660 661 static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index index, uint32_t tag_id) 662 { 663 struct tag *tag = find_tag(index, tag_id); 664 uint32_t offset = tag->offset; 665 uint32_t type = read_u32(src, offset); 666 uint16_t num_input_table_entries; 667 uint16_t num_output_table_entries; 668 uint8_t in_chan, grid_points, out_chan; 669 size_t clut_offset, output_offset; 670 uint32_t clut_size; 671 size_t entry_size; 672 struct lutType *lut; 673 int i; 674 675 /* I'm not sure why the spec specifies a fixed number of entries for LUT8 tables even though 676 * they have room for the num_entries fields */ 677 if (type == LUT8_TYPE) { 678 num_input_table_entries = 256; 679 num_output_table_entries = 256; 680 entry_size = 1; 681 } else if (type == LUT16_TYPE) { 682 num_input_table_entries = read_u16(src, offset + 48); 683 num_output_table_entries = read_u16(src, offset + 50); 684 entry_size = 2; 685 } else { 686 assert(0); // the caller checks that this doesn't happen 687 invalid_source(src, "Unexpected lut type"); 688 return NULL; 689 } 690 691 in_chan = read_u8(src, offset + 8); 692 out_chan = read_u8(src, offset + 9); 693 grid_points = read_u8(src, offset + 10); 694 695 clut_size = pow(grid_points, in_chan); 696 if (clut_size > MAX_CLUT_SIZE) { 697 return NULL; 698 } 699 700 if (in_chan != 3 || out_chan != 3) { 701 return NULL; 702 } 703 704 lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan + clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float)); 705 if (!lut) { 706 return NULL; 707 } 708 709 /* compute the offsets of tables */ 710 lut->input_table = &lut->table_data[0]; 711 lut->clut_table = &lut->table_data[in_chan*num_input_table_entries]; 712 lut->output_table = &lut->table_data[in_chan*num_input_table_entries + clut_size*out_chan]; 713 714 lut->num_input_table_entries = num_input_table_entries; 715 lut->num_output_table_entries = num_output_table_entries; 716 lut->num_input_channels = read_u8(src, offset + 8); 717 lut->num_output_channels = read_u8(src, offset + 9); 718 lut->num_clut_grid_points = read_u8(src, offset + 10); 719 lut->e00 = read_s15Fixed16Number(src, offset+12); 720 lut->e01 = read_s15Fixed16Number(src, offset+16); 721 lut->e02 = read_s15Fixed16Number(src, offset+20); 722 lut->e10 = read_s15Fixed16Number(src, offset+24); 723 lut->e11 = read_s15Fixed16Number(src, offset+28); 724 lut->e12 = read_s15Fixed16Number(src, offset+32); 725 lut->e20 = read_s15Fixed16Number(src, offset+36); 726 lut->e21 = read_s15Fixed16Number(src, offset+40); 727 lut->e22 = read_s15Fixed16Number(src, offset+44); 728 729 for (i = 0; i < lut->num_input_table_entries * in_chan; i++) { 730 if (type == LUT8_TYPE) { 731 lut->input_table[i] = uInt8Number_to_float(read_uInt8Number(src, offset + 52 + i * entry_size)); 732 } else { 733 lut->input_table[i] = uInt16Number_to_float(read_uInt16Number(src, offset + 52 + i * entry_size)); 734 } 735 } 736 737 clut_offset = offset + 52 + lut->num_input_table_entries * in_chan * entry_size; 738 for (i = 0; i < clut_size * out_chan; i+=3) { 739 if (type == LUT8_TYPE) { 740 lut->clut_table[i+0] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 0)); 741 lut->clut_table[i+1] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 1)); 742 lut->clut_table[i+2] = uInt8Number_to_float(read_uInt8Number(src, clut_offset + i*entry_size + 2)); 743 } else { 744 lut->clut_table[i+0] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 0)); 745 lut->clut_table[i+1] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 2)); 746 lut->clut_table[i+2] = uInt16Number_to_float(read_uInt16Number(src, clut_offset + i*entry_size + 4)); 747 } 748 } 749 750 output_offset = clut_offset + clut_size * out_chan * entry_size; 751 for (i = 0; i < lut->num_output_table_entries * out_chan; i++) { 752 if (type == LUT8_TYPE) { 753 lut->output_table[i] = uInt8Number_to_float(read_uInt8Number(src, output_offset + i*entry_size)); 754 } else { 755 lut->output_table[i] = uInt16Number_to_float(read_uInt16Number(src, output_offset + i*entry_size)); 756 } 757 } 758 759 return lut; 760 } 761 762 static void read_rendering_intent(qcms_profile *profile, struct mem_source *src) 763 { 764 profile->rendering_intent = read_u32(src, 64); 765 switch (profile->rendering_intent) { 766 case QCMS_INTENT_PERCEPTUAL: 767 case QCMS_INTENT_SATURATION: 768 case QCMS_INTENT_RELATIVE_COLORIMETRIC: 769 case QCMS_INTENT_ABSOLUTE_COLORIMETRIC: 770 break; 771 default: 772 invalid_source(src, "unknown rendering intent"); 773 } 774 } 775 776 qcms_profile *qcms_profile_create(void) 777 { 778 return calloc(sizeof(qcms_profile), 1); 779 } 780 781 782 783 /* build sRGB gamma table */ 784 /* based on cmsBuildParametricGamma() */ 785 static uint16_t *build_sRGB_gamma_table(int num_entries) 786 { 787 int i; 788 /* taken from lcms: Build_sRGBGamma() */ 789 double gamma = 2.4; 790 double a = 1./1.055; 791 double b = 0.055/1.055; 792 double c = 1./12.92; 793 double d = 0.04045; 794 795 uint16_t *table = malloc(sizeof(uint16_t) * num_entries); 796 if (!table) 797 return NULL; 798 799 for (i=0; i<num_entries; i++) { 800 double x = (double)i / (num_entries-1); 801 double y, output; 802 // IEC 61966-2.1 (sRGB) 803 // Y = (aX + b)^Gamma | X >= d 804 // Y = cX | X < d 805 if (x >= d) { 806 double e = (a*x + b); 807 if (e > 0) 808 y = pow(e, gamma); 809 else 810 y = 0; 811 } else { 812 y = c*x; 813 } 814 815 // Saturate -- this could likely move to a separate function 816 output = y * 65535. + .5; 817 if (output > 65535.) 818 output = 65535; 819 if (output < 0) 820 output = 0; 821 table[i] = (uint16_t)floor(output); 822 } 823 return table; 824 } 825 826 static struct curveType *curve_from_table(uint16_t *table, int num_entries) 827 { 828 struct curveType *curve; 829 int i; 830 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); 831 if (!curve) 832 return NULL; 833 curve->type = CURVE_TYPE; 834 curve->count = num_entries; 835 for (i = 0; i < num_entries; i++) { 836 curve->data[i] = table[i]; 837 } 838 return curve; 839 } 840 841 static uint16_t float_to_u8Fixed8Number(float a) 842 { 843 if (a > (255.f + 255.f/256)) 844 return 0xffff; 845 else if (a < 0.f) 846 return 0; 847 else 848 return floor(a*256.f + .5f); 849 } 850 851 static struct curveType *curve_from_gamma(float gamma) 852 { 853 struct curveType *curve; 854 int num_entries = 1; 855 curve = malloc(sizeof(struct curveType) + sizeof(uInt16Number)*num_entries); 856 if (!curve) 857 return NULL; 858 curve->count = num_entries; 859 curve->data[0] = float_to_u8Fixed8Number(gamma); 860 return curve; 861 } 862 863 864 //XXX: it would be nice if we had a way of ensuring 865 // everything in a profile was initialized regardless of how it was created 866 867 //XXX: should this also be taking a black_point? 868 /* similar to CGColorSpaceCreateCalibratedRGB */ 869 qcms_profile* qcms_profile_create_rgb_with_gamma( 870 qcms_CIE_xyY white_point, 871 qcms_CIE_xyYTRIPLE primaries, 872 float gamma) 873 { 874 qcms_profile* profile = qcms_profile_create(); 875 if (!profile) 876 return NO_MEM_PROFILE; 877 878 //XXX: should store the whitepoint 879 if (!set_rgb_colorants(profile, white_point, primaries)) { 880 qcms_profile_release(profile); 881 return INVALID_PROFILE; 882 } 883 884 profile->redTRC = curve_from_gamma(gamma); 885 profile->blueTRC = curve_from_gamma(gamma); 886 profile->greenTRC = curve_from_gamma(gamma); 887 888 if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { 889 qcms_profile_release(profile); 890 return NO_MEM_PROFILE; 891 } 892 profile->class = DISPLAY_DEVICE_PROFILE; 893 profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; 894 profile->color_space = RGB_SIGNATURE; 895 return profile; 896 } 897 898 qcms_profile* qcms_profile_create_rgb_with_table( 899 qcms_CIE_xyY white_point, 900 qcms_CIE_xyYTRIPLE primaries, 901 uint16_t *table, int num_entries) 902 { 903 qcms_profile* profile = qcms_profile_create(); 904 if (!profile) 905 return NO_MEM_PROFILE; 906 907 //XXX: should store the whitepoint 908 if (!set_rgb_colorants(profile, white_point, primaries)) { 909 qcms_profile_release(profile); 910 return INVALID_PROFILE; 911 } 912 913 profile->redTRC = curve_from_table(table, num_entries); 914 profile->blueTRC = curve_from_table(table, num_entries); 915 profile->greenTRC = curve_from_table(table, num_entries); 916 917 if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) { 918 qcms_profile_release(profile); 919 return NO_MEM_PROFILE; 920 } 921 profile->class = DISPLAY_DEVICE_PROFILE; 922 profile->rendering_intent = QCMS_INTENT_PERCEPTUAL; 923 profile->color_space = RGB_SIGNATURE; 924 return profile; 925 } 926 927 /* from lcms: cmsWhitePointFromTemp */ 928 /* tempK must be >= 4000. and <= 25000. 929 * similar to argyll: icx_DTEMP2XYZ() */ 930 static qcms_CIE_xyY white_point_from_temp(int temp_K) 931 { 932 qcms_CIE_xyY white_point; 933 double x, y; 934 double T, T2, T3; 935 // double M1, M2; 936 937 // No optimization provided. 938 T = temp_K; 939 T2 = T*T; // Square 940 T3 = T2*T; // Cube 941 942 // For correlated color temperature (T) between 4000K and 7000K: 943 if (T >= 4000. && T <= 7000.) { 944 x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; 945 } else { 946 // or for correlated color temperature (T) between 7000K and 25000K: 947 if (T > 7000.0 && T <= 25000.0) { 948 x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; 949 } else { 950 assert(0 && "invalid temp"); 951 } 952 } 953 954 // Obtain y(x) 955 956 y = -3.000*(x*x) + 2.870*x - 0.275; 957 958 // wave factors (not used, but here for futures extensions) 959 960 // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); 961 // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); 962 963 // Fill white_point struct 964 white_point.x = x; 965 white_point.y = y; 966 white_point.Y = 1.0; 967 968 return white_point; 969 } 970 971 qcms_profile* qcms_profile_sRGB(void) 972 { 973 qcms_profile *profile; 974 uint16_t *table; 975 976 qcms_CIE_xyYTRIPLE Rec709Primaries = { 977 {0.6400, 0.3300, 1.0}, 978 {0.3000, 0.6000, 1.0}, 979 {0.1500, 0.0600, 1.0} 980 }; 981 qcms_CIE_xyY D65; 982 983 D65 = white_point_from_temp(6504); 984 985 table = build_sRGB_gamma_table(1024); 986 987 if (!table) 988 return NO_MEM_PROFILE; 989 990 profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024); 991 free(table); 992 return profile; 993 } 994 995 996 /* qcms_profile_from_memory does not hold a reference to the memory passed in */ 997 qcms_profile* qcms_profile_from_memory(const void *mem, size_t size) 998 { 999 uint32_t length; 1000 struct mem_source source; 1001 struct mem_source *src = &source; 1002 struct tag_index index; 1003 qcms_profile *profile; 1004 1005 source.buf = mem; 1006 source.size = size; 1007 source.valid = true; 1008 1009 length = read_u32(src, 0); 1010 if (length <= size) { 1011 // shrink the area that we can read if appropriate 1012 source.size = length; 1013 } else { 1014 return INVALID_PROFILE; 1015 } 1016 1017 /* ensure that the profile size is sane so it's easier to reason about */ 1018 if (source.size <= 64 || source.size >= MAX_PROFILE_SIZE) 1019 return INVALID_PROFILE; 1020 1021 profile = qcms_profile_create(); 1022 if (!profile) 1023 return NO_MEM_PROFILE; 1024 1025 check_CMM_type_signature(src); 1026 check_profile_version(src); 1027 read_class_signature(profile, src); 1028 read_rendering_intent(profile, src); 1029 read_color_space(profile, src); 1030 read_pcs(profile, src); 1031 //TODO read rest of profile stuff 1032 1033 if (!src->valid) 1034 goto invalid_profile; 1035 1036 index = read_tag_table(profile, src); 1037 if (!src->valid || !index.tags) 1038 goto invalid_tag_table; 1039 1040 if (find_tag(index, TAG_CHAD)) { 1041 profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD); 1042 } else { 1043 profile->chromaticAdaption.invalid = true; //Signal the data is not present 1044 } 1045 1046 if (profile->class == DISPLAY_DEVICE_PROFILE || profile->class == INPUT_DEVICE_PROFILE || 1047 profile->class == OUTPUT_DEVICE_PROFILE || profile->class == COLOR_SPACE_PROFILE) { 1048 if (profile->color_space == RGB_SIGNATURE) { 1049 if (find_tag(index, TAG_A2B0)) { 1050 if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT8_TYPE || 1051 read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT16_TYPE) { 1052 profile->A2B0 = read_tag_lutType(src, index, TAG_A2B0); 1053 } else if (read_u32(src, find_tag(index, TAG_A2B0)->offset) == LUT_MAB_TYPE) { 1054 profile->mAB = read_tag_lutmABType(src, index, TAG_A2B0); 1055 } 1056 } 1057 if (find_tag(index, TAG_B2A0)) { 1058 if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT8_TYPE || 1059 read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT16_TYPE) { 1060 profile->B2A0 = read_tag_lutType(src, index, TAG_B2A0); 1061 } else if (read_u32(src, find_tag(index, TAG_B2A0)->offset) == LUT_MBA_TYPE) { 1062 profile->mBA = read_tag_lutmABType(src, index, TAG_B2A0); 1063 } 1064 } 1065 if (find_tag(index, TAG_rXYZ) || !qcms_supports_iccv4) { 1066 profile->redColorant = read_tag_XYZType(src, index, TAG_rXYZ); 1067 profile->greenColorant = read_tag_XYZType(src, index, TAG_gXYZ); 1068 profile->blueColorant = read_tag_XYZType(src, index, TAG_bXYZ); 1069 } 1070 1071 if (!src->valid) 1072 goto invalid_tag_table; 1073 1074 if (find_tag(index, TAG_rTRC) || !qcms_supports_iccv4) { 1075 profile->redTRC = read_tag_curveType(src, index, TAG_rTRC); 1076 profile->greenTRC = read_tag_curveType(src, index, TAG_gTRC); 1077 profile->blueTRC = read_tag_curveType(src, index, TAG_bTRC); 1078 1079 if (!profile->redTRC || !profile->blueTRC || !profile->greenTRC) 1080 goto invalid_tag_table; 1081 } 1082 } else if (profile->color_space == GRAY_SIGNATURE) { 1083 1084 profile->grayTRC = read_tag_curveType(src, index, TAG_kTRC); 1085 if (!profile->grayTRC) 1086 goto invalid_tag_table; 1087 1088 } else { 1089 assert(0 && "read_color_space protects against entering here"); 1090 goto invalid_tag_table; 1091 } 1092 } else { 1093 goto invalid_tag_table; 1094 } 1095 1096 if (!src->valid) 1097 goto invalid_tag_table; 1098 1099 free(index.tags); 1100 1101 return profile; 1102 1103 invalid_tag_table: 1104 free(index.tags); 1105 invalid_profile: 1106 qcms_profile_release(profile); 1107 return INVALID_PROFILE; 1108 } 1109 1110 qcms_intent qcms_profile_get_rendering_intent(qcms_profile *profile) 1111 { 1112 return profile->rendering_intent; 1113 } 1114 1115 icColorSpaceSignature 1116 qcms_profile_get_color_space(qcms_profile *profile) 1117 { 1118 return profile->color_space; 1119 } 1120 1121 static void lut_release(struct lutType *lut) 1122 { 1123 free(lut); 1124 } 1125 1126 void qcms_profile_release(qcms_profile *profile) 1127 { 1128 if (profile->output_table_r) 1129 precache_release(profile->output_table_r); 1130 if (profile->output_table_g) 1131 precache_release(profile->output_table_g); 1132 if (profile->output_table_b) 1133 precache_release(profile->output_table_b); 1134 1135 if (profile->A2B0) 1136 lut_release(profile->A2B0); 1137 if (profile->B2A0) 1138 lut_release(profile->B2A0); 1139 1140 if (profile->mAB) 1141 mAB_release(profile->mAB); 1142 if (profile->mBA) 1143 mAB_release(profile->mBA); 1144 1145 free(profile->redTRC); 1146 free(profile->blueTRC); 1147 free(profile->greenTRC); 1148 free(profile->grayTRC); 1149 free(profile); 1150 } 1151 1152 1153 #include <stdio.h> 1154 qcms_profile* qcms_profile_from_file(FILE *file) 1155 { 1156 uint32_t length, remaining_length; 1157 qcms_profile *profile; 1158 size_t read_length; 1159 be32 length_be; 1160 void *data; 1161 1162 if (fread(&length_be, 1, sizeof(length_be), file) != sizeof(length_be)) 1163 return BAD_VALUE_PROFILE; 1164 1165 length = be32_to_cpu(length_be); 1166 if (length > MAX_PROFILE_SIZE || length < sizeof(length_be)) 1167 return BAD_VALUE_PROFILE; 1168 1169 /* allocate room for the entire profile */ 1170 data = malloc(length); 1171 if (!data) 1172 return NO_MEM_PROFILE; 1173 1174 /* copy in length to the front so that the buffer will contain the entire profile */ 1175 *((be32*)data) = length_be; 1176 remaining_length = length - sizeof(length_be); 1177 1178 /* read the rest profile */ 1179 read_length = fread((unsigned char*)data + sizeof(length_be), 1, remaining_length, file); 1180 if (read_length != remaining_length) { 1181 free(data); 1182 return INVALID_PROFILE; 1183 } 1184 1185 profile = qcms_profile_from_memory(data, length); 1186 free(data); 1187 return profile; 1188 } 1189 1190 qcms_profile* qcms_profile_from_path(const char *path) 1191 { 1192 qcms_profile *profile = NULL; 1193 FILE *file = fopen(path, "rb"); 1194 if (file) { 1195 profile = qcms_profile_from_file(file); 1196 fclose(file); 1197 } 1198 return profile; 1199 } 1200 1201 #ifdef _WIN32 1202 /* Unicode path version */ 1203 qcms_profile* qcms_profile_from_unicode_path(const wchar_t *path) 1204 { 1205 qcms_profile *profile = NULL; 1206 FILE *file = _wfopen(path, L"rb"); 1207 if (file) { 1208 profile = qcms_profile_from_file(file); 1209 fclose(file); 1210 } 1211 return profile; 1212 } 1213 #endif 1214