1 2 /* 3 * International Color Consortium Format Library (icclib) 4 * For ICC profile version 3.4 5 * 6 * Author: Graeme W. Gill 7 * Date: 2001/02/08 8 * Version: 2.00 9 * 10 * Copyright 1997, 1998, 1999, 2000, 2001 Graeme W. Gill 11 * See Licence.txt file for conditions of use. 12 */ 13 14 /* 15 * TTBD: 16 * 17 * NameColor Dump doesn't handle device space correctly - 18 * should use appropriate interpretation in case device is Lab etc. 19 * 20 * Should recognise & honour unicode 0xFFFE endian marker. 21 * Should generate it on writing too ? 22 * 23 * Should fix all write_number failure errors to indicate failed value. 24 * (Partially implimented - need to check all write_number functions) 25 * 26 * Make write fail error messages be specific on which element failed. 27 * 28 * Should add named color space lookup function support. 29 * 30 * Should probably reject reading or writing profiles with majv != 2 ? 31 * 32 * Would be nice to add generic ability to add new tag type handling, 33 * so that the base library doesn't need to be modified (ie. VideoCardGamma) ? 34 * 35 * Need to add DeviceSettings and OutputResponse tags to bring up to 36 * ICC.1:1998-09 [started] 37 * 38 */ 39 40 /* Trial: Make the default grid points of the Lab clut be symetrical about */ 41 /* a/b 0.0, and also make L = 100.0 fall on a grid point. */ 42 /* This seems a good idea. */ 43 44 #define SYMETRICAL_DEFAULT_LAB_RANGE 45 46 /* 47 * Change History: 48 * 49 * 2.00 50 * Change absolute conversion to be white point only, and use 51 * Bradford transform by default. (ie. we are now ignoring the 52 * comment in section 6.4.22 of the 1998 spec. about the 53 * media black point being used for absolute colorimetry, 54 * ignoring the recommendation on page 118 in section E.5, 55 * and are taking up the recommendation on page 124 in section 56 * E.16 that a more sophisticated chromatic adaption model be used.) 57 * 58 * This is for better compatibility with other CMM's, and to 59 * improve the results when using simple links between 60 * profiles with non-D50 white points. Standard profiles 61 * like sRGB will also be more accurate when interpreted 62 * with absolute colorimetric intent. 63 * This will cause some slight incompatibilty with previous 64 * versions of icclib. 65 * 66 * Added ColorSync 2.5 specific VideoCardGamma tag support 67 * (from Neil Okamoto) 68 * 69 * 1.31 70 * Added file I/O class to allow substitution of alternative ICC profile 71 * file access. Provide standard file class instance, and memory image 72 * instance of file I/O class as default and example. 73 * Added an optional new_icc_a() object creator, that takes a memory 74 * allocator class instance. This allows an alternate memory heap to 75 * be used with the icc class. 76 * Renamed object free() methods to del() for more consistency with new(). 77 * 78 * 1.30 79 * Added workaround for reading some Adobe profiles with confused header DateTime. 80 * Enhanced tag allocate() methods so that they can resize allocations. 81 * Enhanced icmLut_set_tables() to access grid points in a cache friendly order. 82 * Fixed bug in check_icc_legal() that caused bogus errors, removed 83 * uneccessary static declarations in icc.h, and fixed a bug in 84 * icmTable_lookup_bwd() that effected both accuracy and speed. (Thanks to Andrei Frolov) 85 * Removed icmAbsoluteColorimetricXYZ intent, and replaced it with 86 * a PCS overide capability. This adds a new parameter to get_luobj() 87 * Added Lab translations of some XYZ "dump" strings. 88 * Fix memory leak after failed tag read + rename_tag function 89 * + shared library support changes. (Thanks to Carles Llopis). 90 * Changed all the public 2str utility routines to a single function 91 * that can be used to interpret an enumeration or tag in a human 92 * readable form. 93 * 94 * 1.23 95 * Fixed important bug in Lut read/write. The matrix values had their 96 * rows and columns switched. Not many profiles exercise this code. 97 * Thanks to David Gillman for discovering this problem. 98 * Fixup compiler complains about illegal enum values for icmCurveStyle, 99 * and icmDataStyle. Malloc memory icmLut_lookup_clut_nl for gw[], so that 100 * it is more friendly to systems with a limited stack. (Thanks to Dave White) 101 * 102 * 1.22 99/11/11 Snapshot of current code. 103 * Added more hooks to support inherited implimentation of 104 * color conversion, used in Argyll to support reversing 105 * multi-dimentional table lookups. 106 * Cleaned up color conversion code to make it easier to follow. 107 * Adding simplex interpolation for non-Lab style input space interpolation. 108 * Fix Sun misalignment and realloc problems (Thanks to Allan N. Hessenflow) 109 * Fixed endian problem with Unicode on read and write. 110 * Expanded icmTextDescription_dump() to do hex dump of Unicode and ScriptCode. 111 * Changed over to ICC.1:1998-09 .h file. 112 * Started implimenting ICC.1:1998-09, but not complete yet! 113 * 114 * 1.21 99/2/14 115 * After re-reading Michael Bourgoin's 1998 SIGGRAPH notes, 116 * I have consolidated the Lut input index, and table value encodings. 117 * The default set_tables() scaling has been adjusted appropriately 118 * for this correction of Lab encoding. 119 * Trying to create an 8 bit XYZ Lut will now fail if icclib helper 120 * functions are used to create it. 121 * 122 * 1.20 99/2/7 123 * Added profile color lookup functon. 124 * Added set_tables() support. 125 * Various bug fixes and enhancements. 126 */ 127 128 #include <stdio.h> 129 #include <stdlib.h> 130 #include <stdarg.h> 131 #include <sys/types.h> 132 #include <string.h> 133 #include <ctype.h> 134 #include <math.h> 135 #include <time.h> 136 #ifdef __sun 137 #include <unistd.h> 138 #endif 139 #if defined(__IBMC__) && defined(_M_IX86) 140 #include <float.h> 141 #endif 142 #include "icc.h" 143 144 /* ========================================================== */ 145 /* Default system interface object implimentations */ 146 147 /* Standard Stream file I/O icmFile compatible class */ 148 /* Note that this uses malloc, so replace class if */ 149 /* you need a different memory allocator. */ 150 151 /* Set current position to offset. Return 0 on success, nz on failure. */ 152 static int icmFileStd_seek( 153 icmFile *pp, 154 long int offset 155 ) { 156 icmFileStd *p = (icmFileStd *)pp; 157 158 return fseek(p->fp, offset, SEEK_SET); 159 } 160 161 /* Read count items of size length. Return number of items successfully read. */ 162 static size_t icmFileStd_read( 163 icmFile *pp, 164 void *buffer, 165 size_t size, 166 size_t count 167 ) { 168 icmFileStd *p = (icmFileStd *)pp; 169 170 return fread(buffer, size, count, p->fp); 171 } 172 173 /* write count items of size length. Return number of items successfully written. */ 174 static size_t icmFileStd_write( 175 icmFile *pp, 176 void *buffer, 177 size_t size, 178 size_t count 179 ) { 180 icmFileStd *p = (icmFileStd *)pp; 181 182 return fwrite(buffer, size, count, p->fp); 183 } 184 185 186 /* flush all write data out to secondary storage. Return nz on failure. */ 187 static int icmFileStd_flush( 188 icmFile *pp 189 ) { 190 icmFileStd *p = (icmFileStd *)pp; 191 192 return fflush(p->fp); 193 } 194 195 /* we're done with the file object, return nz on failure */ 196 static int icmFileStd_delete( 197 icmFile *pp 198 ) { 199 icmFileStd *p = (icmFileStd *)pp; 200 201 if (p->doclose != 0) { 202 if (fclose(p->fp) != 0) 203 return 2; 204 } 205 206 free(p); 207 return 0; 208 } 209 210 /* Create icmFile given a (binary) FILE* */ 211 icmFile *new_icmFileStd_fp( 212 FILE *fp 213 ) { 214 icmFileStd *p; 215 if ((p = (icmFileStd *) calloc(1,sizeof(icmFileStd))) == NULL) 216 return NULL; 217 p->seek = icmFileStd_seek; 218 p->read = icmFileStd_read; 219 p->write = icmFileStd_write; 220 p->flush = icmFileStd_flush; 221 p->del = icmFileStd_delete; 222 223 p->fp = fp; 224 p->doclose = 0; 225 226 return (icmFile *)p; 227 } 228 229 /* Create icmFile given a file name */ 230 icmFile *new_icmFileStd_name( 231 char *name, 232 char *mode 233 ) { 234 FILE *fp; 235 icmFile *p; 236 #if defined(O_BINARY) 237 char nmode[50]; 238 #endif 239 240 if ((fp = fopen(name,mode)) == NULL) 241 return NULL; 242 243 #if defined(O_BINARY) 244 strcpy(nmode, mode); 245 strcat(nmode, "b"); 246 if ((fp = freopen(name, nmode, fp)) == NULL) 247 return NULL; 248 #endif 249 250 p = new_icmFileStd_fp(fp); 251 252 if (p != NULL) { 253 icmFileStd *pp = (icmFileStd *)p; 254 pp->doclose = 1; 255 } 256 return p; 257 } 258 259 /* ------------------------------------------------- */ 260 /* Memory image icmFile compatible class */ 261 /* Note that this uses malloc, so replace class if */ 262 /* you need a different memory allocator. */ 263 264 /* Set current position to offset. Return 0 on success, nz on failure. */ 265 static int icmFileMem_seek( 266 icmFile *pp, 267 long int offset 268 ) { 269 icmFileMem *p = (icmFileMem *)pp; 270 unsigned char *np; 271 272 np = p->start + offset; 273 if (np < p->start || np >= p->end) 274 return 1; 275 p->cur = np; 276 return 0; 277 } 278 279 /* Read count items of size length. Return number of items successfully read. */ 280 static size_t icmFileMem_read( 281 icmFile *pp, 282 void *buffer, 283 size_t size, 284 size_t count 285 ) { 286 icmFileMem *p = (icmFileMem *)pp; 287 size_t len; 288 289 len = size * count; 290 if ((p->cur + len) >= p->end) { /* Too much */ 291 if (size > 0) 292 count = (p->end - p->cur)/size; 293 else 294 count = 0; 295 } 296 len = size * count; 297 if (len > 0) 298 memcpy (buffer, p->cur, len); 299 p->cur += len; 300 return count; 301 } 302 303 /* write count items of size length. Return number of items successfully written. */ 304 static size_t icmFileMem_write( 305 icmFile *pp, 306 void *buffer, 307 size_t size, 308 size_t count 309 ) { 310 icmFileMem *p = (icmFileMem *)pp; 311 size_t len; 312 313 len = size * count; 314 if ((p->cur + len) >= p->end) { /* Too much */ 315 if (size > 0) 316 count = (p->end - p->cur)/size; 317 else 318 count = 0; 319 } 320 len = size * count; 321 if (len > 0) 322 memcpy (p->cur, buffer, len); 323 p->cur += len; 324 return count; 325 } 326 327 328 /* flush all write data out to secondary storage. Return nz on failure. */ 329 static int icmFileMem_flush( 330 icmFile *pp 331 ) { 332 icmFileMem *p = (icmFileMem *)pp; 333 334 return 0; 335 } 336 337 /* we're done with the file object, return nz on failure */ 338 static int icmFileMem_delete( 339 icmFile *pp 340 ) { 341 icmFileMem *p = (icmFileMem *)pp; 342 343 free(p); 344 return 0; 345 } 346 347 /* Create a memory image file access class */ 348 icmFile *new_icmFileMem( 349 void *base, /* Pointer to base of memory buffer */ 350 size_t length /* Number of bytes in buffer */ 351 ) { 352 icmFileMem *p; 353 if ((p = (icmFileMem *) calloc(1,sizeof(icmFileMem))) == NULL) 354 return NULL; 355 p->seek = icmFileMem_seek; 356 p->read = icmFileMem_read; 357 p->write = icmFileMem_write; 358 p->flush = icmFileMem_flush; 359 p->del = icmFileMem_delete; 360 361 p->cur = p->start = base; 362 p->end = p->start + length; 363 364 return (icmFile *)p; 365 } 366 367 /* ------------------------------------------------- */ 368 /* Standard Heap allocator icmAlloc compatible class */ 369 /* Just call the standard system function */ 370 371 static void *icmAllocStd_malloc( 372 struct _icmAlloc *pp, 373 size_t size 374 ) { 375 icmAllocStd *p = (icmAllocStd *)pp; 376 377 return malloc(size); 378 } 379 380 static void *icmAllocStd_calloc( 381 struct _icmAlloc *pp, 382 size_t num, 383 size_t size 384 ) { 385 icmAllocStd *p = (icmAllocStd *)pp; 386 387 return calloc(num, size); 388 } 389 390 void *icmAllocStd_realloc( 391 struct _icmAlloc *pp, 392 void *ptr, 393 size_t size 394 ) { 395 icmAllocStd *p = (icmAllocStd *)pp; 396 397 return realloc(ptr, size); 398 } 399 400 401 static void icmAllocStd_free( 402 struct _icmAlloc *pp, 403 void *ptr 404 ) { 405 icmAllocStd *p = (icmAllocStd *)pp; 406 407 free(ptr); 408 } 409 410 /* we're done with the AllocStd object */ 411 static void icmAllocStd_delete( 412 icmAlloc *pp 413 ) { 414 icmAllocStd *p = (icmAllocStd *)pp; 415 416 free(p); 417 } 418 419 /* Create icmAllocStd */ 420 icmAlloc *new_icmAllocStd() { 421 icmAllocStd *p; 422 if ((p = (icmAllocStd *) calloc(1,sizeof(icmAllocStd))) == NULL) 423 return NULL; 424 p->malloc = icmAllocStd_malloc; 425 p->calloc = icmAllocStd_calloc; 426 p->realloc = icmAllocStd_realloc; 427 p->free = icmAllocStd_free; 428 p->del = icmAllocStd_delete; 429 430 return (icmAlloc *)p; 431 } 432 433 /* ========================================================== */ 434 /* Conversion support functions */ 435 /* Convert between ICC storage types and native C types */ 436 /* Write routine return non-zero if numbers can't be represented */ 437 438 /* Unsigned */ 439 static unsigned int read_UInt8Number(char *p) { 440 unsigned int rv; 441 rv = (unsigned int)((ORD8 *)p)[0]; 442 return rv; 443 } 444 445 static int write_UInt8Number(unsigned int d, char *p) { 446 if (d > 255) 447 return 1; 448 ((ORD8 *)p)[0] = (ORD8)d; 449 return 0; 450 } 451 452 static unsigned int read_UInt16Number(char *p) { 453 unsigned int rv; 454 rv = 256 * (unsigned int)((ORD8 *)p)[0] 455 + (unsigned int)((ORD8 *)p)[1]; 456 return rv; 457 } 458 459 static int write_UInt16Number(unsigned int d, char *p) { 460 if (d > 65535) 461 return 1; 462 ((ORD8 *)p)[0] = (ORD8)(d >> 8); 463 ((ORD8 *)p)[1] = (ORD8)(d); 464 return 0; 465 } 466 467 static unsigned int read_UInt32Number(char *p) { 468 unsigned int rv; 469 rv = 16777216 * (unsigned int)((ORD8 *)p)[0] 470 + 65536 * (unsigned int)((ORD8 *)p)[1] 471 + 256 * (unsigned int)((ORD8 *)p)[2] 472 + (unsigned int)((ORD8 *)p)[3]; 473 return rv; 474 } 475 476 static int write_UInt32Number(unsigned int d, char *p) { 477 ((ORD8 *)p)[0] = (ORD8)(d >> 24); 478 ((ORD8 *)p)[1] = (ORD8)(d >> 16); 479 ((ORD8 *)p)[2] = (ORD8)(d >> 8); 480 ((ORD8 *)p)[3] = (ORD8)(d); 481 return 0; 482 } 483 484 static void read_UInt64Number(uint64 *d, char *p) { 485 d->h = 16777216 * (unsigned int)((ORD8 *)p)[0] 486 + 65536 * (unsigned int)((ORD8 *)p)[1] 487 + 256 * (unsigned int)((ORD8 *)p)[2] 488 + (unsigned int)((ORD8 *)p)[3]; 489 d->l = 16777216 * (unsigned int)((ORD8 *)p)[4] 490 + 65536 * (unsigned int)((ORD8 *)p)[5] 491 + 256 * (unsigned int)((ORD8 *)p)[6] 492 + (unsigned int)((ORD8 *)p)[7]; 493 } 494 495 static int write_UInt64Number(uint64 *d, char *p) { 496 ((ORD8 *)p)[0] = (ORD8)(d->h >> 24); 497 ((ORD8 *)p)[1] = (ORD8)(d->h >> 16); 498 ((ORD8 *)p)[2] = (ORD8)(d->h >> 8); 499 ((ORD8 *)p)[3] = (ORD8)(d->h); 500 ((ORD8 *)p)[4] = (ORD8)(d->l >> 24); 501 ((ORD8 *)p)[5] = (ORD8)(d->l >> 16); 502 ((ORD8 *)p)[6] = (ORD8)(d->l >> 8); 503 ((ORD8 *)p)[7] = (ORD8)(d->l); 504 return 0; 505 } 506 507 static double read_U8Fixed8Number(char *p) { 508 ORD32 o32; 509 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */ 510 + (ORD32)((ORD8 *)p)[1]; 511 return (double)o32/256.0; 512 } 513 514 static int write_U8Fixed8Number(double d, char *p) { 515 ORD32 o32; 516 d = d * 256.0 + 0.5; 517 if (d >= 65536.0) 518 return 1; 519 if (d < 0.0) 520 return 1; 521 o32 = (ORD32)d; 522 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8); 523 ((ORD8 *)p)[1] = (ORD8)((o32)); 524 return 0; 525 } 526 527 static double read_U16Fixed16Number(char *p) { 528 ORD32 o32; 529 o32 = 16777216 * (ORD32)((ORD8 *)p)[0] /* Read big endian 32 bit unsigned */ 530 + 65536 * (ORD32)((ORD8 *)p)[1] 531 + 256 * (ORD32)((ORD8 *)p)[2] 532 + (ORD32)((ORD8 *)p)[3]; 533 return (double)o32/65536.0; 534 } 535 536 static int write_U16Fixed16Number(double d, char *p) { 537 ORD32 o32; 538 d = d * 65536.0 + 0.5; 539 if (d >= 4294967296.0) 540 return 1; 541 if (d < 0.0) 542 return 1; 543 o32 = (ORD32)d; 544 ((ORD8 *)p)[0] = (ORD8)((o32) >> 24); 545 ((ORD8 *)p)[1] = (ORD8)((o32) >> 16); 546 ((ORD8 *)p)[2] = (ORD8)((o32) >> 8); 547 ((ORD8 *)p)[3] = (ORD8)((o32)); 548 return 0; 549 } 550 551 552 /* Signed numbers */ 553 static int read_SInt8Number(char *p) { 554 int rv; 555 rv = (int)((INT8 *)p)[0]; 556 return rv; 557 } 558 559 static int write_SInt8Number(int d, char *p) { 560 if (d > 127) 561 return 1; 562 else if (d < -128) 563 return 1; 564 ((INT8 *)p)[0] = (INT8)d; 565 return 0; 566 } 567 568 static int read_SInt16Number(char *p) { 569 int rv; 570 rv = 256 * (int)((INT8 *)p)[0] 571 + (int)((ORD8 *)p)[1]; 572 return rv; 573 } 574 575 static int write_SInt16Number(int d, char *p) { 576 if (d > 32767) 577 return 1; 578 else if (d < -32768) 579 return 1; 580 ((INT8 *)p)[0] = (INT8)(d >> 8); 581 ((ORD8 *)p)[1] = (ORD8)(d); 582 return 0; 583 } 584 585 static int read_SInt32Number(char *p) { 586 int rv; 587 rv = 16777216 * (int)((INT8 *)p)[0] 588 + 65536 * (int)((ORD8 *)p)[1] 589 + 256 * (int)((ORD8 *)p)[2] 590 + (int)((ORD8 *)p)[3]; 591 return rv; 592 } 593 594 static int write_SInt32Number(int d, char *p) { 595 ((INT8 *)p)[0] = (INT8)(d >> 24); 596 ((ORD8 *)p)[1] = (ORD8)(d >> 16); 597 ((ORD8 *)p)[2] = (ORD8)(d >> 8); 598 ((ORD8 *)p)[3] = (ORD8)(d); 599 return 0; 600 } 601 602 static void read_SInt64Number(int64 *d, char *p) { 603 d->h = 16777216 * (int)((INT8 *)p)[0] 604 + 65536 * (int)((ORD8 *)p)[1] 605 + 256 * (int)((ORD8 *)p)[2] 606 + (int)((ORD8 *)p)[3]; 607 d->l = 16777216 * (unsigned int)((ORD8 *)p)[4] 608 + 65536 * (unsigned int)((ORD8 *)p)[5] 609 + 256 * (unsigned int)((ORD8 *)p)[6] 610 + (unsigned int)((ORD8 *)p)[7]; 611 } 612 613 static int write_SInt64Number(int64 *d, char *p) { 614 ((INT8 *)p)[0] = (INT8)(d->h >> 24); 615 ((ORD8 *)p)[1] = (ORD8)(d->h >> 16); 616 ((ORD8 *)p)[2] = (ORD8)(d->h >> 8); 617 ((ORD8 *)p)[3] = (ORD8)(d->h); 618 ((ORD8 *)p)[4] = (ORD8)(d->l >> 24); 619 ((ORD8 *)p)[5] = (ORD8)(d->l >> 16); 620 ((ORD8 *)p)[6] = (ORD8)(d->l >> 8); 621 ((ORD8 *)p)[7] = (ORD8)(d->l); 622 return 0; 623 } 624 625 static double read_S15Fixed16Number(char *p) { 626 INT32 i32; 627 i32 = 16777216 * (INT32)((INT8 *)p)[0] /* Read big endian 32 bit signed */ 628 + 65536 * (INT32)((ORD8 *)p)[1] 629 + 256 * (INT32)((ORD8 *)p)[2] 630 + (INT32)((ORD8 *)p)[3]; 631 return (double)i32/65536.0; 632 } 633 634 static int write_S15Fixed16Number(double d, char *p) { 635 INT32 i32; 636 d = ceil(d * 65536.0); /* Beware! (int)(d + 0.5) doesn't work! */ 637 if (d >= 2147483648.0) 638 return 1; 639 if (d < -2147483648.0) 640 return 1; 641 i32 = (INT32)d; 642 ((INT8 *)p)[0] = (INT8)((i32) >> 24); /* Write big endian 32 bit signed */ 643 ((ORD8 *)p)[1] = (ORD8)((i32) >> 16); 644 ((ORD8 *)p)[2] = (ORD8)((i32) >> 8); 645 ((ORD8 *)p)[3] = (ORD8)((i32)); 646 return 0; 647 } 648 649 /* PCS encoded numbers */ 650 651 /* 16 bit XYZ - value range 0.0 - 1.9997 */ 652 static double read_PCSXYZ16Number(char *p) { 653 ORD32 o32; 654 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */ 655 + (ORD32)((ORD8 *)p)[1]; 656 return (double)o32/32768.0; 657 } 658 659 static int write_PCSXYZ16Number(double d, char *p) { 660 ORD32 o32; 661 d = d * 32768.0 + 0.5; 662 if (d >= 65536.0) 663 return 1; 664 if (d < 0.0) 665 return 1; 666 o32 = (ORD32)d; 667 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8); 668 ((ORD8 *)p)[1] = (ORD8)((o32)); 669 return 0; 670 } 671 672 /* L part of 8 bit Lab - value range 0.0 - 100.0 */ 673 static double read_PCSL8Number(char *p) { 674 ORD32 o32; 675 o32 = (ORD32)((ORD8 *)p)[0]; /* Read big endian 8 bit unsigned */ 676 return (double)o32/2.550; 677 } 678 679 static int write_PCSL8Number(double d, char *p) { 680 ORD32 o32; 681 d = d * 2.550 + 0.5; 682 if (d >= 256.0) 683 return 1; 684 if (d < 0.0) 685 return 1; 686 o32 = (ORD32)d; 687 ((ORD8 *)p)[0] = (ORD8)((o32)); 688 return 0; 689 } 690 691 /* ab part of 8 bit Lab - value range -128.0 - 127.0 */ 692 static double read_PCSab8Number(char *p) { 693 ORD32 o32; 694 o32 = (ORD32)((ORD8 *)p)[0]; /* Read big endian 8 bit unsigned */ 695 return (double)o32-128.0; 696 } 697 698 static int write_PCSab8Number(double d, char *p) { 699 ORD32 o32; 700 d = (d+128.0) + 0.5; 701 if (d >= 256.0) 702 return 1; 703 if (d < 0.0) 704 return 1; 705 o32 = (ORD32)d; 706 ((ORD8 *)p)[0] = (ORD8)((o32)); 707 return 0; 708 } 709 710 /* L part of 16 bit Lab - value range 0.0 - 100.0 */ 711 static double read_PCSL16Number(char *p) { 712 ORD32 o32; 713 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */ 714 + (ORD32)((ORD8 *)p)[1]; 715 return (double)o32/652.800; /* 0xff00/100.0 */ 716 } 717 718 static int write_PCSL16Number(double d, char *p) { 719 ORD32 o32; 720 d = d * 652.800 + 0.5; 721 if (d >= 65536.0) 722 return 1; 723 if (d < 0.0) 724 return 1; 725 o32 = (ORD32)d; 726 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8); 727 ((ORD8 *)p)[1] = (ORD8)((o32)); 728 return 0; 729 } 730 731 /* ab part of 16 bit Lab - value range -128.0 - 127.9961 */ 732 static double read_PCSab16Number(char *p) { 733 ORD32 o32; 734 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */ 735 + (ORD32)((ORD8 *)p)[1]; 736 return ((double)o32/256.0)-128.0; 737 } 738 739 static int write_PCSab16Number(double d, char *p) { 740 ORD32 o32; 741 d = (d+128.0) * 256.0 + 0.5; 742 if (d >= 65536.0) 743 return 1; 744 if (d < 0.0) 745 return 1; 746 o32 = (ORD32)d; 747 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8); 748 ((ORD8 *)p)[1] = (ORD8)((o32)); 749 return 0; 750 } 751 752 /* Device coordinate as 8 bit value range 0.0 - 1.0 */ 753 static double read_DCS8Number(char *p) { 754 unsigned int rv; 755 rv = (unsigned int)((ORD8 *)p)[0]; 756 return (double)rv/255.0; 757 } 758 759 static int write_DCS8Number(double d, char *p) { 760 ORD32 o32; 761 d = d * 255.0 + 0.5; 762 if (d >= 256.0) 763 return 1; 764 if (d < 0.0) 765 return 1; 766 o32 = (ORD32)d; 767 ((ORD8 *)p)[0] = (ORD8)(o32); 768 return 0; 769 } 770 771 /* Device coordinate as 16 bit value range 0.0 - 1.0 */ 772 static double read_DCS16Number(char *p) { 773 unsigned int rv; 774 rv = 256 * (unsigned int)((ORD8 *)p)[0] 775 + (unsigned int)((ORD8 *)p)[1]; 776 return (double)rv/65535.0; 777 } 778 779 static int write_DCS16Number(double d, char *p) { 780 ORD32 o32; 781 d = d * 65535.0 + 0.5; 782 if (d >= 65536.0) 783 return 1; 784 if (d < 0.0) 785 return 1; 786 o32 = (ORD32)d; 787 ((ORD8 *)p)[0] = (ORD8)(o32 >> 8); 788 ((ORD8 *)p)[1] = (ORD8)(o32); 789 return 0; 790 } 791 792 /* ---------------------------------------------------------- */ 793 /* Auiliary function - return a string that represents a tag */ 794 /* Note - returned buffers are static, can only be used 5 */ 795 /* times before buffers get reused. */ 796 char *tag2str( 797 int tag 798 ) { 799 int i; 800 static int si = 0; /* String buffer index */ 801 static char buf[5][20]; /* String buffers */ 802 char *bp; 803 unsigned char c[4]; 804 805 bp = buf[si++]; 806 si %= 5; /* Rotate through buffers */ 807 808 c[0] = 0xff & (tag >> 24); 809 c[1] = 0xff & (tag >> 16); 810 c[2] = 0xff & (tag >> 8); 811 c[3] = 0xff & (tag >> 0); 812 for (i = 0; i < 4; i++) { /* Can we represent it as a string ? */ 813 if (!isprint(c[i])) 814 break; 815 } 816 if (i < 4) { /* Not printable - use hex */ 817 sprintf(bp,"0x%x",tag); 818 } else { /* Printable */ 819 sprintf(bp,"'%c%c%c%c'",c[0],c[1],c[2],c[3]); 820 } 821 return bp; 822 } 823 824 /* Auiliary function - return a tag created from a string */ 825 int str2tag( 826 char *str 827 ) { 828 unsigned long tag; 829 tag = (((unsigned long)str[0]) << 24) 830 + (((unsigned long)str[1]) << 16) 831 + (((unsigned long)str[2]) << 8) 832 + (((unsigned long)str[3])); 833 return (int)tag; 834 } 835 836 /* helper - return 1 if the string doesn't have a */ 837 /* null terminator, return 0 if it does. */ 838 /* Note: will return 1 if len == 0 */ 839 static int check_null_string(char *cp, int len) { 840 for (; len > 0; len--) { 841 if (*cp++ == '\000') 842 break; 843 } 844 if (len == 0) 845 return 1; 846 return 0; 847 } 848 849 /* helper - return 1 if the string doesn't have a */ 850 /* null terminator, return 0 if it does. */ 851 /* Note: will return 1 if len == 0 */ 852 /* Unicode version */ 853 static int check_null_string16(char *cp, int len) { 854 for (; len > 0; len--) { /* Length is in characters */ 855 if (cp[0] == 0 && cp[1] == 0) 856 break; 857 cp += 2; 858 } 859 if (len == 0) 860 return 1; 861 return 0; 862 } 863 864 /* Color Space to number of component conversion */ 865 /* Return 0 on error */ 866 static unsigned int number_ColorSpaceSignature(icColorSpaceSignature sig) { 867 switch(sig) { 868 case icSigXYZData: 869 return 3; 870 case icSigLabData: 871 return 3; 872 case icSigLuvData: 873 return 3; 874 case icSigYCbCrData: 875 return 3; 876 case icSigYxyData: 877 return 3; 878 case icSigRgbData: 879 return 3; 880 case icSigGrayData: 881 return 1; 882 case icSigHsvData: 883 return 3; 884 case icSigHlsData: 885 return 3; 886 case icSigCmykData: 887 return 4; 888 case icSigCmyData: 889 return 3; 890 case icSig2colorData: 891 return 2; 892 case icSig3colorData: 893 return 3; 894 case icSig4colorData: 895 return 4; 896 case icSig5colorData: 897 case icSigMch5Data: 898 return 5; 899 case icSig6colorData: 900 case icSigMch6Data: 901 return 6; 902 case icSig7colorData: 903 case icSigMch7Data: 904 return 7; 905 case icSig8colorData: 906 case icSigMch8Data: 907 return 8; 908 case icSig9colorData: 909 return 9; 910 case icSig10colorData: 911 return 10; 912 case icSig11colorData: 913 return 11; 914 case icSig12colorData: 915 return 12; 916 case icSig13colorData: 917 return 13; 918 case icSig14colorData: 919 return 14; 920 case icSig15colorData: 921 return 15; 922 } 923 return 0; 924 } 925 926 /* ------------------------------------------------------- */ 927 /* Flag dump functions */ 928 /* Note - returned buffers are static, can only be used 5 */ 929 /* times before buffers get reused. */ 930 931 /* Screening Encodings */ 932 static char *string_ScreenEncodings(unsigned long flags) { 933 static int si = 0; /* String buffer index */ 934 static char buf[5][80]; /* String buffers */ 935 char *bp, *cp; 936 937 cp = bp = buf[si++]; 938 si %= 5; /* Rotate through buffers */ 939 940 if (flags & icPrtrDefaultScreensTrue) { 941 sprintf(cp,"Default Screen"); 942 } else { 943 sprintf(cp,"No Default Screen"); 944 } 945 cp = cp + strlen(cp); 946 if (flags & icLinesPerInch) { 947 sprintf(cp,", Lines Per Inch"); 948 } else { 949 sprintf(cp,", Lines Per cm"); 950 } 951 cp = cp + strlen(cp); 952 953 return bp; 954 } 955 956 /* Device attributes */ 957 static char *string_DeviceAttributes(unsigned long flags) { 958 static int si = 0; /* String buffer index */ 959 static char buf[5][80]; /* String buffers */ 960 char *bp, *cp; 961 962 cp = bp = buf[si++]; 963 si %= 5; /* Rotate through buffers */ 964 965 if (flags & icTransparency) { 966 sprintf(cp,"Transparency"); 967 } else { 968 sprintf(cp,"Reflective"); 969 } 970 cp = cp + strlen(cp); 971 if (flags & icMatte) { 972 sprintf(cp,", Matte"); 973 } else { 974 sprintf(cp,", Glossy"); 975 } 976 cp = cp + strlen(cp); 977 978 return bp; 979 } 980 981 /* Profile header flags */ 982 static char *string_ProfileHeaderFlags(unsigned long flags) { 983 static int si = 0; /* String buffer index */ 984 static char buf[5][80]; /* String buffers */ 985 char *bp, *cp; 986 987 cp = bp = buf[si++]; 988 si %= 5; /* Rotate through buffers */ 989 990 if (flags & icEmbeddedProfileTrue) { 991 sprintf(cp,"Embedded Profile"); 992 } else { 993 sprintf(cp,"Not Embedded Profile"); 994 } 995 cp = cp + strlen(cp); 996 if (flags & icUseWithEmbeddedDataOnly) { 997 sprintf(cp,", Use with embedded data only"); 998 } else { 999 sprintf(cp,", Use anywhere"); 1000 } 1001 cp = cp + strlen(cp); 1002 1003 return bp; 1004 } 1005 1006 1007 static char *string_AsciiOrBinaryData(unsigned long flags) { 1008 static int si = 0; /* String buffer index */ 1009 static char buf[5][80]; /* String buffers */ 1010 char *bp, *cp; 1011 1012 cp = bp = buf[si++]; 1013 si %= 5; /* Rotate through buffers */ 1014 1015 if (flags & icBinaryData) { 1016 sprintf(cp,"Binary"); 1017 } else { 1018 sprintf(cp,"Ascii"); 1019 } 1020 cp = cp + strlen(cp); 1021 1022 return bp; 1023 } 1024 1025 /* ------------------------------------------------------------ */ 1026 /* Enumeration dump functions */ 1027 /* Note - returned buffers are static, can only be used once */ 1028 /* before buffers get reused if type is unknown. */ 1029 1030 /* public tags and sizes */ 1031 static char *string_TagSignature(icTagSignature sig) { 1032 static char buf[80]; 1033 switch(sig) { 1034 case icSigAToB0Tag: 1035 return "AToB0 Multidimentional Transform"; 1036 case icSigAToB1Tag: 1037 return "AToB1 Multidimentional Transform"; 1038 case icSigAToB2Tag: 1039 return "AToB2 Multidimentional Transform"; 1040 case icSigBlueColorantTag: 1041 return "Blue Colorant"; 1042 case icSigBlueTRCTag: 1043 return "Blue Tone Reproduction Curve"; 1044 case icSigBToA0Tag: 1045 return "BToA0 Multidimentional Transform"; 1046 case icSigBToA1Tag: 1047 return "BToA1 Multidimentional Transform"; 1048 case icSigBToA2Tag: 1049 return "BToA2 Multidimentional Transform"; 1050 case icSigCalibrationDateTimeTag: 1051 return "Calibration Date & Time"; 1052 case icSigCharTargetTag: 1053 return "Characterization Target"; 1054 case icSigCopyrightTag: 1055 return "Copyright"; 1056 case icSigCrdInfoTag: 1057 return "CRD Info"; 1058 case icSigDeviceMfgDescTag: 1059 return "Device Manufacturer Description"; 1060 case icSigDeviceModelDescTag: 1061 return "Device Model Description"; 1062 case icSigGamutTag: 1063 return "Gamut"; 1064 case icSigGrayTRCTag: 1065 return "Gray Tone Reproduction Curve"; 1066 case icSigGreenColorantTag: 1067 return "Green Colorant"; 1068 case icSigGreenTRCTag: 1069 return "Green Tone Reproduction Curve"; 1070 case icSigLuminanceTag: 1071 return "Luminance"; 1072 case icSigMeasurementTag: 1073 return "Measurement"; 1074 case icSigMediaBlackPointTag: 1075 return "Media Black Point"; 1076 case icSigMediaWhitePointTag: 1077 return "Media White Point"; 1078 case icSigNamedColorTag: 1079 return "Named Color"; 1080 case icSigNamedColor2Tag: 1081 return "Named Color 2"; 1082 case icSigPreview0Tag: 1083 return "Preview0"; 1084 case icSigPreview1Tag: 1085 return "Preview1"; 1086 case icSigPreview2Tag: 1087 return "Preview2"; 1088 case icSigProfileDescriptionTag: 1089 return "Profile Description"; 1090 case icSigProfileSequenceDescTag: 1091 return "Profile Sequence"; 1092 case icSigPs2CRD0Tag: 1093 return "PS Level 2 CRD perceptual"; 1094 case icSigPs2CRD1Tag: 1095 return "PS Level 2 CRD colorimetric"; 1096 case icSigPs2CRD2Tag: 1097 return "PS Level 2 CRD saturation"; 1098 case icSigPs2CRD3Tag: 1099 return "PS Level 2 CRD absolute"; 1100 case icSigPs2CSATag: 1101 return "PS Level 2 color space array"; 1102 case icSigPs2RenderingIntentTag: 1103 return "PS Level 2 Rendering Intent"; 1104 case icSigRedColorantTag: 1105 return "Red Colorant"; 1106 case icSigRedTRCTag: 1107 return "Red Tone Reproduction Curve"; 1108 case icSigScreeningDescTag: 1109 return "Screening Description"; 1110 case icSigScreeningTag: 1111 return "Screening Attributes"; 1112 case icSigTechnologyTag: 1113 return "Device Technology"; 1114 case icSigUcrBgTag: 1115 return "Under Color Removal & Black Generation"; 1116 case icSigVideoCardGammaTag: 1117 return "Video Card Gamma Curve"; 1118 case icSigViewingCondDescTag: 1119 return "Viewing Condition Description"; 1120 case icSigViewingConditionsTag: 1121 return "Viewing Condition Paramaters"; 1122 } 1123 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1124 return buf; 1125 } 1126 1127 /* technology signature descriptions */ 1128 static char *string_TechnologySignature(icTechnologySignature sig) { 1129 static char buf[80]; 1130 switch(sig) { 1131 case icSigDigitalCamera: 1132 return "Digital Camera"; 1133 case icSigFilmScanner: 1134 return "Film Scanner"; 1135 case icSigReflectiveScanner: 1136 return "Reflective Scanner"; 1137 case icSigInkJetPrinter: 1138 return "InkJet Printer"; 1139 case icSigThermalWaxPrinter: 1140 return "Thermal WaxPrinter"; 1141 case icSigElectrophotographicPrinter: 1142 return "Electrophotographic Printer"; 1143 case icSigElectrostaticPrinter: 1144 return "Electrostatic Printer"; 1145 case icSigDyeSublimationPrinter: 1146 return "DyeSublimation Printer"; 1147 case icSigPhotographicPaperPrinter: 1148 return "Photographic Paper Printer"; 1149 case icSigFilmWriter: 1150 return "Film Writer"; 1151 case icSigVideoMonitor: 1152 return "Video Monitor"; 1153 case icSigVideoCamera: 1154 return "Video Camera"; 1155 case icSigProjectionTelevision: 1156 return "Projection Television"; 1157 case icSigCRTDisplay: 1158 return "Cathode Ray Tube Display"; 1159 case icSigPMDisplay: 1160 return "Passive Matrix Display"; 1161 case icSigAMDisplay: 1162 return "Active Matrix Display"; 1163 case icSigPhotoCD: 1164 return "Photo CD"; 1165 case icSigPhotoImageSetter: 1166 return "Photo ImageSetter"; 1167 case icSigGravure: 1168 return "Gravure"; 1169 case icSigOffsetLithography: 1170 return "Offset Lithography"; 1171 case icSigSilkscreen: 1172 return "Silkscreen"; 1173 case icSigFlexography: 1174 return "Flexography"; 1175 } 1176 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1177 return buf; 1178 } 1179 1180 /* type signatures */ 1181 static char *string_TypeSignature(icTagTypeSignature sig) { 1182 static char buf[80]; 1183 switch(sig) { 1184 case icSigCurveType: 1185 return "Curve"; 1186 case icSigDataType: 1187 return "Data"; 1188 case icSigDateTimeType: 1189 return "DateTime"; 1190 case icSigLut16Type: 1191 return "Lut16"; 1192 case icSigLut8Type: 1193 return "Lut8"; 1194 case icSigMeasurementType: 1195 return "Measurement"; 1196 case icSigNamedColorType: 1197 return "Named Color"; 1198 case icSigProfileSequenceDescType: 1199 return "Profile Sequence Desc"; 1200 case icSigS15Fixed16ArrayType: 1201 return "S15Fixed16 Array"; 1202 case icSigScreeningType: 1203 return "Screening"; 1204 case icSigSignatureType: 1205 return "Signature"; 1206 case icSigTextType: 1207 return "Text"; 1208 case icSigTextDescriptionType: 1209 return "Text Description"; 1210 case icSigU16Fixed16ArrayType: 1211 return "U16Fixed16 Array"; 1212 case icSigUcrBgType: 1213 return "Under Color Removal & Black Generation"; 1214 case icSigUInt16ArrayType: 1215 return "UInt16 Array"; 1216 case icSigUInt32ArrayType: 1217 return "UInt32 Array"; 1218 case icSigUInt64ArrayType: 1219 return "UInt64 Array"; 1220 case icSigUInt8ArrayType: 1221 return "UInt8 Array"; 1222 case icSigVideoCardGammaType: 1223 return "Video Card Gamma"; 1224 case icSigViewingConditionsType: 1225 return "Viewing Conditions"; 1226 case icSigXYZType: 1227 return "XYZ (Array?)"; 1228 case icSigNamedColor2Type: 1229 return "Named Color 2"; 1230 case icSigCrdInfoType: 1231 return "CRD Info"; 1232 } 1233 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1234 return buf; 1235 } 1236 1237 /* Color Space Signatures */ 1238 static char *string_ColorSpaceSignature(icColorSpaceSignature sig) { 1239 static char buf[80]; 1240 switch(sig) { 1241 case icSigXYZData: 1242 return "XYZ"; 1243 case icSigLabData: 1244 return "Lab"; 1245 case icSigLuvData: 1246 return "Luv"; 1247 case icSigYCbCrData: 1248 return "YCbCr"; 1249 case icSigYxyData: 1250 return "Yxy"; 1251 case icSigRgbData: 1252 return "RGB"; 1253 case icSigGrayData: 1254 return "Gray"; 1255 case icSigHsvData: 1256 return "HSV"; 1257 case icSigHlsData: 1258 return "HLS"; 1259 case icSigCmykData: 1260 return "CMYK"; 1261 case icSigCmyData: 1262 return "CMY"; 1263 case icSig2colorData: 1264 return "2 Color"; 1265 case icSig3colorData: 1266 return "3 Color"; 1267 case icSig4colorData: 1268 return "4 Color"; 1269 case icSig5colorData: 1270 case icSigMch5Data: 1271 return "5 Color"; 1272 case icSig6colorData: 1273 case icSigMch6Data: 1274 return "6 Color"; 1275 case icSig7colorData: 1276 case icSigMch7Data: 1277 return "7 Color"; 1278 case icSig8colorData: 1279 case icSigMch8Data: 1280 return "8 Color"; 1281 case icSig9colorData: 1282 return "9 Color"; 1283 case icSig10colorData: 1284 return "10 Color"; 1285 case icSig11colorData: 1286 return "11 Color"; 1287 case icSig12colorData: 1288 return "12 Color"; 1289 case icSig13colorData: 1290 return "13 Color"; 1291 case icSig14colorData: 1292 return "14 Color"; 1293 case icSig15colorData: 1294 return "15 Color"; 1295 } 1296 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1297 return buf; 1298 } 1299 1300 #ifdef NEVER 1301 /* Public version of above */ 1302 char *ColorSpaceSignature2str(icColorSpaceSignature sig) { 1303 return string_ColorSpaceSignature(sig); 1304 } 1305 #endif 1306 1307 1308 /* profileClass enumerations */ 1309 static char *string_ProfileClassSignature(icProfileClassSignature sig) { 1310 static char buf[80]; 1311 switch(sig) { 1312 case icSigInputClass: 1313 return "Input"; 1314 case icSigDisplayClass: 1315 return "Display"; 1316 case icSigOutputClass: 1317 return "Output"; 1318 case icSigLinkClass: 1319 return "Link"; 1320 case icSigAbstractClass: 1321 return "Abstract"; 1322 case icSigColorSpaceClass: 1323 return "Color Space"; 1324 case icSigNamedColorClass: 1325 return "Named Color"; 1326 } 1327 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1328 return buf; 1329 } 1330 1331 /* Platform Signatures */ 1332 static char *string_PlatformSignature(icPlatformSignature sig) { 1333 static char buf[80]; 1334 switch(sig) { 1335 case icSigMacintosh: 1336 return "Macintosh"; 1337 case icSigMicrosoft: 1338 return "Microsoft"; 1339 case icSigSolaris: 1340 return "Solaris"; 1341 case icSigSGI: 1342 return "SGI"; 1343 case icSigTaligent: 1344 return "Taligent"; 1345 } 1346 sprintf(buf,"Unrecognized - %s",tag2str(sig)); 1347 return buf; 1348 } 1349 1350 /* Measurement Geometry, used in the measurmentType tag */ 1351 static char *string_MeasurementGeometry(icMeasurementGeometry sig) { 1352 static char buf[30]; 1353 switch(sig) { 1354 case icGeometryUnknown: 1355 return "Unknown"; 1356 case icGeometry045or450: 1357 return "0/45 or 45/0"; 1358 case icGeometry0dord0: 1359 return "0/d or d/0"; 1360 } 1361 sprintf(buf,"Unrecognized - 0x%x",sig); 1362 return buf; 1363 } 1364 1365 /* Rendering Intents, used in the profile header */ 1366 static char *string_RenderingIntent(icRenderingIntent sig) { 1367 static char buf[30]; 1368 switch(sig) { 1369 case icPerceptual: 1370 return "Perceptual"; 1371 case icRelativeColorimetric: 1372 return "Relative Colorimetric"; 1373 case icSaturation: 1374 return "Saturation"; 1375 case icAbsoluteColorimetric: 1376 return "Absolute Colorimetric"; 1377 } 1378 sprintf(buf,"Unrecognized - 0x%x",sig); 1379 return buf; 1380 } 1381 1382 /* Different Spot Shapes currently defined, used for screeningType */ 1383 static char *string_SpotShape(icSpotShape sig) { 1384 static char buf[30]; 1385 switch(sig) { 1386 case icSpotShapeUnknown: 1387 return "Unknown"; 1388 case icSpotShapePrinterDefault: 1389 return "Printer Default"; 1390 case icSpotShapeRound: 1391 return "Round"; 1392 case icSpotShapeDiamond: 1393 return "Diamond"; 1394 case icSpotShapeEllipse: 1395 return "Ellipse"; 1396 case icSpotShapeLine: 1397 return "Line"; 1398 case icSpotShapeSquare: 1399 return "Square"; 1400 case icSpotShapeCross: 1401 return "Cross"; 1402 } 1403 sprintf(buf,"Unrecognized - 0x%x",sig); 1404 return buf; 1405 } 1406 1407 /* Standard Observer, used in the measurmentType tag */ 1408 static char *string_StandardObserver(icStandardObserver sig) { 1409 static char buf[30]; 1410 switch(sig) { 1411 case icStdObsUnknown: 1412 return "Unknown"; 1413 case icStdObs1931TwoDegrees: 1414 return "1931 Two Degrees"; 1415 case icStdObs1964TenDegrees: 1416 return "1964 Ten Degrees"; 1417 } 1418 sprintf(buf,"Unrecognized - 0x%x",sig); 1419 return buf; 1420 } 1421 1422 /* Pre-defined illuminants, used in measurement and viewing conditions type */ 1423 static char *string_Illuminant(icIlluminant sig) { 1424 static char buf[30]; 1425 switch(sig) { 1426 case icIlluminantUnknown: 1427 return "Unknown"; 1428 case icIlluminantD50: 1429 return "D50"; 1430 case icIlluminantD65: 1431 return "D65"; 1432 case icIlluminantD93: 1433 return "D93"; 1434 case icIlluminantF2: 1435 return "F2"; 1436 case icIlluminantD55: 1437 return "D55"; 1438 case icIlluminantA: 1439 return "A"; 1440 case icIlluminantEquiPowerE: 1441 return "Equi-Power(E)"; 1442 case icIlluminantF8: 1443 return "F8"; 1444 } 1445 sprintf(buf,"Unrecognized - 0x%x",sig); 1446 return buf; 1447 } 1448 1449 /* Return a text abreviation of a color lookup algorithm */ 1450 static char *string_LuAlg(icmLuAlgType alg) { 1451 static char buf[80]; 1452 1453 switch(alg) { 1454 case icmMonoFwdType: 1455 return "MonoFwd"; 1456 case icmMonoBwdType: 1457 return "MonoBwd"; 1458 case icmMatrixFwdType: 1459 return "MatrixFwd"; 1460 case icmMatrixBwdType: 1461 return "MatrixBwd"; 1462 case icmLutType: 1463 return "Lut"; 1464 } 1465 sprintf(buf,"Unrecognized - %d",alg); 1466 return buf; 1467 } 1468 1469 /* Return a string description of the given enumeration value */ 1470 /* Public: */ 1471 char *icm2str(icmEnumType etype, int enumval) { 1472 1473 switch(etype) { 1474 case icmScreenEncodings: 1475 return string_ScreenEncodings((unsigned long) enumval); 1476 case icmDeviceAttributes: 1477 return string_DeviceAttributes((unsigned long) enumval); 1478 case icmProfileHeaderFlags: 1479 return string_ProfileHeaderFlags((unsigned long) enumval); 1480 case icmAsciiOrBinaryData: 1481 return string_AsciiOrBinaryData((unsigned long) enumval); 1482 case icmTagSignature: 1483 return string_TagSignature((icTagSignature) enumval); 1484 case icmTechnologySignature: 1485 return string_TechnologySignature((icTechnologySignature) enumval); 1486 case icmTypeSignature: 1487 return string_TypeSignature((icTagTypeSignature) enumval); 1488 case icmColorSpaceSignature: 1489 return string_ColorSpaceSignature((icColorSpaceSignature) enumval); 1490 case icmProfileClassSignaure: 1491 return string_ProfileClassSignature((icProfileClassSignature) enumval); 1492 case icmPlatformSignature: 1493 return string_PlatformSignature((icPlatformSignature) enumval); 1494 case icmMeasurementGeometry: 1495 return string_MeasurementGeometry((icMeasurementGeometry) enumval); 1496 case icmRenderingIntent: 1497 return string_RenderingIntent((icRenderingIntent) enumval); 1498 case icmSpotShape: 1499 return string_SpotShape((icSpotShape) enumval); 1500 case icmStandardObserver: 1501 return string_StandardObserver((icStandardObserver) enumval); 1502 case icmIlluminant: 1503 return string_Illuminant((icIlluminant) enumval); 1504 case icmLuAlg: 1505 return string_LuAlg((icmLuAlgType) enumval); 1506 } 1507 return "enum2str got unknown type"; 1508 } 1509 1510 /* ========================================================== */ 1511 /* Object I/O routines */ 1512 /* ========================================================== */ 1513 /* icmUInt8Array object */ 1514 1515 /* Return the number of bytes needed to write this tag */ 1516 static unsigned int icmUInt8Array_get_size( 1517 icmBase *pp 1518 ) { 1519 icmUInt8Array *p = (icmUInt8Array *)pp; 1520 unsigned int len = 0; 1521 len += 8; /* 8 bytes for tag and padding */ 1522 len += p->size * 1; /* 1 byte for each UInt8 */ 1523 return len; 1524 } 1525 1526 /* read the object, return 0 on success, error code on fail */ 1527 static int icmUInt8Array_read( 1528 icmBase *pp, 1529 unsigned long len, /* tag length */ 1530 unsigned long of /* start offset within file */ 1531 ) { 1532 icmUInt8Array *p = (icmUInt8Array *)pp; 1533 icc *icp = p->icp; 1534 int rv = 0; 1535 unsigned long i, size; 1536 char *bp, *buf; 1537 1538 if (len < 8) { 1539 sprintf(icp->err,"icmUInt8Array_read: Tag too small to be legal"); 1540 return icp->errc = 1; 1541 } 1542 1543 /* Allocate a file read buffer */ 1544 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1545 sprintf(icp->err,"icmUInt8Array_read: malloc() failed"); 1546 return icp->errc = 2; 1547 } 1548 bp = buf; 1549 1550 /* Read portion of file into buffer */ 1551 if ( icp->fp->seek(icp->fp, of) != 0 1552 || icp->fp->read(icp->fp, bp, 1, len) != len) { 1553 sprintf(icp->err,"icmUInt8Array_read: fseek() or fread() failed"); 1554 icp->al->free(icp->al, buf); 1555 return icp->errc = 1; 1556 } 1557 p->size = size = (len - 8)/1; /* Number of elements in the array */ 1558 1559 if ((rv = p->allocate((icmBase *)p)) != 0) { 1560 icp->al->free(icp->al, buf); 1561 return rv; 1562 } 1563 1564 /* Read type descriptor from the buffer */ 1565 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 1566 icp->al->free(icp->al, buf); 1567 sprintf(icp->err,"icmUInt8Array_read: Wrong tag type for icmUInt8Array"); 1568 return icp->errc = 1; 1569 } 1570 bp += 8; /* Skip padding */ 1571 1572 /* Read all the data from the buffer */ 1573 for (i = 0; i < size; i++, bp += 1) { 1574 p->data[i] = read_UInt8Number(bp); 1575 } 1576 icp->al->free(p->icp->al, buf); 1577 return 0; 1578 } 1579 1580 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 1581 static int icmUInt8Array_write( 1582 icmBase *pp, 1583 unsigned long of /* File offset to write from */ 1584 ) { 1585 icmUInt8Array *p = (icmUInt8Array *)pp; 1586 icc *icp = p->icp; 1587 unsigned long i; 1588 unsigned int len; 1589 char *bp, *buf; /* Buffer to write from */ 1590 int rv = 0; 1591 1592 /* Allocate a file write buffer */ 1593 len = p->get_size((icmBase *)p); 1594 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1595 sprintf(icp->err,"icmUInt8Array_write malloc() failed"); 1596 return icp->errc = 2; 1597 } 1598 bp = buf; 1599 1600 /* Write type descriptor to the buffer */ 1601 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 1602 sprintf(icp->err,"icmUInt8Array_write: write_SInt32Number() failed"); 1603 icp->al->free(icp->al, buf); 1604 return icp->errc = rv; 1605 } 1606 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 1607 bp += 8; /* Skip padding */ 1608 1609 /* Write all the data to the buffer */ 1610 for (i = 0; i < p->size; i++, bp += 1) { 1611 if ((rv = write_UInt8Number(p->data[i],bp)) != 0) { 1612 sprintf(icp->err,"icmUInt8Array_write: write_UInt8umber() failed"); 1613 icp->al->free(icp->al, buf); 1614 return icp->errc = rv; 1615 } 1616 } 1617 1618 /* Write to the file */ 1619 if ( icp->fp->seek(icp->fp, of) != 0 1620 || icp->fp->write(icp->fp, buf, 1, len) != len) { 1621 sprintf(icp->err,"icmUInt8Array_write fseek() or fwrite() failed"); 1622 icp->al->free(icp->al, buf); 1623 return icp->errc = 2; 1624 } 1625 icp->al->free(icp->al, buf); 1626 return 0; 1627 } 1628 1629 /* Dump a text description of the object */ 1630 static void icmUInt8Array_dump( 1631 icmBase *pp, 1632 FILE *op, /* Output to dump to */ 1633 int verb /* Verbosity level */ 1634 ) { 1635 icmUInt8Array *p = (icmUInt8Array *)pp; 1636 if (verb <= 0) 1637 return; 1638 1639 fprintf(op,"UInt8Array:\n"); 1640 fprintf(op," No. elements = %u\n",p->size); 1641 if (verb >= 2) { 1642 unsigned long i; 1643 for (i = 0; i < p->size; i++) 1644 fprintf(op," %u: %u\n",i,p->data[i]); 1645 } 1646 } 1647 1648 /* Allocate variable sized data elements */ 1649 static int icmUInt8Array_allocate( 1650 icmBase *pp 1651 ) { 1652 icmUInt8Array *p = (icmUInt8Array *)pp; 1653 icc *icp = p->icp; 1654 1655 if (p->size != p->_size) { 1656 if (p->data != NULL) 1657 icp->al->free(icp->al, p->data); 1658 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) { 1659 sprintf(icp->err,"icmUInt8Array_alloc: malloc() of icmUInt8Array data failed"); 1660 return icp->errc = 2; 1661 } 1662 p->_size = p->size; 1663 } 1664 return 0; 1665 } 1666 1667 /* Free all storage in the object */ 1668 static void icmUInt8Array_delete( 1669 icmBase *pp 1670 ) { 1671 icmUInt8Array *p = (icmUInt8Array *)pp; 1672 icc *icp = p->icp; 1673 1674 if (p->data != NULL) 1675 icp->al->free(icp->al, p->data); 1676 icp->al->free(icp->al, p); 1677 } 1678 1679 /* Create an empty object. Return null on error */ 1680 static icmBase *new_icmUInt8Array( 1681 icc *icp 1682 ) { 1683 icmUInt8Array *p; 1684 if ((p = (icmUInt8Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt8Array))) == NULL) 1685 return NULL; 1686 p->ttype = icSigUInt8ArrayType; 1687 p->refcount = 1; 1688 p->get_size = icmUInt8Array_get_size; 1689 p->read = icmUInt8Array_read; 1690 p->write = icmUInt8Array_write; 1691 p->dump = icmUInt8Array_dump; 1692 p->allocate = icmUInt8Array_allocate; 1693 p->del = icmUInt8Array_delete; 1694 p->icp = icp; 1695 1696 return (icmBase *)p; 1697 } 1698 1699 /* ---------------------------------------------------------- */ 1700 /* icmUInt16Array object */ 1701 1702 /* Return the number of bytes needed to write this tag */ 1703 static unsigned int icmUInt16Array_get_size( 1704 icmBase *pp 1705 ) { 1706 icmUInt16Array *p = (icmUInt16Array *)pp; 1707 unsigned int len = 0; 1708 len += 8; /* 8 bytes for tag and padding */ 1709 len += p->size * 2; /* 2 bytes for each UInt16 */ 1710 return len; 1711 } 1712 1713 /* read the object, return 0 on success, error code on fail */ 1714 static int icmUInt16Array_read( 1715 icmBase *pp, 1716 unsigned long len, /* tag length */ 1717 unsigned long of /* start offset within file */ 1718 ) { 1719 icmUInt16Array *p = (icmUInt16Array *)pp; 1720 icc *icp = p->icp; 1721 int rv = 0; 1722 unsigned long i, size; 1723 char *bp, *buf; 1724 1725 if (len < 8) { 1726 sprintf(icp->err,"icmUInt16Array_read: Tag too small to be legal"); 1727 return icp->errc = 1; 1728 } 1729 1730 /* Allocate a file read buffer */ 1731 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1732 sprintf(icp->err,"icmUInt16Array_read: malloc() failed"); 1733 return icp->errc = 2; 1734 } 1735 bp = buf; 1736 1737 /* Read portion of file into buffer */ 1738 if ( icp->fp->seek(icp->fp, of) != 0 1739 || icp->fp->read(icp->fp, bp, 1, len) != len) { 1740 sprintf(icp->err,"icmUInt16Array_read: fseek() or fread() failed"); 1741 icp->al->free(icp->al, buf); 1742 return icp->errc = 1; 1743 } 1744 p->size = size = (len - 8)/2; /* Number of elements in the array */ 1745 1746 if ((rv = p->allocate((icmBase *)p)) != 0) { 1747 icp->al->free(icp->al, buf); 1748 return rv; 1749 } 1750 1751 /* Read type descriptor from the buffer */ 1752 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 1753 sprintf(icp->err,"icmUInt16Array_read: Wrong tag type for icmUInt16Array"); 1754 icp->al->free(icp->al, buf); 1755 return icp->errc = 1; 1756 } 1757 bp += 8; /* Skip padding */ 1758 1759 /* Read all the data from the buffer */ 1760 for (i = 0; i < size; i++, bp += 2) { 1761 p->data[i] = read_UInt16Number(bp); 1762 } 1763 icp->al->free(icp->al, buf); 1764 return 0; 1765 } 1766 1767 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 1768 static int icmUInt16Array_write( 1769 icmBase *pp, 1770 unsigned long of /* File offset to write from */ 1771 ) { 1772 icmUInt16Array *p = (icmUInt16Array *)pp; 1773 icc *icp = p->icp; 1774 unsigned long i; 1775 unsigned int len; 1776 char *bp, *buf; /* Buffer to write from */ 1777 int rv = 0; 1778 1779 /* Allocate a file write buffer */ 1780 len = p->get_size((icmBase *)p); 1781 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1782 sprintf(icp->err,"icmUInt16Array_write malloc() failed"); 1783 return icp->errc = 2; 1784 } 1785 bp = buf; 1786 1787 /* Write type descriptor to the buffer */ 1788 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 1789 sprintf(icp->err,"icmUInt16Array_write: write_SInt32Number() failed"); 1790 icp->al->free(icp->al, buf); 1791 return icp->errc = rv; 1792 } 1793 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 1794 1795 /* Write all the data to the buffer */ 1796 bp += 8; /* Skip padding */ 1797 for (i = 0; i < p->size; i++, bp += 2) { 1798 if ((rv = write_UInt16Number(p->data[i],bp)) != 0) { 1799 sprintf(icp->err,"icmUInt16Array_write: write_UInt16umber() failed"); 1800 icp->al->free(icp->al, buf); 1801 return icp->errc = rv; 1802 } 1803 } 1804 1805 /* Write to the file */ 1806 if ( icp->fp->seek(icp->fp, of) != 0 1807 || icp->fp->write(icp->fp, buf, 1, len) != len) { 1808 sprintf(icp->err,"icmUInt16Array_write fseek() or fwrite() failed"); 1809 icp->al->free(icp->al, buf); 1810 return icp->errc = 2; 1811 } 1812 icp->al->free(icp->al, buf); 1813 return 0; 1814 } 1815 1816 /* Dump a text description of the object */ 1817 static void icmUInt16Array_dump( 1818 icmBase *pp, 1819 FILE *op, /* Output to dump to */ 1820 int verb /* Verbosity level */ 1821 ) { 1822 icmUInt16Array *p = (icmUInt16Array *)pp; 1823 if (verb <= 0) 1824 return; 1825 1826 fprintf(op,"UInt16Array:\n"); 1827 fprintf(op," No. elements = %u\n",p->size); 1828 if (verb >= 2) { 1829 unsigned long i; 1830 for (i = 0; i < p->size; i++) 1831 fprintf(op," %u: %u\n",i,p->data[i]); 1832 } 1833 } 1834 1835 /* Allocate variable sized data elements */ 1836 static int icmUInt16Array_allocate( 1837 icmBase *pp 1838 ) { 1839 icmUInt16Array *p = (icmUInt16Array *)pp; 1840 icc *icp = p->icp; 1841 1842 if (p->size != p->_size) { 1843 if (p->data != NULL) 1844 icp->al->free(icp->al, p->data); 1845 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) { 1846 sprintf(icp->err,"icmUInt16Array_alloc: malloc() of icmUInt16Array data failed"); 1847 return icp->errc = 2; 1848 } 1849 p->_size = p->size; 1850 } 1851 return 0; 1852 } 1853 1854 /* Free all storage in the object */ 1855 static void icmUInt16Array_delete( 1856 icmBase *pp 1857 ) { 1858 icmUInt16Array *p = (icmUInt16Array *)pp; 1859 icc *icp = p->icp; 1860 1861 if (p->data != NULL) 1862 icp->al->free(icp->al, p->data); 1863 icp->al->free(icp->al, p); 1864 } 1865 1866 /* Create an empty object. Return null on error */ 1867 static icmBase *new_icmUInt16Array( 1868 icc *icp 1869 ) { 1870 icmUInt16Array *p; 1871 if ((p = (icmUInt16Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt16Array))) == NULL) 1872 return NULL; 1873 p->ttype = icSigUInt16ArrayType; 1874 p->refcount = 1; 1875 p->get_size = icmUInt16Array_get_size; 1876 p->read = icmUInt16Array_read; 1877 p->write = icmUInt16Array_write; 1878 p->dump = icmUInt16Array_dump; 1879 p->allocate = icmUInt16Array_allocate; 1880 p->del = icmUInt16Array_delete; 1881 p->icp = icp; 1882 1883 return (icmBase *)p; 1884 } 1885 1886 /* ---------------------------------------------------------- */ 1887 /* icmUInt32Array object */ 1888 1889 /* Return the number of bytes needed to write this tag */ 1890 static unsigned int icmUInt32Array_get_size( 1891 icmBase *pp 1892 ) { 1893 icmUInt32Array *p = (icmUInt32Array *)pp; 1894 unsigned int len = 0; 1895 len += 8; /* 8 bytes for tag and padding */ 1896 len += p->size * 4; /* 4 bytes for each UInt32 */ 1897 return len; 1898 } 1899 1900 /* read the object, return 0 on success, error code on fail */ 1901 static int icmUInt32Array_read( 1902 icmBase *pp, 1903 unsigned long len, /* tag length */ 1904 unsigned long of /* start offset within file */ 1905 ) { 1906 icmUInt32Array *p = (icmUInt32Array *)pp; 1907 icc *icp = p->icp; 1908 int rv = 0; 1909 unsigned long i, size; 1910 char *bp, *buf; 1911 1912 if (len < 8) { 1913 sprintf(icp->err,"icmUInt32Array_read: Tag too small to be legal"); 1914 return icp->errc = 1; 1915 } 1916 1917 /* Allocate a file read buffer */ 1918 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1919 sprintf(icp->err,"icmUInt32Array_read: malloc() failed"); 1920 return icp->errc = 2; 1921 } 1922 bp = buf; 1923 1924 /* Read portion of file into buffer */ 1925 if ( icp->fp->seek(icp->fp, of) != 0 1926 || icp->fp->read(icp->fp, bp, 1, len) != len) { 1927 sprintf(icp->err,"icmUInt32Array_read: fseek() or fread() failed"); 1928 icp->al->free(icp->al, buf); 1929 return icp->errc = 1; 1930 } 1931 p->size = size = (len - 8)/4; /* Number of elements in the array */ 1932 1933 if ((rv = p->allocate((icmBase *)p)) != 0) { 1934 icp->al->free(icp->al, buf); 1935 return rv; 1936 } 1937 1938 /* Read type descriptor from the buffer */ 1939 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 1940 sprintf(icp->err,"icmUInt32Array_read: Wrong tag type for icmUInt32Array"); 1941 icp->al->free(icp->al, buf); 1942 return icp->errc = 1; 1943 } 1944 bp += 8; /* Skip padding */ 1945 1946 /* Read all the data from the buffer */ 1947 for (i = 0; i < size; i++, bp += 4) { 1948 p->data[i] = read_UInt32Number(bp); 1949 } 1950 icp->al->free(icp->al, buf); 1951 return 0; 1952 } 1953 1954 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 1955 static int icmUInt32Array_write( 1956 icmBase *pp, 1957 unsigned long of /* File offset to write from */ 1958 ) { 1959 icmUInt32Array *p = (icmUInt32Array *)pp; 1960 icc *icp = p->icp; 1961 unsigned long i; 1962 unsigned int len; 1963 char *bp, *buf; /* Buffer to write from */ 1964 int rv = 0; 1965 1966 /* Allocate a file write buffer */ 1967 len = p->get_size((icmBase *)p); 1968 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 1969 sprintf(icp->err,"icmUInt32Array_write malloc() failed"); 1970 return icp->errc = 2; 1971 } 1972 bp = buf; 1973 1974 /* Write type descriptor to the buffer */ 1975 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 1976 sprintf(icp->err,"icmUInt32Array_write: write_SInt32Number() failed"); 1977 icp->al->free(icp->al, buf); 1978 return icp->errc = rv; 1979 } 1980 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 1981 1982 /* Write all the data to the buffer */ 1983 bp += 8; /* Skip padding */ 1984 for (i = 0; i < p->size; i++, bp += 4) { 1985 if ((rv = write_UInt32Number(p->data[i],bp)) != 0) { 1986 sprintf(icp->err,"icmUInt32Array_write: write_UInt32umber() failed"); 1987 icp->al->free(icp->al, buf); 1988 return icp->errc = rv; 1989 } 1990 } 1991 1992 /* Write to the file */ 1993 if ( icp->fp->seek(icp->fp, of) != 0 1994 || icp->fp->write(icp->fp, buf, 1, len) != len) { 1995 sprintf(icp->err,"icmUInt32Array_write fseek() or fwrite() failed"); 1996 icp->al->free(icp->al, buf); 1997 return icp->errc = 2; 1998 } 1999 icp->al->free(icp->al, buf); 2000 return 0; 2001 } 2002 2003 /* Dump a text description of the object */ 2004 static void icmUInt32Array_dump( 2005 icmBase *pp, 2006 FILE *op, /* Output to dump to */ 2007 int verb /* Verbosity level */ 2008 ) { 2009 icmUInt32Array *p = (icmUInt32Array *)pp; 2010 if (verb <= 0) 2011 return; 2012 2013 fprintf(op,"UInt32Array:\n"); 2014 fprintf(op," No. elements = %u\n",p->size); 2015 if (verb >= 2) { 2016 unsigned long i; 2017 for (i = 0; i < p->size; i++) 2018 fprintf(op," %u: %u\n",i,p->data[i]); 2019 } 2020 } 2021 2022 /* Allocate variable sized data elements */ 2023 static int icmUInt32Array_allocate( 2024 icmBase *pp 2025 ) { 2026 icmUInt32Array *p = (icmUInt32Array *)pp; 2027 icc *icp = p->icp; 2028 2029 if (p->size != p->_size) { 2030 if (p->data != NULL) 2031 icp->al->free(icp->al, p->data); 2032 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) { 2033 sprintf(icp->err,"icmUInt32Array_alloc: malloc() of icmUInt32Array data failed"); 2034 return icp->errc = 2; 2035 } 2036 p->_size = p->size; 2037 } 2038 return 0; 2039 } 2040 2041 /* Free all storage in the object */ 2042 static void icmUInt32Array_delete( 2043 icmBase *pp 2044 ) { 2045 icmUInt32Array *p = (icmUInt32Array *)pp; 2046 icc *icp = p->icp; 2047 2048 if (p->data != NULL) 2049 icp->al->free(icp->al, p->data); 2050 icp->al->free(icp->al, p); 2051 } 2052 2053 /* Create an empty object. Return null on error */ 2054 static icmBase *new_icmUInt32Array( 2055 icc *icp 2056 ) { 2057 icmUInt32Array *p; 2058 if ((p = (icmUInt32Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt32Array))) == NULL) 2059 return NULL; 2060 p->ttype = icSigUInt32ArrayType; 2061 p->refcount = 1; 2062 p->get_size = icmUInt32Array_get_size; 2063 p->read = icmUInt32Array_read; 2064 p->write = icmUInt32Array_write; 2065 p->dump = icmUInt32Array_dump; 2066 p->allocate = icmUInt32Array_allocate; 2067 p->del = icmUInt32Array_delete; 2068 p->icp = icp; 2069 2070 return (icmBase *)p; 2071 } 2072 2073 /* ---------------------------------------------------------- */ 2074 /* icmUInt64Array object */ 2075 2076 /* Return the number of bytes needed to write this tag */ 2077 static unsigned int icmUInt64Array_get_size( 2078 icmBase *pp 2079 ) { 2080 icmUInt64Array *p = (icmUInt64Array *)pp; 2081 unsigned int len = 0; 2082 len += 8; /* 8 bytes for tag and padding */ 2083 len += p->size * 8; /* 8 bytes for each UInt64 */ 2084 return len; 2085 } 2086 2087 /* read the object, return 0 on success, error code on fail */ 2088 static int icmUInt64Array_read( 2089 icmBase *pp, 2090 unsigned long len, /* tag length */ 2091 unsigned long of /* start offset within file */ 2092 ) { 2093 icmUInt64Array *p = (icmUInt64Array *)pp; 2094 icc *icp = p->icp; 2095 int rv = 0; 2096 unsigned long i, size; 2097 char *bp, *buf; 2098 2099 if (len < 8) { 2100 sprintf(icp->err,"icmUInt64Array_read: Tag too small to be legal"); 2101 return icp->errc = 1; 2102 } 2103 2104 /* Allocate a file read buffer */ 2105 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2106 sprintf(icp->err,"icmUInt64Array_read: malloc() failed"); 2107 return icp->errc = 2; 2108 } 2109 bp = buf; 2110 2111 /* Read portion of file into buffer */ 2112 if ( icp->fp->seek(icp->fp, of) != 0 2113 || icp->fp->read(icp->fp, bp, 1, len) != len) { 2114 sprintf(icp->err,"icmUInt64Array_read: fseek() or fread() failed"); 2115 icp->al->free(icp->al, buf); 2116 return icp->errc = 1; 2117 } 2118 p->size = size = (len - 8)/8; /* Number of elements in the array */ 2119 2120 if ((rv = p->allocate((icmBase *)p)) != 0) { 2121 icp->al->free(icp->al, buf); 2122 return rv; 2123 } 2124 2125 /* Read type descriptor from the buffer */ 2126 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 2127 sprintf(icp->err,"icmUInt64Array_read: Wrong tag type for icmUInt64Array"); 2128 icp->al->free(icp->al, buf); 2129 return icp->errc = 1; 2130 } 2131 bp += 8; /* Skip padding */ 2132 2133 /* Read all the data from the buffer */ 2134 for (i = 0; i < size; i++, bp += 8) { 2135 read_UInt64Number(&p->data[i], bp); 2136 } 2137 icp->al->free(icp->al, buf); 2138 return 0; 2139 } 2140 2141 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 2142 static int icmUInt64Array_write( 2143 icmBase *pp, 2144 unsigned long of /* File offset to write from */ 2145 ) { 2146 icmUInt64Array *p = (icmUInt64Array *)pp; 2147 icc *icp = p->icp; 2148 unsigned long i; 2149 unsigned int len; 2150 char *bp, *buf; /* Buffer to write from */ 2151 int rv = 0; 2152 2153 /* Allocate a file write buffer */ 2154 len = p->get_size((icmBase *)p); 2155 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2156 sprintf(icp->err,"icmUInt64Array_write malloc() failed"); 2157 return icp->errc = 2; 2158 } 2159 bp = buf; 2160 2161 /* Write type descriptor to the buffer */ 2162 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 2163 sprintf(icp->err,"icmUInt64Array_write: write_SInt32Number() failed"); 2164 icp->al->free(icp->al, buf); 2165 return icp->errc = rv; 2166 } 2167 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 2168 2169 /* Write all the data to the buffer */ 2170 bp += 8; /* Skip padding */ 2171 for (i = 0; i < p->size; i++, bp += 8) { 2172 if ((rv = write_UInt64Number(&p->data[i],bp)) != 0) { 2173 sprintf(icp->err,"icmUInt64Array_write: write_UInt64umber() failed"); 2174 icp->al->free(icp->al, buf); 2175 return icp->errc = rv; 2176 } 2177 } 2178 2179 /* Write to the file */ 2180 if ( icp->fp->seek(icp->fp, of) != 0 2181 || icp->fp->write(icp->fp, buf, 1, len) != len) { 2182 sprintf(icp->err,"icmUInt64Array_write fseek() or fwrite() failed"); 2183 icp->al->free(icp->al, buf); 2184 return icp->errc = 2; 2185 } 2186 icp->al->free(icp->al, buf); 2187 return 0; 2188 } 2189 2190 /* Dump a text description of the object */ 2191 static void icmUInt64Array_dump( 2192 icmBase *pp, 2193 FILE *op, /* Output to dump to */ 2194 int verb /* Verbosity level */ 2195 ) { 2196 icmUInt64Array *p = (icmUInt64Array *)pp; 2197 if (verb <= 0) 2198 return; 2199 2200 fprintf(op,"UInt64Array:\n"); 2201 fprintf(op," No. elements = %u\n",p->size); 2202 if (verb >= 2) { 2203 unsigned long i; 2204 for (i = 0; i < p->size; i++) 2205 fprintf(op," %u: h=%u, l=%u\n",i,p->data[i].h,p->data[i].l); 2206 } 2207 } 2208 2209 /* Allocate variable sized data elements */ 2210 static int icmUInt64Array_allocate( 2211 icmBase *pp 2212 ) { 2213 icmUInt64Array *p = (icmUInt64Array *)pp; 2214 icc *icp = p->icp; 2215 2216 if (p->size != p->_size) { 2217 if (p->data != NULL) 2218 icp->al->free(icp->al, p->data); 2219 if ((p->data = (uint64 *) icp->al->malloc(icp->al, p->size * sizeof(uint64))) == NULL) { 2220 sprintf(icp->err,"icmUInt64Array_alloc: malloc() of icmUInt64Array data failed"); 2221 return icp->errc = 2; 2222 } 2223 p->_size = p->size; 2224 } 2225 return 0; 2226 } 2227 2228 /* Free all storage in the object */ 2229 static void icmUInt64Array_delete( 2230 icmBase *pp 2231 ) { 2232 icmUInt64Array *p = (icmUInt64Array *)pp; 2233 icc *icp = p->icp; 2234 2235 if (p->data != NULL) 2236 icp->al->free(icp->al, p->data); 2237 icp->al->free(icp->al, p); 2238 } 2239 2240 /* Create an empty object. Return null on error */ 2241 static icmBase *new_icmUInt64Array( 2242 icc *icp 2243 ) { 2244 icmUInt64Array *p; 2245 if ((p = (icmUInt64Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt64Array))) == NULL) 2246 return NULL; 2247 p->ttype = icSigUInt64ArrayType; 2248 p->refcount = 1; 2249 p->get_size = icmUInt64Array_get_size; 2250 p->read = icmUInt64Array_read; 2251 p->write = icmUInt64Array_write; 2252 p->dump = icmUInt64Array_dump; 2253 p->allocate = icmUInt64Array_allocate; 2254 p->del = icmUInt64Array_delete; 2255 p->icp = icp; 2256 2257 return (icmBase *)p; 2258 } 2259 2260 /* ---------------------------------------------------------- */ 2261 /* icmU16Fixed16Array object */ 2262 2263 /* Return the number of bytes needed to write this tag */ 2264 static unsigned int icmU16Fixed16Array_get_size( 2265 icmBase *pp 2266 ) { 2267 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2268 unsigned int len = 0; 2269 len += 8; /* 8 bytes for tag and padding */ 2270 len += p->size * 4; /* 4 byte for each U16Fixed16 */ 2271 return len; 2272 } 2273 2274 /* read the object, return 0 on success, error code on fail */ 2275 static int icmU16Fixed16Array_read( 2276 icmBase *pp, 2277 unsigned long len, /* tag length */ 2278 unsigned long of /* start offset within file */ 2279 ) { 2280 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2281 icc *icp = p->icp; 2282 int rv = 0; 2283 unsigned long i, size; 2284 char *bp, *buf; 2285 2286 if (len < 8) { 2287 sprintf(icp->err,"icmU16Fixed16Array_read: Tag too small to be legal"); 2288 return icp->errc = 1; 2289 } 2290 2291 /* Allocate a file read buffer */ 2292 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2293 sprintf(icp->err,"icmU16Fixed16Array_read: malloc() failed"); 2294 return icp->errc = 2; 2295 } 2296 bp = buf; 2297 2298 /* Read portion of file into buffer */ 2299 if ( icp->fp->seek(icp->fp, of) != 0 2300 || icp->fp->read(icp->fp, bp, 1, len) != len) { 2301 sprintf(icp->err,"icmU16Fixed16Array_read: fseek() or fread() failed"); 2302 icp->al->free(icp->al, buf); 2303 return icp->errc = 1; 2304 } 2305 p->size = size = (len - 8)/4; /* Number of elements in the array */ 2306 2307 if ((rv = p->allocate((icmBase *)p)) != 0) { 2308 icp->al->free(icp->al, buf); 2309 return rv; 2310 } 2311 2312 /* Read type descriptor from the buffer */ 2313 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 2314 sprintf(icp->err,"icmU16Fixed16Array_read: Wrong tag type for icmU16Fixed16Array"); 2315 icp->al->free(icp->al, buf); 2316 return icp->errc = 1; 2317 } 2318 bp += 8; /* Skip padding */ 2319 2320 /* Read all the data from the buffer */ 2321 for (i = 0; i < size; i++, bp += 4) { 2322 p->data[i] = read_U16Fixed16Number(bp); 2323 } 2324 icp->al->free(icp->al, buf); 2325 return 0; 2326 } 2327 2328 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 2329 static int icmU16Fixed16Array_write( 2330 icmBase *pp, 2331 unsigned long of /* File offset to write from */ 2332 ) { 2333 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2334 icc *icp = p->icp; 2335 unsigned long i; 2336 unsigned int len; 2337 char *bp, *buf; /* Buffer to write from */ 2338 int rv = 0; 2339 2340 /* Allocate a file write buffer */ 2341 len = p->get_size((icmBase *)p); 2342 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2343 sprintf(icp->err,"icmU16Fixed16Array_write malloc() failed"); 2344 return icp->errc = 2; 2345 } 2346 bp = buf; 2347 2348 /* Write type descriptor to the buffer */ 2349 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 2350 sprintf(icp->err,"icmU16Fixed16Array_write: write_SInt32Number() failed"); 2351 icp->al->free(icp->al, buf); 2352 return icp->errc = rv; 2353 } 2354 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 2355 2356 /* Write all the data to the buffer */ 2357 bp += 8; /* Skip padding */ 2358 for (i = 0; i < p->size; i++, bp += 4) { 2359 if ((rv = write_U16Fixed16Number(p->data[i],bp)) != 0) { 2360 sprintf(icp->err,"icmU16Fixed16Array_write: write_U16Fixed16umber() failed"); 2361 icp->al->free(icp->al, buf); 2362 return icp->errc = rv; 2363 } 2364 } 2365 2366 /* Write to the file */ 2367 if ( icp->fp->seek(icp->fp, of) != 0 2368 || icp->fp->write(icp->fp, buf, 1, len) != len) { 2369 sprintf(icp->err,"icmU16Fixed16Array_write fseek() or fwrite() failed"); 2370 icp->al->free(icp->al, buf); 2371 return icp->errc = 2; 2372 } 2373 icp->al->free(icp->al, buf); 2374 return 0; 2375 } 2376 2377 /* Dump a text description of the object */ 2378 static void icmU16Fixed16Array_dump( 2379 icmBase *pp, 2380 FILE *op, /* Output to dump to */ 2381 int verb /* Verbosity level */ 2382 ) { 2383 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2384 if (verb <= 0) 2385 return; 2386 2387 fprintf(op,"U16Fixed16Array:\n"); 2388 fprintf(op," No. elements = %u\n",p->size); 2389 if (verb >= 2) { 2390 unsigned long i; 2391 for (i = 0; i < p->size; i++) 2392 fprintf(op," %u: %f\n",i,p->data[i]); 2393 } 2394 } 2395 2396 /* Allocate variable sized data elements */ 2397 static int icmU16Fixed16Array_allocate( 2398 icmBase *pp 2399 ) { 2400 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2401 icc *icp = p->icp; 2402 2403 if (p->size != p->_size) { 2404 if (p->data != NULL) 2405 icp->al->free(icp->al, p->data); 2406 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) { 2407 sprintf(icp->err,"icmU16Fixed16Array_alloc: malloc() of icmU16Fixed16Array data failed"); 2408 return icp->errc = 2; 2409 } 2410 p->_size = p->size; 2411 } 2412 return 0; 2413 } 2414 2415 /* Free all storage in the object */ 2416 static void icmU16Fixed16Array_delete( 2417 icmBase *pp 2418 ) { 2419 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp; 2420 icc *icp = p->icp; 2421 2422 if (p->data != NULL) 2423 icp->al->free(icp->al, p->data); 2424 icp->al->free(icp->al, p); 2425 } 2426 2427 /* Create an empty object. Return null on error */ 2428 static icmBase *new_icmU16Fixed16Array( 2429 icc *icp 2430 ) { 2431 icmU16Fixed16Array *p; 2432 if ((p = (icmU16Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmU16Fixed16Array))) == NULL) 2433 return NULL; 2434 p->ttype = icSigU16Fixed16ArrayType; 2435 p->refcount = 1; 2436 p->get_size = icmU16Fixed16Array_get_size; 2437 p->read = icmU16Fixed16Array_read; 2438 p->write = icmU16Fixed16Array_write; 2439 p->dump = icmU16Fixed16Array_dump; 2440 p->allocate = icmU16Fixed16Array_allocate; 2441 p->del = icmU16Fixed16Array_delete; 2442 p->icp = icp; 2443 2444 return (icmBase *)p; 2445 } 2446 2447 /* ---------------------------------------------------------- */ 2448 /* icmS15Fixed16Array object */ 2449 2450 /* Return the number of bytes needed to write this tag */ 2451 static unsigned int icmS15Fixed16Array_get_size( 2452 icmBase *pp 2453 ) { 2454 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2455 unsigned int len = 0; 2456 len += 8; /* 8 bytes for tag and padding */ 2457 len += p->size * 4; /* 4 byte for each S15Fixed16 */ 2458 return len; 2459 } 2460 2461 /* read the object, return 0 on success, error code on fail */ 2462 static int icmS15Fixed16Array_read( 2463 icmBase *pp, 2464 unsigned long len, /* tag length */ 2465 unsigned long of /* start offset within file */ 2466 ) { 2467 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2468 icc *icp = p->icp; 2469 int rv = 0; 2470 unsigned long i, size; 2471 char *bp, *buf; 2472 2473 if (len < 8) { 2474 sprintf(icp->err,"icmS15Fixed16Array_read: Tag too small to be legal"); 2475 return icp->errc = 1; 2476 } 2477 2478 /* Allocate a file read buffer */ 2479 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2480 sprintf(icp->err,"icmS15Fixed16Array_read: malloc() failed"); 2481 return icp->errc = 2; 2482 } 2483 bp = buf; 2484 2485 /* Read portion of file into buffer */ 2486 if ( icp->fp->seek(icp->fp, of) != 0 2487 || icp->fp->read(icp->fp, bp, 1, len) != len) { 2488 sprintf(icp->err,"icmS15Fixed16Array_read: fseek() or fread() failed"); 2489 icp->al->free(icp->al, buf); 2490 return icp->errc = 1; 2491 } 2492 p->size = size = (len - 8)/4; /* Number of elements in the array */ 2493 2494 if ((rv = p->allocate((icmBase *)p)) != 0) { 2495 icp->al->free(icp->al, buf); 2496 return rv; 2497 } 2498 2499 /* Read type descriptor from the buffer */ 2500 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 2501 sprintf(icp->err,"icmS15Fixed16Array_read: Wrong tag type for icmS15Fixed16Array"); 2502 icp->al->free(icp->al, buf); 2503 return icp->errc = 1; 2504 } 2505 bp += 8; /* Skip padding */ 2506 2507 /* Read all the data from the buffer */ 2508 for (i = 0; i < size; i++, bp += 4) { 2509 p->data[i] = read_S15Fixed16Number(bp); 2510 } 2511 icp->al->free(icp->al, buf); 2512 return 0; 2513 } 2514 2515 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 2516 static int icmS15Fixed16Array_write( 2517 icmBase *pp, 2518 unsigned long of /* File offset to write from */ 2519 ) { 2520 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2521 icc *icp = p->icp; 2522 unsigned long i; 2523 unsigned int len; 2524 char *bp, *buf; /* Buffer to write from */ 2525 int rv = 0; 2526 2527 /* Allocate a file write buffer */ 2528 len = p->get_size((icmBase *)p); 2529 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2530 sprintf(icp->err,"icmS15Fixed16Array_write malloc() failed"); 2531 return icp->errc = 2; 2532 } 2533 bp = buf; 2534 2535 /* Write type descriptor to the buffer */ 2536 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 2537 sprintf(icp->err,"icmS15Fixed16Array_write: write_SInt32Number() failed"); 2538 icp->al->free(icp->al, buf); 2539 return icp->errc = rv; 2540 } 2541 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 2542 2543 /* Write all the data to the buffer */ 2544 bp += 8; /* Skip padding */ 2545 for (i = 0; i < p->size; i++, bp += 4) { 2546 if ((rv = write_S15Fixed16Number(p->data[i],bp)) != 0) { 2547 sprintf(icp->err,"icmS15Fixed16Array_write: write_S15Fixed16umber() failed"); 2548 icp->al->free(icp->al, buf); 2549 return icp->errc = rv; 2550 } 2551 } 2552 2553 /* Write to the file */ 2554 if ( icp->fp->seek(icp->fp, of) != 0 2555 || icp->fp->write(icp->fp, buf, 1, len) != len) { 2556 sprintf(icp->err,"icmS15Fixed16Array_write fseek() or fwrite() failed"); 2557 icp->al->free(icp->al, buf); 2558 return icp->errc = 2; 2559 } 2560 icp->al->free(icp->al, buf); 2561 return 0; 2562 } 2563 2564 /* Dump a text description of the object */ 2565 static void icmS15Fixed16Array_dump( 2566 icmBase *pp, 2567 FILE *op, /* Output to dump to */ 2568 int verb /* Verbosity level */ 2569 ) { 2570 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2571 if (verb <= 0) 2572 return; 2573 2574 fprintf(op,"S15Fixed16Array:\n"); 2575 fprintf(op," No. elements = %u\n",p->size); 2576 if (verb >= 2) { 2577 unsigned long i; 2578 for (i = 0; i < p->size; i++) 2579 fprintf(op," %u: %f\n",i,p->data[i]); 2580 } 2581 } 2582 2583 /* Allocate variable sized data elements */ 2584 static int icmS15Fixed16Array_allocate( 2585 icmBase *pp 2586 ) { 2587 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2588 icc *icp = p->icp; 2589 2590 if (p->size != p->_size) { 2591 if (p->data != NULL) 2592 icp->al->free(icp->al, p->data); 2593 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) { 2594 sprintf(icp->err,"icmS15Fixed16Array_alloc: malloc() of icmS15Fixed16Array data failed"); 2595 return icp->errc = 2; 2596 } 2597 p->_size = p->size; 2598 } 2599 return 0; 2600 } 2601 2602 /* Free all storage in the object */ 2603 static void icmS15Fixed16Array_delete( 2604 icmBase *pp 2605 ) { 2606 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp; 2607 icc *icp = p->icp; 2608 2609 if (p->data != NULL) 2610 icp->al->free(icp->al, p->data); 2611 icp->al->free(icp->al, p); 2612 } 2613 2614 /* Create an empty object. Return null on error */ 2615 static icmBase *new_icmS15Fixed16Array( 2616 icc *icp 2617 ) { 2618 icmS15Fixed16Array *p; 2619 if ((p = (icmS15Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmS15Fixed16Array))) == NULL) 2620 return NULL; 2621 p->ttype = icSigS15Fixed16ArrayType; 2622 p->refcount = 1; 2623 p->get_size = icmS15Fixed16Array_get_size; 2624 p->read = icmS15Fixed16Array_read; 2625 p->write = icmS15Fixed16Array_write; 2626 p->dump = icmS15Fixed16Array_dump; 2627 p->allocate = icmS15Fixed16Array_allocate; 2628 p->del = icmS15Fixed16Array_delete; 2629 p->icp = icp; 2630 2631 return (icmBase *)p; 2632 } 2633 2634 /* ---------------------------------------------------------- */ 2635 2636 /* Data conversion support functions */ 2637 static int write_XYZNumber(icmXYZNumber *p, char *d) { 2638 int rv; 2639 if ((rv = write_S15Fixed16Number(p->X, d + 0)) != 0) 2640 return rv; 2641 if ((rv = write_S15Fixed16Number(p->Y, d + 4)) != 0) 2642 return rv; 2643 if ((rv = write_S15Fixed16Number(p->Z, d + 8)) != 0) 2644 return rv; 2645 return 0; 2646 } 2647 2648 static int read_XYZNumber(icmXYZNumber *p, char *d) { 2649 p->X = read_S15Fixed16Number(d + 0); 2650 p->Y = read_S15Fixed16Number(d + 4); 2651 p->Z = read_S15Fixed16Number(d + 8); 2652 return 0; 2653 } 2654 2655 2656 /* Helper: Return a string that shows the XYZ number value */ 2657 static char *string_XYZNumber(icmXYZNumber *p) { 2658 static char buf[40]; 2659 2660 sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z); 2661 return buf; 2662 } 2663 2664 /* Helper: Return a string that shows the XYZ number value, */ 2665 /* and the Lab D50 number in paren. */ 2666 static char *string_XYZNumber_and_Lab(icmXYZNumber *p) { 2667 static char buf[50]; 2668 double lab[3]; 2669 lab[0] = p->X; 2670 lab[1] = p->Y; 2671 lab[2] = p->Z; 2672 icmXYZ2Lab(&icmD50, lab, lab); 2673 sprintf(buf,"%f, %f, %f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]); 2674 return buf; 2675 } 2676 2677 /* icmXYZArray object */ 2678 2679 /* Return the number of bytes needed to write this tag */ 2680 static unsigned int icmXYZArray_get_size( 2681 icmBase *pp 2682 ) { 2683 icmXYZArray *p = (icmXYZArray *)pp; 2684 unsigned int len = 0; 2685 len += 8; /* 8 bytes for tag and padding */ 2686 len += p->size * 12; /* 12 bytes for each XYZ */ 2687 return len; 2688 } 2689 2690 /* read the object, return 0 on success, error code on fail */ 2691 static int icmXYZArray_read( 2692 icmBase *pp, 2693 unsigned long len, /* tag length */ 2694 unsigned long of /* start offset within file */ 2695 ) { 2696 icmXYZArray *p = (icmXYZArray *)pp; 2697 icc *icp = p->icp; 2698 int rv = 0; 2699 unsigned long i, size; 2700 char *bp, *buf; 2701 2702 if (len < 8) { 2703 sprintf(icp->err,"icmXYZArray_read: Tag too small to be legal"); 2704 return icp->errc = 1; 2705 } 2706 2707 /* Allocate a file read buffer */ 2708 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2709 sprintf(icp->err,"icmXYZArray_read: malloc() failed"); 2710 return icp->errc = 2; 2711 } 2712 bp = buf; 2713 2714 /* Read portion of file into buffer */ 2715 if ( icp->fp->seek(icp->fp, of) != 0 2716 || icp->fp->read(icp->fp, bp, 1, len) != len) { 2717 sprintf(icp->err,"icmXYZArray_read: fseek() or fread() failed"); 2718 icp->al->free(icp->al, buf); 2719 return icp->errc = 1; 2720 } 2721 p->size = size = (len - 8)/12; /* Number of elements in the array */ 2722 2723 if ((rv = p->allocate((icmBase *)p)) != 0) { 2724 icp->al->free(icp->al, buf); 2725 return rv; 2726 } 2727 2728 /* Read type descriptor from the buffer */ 2729 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 2730 sprintf(icp->err,"icmXYZArray_read: Wrong tag type for icmXYZArray"); 2731 icp->al->free(icp->al, buf); 2732 return icp->errc = 1; 2733 } 2734 bp += 8; /* Skip padding */ 2735 2736 /* Read all the data from the buffer */ 2737 for (i = 0; i < size; i++, bp += 12) { 2738 read_XYZNumber(&p->data[i], bp); 2739 } 2740 icp->al->free(icp->al, buf); 2741 return 0; 2742 } 2743 2744 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 2745 static int icmXYZArray_write( 2746 icmBase *pp, 2747 unsigned long of /* File offset to write from */ 2748 ) { 2749 icmXYZArray *p = (icmXYZArray *)pp; 2750 icc *icp = p->icp; 2751 unsigned long i; 2752 unsigned int len; 2753 char *bp, *buf; /* Buffer to write from */ 2754 int rv = 0; 2755 2756 /* Allocate a file write buffer */ 2757 len = p->get_size((icmBase *)p); 2758 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 2759 sprintf(icp->err,"icmXYZArray_write malloc() failed"); 2760 return icp->errc = 2; 2761 } 2762 bp = buf; 2763 2764 /* Write type descriptor to the buffer */ 2765 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 2766 sprintf(icp->err,"icmXYZArray_write: write_SInt32Number() failed"); 2767 icp->al->free(icp->al, buf); 2768 return icp->errc = rv; 2769 } 2770 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 2771 2772 /* Write all the data to the buffer */ 2773 bp += 8; /* Skip padding */ 2774 for (i = 0; i < p->size; i++, bp += 12) { 2775 if ((rv = write_XYZNumber(&p->data[i],bp)) != 0) { 2776 sprintf(icp->err,"icmXYZArray_write: write_XYZumber() failed"); 2777 icp->al->free(icp->al, buf); 2778 return icp->errc = rv; 2779 } 2780 } 2781 2782 /* Write to the file */ 2783 if ( icp->fp->seek(icp->fp, of) != 0 2784 || icp->fp->write(icp->fp, buf, 1, len) != len) { 2785 sprintf(icp->err,"icmXYZArray_write fseek() or fwrite() failed"); 2786 icp->al->free(icp->al, buf); 2787 return icp->errc = 2; 2788 } 2789 icp->al->free(icp->al, buf); 2790 return 0; 2791 } 2792 2793 /* Dump a text description of the object */ 2794 static void icmXYZArray_dump( 2795 icmBase *pp, 2796 FILE *op, /* Output to dump to */ 2797 int verb /* Verbosity level */ 2798 ) { 2799 icmXYZArray *p = (icmXYZArray *)pp; 2800 if (verb <= 0) 2801 return; 2802 2803 fprintf(op,"XYZArray:\n"); 2804 fprintf(op," No. elements = %u\n",p->size); 2805 if (verb >= 2) { 2806 unsigned long i; 2807 for (i = 0; i < p->size; i++) { 2808 fprintf(op," %u: %s\n",i,string_XYZNumber_and_Lab(&p->data[i])); 2809 2810 } 2811 } 2812 } 2813 2814 2815 /* Allocate variable sized data elements */ 2816 static int icmXYZArray_allocate( 2817 icmBase *pp 2818 ) { 2819 icmXYZArray *p = (icmXYZArray *)pp; 2820 icc *icp = p->icp; 2821 2822 if (p->size != p->_size) { 2823 if (p->data != NULL) 2824 icp->al->free(icp->al, p->data); 2825 if ((p->data = (icmXYZNumber *) icp->al->malloc(icp->al, p->size * sizeof(icmXYZNumber))) == NULL) { 2826 sprintf(icp->err,"icmXYZArray_alloc: malloc() of icmXYZArray data failed"); 2827 return icp->errc = 2; 2828 } 2829 p->_size = p->size; 2830 } 2831 return 0; 2832 } 2833 2834 /* Free all storage in the object */ 2835 static void icmXYZArray_delete( 2836 icmBase *pp 2837 ) { 2838 icmXYZArray *p = (icmXYZArray *)pp; 2839 icc *icp = p->icp; 2840 2841 if (p->data != NULL) 2842 icp->al->free(icp->al, p->data); 2843 icp->al->free(icp->al, p); 2844 } 2845 2846 /* Create an empty object. Return null on error */ 2847 static icmBase *new_icmXYZArray( 2848 icc *icp 2849 ) { 2850 icmXYZArray *p; 2851 if ((p = (icmXYZArray *) icp->al->calloc(icp->al,1,sizeof(icmXYZArray))) == NULL) 2852 return NULL; 2853 p->ttype = icSigXYZArrayType; 2854 p->refcount = 1; 2855 p->get_size = icmXYZArray_get_size; 2856 p->read = icmXYZArray_read; 2857 p->write = icmXYZArray_write; 2858 p->dump = icmXYZArray_dump; 2859 p->allocate = icmXYZArray_allocate; 2860 p->del = icmXYZArray_delete; 2861 p->icp = icp; 2862 2863 return (icmBase *)p; 2864 } 2865 2866 /* ---------------------------------------------------------- */ 2867 /* icmCurve object */ 2868 2869 /* Do a forward lookup through the curve */ 2870 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 2871 static int icmCurve_lookup_fwd( 2872 icmCurve *p, 2873 double *out, 2874 double *in 2875 ) { 2876 int rv = 0; 2877 if (p->flag == icmCurveLin) { 2878 *out = *in; 2879 } else if (p->flag == icmCurveGamma) { 2880 double val = *in; 2881 if (val <= 0.0) 2882 *out = 0.0; 2883 else 2884 *out = pow(val, p->data[0]); 2885 } else { /* Use linear interpolation */ 2886 int ix; 2887 double val, w; 2888 double inputEnt_1 = (double)(p->size-1); 2889 2890 val = *in * inputEnt_1; 2891 if (val < 0.0) { 2892 val = 0.0; 2893 rv |= 1; 2894 } else if (val > inputEnt_1) { 2895 val = inputEnt_1; 2896 rv |= 1; 2897 } 2898 ix = (int)floor(val); /* Coordinate */ 2899 if (ix > (p->size-2)) 2900 ix = (p->size-2); 2901 w = val - (double)ix; /* weight */ 2902 val = p->data[ix]; 2903 *out = val + w * (p->data[ix+1] - val); 2904 } 2905 return rv; 2906 } 2907 2908 /* - - - - - - - - - - - - */ 2909 /* Support for reverse interpolation of 1D lookup tables */ 2910 2911 /* Create a reverse curve lookup acceleration table */ 2912 /* return non-zero on error, 2 = malloc error. */ 2913 static int icmTable_setup_bwd( 2914 icc *icp, /* Base icc object */ 2915 icmRevTable *rt, /* Reverse table data to setup */ 2916 unsigned long size, /* Size of fwd table */ 2917 double *data /* Table */ 2918 ) { 2919 int i; 2920 2921 rt->size = size; /* Stash pointers to these away */ 2922 rt->data = data; 2923 2924 /* Find range of output values */ 2925 rt->rmin = 1e300; 2926 rt->rmax = -1e300; 2927 for (i = 0; i < rt->size; i++) { 2928 if (rt->data[i] > rt->rmax) 2929 rt->rmax = rt->data[i]; 2930 if (rt->data[i] < rt->rmin) 2931 rt->rmin = rt->data[i]; 2932 } 2933 2934 /* Decide on reverse granularity */ 2935 rt->rsize = (rt->size+2)/2; 2936 rt->qscale = (double)rt->rsize/(rt->rmax - rt->rmin); /* Scale factor to quantize to */ 2937 2938 /* Initialize the reverse lookup structures, and get overall min/max */ 2939 if ((rt->rlists = (int **) icp->al->calloc(icp->al, 1, rt->rsize * sizeof(int *))) == NULL) { 2940 return 2; 2941 } 2942 2943 /* Assign each output value range bucket lists it intersects */ 2944 for (i = 0; i < (rt->size-1); i++) { 2945 int s, e, j; /* Start and end indexes (inclusive) */ 2946 s = ((rt->data[i] - rt->rmin) * rt->qscale); 2947 e = ((rt->data[i+1] - rt->rmin) * rt->qscale); 2948 if (s > e) { /* swap */ 2949 int t; 2950 t = s; s = e; e = t; 2951 } 2952 if (e >= rt->rsize) 2953 e = rt->rsize-1; 2954 2955 /* For all buckets that may contain this output range, add index of this output */ 2956 for (j = s; j <= e; j++) { 2957 int as; /* Allocation size */ 2958 int nf; /* Next free slot */ 2959 if (rt->rlists[j] == NULL) { /* No allocation */ 2960 as = 5; /* Start with space for 5 */ 2961 if ((rt->rlists[j] = (int *) icp->al->malloc(icp->al, sizeof(int) * as)) == NULL) { 2962 return 2; 2963 } 2964 rt->rlists[j][0] = as; 2965 nf = rt->rlists[j][1] = 2; 2966 } else { 2967 as = rt->rlists[j][0]; /* Allocate space for this list */ 2968 nf = rt->rlists[j][1]; /* Next free location in list */ 2969 if (nf >= as) { /* need to expand space */ 2970 as *= 2; 2971 rt->rlists[j] = (int *) icp->al->realloc(icp->al,rt->rlists[j], sizeof(int) * as); 2972 if (rt->rlists[j] == NULL) { 2973 return 2; 2974 } 2975 rt->rlists[j][0] = as; 2976 } 2977 } 2978 rt->rlists[j][nf++] = i; 2979 rt->rlists[j][1] = nf; 2980 } 2981 } 2982 rt->inited = 1; 2983 return 0; 2984 } 2985 2986 /* Free up any data */ 2987 static void icmTable_delete_bwd( 2988 icc *icp, /* Base icc */ 2989 icmRevTable *rt /* Reverse table data to setup */ 2990 ) { 2991 if (rt->inited != 0) { 2992 while (rt->rsize > 0) 2993 icp->al->free(icp->al, rt->rlists[--rt->rsize]); 2994 icp->al->free(icp->al, rt->rlists); 2995 rt->size = 0; /* Don't keep these */ 2996 rt->data = NULL; 2997 } 2998 } 2999 3000 /* Do a reverse lookup through the curve */ 3001 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 3002 static int icmTable_lookup_bwd( 3003 icmRevTable *rt, 3004 double *out, 3005 double *in 3006 ) { 3007 int rv = 0; 3008 int ix, i, k; 3009 double oval, ival = *in, val; 3010 double rsize_1; 3011 3012 /* Find appropriate reverse list */ 3013 rsize_1 = (double)(rt->rsize-1); 3014 val = ((ival - rt->rmin) * rt->qscale); 3015 if (val < 0.0) 3016 val = 0.0; 3017 else if (val > rsize_1) 3018 val = rsize_1; 3019 ix = (int)floor(val); /* Coordinate */ 3020 3021 if (ix > (rt->size-2)) 3022 ix = (rt->size-2); 3023 if (rt->rlists[ix] != NULL) { /* There is a list of fwd candidates */ 3024 /* For each candidate forward range */ 3025 for (i = 2; i < rt->rlists[ix][1]; i++) { /* For all fwd indexes */ 3026 double lv,hv; 3027 k = rt->rlists[ix][i]; /* Base index */ 3028 lv = rt->data[k]; 3029 hv = rt->data[k+1]; 3030 if ((ival >= lv && ival <= hv) /* If this slot contains output value */ 3031 || (ival >= hv && ival <= lv)) { 3032 /* Reverse linear interpolation */ 3033 if (hv == lv) { /* Technically non-monotonic - due to quantization ? */ 3034 oval = (k + 0.5)/(rt->size-1.0); 3035 } else 3036 oval = (k + ((ival - lv)/(hv - lv)))/(rt->size-1.0); 3037 /* If we kept looking, we would find multiple */ 3038 /* solution for non-monotonic curve */ 3039 *out = oval; 3040 return rv; 3041 } 3042 } 3043 } 3044 3045 /* We have failed to find an exact value, so return the nearest value */ 3046 /* (This is slow !) */ 3047 val = fabs(ival - rt->data[0]); 3048 for (k = 0, i = 1; i < rt->size; i++) { 3049 double er; 3050 er = fabs(ival - rt->data[i]); 3051 if (er < val) { /* new best */ 3052 val = er; 3053 k = i; 3054 } 3055 } 3056 *out = k/(rt->size-1.0); 3057 rv |= 1; 3058 return rv; 3059 } 3060 3061 3062 /* - - - - - - - - - - - - */ 3063 3064 /* Do a reverse lookup through the curve */ 3065 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 3066 static int icmCurve_lookup_bwd( 3067 icmCurve *p, 3068 double *out, 3069 double *in 3070 ) { 3071 icc *icp = p->icp; 3072 int rv = 0; 3073 if (p->flag == icmCurveLin) { 3074 *out = *in; 3075 } else if (p->flag == icmCurveGamma) { 3076 double val = *in; 3077 if (val <= 0.0) 3078 *out = 0.0; 3079 else 3080 *out = pow(val, 1.0/p->data[0]); 3081 } else { /* Use linear interpolation */ 3082 if (p->rt.inited == 0) { 3083 rv = icmTable_setup_bwd(icp, &p->rt, p->size, p->data); 3084 if (rv != 0) { 3085 sprintf(icp->err,"icmCurve_lookup: Malloc failure in reverse lookup init."); 3086 return icp->errc = rv; 3087 } 3088 } 3089 rv = icmTable_lookup_bwd(&p->rt, out, in); 3090 } 3091 return rv; 3092 } 3093 3094 /* Return the number of bytes needed to write this tag */ 3095 static unsigned int icmCurve_get_size( 3096 icmBase *pp 3097 ) { 3098 icmCurve *p = (icmCurve *)pp; 3099 unsigned int len = 0; 3100 len += 12; /* 12 bytes for tag, padding and count */ 3101 len += p->size * 2; /* 2 bytes for each UInt16 */ 3102 return len; 3103 } 3104 3105 /* read the object, return 0 on success, error code on fail */ 3106 static int icmCurve_read( 3107 icmBase *pp, 3108 unsigned long len, /* tag length */ 3109 unsigned long of /* start offset within file */ 3110 ) { 3111 icmCurve *p = (icmCurve *)pp; 3112 icc *icp = p->icp; 3113 int rv = 0; 3114 unsigned long i; 3115 char *bp, *buf, *end; 3116 3117 if (len < 12) { 3118 sprintf(icp->err,"icmCurve_read: Tag too small to be legal"); 3119 return icp->errc = 1; 3120 } 3121 3122 /* Allocate a file read buffer */ 3123 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3124 sprintf(icp->err,"icmCurve_read: malloc() failed"); 3125 return icp->errc = 2; 3126 } 3127 bp = buf; 3128 end = buf + len; 3129 3130 /* Read portion of file into buffer */ 3131 if ( icp->fp->seek(icp->fp, of) != 0 3132 || icp->fp->read(icp->fp, bp, 1, len) != len) { 3133 sprintf(icp->err,"icmCurve_read: fseek() or fread() failed"); 3134 icp->al->free(icp->al, buf); 3135 return icp->errc = 1; 3136 } 3137 3138 /* Read type descriptor from the buffer */ 3139 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 3140 sprintf(icp->err,"icmCurve_read: Wrong tag type for icmCurve"); 3141 icp->al->free(icp->al, buf); 3142 return icp->errc = 1; 3143 } 3144 3145 p->size = read_UInt32Number(bp+8); 3146 bp = bp + 12; 3147 3148 /* Set flag up before allocating */ 3149 if (p->size == 0) { /* Linear curve */ 3150 p->flag = icmCurveLin; 3151 } else if (p->size == 1) { /* Gamma curve */ 3152 p->flag = icmCurveGamma; 3153 } else { 3154 p->flag = icmCurveSpec; 3155 } 3156 3157 if ((rv = p->allocate((icmBase *)p)) != 0) { 3158 icp->al->free(icp->al, buf); 3159 return rv; 3160 } 3161 3162 if (p->flag == icmCurveGamma) { /* Gamma curve */ 3163 if ((bp + 1) > end) { 3164 sprintf(icp->err,"icmCurve_read: Data too short to curve gamma"); 3165 icp->al->free(icp->al, buf); 3166 return icp->errc = 1; 3167 } 3168 p->data[0] = read_U8Fixed8Number(bp); 3169 } else if (p->flag == icmCurveSpec) { 3170 /* Read all the data from the buffer */ 3171 for (i = 0; i < p->size; i++, bp += 2) { 3172 if ((bp + 2) > end) { 3173 sprintf(icp->err,"icmData_read: Data too short to curve value"); 3174 icp->al->free(icp->al, buf); 3175 return icp->errc = 1; 3176 } 3177 p->data[i] = read_DCS16Number(bp); 3178 } 3179 } 3180 icp->al->free(icp->al, buf); 3181 return 0; 3182 } 3183 3184 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 3185 static int icmCurve_write( 3186 icmBase *pp, 3187 unsigned long of /* File offset to write from */ 3188 ) { 3189 icmCurve *p = (icmCurve *)pp; 3190 icc *icp = p->icp; 3191 unsigned long i; 3192 unsigned int len; 3193 char *bp, *buf; /* Buffer to write from */ 3194 int rv = 0; 3195 3196 /* Allocate a file write buffer */ 3197 len = p->get_size((icmBase *)p); 3198 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3199 sprintf(icp->err,"icmCurve_write malloc() failed"); 3200 return icp->errc = 2; 3201 } 3202 bp = buf; 3203 3204 /* Write type descriptor to the buffer */ 3205 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 3206 sprintf(icp->err,"icmCurve_write: write_SInt32Number() failed"); 3207 icp->al->free(icp->al, buf); 3208 return icp->errc = rv; 3209 } 3210 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 3211 /* Write count */ 3212 if ((rv = write_UInt32Number(p->size,bp+8)) != 0) { 3213 sprintf(icp->err,"icmCurve_write: write_UInt32Number() failed"); 3214 icp->al->free(icp->al, buf); 3215 return icp->errc = rv; 3216 } 3217 3218 /* Write all the data to the buffer */ 3219 bp += 12; /* Skip padding */ 3220 if (p->flag == icmCurveLin) { 3221 if (p->size != 0) { 3222 sprintf(icp->err,"icmCurve_write: Must be exactly 0 entry for Linear"); 3223 icp->al->free(icp->al, buf); 3224 return icp->errc = 1; 3225 } 3226 } else if (p->flag == icmCurveGamma) { 3227 if (p->size != 1) { 3228 sprintf(icp->err,"icmCurve_write: Must be exactly 1 entry for Gamma"); 3229 icp->al->free(icp->al, buf); 3230 return icp->errc = 1; 3231 } 3232 if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) { 3233 sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]); 3234 icp->al->free(icp->al, buf); 3235 return icp->errc = rv; 3236 } 3237 } else if (p->flag == icmCurveSpec) { 3238 if (p->size < 2) { 3239 sprintf(icp->err,"icmCurve_write: Must be 2 or more entries for Specified curve"); 3240 icp->al->free(icp->al, buf); 3241 return icp->errc = 1; 3242 } 3243 for (i = 0; i < p->size; i++, bp += 2) { 3244 if ((rv = write_DCS16Number(p->data[i],bp)) != 0) { 3245 sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]); 3246 icp->al->free(icp->al, buf); 3247 return icp->errc = rv; 3248 } 3249 } 3250 } 3251 3252 /* Write to the file */ 3253 if ( icp->fp->seek(icp->fp, of) != 0 3254 || icp->fp->write(icp->fp, buf, 1, len) != len) { 3255 sprintf(icp->err,"icmCurve_write fseek() or fwrite() failed"); 3256 icp->al->free(icp->al, buf); 3257 return icp->errc = 2; 3258 } 3259 icp->al->free(icp->al, buf); 3260 return 0; 3261 } 3262 3263 /* Dump a text description of the object */ 3264 static void icmCurve_dump( 3265 icmBase *pp, 3266 FILE *op, /* Output to dump to */ 3267 int verb /* Verbosity level */ 3268 ) { 3269 icmCurve *p = (icmCurve *)pp; 3270 if (verb <= 0) 3271 return; 3272 3273 fprintf(op,"Curve:\n"); 3274 3275 if (p->flag == icmCurveLin) { 3276 fprintf(op," Curve is linear\n"); 3277 } else if (p->flag == icmCurveGamma) { 3278 fprintf(op," Curve is gamma of %f\n",p->data[0]); 3279 } else { 3280 fprintf(op," No. elements = %u\n",p->size); 3281 if (verb >= 2) { 3282 unsigned long i; 3283 for (i = 0; i < p->size; i++) 3284 fprintf(op," % 3u: %f\n",i,p->data[i]); 3285 } 3286 } 3287 } 3288 3289 /* Allocate variable sized data elements */ 3290 static int icmCurve_allocate( 3291 icmBase *pp 3292 ) { 3293 icmCurve *p = (icmCurve *)pp; 3294 icc *icp = p->icp; 3295 3296 if (p->flag == icmCurveUndef) { 3297 sprintf(icp->err,"icmCurve_alloc: flag not set"); 3298 return icp->errc = 1; 3299 } else if (p->flag == icmCurveLin) { 3300 p->size = 0; 3301 } else if (p->flag == icmCurveGamma) { 3302 p->size = 1; 3303 } 3304 if (p->size != p->_size) { 3305 if (p->data != NULL) 3306 icp->al->free(icp->al, p->data); 3307 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) { 3308 sprintf(icp->err,"icmCurve_alloc: malloc() of icmCurve data failed"); 3309 return icp->errc = 2; 3310 } 3311 p->_size = p->size; 3312 } 3313 return 0; 3314 } 3315 3316 /* Free all storage in the object */ 3317 static void icmCurve_delete( 3318 icmBase *pp 3319 ) { 3320 icmCurve *p = (icmCurve *)pp; 3321 icc *icp = p->icp; 3322 3323 if (p->data != NULL) 3324 icp->al->free(icp->al, p->data); 3325 icmTable_delete_bwd(icp, &p->rt); /* Free reverse table info */ 3326 icp->al->free(icp->al, p); 3327 } 3328 3329 /* Create an empty object. Return null on error */ 3330 static icmBase *new_icmCurve( 3331 icc *icp 3332 ) { 3333 icmCurve *p; 3334 if ((p = (icmCurve *) icp->al->calloc(icp->al,1,sizeof(icmCurve))) == NULL) 3335 return NULL; 3336 p->ttype = icSigCurveType; 3337 p->refcount = 1; 3338 p->get_size = icmCurve_get_size; 3339 p->read = icmCurve_read; 3340 p->write = icmCurve_write; 3341 p->dump = icmCurve_dump; 3342 p->allocate = icmCurve_allocate; 3343 p->del = icmCurve_delete; 3344 p->icp = icp; 3345 3346 p->lookup_fwd = icmCurve_lookup_fwd; 3347 p->lookup_bwd = icmCurve_lookup_bwd; 3348 3349 p->rt.inited = 0; 3350 3351 p->flag = icmCurveUndef; 3352 return (icmBase *)p; 3353 } 3354 3355 /* ---------------------------------------------------------- */ 3356 /* icmData object */ 3357 3358 /* Return the number of bytes needed to write this tag */ 3359 static unsigned int icmData_get_size( 3360 icmBase *pp 3361 ) { 3362 icmData *p = (icmData *)pp; 3363 unsigned int len = 0; 3364 len += 12; /* 12 bytes for tag and padding */ 3365 len += p->size * 1; /* 1 byte for each data element */ 3366 return len; 3367 } 3368 3369 /* read the object, return 0 on success, error code on fail */ 3370 static int icmData_read( 3371 icmBase *pp, 3372 unsigned long len, /* tag length */ 3373 unsigned long of /* start offset within file */ 3374 ) { 3375 icmData *p = (icmData *)pp; 3376 icc *icp = p->icp; 3377 int rv = 0; 3378 unsigned size, f; 3379 char *bp, *buf; 3380 3381 if (len < 12) { 3382 sprintf(icp->err,"icmData_read: Tag too small to be legal"); 3383 return icp->errc = 1; 3384 } 3385 3386 /* Allocate a file read buffer */ 3387 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3388 sprintf(icp->err,"icmData_read: malloc() failed"); 3389 return icp->errc = 2; 3390 } 3391 bp = buf; 3392 3393 /* Read portion of file into buffer */ 3394 if ( icp->fp->seek(icp->fp, of) != 0 3395 || icp->fp->read(icp->fp, bp, 1, len) != len) { 3396 sprintf(icp->err,"icmData_read: fseek() or fread() failed"); 3397 icp->al->free(icp->al, buf); 3398 return icp->errc = 1; 3399 } 3400 p->size = size = (len - 12)/1; /* Number of elements in the array */ 3401 3402 /* Read type descriptor from the buffer */ 3403 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 3404 sprintf(icp->err,"icmData_read: Wrong tag type for icmData"); 3405 icp->al->free(icp->al, buf); 3406 return icp->errc = 1; 3407 } 3408 /* Read the data type flag */ 3409 f = read_UInt32Number(bp+8); 3410 if (f == 0) { 3411 p->flag = icmDataASCII; 3412 } else if (f == 1) { 3413 p->flag = icmDataBin; 3414 } else { 3415 sprintf(icp->err,"icmData_read: Unknown flag value 0x%x",f); 3416 icp->al->free(icp->al, buf); 3417 return icp->errc = 1; 3418 } 3419 bp += 12; /* Skip padding and flag */ 3420 3421 if (p->size > 0) { 3422 if (p->flag == icmDataASCII) { 3423 if (check_null_string(bp,p->size) != 0) { 3424 sprintf(icp->err,"icmData_read: ACSII is not null terminated"); 3425 icp->al->free(icp->al, buf); 3426 return icp->errc = 1; 3427 } 3428 } 3429 if ((rv = p->allocate((icmBase *)p)) != 0) { 3430 icp->al->free(icp->al, buf); 3431 return rv; 3432 } 3433 3434 memcpy((void *)p->data, (void *)bp, p->size); 3435 } 3436 icp->al->free(icp->al, buf); 3437 return 0; 3438 } 3439 3440 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 3441 static int icmData_write( 3442 icmBase *pp, 3443 unsigned long of /* File offset to write from */ 3444 ) { 3445 icmData *p = (icmData *)pp; 3446 icc *icp = p->icp; 3447 unsigned int len, f; 3448 char *bp, *buf; /* Buffer to write from */ 3449 int rv = 0; 3450 3451 /* Allocate a file write buffer */ 3452 len = p->get_size((icmBase *)p); 3453 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3454 sprintf(icp->err,"icmData_write malloc() failed"); 3455 return icp->errc = 2; 3456 } 3457 bp = buf; 3458 3459 /* Write type descriptor to the buffer */ 3460 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 3461 sprintf(icp->err,"icmData_write: write_SInt32Number() failed"); 3462 icp->al->free(icp->al, buf); 3463 return icp->errc = rv; 3464 } 3465 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 3466 switch(p->flag) { 3467 case icmDataASCII: 3468 f = 0; 3469 break; 3470 case icmDataBin: 3471 f = 1; 3472 break; 3473 default: 3474 sprintf(icp->err,"icmData_write: Unknown Data Flag value"); 3475 icp->al->free(icp->al, buf); 3476 return icp->errc = 1; 3477 } 3478 /* Write data flag descriptor to the buffer */ 3479 if ((rv = write_UInt32Number(f,bp+8)) != 0) { 3480 sprintf(icp->err,"icmData_write: write_SInt32Number() failed"); 3481 icp->al->free(icp->al, buf); 3482 return icp->errc = rv; 3483 } 3484 bp += 12; /* Skip padding */ 3485 3486 if (p->data != NULL) { 3487 if (p->flag == icmDataASCII) { 3488 if ((rv = check_null_string((char*)p->data, p->size)) != 0) { /* RSC added cast */ 3489 sprintf(icp->err,"icmData_write: ASCII is not null terminated"); 3490 icp->al->free(icp->al, buf); 3491 return icp->errc = 1; 3492 } 3493 } 3494 memcpy((void *)bp, (void *)p->data, p->size); 3495 } 3496 3497 /* Write to the file */ 3498 if ( icp->fp->seek(icp->fp, of) != 0 3499 || icp->fp->write(icp->fp, buf, 1, len) != len) { 3500 sprintf(icp->err,"icmData_write fseek() or fwrite() failed"); 3501 icp->al->free(icp->al, buf); 3502 return icp->errc = 2; 3503 } 3504 icp->al->free(icp->al, buf); 3505 return 0; 3506 } 3507 3508 /* Dump a text description of the object */ 3509 static void icmData_dump( 3510 icmBase *pp, 3511 FILE *op, /* Output to dump to */ 3512 int verb /* Verbosity level */ 3513 ) { 3514 icmData *p = (icmData *)pp; 3515 unsigned long i, r, c, size; 3516 3517 if (verb <= 0) 3518 return; 3519 3520 fprintf(op,"Data:\n"); 3521 switch(p->flag) { 3522 case icmDataASCII: 3523 fprintf(op," ASCII data\n"); 3524 size = p->size > 0 ? p->size-1 : 0; 3525 break; 3526 case icmDataBin: 3527 fprintf(op," Binary data\n"); 3528 size = p->size; 3529 break; 3530 } 3531 fprintf(op," No. elements = %u\n",p->size); 3532 3533 i = 0; 3534 for (r = 1;; r++) { /* count rows */ 3535 if (i >= size) { 3536 fprintf(op,"\n"); 3537 break; 3538 } 3539 if (r > 1 && verb < 2) { 3540 fprintf(op,"...\n"); 3541 break; /* Print 1 row if not verbose */ 3542 } 3543 c = 1; 3544 fprintf(op," 0x%04x: ",i); 3545 c += 10; 3546 while (i < size && c < 75) { 3547 if (p->flag == icmDataASCII) { 3548 if (isprint(p->data[i])) { 3549 fprintf(op,"%c",p->data[i]); 3550 c++; 3551 } else { 3552 fprintf(op,"\\%03o",p->data[i]); 3553 c += 4; 3554 } 3555 } else { 3556 fprintf(op,"%02x ",p->data[i]); 3557 c += 3; 3558 } 3559 i++; 3560 } 3561 if (i < size) 3562 fprintf(op,"\n"); 3563 } 3564 } 3565 3566 /* Allocate variable sized data elements */ 3567 static int icmData_allocate( 3568 icmBase *pp 3569 ) { 3570 icmData *p = (icmData *)pp; 3571 icc *icp = p->icp; 3572 3573 if (p->size != p->_size) { 3574 if (p->data != NULL) 3575 icp->al->free(icp->al, p->data); 3576 if ((p->data = (unsigned char *) icp->al->malloc(icp->al, p->size * sizeof(unsigned char))) == NULL) { 3577 sprintf(icp->err,"icmData_alloc: malloc() of icmData data failed"); 3578 return icp->errc = 2; 3579 } 3580 p->_size = p->size; 3581 } 3582 return 0; 3583 } 3584 3585 /* Free all storage in the object */ 3586 static void icmData_delete( 3587 icmBase *pp 3588 ) { 3589 icmData *p = (icmData *)pp; 3590 icc *icp = p->icp; 3591 3592 if (p->data != NULL) 3593 icp->al->free(icp->al, p->data); 3594 icp->al->free(icp->al, p); 3595 } 3596 3597 /* Create an empty object. Return null on error */ 3598 static icmBase *new_icmData( 3599 icc *icp 3600 ) { 3601 icmData *p; 3602 if ((p = (icmData *) icp->al->calloc(icp->al,1,sizeof(icmData))) == NULL) 3603 return NULL; 3604 p->ttype = icSigDataType; 3605 p->refcount = 1; 3606 p->get_size = icmData_get_size; 3607 p->read = icmData_read; 3608 p->write = icmData_write; 3609 p->dump = icmData_dump; 3610 p->allocate = icmData_allocate; 3611 p->del = icmData_delete; 3612 p->icp = icp; 3613 3614 p->flag = icmDataUndef; 3615 return (icmBase *)p; 3616 } 3617 3618 /* ---------------------------------------------------------- */ 3619 /* icmText object */ 3620 3621 /* Return the number of bytes needed to write this tag */ 3622 static unsigned int icmText_get_size( 3623 icmBase *pp 3624 ) { 3625 icmText *p = (icmText *)pp; 3626 unsigned int len = 0; 3627 len += 8; /* 8 bytes for tag and padding */ 3628 len += p->size; /* 1 byte for each character element (inc. null) */ 3629 return len; 3630 } 3631 3632 /* read the object, return 0 on success, error code on fail */ 3633 static int icmText_read( 3634 icmBase *pp, 3635 unsigned long len, /* tag length */ 3636 unsigned long of /* start offset within file */ 3637 ) { 3638 icmText *p = (icmText *)pp; 3639 icc *icp = p->icp; 3640 int rv = 0; 3641 char *bp, *buf; 3642 3643 if (len < 8) { 3644 sprintf(icp->err,"icmText_read: Tag too short to be legal"); 3645 return icp->errc = 1; 3646 } 3647 3648 /* Allocate a file read buffer */ 3649 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3650 sprintf(icp->err,"icmText_read: malloc() failed"); 3651 return icp->errc = 2; 3652 } 3653 bp = buf; 3654 3655 /* Read portion of file into buffer */ 3656 if ( icp->fp->seek(icp->fp, of) != 0 3657 || icp->fp->read(icp->fp, bp, 1, len) != len) { 3658 sprintf(icp->err,"icmText_read: fseek() or fread() failed"); 3659 icp->al->free(icp->al, buf); 3660 return icp->errc = 1; 3661 } 3662 p->size = (len - 8)/1; /* Number of elements in the array */ 3663 3664 /* Read type descriptor from the buffer */ 3665 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 3666 sprintf(icp->err,"icmText_read: Wrong tag type for icmText"); 3667 icp->al->free(icp->al, buf); 3668 return icp->errc = 1; 3669 } 3670 bp = bp + 8; 3671 3672 if (p->size > 0) { 3673 if (check_null_string(bp,p->size) != 0) { 3674 sprintf(icp->err,"icmText_read: text is not null terminated"); 3675 icp->al->free(icp->al, buf); 3676 return icp->errc = 1; 3677 } 3678 if ((rv = p->allocate((icmBase *)p)) != 0) { 3679 icp->al->free(icp->al, buf); 3680 return rv; 3681 } 3682 memcpy((void *)p->data, (void *)bp, p->size); 3683 } 3684 icp->al->free(icp->al, buf); 3685 return 0; 3686 } 3687 3688 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 3689 static int icmText_write( 3690 icmBase *pp, 3691 unsigned long of /* File offset to write from */ 3692 ) { 3693 icmText *p = (icmText *)pp; 3694 icc *icp = p->icp; 3695 unsigned int len; 3696 char *bp, *buf; /* Buffer to write from */ 3697 int rv = 0; 3698 3699 /* Allocate a file write buffer */ 3700 len = p->get_size((icmBase *)p); 3701 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3702 sprintf(icp->err,"icmText_write malloc() failed"); 3703 return icp->errc = 2; 3704 } 3705 bp = buf; 3706 3707 /* Write type descriptor to the buffer */ 3708 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 3709 sprintf(icp->err,"icmText_write: write_SInt32Number() failed"); 3710 icp->al->free(icp->al, buf); 3711 return icp->errc = rv; 3712 } 3713 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 3714 bp = bp + 8; 3715 3716 if (p->data != NULL) { 3717 if ((rv = check_null_string(p->data, p->size)) != 0) { 3718 sprintf(icp->err,"icmText_write: text is not null terminated"); 3719 icp->al->free(icp->al, buf); 3720 return icp->errc = 1; 3721 } 3722 memcpy((void *)bp, (void *)p->data, p->size); 3723 } 3724 3725 /* Write to the file */ 3726 if ( icp->fp->seek(icp->fp, of) != 0 3727 || icp->fp->write(icp->fp, buf, 1, len) != len) { 3728 sprintf(icp->err,"icmText_write fseek() or fwrite() failed"); 3729 icp->al->free(icp->al, buf); 3730 return icp->errc = 2; 3731 } 3732 icp->al->free(icp->al, buf); 3733 return 0; 3734 } 3735 3736 /* Dump a text description of the object */ 3737 static void icmText_dump( 3738 icmBase *pp, 3739 FILE *op, /* Output to dump to */ 3740 int verb /* Verbosity level */ 3741 ) { 3742 icmText *p = (icmText *)pp; 3743 unsigned long i, r, c, size; 3744 3745 if (verb <= 0) 3746 return; 3747 3748 fprintf(op,"Text:\n"); 3749 fprintf(op," No. chars = %u\n",p->size); 3750 3751 size = p->size > 0 ? p->size-1 : 0; 3752 i = 0; 3753 for (r = 1;; r++) { /* count rows */ 3754 if (i >= size) { 3755 fprintf(op,"\n"); 3756 break; 3757 } 3758 if (r > 1 && verb < 2) { 3759 fprintf(op,"...\n"); 3760 break; /* Print 1 row if not verbose */ 3761 } 3762 c = 1; 3763 fprintf(op," 0x%04x: ",i); 3764 c += 10; 3765 while (i < size && c < 75) { 3766 if (isprint(p->data[i])) { 3767 fprintf(op,"%c",p->data[i]); 3768 c++; 3769 } else { 3770 fprintf(op,"\\%03o",p->data[i]); 3771 c += 4; 3772 } 3773 i++; 3774 } 3775 if (i < size) 3776 fprintf(op,"\n"); 3777 } 3778 } 3779 3780 /* Allocate variable sized data elements */ 3781 static int icmText_allocate( 3782 icmBase *pp 3783 ) { 3784 icmText *p = (icmText *)pp; 3785 icc *icp = p->icp; 3786 3787 if (p->size != p->_size) { 3788 if (p->data != NULL) 3789 icp->al->free(icp->al, p->data); 3790 if ((p->data = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) { 3791 sprintf(icp->err,"icmText_alloc: malloc() of icmText data failed"); 3792 return icp->errc = 2; 3793 } 3794 p->_size = p->size; 3795 } 3796 return 0; 3797 } 3798 3799 /* Free all storage in the object */ 3800 static void icmText_delete( 3801 icmBase *pp 3802 ) { 3803 icmText *p = (icmText *)pp; 3804 icc *icp = p->icp; 3805 3806 if (p->data != NULL) 3807 icp->al->free(icp->al, p->data); 3808 icp->al->free(icp->al, p); 3809 } 3810 3811 /* Create an empty object. Return null on error */ 3812 static icmBase *new_icmText( 3813 icc *icp 3814 ) { 3815 icmText *p; 3816 if ((p = (icmText *) icp->al->calloc(icp->al,1,sizeof(icmText))) == NULL) 3817 return NULL; 3818 p->ttype = icSigTextType; 3819 p->refcount = 1; 3820 p->get_size = icmText_get_size; 3821 p->read = icmText_read; 3822 p->write = icmText_write; 3823 p->dump = icmText_dump; 3824 p->allocate = icmText_allocate; 3825 p->del = icmText_delete; 3826 p->icp = icp; 3827 3828 return (icmBase *)p; 3829 } 3830 3831 /* ---------------------------------------------------------- */ 3832 3833 /* Data conversion support functions */ 3834 static int write_DateTimeNumber(icmDateTimeNumber *p, char *d) { 3835 int rv; 3836 if (p->year < 1900 || p->year > 3000 3837 || p->month == 0 || p->month > 12 3838 || p->day == 0 || p->day > 31 3839 || p->hours > 23 3840 || p->minutes > 59 3841 || p->seconds > 59) 3842 return 1; 3843 3844 if ((rv = write_UInt16Number(p->year, d + 0)) != 0) 3845 return rv; 3846 if ((rv = write_UInt16Number(p->month, d + 2)) != 0) 3847 return rv; 3848 if ((rv = write_UInt16Number(p->day, d + 4)) != 0) 3849 return rv; 3850 if ((rv = write_UInt16Number(p->hours, d + 6)) != 0) 3851 return rv; 3852 if ((rv = write_UInt16Number(p->minutes, d + 8)) != 0) 3853 return rv; 3854 if ((rv = write_UInt16Number(p->seconds, d + 10)) != 0) 3855 return rv; 3856 return 0; 3857 } 3858 3859 static int read_DateTimeNumber(icmDateTimeNumber *p, char *d) { 3860 p->year = read_UInt16Number(d + 0); 3861 p->month = read_UInt16Number(d + 2); 3862 p->day = read_UInt16Number(d + 4); 3863 p->hours = read_UInt16Number(d + 6); 3864 p->minutes = read_UInt16Number(d + 8); 3865 p->seconds = read_UInt16Number(d + 10); 3866 3867 if (p->year < 1900 || p->year > 3000 3868 || p->month == 0 || p->month > 12 3869 || p->day == 0 || p->day > 31 3870 || p->hours > 23 3871 || p->minutes > 59 3872 || p->seconds > 59) { 3873 unsigned int tt; 3874 3875 /* Check for Adobe problem */ 3876 if (p->month < 1900 || p->month > 3000 3877 || p->year == 0 || p->year > 12 3878 || p->hours == 0 || p->hours > 31 3879 || p->day > 23 3880 || p->seconds > 59 3881 || p->minutes > 59) 3882 return 1; /* Nope */ 3883 3884 /* Correct Adobe's faulty profile */ 3885 tt = p->month; p->month = p->year; p->year = tt; 3886 tt = p->hours; p->hours = p->day; p->day = tt; 3887 tt = p->seconds; p->seconds = p->minutes; p->minutes = tt; 3888 return 0; 3889 } 3890 return 0; 3891 } 3892 3893 /* Return a string that shows the given date and time */ 3894 static char *string_DateTimeNumber(icmDateTimeNumber *p) { 3895 static char *mstring[13] = {"Bad", "Jan","Feb","Mar","Apr","May","Jun", 3896 "Jul","Aug","Sep","Oct","Nov","Dec"}; 3897 static char buf[80]; 3898 3899 sprintf(buf,"%d %s %4d, %d:%02d:%02d", 3900 p->day, mstring[p->month > 12 ? 0 : p->month], p->year, 3901 p->hours, p->minutes, p->seconds); 3902 return buf; 3903 } 3904 3905 /* Set the DateTime structure to the current date and time */ 3906 static void setcur_DateTimeNumber(icmDateTimeNumber *p) { 3907 time_t cclk; 3908 struct tm *ctm; 3909 3910 cclk = time(NULL); 3911 ctm = localtime(&cclk); 3912 3913 p->year = ctm->tm_year + 1900; 3914 p->month = ctm->tm_mon + 1; 3915 p->day = ctm->tm_mday; 3916 p->hours = ctm->tm_hour; 3917 p->minutes = ctm->tm_min; 3918 p->seconds = ctm->tm_sec; 3919 } 3920 3921 /* Return the number of bytes needed to write this tag */ 3922 static unsigned int icmDateTimeNumber_get_size( 3923 icmBase *pp 3924 ) { 3925 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 3926 unsigned int len = 0; 3927 len += 8; /* 8 bytes for tag and padding */ 3928 len += 12; /* 12 bytes for Date & Time */ 3929 return len; 3930 } 3931 3932 /* read the object, return 0 on success, error code on fail */ 3933 static int icmDateTimeNumber_read( 3934 icmBase *pp, 3935 unsigned long len, /* tag length */ 3936 unsigned long of /* start offset within file */ 3937 ) { 3938 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 3939 icc *icp = p->icp; 3940 int rv; 3941 char *bp, *buf; 3942 3943 if (len < 20) { 3944 sprintf(icp->err,"icmDateTimeNumber_read: Tag too small to be legal"); 3945 return icp->errc = 1; 3946 } 3947 3948 /* Allocate a file read buffer */ 3949 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3950 sprintf(icp->err,"icmDateTimeNumber_read: malloc() failed"); 3951 return icp->errc = 2; 3952 } 3953 bp = buf; 3954 3955 /* Read portion of file into buffer */ 3956 if ( icp->fp->seek(icp->fp, of) != 0 3957 || icp->fp->read(icp->fp, bp, 1, len) != len) { 3958 sprintf(icp->err,"icmDateTimeNumber_read: fseek() or fread() failed"); 3959 icp->al->free(icp->al, buf); 3960 return icp->errc = 1; 3961 } 3962 3963 /* Read type descriptor from the buffer */ 3964 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 3965 sprintf(icp->err,"icmDateTimeNumber_read: Wrong tag type for icmDateTimeNumber"); 3966 icp->al->free(icp->al, buf); 3967 return icp->errc = 1; 3968 } 3969 bp += 8; /* Skip padding */ 3970 3971 /* Read the time and date from buffer */ 3972 if((rv = read_DateTimeNumber(p, bp)) != 0) { 3973 sprintf(icp->err,"icmDateTimeNumber_read: Corrupted DateTime"); 3974 icp->al->free(icp->al, buf); 3975 return icp->errc = rv; 3976 } 3977 3978 icp->al->free(icp->al, buf); 3979 return 0; 3980 } 3981 3982 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 3983 static int icmDateTimeNumber_write( 3984 icmBase *pp, 3985 unsigned long of /* File offset to write from */ 3986 ) { 3987 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 3988 icc *icp = p->icp; 3989 unsigned int len; 3990 char *bp, *buf; /* Buffer to write from */ 3991 int rv = 0; 3992 3993 /* Allocate a file write buffer */ 3994 len = p->get_size((icmBase *)p); 3995 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 3996 sprintf(icp->err,"icmDateTimeNumber_write malloc() failed"); 3997 return icp->errc = 2; 3998 } 3999 bp = buf; 4000 4001 /* Write type descriptor to the buffer */ 4002 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 4003 sprintf(icp->err,"icmDateTimeNumber_write: write_SInt32Number() failed"); 4004 icp->al->free(icp->al, buf); 4005 return icp->errc = rv; 4006 } 4007 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 4008 4009 /* Write all the data to the buffer */ 4010 bp += 8; /* Skip padding */ 4011 if ((rv = write_DateTimeNumber(p, bp)) != 0) { 4012 sprintf(icp->err,"icmDateTimeNumber_write: write_DateTimeNumber() failed"); 4013 icp->al->free(icp->al, buf); 4014 return icp->errc = rv; 4015 } 4016 4017 /* Write to the file */ 4018 if ( icp->fp->seek(icp->fp, of) != 0 4019 || icp->fp->write(icp->fp, buf, 1, len) != len) { 4020 sprintf(icp->err,"icmDateTimeNumber_write fseek() or fwrite() failed"); 4021 icp->al->free(icp->al, buf); 4022 return icp->errc = 2; 4023 } 4024 icp->al->free(icp->al, buf); 4025 return 0; 4026 } 4027 4028 /* Dump a text description of the object */ 4029 static void icmDateTimeNumber_dump( 4030 icmBase *pp, 4031 FILE *op, /* Output to dump to */ 4032 int verb /* Verbosity level */ 4033 ) { 4034 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 4035 if (verb <= 0) 4036 return; 4037 4038 fprintf(op,"DateTimeNumber:\n"); 4039 fprintf(op," Date = %s\n", string_DateTimeNumber(p)); 4040 } 4041 4042 /* Allocate variable sized data elements */ 4043 static int icmDateTimeNumber_allocate( 4044 icmBase *pp 4045 ) { 4046 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 4047 4048 /* Nothing to do */ 4049 return 0; 4050 } 4051 4052 /* Free all storage in the object */ 4053 static void icmDateTimeNumber_delete( 4054 icmBase *pp 4055 ) { 4056 icmDateTimeNumber *p = (icmDateTimeNumber *)pp; 4057 icc *icp = p->icp; 4058 4059 icp->al->free(icp->al, p); 4060 } 4061 4062 /* Create an empty object. Return null on error */ 4063 static icmBase *new_icmDateTimeNumber( 4064 icc *icp 4065 ) { 4066 icmDateTimeNumber *p; 4067 if ((p = (icmDateTimeNumber *) icp->al->calloc(icp->al,1,sizeof(icmDateTimeNumber))) == NULL) 4068 return NULL; 4069 p->ttype = icSigDateTimeType; 4070 p->refcount = 1; 4071 p->get_size = icmDateTimeNumber_get_size; 4072 p->read = icmDateTimeNumber_read; 4073 p->write = icmDateTimeNumber_write; 4074 p->dump = icmDateTimeNumber_dump; 4075 p->allocate = icmDateTimeNumber_allocate; 4076 p->del = icmDateTimeNumber_delete; 4077 p->icp = icp; 4078 4079 setcur_DateTimeNumber(p); /* Default to current date and time */ 4080 return (icmBase *)p; 4081 } 4082 4083 /* ---------------------------------------------------------- */ 4084 /* icmLut object */ 4085 4086 /* Utility function - raise one integer to an integer power */ 4087 unsigned int uipow(unsigned int a, unsigned int b) { 4088 unsigned int rv = 1; 4089 for (; b > 0; b--) 4090 rv *= a; 4091 return rv; 4092 } 4093 4094 /* - - - - - - - - - - - - - - - - */ 4095 /* Check if the matrix is non-zero */ 4096 static int icmLut_nu_matrix( 4097 icmLut *p /* Pointer to Lut object */ 4098 ) { 4099 int i, j; 4100 4101 for (j = 0; j < 3; j++) { /* Rows */ 4102 for (i = 0; i < 3; i++) { /* Columns */ 4103 if ( (i == j && p->e[j][i] != 1.0) 4104 || (i != j && p->e[j][i] != 0.0)) 4105 return 1; 4106 } 4107 } 4108 return 0; 4109 } 4110 4111 /* return the locations of the minimum and */ 4112 /* maximum values of the given channel, in the clut */ 4113 void icmLut_min_max( 4114 icmLut *p, /* Pointer to Lut object */ 4115 double *minp, /* Return position of min/max */ 4116 double *maxp, 4117 int chan /* Chanel, -1 for average of all */ 4118 ) { 4119 double *tp; 4120 double minv, maxv; /* Values */ 4121 int e, ee, f; 4122 double gc[MAX_CHAN]; /* Grid coordinate */ 4123 4124 minv = 1e6; 4125 maxv = -1e6; 4126 4127 for (e = 0; e < p->inputChan; e++) 4128 gc[e] = 0; /* init coords */ 4129 4130 /* Search the whole table */ 4131 for (tp = p->clutTable, e = 0; e < p->inputChan; tp += p->outputChan) { 4132 double v; 4133 if (chan == -1) { 4134 for (v = 0.0, f = 0; f < p->outputChan; f++) 4135 v += tp[f]; 4136 } else { 4137 v = tp[chan]; 4138 } 4139 if (v < minv) { 4140 minv = v; 4141 for (ee = 0; ee < p->inputChan; ee++) 4142 minp[ee] = gc[ee]/(p->clutPoints-1.0); 4143 } 4144 if (v > maxv) { 4145 maxv = v; 4146 for (ee = 0; ee < p->inputChan; ee++) 4147 maxp[ee] = gc[ee]/(p->clutPoints-1.0); 4148 } 4149 4150 /* Increment coord */ 4151 for (e = 0; e < p->inputChan; e++) { 4152 gc[e]++; 4153 if (gc[e] < p->clutPoints) 4154 break; /* No carry */ 4155 gc[e] = 0; 4156 } 4157 } 4158 } 4159 4160 /* Convert XYZ throught Luts matrix */ 4161 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 4162 static int icmLut_lookup_matrix( 4163 icmLut *p, /* Pointer to Lut object */ 4164 double *out, /* Output array[outputChan] in ICC order - see Table 39 in 6.5.5 */ 4165 double *in /* Input array[inputChan] */ 4166 ) { 4167 double t0,t1; /* Take care if out == in */ 4168 t0 = p->e[0][0] * in[0] + p->e[0][1] * in[1] + p->e[0][2] * in[2]; 4169 t1 = p->e[1][0] * in[0] + p->e[1][1] * in[1] + p->e[1][2] * in[2]; 4170 out[2] = p->e[2][0] * in[0] + p->e[2][1] * in[1] + p->e[2][2] * in[2]; 4171 out[0] = t0; 4172 out[1] = t1; 4173 4174 return 0; 4175 } 4176 4177 /* Convert normalized numbers though this Luts input tables. */ 4178 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 4179 static int icmLut_lookup_input( 4180 icmLut *p, /* Pointer to Lut object */ 4181 double *out, /* Output array[inputChan] */ 4182 double *in /* Input array[inputChan] */ 4183 ) { 4184 int rv = 0; 4185 int ix,n; 4186 double inputEnt_1 = (double)(p->inputEnt-1); 4187 double *table = p->inputTable; 4188 4189 /* Use linear interpolation */ 4190 for (n = 0; n < p->inputChan; n++, table += p->inputEnt) { 4191 double val, w; 4192 val = in[n] * inputEnt_1; 4193 if (val < 0.0) { 4194 val = 0.0; 4195 rv |= 1; 4196 } else if (val > inputEnt_1) { 4197 val = inputEnt_1; 4198 rv |= 1; 4199 } 4200 ix = (int)floor(val); /* Grid coordinate */ 4201 if (ix > (p->inputEnt-2)) 4202 ix = (p->inputEnt-2); 4203 w = val - (double)ix; /* weight */ 4204 val = table[ix]; 4205 out[n] = val + w * (table[ix+1] - val); 4206 } 4207 return rv; 4208 } 4209 4210 /* Convert normalized numbers though this Luts multi-dimensional table. */ 4211 /* using n-linear interpolation. */ 4212 static int icmLut_lookup_clut_nl( 4213 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 4214 icmLut *p, /* Pointer to Lut object */ 4215 double *out, /* Output array[inputChan] */ 4216 double *in /* Input array[outputChan] */ 4217 ) { 4218 icc *icp = p->icp; 4219 int rv = 0; 4220 double *gp; /* Pointer to grid cube base */ 4221 double co[MAX_CHAN]; /* Coordinate offset with the grid cell */ 4222 double *gw, GW[1 << 8]; /* weight for each grid cube corner */ 4223 4224 if (p->inputChan <= 8) { 4225 gw = GW; /* Use stack allocation */ 4226 } else { 4227 if ((gw = (double *) icp->al->malloc(icp->al, (1 << p->inputChan) * sizeof(double))) == NULL) { 4228 sprintf(icp->err,"icmLut_lookup_clut: malloc() failed"); 4229 return icp->errc = 2; 4230 } 4231 } 4232 4233 /* We are using an n-linear (ie. Trilinear for 3D input) interpolation. */ 4234 /* The implimentation here uses more multiplies that some other schemes, */ 4235 /* (for instance, see "Tri-Linear Interpolation" by Steve Hill, */ 4236 /* Graphics Gems IV, page 521), but has less involved bookeeping, */ 4237 /* needs less local storage for intermediate output values, does fewer */ 4238 /* output and intermediate value reads, and fp multiplies are fast on */ 4239 /* todays processors! */ 4240 4241 /* Compute base index into grid and coordinate offsets */ 4242 { 4243 int e; 4244 double clutPoints_1 = (double)(p->clutPoints-1); 4245 int clutPoints_2 = p->clutPoints-2; 4246 gp = p->clutTable; /* Base of grid array */ 4247 4248 for (e = 0; e < p->inputChan; e++) { 4249 int x; 4250 double val; 4251 val = in[e] * clutPoints_1; 4252 if (val < 0.0) { 4253 val = 0.0; 4254 rv |= 1; 4255 } else if (val > clutPoints_1) { 4256 val = clutPoints_1; 4257 rv |= 1; 4258 } 4259 x = (int)floor(val); /* Grid coordinate */ 4260 if (x > clutPoints_2) 4261 x = clutPoints_2; 4262 co[e] = val - (double)x; /* 1.0 - weight */ 4263 gp += x * p->dinc[e]; /* Add index offset for base of cube */ 4264 } 4265 } 4266 /* Compute corner weights needed for interpolation */ 4267 { 4268 int e, i, g = 1; 4269 gw[0] = 1.0; 4270 for (e = 0; e < p->inputChan; e++) { 4271 for (i = 0; i < g; i++) { 4272 gw[g+i] = gw[i] * co[e]; 4273 gw[i] *= (1.0 - co[e]); 4274 } 4275 g *= 2; 4276 } 4277 } 4278 /* Now compute the output values */ 4279 { 4280 int i, f; 4281 double w = gw[0]; 4282 double *d = gp + p->dcube[0]; 4283 for (f = 0; f < p->outputChan; f++) /* Base of cube */ 4284 out[f] = w * d[f]; 4285 for (i = 1; i < (1 << p->inputChan); i++) { /* For all other corners of cube */ 4286 w = gw[i]; /* Strength reduce */ 4287 d = gp + p->dcube[i]; 4288 for (f = 0; f < p->outputChan; f++) { 4289 out[f] += w * d[f]; 4290 } 4291 } 4292 } 4293 if (gw != GW) 4294 icp->al->free(icp->al, (void *)gw); 4295 return rv; 4296 } 4297 4298 /* Convert normalized numbers though this Luts multi-dimensional table */ 4299 /* using simplex interpolation. */ 4300 static int icmLut_lookup_clut_sx( 4301 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 4302 icmLut *p, /* Pointer to Lut object */ 4303 double *out, /* Output array[inputChan] */ 4304 double *in /* Input array[outputChan] */ 4305 ) { 4306 int rv = 0; 4307 double *gp; /* Pointer to grid cube base */ 4308 double co[MAX_CHAN]; /* Coordinate offset with the grid cell */ 4309 int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */ 4310 4311 /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */ 4312 /* This method is more appropriate for XYZ/RGB/CMYK input spaces, */ 4313 4314 /* Compute base index into grid and coordinate offsets */ 4315 { 4316 int e; 4317 double clutPoints_1 = (double)(p->clutPoints-1); 4318 int clutPoints_2 = p->clutPoints-2; 4319 gp = p->clutTable; /* Base of grid array */ 4320 4321 for (e = 0; e < p->inputChan; e++) { 4322 int x; 4323 double val; 4324 val = in[e] * clutPoints_1; 4325 if (val < 0.0) { 4326 val = 0.0; 4327 rv |= 1; 4328 } else if (val > clutPoints_1) { 4329 val = clutPoints_1; 4330 rv |= 1; 4331 } 4332 x = (int)floor(val); /* Grid coordinate */ 4333 if (x > clutPoints_2) 4334 x = clutPoints_2; 4335 co[e] = val - (double)x; /* 1.0 - weight */ 4336 gp += x * p->dinc[e]; /* Add index offset for base of cube */ 4337 } 4338 } 4339 /* Do selection sort on coordinates */ 4340 { 4341 int e, f; 4342 for (e = 0; e < p->inputChan; e++) 4343 si[e] = e; /* Initial unsorted indexes */ 4344 for (e = 0; e < (p->inputChan-1); e++) { 4345 double cosn; 4346 cosn = co[si[e]]; /* Current smallest value */ 4347 for (f = e+1; f < p->inputChan; f++) { /* Check against rest */ 4348 int tt; 4349 tt = si[f]; 4350 if (cosn > co[tt]) { 4351 si[f] = si[e]; /* Exchange */ 4352 si[e] = tt; 4353 cosn = co[tt]; 4354 } 4355 } 4356 } 4357 } 4358 /* Now compute the weightings, simplex vertices and output values */ 4359 { 4360 int e, f; 4361 double w; /* Current vertex weight */ 4362 4363 w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */ 4364 for (f = 0; f < p->outputChan; f++) 4365 out[f] = w * gp[f]; 4366 4367 for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */ 4368 w = co[si[e]] - co[si[e-1]]; 4369 gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */ 4370 for (f = 0; f < p->outputChan; f++) 4371 out[f] += w * gp[f]; 4372 } 4373 4374 w = co[si[0]]; 4375 gp += p->dinc[si[0]]; /* Far corner from base of cell */ 4376 for (f = 0; f < p->outputChan; f++) 4377 out[f] += w * gp[f]; 4378 } 4379 return rv; 4380 } 4381 4382 /* Convert normalized numbers though this Luts output tables. */ 4383 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 4384 static int icmLut_lookup_output( 4385 icmLut *p, /* Pointer to Lut object */ 4386 double *out, /* Output array[outputChan] */ 4387 double *in /* Input array[outputChan] */ 4388 ) { 4389 int rv = 0; 4390 int ix,n; 4391 double outputEnt_1 = (double)(p->outputEnt-1); 4392 double *table = p->outputTable; 4393 4394 /* Use linear interpolation */ 4395 for (n = 0; n < p->outputChan; n++, table += p->outputEnt) { 4396 double val, w; 4397 val = in[n] * outputEnt_1; 4398 if (val < 0.0) { 4399 val = 0.0; 4400 rv |= 1; 4401 } else if (val > outputEnt_1) { 4402 val = outputEnt_1; 4403 rv |= 1; 4404 } 4405 ix = (int)floor(val); /* Grid coordinate */ 4406 if (ix > (p->outputEnt-2)) 4407 ix = (p->outputEnt-2); 4408 w = val - (double)ix; /* weight */ 4409 val = table[ix]; 4410 out[n] = val + w * (table[ix+1] - val); 4411 } 4412 return rv; 4413 } 4414 4415 /* ----------------------------------------------- */ 4416 /* Pseudo - Hilbert count sequencer */ 4417 4418 /* This multi-dimensional count sequence is a distributed */ 4419 /* Gray code sequence, with direction reversal on every */ 4420 /* alternate power of 2 scale. */ 4421 /* It is intended to aid cache coherence in multi-dimensional */ 4422 /* regular sampling. It approximates the Hilbert curve sequence. */ 4423 4424 /* Initialise, returns total usable count */ 4425 unsigned 4426 psh_init( 4427 psh *p, /* Pointer to structure to initialise */ 4428 int di, /* Dimensionality */ 4429 unsigned res, /* Size per coordinate */ 4430 int co[] /* Coordinates to initialise (May be NULL) */ 4431 ) { 4432 int e; 4433 4434 p->di = di; 4435 p->res = res; 4436 4437 /* Compute bits */ 4438 for (p->bits = 0; (1 << p->bits) < res; p->bits++) 4439 ; 4440 4441 /* Compute the total count mask */ 4442 p->tmask = ((((unsigned)1) << (p->bits * di))-1); 4443 4444 /* Compute usable count */ 4445 p->count = 1; 4446 for (e = 0; e < di; e++) 4447 p->count *= res; 4448 4449 p->ix = 0; 4450 4451 if (co != NULL) { 4452 for (e = 0; e < di; e++) 4453 co[e] = 0; 4454 } 4455 4456 return p->count; 4457 } 4458 4459 /* Reset the counter */ 4460 void 4461 psh_reset( 4462 psh *p /* Pointer to structure */ 4463 ) { 4464 p->ix = 0; 4465 } 4466 4467 /* Increment pseudo-hilbert coordinates */ 4468 /* Return non-zero if count rolls over to 0 */ 4469 int 4470 psh_inc( 4471 psh *p, /* Pointer to structure */ 4472 int co[] /* Coordinates to return */ 4473 ) { 4474 int di = p->di; 4475 int res = p->res; 4476 int bits = p->bits; 4477 int e; 4478 4479 do { 4480 int b; 4481 int gix; /* Gray code index */ 4482 4483 p->ix = (p->ix + 1) & p->tmask; 4484 4485 gix = p->ix ^ (p->ix >> 1); /* Convert to gray code index */ 4486 4487 for (e = 0; e < di; e++) 4488 co[e] = 0; 4489 4490 for (b = 0; b < bits; b++) { /* Distribute bits */ 4491 if (b & 1) { 4492 for (e = di-1; e >= 0; e--) { /* In reverse order */ 4493 co[e] |= (gix & 1) << b; 4494 gix >>= 1; 4495 } 4496 } else { 4497 for (e = 0; e < di; e++) { /* In normal order */ 4498 co[e] |= (gix & 1) << b; 4499 gix >>= 1; 4500 } 4501 } 4502 } 4503 4504 /* Convert from Gray to binary coordinates */ 4505 for (e = 0; e < di; e++) { 4506 unsigned sh, tv; 4507 4508 for(sh = 1, tv = co[e];; sh <<= 1) { 4509 unsigned ptv = tv; 4510 tv ^= (tv >> sh); 4511 if (ptv <= 1 || sh == 16) 4512 break; 4513 } 4514 if (tv >= res) /* Dumbo filter - increment again if outside cube range */ 4515 break; 4516 co[e] = tv; 4517 } 4518 4519 } while (e < di); 4520 4521 return (p->ix == 0); 4522 } 4523 4524 /* ------------------------------------------------------- */ 4525 /* Parameter to getNormFunc function */ 4526 typedef enum { 4527 icmFromLuti = 0, /* return "fromo Lut normalized index" conversion function */ 4528 icmToLuti = 1, /* return "to Lut normalized index" conversion function */ 4529 icmFromLutv = 2, /* return "from Lut normalized value" conversion function */ 4530 icmToLutv = 3 /* return "to Lut normalized value" conversion function */ 4531 } icmNormFlag; 4532 4533 /* Return an appropriate color space normalization function, */ 4534 /* given the color space and Lut type */ 4535 /* Return 0 on success, 1 on match failure */ 4536 static int getNormFunc( 4537 icColorSpaceSignature csig, 4538 icTagTypeSignature tagSig, 4539 icmNormFlag flag, 4540 void (**nfunc)(double *out, double *in) 4541 ); 4542 4543 /* Helper function to initialize the three tables contents */ 4544 /* from supplied transfer functions. */ 4545 /* Set errc and return error number */ 4546 static int icmLut_set_tables ( 4547 icmLut *p, /* Pointer to Lut object */ 4548 void *cbctx, /* Opaque callback context pointer value */ 4549 icColorSpaceSignature insig, /* Input color space */ 4550 icColorSpaceSignature outsig, /* Output color space */ 4551 void (*infunc)(void *cbcntx, double *out, double *in), 4552 /* Input transfer function, inspace->inspace' (NULL = default) */ 4553 double *inmin, double *inmax, /* Maximum range of inspace' values (NULL = default) */ 4554 void (*clutfunc)(void *cbctx, double *out, double *in), 4555 /* inspace' -> outspace' transfer function */ 4556 double *clutmin, double *clutmax, /* Maximum range of outspace' values (NULL = default) */ 4557 void (*outfunc)(void *cbctx, double *out, double *in) 4558 /* Output transfer function, outspace'->outspace (NULL = deflt) */ 4559 ) { 4560 icc *icp = p->icp; 4561 int j, n, e; 4562 int ii[MAX_CHAN]; /* Index value */ 4563 psh counter; /* Pseudo-Hilbert counter */ 4564 double _iv[2 * MAX_CHAN], *iv = &_iv[MAX_CHAN]; /* Real index value/table value */ 4565 double imin[MAX_CHAN], imax[MAX_CHAN]; 4566 double omin[MAX_CHAN], omax[MAX_CHAN]; 4567 void (*ifromindex)(double *out, double *in); /* Index to input color space function */ 4568 void (*itoentry)(double *out, double *in); /* Input color space to entry function */ 4569 void (*ifromentry)(double *out, double *in); /* Entry to input color space function */ 4570 void (*otoentry)(double *out, double *in); /* Output colorspace to table value function */ 4571 void (*ofromentry)(double *out, double *in); /* Table value to output color space function */ 4572 4573 if (getNormFunc(insig, p->ttype, icmFromLuti, &ifromindex) != 0) { 4574 sprintf(icp->err,"icmLut_set_tables index to input colorspace function lookup failed"); 4575 return icp->errc = 1; 4576 } 4577 if (getNormFunc(insig, p->ttype, icmToLutv, &itoentry) != 0) { 4578 sprintf(icp->err,"icmLut_set_tables input colorspace to table entry function lookup failed"); 4579 return icp->errc = 1; 4580 } 4581 if (getNormFunc(insig, p->ttype, icmFromLutv, &ifromentry) != 0) { 4582 sprintf(icp->err,"icmLut_set_tables table entry to input colorspace function lookup failed"); 4583 return icp->errc = 1; 4584 } 4585 4586 if (getNormFunc(outsig, p->ttype, icmToLutv, &otoentry) != 0) { 4587 sprintf(icp->err,"icmLut_set_tables output colorspace to table entry function lookup failed"); 4588 return icp->errc = 1; 4589 } 4590 if (getNormFunc(outsig, p->ttype, icmFromLutv, &ofromentry) != 0) { 4591 sprintf(icp->err,"icmLut_set_tables table entry to output colorspace function lookup failed"); 4592 return icp->errc = 1; 4593 } 4594 4595 /* Setup input table value min-max */ 4596 if (inmin == NULL) { 4597 #ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Try symetrical range */ 4598 if (insig == icSigLabData) { /* Special case Lab */ 4599 double mn[3], mx[3]; 4600 /* Because the symetric range will cause slight clipping, */ 4601 /* only do it if the input table has sufficient resolution */ 4602 /* to represent the clipping faithfuly. */ 4603 if (p->inputEnt >= 64) { 4604 mn[0] = 0.0, mn[1] = -127.0, mn[2] = -127.0; 4605 mx[0] = 100.0, mx[1] = 127.0, mx[2] = 127.0; 4606 itoentry(imin, mn); /* Convert from input color space to table representation */ 4607 itoentry(imax, mx); 4608 } else { 4609 for (e = 0; e < p->inputChan; e++) { 4610 imin[e] = 0.0; 4611 imax[e] = 1.0; 4612 } 4613 } 4614 } else 4615 #endif 4616 { 4617 for (e = 0; e < p->inputChan; e++) { 4618 imin[e] = 0.0; /* We are assuming this is true for all other color spaces. */ 4619 imax[e] = 1.0; 4620 } 4621 } 4622 } else { 4623 itoentry(imin, inmin); /* Convert from input color space to table representation */ 4624 itoentry(imax, inmax); 4625 } 4626 4627 /* Setup output table value min-max */ 4628 if (clutmin == NULL) { 4629 #ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Try symetrical range */ 4630 if (outsig == icSigLabData) { /* Special case Lab */ 4631 double mn[3], mx[3]; 4632 /* Because the symetric range will cause slight clipping, */ 4633 /* only do it if the output table has sufficient resolution */ 4634 /* to represent the clipping faithfuly. */ 4635 if (p->outputEnt >= 64) { 4636 mn[0] = 0.0, mn[1] = -127.0, mn[2] = -127.0; 4637 mx[0] = 100.0, mx[1] = 127.0, mx[2] = 127.0; 4638 otoentry(omin, mn);/* Convert from output color space to table representation */ 4639 otoentry(omax, mx); 4640 } else { 4641 for (e = 0; e < p->inputChan; e++) { 4642 omin[e] = 0.0; 4643 omax[e] = 1.0; 4644 } 4645 } 4646 } else 4647 #endif 4648 { 4649 for (e = 0; e < p->outputChan; e++) { 4650 omin[e] = 0.0; /* We are assuming this is true for all other color spaces. */ 4651 omax[e] = 1.0; 4652 } 4653 } 4654 } else { 4655 otoentry(omin, clutmin);/* Convert from output color space to table representation */ 4656 otoentry(omax, clutmax); 4657 } 4658 4659 /* Create the input table entry values */ 4660 for (n = 0; n < p->inputEnt; n++) { 4661 double fv; 4662 fv = n/(p->inputEnt-1.0); 4663 for (e = 0; e < p->inputChan; e++) 4664 iv[e] = fv; 4665 4666 ifromindex(iv,iv); /* Convert from index value to input color space value */ 4667 4668 if (infunc != NULL) 4669 infunc(cbctx, iv, iv); /* In colorspace -> input table -> In colorspace. */ 4670 4671 itoentry(iv,iv); /* Convert from input color space value to table value */ 4672 4673 /* Expand used range to 0.0 - 1.0, and clip to legal values */ 4674 /* Note that if the range is reduced, and clipping occurs, */ 4675 /* then there should be enough resolution within the input */ 4676 /* table, to represent the sharp edges of the clipping. */ 4677 for (e = 0; e < p->inputChan; e++) { 4678 double tt; 4679 tt = (iv[e] - imin[e])/(imax[e] - imin[e]); 4680 if (tt < 0.0) 4681 tt = 0.0; 4682 else if (tt > 1.0) 4683 tt = 1.0; 4684 iv[e] = tt; 4685 } 4686 4687 for (e = 0; e < p->inputChan; e++) /* Input tables */ 4688 p->inputTable[e * p->inputEnt + n] = iv[e]; 4689 } 4690 4691 /* Create the multi-dimensional lookup table values */ 4692 4693 /* To make this clut function cache friendly, we use the pseudo-hilbert */ 4694 /* count sequence. This keeps each point close to the last in the */ 4695 /* multi-dimensional space. */ 4696 4697 psh_init(&counter, p->inputChan, p->clutPoints, ii); /* Initialise counter */ 4698 4699 /* Itterate through all verticies in the grid */ 4700 for (;;) { 4701 int ti; /* Table index */ 4702 4703 for (ti = e = 0; e < p->inputChan; e++) { /* Input tables */ 4704 ti += ii[e] * p->dinc[e]; /* Clut index */ 4705 iv[e] = ii[e]/(p->clutPoints-1.0); /* Vertex coordinates */ 4706 iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */ 4707 *((int *)&iv[-e-1]) = ii[e]; /* Trick to supply grid index in iv[] */ 4708 } 4709 4710 ifromentry(iv,iv); /* Convert from table value to input color space */ 4711 4712 /* Apply incolor -> outcolor function we want to represent */ 4713 clutfunc(cbctx, iv, iv); 4714 4715 otoentry(iv,iv); /* Convert from output color space value to table value */ 4716 4717 /* Expand used range to 0.0 - 1.0, and clip to legal values */ 4718 for (e = 0; e < p->outputChan; e++) { 4719 double tt; 4720 tt = (iv[e] - omin[e])/(omax[e] - omin[e]); 4721 if (tt < 0.0) 4722 tt = 0.0; 4723 else if (tt > 1.0) 4724 tt = 1.0; 4725 iv[e] = tt; 4726 } 4727 4728 for (e = 0; e < p->outputChan; e++) /* Output chans */ 4729 p->clutTable[ti++] = iv[e]; 4730 4731 /* Increment index within block (Reverse index significancd) */ 4732 if (psh_inc(&counter, ii)) 4733 break; 4734 } 4735 4736 /* Create the output table entry values */ 4737 for (n = 0; n < p->outputEnt; n++) { 4738 double fv; 4739 fv = n/(p->outputEnt-1.0); 4740 for (e = 0; e < p->outputChan; e++) 4741 iv[e] = fv; 4742 4743 /* Undo expansion to 0.0 - 1.0 */ 4744 for (e = 0; e < p->outputChan; e++) /* Output tables */ 4745 iv[e] = iv[e] * (omax[e] - omin[e]) + omin[e]; 4746 4747 ofromentry(iv,iv); /* Convert from table value to output color space value */ 4748 4749 if (outfunc != NULL) 4750 outfunc(cbctx, iv, iv); /* Out colorspace -> output table -> out colorspace. */ 4751 4752 otoentry(iv,iv); /* Convert from output color space value to table value */ 4753 4754 /* Clip to legal values */ 4755 for (e = 0; e < p->outputChan; e++) { 4756 double tt; 4757 tt = iv[e]; 4758 if (tt < 0.0) 4759 tt = 0.0; 4760 else if (tt > 1.0) 4761 tt = 1.0; 4762 iv[e] = tt; 4763 } 4764 4765 for (e = 0; e < p->outputChan; e++) /* Input tables */ 4766 p->outputTable[e * p->outputEnt + n] = iv[e]; 4767 } 4768 return 0; 4769 } 4770 4771 /* - - - - - - - - - - - - - - - - */ 4772 /* Return the number of bytes needed to write this tag */ 4773 static unsigned int icmLut_get_size( 4774 icmBase *pp 4775 ) { 4776 icmLut *p = (icmLut *)pp; 4777 unsigned int len = 0; 4778 4779 if (p->ttype == icSigLut8Type) { 4780 len += 48; /* tag and header */ 4781 len += 1 * (p->inputChan * p->inputEnt); 4782 len += 1 * (p->outputChan * uipow(p->clutPoints,p->inputChan)); 4783 len += 1 * (p->outputChan * p->outputEnt); 4784 } else { 4785 len += 52; /* tag and header */ 4786 len += 2 * (p->inputChan * p->inputEnt); 4787 len += 2 * (p->outputChan * uipow(p->clutPoints,p->inputChan)); 4788 len += 2 * (p->outputChan * p->outputEnt); 4789 } 4790 return len; 4791 } 4792 4793 /* read the object, return 0 on success, error code on fail */ 4794 static int icmLut_read( 4795 icmBase *pp, 4796 unsigned long len, /* tag length */ 4797 unsigned long of /* start offset within file */ 4798 ) { 4799 icmLut *p = (icmLut *)pp; 4800 icc *icp = p->icp; 4801 int rv = 0; 4802 unsigned long i, j, g, size; 4803 char *bp, *buf; 4804 4805 if (len < 4) { 4806 sprintf(icp->err,"icmLut_read: Tag too small to be legal"); 4807 return icp->errc = 1; 4808 } 4809 4810 /* Allocate a file read buffer */ 4811 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 4812 sprintf(icp->err,"icmLut_read: malloc() failed"); 4813 return icp->errc = 2; 4814 } 4815 bp = buf; 4816 4817 /* Read portion of file into buffer */ 4818 if ( icp->fp->seek(icp->fp, of) != 0 4819 || icp->fp->read(icp->fp, bp, 1, len) != len) { 4820 sprintf(icp->err,"icmLut_read: fseek() or fread() failed"); 4821 icp->al->free(icp->al, buf); 4822 return icp->errc = 1; 4823 } 4824 4825 /* Read type descriptor from the buffer */ 4826 p->ttype = (icTagTypeSignature)read_SInt32Number(bp); 4827 if (p->ttype != icSigLut8Type && p->ttype != icSigLut16Type) { 4828 sprintf(icp->err,"icmLut_read: Wrong tag type for icmLut"); 4829 icp->al->free(icp->al, buf); 4830 return icp->errc = 1; 4831 } 4832 4833 if (p->ttype == icSigLut8Type) { 4834 if (len < 48) { 4835 sprintf(icp->err,"icmLut_read: Tag too small to be legal"); 4836 icp->al->free(icp->al, buf); 4837 return icp->errc = 1; 4838 } 4839 } else { 4840 if (len < 52) { 4841 sprintf(icp->err,"icmLut_read: Tag too small to be legal"); 4842 icp->al->free(icp->al, buf); 4843 return icp->errc = 1; 4844 } 4845 } 4846 4847 /* Read in the info common to 8 and 16 bit Lut */ 4848 p->inputChan = read_UInt8Number(bp+8); 4849 p->outputChan = read_UInt8Number(bp+9); 4850 p->clutPoints = read_UInt8Number(bp+10); 4851 4852 /* Sanity check */ 4853 if (p->inputChan > MAX_CHAN) { 4854 sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN); 4855 return icp->errc = 1; 4856 } 4857 4858 if (p->outputChan > MAX_CHAN) { 4859 sprintf(icp->err,"icmLut_read: Can't handle > %d output channels\n",MAX_CHAN); 4860 return icp->errc = 1; 4861 } 4862 4863 /* Read 3x3 transform matrix */ 4864 for (j = 0; j < 3; j++) { /* Rows */ 4865 for (i = 0; i < 3; i++) { /* Columns */ 4866 p->e[j][i] = read_S15Fixed16Number(bp + 12 + ((j * 3 + i) * 4)); 4867 } 4868 } 4869 /* Read 16 bit specific stuff */ 4870 if (p->ttype == icSigLut8Type) { 4871 p->inputEnt = 256; /* By definition */ 4872 p->outputEnt = 256; /* By definition */ 4873 bp = buf+48; 4874 } else { 4875 p->inputEnt = read_UInt16Number(bp+48); 4876 p->outputEnt = read_UInt16Number(bp+50); 4877 bp = buf+52; 4878 } 4879 4880 if (len < icmLut_get_size((icmBase *)p)) { 4881 sprintf(icp->err,"icmLut_read: Tag too small for contents"); 4882 icp->al->free(icp->al, buf); 4883 return icp->errc = 1; 4884 } 4885 4886 /* Read the input tables */ 4887 size = (p->inputChan * p->inputEnt); 4888 if ((rv = p->allocate((icmBase *)p)) != 0) { 4889 icp->al->free(icp->al, buf); 4890 return rv; 4891 } 4892 if (p->ttype == icSigLut8Type) { 4893 for (i = 0; i < size; i++, bp += 1) 4894 p->inputTable[i] = read_DCS8Number(bp); 4895 } else { 4896 for (i = 0; i < size; i++, bp += 2) 4897 p->inputTable[i] = read_DCS16Number(bp); 4898 } 4899 4900 /* Read the clut table */ 4901 size = (p->outputChan * uipow(p->clutPoints,p->inputChan)); 4902 if ((rv = p->allocate((icmBase *)p)) != 0) { 4903 icp->al->free(icp->al, buf); 4904 return rv; 4905 } 4906 if (p->ttype == icSigLut8Type) { 4907 for (i = 0; i < size; i++, bp += 1) 4908 p->clutTable[i] = read_DCS8Number(bp); 4909 } else { 4910 for (i = 0; i < size; i++, bp += 2) 4911 p->clutTable[i] = read_DCS16Number(bp); 4912 } 4913 4914 /* Read the output tables */ 4915 size = (p->outputChan * p->outputEnt); 4916 if ((rv = p->allocate((icmBase *)p)) != 0) { 4917 icp->al->free(icp->al, buf); 4918 return rv; 4919 } 4920 if (p->ttype == icSigLut8Type) { 4921 for (i = 0; i < size; i++, bp += 1) 4922 p->outputTable[i] = read_DCS8Number(bp); 4923 } else { 4924 for (i = 0; i < size; i++, bp += 2) 4925 p->outputTable[i] = read_DCS16Number(bp); 4926 } 4927 4928 /* Private: compute dimensional increment though clut */ 4929 /* Note that first channel varies least rapidly. */ 4930 i = p->inputChan-1; 4931 p->dinc[i--] = p->outputChan; 4932 for (; i < p->inputChan; i--) 4933 p->dinc[i] = p->dinc[i+1] * p->clutPoints; 4934 4935 /* Private: compute offsets from base of cube to other corners */ 4936 for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) { 4937 for (i = 0; i < g; i++) 4938 p->dcube[g+i] = p->dcube[i] + p->dinc[j]; 4939 g *= 2; 4940 } 4941 4942 icp->al->free(icp->al, buf); 4943 return 0; 4944 } 4945 4946 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 4947 static int icmLut_write( 4948 icmBase *pp, 4949 unsigned long of /* File offset to write from */ 4950 ) { 4951 icmLut *p = (icmLut *)pp; 4952 icc *icp = p->icp; 4953 unsigned long i,j; 4954 unsigned int len, size; 4955 char *bp, *buf; /* Buffer to write from */ 4956 int rv = 0; 4957 4958 /* Allocate a file write buffer */ 4959 len = p->get_size((icmBase *)p); 4960 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 4961 sprintf(icp->err,"icmLut_write malloc() failed"); 4962 return icp->errc = 2; 4963 } 4964 bp = buf; 4965 4966 /* Write type descriptor to the buffer */ 4967 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 4968 sprintf(icp->err,"icmLut_write: write_SInt32Number() failed"); 4969 icp->al->free(icp->al, buf); 4970 return icp->errc = rv; 4971 } 4972 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 4973 4974 /* Write the info common to 8 and 16 bit Lut */ 4975 if ((rv = write_UInt8Number(p->inputChan, bp+8)) != 0) { 4976 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed"); 4977 icp->al->free(icp->al, buf); 4978 return icp->errc = rv; 4979 } 4980 if ((rv = write_UInt8Number(p->outputChan, bp+9)) != 0) { 4981 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed"); 4982 icp->al->free(icp->al, buf); 4983 return icp->errc = rv; 4984 } 4985 if ((rv = write_UInt8Number(p->clutPoints, bp+10)) != 0) { 4986 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed"); 4987 icp->al->free(icp->al, buf); 4988 return icp->errc = rv; 4989 } 4990 4991 /* Write 3x3 transform matrix */ 4992 for (j = 0; j < 3; j++) { /* Rows */ 4993 for (i = 0; i < 3; i++) { /* Columns */ 4994 if ((rv = write_S15Fixed16Number(p->e[j][i],bp + 12 + ((j * 3 + i) * 4))) != 0) { 4995 sprintf(icp->err,"icmLut_write: write_S15Fixed16Number() failed"); 4996 icp->al->free(icp->al, buf); 4997 return icp->errc = rv; 4998 } 4999 } 5000 } 5001 5002 /* Write 16 bit specific stuff */ 5003 if (p->ttype == icSigLut8Type) { 5004 if (p->inputEnt != 256 || p->outputEnt != 256) { 5005 sprintf(icp->err,"icmLut_write: 8 bit Input and Output tables must be 256 entries"); 5006 icp->al->free(icp->al, buf); 5007 return icp->errc = 1; 5008 } 5009 bp = buf+48; 5010 } else { 5011 if ((rv = write_UInt16Number(p->inputEnt, bp+48)) != 0) { 5012 sprintf(icp->err,"icmLut_write: write_UInt16Number() failed"); 5013 icp->al->free(icp->al, buf); 5014 return icp->errc = rv; 5015 } 5016 if ((rv = write_UInt16Number(p->outputEnt, bp+50)) != 0) { 5017 sprintf(icp->err,"icmLut_write: write_UInt16Number() failed"); 5018 icp->al->free(icp->al, buf); 5019 return icp->errc = rv; 5020 } 5021 bp = buf+52; 5022 } 5023 5024 /* Write the input tables */ 5025 size = (p->inputChan * p->inputEnt); 5026 if (p->ttype == icSigLut8Type) { 5027 for (i = 0; i < size; i++, bp += 1) { 5028 if ((rv = write_DCS8Number(p->inputTable[i], bp)) != 0) { 5029 sprintf(icp->err,"icmLut_write: inputTable write_DCS8Number() failed"); 5030 icp->al->free(icp->al, buf); 5031 return icp->errc = rv; 5032 } 5033 } 5034 } else { 5035 for (i = 0; i < size; i++, bp += 2) { 5036 if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) { 5037 sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]); 5038 icp->al->free(icp->al, buf); 5039 return icp->errc = rv; 5040 } 5041 } 5042 } 5043 5044 /* Write the clut table */ 5045 size = (p->outputChan * uipow(p->clutPoints,p->inputChan)); 5046 if (p->ttype == icSigLut8Type) { 5047 for (i = 0; i < size; i++, bp += 1) { 5048 if ((rv = write_DCS8Number(p->clutTable[i], bp)) != 0) { 5049 sprintf(icp->err,"icmLut_write: clutTable write_DCS8Number() failed"); 5050 icp->al->free(icp->al, buf); 5051 return icp->errc = rv; 5052 } 5053 } 5054 } else { 5055 for (i = 0; i < size; i++, bp += 2) { 5056 if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) { 5057 sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]); 5058 icp->al->free(icp->al, buf); 5059 return icp->errc = rv; 5060 } 5061 } 5062 } 5063 5064 /* Write the output tables */ 5065 size = (p->outputChan * p->outputEnt); 5066 if (p->ttype == icSigLut8Type) { 5067 for (i = 0; i < size; i++, bp += 1) { 5068 if ((rv = write_DCS8Number(p->outputTable[i], bp)) != 0) { 5069 sprintf(icp->err,"icmLut_write: outputTable write_DCS8Number() failed"); 5070 icp->al->free(icp->al, buf); 5071 return icp->errc = rv; 5072 } 5073 } 5074 } else { 5075 for (i = 0; i < size; i++, bp += 2) { 5076 if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) { 5077 sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]); 5078 icp->al->free(icp->al, buf); 5079 return icp->errc = rv; 5080 } 5081 } 5082 } 5083 5084 /* Write buffer to the file */ 5085 if ( icp->fp->seek(icp->fp, of) != 0 5086 || icp->fp->write(icp->fp, buf, 1, len) != len) { 5087 sprintf(icp->err,"icmLut_write fseek() or fwrite() failed"); 5088 icp->al->free(icp->al, buf); 5089 return icp->errc = 2; 5090 } 5091 icp->al->free(icp->al, buf); 5092 return 0; 5093 } 5094 5095 /* Dump a text description of the object */ 5096 static void icmLut_dump( 5097 icmBase *pp, 5098 FILE *op, /* Output to dump to */ 5099 int verb /* Verbosity level */ 5100 ) { 5101 icmLut *p = (icmLut *)pp; 5102 if (verb <= 0) 5103 return; 5104 5105 if (p->ttype == icSigLut8Type) { 5106 fprintf(op,"Lut8:\n"); 5107 } else { 5108 fprintf(op,"Lut16:\n"); 5109 } 5110 fprintf(op," Input Channels = %u\n",p->inputChan); 5111 fprintf(op," Output Channels = %u\n",p->outputChan); 5112 fprintf(op," CLUT resolution = %u\n",p->clutPoints); 5113 fprintf(op," Input Table entries = %u\n",p->inputEnt); 5114 fprintf(op," Output Table entries = %u\n",p->outputEnt); 5115 fprintf(op," XYZ matrix = %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]); 5116 fprintf(op," %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]); 5117 fprintf(op," %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]); 5118 5119 if (verb >= 2) { 5120 unsigned int i,size; 5121 int j; 5122 unsigned int ii[MAX_CHAN]; /* maximum no of input channels */ 5123 5124 fprintf(op," Input table:\n"); 5125 for (i = 0; i < p->inputEnt; i++) { 5126 fprintf(op," %3u: ",i); 5127 for (j = 0; j < p->inputChan; j++) 5128 fprintf(op," %1.10f",p->inputTable[j * p->inputEnt + i]); 5129 fprintf(op,"\n"); 5130 } 5131 5132 fprintf(op,"\n CLUT table:\n"); 5133 if (p->inputChan > MAX_CHAN) { 5134 fprintf(op," !!Can't dump > %d input channel CLUT table!!\n",MAX_CHAN); 5135 } else { 5136 size = (p->outputChan * uipow(p->clutPoints,p->inputChan)); 5137 for (j = 0; j < p->inputChan; j++) 5138 ii[j] = 0; 5139 for (i = 0; i < size;) { 5140 int k; 5141 /* Print table entry index */ 5142 fprintf(op," "); 5143 for (j = p->inputChan-1; j >= 0; j--) 5144 fprintf(op," %2u",ii[j]); 5145 fprintf(op,":"); 5146 /* Print table entry contents */ 5147 for (k = 0; k < p->outputChan; k++, i++) 5148 fprintf(op," %1.10f",p->clutTable[i]); 5149 fprintf(op,"\n"); 5150 5151 for (j = 0; j < p->inputChan; j++) { /* Increment index */ 5152 ii[j]++; 5153 if (ii[j] < p->clutPoints) 5154 break; /* No carry */ 5155 ii[j] = 0; 5156 } 5157 } 5158 } 5159 5160 fprintf(op,"\n Output table:\n"); 5161 for (i = 0; i < p->outputEnt; i++) { 5162 fprintf(op," %3u: ",i); 5163 for (j = 0; j < p->outputChan; j++) 5164 fprintf(op," %1.10f",p->outputTable[j * p->outputEnt + i]); 5165 fprintf(op,"\n"); 5166 } 5167 5168 } 5169 } 5170 5171 /* Allocate variable sized data elements */ 5172 static int icmLut_allocate( 5173 icmBase *pp 5174 ) { 5175 unsigned int i, j, g, size; 5176 icmLut *p = (icmLut *)pp; 5177 icc *icp = p->icp; 5178 5179 /* Sanity check */ 5180 if (p->inputChan > MAX_CHAN) { 5181 sprintf(icp->err,"icmLut_alloc: Can't handle > %d input channels\n",MAX_CHAN); 5182 return icp->errc = 1; 5183 } 5184 5185 if (p->outputChan > MAX_CHAN) { 5186 sprintf(icp->err,"icmLut_alloc: Can't handle > %d output channels\n",MAX_CHAN); 5187 return icp->errc = 1; 5188 } 5189 5190 size = (p->inputChan * p->inputEnt); 5191 if (size != p->inputTable_size) { 5192 if (p->inputTable != NULL) 5193 icp->al->free(icp->al, p->inputTable); 5194 if ((p->inputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) { 5195 sprintf(icp->err,"icmLut_alloc: calloc() of Lut inputTable data failed"); 5196 return icp->errc = 2; 5197 } 5198 p->inputTable_size = size; 5199 } 5200 size = (p->outputChan * uipow(p->clutPoints,p->inputChan)); 5201 if (size != p->clutTable_size) { 5202 if (p->clutTable != NULL) 5203 icp->al->free(icp->al, p->clutTable); 5204 if ((p->clutTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) { 5205 sprintf(icp->err,"icmLut_alloc: calloc() of Lut clutTable data failed"); 5206 return icp->errc = 2; 5207 } 5208 p->clutTable_size = size; 5209 } 5210 size = (p->outputChan * p->outputEnt); 5211 if (size != p->outputTable_size) { 5212 if (p->outputTable != NULL) 5213 icp->al->free(icp->al, p->outputTable); 5214 if ((p->outputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) { 5215 sprintf(icp->err,"icmLut_alloc: calloc() of Lut outputTable data failed"); 5216 return icp->errc = 2; 5217 } 5218 p->outputTable_size = size; 5219 } 5220 5221 /* Private: compute dimensional increment though clut */ 5222 /* Note that first channel varies least rapidly. */ 5223 i = p->inputChan-1; 5224 p->dinc[i--] = p->outputChan; 5225 for (; i < p->inputChan; i--) 5226 p->dinc[i] = p->dinc[i+1] * p->clutPoints; 5227 5228 /* Private: compute offsets from base of cube to other corners */ 5229 for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) { 5230 for (i = 0; i < g; i++) 5231 p->dcube[g+i] = p->dcube[i] + p->dinc[j]; 5232 g *= 2; 5233 } 5234 5235 return 0; 5236 } 5237 5238 /* Free all storage in the object */ 5239 static void icmLut_delete( 5240 icmBase *pp 5241 ) { 5242 icmLut *p = (icmLut *)pp; 5243 icc *icp = p->icp; 5244 5245 if (p->inputTable != NULL) 5246 icp->al->free(icp->al, p->inputTable); 5247 if (p->clutTable != NULL) 5248 icp->al->free(icp->al, p->clutTable); 5249 if (p->outputTable != NULL) 5250 icp->al->free(icp->al, p->outputTable); 5251 icmTable_delete_bwd(icp, &p->rit); 5252 icmTable_delete_bwd(icp, &p->rot); 5253 icp->al->free(icp->al, p); 5254 } 5255 5256 /* Create an empty object. Return null on error */ 5257 static icmBase *new_icmLut( 5258 icc *icp 5259 ) { 5260 int i,j; 5261 icmLut *p; 5262 if ((p = (icmLut *) icp->al->calloc(icp->al,1,sizeof(icmLut))) == NULL) 5263 return NULL; 5264 p->ttype = icSigLut16Type; 5265 p->refcount = 1; 5266 p->get_size = icmLut_get_size; 5267 p->read = icmLut_read; 5268 p->write = icmLut_write; 5269 p->dump = icmLut_dump; 5270 p->allocate = icmLut_allocate; 5271 p->del = icmLut_delete; 5272 5273 /* Lookup methods */ 5274 p->nu_matrix = icmLut_nu_matrix; 5275 p->min_max = icmLut_min_max; 5276 p->lookup_matrix = icmLut_lookup_matrix; 5277 p->lookup_input = icmLut_lookup_input; 5278 p->lookup_clut_nl = icmLut_lookup_clut_nl; 5279 p->lookup_clut_sx = icmLut_lookup_clut_sx; 5280 p->lookup_output = icmLut_lookup_output; 5281 5282 /* Set method */ 5283 p->set_tables = icmLut_set_tables; 5284 5285 p->icp = icp; 5286 5287 /* Set matrix to reasonable default */ 5288 for (i = 0; i < 3; i++) 5289 for (j = 0; j < 3; j++) { 5290 if (i == j) 5291 p->e[i][j] = 1.0; 5292 else 5293 p->e[i][j] = 0.0; 5294 } 5295 5296 /* Init lookups to non-dangerous values */ 5297 for (i = 0; i < MAX_CHAN; i++) 5298 p->dinc[i] = 0; 5299 5300 for (i = 0; i < (1 << MAX_CHAN); i++) 5301 p->dcube[i] = 0; 5302 5303 p->rit.inited = 0; 5304 p->rot.inited = 0; 5305 5306 return (icmBase *)p; 5307 } 5308 5309 /* ---------------------------------------------------------- */ 5310 /* Measurement */ 5311 5312 /* Return the number of bytes needed to write this tag */ 5313 static unsigned int icmMeasurement_get_size( 5314 icmBase *pp 5315 ) { 5316 icmMeasurement *p = (icmMeasurement *)pp; 5317 unsigned int len = 0; 5318 len += 8; /* 8 bytes for tag and padding */ 5319 len += 4; /* 4 for standard observer */ 5320 len += 12; /* 12 for XYZ of measurement backing */ 5321 len += 4; /* 4 for measurement geometry */ 5322 len += 4; /* 4 for measurement flare */ 5323 len += 4; /* 4 for standard illuminant */ 5324 return len; 5325 } 5326 5327 /* read the object, return 0 on success, error code on fail */ 5328 static int icmMeasurement_read( 5329 icmBase *pp, 5330 unsigned long len, /* tag length */ 5331 unsigned long of /* start offset within file */ 5332 ) { 5333 icmMeasurement *p = (icmMeasurement *)pp; 5334 icc *icp = p->icp; 5335 int rv; 5336 char *bp, *buf; 5337 5338 if (len < 36) { 5339 sprintf(icp->err,"icmMeasurement_read: Tag too small to be legal"); 5340 return icp->errc = 1; 5341 } 5342 5343 /* Allocate a file read buffer */ 5344 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 5345 sprintf(icp->err,"icmMeasurement_read: malloc() failed"); 5346 return icp->errc = 2; 5347 } 5348 bp = buf; 5349 5350 /* Read portion of file into buffer */ 5351 if ( icp->fp->seek(icp->fp, of) != 0 5352 || icp->fp->read(icp->fp, bp, 1, len) != len) { 5353 sprintf(icp->err,"icmMeasurement_read: fseek() or fread() failed"); 5354 icp->al->free(icp->al, buf); 5355 return icp->errc = 1; 5356 } 5357 5358 /* Read type descriptor from the buffer */ 5359 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 5360 sprintf(icp->err,"icmMeasurement_read: Wrong tag type for icmMeasurement"); 5361 icp->al->free(icp->al, buf); 5362 return icp->errc = 1; 5363 } 5364 5365 /* Read the encoded standard observer */ 5366 p->observer = (icStandardObserver)read_SInt32Number(bp + 8); 5367 5368 /* Read the XYZ values for measurement backing */ 5369 if ((rv = read_XYZNumber(&p->backing, bp+12)) != 0) { 5370 sprintf(icp->err,"icmMeasurement: read_XYZNumber error"); 5371 icp->al->free(icp->al, buf); 5372 return icp->errc = rv; 5373 } 5374 5375 /* Read the encoded measurement geometry */ 5376 p->geometry = (icMeasurementGeometry)read_SInt32Number(bp + 24); 5377 5378 /* Read the proportion of flare */ 5379 p->flare = read_U16Fixed16Number(bp + 28); 5380 5381 /* Read the encoded standard illuminant */ 5382 p->illuminant = (icMeasurementFlare)read_SInt32Number(bp + 32); 5383 5384 icp->al->free(icp->al, buf); 5385 return 0; 5386 } 5387 5388 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 5389 static int icmMeasurement_write( 5390 icmBase *pp, 5391 unsigned long of /* File offset to write from */ 5392 ) { 5393 icmMeasurement *p = (icmMeasurement *)pp; 5394 icc *icp = p->icp; 5395 unsigned int len; 5396 char *bp, *buf; /* Buffer to write from */ 5397 int rv = 0; 5398 5399 /* Allocate a file write buffer */ 5400 len = p->get_size((icmBase *)p); 5401 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 5402 sprintf(icp->err,"icmMeasurement_write malloc() failed"); 5403 return icp->errc = 2; 5404 } 5405 bp = buf; 5406 5407 /* Write type descriptor to the buffer */ 5408 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 5409 sprintf(icp->err,"icmMeasurement_write, type: write_SInt32Number() failed"); 5410 icp->al->free(icp->al, buf); 5411 return icp->errc = rv; 5412 } 5413 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 5414 5415 /* Write the encoded standard observer */ 5416 if ((rv = write_SInt32Number((int)p->observer, bp + 8)) != 0) { 5417 sprintf(icp->err,"icmMeasurementa_write, observer: write_SInt32Number() failed"); 5418 icp->al->free(icp->al, buf); 5419 return icp->errc = rv; 5420 } 5421 5422 /* Write the XYZ values for measurement backing */ 5423 if ((rv = write_XYZNumber(&p->backing, bp+12)) != 0) { 5424 sprintf(icp->err,"icmMeasurement, backing: write_XYZNumber error"); 5425 icp->al->free(icp->al, buf); 5426 return icp->errc = rv; 5427 } 5428 5429 /* Write the encoded measurement geometry */ 5430 if ((rv = write_SInt32Number((int)p->geometry, bp + 24)) != 0) { 5431 sprintf(icp->err,"icmMeasurementa_write, geometry: write_SInt32Number() failed"); 5432 icp->al->free(icp->al, buf); 5433 return icp->errc = rv; 5434 } 5435 5436 /* Write the proportion of flare */ 5437 if ((rv = write_U16Fixed16Number(p->flare, bp + 28)) != 0) { 5438 sprintf(icp->err,"icmMeasurementa_write, flare: write_U16Fixed16Number() failed"); 5439 icp->al->free(icp->al, buf); 5440 return icp->errc = rv; 5441 } 5442 5443 /* Write the encoded standard illuminant */ 5444 if ((rv = write_SInt32Number((int)p->illuminant, bp + 32)) != 0) { 5445 sprintf(icp->err,"icmMeasurementa_write, illuminant: write_SInt32Number() failed"); 5446 icp->al->free(icp->al, buf); 5447 return icp->errc = rv; 5448 } 5449 5450 /* Write to the file */ 5451 if ( icp->fp->seek(icp->fp, of) != 0 5452 || icp->fp->write(icp->fp, buf, 1, len) != len) { 5453 sprintf(icp->err,"icmMeasurement_write fseek() or fwrite() failed"); 5454 icp->al->free(icp->al, buf); 5455 return icp->errc = 2; 5456 } 5457 icp->al->free(icp->al, buf); 5458 return 0; 5459 } 5460 5461 /* Dump a text description of the object */ 5462 static void icmMeasurement_dump( 5463 icmBase *pp, 5464 FILE *op, /* Output to dump to */ 5465 int verb /* Verbosity level */ 5466 ) { 5467 icmMeasurement *p = (icmMeasurement *)pp; 5468 if (verb <= 0) 5469 return; 5470 5471 fprintf(op,"Measurement:\n"); 5472 fprintf(op," Standard Observer = %s\n", string_StandardObserver(p->observer)); 5473 fprintf(op," XYZ for Measurement Backing = %s\n", string_XYZNumber_and_Lab(&p->backing)); 5474 fprintf(op," Measurement Geometry = %s\n", string_MeasurementGeometry(p->geometry)); 5475 fprintf(op," Measurement Flare = %5.1f%%\n", p->flare * 100.0); 5476 fprintf(op," Standard Illuminant = %s\n", string_Illuminant(p->illuminant)); 5477 } 5478 5479 /* Allocate variable sized data elements */ 5480 static int icmMeasurement_allocate( 5481 icmBase *pp 5482 ) { 5483 icmMeasurement *p = (icmMeasurement *)pp; 5484 5485 /* Nothing to do */ 5486 return 0; 5487 } 5488 5489 /* Free all storage in the object */ 5490 static void icmMeasurement_delete( 5491 icmBase *pp 5492 ) { 5493 icmMeasurement *p = (icmMeasurement *)pp; 5494 icc *icp = p->icp; 5495 5496 icp->al->free(icp->al, p); 5497 } 5498 5499 /* Create an empty object. Return null on error */ 5500 static icmBase *new_icmMeasurement( 5501 icc *icp 5502 ) { 5503 icmMeasurement *p; 5504 if ((p = (icmMeasurement *) icp->al->calloc(icp->al,1,sizeof(icmMeasurement))) == NULL) 5505 return NULL; 5506 p->ttype = icSigMeasurementType; 5507 p->refcount = 1; 5508 p->get_size = icmMeasurement_get_size; 5509 p->read = icmMeasurement_read; 5510 p->write = icmMeasurement_write; 5511 p->dump = icmMeasurement_dump; 5512 p->allocate = icmMeasurement_allocate; 5513 p->del = icmMeasurement_delete; 5514 p->icp = icp; 5515 5516 return (icmBase *)p; 5517 } 5518 5519 /* ---------------------------------------------------------- */ 5520 5521 /* Named color structure read/write support */ 5522 static int read_NamedColorVal( 5523 icmNamedColorVal *p, 5524 char *bp, 5525 char *end, 5526 icColorSpaceSignature pcs, /* Header Profile Connection Space */ 5527 unsigned int ndc /* Number of device corrds */ 5528 ) { 5529 icc *icp = p->icp; 5530 int i; 5531 unsigned int mxl; /* Max possible string length */ 5532 5533 mxl = (end - bp) < 32 ? (end - bp) : 32; 5534 if (check_null_string(bp,mxl)) { 5535 sprintf(icp->err,"icmNamedColorVal_read: Root name string not terminated"); 5536 return icp->errc = 1; 5537 } 5538 strcpy((void *)p->root, (void *)bp); 5539 bp += strlen(p->root) + 1; 5540 if ((bp + ndc) > end) { 5541 sprintf(icp->err,"icmNamedColorVal_read: Data too short to read device coords"); 5542 return icp->errc = 1; 5543 } 5544 for (i = 0; i < ndc; i++) { 5545 p->deviceCoords[i] = read_DCS8Number(bp); 5546 bp += 1; 5547 } 5548 return 0; 5549 } 5550 5551 static int read_NamedColorVal2( 5552 icmNamedColorVal *p, 5553 char *bp, 5554 char *end, 5555 icColorSpaceSignature pcs, /* Header Profile Connection Space */ 5556 unsigned int ndc /* Number of device corrds */ 5557 ) { 5558 icc *icp = p->icp; 5559 int i; 5560 if ((bp + 32 + 6 + ndc * 2) > end) { 5561 sprintf(icp->err,"icmNamedColorVal2_read: Data too short to read"); 5562 return icp->errc = 1; 5563 } 5564 if (check_null_string(bp,32)) { 5565 sprintf(icp->err,"icmNamedColorVal2_read: Root name string not terminated"); 5566 return icp->errc = 1; 5567 } 5568 memcpy((void *)p->root,(void *)(bp + 0),32); 5569 switch(pcs) { 5570 case icSigXYZData: 5571 p->pcsCoords[0] = read_PCSXYZ16Number(bp+32); 5572 p->pcsCoords[1] = read_PCSXYZ16Number(bp+34); 5573 p->pcsCoords[2] = read_PCSXYZ16Number(bp+36); 5574 break; 5575 case icSigLabData: 5576 p->pcsCoords[0] = read_PCSL16Number(bp+32); 5577 p->pcsCoords[1] = read_PCSab16Number(bp+34); 5578 p->pcsCoords[2] = read_PCSab16Number(bp+36); 5579 break; 5580 default: 5581 return 1; /* Unknown PCS */ 5582 } 5583 for (i = 0; i < ndc; i++) 5584 p->deviceCoords[i] = read_DCS16Number(bp + 32 + 6 + 2 * i); 5585 return 0; 5586 } 5587 5588 static int write_NamedColorVal( 5589 icmNamedColorVal *p, 5590 char *d, 5591 icColorSpaceSignature pcs, /* Header Profile Connection Space */ 5592 unsigned int ndc /* Number of device corrds */ 5593 ) { 5594 icc *icp = p->icp; 5595 int i, rv = 0; 5596 if (check_null_string(p->root,32) != 0) { 5597 sprintf(icp->err,"icmNamedColorVal_write: Root string names is unterminated"); 5598 return icp->errc = 1; 5599 } 5600 strcpy((void *)d,(void *)p->root); 5601 d += strlen(p->root) + 1; 5602 for (i = 0; i < ndc; i++) { 5603 if ((rv = write_DCS8Number(p->deviceCoords[i], d)) != 0) { 5604 sprintf(icp->err,"icmNamedColorVal_write: write of device coord failed"); 5605 return icp->errc = 1; 5606 } 5607 d += 1; 5608 } 5609 return 0; 5610 } 5611 5612 static int write_NamedColorVal2( 5613 icmNamedColorVal *p, 5614 char *bp, 5615 icColorSpaceSignature pcs, /* Header Profile Connection Space */ 5616 unsigned int ndc /* Number of device corrds */ 5617 ) { 5618 icc *icp = p->icp; 5619 int i, rv = 0; 5620 if (check_null_string(p->root,32)) { 5621 sprintf(icp->err,"icmNamedColorVal2_write: Root string names is unterminated"); 5622 return icp->errc = 1; 5623 } 5624 memcpy((void *)(bp + 0),(void *)p->root,32); 5625 switch(pcs) { 5626 case icSigXYZData: 5627 rv |= write_PCSXYZ16Number(p->pcsCoords[0], bp+32); 5628 rv |= write_PCSXYZ16Number(p->pcsCoords[1], bp+34); 5629 rv |= write_PCSXYZ16Number(p->pcsCoords[2], bp+36); 5630 break; 5631 case icSigLabData: 5632 rv |= write_PCSL16Number(p->pcsCoords[0], bp+32); 5633 rv |= write_PCSab16Number(p->pcsCoords[1], bp+34); 5634 rv |= write_PCSab16Number(p->pcsCoords[2], bp+36); 5635 break; 5636 default: 5637 sprintf(icp->err,"icmNamedColorVal2_write: Unknown PCS"); 5638 return icp->errc = 1; 5639 } 5640 if (rv) { 5641 sprintf(icp->err,"icmNamedColorVal2_write: write of PCS coord failed"); 5642 return icp->errc = 1; 5643 } 5644 for (i = 0; i < ndc; i++) { 5645 if ((rv = write_DCS16Number(p->deviceCoords[i], bp + 32 + 6 + 2 * i)) != 0) { 5646 sprintf(icp->err,"icmNamedColorVal2_write: write of device coord failed"); 5647 return icp->errc = 1; 5648 } 5649 } 5650 return 0; 5651 } 5652 5653 /* - - - - - - - - - - - */ 5654 /* icmNamedColor object */ 5655 5656 /* Return the number of bytes needed to write this tag */ 5657 static unsigned int icmNamedColor_get_size( 5658 icmBase *pp 5659 ) { 5660 icmNamedColor *p = (icmNamedColor *)pp; 5661 unsigned int len = 0; 5662 if (p->ttype == icSigNamedColorType) { 5663 unsigned int i; 5664 len += 8; /* 8 bytes for tag and padding */ 5665 len += 4; /* 4 for vendor specific flags */ 5666 len += 4; /* 4 for count of named colors */ 5667 len += strlen(p->prefix) + 1; /* prefix of color names */ 5668 len += strlen(p->suffix) + 1; /* suffix of color names */ 5669 for (i = 0; i < p->count; i++) { 5670 len += strlen(p->data[i].root) + 1; /* color names */ 5671 len += p->nDeviceCoords * 1; /* bytes for each named color */ 5672 } 5673 } else { /* Named Color 2 */ 5674 len += 8; /* 8 bytes for tag and padding */ 5675 len += 4; /* 4 for vendor specific flags */ 5676 len += 4; /* 4 for count of named colors */ 5677 len += 4; /* 4 for number of device coords */ 5678 len += 32; /* 32 for prefix of color names */ 5679 len += 32; /* 32 for suffix of color names */ 5680 len += p->count * (32 + 6 + p->nDeviceCoords * 2); /* bytes for each named color */ 5681 } 5682 return len; 5683 } 5684 5685 /* read the object, return 0 on success, error code on fail */ 5686 static int icmNamedColor_read( 5687 icmBase *pp, 5688 unsigned long len, /* tag length */ 5689 unsigned long of /* start offset within file */ 5690 ) { 5691 icmNamedColor *p = (icmNamedColor *)pp; 5692 icc *icp = p->icp; 5693 unsigned long i; 5694 char *bp, *buf, *end; 5695 int rv = 0; 5696 5697 if (len < 4) { 5698 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal"); 5699 return icp->errc = 1; 5700 } 5701 5702 /* Allocate a file read buffer */ 5703 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 5704 sprintf(icp->err,"icmNamedColor_read: malloc() failed"); 5705 return icp->errc = 2; 5706 } 5707 bp = buf; 5708 end = buf + len; 5709 5710 /* Read portion of file into buffer */ 5711 if ( icp->fp->seek(icp->fp, of) != 0 5712 || icp->fp->read(icp->fp, bp, 1, len) != len) { 5713 sprintf(icp->err,"icmNamedColor_read: fseek() or fread() failed"); 5714 icp->al->free(icp->al, buf); 5715 return icp->errc = 1; 5716 } 5717 5718 /* Read type descriptor from the buffer */ 5719 p->ttype = (icTagTypeSignature)read_SInt32Number(bp); 5720 if (p->ttype != icSigNamedColorType && p->ttype != icSigNamedColor2Type) { 5721 sprintf(icp->err,"icmNamedColor_read: Wrong tag type for icmNamedColor"); 5722 icp->al->free(icp->al, buf); 5723 return icp->errc = 1; 5724 } 5725 5726 if (p->ttype == icSigNamedColorType) { 5727 if (len < 16) { 5728 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal"); 5729 icp->al->free(icp->al, buf); 5730 return icp->errc = 1; 5731 } 5732 /* Make sure that the number of device coords in known */ 5733 p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace); 5734 if (p->nDeviceCoords > MAX_CHAN) { 5735 sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN); 5736 icp->al->free(icp->al, buf); 5737 return icp->errc = 1; 5738 } 5739 5740 } else { /* icmNC2 */ 5741 if (len < 84) { 5742 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal"); 5743 icp->al->free(icp->al, buf); 5744 return icp->errc = 1; 5745 } 5746 } 5747 5748 /* Read vendor specific flag */ 5749 p->vendorFlag = read_UInt32Number(bp+8); 5750 5751 /* Read count of named colors */ 5752 p->count = read_UInt32Number(bp+12); 5753 5754 if (p->ttype == icSigNamedColorType) { 5755 unsigned int mxl; /* Max possible string length */ 5756 bp = bp + 16; 5757 5758 /* Prefix for each color name */ 5759 mxl = (end - bp) < 32 ? (end - bp) : 32; 5760 if (check_null_string(bp,mxl) != 0) { 5761 sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated"); 5762 icp->al->free(icp->al, buf); 5763 return icp->errc = 1; 5764 } 5765 strcpy((void *)p->prefix, (void *)bp); 5766 bp += strlen(p->prefix) + 1; 5767 5768 /* Suffix for each color name */ 5769 mxl = (end - bp) < 32 ? (end - bp) : 32; 5770 if (check_null_string(bp,mxl) != 0) { 5771 sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated"); 5772 icp->al->free(icp->al, buf); 5773 return icp->errc = 1; 5774 } 5775 strcpy((void *)p->suffix, (void *)bp); 5776 bp += strlen(p->suffix) + 1; 5777 5778 if ((rv = p->allocate((void *)p)) != 0) { 5779 icp->al->free(icp->al, buf); 5780 return rv; 5781 } 5782 5783 /* Read all the data from the buffer */ 5784 for (i = 0; i < p->count; i++) { 5785 if ((rv = read_NamedColorVal(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) { 5786 icp->al->free(icp->al, buf); 5787 return rv; 5788 } 5789 bp += strlen(p->data[i].root) + 1; 5790 bp += p->nDeviceCoords * 1; 5791 } 5792 } else { /* icmNC2 */ 5793 /* Number of device coords per color */ 5794 p->nDeviceCoords = read_UInt32Number(bp+16); 5795 5796 /* Prefix for each color name */ 5797 memcpy((void *)p->prefix, (void *)(bp + 20), 32); 5798 if (check_null_string(p->prefix,32) != 0) { 5799 sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated"); 5800 icp->al->free(icp->al, buf); 5801 return icp->errc = 1; 5802 } 5803 5804 /* Suffix for each color name */ 5805 memcpy((void *)p->suffix, (void *)(bp + 52), 32); 5806 if (check_null_string(p->suffix,32) != 0) { 5807 sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated"); 5808 icp->al->free(icp->al, buf); 5809 return icp->errc = 1; 5810 } 5811 5812 if ((rv = p->allocate((icmBase *)p)) != 0) { 5813 icp->al->free(icp->al, buf); 5814 return rv; 5815 } 5816 5817 /* Read all the data from the buffer */ 5818 bp = bp + 84; 5819 for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) { 5820 if ((rv = read_NamedColorVal2(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) { 5821 icp->al->free(icp->al, buf); 5822 return rv; 5823 } 5824 } 5825 } 5826 icp->al->free(icp->al, buf); 5827 return rv; 5828 } 5829 5830 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 5831 static int icmNamedColor_write( 5832 icmBase *pp, 5833 unsigned long of /* File offset to write from */ 5834 ) { 5835 icmNamedColor *p = (icmNamedColor *)pp; 5836 icc *icp = p->icp; 5837 unsigned long i; 5838 unsigned int len; 5839 char *bp, *buf; /* Buffer to write from */ 5840 int rv = 0; 5841 5842 /* Allocate a file write buffer */ 5843 len = p->get_size((icmBase *)p); 5844 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 5845 sprintf(icp->err,"icmNamedColor_write malloc() failed"); 5846 return icp->errc = 2; 5847 } 5848 bp = buf; 5849 5850 /* Write type descriptor to the buffer */ 5851 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 5852 sprintf(icp->err,"icmNamedColor_write: write_SInt32Number() failed"); 5853 icp->al->free(icp->al, buf); 5854 return icp->errc = rv; 5855 } 5856 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 5857 5858 /* Write vendor specific flag */ 5859 if ((rv = write_UInt32Number(p->vendorFlag, bp+8)) != 0) { 5860 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed"); 5861 icp->al->free(icp->al, buf); 5862 return icp->errc = rv; 5863 } 5864 5865 /* Write count of named colors */ 5866 if ((rv = write_UInt32Number(p->count, bp+12)) != 0) { 5867 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed"); 5868 icp->al->free(icp->al, buf); 5869 return icp->errc = rv; 5870 } 5871 5872 if (p->ttype == icSigNamedColorType) { 5873 bp = bp + 16; 5874 5875 /* Prefix for each color name */ 5876 if ((rv = check_null_string(p->prefix,32)) != 0) { 5877 sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated"); 5878 icp->al->free(icp->al, buf); 5879 return icp->errc = 1; 5880 } 5881 strcpy((void *)bp, (void *)p->prefix); 5882 bp += strlen(p->prefix) + 1; 5883 5884 /* Suffix for each color name */ 5885 if (check_null_string(p->suffix,32)) { 5886 sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated"); 5887 icp->al->free(icp->al, buf); 5888 return icp->errc = 1; 5889 } 5890 strcpy((void *)bp, (void *)p->suffix); 5891 bp += strlen(p->suffix) + 1; 5892 5893 /* Write all the data to the buffer */ 5894 5895 for (i = 0; i < p->count; i++) { 5896 if ((rv = write_NamedColorVal(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) { 5897 icp->al->free(icp->al, buf); 5898 return rv; 5899 } 5900 bp += strlen(p->data[i].root) + 1; 5901 bp += p->nDeviceCoords * 1; 5902 } 5903 } else { /* icmNC2 */ 5904 /* Number of device coords per color */ 5905 if ((rv = write_UInt32Number(p->nDeviceCoords, bp+16)) != 0) { 5906 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed"); 5907 icp->al->free(icp->al, buf); 5908 return icp->errc = rv; 5909 } 5910 5911 /* Prefix for each color name */ 5912 if ((rv = check_null_string(p->prefix,32)) != 0) { 5913 sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated"); 5914 icp->al->free(icp->al, buf); 5915 return icp->errc = 1; 5916 } 5917 memcpy((void *)(bp + 20), (void *)p->prefix, 32); 5918 5919 /* Suffix for each color name */ 5920 if (check_null_string(p->suffix,32)) { 5921 sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated"); 5922 icp->al->free(icp->al, buf); 5923 return icp->errc = 1; 5924 } 5925 memcpy((void *)(bp + 52), (void *)p->suffix, 32); 5926 5927 /* Write all the data to the buffer */ 5928 bp = bp + 84; 5929 for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) { 5930 if ((rv = write_NamedColorVal2(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) { 5931 icp->al->free(icp->al, buf); 5932 return rv; 5933 } 5934 } 5935 } 5936 5937 /* Write to the file */ 5938 if ( icp->fp->seek(icp->fp, of) != 0 5939 || icp->fp->write(icp->fp, buf, 1, len) != len) { 5940 sprintf(icp->err,"icmNamedColor_write fseek() or fwrite() failed"); 5941 icp->al->free(icp->al, buf); 5942 return icp->errc = 2; 5943 } 5944 icp->al->free(icp->al, buf); 5945 return 0; 5946 } 5947 5948 /* Dump a text description of the object */ 5949 static void icmNamedColor_dump( 5950 icmBase *pp, 5951 FILE *op, /* Output to dump to */ 5952 int verb /* Verbosity level */ 5953 ) { 5954 icmNamedColor *p = (icmNamedColor *)pp; 5955 icc *icp = p->icp; 5956 if (verb <= 0) 5957 return; 5958 5959 if (p->ttype == icSigNamedColorType) 5960 fprintf(op,"NamedColor:\n"); 5961 else 5962 fprintf(op,"NamedColor2:\n"); 5963 fprintf(op," Vendor Flag = 0x%x\n",p->vendorFlag); 5964 fprintf(op," No. colors = %u\n",p->count); 5965 fprintf(op," No. dev. coords = %u\n",p->nDeviceCoords); 5966 fprintf(op," Name prefix = '%s'\n",p->prefix); 5967 fprintf(op," Name suffix = '%s'\n",p->suffix); 5968 if (verb >= 2) { 5969 unsigned long i, n; 5970 icmNamedColorVal *vp; 5971 for (i = 0; i < p->count; i++) { 5972 vp = p->data + i; 5973 fprintf(op," Color %u:\n",i); 5974 fprintf(op," Name root = '%s'\n",vp->root); 5975 5976 if (p->ttype == icSigNamedColor2Type) { 5977 switch(icp->header->pcs) { 5978 case icSigXYZData: 5979 fprintf(op," XYZ = %f, %f, %f'\n", 5980 vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]); 5981 break; 5982 case icSigLabData: 5983 fprintf(op," Lab = %f, %f, %f'\n", 5984 vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]); 5985 break; 5986 default: 5987 fprintf(op," Unexpected PCS\n"); 5988 break; 5989 } 5990 } 5991 if (p->nDeviceCoords > 0) { 5992 fprintf(op," Device Coords = "); 5993 for (n = 0; n < p->nDeviceCoords; n++) { 5994 if (n > 0) 5995 printf(", "); 5996 printf("%f",vp->deviceCoords[n]); 5997 } 5998 printf("\n"); 5999 } 6000 } 6001 } 6002 } 6003 6004 /* Allocate variable sized data elements */ 6005 static int icmNamedColor_allocate( 6006 icmBase *pp 6007 ) { 6008 icmNamedColor *p = (icmNamedColor *)pp; 6009 icc *icp = p->icp; 6010 6011 if (p->count != p->_count) { 6012 unsigned int i; 6013 if (p->data != NULL) 6014 icp->al->free(icp->al, p->data); 6015 if ((p->data = (icmNamedColorVal *) icp->al->calloc(icp->al,p->count, sizeof(icmNamedColorVal))) == NULL) { 6016 sprintf(icp->err,"icmNamedColor_alloc: malloc() of icmNamedColor data failed"); 6017 return icp->errc = 2; 6018 } 6019 for (i = 0; i < p->count; i++) { 6020 p->data[i].icp = icp; /* Do init */ 6021 } 6022 p->_count = p->count; 6023 } 6024 return 0; 6025 } 6026 6027 /* Free all storage in the object */ 6028 static void icmNamedColor_delete( 6029 icmBase *pp 6030 ) { 6031 icmNamedColor *p = (icmNamedColor *)pp; 6032 icc *icp = p->icp; 6033 6034 if (p->data != NULL) 6035 icp->al->free(icp->al, p->data); 6036 icp->al->free(icp->al, p); 6037 } 6038 6039 /* Create an empty object. Return null on error */ 6040 static icmBase *new_icmNamedColor( 6041 icc *icp 6042 ) { 6043 icmNamedColor *p; 6044 if ((p = (icmNamedColor *) icp->al->calloc(icp->al,1,sizeof(icmNamedColor))) == NULL) 6045 return NULL; 6046 p->ttype = icSigNamedColor2Type; 6047 p->refcount = 1; 6048 p->get_size = icmNamedColor_get_size; 6049 p->read = icmNamedColor_read; 6050 p->write = icmNamedColor_write; 6051 p->dump = icmNamedColor_dump; 6052 p->allocate = icmNamedColor_allocate; 6053 p->del = icmNamedColor_delete; 6054 p->icp = icp; 6055 6056 /* Default the the number of device coords appropriately for NamedColorType */ 6057 p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace); 6058 6059 return (icmBase *)p; 6060 } 6061 6062 /* ---------------------------------------------------------- */ 6063 /* textDescription */ 6064 6065 /* Return the number of bytes needed to write this tag */ 6066 static unsigned int icmTextDescription_get_size( 6067 icmBase *pp 6068 ) { 6069 icmTextDescription *p = (icmTextDescription *)pp; 6070 unsigned int len = 0; 6071 len += 8; /* 8 bytes for tag and padding */ 6072 len += 4 + p->size; /* Ascii string length + ascii string */ 6073 len += 8 + 2 * p->ucSize; /* Unicode language code + length + string */ 6074 len += 3 + 67; /* ScriptCode code, length string */ 6075 return len; 6076 } 6077 6078 /* read the object, return 0 on success, error code on fail */ 6079 static int icmTextDescription_read( 6080 icmBase *pp, 6081 unsigned long len, /* tag length */ 6082 unsigned long of /* start offset within file */ 6083 ) { 6084 icmTextDescription *p = (icmTextDescription *)pp; 6085 icc *icp = p->icp; 6086 int rv; 6087 char *bp, *buf, *end; 6088 6089 if (len < 90) { 6090 sprintf(icp->err,"icmTextDescription_read: Tag too small to be legal"); 6091 return icp->errc = 1; 6092 } 6093 6094 /* Allocate a file read buffer */ 6095 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 6096 sprintf(icp->err,"icmTextDescription_read: malloc() failed"); 6097 return icp->errc = 2; 6098 } 6099 bp = buf; 6100 end = buf + len; 6101 6102 /* Read portion of file into buffer */ 6103 if ( icp->fp->seek(icp->fp, of) != 0 6104 || icp->fp->read(icp->fp, bp, 1, len) != len) { 6105 sprintf(icp->err,"icmTextDescription_read: fseek() or fread() failed"); 6106 icp->al->free(icp->al, buf); 6107 return icp->errc = 1; 6108 } 6109 6110 /* Read from the buffer into the structure */ 6111 if ((rv = p->core_read(p, &bp, end)) != 0) { 6112 icp->al->free(icp->al, buf); 6113 return rv; 6114 } 6115 6116 icp->al->free(icp->al, buf); 6117 return 0; 6118 } 6119 6120 /* core read the object, return 0 on success, error code on fail */ 6121 static int icmTextDescription_core_read( 6122 icmTextDescription *p, 6123 char **bpp, /* Pointer to buffer pointer, returns next after read */ 6124 char *end /* Pointer to past end of read buffer */ 6125 ) { 6126 icc *icp = p->icp; 6127 int rv = 0; 6128 char *bp = *bpp; 6129 6130 if ((bp + 8) > end) { 6131 sprintf(icp->err,"icmTextDescription_read: Data too short to type descriptor"); 6132 *bpp = bp; 6133 return icp->errc = 1; 6134 } 6135 6136 p->size = read_UInt32Number(bp); 6137 /* Read type descriptor from the buffer */ 6138 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 6139 *bpp = bp; 6140 sprintf(icp->err,"icmTextDescription_read: Wrong tag type for icmTextDescription"); 6141 return icp->errc = 1; 6142 } 6143 bp = bp + 8; 6144 6145 /* Read the Ascii string */ 6146 if ((bp + 4) > end) { 6147 *bpp = bp; 6148 sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii header"); 6149 return icp->errc = 1; 6150 } 6151 p->size = read_UInt32Number(bp); 6152 bp += 4; 6153 if (p->size > 0) { 6154 if ((bp + p->size) > end) { 6155 *bpp = bp; 6156 sprintf(icp->err,"icmTextDescription_read: Data to short to read Ascii string"); 6157 return icp->errc = 1; 6158 } 6159 if (check_null_string(bp,p->size)) { 6160 *bpp = bp; 6161 sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated"); 6162 return icp->errc = 1; 6163 } 6164 if ((rv = p->allocate((icmBase *)p)) != 0) { 6165 return rv; 6166 } 6167 strcpy((void *)p->desc, (void *)bp); 6168 bp += p->size; 6169 } 6170 6171 /* Read the Unicode string */ 6172 if ((bp + 8) > end) { 6173 *bpp = bp; 6174 sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string"); 6175 return icp->errc = 1; 6176 } 6177 p->ucLangCode = read_UInt32Number(bp); 6178 bp += 4; 6179 p->ucSize = read_UInt32Number(bp); 6180 bp += 4; 6181 if (p->ucSize > 0) { 6182 ORD16 *up; 6183 if ((bp + 2 * p->ucSize) > end) { 6184 *bpp = bp; 6185 sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string"); 6186 return icp->errc = 1; 6187 } 6188 if (check_null_string16(bp,p->ucSize)) { 6189 *bpp = bp; 6190 sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated"); 6191 return icp->errc = 1; 6192 } 6193 if ((rv = p->allocate((icmBase *)p)) != 0) { 6194 return rv; 6195 } 6196 for(up = p->ucDesc; bp[0] != 0 || bp[1] != 0; up++, bp += 2) 6197 *up = read_UInt16Number(bp); 6198 *up = 0; /* Unicode null */ 6199 bp += 2; 6200 } 6201 6202 /* Read the ScriptCode string */ 6203 if ((bp + 3) > end) { 6204 *bpp = bp; 6205 sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode header"); 6206 return icp->errc = 1; 6207 } 6208 p->scCode = read_UInt16Number(bp); 6209 bp += 2; 6210 p->scSize = read_UInt8Number(bp); 6211 bp += 1; 6212 if (p->scSize > 0) { 6213 if (p->scSize > 67) { 6214 *bpp = bp; 6215 sprintf(icp->err,"icmTextDescription_read: ScriptCode string too long"); 6216 return icp->errc = 1; 6217 } 6218 if ((bp + p->scSize) > end) { 6219 *bpp = bp; 6220 sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode string"); 6221 return icp->errc = 1; 6222 } 6223 if (check_null_string(bp,p->scSize)) { 6224 *bpp = bp; 6225 sprintf(icp->err,"icmTextDescription_read: ScriptCode string is not terminated"); 6226 return icp->errc = 1; 6227 } 6228 memcpy((void *)p->scDesc, (void *)bp, p->scSize); 6229 } else { 6230 memset((void *)p->scDesc, 0, 67); 6231 } 6232 bp += 67; 6233 6234 *bpp = bp; 6235 return 0; 6236 } 6237 6238 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 6239 static int icmTextDescription_write( 6240 icmBase *pp, 6241 unsigned long of /* File offset to write from */ 6242 ) { 6243 icmTextDescription *p = (icmTextDescription *)pp; 6244 icc *icp = p->icp; 6245 unsigned int len; 6246 char *bp, *buf; /* Buffer to write from */ 6247 int rv = 0; 6248 6249 /* Allocate a file write buffer */ 6250 len = p->get_size((icmBase *)p); 6251 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 6252 sprintf(icp->err,"icmTextDescription_write malloc() failed"); 6253 return icp->errc = 2; 6254 } 6255 bp = buf; 6256 6257 /* Write to the buffer from the structure */ 6258 if ((rv = p->core_write(p, &bp)) != 0) { 6259 icp->al->free(icp->al, buf); 6260 return rv; 6261 } 6262 6263 /* Write to the file */ 6264 if ( icp->fp->seek(icp->fp, of) != 0 6265 || icp->fp->write(icp->fp, buf, 1, len) != len) { 6266 sprintf(icp->err,"icmTextDescription_write fseek() or fwrite() failed"); 6267 icp->al->free(icp->al, buf); 6268 return icp->errc = 2; 6269 } 6270 icp->al->free(icp->al, buf); 6271 return 0; 6272 } 6273 6274 /* Core write the contents of the object. Return 0 on sucess, error code on failure */ 6275 static int icmTextDescription_core_write( 6276 icmTextDescription *p, 6277 char **bpp /* Pointer to buffer pointer, returns next after read */ 6278 ) { 6279 icc *icp = p->icp; 6280 char *bp = *bpp; 6281 int rv = 0; 6282 6283 /* Write type descriptor to the buffer */ 6284 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 6285 sprintf(icp->err,"icmTextDescription_write: write_SInt32Number() failed"); 6286 *bpp = bp; 6287 return icp->errc = rv; 6288 } 6289 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 6290 bp = bp + 8; 6291 6292 /* Write the Ascii string */ 6293 if ((rv = write_UInt32Number(p->size,bp)) != 0) { 6294 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed"); 6295 *bpp = bp; 6296 return icp->errc = rv; 6297 } 6298 bp += 4; 6299 if (p->size > 0) { 6300 if (check_null_string(p->desc,p->size)) { 6301 *bpp = bp; 6302 sprintf(icp->err,"icmTextDescription_write: ascii string is not terminated"); 6303 return icp->errc = 1; 6304 } 6305 strcpy((void *)bp, (void *)p->desc); 6306 bp += p->size; 6307 } 6308 6309 /* Write the Unicode string */ 6310 if ((rv = write_UInt32Number(p->ucLangCode, bp)) != 0) { 6311 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed"); 6312 *bpp = bp; 6313 return icp->errc = rv; 6314 } 6315 bp += 4; 6316 if ((rv = write_UInt32Number(p->ucSize, bp)) != 0) { 6317 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed"); 6318 *bpp = bp; 6319 return icp->errc = rv; 6320 } 6321 bp += 4; 6322 if (p->ucSize > 0) { 6323 ORD16 *up; 6324 if (check_null_string16((char *)p->ucDesc,p->ucSize)) { 6325 *bpp = bp; 6326 sprintf(icp->err,"icmTextDescription_write: Unicode string is not terminated"); 6327 return icp->errc = 1; 6328 } 6329 for(up = p->ucDesc; *up != 0; up++, bp += 2) { 6330 if ((rv = write_UInt16Number(((unsigned int)*up), bp)) != 0) { 6331 sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed"); 6332 *bpp = bp; 6333 return icp->errc = rv; 6334 } 6335 } 6336 bp[0] = 0; /* null */ 6337 bp[1] = 0; 6338 bp += 2; 6339 } 6340 6341 /* Write the ScriptCode string */ 6342 if ((rv = write_UInt16Number(p->scCode, bp)) != 0) { 6343 sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed"); 6344 *bpp = bp; 6345 return icp->errc = rv; 6346 } 6347 bp += 2; 6348 if ((rv = write_UInt8Number(p->scSize, bp)) != 0) { 6349 sprintf(icp->err,"icmTextDescription_write: write_UInt8Number() failed"); 6350 *bpp = bp; 6351 return icp->errc = rv; 6352 } 6353 bp += 1; 6354 if (p->scSize > 0) { 6355 if (p->scSize > 67) { 6356 *bpp = bp; 6357 sprintf(icp->err,"icmTextDescription_write: ScriptCode string too long"); 6358 return icp->errc = 1; 6359 } 6360 if (check_null_string((char*)p->scDesc,p->scSize)) { /* RSC added cast */ 6361 *bpp = bp; 6362 sprintf(icp->err,"icmTextDescription_write: ScriptCode string is not terminated"); 6363 return icp->errc = 1; 6364 } 6365 memcpy((void *)bp, (void *)p->scDesc, 67); 6366 } else { 6367 memset((void *)bp, 0, 67); 6368 } 6369 bp += 67; 6370 6371 *bpp = bp; 6372 return 0; 6373 } 6374 6375 /* Dump a text description of the object */ 6376 static void icmTextDescription_dump( 6377 icmBase *pp, 6378 FILE *op, /* Output to dump to */ 6379 int verb /* Verbosity level */ 6380 ) { 6381 icmTextDescription *p = (icmTextDescription *)pp; 6382 unsigned long i, r, c; 6383 6384 if (verb <= 0) 6385 return; 6386 6387 fprintf(op,"TextDescription:\n"); 6388 6389 if (p->size > 0) { 6390 unsigned long size = p->size > 0 ? p->size-1 : 0; 6391 fprintf(op," ASCII data, length %u chars:\n",p->size); 6392 6393 i = 0; 6394 for (r = 1;; r++) { /* count rows */ 6395 if (i >= size) { 6396 fprintf(op,"\n"); 6397 break; 6398 } 6399 if (r > 1 && verb < 2) { 6400 fprintf(op,"...\n"); 6401 break; /* Print 1 row if not verbose */ 6402 } 6403 c = 1; 6404 fprintf(op," 0x%04x: ",i); 6405 c += 10; 6406 while (i < size && c < 75) { 6407 if (isprint(p->desc[i])) { 6408 fprintf(op,"%c",p->desc[i]); 6409 c++; 6410 } else { 6411 fprintf(op,"\\%03o",p->desc[i]); 6412 c += 4; 6413 } 6414 i++; 6415 } 6416 if (i < size) 6417 fprintf(op,"\n"); 6418 } 6419 } else { 6420 fprintf(op," No ASCII data\n"); 6421 } 6422 6423 /* Can't dump Unicode or ScriptCode as text with portable code */ 6424 if (p->ucSize > 0) { 6425 unsigned long size = p->ucSize; 6426 fprintf(op," Unicode Data, Language code 0x%x, length %u chars\n", 6427 p->ucLangCode, p->ucSize); 6428 i = 0; 6429 for (r = 1;; r++) { /* count rows */ 6430 if (i >= size) { 6431 fprintf(op,"\n"); 6432 break; 6433 } 6434 if (r > 1 && verb < 2) { 6435 fprintf(op,"...\n"); 6436 break; /* Print 1 row if not verbose */ 6437 } 6438 c = 1; 6439 fprintf(op," 0x%04x: ",i); 6440 c += 10; 6441 while (i < size && c < 75) { 6442 fprintf(op,"%04x ",p->ucDesc[i]); 6443 c += 5; 6444 i++; 6445 } 6446 if (i < size) 6447 fprintf(op,"\n"); 6448 } 6449 } else { 6450 fprintf(op," No Unicode data\n"); 6451 } 6452 if (p->scSize > 0) { 6453 unsigned long size = p->scSize; 6454 fprintf(op," ScriptCode Data, Code 0x%x, length %u chars\n", 6455 p->scCode, p->scSize); 6456 i = 0; 6457 for (r = 1;; r++) { /* count rows */ 6458 if (i >= size) { 6459 fprintf(op,"\n"); 6460 break; 6461 } 6462 if (r > 1 && verb < 2) { 6463 fprintf(op,"...\n"); 6464 break; /* Print 1 row if not verbose */ 6465 } 6466 c = 1; 6467 fprintf(op," 0x%04x: ",i); 6468 c += 10; 6469 while (i < size && c < 75) { 6470 fprintf(op,"%02x ",p->scDesc[i]); 6471 c += 3; 6472 i++; 6473 } 6474 if (i < size) 6475 fprintf(op,"\n"); 6476 } 6477 } else { 6478 fprintf(op," No ScriptCode data\n"); 6479 } 6480 } 6481 6482 /* Allocate variable sized data elements */ 6483 static int icmTextDescription_allocate( 6484 icmBase *pp 6485 ) { 6486 icmTextDescription *p = (icmTextDescription *)pp; 6487 icc *icp = p->icp; 6488 6489 if (p->size != p->_size) { 6490 if (p->desc != NULL) 6491 icp->al->free(icp->al, p->desc); 6492 if ((p->desc = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) { 6493 sprintf(icp->err,"icmTextDescription_alloc: malloc() of Ascii description failed"); 6494 return icp->errc = 2; 6495 } 6496 p->_size = p->size; 6497 } 6498 if (p->ucSize != p->uc_size) { 6499 if (p->ucDesc != NULL) 6500 icp->al->free(icp->al, p->ucDesc); 6501 if ((p->ucDesc = (ORD16 *) icp->al->malloc(icp->al, p->ucSize * sizeof(ORD16))) == NULL) { 6502 sprintf(icp->err,"icmTextDescription_alloc: malloc() of Unicode description failed"); 6503 return icp->errc = 2; 6504 } 6505 p->uc_size = p->ucSize; 6506 } 6507 return 0; 6508 } 6509 6510 /* Free all variable sized elements */ 6511 void icmTextDescription_unallocate( 6512 icmTextDescription *p 6513 ) { 6514 icc *icp = p->icp; 6515 6516 if (p->desc != NULL) 6517 icp->al->free(icp->al, p->desc); 6518 if (p->ucDesc != NULL) 6519 icp->al->free(icp->al, p->ucDesc); 6520 } 6521 6522 /* Free all storage in the object */ 6523 static void icmTextDescription_delete( 6524 icmBase *pp 6525 ) { 6526 icmTextDescription *p = (icmTextDescription *)pp; 6527 icc *icp = p->icp; 6528 6529 icmTextDescription_unallocate(p); 6530 icp->al->free(icp->al, p); 6531 } 6532 6533 /* Initialze a named object */ 6534 static void icmTextDescription_init( 6535 icmTextDescription *p, 6536 icc *icp 6537 ) { 6538 memset((void *)p, 0, sizeof(icmTextDescription)); /* Imitate calloc */ 6539 6540 p->ttype = icSigTextDescriptionType; 6541 p->refcount = 1; 6542 p->get_size = icmTextDescription_get_size; 6543 p->read = icmTextDescription_read; 6544 p->write = icmTextDescription_write; 6545 p->dump = icmTextDescription_dump; 6546 p->allocate = icmTextDescription_allocate; 6547 p->del = icmTextDescription_delete; 6548 p->icp = icp; 6549 6550 p->core_read = icmTextDescription_core_read; 6551 p->core_write = icmTextDescription_core_write; 6552 } 6553 6554 /* Create an empty object. Return null on error */ 6555 static icmBase *new_icmTextDescription( 6556 icc *icp 6557 ) { 6558 icmTextDescription *p; 6559 if ((p = (icmTextDescription *) icp->al->calloc(icp->al,1,sizeof(icmTextDescription))) == NULL) 6560 return NULL; 6561 6562 icmTextDescription_init(p,icp); 6563 return (icmBase *)p; 6564 } 6565 6566 /* ---------------------------------------------------------- */ 6567 6568 /* Support for icmDescStruct */ 6569 6570 /* Return the number of bytes needed to write this tag */ 6571 static unsigned int icmDescStruct_get_size( 6572 icmDescStruct *p 6573 ) { 6574 unsigned int len = 0; 6575 len += 20; /* 20 bytes for header info */ 6576 len += p->device.get_size((icmBase *)&p->device); 6577 len += p->model.get_size((icmBase *)&p->model); 6578 return len; 6579 } 6580 6581 /* read the object, return 0 on success, error code on fail */ 6582 static int icmDescStruct_read( 6583 icmDescStruct *p, 6584 char **bpp, /* Pointer to buffer pointer, returns next after read */ 6585 char *end /* Pointer to past end of read buffer */ 6586 ) { 6587 icc *icp = p->icp; 6588 char *bp = *bpp; 6589 int rv = 0; 6590 6591 if ((bp + 20) > end) { 6592 sprintf(icp->err,"icmDescStruct_read: Data too short read header"); 6593 *bpp = bp; 6594 return icp->errc = 1; 6595 } 6596 6597 p->deviceMfg = read_SInt32Number(bp + 0); 6598 p->deviceModel = read_UInt32Number(bp + 4); 6599 read_UInt64Number(&p->attributes, bp + 8); 6600 p->technology = read_UInt32Number(bp + 16); 6601 *bpp = bp += 20; 6602 6603 /* Read the device text description */ 6604 if ((rv = p->device.core_read(&p->device, bpp, end)) != 0) { 6605 return rv; 6606 } 6607 6608 /* Read the model text description */ 6609 if ((rv = p->model.core_read(&p->model, bpp, end)) != 0) { 6610 return rv; 6611 } 6612 6613 return 0; 6614 } 6615 6616 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 6617 static int icmDescStruct_write( 6618 icmDescStruct *p, 6619 char **bpp /* Pointer to buffer pointer, returns next after read */ 6620 ) { 6621 icc *icp = p->icp; 6622 char *bp = *bpp; 6623 int rv = 0; 6624 6625 if ((rv = write_SInt32Number(p->deviceMfg, bp + 0)) != 0) { 6626 sprintf(icp->err,"icmDescStruct_write: write_SInt32Number() failed"); 6627 *bpp = bp; 6628 return icp->errc = rv; 6629 } 6630 if ((rv = write_UInt32Number(p->deviceModel, bp + 4)) != 0) { 6631 sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed"); 6632 *bpp = bp; 6633 return icp->errc = rv; 6634 } 6635 if ((rv = write_UInt64Number(&p->attributes, bp + 8)) != 0) { 6636 sprintf(icp->err,"icmDescStruct_write: write_UInt64Number() failed"); 6637 *bpp = bp; 6638 return icp->errc = rv; 6639 } 6640 if ((rv = write_UInt32Number(p->technology, bp + 16)) != 0) { 6641 sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed"); 6642 *bpp = bp; 6643 return icp->errc = rv; 6644 } 6645 *bpp = bp += 20; 6646 6647 /* Write the device text description */ 6648 if ((rv = p->device.core_write(&p->device, bpp)) != 0) { 6649 return rv; 6650 } 6651 6652 /* Write the model text description */ 6653 if ((rv = p->model.core_write(&p->model, bpp)) != 0) { 6654 return rv; 6655 } 6656 6657 return 0; 6658 } 6659 6660 /* Dump a text description of the object */ 6661 static void icmDescStruct_dump( 6662 icmDescStruct *p, 6663 FILE *op, /* Output to dump to */ 6664 int verb, /* Verbosity level */ 6665 int index /* Description index */ 6666 ) { 6667 if (verb <= 0) 6668 return; 6669 6670 fprintf(op,"DescStruct %u:\n",index); 6671 if (verb >= 1) { 6672 fprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->deviceMfg)); /* ~~~ */ 6673 fprintf(op," Dev. Model = %s\n",tag2str(p->deviceModel)); /* ~~~ */ 6674 fprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l)); 6675 fprintf(op," Dev. Technology = %s\n", string_TechnologySignature(p->technology)); 6676 p->device.dump((icmBase *)&p->device, op,verb); 6677 p->model.dump((icmBase *)&p->model, op,verb); 6678 fprintf(op,"\n"); 6679 } 6680 } 6681 6682 /* Allocate variable sized data elements (ie. descriptions) */ 6683 static int icmDescStruct_allocate( 6684 icmDescStruct *p 6685 ) { 6686 int rv; 6687 6688 if ((rv = p->device.allocate((icmBase *)&p->device)) != 0) { 6689 return rv; 6690 } 6691 if ((rv = p->model.allocate((icmBase *)&p->model)) != 0) { 6692 return rv; 6693 } 6694 return 0; 6695 } 6696 6697 /* Free all storage in the object */ 6698 static void icmDescStruct_delete( 6699 icmDescStruct *p 6700 ) { 6701 icmTextDescription_unallocate(&p->device); 6702 icmTextDescription_unallocate(&p->model); 6703 } 6704 6705 /* Init a DescStruct object */ 6706 static void icmDescStruct_init( 6707 icmDescStruct *p, 6708 icc *icp 6709 ) { 6710 6711 p->allocate = icmDescStruct_allocate; 6712 p->icp = icp; 6713 6714 icmTextDescription_init(&p->device, icp); 6715 icmTextDescription_init(&p->model, icp); 6716 } 6717 6718 /* - - - - - - - - - - - - - - - */ 6719 /* icmProfileSequenceDesc object */ 6720 6721 /* Return the number of bytes needed to write this tag */ 6722 static unsigned int icmProfileSequenceDesc_get_size( 6723 icmBase *pp 6724 ) { 6725 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6726 unsigned int len = 0; 6727 unsigned int i; 6728 len += 12; /* 8 bytes for tag, padding and count */ 6729 for (i = 0; i < p->count; i++) { /* All the description structures */ 6730 len += icmDescStruct_get_size(&p->data[i]); 6731 } 6732 return len; 6733 } 6734 6735 /* read the object, return 0 on success, error code on fail */ 6736 static int icmProfileSequenceDesc_read( 6737 icmBase *pp, 6738 unsigned long len, /* tag length */ 6739 unsigned long of /* start offset within file */ 6740 ) { 6741 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6742 icc *icp = p->icp; 6743 unsigned long i; 6744 char *bp, *buf, *end; 6745 int rv = 0; 6746 6747 if (len < 12) { 6748 sprintf(icp->err,"icmProfileSequenceDesc_read: Tag too small to be legal"); 6749 return icp->errc = 1; 6750 } 6751 6752 /* Allocate a file read buffer */ 6753 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 6754 sprintf(icp->err,"icmProfileSequenceDesc_read: malloc() failed"); 6755 return icp->errc = 2; 6756 } 6757 bp = buf; 6758 end = buf + len; 6759 6760 /* Read portion of file into buffer */ 6761 if ( icp->fp->seek(icp->fp, of) != 0 6762 || icp->fp->read(icp->fp, bp, 1, len) != len) { 6763 sprintf(icp->err,"icmProfileSequenceDesc_read: fseek() or fread() failed"); 6764 icp->al->free(icp->al, buf); 6765 return icp->errc = 1; 6766 } 6767 6768 /* Read type descriptor from the buffer */ 6769 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 6770 sprintf(icp->err,"icmProfileSequenceDesc_read: Wrong tag type for icmProfileSequenceDesc"); 6771 icp->al->free(icp->al, buf); 6772 return icp->errc = 1; 6773 } 6774 bp += 8; /* Skip padding */ 6775 6776 p->count = read_UInt32Number(bp); /* Number of sequence descriptions */ 6777 bp += 4; 6778 6779 /* Read all the sequence descriptions */ 6780 if ((rv = p->allocate((icmBase *)p)) != 0) { 6781 icp->al->free(icp->al, buf); 6782 return rv; 6783 } 6784 for (i = 0; i < p->count; i++) { 6785 if ((rv = icmDescStruct_read(&p->data[i], &bp, end)) != 0) { 6786 icp->al->free(icp->al, buf); 6787 return rv; 6788 } 6789 } 6790 6791 icp->al->free(icp->al, buf); 6792 return 0; 6793 } 6794 6795 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 6796 static int icmProfileSequenceDesc_write( 6797 icmBase *pp, 6798 unsigned long of /* File offset to write from */ 6799 ) { 6800 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6801 icc *icp = p->icp; 6802 unsigned long i; 6803 unsigned int len; 6804 char *bp, *buf; /* Buffer to write from */ 6805 int rv = 0; 6806 6807 /* Allocate a file write buffer */ 6808 len = p->get_size((icmBase *)p); 6809 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 6810 sprintf(icp->err,"icmProfileSequenceDesc_write malloc() failed"); 6811 return icp->errc = 2; 6812 } 6813 bp = buf; 6814 6815 /* Write type descriptor to the buffer */ 6816 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 6817 sprintf(icp->err,"icmProfileSequenceDesc_write: write_SInt32Number() failed"); 6818 icp->al->free(icp->al, buf); 6819 return icp->errc = rv; 6820 } 6821 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 6822 6823 if ((rv = write_UInt32Number(p->count,bp+8)) != 0) { 6824 sprintf(icp->err,"icmProfileSequenceDesc_write: write_UInt32Number() failed"); 6825 icp->al->free(icp->al, buf); 6826 return icp->errc = rv; 6827 } 6828 bp = bp + 12; 6829 6830 /* Write all the description structures */ 6831 for (i = 0; i < p->count; i++) { 6832 if ((rv = icmDescStruct_write(&p->data[i], &bp)) != 0) { 6833 icp->al->free(icp->al, buf); 6834 return rv; 6835 } 6836 } 6837 6838 /* Write to the file */ 6839 if ( icp->fp->seek(icp->fp, of) != 0 6840 || icp->fp->write(icp->fp, buf, 1, len) != len) { 6841 sprintf(icp->err,"icmProfileSequenceDesc_write fseek() or fwrite() failed"); 6842 icp->al->free(icp->al, buf); 6843 return icp->errc = 2; 6844 } 6845 icp->al->free(icp->al, buf); 6846 return 0; 6847 } 6848 6849 /* Dump a text description of the object */ 6850 static void icmProfileSequenceDesc_dump( 6851 icmBase *pp, 6852 FILE *op, /* Output to dump to */ 6853 int verb /* Verbosity level */ 6854 ) { 6855 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6856 if (verb <= 0) 6857 return; 6858 6859 fprintf(op,"ProfileSequenceDesc:\n"); 6860 fprintf(op," No. elements = %u\n",p->count); 6861 if (verb >= 2) { 6862 unsigned long i; 6863 for (i = 0; i < p->count; i++) 6864 icmDescStruct_dump(&p->data[i], op, verb-1, i); 6865 } 6866 } 6867 6868 /* Allocate variable sized data elements (ie. count of profile descriptions) */ 6869 static int icmProfileSequenceDesc_allocate( 6870 icmBase *pp 6871 ) { 6872 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6873 icc *icp = p->icp; 6874 unsigned int i; 6875 6876 if (p->count != p->_count) { 6877 if (p->data != NULL) 6878 icp->al->free(icp->al, p->data); 6879 if ((p->data = (icmDescStruct *) icp->al->malloc(icp->al, p->count * sizeof(icmDescStruct))) == NULL) { 6880 sprintf(icp->err,"icmProfileSequenceDesc_allocate Allocation of DescStruct array failed"); 6881 return icp->errc = 2; 6882 } 6883 /* Now init the DescStructs */ 6884 for (i = 0; i < p->count; i++) { 6885 icmDescStruct_init(&p->data[i], icp); 6886 } 6887 p->_count = p->count; 6888 } 6889 return 0; 6890 } 6891 6892 /* Free all storage in the object */ 6893 static void icmProfileSequenceDesc_delete( 6894 icmBase *pp 6895 ) { 6896 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp; 6897 icc *icp = p->icp; 6898 unsigned int i; 6899 6900 for (i = 0; i < p->count; i++) { 6901 icmDescStruct_delete(&p->data[i]); /* Free allocated contents */ 6902 } 6903 if (p->data != NULL) 6904 icp->al->free(icp->al, p->data); 6905 icp->al->free(icp->al, p); 6906 } 6907 6908 /* Create an empty object. Return null on error */ 6909 static icmBase *new_icmProfileSequenceDesc( 6910 icc *icp 6911 ) { 6912 icmProfileSequenceDesc *p; 6913 if ((p = (icmProfileSequenceDesc *) icp->al->calloc(icp->al,1,sizeof(icmProfileSequenceDesc))) == NULL) 6914 return NULL; 6915 p->ttype = icSigProfileSequenceDescType; 6916 p->refcount = 1; 6917 p->get_size = icmProfileSequenceDesc_get_size; 6918 p->read = icmProfileSequenceDesc_read; 6919 p->write = icmProfileSequenceDesc_write; 6920 p->dump = icmProfileSequenceDesc_dump; 6921 p->allocate = icmProfileSequenceDesc_allocate; 6922 p->del = icmProfileSequenceDesc_delete; 6923 p->icp = icp; 6924 6925 return (icmBase *)p; 6926 } 6927 6928 /* ---------------------------------------------------------- */ 6929 /* Signature */ 6930 6931 /* Return the number of bytes needed to write this tag */ 6932 static unsigned int icmSignature_get_size( 6933 icmBase *pp 6934 ) { 6935 icmSignature *p = (icmSignature *)pp; 6936 unsigned int len = 0; 6937 len += 8; /* 8 bytes for tag and padding */ 6938 len += 4; /* 4 for signature */ 6939 return len; 6940 } 6941 6942 /* read the object, return 0 on success, error code on fail */ 6943 static int icmSignature_read( 6944 icmBase *pp, 6945 unsigned long len, /* tag length */ 6946 unsigned long of /* start offset within file */ 6947 ) { 6948 icmSignature *p = (icmSignature *)pp; 6949 icc *icp = p->icp; 6950 char *bp, *buf; 6951 6952 if (len < 12) { 6953 sprintf(icp->err,"icmSignature_read: Tag too small to be legal"); 6954 return icp->errc = 1; 6955 } 6956 6957 /* Allocate a file read buffer */ 6958 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 6959 sprintf(icp->err,"icmSignature_read: malloc() failed"); 6960 return icp->errc = 2; 6961 } 6962 bp = buf; 6963 6964 /* Read portion of file into buffer */ 6965 if ( icp->fp->seek(icp->fp, of) != 0 6966 || icp->fp->read(icp->fp, bp, 1, len) != len) { 6967 sprintf(icp->err,"icmSignature_read: fseek() or fread() failed"); 6968 icp->al->free(icp->al, buf); 6969 return icp->errc = 1; 6970 } 6971 6972 /* Read type descriptor from the buffer */ 6973 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 6974 sprintf(icp->err,"icmSignaturSignatureng tag type for icmSignature"); 6975 icp->al->free(icp->al, buf); 6976 return icp->errc = 1; 6977 } 6978 6979 /* Read the encoded measurement geometry */ 6980 p->sig = (icTechnologySignature)read_SInt32Number(bp + 8); 6981 6982 icp->al->free(icp->al, buf); 6983 return 0; 6984 } 6985 6986 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 6987 static int icmSignature_write( 6988 icmBase *pp, 6989 unsigned long of /* File offset to write from */ 6990 ) { 6991 icmSignature *p = (icmSignature *)pp; 6992 icc *icp = p->icp; 6993 unsigned int len; 6994 char *bp, *buf; /* Buffer to write from */ 6995 int rv = 0; 6996 6997 /* Allocate a file write buffer */ 6998 len = p->get_size((icmBase *)p); 6999 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7000 sprintf(icp->err,"icmSignature_write malloc() failed"); 7001 return icp->errc = 2; 7002 } 7003 bp = buf; 7004 7005 /* Write type descriptor to the buffer */ 7006 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 7007 sprintf(icp->err,"icmSignature_write: write_SInt32Number() failed"); 7008 icp->al->free(icp->al, buf); 7009 return icp->errc = rv; 7010 } 7011 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 7012 7013 /* Write the signature */ 7014 if ((rv = write_SInt32Number((int)p->sig, bp + 8)) != 0) { 7015 sprintf(icp->err,"icmSignaturea_write: write_SInt32Number() failed"); 7016 icp->al->free(icp->al, buf); 7017 return icp->errc = rv; 7018 } 7019 7020 /* Write to the file */ 7021 if ( icp->fp->seek(icp->fp, of) != 0 7022 || icp->fp->write(icp->fp, buf, 1, len) != len) { 7023 sprintf(icp->err,"icmSignature_write fseek() or fwrite() failed"); 7024 icp->al->free(icp->al, buf); 7025 return icp->errc = 2; 7026 } 7027 icp->al->free(icp->al, buf); 7028 return 0; 7029 } 7030 7031 /* Dump a text description of the object */ 7032 static void icmSignature_dump( 7033 icmBase *pp, 7034 FILE *op, /* Output to dump to */ 7035 int verb /* Verbosity level */ 7036 ) { 7037 icmSignature *p = (icmSignature *)pp; 7038 if (verb <= 0) 7039 return; 7040 7041 fprintf(op,"Signature\n"); 7042 fprintf(op," Technology = %s\n", string_TechnologySignature(p->sig)); 7043 } 7044 7045 /* Allocate variable sized data elements */ 7046 static int icmSignature_allocate( 7047 icmBase *pp 7048 ) { 7049 icmSignature *p = (icmSignature *)pp; 7050 7051 /* Nothing to do */ 7052 return 0; 7053 } 7054 7055 /* Free all storage in the object */ 7056 static void icmSignature_delete( 7057 icmBase *pp 7058 ) { 7059 icmSignature *p = (icmSignature *)pp; 7060 icc *icp = p->icp; 7061 7062 icp->al->free(icp->al, p); 7063 } 7064 7065 /* Create an empty object. Return null on error */ 7066 static icmBase *new_icmSignature( 7067 icc *icp 7068 ) { 7069 icmSignature *p; 7070 if ((p = (icmSignature *) icp->al->calloc(icp->al,1,sizeof(icmSignature))) == NULL) 7071 return NULL; 7072 p->ttype = icSigSignatureType; 7073 p->refcount = 1; 7074 p->get_size = icmSignature_get_size; 7075 p->read = icmSignature_read; 7076 p->write = icmSignature_write; 7077 p->dump = icmSignature_dump; 7078 p->allocate = icmSignature_allocate; 7079 p->del = icmSignature_delete; 7080 p->icp = icp; 7081 7082 return (icmBase *)p; 7083 } 7084 7085 /* ---------------------------------------------------------- */ 7086 7087 /* Data conversion support functions */ 7088 static int read_ScreeningData(icmScreeningData *p, char *d) { 7089 p->frequency = read_S15Fixed16Number(d + 0); 7090 p->angle = read_S15Fixed16Number(d + 4); 7091 p->spotShape = (icSpotShape)read_SInt32Number(d + 8); 7092 return 0; 7093 } 7094 7095 static int write_ScreeningData(icmScreeningData *p, char *d) { 7096 int rv; 7097 if ((rv = write_S15Fixed16Number(p->frequency, d + 0)) != 0) 7098 return rv; 7099 if ((rv = write_S15Fixed16Number(p->angle, d + 4)) != 0) 7100 return rv; 7101 if ((rv = write_SInt32Number((int)p->spotShape, d + 8)) != 0) 7102 return rv; 7103 return 0; 7104 } 7105 7106 7107 /* icmScreening object */ 7108 7109 /* Return the number of bytes needed to write this tag */ 7110 static unsigned int icmScreening_get_size( 7111 icmBase *pp 7112 ) { 7113 icmScreening *p = (icmScreening *)pp; 7114 unsigned int len = 0; 7115 len += 16; /* 16 bytes for tag, padding, flag & channeles */ 7116 len += p->channels * 12; /* 12 bytes for each channel */ 7117 return len; 7118 } 7119 7120 /* read the object, return 0 on success, error code on fail */ 7121 static int icmScreening_read( 7122 icmBase *pp, 7123 unsigned long len, /* tag length */ 7124 unsigned long of /* start offset within file */ 7125 ) { 7126 icmScreening *p = (icmScreening *)pp; 7127 icc *icp = p->icp; 7128 int rv = 0; 7129 unsigned long i; 7130 char *bp, *buf, *end; 7131 7132 if (len < 12) { 7133 sprintf(icp->err,"icmScreening_read: Tag too small to be legal"); 7134 return icp->errc = 1; 7135 } 7136 7137 /* Allocate a file read buffer */ 7138 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7139 sprintf(icp->err,"icmScreening_read: malloc() failed"); 7140 return icp->errc = 2; 7141 } 7142 bp = buf; 7143 end = buf + len; 7144 7145 /* Read portion of file into buffer */ 7146 if ( icp->fp->seek(icp->fp, of) != 0 7147 || icp->fp->read(icp->fp, bp, 1, len) != len) { 7148 sprintf(icp->err,"icmScreening_read: fseek() or fread() failed"); 7149 icp->al->free(icp->al, buf); 7150 return icp->errc = 1; 7151 } 7152 7153 /* Read type descriptor from the buffer */ 7154 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 7155 sprintf(icp->err,"icmScreening_read: Wrong tag type for icmScreening"); 7156 icp->al->free(icp->al, buf); 7157 return icp->errc = 1; 7158 } 7159 p->screeningFlag = read_UInt32Number(bp+8); /* Flags */ 7160 p->channels = read_UInt32Number(bp+12); /* Number of channels */ 7161 bp = bp + 16; 7162 7163 if ((rv = p->allocate((icmBase *)p)) != 0) { 7164 icp->al->free(icp->al, buf); 7165 return rv; 7166 } 7167 7168 /* Read all the data from the buffer */ 7169 for (i = 0; i < p->channels; i++, bp += 12) { 7170 if ((bp + 12) > end) { 7171 sprintf(icp->err,"icmScreening_read: Data too short to read Screening Data"); 7172 icp->al->free(icp->al, buf); 7173 return icp->errc = 1; 7174 } 7175 read_ScreeningData(&p->data[i], bp); 7176 } 7177 icp->al->free(icp->al, buf); 7178 return 0; 7179 } 7180 7181 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 7182 static int icmScreening_write( 7183 icmBase *pp, 7184 unsigned long of /* File offset to write from */ 7185 ) { 7186 icmScreening *p = (icmScreening *)pp; 7187 icc *icp = p->icp; 7188 unsigned long i; 7189 unsigned int len; 7190 char *bp, *buf; /* Buffer to write from */ 7191 int rv = 0; 7192 7193 /* Allocate a file write buffer */ 7194 len = p->get_size((icmBase *)p); 7195 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7196 sprintf(icp->err,"icmScreening_write malloc() failed"); 7197 return icp->errc = 2; 7198 } 7199 bp = buf; 7200 7201 /* Write type descriptor to the buffer */ 7202 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 7203 sprintf(icp->err,"icmScreening_write: write_SInt32Number() failed"); 7204 icp->al->free(icp->al, buf); 7205 return icp->errc = rv; 7206 } 7207 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 7208 7209 if ((rv = write_UInt32Number(p->screeningFlag,bp+8)) != 0) { 7210 sprintf(icp->err,"icmScreening_write: write_UInt32Number() failed"); 7211 icp->al->free(icp->al, buf); 7212 return icp->errc = rv; 7213 } 7214 if ((rv = write_UInt32Number(p->channels,bp+12)) != 0) { 7215 sprintf(icp->err,"icmScreening_write: write_UInt32NumberXYZumber() failed"); 7216 icp->al->free(icp->al, buf); 7217 return icp->errc = rv; 7218 } 7219 bp = bp + 16; 7220 7221 /* Write all the data to the buffer */ 7222 for (i = 0; i < p->channels; i++, bp += 12) { 7223 if ((rv = write_ScreeningData(&p->data[i],bp)) != 0) { 7224 sprintf(icp->err,"icmScreening_write: write_ScreeningData() failed"); 7225 icp->al->free(icp->al, buf); 7226 return icp->errc = rv; 7227 } 7228 } 7229 7230 /* Write to the file */ 7231 if ( icp->fp->seek(icp->fp, of) != 0 7232 || icp->fp->write(icp->fp, buf, 1, len) != len) { 7233 sprintf(icp->err,"icmScreening_write fseek() or fwrite() failed"); 7234 icp->al->free(icp->al, buf); 7235 return icp->errc = 2; 7236 } 7237 icp->al->free(icp->al, buf); 7238 return 0; 7239 } 7240 7241 /* Dump a text description of the object */ 7242 static void icmScreening_dump( 7243 icmBase *pp, 7244 FILE *op, /* Output to dump to */ 7245 int verb /* Verbosity level */ 7246 ) { 7247 icmScreening *p = (icmScreening *)pp; 7248 if (verb <= 0) 7249 return; 7250 7251 fprintf(op,"Screening:\n"); 7252 fprintf(op," Flags = %s\n", string_ScreenEncodings(p->screeningFlag)); 7253 fprintf(op," No. channels = %u\n",p->channels); 7254 if (verb >= 2) { 7255 unsigned long i; 7256 for (i = 0; i < p->channels; i++) { 7257 fprintf(op," %u:\n",i); 7258 fprintf(op," Frequency: %f\n",p->data[i].frequency); 7259 fprintf(op," Angle: %f\n",p->data[i].angle); 7260 fprintf(op," Spot shape: %s\n", string_SpotShape(p->data[i].spotShape)); 7261 } 7262 } 7263 } 7264 7265 /* Allocate variable sized data elements */ 7266 static int icmScreening_allocate( 7267 icmBase *pp 7268 ) { 7269 icmScreening *p = (icmScreening *)pp; 7270 icc *icp = p->icp; 7271 7272 if (p->channels != p->_channels) { 7273 if (p->data != NULL) 7274 icp->al->free(icp->al, p->data); 7275 if ((p->data = (icmScreeningData *) icp->al->malloc(icp->al, p->channels * sizeof(icmScreeningData))) == NULL) { 7276 sprintf(icp->err,"icmScreening_alloc: malloc() of icmScreening data failed"); 7277 return icp->errc = 2; 7278 } 7279 p->_channels = p->channels; 7280 } 7281 return 0; 7282 } 7283 7284 /* Free all storage in the object */ 7285 static void icmScreening_delete( 7286 icmBase *pp 7287 ) { 7288 icmScreening *p = (icmScreening *)pp; 7289 icc *icp = p->icp; 7290 7291 if (p->data != NULL) 7292 icp->al->free(icp->al, p->data); 7293 icp->al->free(icp->al, p); 7294 } 7295 7296 /* Create an empty object. Return null on error */ 7297 static icmBase *new_icmScreening( 7298 icc *icp 7299 ) { 7300 icmScreening *p; 7301 if ((p = (icmScreening *) icp->al->calloc(icp->al,1,sizeof(icmScreening))) == NULL) 7302 return NULL; 7303 p->ttype = icSigScreeningType; 7304 p->refcount = 1; 7305 p->get_size = icmScreening_get_size; 7306 p->read = icmScreening_read; 7307 p->write = icmScreening_write; 7308 p->dump = icmScreening_dump; 7309 p->allocate = icmScreening_allocate; 7310 p->del = icmScreening_delete; 7311 p->icp = icp; 7312 7313 return (icmBase *)p; 7314 } 7315 7316 /* ---------------------------------------------------------- */ 7317 /* icmUcrBg object */ 7318 7319 /* Return the number of bytes needed to write this tag */ 7320 static unsigned int icmUcrBg_get_size( 7321 icmBase *pp 7322 ) { 7323 icmUcrBg *p = (icmUcrBg *)pp; 7324 unsigned int len = 0; 7325 len += 8; /* 8 bytes for tag and padding */ 7326 len += 4 + p->UCRcount * 2; /* Undercolor Removal */ 7327 len += 4 + p->BGcount * 2; /* Black Generation */ 7328 len += p->size; /* Description string */ 7329 return len; 7330 } 7331 7332 /* read the object, return 0 on success, error code on fail */ 7333 static int icmUcrBg_read( 7334 icmBase *pp, 7335 unsigned long len, /* tag length */ 7336 unsigned long of /* start offset within file */ 7337 ) { 7338 icmUcrBg *p = (icmUcrBg *)pp; 7339 icc *icp = p->icp; 7340 unsigned long i; 7341 int rv = 0; 7342 char *bp, *buf, *end; 7343 7344 if (len < 16) { 7345 sprintf(icp->err,"icmUcrBg_read: Tag too small to be legal"); 7346 return icp->errc = 1; 7347 } 7348 7349 /* Allocate a file read buffer */ 7350 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7351 sprintf(icp->err,"icmUcrBg_read: malloc() failed"); 7352 return icp->errc = 2; 7353 } 7354 bp = buf; 7355 end = buf + len; 7356 7357 /* Read portion of file into buffer */ 7358 if ( icp->fp->seek(icp->fp, of) != 0 7359 || icp->fp->read(icp->fp, bp, 1, len) != len) { 7360 sprintf(icp->err,"icmUcrBg_read: fseek() or fread() failed"); 7361 icp->al->free(icp->al, buf); 7362 return icp->errc = 1; 7363 } 7364 7365 /* Read type descriptor from the buffer */ 7366 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 7367 sprintf(icp->err,"icmUcrBg_read: Wrong tag type for icmUcrBg"); 7368 icp->al->free(icp->al, buf); 7369 return icp->errc = 1; 7370 } 7371 p->UCRcount = read_UInt32Number(bp+8); /* First curve count */ 7372 bp = bp + 12; 7373 7374 if (p->UCRcount > 0) { 7375 if ((rv = p->allocate((icmBase *)p)) != 0) { 7376 icp->al->free(icp->al, buf); 7377 return rv; 7378 } 7379 for (i = 0; i < p->UCRcount; i++, bp += 2) { 7380 if ((bp + 2) > end) { 7381 sprintf(icp->err,"icmUcrBg_read: Data too short to read UCR Data"); 7382 icp->al->free(icp->al, buf); 7383 return icp->errc = 1; 7384 } 7385 if (p->UCRcount == 1) /* % */ 7386 p->UCRcurve[i] = (double)read_UInt16Number(bp); 7387 else /* 0.0 - 1.0 */ 7388 p->UCRcurve[i] = read_DCS16Number(bp); 7389 } 7390 } else { 7391 p->UCRcurve = NULL; 7392 } 7393 7394 if ((bp + 4) > end) { 7395 sprintf(icp->err,"icmData_read: Data too short to read Black Gen count"); 7396 icp->al->free(icp->al, buf); 7397 return icp->errc = 1; 7398 } 7399 p->BGcount = read_UInt32Number(bp); /* First curve count */ 7400 bp += 4; 7401 7402 if (p->BGcount > 0) { 7403 if ((rv = p->allocate((icmBase *)p)) != 0) { 7404 icp->al->free(icp->al, buf); 7405 return rv; 7406 } 7407 for (i = 0; i < p->BGcount; i++, bp += 2) { 7408 if ((bp + 2) > end) { 7409 sprintf(icp->err,"icmUcrBg_read: Data too short to read BG Data"); 7410 icp->al->free(icp->al, buf); 7411 return icp->errc = 1; 7412 } 7413 if (p->BGcount == 1) /* % */ 7414 p->BGcurve[i] = (double)read_UInt16Number(bp); 7415 else /* 0.0 - 1.0 */ 7416 p->BGcurve[i] = read_DCS16Number(bp); 7417 } 7418 } else { 7419 p->BGcurve = NULL; 7420 } 7421 7422 p->size = end - bp; /* Nominal string length */ 7423 if (p->size > 0) { 7424 if (check_null_string(bp, p->size) != 0) { 7425 sprintf(icp->err,"icmUcrBg_read: string is not null terminated"); 7426 icp->al->free(icp->al, buf); 7427 return icp->errc = 1; 7428 } 7429 p->size = strlen(bp) + 1; 7430 if ((rv = p->allocate((icmBase *)p)) != 0) { 7431 icp->al->free(icp->al, buf); 7432 return rv; 7433 } 7434 memcpy((void *)p->string, (void *)bp, p->size); 7435 bp += p->size; 7436 } else { 7437 p->string = NULL; 7438 } 7439 7440 icp->al->free(icp->al, buf); 7441 return 0; 7442 } 7443 7444 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 7445 static int icmUcrBg_write( 7446 icmBase *pp, 7447 unsigned long of /* File offset to write from */ 7448 ) { 7449 icmUcrBg *p = (icmUcrBg *)pp; 7450 icc *icp = p->icp; 7451 unsigned long i; 7452 unsigned int len; 7453 char *bp, *buf; /* Buffer to write from */ 7454 int rv = 0; 7455 7456 /* Allocate a file write buffer */ 7457 len = p->get_size((icmBase *)p); 7458 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7459 sprintf(icp->err,"icmUcrBg_write malloc() failed"); 7460 return icp->errc = 2; 7461 } 7462 bp = buf; 7463 7464 /* Write type descriptor to the buffer */ 7465 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 7466 sprintf(icp->err,"icmUcrBg_write: write_SInt32Number() failed"); 7467 icp->al->free(icp->al, buf); 7468 return icp->errc = rv; 7469 } 7470 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 7471 bp = bp + 8; 7472 7473 /* Write UCR curve */ 7474 if ((rv = write_UInt32Number(p->UCRcount,bp)) != 0) { 7475 sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed"); 7476 icp->al->free(icp->al, buf); 7477 return icp->errc = rv; 7478 } 7479 bp += 4; 7480 7481 for (i = 0; i < p->UCRcount; i++, bp += 2) { 7482 if (p->UCRcount == 1) { /* % */ 7483 if ((rv = write_UInt16Number((unsigned int)(p->UCRcurve[i]+0.5),bp)) != 0) { 7484 sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed"); 7485 icp->al->free(icp->al, buf); 7486 return icp->errc = rv; 7487 } 7488 } else { 7489 if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) { 7490 sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]); 7491 icp->al->free(icp->al, buf); 7492 return icp->errc = rv; 7493 } 7494 } 7495 } 7496 7497 /* Write BG curve */ 7498 if ((rv = write_UInt32Number(p->BGcount,bp)) != 0) { 7499 sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed"); 7500 icp->al->free(icp->al, buf); 7501 return icp->errc = rv; 7502 } 7503 bp += 4; 7504 7505 for (i = 0; i < p->BGcount; i++, bp += 2) { 7506 if (p->BGcount == 1) { /* % */ 7507 if ((rv = write_UInt16Number((unsigned int)(p->BGcurve[i]+0.5),bp)) != 0) { 7508 sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed"); 7509 icp->al->free(icp->al, buf); 7510 return icp->errc = rv; 7511 } 7512 } else { 7513 if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) { 7514 sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]); 7515 icp->al->free(icp->al, buf); 7516 return icp->errc = rv; 7517 } 7518 } 7519 } 7520 7521 if (p->string != NULL) { 7522 if ((rv = check_null_string(p->string,p->size)) != 0) { 7523 sprintf(icp->err,"icmUcrBg_write: text is not null terminated"); 7524 icp->al->free(icp->al, buf); 7525 return icp->errc = 1; 7526 } 7527 memcpy((void *)bp, (void *)p->string, p->size); 7528 } 7529 7530 /* Write to the file */ 7531 if ( icp->fp->seek(icp->fp, of) != 0 7532 || icp->fp->write(icp->fp, buf, 1, len) != len) { 7533 sprintf(icp->err,"icmUcrBg_write fseek() or fwrite() failed"); 7534 icp->al->free(icp->al, buf); 7535 return icp->errc = 2; 7536 } 7537 icp->al->free(icp->al, buf); 7538 return 0; 7539 } 7540 7541 /* Dump a text description of the object */ 7542 static void icmUcrBg_dump( 7543 icmBase *pp, 7544 FILE *op, /* Output to dump to */ 7545 int verb /* Verbosity level */ 7546 ) { 7547 icmUcrBg *p = (icmUcrBg *)pp; 7548 if (verb <= 0) 7549 return; 7550 7551 fprintf(op,"Undercolor Removal Curve & Black Generation:\n"); 7552 7553 if (p->UCRcount == 0) { 7554 fprintf(op," UCR: Not specified\n"); 7555 } else if (p->UCRcount == 1) { 7556 fprintf(op," UCR: %f%%\n",p->UCRcurve[0]); 7557 } else { 7558 fprintf(op," UCR curve no. elements = %u\n",p->UCRcount); 7559 if (verb >= 2) { 7560 unsigned long i; 7561 for (i = 0; i < p->UCRcount; i++) 7562 fprintf(op," % 3u: %f\n",i,p->UCRcurve[i]); 7563 } 7564 } 7565 if (p->BGcount == 0) { 7566 fprintf(op," BG: Not specified\n"); 7567 } else if (p->BGcount == 1) { 7568 fprintf(op," BG: %f%%\n",p->BGcurve[0]); 7569 } else { 7570 fprintf(op," BG curve no. elements = %u\n",p->BGcount); 7571 if (verb >= 2) { 7572 unsigned long i; 7573 for (i = 0; i < p->BGcount; i++) 7574 fprintf(op," % 3u: %f\n",i,p->BGcurve[i]); 7575 } 7576 } 7577 7578 { 7579 unsigned long i, r, c, size; 7580 fprintf(op," Description:\n"); 7581 fprintf(op," No. chars = %u\n",p->size); 7582 7583 size = p->size > 0 ? p->size-1 : 0; 7584 i = 0; 7585 for (r = 1;; r++) { /* count rows */ 7586 if (i >= size) { 7587 fprintf(op,"\n"); 7588 break; 7589 } 7590 if (r > 1 && verb < 2) { 7591 fprintf(op,"...\n"); 7592 break; /* Print 1 row if not verbose */ 7593 } 7594 c = 1; 7595 fprintf(op," 0x%04x: ",i); 7596 c += 10; 7597 while (i < size && c < 73) { 7598 if (isprint(p->string[i])) { 7599 fprintf(op,"%c",p->string[i]); 7600 c++; 7601 } else { 7602 fprintf(op,"\\%03o",p->string[i]); 7603 c += 4; 7604 } 7605 i++; 7606 } 7607 if (i < size) 7608 fprintf(op,"\n"); 7609 } 7610 } 7611 } 7612 7613 /* Allocate variable sized data elements */ 7614 static int icmUcrBg_allocate( 7615 icmBase *pp 7616 ) { 7617 icmUcrBg *p = (icmUcrBg *)pp; 7618 icc *icp = p->icp; 7619 7620 if (p->UCRcount != p->UCR_count) { 7621 if (p->UCRcurve != NULL) 7622 icp->al->free(icp->al, p->UCRcurve); 7623 if ((p->UCRcurve = (double *) icp->al->malloc(icp->al, p->UCRcount * sizeof(double))) == NULL) { 7624 sprintf(icp->err,"icmUcrBg_allocate: malloc() of UCR curve data failed"); 7625 return icp->errc = 2; 7626 } 7627 p->UCR_count = p->UCRcount; 7628 } 7629 if (p->BGcount != p->BG_count) { 7630 if (p->BGcurve != NULL) 7631 icp->al->free(icp->al, p->BGcurve); 7632 if ((p->BGcurve = (double *) icp->al->malloc(icp->al, p->BGcount * sizeof(double))) == NULL) { 7633 sprintf(icp->err,"icmUcrBg_allocate: malloc() of BG curve data failed"); 7634 return icp->errc = 2; 7635 } 7636 p->BG_count = p->BGcount; 7637 } 7638 if (p->size != p->_size) { 7639 if (p->string != NULL) 7640 icp->al->free(icp->al, p->string); 7641 if ((p->string = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) { 7642 sprintf(icp->err,"icmUcrBg_allocate: malloc() of string data failed"); 7643 return icp->errc = 2; 7644 } 7645 p->_size = p->size; 7646 } 7647 return 0; 7648 } 7649 7650 /* Free all storage in the object */ 7651 static void icmUcrBg_delete( 7652 icmBase *pp 7653 ) { 7654 icmUcrBg *p = (icmUcrBg *)pp; 7655 icc *icp = p->icp; 7656 7657 if (p->UCRcurve != NULL) 7658 icp->al->free(icp->al, p->UCRcurve); 7659 if (p->BGcurve != NULL) 7660 icp->al->free(icp->al, p->BGcurve); 7661 if (p->string != NULL) 7662 icp->al->free(icp->al, p->string); 7663 icp->al->free(icp->al, p); 7664 } 7665 7666 /* Create an empty object. Return null on error */ 7667 static icmBase *new_icmUcrBg( 7668 icc *icp 7669 ) { 7670 icmUcrBg *p; 7671 if ((p = (icmUcrBg *) icp->al->calloc(icp->al,1,sizeof(icmUcrBg))) == NULL) 7672 return NULL; 7673 p->ttype = icSigUcrBgType; 7674 p->refcount = 1; 7675 p->get_size = icmUcrBg_get_size; 7676 p->read = icmUcrBg_read; 7677 p->write = icmUcrBg_write; 7678 p->dump = icmUcrBg_dump; 7679 p->allocate = icmUcrBg_allocate; 7680 p->del = icmUcrBg_delete; 7681 p->icp = icp; 7682 7683 return (icmBase *)p; 7684 } 7685 7686 /* ---------------------------------------------------------- */ 7687 /* VideoCardGamma (ColorSync 2.5 specific - c/o Neil Okamoto) */ 7688 7689 static unsigned int icmVideoCardGamma_get_size( 7690 icmBase *pp 7691 ) { 7692 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 7693 unsigned int len = 0; 7694 7695 len += 8; /* 8 bytes for tag and padding */ 7696 len += 4; /* 4 for gamma type */ 7697 7698 /* compute size of remainder */ 7699 if (p->tagType == icmVideoCardGammaTableType) { 7700 len += 2; /* 2 bytes for channels */ 7701 len += 2; /* 2 for entry count */ 7702 len += 2; /* 2 for entry size */ 7703 len += ( p->u.table.channels * /* compute table size */ 7704 p->u.table.entryCount * 7705 p->u.table.entrySize ); 7706 } 7707 else if (p->tagType == icmVideoCardGammaFormulaType) { 7708 len += 12; /* 4 bytes each for red gamma, min, & max */ 7709 len += 12; /* 4 bytes each for green gamma, min & max */ 7710 len += 12; /* 4 bytes each for blue gamma, min & max */ 7711 } 7712 return len; 7713 } 7714 /* read the object, return 0 on success, error code on fail */ 7715 static int icmVideoCardGamma_read( 7716 icmBase *pp, 7717 unsigned long len, /* tag length */ 7718 unsigned long of /* start offset within file */ 7719 ) { 7720 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 7721 icc *icp = p->icp; 7722 int rv, c; 7723 char *bp, *buf; 7724 unsigned char *pchar; 7725 unsigned short *pshort; 7726 7727 if (len < 18) { 7728 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal"); 7729 return icp->errc = 1; 7730 } 7731 7732 /* Allocate a file read buffer */ 7733 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7734 sprintf(icp->err,"icmVideoCardGamma_read: malloc() failed"); 7735 return icp->errc = 2; 7736 } 7737 bp = buf; 7738 7739 /* Read portion of file into buffer */ 7740 if ( icp->fp->seek(icp->fp, of) != 0 7741 || icp->fp->read(icp->fp, bp, 1, len) != len) { 7742 sprintf(icp->err,"icmVideoCardGamma_read: fseek() or fread() failed"); 7743 icp->al->free(icp->al, buf); 7744 return icp->errc = 1; 7745 } 7746 7747 /* Read type descriptor from the buffer */ 7748 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 7749 sprintf(icp->err,"icmVideoCardGamma_read: Wrong tag type for icmVideoCardGamma"); 7750 icp->al->free(icp->al, buf); 7751 return icp->errc = 1; 7752 } 7753 7754 /* Read gamma format (eg. table or formula) from the buffer */ 7755 p->tagType = read_UInt32Number(bp+8); 7756 7757 /* Read remaining gamma data based on format */ 7758 switch (p->tagType) { 7759 case icmVideoCardGammaTableType: 7760 p->u.table.channels = read_UInt16Number(bp+12); 7761 p->u.table.entryCount = read_UInt16Number(bp+14); 7762 p->u.table.entrySize = read_UInt16Number(bp+16); 7763 if (len-18 < p->u.table.channels*p->u.table.entryCount*p->u.table.entrySize) { 7764 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal"); 7765 return icp->errc = 1; 7766 } 7767 if ((rv = pp->allocate(pp)) != 0) { /* make space for table */ 7768 icp->al->free(icp->al, buf); 7769 return icp->errc = rv; 7770 } 7771 pchar = (unsigned char*)p->u.table.data; 7772 pshort = (unsigned short*)p->u.table.data; 7773 for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) { 7774 switch (p->u.table.entrySize) { 7775 case 1: 7776 *pchar++ = read_UInt8Number(bp); 7777 bp++; 7778 break; 7779 case 2: 7780 *pshort++ = read_UInt16Number(bp); 7781 bp+=2; 7782 break; 7783 default: 7784 sprintf(icp->err,"icmVideoCardGamma_read: unsupported table entry size"); 7785 pp->del(pp); 7786 icp->al->free(icp->al, buf); 7787 return icp->errc = 1; 7788 } 7789 } 7790 break; 7791 case icmVideoCardGammaFormulaType: 7792 if (len < 48) { 7793 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal"); 7794 return icp->errc = 1; 7795 } 7796 p->u.formula.redGamma = read_S15Fixed16Number(bp+12); 7797 p->u.formula.redMin = read_S15Fixed16Number(bp+16); 7798 p->u.formula.redMax = read_S15Fixed16Number(bp+20); 7799 p->u.formula.greenGamma = read_S15Fixed16Number(bp+24); 7800 p->u.formula.greenMin = read_S15Fixed16Number(bp+28); 7801 p->u.formula.greenMax = read_S15Fixed16Number(bp+32); 7802 p->u.formula.blueGamma = read_S15Fixed16Number(bp+36); 7803 p->u.formula.blueMin = read_S15Fixed16Number(bp+40); 7804 p->u.formula.blueMax = read_S15Fixed16Number(bp+44); 7805 break; 7806 default: 7807 sprintf(icp->err,"icmVideoCardGammaTable_read: Unknown gamma format for icmVideoCardGamma"); 7808 icp->al->free(icp->al, buf); 7809 return icp->errc = 1; 7810 } 7811 7812 icp->al->free(icp->al, buf); 7813 return 0; 7814 } 7815 7816 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 7817 static int icmVideoCardGamma_write( 7818 icmBase *pp, 7819 unsigned long of /* File offset to write from */ 7820 ) { 7821 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 7822 icc *icp = p->icp; 7823 unsigned int len; 7824 char *bp, *buf; /* Buffer to write from */ 7825 int rv = 0, c; 7826 unsigned char *pchar; 7827 unsigned short *pshort; 7828 7829 /* Allocate a file write buffer */ 7830 len = p->get_size((icmBase *)p); 7831 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 7832 sprintf(icp->err,"icmViewingConditions_write malloc() failed"); 7833 return icp->errc = 2; 7834 } 7835 bp = buf; 7836 7837 /* Write type descriptor to the buffer */ 7838 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 7839 sprintf(icp->err,"icmVideoCardGamma_write: write_SInt32Number() failed"); 7840 icp->al->free(icp->al, buf); 7841 return icp->errc = rv; 7842 } 7843 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 7844 7845 /* Write gamma format (eg. table of formula) */ 7846 if ((rv = write_UInt32Number(p->tagType,bp+8)) != 0) { 7847 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt32Number() failed"); 7848 icp->al->free(icp->al, buf); 7849 return icp->errc = rv; 7850 } 7851 7852 /* Write remaining gamma data based on format */ 7853 switch (p->tagType) { 7854 case icmVideoCardGammaTableType: 7855 if ((rv = write_UInt16Number(p->u.table.channels,bp+12)) != 0) { 7856 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed"); 7857 icp->al->free(icp->al, buf); 7858 return icp->errc = rv; 7859 } 7860 if ((rv = write_UInt16Number(p->u.table.entryCount,bp+14)) != 0) { 7861 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed"); 7862 icp->al->free(icp->al, buf); 7863 return icp->errc = rv; 7864 } 7865 if ((rv = write_UInt16Number(p->u.table.entrySize,bp+16)) != 0) { 7866 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed"); 7867 icp->al->free(icp->al, buf); 7868 return icp->errc = rv; 7869 } 7870 pchar = (unsigned char*)p->u.table.data; 7871 pshort = (unsigned short*)p->u.table.data; 7872 for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) { 7873 switch (p->u.table.entrySize) { 7874 case 1: 7875 write_UInt8Number(*pchar++,bp); 7876 bp++; 7877 break; 7878 case 2: 7879 write_UInt16Number(*pshort++,bp); 7880 bp+=2; 7881 break; 7882 default: 7883 sprintf(icp->err,"icmVideoCardGamma_write: unsupported table entry size"); 7884 icp->al->free(icp->al, buf); 7885 return icp->errc = 1; 7886 } 7887 } 7888 break; 7889 case icmVideoCardGammaFormulaType: 7890 if ((rv = write_S15Fixed16Number(p->u.formula.redGamma,bp+12)) != 0) { 7891 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7892 icp->al->free(icp->al, buf); 7893 return icp->errc = rv; 7894 } 7895 if ((rv = write_S15Fixed16Number(p->u.formula.redMin,bp+16)) != 0) { 7896 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7897 icp->al->free(icp->al, buf); 7898 return icp->errc = rv; 7899 } 7900 if ((rv = write_S15Fixed16Number(p->u.formula.redMax,bp+20)) != 0) { 7901 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7902 icp->al->free(icp->al, buf); 7903 return icp->errc = rv; 7904 } 7905 if ((rv = write_S15Fixed16Number(p->u.formula.greenGamma,bp+24)) != 0) { 7906 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7907 icp->al->free(icp->al, buf); 7908 return icp->errc = rv; 7909 } 7910 if ((rv = write_S15Fixed16Number(p->u.formula.greenMin,bp+28)) != 0) { 7911 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7912 icp->al->free(icp->al, buf); 7913 return icp->errc = rv; 7914 } 7915 if ((rv = write_S15Fixed16Number(p->u.formula.greenMax,bp+32)) != 0) { 7916 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7917 icp->al->free(icp->al, buf); 7918 return icp->errc = rv; 7919 } 7920 if ((rv = write_S15Fixed16Number(p->u.formula.blueGamma,bp+36)) != 0) { 7921 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7922 icp->al->free(icp->al, buf); 7923 return icp->errc = rv; 7924 } 7925 if ((rv = write_S15Fixed16Number(p->u.formula.blueMin,bp+40)) != 0) { 7926 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7927 icp->al->free(icp->al, buf); 7928 return icp->errc = rv; 7929 } 7930 if ((rv = write_S15Fixed16Number(p->u.formula.blueMax,bp+44)) != 0) { 7931 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed"); 7932 icp->al->free(icp->al, buf); 7933 return icp->errc = rv; 7934 } 7935 break; 7936 default: 7937 sprintf(icp->err,"icmVideoCardGammaTable_write: Unknown gamma format for icmVideoCardGamma"); 7938 icp->al->free(icp->al, buf); 7939 return icp->errc = 1; 7940 } 7941 7942 /* Write to the file */ 7943 if ( icp->fp->seek(icp->fp, of) != 0 7944 || icp->fp->write(icp->fp, buf, 1, len) != len) { 7945 sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed"); 7946 icp->al->free(icp->al, buf); 7947 return icp->errc = 2; 7948 } 7949 icp->al->free(icp->al, buf); 7950 return 0; 7951 } 7952 7953 /* Dump a text description of the object */ 7954 static void icmVideoCardGamma_dump( 7955 icmBase *pp, 7956 FILE *op, /* Output to dump to */ 7957 int verb /* Verbosity level */ 7958 ) { 7959 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 7960 int c,i; 7961 7962 if (verb <= 0) 7963 return; 7964 7965 switch (p->tagType) { 7966 case icmVideoCardGammaTableType: 7967 fprintf(op,"VideoCardGammaTable:\n"); 7968 fprintf(op," channels = %d\n", p->u.table.channels); 7969 fprintf(op," entries = %d\n", p->u.table.entryCount); 7970 fprintf(op," entrysize = %d\n", p->u.table.entrySize); 7971 if (verb >= 2) { 7972 /* dump array contents also */ 7973 for (c=0; c<p->u.table.channels; c++) { 7974 fprintf(op," channel #%d\n",c); 7975 for (i=0; i<p->u.table.entryCount; i++) { 7976 if (p->u.table.entrySize == 1) { 7977 fprintf(op," %d: %d\n",i,((unsigned char*)p->u.table.data)[c*p->u.table.entryCount+i]); 7978 } 7979 else if (p->u.table.entrySize == 2) { 7980 fprintf(op," %d: %d\n",i,((unsigned short*)p->u.table.data)[c*p->u.table.entryCount+i]); 7981 } 7982 } 7983 } 7984 } 7985 break; 7986 case icmVideoCardGammaFormulaType: 7987 fprintf(op,"VideoCardGammaFormula:\n"); 7988 fprintf(op," red gamma = %lf\n", p->u.formula.redGamma); 7989 fprintf(op," red min = %lf\n", p->u.formula.redMin); 7990 fprintf(op," red max = %lf\n", p->u.formula.redMax); 7991 fprintf(op," green gamma = %lf\n", p->u.formula.greenGamma); 7992 fprintf(op," green min = %lf\n", p->u.formula.greenMin); 7993 fprintf(op," green max = %lf\n", p->u.formula.greenMax); 7994 fprintf(op," blue gamma = %lf\n", p->u.formula.blueGamma); 7995 fprintf(op," blue min = %lf\n", p->u.formula.blueMin); 7996 fprintf(op," blue max = %lf\n", p->u.formula.blueMax); 7997 break; 7998 default: 7999 fprintf(op," Unknown tag format\n"); 8000 } 8001 } 8002 8003 /* Allocate variable sized data elements */ 8004 static int icmVideoCardGamma_allocate( 8005 icmBase *pp 8006 ) { 8007 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 8008 icc *icp = p->icp; 8009 int size; 8010 8011 /* note: allocation is only relevant for table type 8012 * and in that case the channels, entryCount, and entrySize 8013 * fields must all be set prior to getting here 8014 */ 8015 8016 if (p->tagType == icmVideoCardGammaTableType) { 8017 if (p->u.table.data != NULL) 8018 icp->al->free(icp->al, p->u.table.data); 8019 size = (p->u.table.channels * 8020 p->u.table.entryCount); 8021 switch (p->u.table.entrySize) { 8022 case 1: 8023 size *= sizeof(unsigned char); 8024 break; 8025 case 2: 8026 size *= sizeof(unsigned short); 8027 break; 8028 default: 8029 sprintf(icp->err,"icmVideoCardGamma_alloc: unsupported table entry size"); 8030 return icp->errc = 1; 8031 } 8032 if ((p->u.table.data = (void*) icp->al->malloc(icp->al, size)) == NULL) { 8033 sprintf(icp->err,"icmVideoCardGamma_alloc: malloc() of table data failed"); 8034 return icp->errc = 2; 8035 } 8036 } 8037 8038 return 0; 8039 } 8040 8041 /* Free all storage in the object */ 8042 static void icmVideoCardGamma_delete( 8043 icmBase *pp 8044 ) { 8045 icmVideoCardGamma *p = (icmVideoCardGamma *)pp; 8046 icc *icp = p->icp; 8047 8048 if (p->tagType == icmVideoCardGammaTableType && p->u.table.data != NULL) 8049 icp->al->free(icp->al, p->u.table.data); 8050 8051 icp->al->free(icp->al, p); 8052 } 8053 8054 /* Create an empty object. Return null on error */ 8055 static icmBase *new_icmVideoCardGamma( 8056 icc *icp 8057 ) { 8058 icmVideoCardGamma *p; 8059 if ((p = (icmVideoCardGamma *) icp->al->calloc(icp->al,1,sizeof(icmVideoCardGamma))) == NULL) 8060 return NULL; 8061 p->ttype = icSigVideoCardGammaType; 8062 p->refcount = 1; 8063 p->get_size = icmVideoCardGamma_get_size; 8064 p->read = icmVideoCardGamma_read; 8065 p->write = icmVideoCardGamma_write; 8066 p->dump = icmVideoCardGamma_dump; 8067 p->allocate = icmVideoCardGamma_allocate; 8068 p->del = icmVideoCardGamma_delete; 8069 p->icp = icp; 8070 8071 return (icmBase *)p; 8072 } 8073 8074 /* ---------------------------------------------------------- */ 8075 /* ViewingConditions */ 8076 8077 /* Return the number of bytes needed to write this tag */ 8078 static unsigned int icmViewingConditions_get_size( 8079 icmBase *pp 8080 ) { 8081 icmViewingConditions *p = (icmViewingConditions *)pp; 8082 unsigned int len = 0; 8083 len += 8; /* 8 bytes for tag and padding */ 8084 len += 12; /* 12 for XYZ of illuminant */ 8085 len += 12; /* 12 for XYZ of surround */ 8086 len += 4; /* 4 for illuminant type */ 8087 return len; 8088 } 8089 8090 /* read the object, return 0 on success, error code on fail */ 8091 static int icmViewingConditions_read( 8092 icmBase *pp, 8093 unsigned long len, /* tag length */ 8094 unsigned long of /* start offset within file */ 8095 ) { 8096 icmViewingConditions *p = (icmViewingConditions *)pp; 8097 icc *icp = p->icp; 8098 int rv; 8099 char *bp, *buf; 8100 8101 if (len < 36) { 8102 sprintf(icp->err,"icmViewingConditions_read: Tag too small to be legal"); 8103 return icp->errc = 1; 8104 } 8105 8106 /* Allocate a file read buffer */ 8107 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 8108 sprintf(icp->err,"icmViewingConditions_read: malloc() failed"); 8109 return icp->errc = 2; 8110 } 8111 bp = buf; 8112 8113 /* Read portion of file into buffer */ 8114 if ( icp->fp->seek(icp->fp, of) != 0 8115 || icp->fp->read(icp->fp, bp, 1, len) != len) { 8116 sprintf(icp->err,"icmViewingConditions_read: fseek() or fread() failed"); 8117 icp->al->free(icp->al, buf); 8118 return icp->errc = 1; 8119 } 8120 8121 /* Read type descriptor from the buffer */ 8122 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 8123 sprintf(icp->err,"icmViewingConditions_read: Wrong tag type for icmViewingConditions"); 8124 icp->al->free(icp->al, buf); 8125 return icp->errc = 1; 8126 } 8127 8128 /* Read the XYZ values for the illuminant */ 8129 if ((rv = read_XYZNumber(&p->illuminant, bp+8)) != 0) { 8130 sprintf(icp->err,"icmViewingConditions: read_XYZNumber error"); 8131 icp->al->free(icp->al, buf); 8132 return icp->errc = rv; 8133 } 8134 8135 /* Read the XYZ values for the surround */ 8136 if ((rv = read_XYZNumber(&p->surround, bp+20)) != 0) { 8137 sprintf(icp->err,"icmViewingConditions: read_XYZNumber error"); 8138 icp->al->free(icp->al, buf); 8139 return icp->errc = rv; 8140 } 8141 8142 /* Read the encoded standard illuminant */ 8143 p->stdIlluminant = (icIlluminant)read_SInt32Number(bp + 32); 8144 8145 icp->al->free(icp->al, buf); 8146 return 0; 8147 } 8148 8149 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 8150 static int icmViewingConditions_write( 8151 icmBase *pp, 8152 unsigned long of /* File offset to write from */ 8153 ) { 8154 icmViewingConditions *p = (icmViewingConditions *)pp; 8155 icc *icp = p->icp; 8156 unsigned int len; 8157 char *bp, *buf; /* Buffer to write from */ 8158 int rv = 0; 8159 8160 /* Allocate a file write buffer */ 8161 len = p->get_size((icmBase *)p); 8162 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 8163 sprintf(icp->err,"icmViewingConditions_write malloc() failed"); 8164 return icp->errc = 2; 8165 } 8166 bp = buf; 8167 8168 /* Write type descriptor to the buffer */ 8169 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 8170 sprintf(icp->err,"icmViewingConditions_write: write_SInt32Number() failed"); 8171 icp->al->free(icp->al, buf); 8172 return icp->errc = rv; 8173 } 8174 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 8175 8176 /* Write the XYZ values for the illuminant */ 8177 if ((rv = write_XYZNumber(&p->illuminant, bp+8)) != 0) { 8178 sprintf(icp->err,"icmViewingConditions: write_XYZNumber error"); 8179 icp->al->free(icp->al, buf); 8180 return icp->errc = rv; 8181 } 8182 8183 /* Write the XYZ values for the surround */ 8184 if ((rv = write_XYZNumber(&p->surround, bp+20)) != 0) { 8185 sprintf(icp->err,"icmViewingConditions: write_XYZNumber error"); 8186 icp->al->free(icp->al, buf); 8187 return icp->errc = rv; 8188 } 8189 8190 /* Write the encoded standard illuminant */ 8191 if ((rv = write_SInt32Number((int)p->stdIlluminant, bp + 32)) != 0) { 8192 sprintf(icp->err,"icmViewingConditionsa_write: write_SInt32Number() failed"); 8193 icp->al->free(icp->al, buf); 8194 return icp->errc = rv; 8195 } 8196 8197 /* Write to the file */ 8198 if ( icp->fp->seek(icp->fp, of) != 0 8199 || icp->fp->write(icp->fp, buf, 1, len) != len) { 8200 sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed"); 8201 icp->al->free(icp->al, buf); 8202 return icp->errc = 2; 8203 } 8204 icp->al->free(icp->al, buf); 8205 return 0; 8206 } 8207 8208 /* Dump a text description of the object */ 8209 static void icmViewingConditions_dump( 8210 icmBase *pp, 8211 FILE *op, /* Output to dump to */ 8212 int verb /* Verbosity level */ 8213 ) { 8214 icmViewingConditions *p = (icmViewingConditions *)pp; 8215 if (verb <= 0) 8216 return; 8217 8218 fprintf(op,"Viewing Conditions:\n"); 8219 fprintf(op," XYZ value of illuminant in cd/m^2 = %s\n", string_XYZNumber(&p->illuminant)); 8220 fprintf(op," XYZ value of surround in cd/m^2 = %s\n", string_XYZNumber(&p->surround)); 8221 fprintf(op," Illuminant type = %s\n", string_Illuminant(p->stdIlluminant)); 8222 } 8223 8224 /* Allocate variable sized data elements */ 8225 static int icmViewingConditions_allocate( 8226 icmBase *pp 8227 ) { 8228 icmViewingConditions *p = (icmViewingConditions *)pp; 8229 8230 /* Nothing to do */ 8231 return 0; 8232 } 8233 8234 /* Free all storage in the object */ 8235 static void icmViewingConditions_delete( 8236 icmBase *pp 8237 ) { 8238 icmViewingConditions *p = (icmViewingConditions *)pp; 8239 icc *icp = p->icp; 8240 8241 icp->al->free(icp->al, p); 8242 } 8243 8244 /* Create an empty object. Return null on error */ 8245 static icmBase *new_icmViewingConditions( 8246 icc *icp 8247 ) { 8248 icmViewingConditions *p; 8249 if ((p = (icmViewingConditions *) icp->al->calloc(icp->al,1,sizeof(icmViewingConditions))) == NULL) 8250 return NULL; 8251 p->ttype = icSigViewingConditionsType; 8252 p->refcount = 1; 8253 p->get_size = icmViewingConditions_get_size; 8254 p->read = icmViewingConditions_read; 8255 p->write = icmViewingConditions_write; 8256 p->dump = icmViewingConditions_dump; 8257 p->allocate = icmViewingConditions_allocate; 8258 p->del = icmViewingConditions_delete; 8259 p->icp = icp; 8260 8261 return (icmBase *)p; 8262 } 8263 8264 /* ---------------------------------------------------------- */ 8265 /* icmCrdInfo object */ 8266 8267 /* Return the number of bytes needed to write this tag */ 8268 static unsigned int icmCrdInfo_get_size( 8269 icmBase *pp 8270 ) { 8271 icmCrdInfo *p = (icmCrdInfo *)pp; 8272 unsigned int len = 0, t; 8273 len += 8; /* 8 bytes for tag and padding */ 8274 len += 4 + p->ppsize; /* Postscript product name */ 8275 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8276 len += 4 + p->crdsize[t]; /* crd names */ 8277 } 8278 return len; 8279 } 8280 8281 /* read the object, return 0 on success, error code on fail */ 8282 static int icmCrdInfo_read( 8283 icmBase *pp, 8284 unsigned long len, /* tag length */ 8285 unsigned long of /* start offset within file */ 8286 ) { 8287 icmCrdInfo *p = (icmCrdInfo *)pp; 8288 icc *icp = p->icp; 8289 unsigned long t; 8290 int rv = 0; 8291 char *bp, *buf, *end; 8292 8293 if (len < 28) { 8294 sprintf(icp->err,"icmCrdInfo_read: Tag too small to be legal"); 8295 return icp->errc = 1; 8296 } 8297 8298 /* Allocate a file read buffer */ 8299 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 8300 sprintf(icp->err,"icmCrdInfo_read: malloc() failed"); 8301 return icp->errc = 2; 8302 } 8303 bp = buf; 8304 end = buf + len; 8305 8306 /* Read portion of file into buffer */ 8307 if ( icp->fp->seek(icp->fp, of) != 0 8308 || icp->fp->read(icp->fp, bp, 1, len) != len) { 8309 sprintf(icp->err,"icmCrdInfo_read: fseek() or fread() failed"); 8310 icp->al->free(icp->al, buf); 8311 return icp->errc = 1; 8312 } 8313 8314 /* Read type descriptor from the buffer */ 8315 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) { 8316 sprintf(icp->err,"icmCrdInfo_read: Wrong tag type for icmCrdInfo"); 8317 icp->al->free(icp->al, buf); 8318 return icp->errc = 1; 8319 } 8320 bp = bp + 8; 8321 8322 /* Postscript product name */ 8323 if ((bp + 4) > end) { 8324 sprintf(icp->err,"icmCrdInfo_read: Data too short to read Postscript product name"); 8325 icp->al->free(icp->al, buf); 8326 return icp->errc = 1; 8327 } 8328 p->ppsize = read_UInt32Number(bp); 8329 bp += 4; 8330 if (p->ppsize > 0) { 8331 if ((bp + p->ppsize) > end) { 8332 sprintf(icp->err,"icmCrdInfo_read: Data to short to read Postscript product string"); 8333 icp->al->free(icp->al, buf); 8334 return icp->errc = 1; 8335 } 8336 if (check_null_string(bp,p->ppsize)) { 8337 sprintf(icp->err,"icmCrdInfo_read: Postscript product name is not terminated"); 8338 icp->al->free(icp->al, buf); 8339 return icp->errc = 1; 8340 } 8341 if ((rv = p->allocate((icmBase *)p)) != 0) { 8342 icp->al->free(icp->al, buf); 8343 return rv; 8344 } 8345 memcpy((void *)p->ppname, (void *)bp, p->ppsize); 8346 bp += p->ppsize; 8347 } 8348 8349 /* CRD names for the four rendering intents */ 8350 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8351 if ((bp + 4) > end) { 8352 sprintf(icp->err,"icmCrdInfo_read: Data too short to read CRD%d name",t); 8353 icp->al->free(icp->al, buf); 8354 return icp->errc = 1; 8355 } 8356 p->crdsize[t] = read_UInt32Number(bp); 8357 bp += 4; 8358 if (p->crdsize[t] > 0) { 8359 if ((bp + p->crdsize[t]) > end) { 8360 sprintf(icp->err,"icmCrdInfo_read: Data to short to read CRD%d string",t); 8361 icp->al->free(icp->al, buf); 8362 return icp->errc = 1; 8363 } 8364 if (check_null_string(bp,p->crdsize[t])) { 8365 sprintf(icp->err,"icmCrdInfo_read: CRD%d name is not terminated",t); 8366 icp->al->free(icp->al, buf); 8367 return icp->errc = 1; 8368 } 8369 if ((rv = p->allocate((icmBase *)p)) != 0) { 8370 icp->al->free(icp->al, buf); 8371 return rv; 8372 } 8373 memcpy((void *)p->crdname[t], (void *)bp, p->crdsize[t]); 8374 bp += p->crdsize[t]; 8375 } 8376 } 8377 8378 icp->al->free(icp->al, buf); 8379 return 0; 8380 } 8381 8382 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 8383 static int icmCrdInfo_write( 8384 icmBase *pp, 8385 unsigned long of /* File offset to write from */ 8386 ) { 8387 icmCrdInfo *p = (icmCrdInfo *)pp; 8388 icc *icp = p->icp; 8389 unsigned long t; 8390 unsigned int len; 8391 char *bp, *buf; /* Buffer to write from */ 8392 int rv = 0; 8393 8394 /* Allocate a file write buffer */ 8395 len = p->get_size((icmBase *)p); 8396 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 8397 sprintf(icp->err,"icmCrdInfo_write malloc() failed"); 8398 return icp->errc = 2; 8399 } 8400 bp = buf; 8401 8402 /* Write type descriptor to the buffer */ 8403 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) { 8404 sprintf(icp->err,"icmCrdInfo_write: write_SInt32Number() failed"); 8405 icp->al->free(icp->al, buf); 8406 return icp->errc = rv; 8407 } 8408 write_SInt32Number(0,bp+4); /* Set padding to 0 */ 8409 bp = bp + 8; 8410 8411 /* Postscript product name */ 8412 if ((rv = write_UInt32Number(p->ppsize,bp)) != 0) { 8413 sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed"); 8414 icp->al->free(icp->al, buf); 8415 return icp->errc = rv; 8416 } 8417 bp += 4; 8418 if (p->ppsize > 0) { 8419 if ((rv = check_null_string(p->ppname,p->ppsize)) != 0) { 8420 sprintf(icp->err,"icmCrdInfo_write: Postscript product name is not terminated"); 8421 icp->al->free(icp->al, buf); 8422 return icp->errc = 1; 8423 } 8424 memcpy((void *)bp, (void *)p->ppname, p->ppsize); 8425 bp += p->ppsize; 8426 } 8427 8428 /* CRD names for the four rendering intents */ 8429 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8430 if ((rv = write_UInt32Number(p->crdsize[t],bp)) != 0) { 8431 sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed"); 8432 icp->al->free(icp->al, buf); 8433 return icp->errc = rv; 8434 } 8435 bp += 4; 8436 if (p->ppsize > 0) { 8437 if ((rv = check_null_string(p->crdname[t],p->crdsize[t])) != 0) { 8438 sprintf(icp->err,"icmCrdInfo_write: CRD%d name is not terminated",t); 8439 icp->al->free(icp->al, buf); 8440 return icp->errc = 1; 8441 } 8442 memcpy((void *)bp, (void *)p->crdname[t], p->crdsize[t]); 8443 bp += p->crdsize[t]; 8444 } 8445 } 8446 8447 /* Write to the file */ 8448 if ( icp->fp->seek(icp->fp, of) != 0 8449 || icp->fp->write(icp->fp, buf, 1, len) != len) { 8450 sprintf(icp->err,"icmCrdInfo_write fseek() or fwrite() failed"); 8451 icp->al->free(icp->al, buf); 8452 return icp->errc = 2; 8453 } 8454 icp->al->free(icp->al, buf); 8455 return 0; 8456 } 8457 8458 /* Dump a text description of the object */ 8459 static void icmCrdInfo_dump( 8460 icmBase *pp, 8461 FILE *op, /* Output to dump to */ 8462 int verb /* Verbosity level */ 8463 ) { 8464 icmCrdInfo *p = (icmCrdInfo *)pp; 8465 unsigned long i, r, c, size, t; 8466 8467 if (verb <= 0) 8468 return; 8469 8470 fprintf(op,"PostScript Product name and CRD names:\n"); 8471 8472 fprintf(op," Product name:\n"); 8473 fprintf(op," No. chars = %u\n",p->ppsize); 8474 8475 size = p->ppsize > 0 ? p->ppsize-1 : 0; 8476 i = 0; 8477 for (r = 1;; r++) { /* count rows */ 8478 if (i >= size) { 8479 fprintf(op,"\n"); 8480 break; 8481 } 8482 if (r > 1 && verb < 2) { 8483 fprintf(op,"...\n"); 8484 break; /* Print 1 row if not verbose */ 8485 } 8486 c = 1; 8487 fprintf(op," 0x%04x: ",i); 8488 c += 10; 8489 while (i < size && c < 73) { 8490 if (isprint(p->ppname[i])) { 8491 fprintf(op,"%c",p->ppname[i]); 8492 c++; 8493 } else { 8494 fprintf(op,"\\%03o",p->ppname[i]); 8495 c += 4; 8496 } 8497 i++; 8498 } 8499 if (i < size) 8500 fprintf(op,"\n"); 8501 } 8502 8503 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8504 fprintf(op," CRD%d name:\n",t); 8505 fprintf(op," No. chars = %u\n",p->crdsize[t]); 8506 8507 size = p->crdsize[t] > 0 ? p->crdsize[t]-1 : 0; 8508 i = 0; 8509 for (r = 1;; r++) { /* count rows */ 8510 if (i >= size) { 8511 fprintf(op,"\n"); 8512 break; 8513 } 8514 if (r > 1 && verb < 2) { 8515 fprintf(op,"...\n"); 8516 break; /* Print 1 row if not verbose */ 8517 } 8518 c = 1; 8519 fprintf(op," 0x%04x: ",i); 8520 c += 10; 8521 while (i < size && c < 73) { 8522 if (isprint(p->crdname[t][i])) { 8523 fprintf(op,"%c",p->crdname[t][i]); 8524 c++; 8525 } else { 8526 fprintf(op,"\\%03o",p->crdname[t][i]); 8527 c += 4; 8528 } 8529 i++; 8530 } 8531 if (i < size) 8532 fprintf(op,"\n"); 8533 } 8534 } 8535 } 8536 8537 /* Allocate variable sized data elements */ 8538 static int icmCrdInfo_allocate( 8539 icmBase *pp 8540 ) { 8541 icmCrdInfo *p = (icmCrdInfo *)pp; 8542 icc *icp = p->icp; 8543 unsigned int t; 8544 8545 if (p->ppsize != p->_ppsize) { 8546 if (p->ppname != NULL) 8547 icp->al->free(icp->al, p->ppname); 8548 if ((p->ppname = (char *) icp->al->malloc(icp->al, p->ppsize * sizeof(char))) == NULL) { 8549 sprintf(icp->err,"icmCrdInfo_alloc: malloc() of string data failed"); 8550 return icp->errc = 2; 8551 } 8552 p->_ppsize = p->ppsize; 8553 } 8554 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8555 if (p->crdsize[t] != p->_crdsize[t]) { 8556 if (p->crdname[t] != NULL) 8557 icp->al->free(icp->al, p->crdname[t]); 8558 if ((p->crdname[t] = (char *) icp->al->malloc(icp->al, p->crdsize[t] * sizeof(char))) == NULL) { 8559 sprintf(icp->err,"icmCrdInfo_alloc: malloc() of CRD%d name string failed",t); 8560 return icp->errc = 2; 8561 } 8562 p->_crdsize[t] = p->crdsize[t]; 8563 } 8564 } 8565 return 0; 8566 } 8567 8568 /* Free all storage in the object */ 8569 static void icmCrdInfo_delete( 8570 icmBase *pp 8571 ) { 8572 icmCrdInfo *p = (icmCrdInfo *)pp; 8573 icc *icp = p->icp; 8574 unsigned int t; 8575 8576 if (p->ppname != NULL) 8577 icp->al->free(icp->al, p->ppname); 8578 for (t = 0; t < 4; t++) { /* For all 4 intents */ 8579 if (p->crdname[t] != NULL) 8580 icp->al->free(icp->al, p->crdname[t]); 8581 } 8582 icp->al->free(icp->al, p); 8583 } 8584 8585 /* Create an empty object. Return null on error */ 8586 static icmBase *new_icmCrdInfo( 8587 icc *icp 8588 ) { 8589 icmCrdInfo *p; 8590 if ((p = (icmCrdInfo *) icp->al->calloc(icp->al,1,sizeof(icmCrdInfo))) == NULL) 8591 return NULL; 8592 p->ttype = icSigCrdInfoType; 8593 p->refcount = 1; 8594 p->get_size = icmCrdInfo_get_size; 8595 p->read = icmCrdInfo_read; 8596 p->write = icmCrdInfo_write; 8597 p->dump = icmCrdInfo_dump; 8598 p->allocate = icmCrdInfo_allocate; 8599 p->del = icmCrdInfo_delete; 8600 p->icp = icp; 8601 8602 return (icmBase *)p; 8603 } 8604 8605 /* ========================================================== */ 8606 /* icmHeader object */ 8607 /* ========================================================== */ 8608 8609 /* Return the number of bytes needed to write this tag */ 8610 static unsigned int icmHeader_get_size( 8611 icmHeader *p 8612 ) { 8613 return 128; /* By definition */ 8614 } 8615 8616 /* read the object, return 0 on success, error code on fail */ 8617 static int icmHeader_read( 8618 icmHeader *p, 8619 unsigned long len, /* tag length */ 8620 unsigned long of /* start offset within file */ 8621 ) { 8622 icc *icp = p->icp; 8623 char *buf; 8624 unsigned int tt; 8625 int rv = 0; 8626 8627 if (len != 128) { 8628 sprintf(icp->err,"icmHeader_read: Length expected to be 128"); 8629 return icp->errc = 1; 8630 } 8631 8632 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) { 8633 sprintf(icp->err,"icmHeader_read: malloc() failed"); 8634 return icp->errc = 2; 8635 } 8636 if ( icp->fp->seek(icp->fp, of) != 0 8637 || icp->fp->read(icp->fp, buf, 1, len) != len) { 8638 sprintf(icp->err,"icmHeader_read: fseek() or fread() failed"); 8639 icp->al->free(icp->al, buf); 8640 return icp->errc = 1; 8641 } 8642 8643 /* Fill in the in-memory structure */ 8644 p->size = read_UInt32Number(buf + 0); /* Profile size in bytes */ 8645 p->cmmId = read_SInt32Number(buf + 4); /* CMM for profile */ 8646 tt = read_UInt8Number(buf + 8); /* Raw major version number */ 8647 p->majv = (tt >> 4) * 10 + (tt & 0xf); /* Integer major version number */ 8648 tt = read_UInt8Number(buf + 9); /* Raw minor/bug fix version numbers */ 8649 p->minv = (tt >> 4); /* Integer minor version number */ 8650 p->bfv = (tt & 0xf); /* Integer bug fix version number */ 8651 p->deviceClass = (icProfileClassSignature) 8652 read_SInt32Number(buf + 12); /* Type of profile */ 8653 p->colorSpace = (icColorSpaceSignature) 8654 read_SInt32Number(buf + 16); /* Color space of data */ 8655 p->pcs = (icColorSpaceSignature) 8656 read_SInt32Number(buf + 20); /* PCS: XYZ or Lab */ 8657 if ((rv = read_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */ 8658 sprintf(icp->err,"icmHeader_read: read_DateTimeNumber corrupted"); 8659 icp->al->free(icp->al, buf); 8660 return icp->errc = rv; 8661 } 8662 tt = read_SInt32Number(buf+36); 8663 if (tt != icMagicNumber) { /* Check magic number */ 8664 sprintf(icp->err,"icmHeader_read: wrong magic number 0x%x",tt); 8665 icp->al->free(icp->al, buf); 8666 return icp->errc = 1; 8667 } 8668 p->platform = (icPlatformSignature) 8669 read_SInt32Number(buf + 40); /* Primary platform */ 8670 p->flags = read_UInt32Number(buf + 44); /* Various bits */ 8671 p->manufacturer = read_SInt32Number(buf + 48); /* Dev manufacturer */ 8672 p->model = read_SInt32Number(buf + 52); /* Dev model */ 8673 read_UInt64Number(&p->attributes, buf + 56); /* Device attributes */ 8674 p->renderingIntent = (icRenderingIntent) 8675 read_SInt32Number(buf + 64); /* Rendering intent */ 8676 if ((rv = read_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */ 8677 sprintf(icp->err,"icmHeader_read: read_XYZNumber error"); 8678 icp->al->free(icp->al, buf); 8679 return icp->errc = rv; 8680 } 8681 p->creator = read_SInt32Number(buf + 80); /* Profile creator */ 8682 8683 icp->al->free(icp->al, buf); 8684 return 0; 8685 } 8686 8687 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 8688 static int icmHeader_write( 8689 icmHeader *p, 8690 unsigned long of /* File offset to write from */ 8691 ) { 8692 icc *icp = p->icp; 8693 char *buf; /* Buffer to write from */ 8694 unsigned int len; 8695 unsigned int tt; 8696 int rv = 0; 8697 8698 len = p->get_size(p); 8699 if ((buf = (char *) icp->al->calloc(icp->al,1,len)) == NULL) { /* Zero it - some CMS are fussy */ 8700 sprintf(icp->err,"icmHeader_write calloc() failed"); 8701 return icp->errc = 2; 8702 } 8703 8704 /* Fill in the write buffer */ 8705 if ((rv = write_UInt32Number(p->size, buf + 0)) != 0) { /* Profile size in bytes */ 8706 sprintf(icp->err,"icmHeader_write: profile size"); 8707 icp->al->free(icp->al, buf); 8708 return icp->errc = rv; 8709 } 8710 8711 if ((rv = write_SInt32Number(p->cmmId, buf + 4)) != 0) { /* CMM for profile */ 8712 sprintf(icp->err,"icmHeader_write: cmmId"); 8713 icp->al->free(icp->al, buf); 8714 return icp->errc = rv; 8715 } 8716 if (p->majv < 0 || p->majv > 99 /* Sanity check version numbers */ 8717 || p->minv < 0 || p->minv > 9 8718 || p->bfv < 0 || p->bfv > 9) { 8719 sprintf(icp->err,"icmHeader_write: version number"); 8720 icp->al->free(icp->al, buf); 8721 return icp->errc = 1; 8722 } 8723 tt = ((p->majv/10) << 4) + (p->majv % 10); 8724 if ((rv = write_UInt8Number(tt, buf + 8)) != 0) { /* Raw major version number */ 8725 sprintf(icp->err,"icmHeader_write: Uint8Number major version"); 8726 icp->al->free(icp->al, buf); 8727 return icp->errc = rv; 8728 } 8729 tt = (p->minv << 4) + p->bfv; 8730 if ((rv = write_UInt8Number(tt, buf + 9)) != 0) { /* Raw minor/bug fix version numbers */ 8731 sprintf(icp->err,"icmHeader_write: Uint8Number minor/bug fix"); 8732 icp->al->free(icp->al, buf); 8733 return icp->errc = rv; 8734 } 8735 if ((rv = write_SInt32Number((int)p->deviceClass, buf + 12)) != 0) { /* Type of profile */ 8736 sprintf(icp->err,"icmHeader_write: SInt32Number deviceClass"); 8737 icp->al->free(icp->al, buf); 8738 return icp->errc = rv; 8739 } 8740 if ((rv = write_SInt32Number((int)p->colorSpace, buf + 16)) != 0) { /* Color space of data */ 8741 sprintf(icp->err,"icmHeader_write: SInt32Number data color space"); 8742 icp->al->free(icp->al, buf); 8743 return icp->errc = rv; 8744 } 8745 if ((rv = write_SInt32Number((int)p->pcs, buf + 20)) != 0) { /* PCS: XYZ or Lab */ 8746 sprintf(icp->err,"icmHeader_write: SInt32Number PCS"); 8747 icp->al->free(icp->al, buf); 8748 return icp->errc = rv; 8749 } 8750 if ((rv = write_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */ 8751 sprintf(icp->err,"icmHeader_write: DateTimeNumber creation"); 8752 icp->al->free(icp->al, buf); 8753 return icp->errc = rv; 8754 } 8755 if ((rv = write_SInt32Number(icMagicNumber, buf+36)) != 0) { /* Magic number */ 8756 sprintf(icp->err,"icmHeader_write: SInt32Number magic"); 8757 icp->al->free(icp->al, buf); 8758 return icp->errc = rv; 8759 } 8760 if ((rv = write_SInt32Number((int)p->platform, buf + 40)) != 0) { /* Primary platform */ 8761 sprintf(icp->err,"icmHeader_write: SInt32Number platform"); 8762 icp->al->free(icp->al, buf); 8763 return icp->errc = rv; 8764 } 8765 if ((rv = write_UInt32Number(p->flags, buf + 44)) != 0) { /* Various bits */ 8766 sprintf(icp->err,"icmHeader_write: UInt32Number flags"); 8767 icp->al->free(icp->al, buf); 8768 return icp->errc = rv; 8769 } 8770 if ((rv = write_SInt32Number(p->manufacturer, buf + 48)) != 0) { /* Dev manufacturer */ 8771 sprintf(icp->err,"icmHeader_write: SInt32Number manufaturer"); 8772 icp->al->free(icp->al, buf); 8773 return icp->errc = rv; 8774 } 8775 if ((write_SInt32Number(p->model, buf + 52)) != 0) { /* Dev model */ 8776 sprintf(icp->err,"icmHeader_write: SInt32Number model"); 8777 icp->al->free(icp->al, buf); 8778 return icp->errc = rv; 8779 } 8780 if ((rv = write_UInt64Number(&p->attributes, buf + 56)) != 0) { /* Device attributes */ 8781 sprintf(icp->err,"icmHeader_write: UInt64Number attributes"); 8782 icp->al->free(icp->al, buf); 8783 return icp->errc = rv; 8784 } 8785 if ((rv = write_SInt32Number((int)p->renderingIntent, buf + 64)) != 0) { /* Rendering intent */ 8786 sprintf(icp->err,"icmHeader_write: SInt32Number rendering intent"); 8787 icp->al->free(icp->al, buf); 8788 return icp->errc = rv; 8789 } 8790 if ((rv = write_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */ 8791 sprintf(icp->err,"icmHeader_write: XYZNumber illuminant"); 8792 icp->al->free(icp->al, buf); 8793 return icp->errc = rv; 8794 } 8795 if ((rv = write_SInt32Number(p->creator, buf + 80)) != 0) { /* Profile creator */ 8796 sprintf(icp->err,"icmHeader_write: SInt32Number creator"); 8797 icp->al->free(icp->al, buf); 8798 return icp->errc = rv; 8799 } 8800 8801 if ( icp->fp->seek(icp->fp, of) != 0 8802 || icp->fp->write(icp->fp, buf, 1, len) != len) { 8803 sprintf(icp->err,"icmHeader_write fseek() or fwrite() failed"); 8804 icp->al->free(icp->al, buf); 8805 return icp->errc = 2; 8806 } 8807 8808 icp->al->free(icp->al, buf); 8809 return rv; 8810 } 8811 8812 static void icmHeader_dump( 8813 icmHeader *p, 8814 FILE *op, /* Output to dump to */ 8815 int verb /* Verbosity level */ 8816 ) { 8817 if (verb <= 0) 8818 return; 8819 8820 fprintf(op,"Header:\n"); 8821 fprintf(op," size = %d bytes\n",p->size); 8822 fprintf(op," CMM = %s\n",tag2str(p->cmmId)); 8823 fprintf(op," Version = %d.%d.%d\n",p->majv, p->minv, p->bfv); 8824 fprintf(op," Device Class = %s\n", string_ProfileClassSignature(p->deviceClass)); 8825 fprintf(op," Color Space = %s\n", string_ColorSpaceSignature(p->colorSpace)); 8826 fprintf(op," Conn. Space = %s\n", string_ColorSpaceSignature(p->pcs)); 8827 fprintf(op," Date, Time = %s\n", string_DateTimeNumber(&p->date)); 8828 fprintf(op," Platform = %s\n", string_PlatformSignature(p->platform)); 8829 fprintf(op," Flags = %s\n", string_ProfileHeaderFlags(p->flags)); 8830 fprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->manufacturer)); /* ~~~ */ 8831 fprintf(op," Dev. Model = %s\n",tag2str(p->model)); /* ~~~ */ 8832 fprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l)); 8833 fprintf(op," Rndrng Intnt = %s\n", string_RenderingIntent(p->renderingIntent)); 8834 fprintf(op," Illuminant = %s\n", string_XYZNumber_and_Lab(&p->illuminant)); 8835 fprintf(op," Creator = %s\n",tag2str(p->creator)); /* ~~~ */ 8836 fprintf(op,"\n"); 8837 } 8838 8839 static void icmHeader_delete( 8840 icmHeader *p 8841 ) { 8842 icc *icp = p->icp; 8843 8844 icp->al->free(icp->al, p); 8845 } 8846 8847 /* Create an empty object. Return null on error */ 8848 static icmHeader *new_icmHeader( 8849 icc *icp 8850 ) { 8851 icmHeader *p; 8852 if ((p = (icmHeader *) icp->al->calloc(icp->al,1,sizeof(icmHeader))) == NULL) 8853 return NULL; 8854 p->icp = icp; 8855 p->get_size = icmHeader_get_size; 8856 p->read = icmHeader_read; 8857 p->write = icmHeader_write; 8858 p->dump = icmHeader_dump; 8859 p->del = icmHeader_delete; 8860 8861 return p; 8862 } 8863 8864 /* ---------------------------------------------------------- */ 8865 /* Type vector table. Match the Tag type against the object creator */ 8866 static struct { 8867 icTagTypeSignature ttype; /* The tag type signature */ 8868 icmBase * (*new_obj)(icc *icp); 8869 } typetable[] = { 8870 {icSigCrdInfoType, new_icmCrdInfo}, 8871 {icSigCurveType, new_icmCurve}, 8872 {icSigDataType, new_icmData}, 8873 {icSigDateTimeType, new_icmDateTimeNumber}, 8874 {icSigLut16Type, new_icmLut}, 8875 {icSigLut8Type, new_icmLut}, 8876 {icSigMeasurementType, new_icmMeasurement}, 8877 {icSigNamedColorType, new_icmNamedColor}, 8878 {icSigNamedColor2Type, new_icmNamedColor}, 8879 {icSigProfileSequenceDescType, new_icmProfileSequenceDesc}, 8880 {icSigS15Fixed16ArrayType, new_icmS15Fixed16Array}, 8881 {icSigScreeningType, new_icmScreening}, 8882 {icSigSignatureType, new_icmSignature}, 8883 {icSigTextDescriptionType, new_icmTextDescription}, 8884 {icSigTextType, new_icmText}, 8885 {icSigU16Fixed16ArrayType, new_icmU16Fixed16Array}, 8886 {icSigUcrBgType, new_icmUcrBg}, 8887 {icSigVideoCardGammaType, new_icmVideoCardGamma}, 8888 {icSigUInt16ArrayType, new_icmUInt16Array}, 8889 {icSigUInt32ArrayType, new_icmUInt32Array}, 8890 {icSigUInt64ArrayType, new_icmUInt64Array}, 8891 {icSigUInt8ArrayType, new_icmUInt8Array}, 8892 {icSigViewingConditionsType, new_icmViewingConditions}, 8893 {icSigXYZArrayType, new_icmXYZArray}, 8894 {icMaxEnumType, NULL} 8895 }; 8896 8897 /* Table that lists the legal Types for each Tag Signature */ 8898 static struct { 8899 icTagSignature sig; 8900 icTagTypeSignature ttypes[4]; /* Arbitrary max of 4 */ 8901 } sigtypetable[] = { 8902 {icSigAToB0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8903 {icSigAToB1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8904 {icSigAToB2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8905 {icSigBlueColorantTag, {icSigXYZType,icMaxEnumType}}, 8906 {icSigBlueTRCTag, {icSigCurveType,icMaxEnumType}}, 8907 {icSigBToA0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8908 {icSigBToA1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8909 {icSigBToA2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8910 {icSigCalibrationDateTimeTag, {icSigDateTimeType,icMaxEnumType}}, 8911 {icSigCharTargetTag, {icSigTextType,icMaxEnumType}}, 8912 {icSigCopyrightTag, {icSigTextType,icMaxEnumType}}, 8913 {icSigCrdInfoTag, {icSigCrdInfoType,icMaxEnumType}}, 8914 {icSigDeviceMfgDescTag, {icSigTextDescriptionType,icMaxEnumType}}, 8915 {icSigDeviceModelDescTag, {icSigTextDescriptionType,icMaxEnumType}}, 8916 {icSigGamutTag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8917 {icSigGrayTRCTag, {icSigCurveType,icMaxEnumType}}, 8918 {icSigGreenColorantTag, {icSigXYZType,icMaxEnumType}}, 8919 {icSigGreenTRCTag, {icSigCurveType,icMaxEnumType}}, 8920 {icSigLuminanceTag, {icSigXYZType,icMaxEnumType}}, 8921 {icSigMeasurementTag, {icSigMeasurementType,icMaxEnumType}}, 8922 {icSigMediaBlackPointTag, {icSigXYZType,icMaxEnumType}}, 8923 {icSigMediaWhitePointTag, {icSigXYZType,icMaxEnumType}}, 8924 {icSigNamedColorTag, {icSigNamedColorType,icMaxEnumType}}, 8925 {icSigNamedColor2Tag, {icSigNamedColor2Type,icMaxEnumType}}, 8926 {icSigPreview0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8927 {icSigPreview1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8928 {icSigPreview2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}}, 8929 {icSigProfileDescriptionTag, {icSigTextDescriptionType,icMaxEnumType}}, 8930 {icSigProfileSequenceDescTag, {icSigProfileSequenceDescType,icMaxEnumType}}, 8931 {icSigPs2CRD0Tag, {icSigDataType,icMaxEnumType}}, 8932 {icSigPs2CRD1Tag, {icSigDataType,icMaxEnumType}}, 8933 {icSigPs2CRD2Tag, {icSigDataType,icMaxEnumType}}, 8934 {icSigPs2CRD3Tag, {icSigDataType,icMaxEnumType}}, 8935 {icSigPs2CSATag, {icSigDataType,icMaxEnumType}}, 8936 {icSigPs2RenderingIntentTag, {icSigDataType,icMaxEnumType}}, 8937 {icSigRedColorantTag, {icSigXYZType,icMaxEnumType}}, 8938 {icSigRedTRCTag, {icSigCurveType,icMaxEnumType}}, 8939 {icSigScreeningDescTag, {icSigTextDescriptionType,icMaxEnumType}}, 8940 {icSigScreeningTag, {icSigScreeningType,icMaxEnumType}}, 8941 {icSigTechnologyTag, {icSigSignatureType,icMaxEnumType}}, 8942 {icSigUcrBgTag, {icSigUcrBgType,icMaxEnumType}}, 8943 {icSigVideoCardGammaTag, {icSigVideoCardGammaType,icMaxEnumType}}, 8944 {icSigViewingCondDescTag, {icSigTextDescriptionType,icMaxEnumType}}, 8945 {icSigViewingConditionsTag, {icSigViewingConditionsType,icMaxEnumType}}, 8946 {icMaxEnumType, {icMaxEnumType}} 8947 }; 8948 8949 /* Fake color tag for specifying PCS */ 8950 #define icSigPCSData ((icColorSpaceSignature) 0x50435320L) 8951 8952 /* Table that lists the required tags for various profiles */ 8953 static struct { 8954 icProfileClassSignature sig; /* Profile signature */ 8955 int chans; /* Data Color channels, -ve for match but try next, */ 8956 /* -100 for ignore, -200 for ignore and try next */ 8957 icColorSpaceSignature colsig; /* Data Color space signature, icMaxEnumData for ignore, */ 8958 /* icSigPCSData for XYZ of Lab */ 8959 icColorSpaceSignature pcssig; /* PCS Color space signature, icMaxEnumData for ignore, */ 8960 /* icSigPCSData for XYZ or Lab */ 8961 icTagSignature tags[12]; /* Arbitrary max of 12 */ 8962 } tagchecktable[] = { 8963 {icSigInputClass, -1, icMaxEnumData, icSigPCSData, 8964 {icSigProfileDescriptionTag, 8965 icSigGrayTRCTag, 8966 icSigMediaWhitePointTag, 8967 icSigCopyrightTag, icMaxEnumType}}, 8968 8969 {icSigInputClass, -3, icMaxEnumData, icSigXYZData, 8970 {icSigProfileDescriptionTag, 8971 icSigRedColorantTag, 8972 icSigGreenColorantTag, 8973 icSigBlueColorantTag, 8974 icSigRedTRCTag, 8975 icSigGreenTRCTag, 8976 icSigBlueTRCTag, 8977 icSigMediaWhitePointTag, 8978 icSigCopyrightTag, icMaxEnumType}}, 8979 8980 {icSigInputClass, -100, icMaxEnumData, icSigPCSData, 8981 {icSigProfileDescriptionTag, 8982 icSigAToB0Tag, 8983 icSigMediaWhitePointTag, 8984 icSigCopyrightTag, icMaxEnumType}}, 8985 8986 {icSigDisplayClass, -1, icMaxEnumData, icSigPCSData, 8987 {icSigProfileDescriptionTag, 8988 icSigGrayTRCTag, 8989 icSigMediaWhitePointTag, 8990 icSigCopyrightTag, icMaxEnumType}}, 8991 8992 {icSigDisplayClass, -3, icSigRgbData, icSigXYZData, /* Rgb or any 3 component space ?? */ 8993 {icSigProfileDescriptionTag, 8994 icSigRedColorantTag, 8995 icSigGreenColorantTag, 8996 icSigBlueColorantTag, 8997 icSigRedTRCTag, 8998 icSigGreenTRCTag, 8999 icSigBlueTRCTag, 9000 icSigMediaWhitePointTag, 9001 icSigCopyrightTag, icMaxEnumType}}, 9002 9003 /* Non-3 component Display device */ 9004 {icSigDisplayClass, -100, icMaxEnumData, icSigPCSData, 9005 {icSigProfileDescriptionTag, 9006 icSigAToB0Tag, /* BToA doesn't seem to be required, which is strange... */ 9007 icSigMediaWhitePointTag, 9008 icSigCopyrightTag, icMaxEnumType}}, 9009 9010 {icSigOutputClass, -1, icMaxEnumData, icSigPCSData, 9011 {icSigProfileDescriptionTag, 9012 icSigGrayTRCTag, 9013 icSigMediaWhitePointTag, 9014 icSigCopyrightTag, icMaxEnumType}}, 9015 9016 {icSigOutputClass, -1, icMaxEnumData, icSigPCSData, 9017 {icSigProfileDescriptionTag, 9018 icSigAToB0Tag, 9019 icSigBToA0Tag, 9020 icSigGamutTag, 9021 icSigAToB1Tag, 9022 icSigBToA1Tag, 9023 icSigAToB2Tag, 9024 icSigBToA2Tag, 9025 icSigMediaWhitePointTag, 9026 icSigCopyrightTag, icMaxEnumType}}, 9027 9028 {icSigOutputClass, -2, icMaxEnumData, icSigPCSData, 9029 {icSigProfileDescriptionTag, 9030 icSigAToB0Tag, 9031 icSigBToA0Tag, 9032 icSigGamutTag, 9033 icSigAToB1Tag, 9034 icSigBToA1Tag, 9035 icSigAToB2Tag, 9036 icSigBToA2Tag, 9037 icSigMediaWhitePointTag, 9038 icSigCopyrightTag, icMaxEnumType}}, 9039 9040 {icSigOutputClass, -3, icMaxEnumData, icSigPCSData, 9041 {icSigProfileDescriptionTag, 9042 icSigAToB0Tag, 9043 icSigBToA0Tag, 9044 icSigGamutTag, 9045 icSigAToB1Tag, 9046 icSigBToA1Tag, 9047 icSigAToB2Tag, 9048 icSigBToA2Tag, 9049 icSigMediaWhitePointTag, 9050 icSigCopyrightTag, icMaxEnumType}}, 9051 9052 {icSigOutputClass, -4, icMaxEnumData, icSigPCSData, 9053 {icSigProfileDescriptionTag, 9054 icSigAToB0Tag, 9055 icSigBToA0Tag, 9056 icSigGamutTag, 9057 icSigAToB1Tag, 9058 icSigBToA1Tag, 9059 icSigAToB2Tag, 9060 icSigBToA2Tag, 9061 icSigMediaWhitePointTag, 9062 icSigCopyrightTag, icMaxEnumType}}, 9063 9064 {icSigOutputClass, -100, icMaxEnumData, icSigPCSData, /* Assumed from Hexachrome examples */ 9065 {icSigProfileDescriptionTag, 9066 icSigBToA0Tag, 9067 icSigBToA1Tag, 9068 icSigBToA2Tag, 9069 icSigMediaWhitePointTag, 9070 icSigCopyrightTag, icMaxEnumType}}, 9071 9072 {icSigLinkClass, -100, icMaxEnumData, icMaxEnumData, 9073 {icSigProfileDescriptionTag, 9074 icSigAToB0Tag, 9075 icSigProfileSequenceDescTag, 9076 icSigCopyrightTag, icMaxEnumType}}, 9077 9078 {icSigColorSpaceClass, -100, icMaxEnumData, icSigPCSData, 9079 {icSigProfileDescriptionTag, 9080 icSigBToA0Tag, 9081 icSigAToB0Tag, 9082 icSigMediaWhitePointTag, 9083 icSigCopyrightTag, icMaxEnumType}}, 9084 9085 {icSigAbstractClass, -100, icSigPCSData, icSigPCSData, 9086 {icSigProfileDescriptionTag, 9087 icSigAToB0Tag, 9088 icSigMediaWhitePointTag, 9089 icSigCopyrightTag, icMaxEnumType}}, 9090 9091 {icSigNamedColorClass, -200, icMaxEnumData, icMaxEnumData, 9092 {icSigProfileDescriptionTag, 9093 icSigNamedColor2Tag, 9094 icSigMediaWhitePointTag, 9095 icSigCopyrightTag, icMaxEnumType}}, 9096 9097 {icSigNamedColorClass, -100, icMaxEnumData, icMaxEnumData, 9098 {icSigProfileDescriptionTag, 9099 icSigNamedColorTag, /* Not strictly V3.4 */ 9100 icSigMediaWhitePointTag, 9101 icSigCopyrightTag, icMaxEnumType}}, 9102 9103 {icMaxEnumType,-1,icMaxEnumData, icMaxEnumData, {icMaxEnumType}} 9104 }; 9105 9106 /* ------------------------------------------------------------- */ 9107 /* Check that the ICC profile looks like it will be legal. */ 9108 /* Return non-zero and set error string if not */ 9109 static int check_icc_legal( 9110 icc *p 9111 ) { 9112 int i, j; 9113 icProfileClassSignature sig; 9114 icColorSpaceSignature colsig; 9115 icColorSpaceSignature pcssig; 9116 int dchans; 9117 9118 if (p->header == NULL) { 9119 sprintf(p->err,"icc_check_legal: Header is missing"); 9120 return p->errc = 1; 9121 } 9122 9123 sig = p->header->deviceClass; 9124 colsig = p->header->colorSpace; 9125 dchans = number_ColorSpaceSignature(colsig); 9126 pcssig = p->header->pcs; 9127 9128 /* Find a matching table entry */ 9129 for (i = 0; tagchecktable[i].sig != icMaxEnumType; i++) { 9130 if ( tagchecktable[i].sig == sig 9131 && ( tagchecktable[i].chans == dchans /* Exactly matches */ 9132 || tagchecktable[i].chans == -dchans /* Exactly matches, but can try next table */ 9133 || tagchecktable[i].chans < -99) /* Doesn't have to match or try next table */ 9134 && ( tagchecktable[i].colsig == colsig 9135 || (tagchecktable[i].colsig == icSigPCSData 9136 && (colsig == icSigXYZData || colsig == icSigLabData)) 9137 || tagchecktable[i].colsig == icMaxEnumData) 9138 && ( tagchecktable[i].pcssig == pcssig 9139 || (tagchecktable[i].pcssig == icSigPCSData 9140 && (pcssig == icSigXYZData || pcssig == icSigLabData)) 9141 || tagchecktable[i].pcssig == icMaxEnumData)) { 9142 9143 /* Found entry, so now check that all the required tags are present. */ 9144 for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) { 9145 if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) { /* Not present! */ 9146 if (tagchecktable[i].chans == -200 9147 || tagchecktable[i].chans == -dchans) { /* But can try next table */ 9148 break; 9149 } 9150 sprintf(p->err,"icc_check_legal: deviceClass %s is missing required tag %s", 9151 tag2str(sig), tag2str(tagchecktable[i].tags[j])); 9152 return p->errc = 1; 9153 } 9154 } 9155 if (tagchecktable[i].tags[j] == icMaxEnumType) { 9156 break; /* Fount all required tags */ 9157 } 9158 } 9159 } 9160 9161 /* According to the spec. if the deviceClass is: 9162 an Abstract Class: both in and out color spaces should be PCS 9163 an Link Class: both in and out color spaces can be any, and should 9164 be the input space of the first profile in the link, and the 9165 input space of the last profile in the link respectively. 9166 a Named Class: in and out color spaces are not defined in the spec. 9167 Input, Display, Output and ColorSpace Classes, input color 9168 space can be any, and the output space must be PCS. 9169 ~~ should check this here ??? 9170 */ 9171 9172 return 0; /* Assume anything is ok */ 9173 } 9174 9175 9176 /* read the object, return 0 on success, error code on fail */ 9177 /* NOTE: this doesn't read the tag types, they should be read on demand. */ 9178 static int icc_read( 9179 icc *p, 9180 icmFile *fp, /* File to read from */ 9181 unsigned long of /* File offset to read from */ 9182 ) { 9183 char tcbuf[4]; /* Tag count read buffer */ 9184 int i; 9185 unsigned int len; 9186 int er = 0; /* Error code */ 9187 9188 p->fp = fp; 9189 p->of = of; 9190 if (p->header == NULL) { 9191 sprintf(p->err,"icc_read: No header defined"); 9192 return p->errc = 1; 9193 } 9194 9195 /* Read the header */ 9196 if (p->header->read(p->header, 128, of)) { 9197 return 1; 9198 } 9199 9200 /* Read the tag count */ 9201 if ( p->fp->seek(p->fp, of + 128) != 0 9202 || p->fp->read(p->fp, tcbuf, 1, 4) != 4) { 9203 sprintf(p->err,"icc_read: fseek() or fread() failed on tag count"); 9204 return p->errc = 1; 9205 } 9206 9207 p->count = read_UInt32Number(tcbuf); /* Tag count */ 9208 if (p->count > 0) { 9209 char *bp, *buf; 9210 if ((p->data = (icmTag *) p->al->malloc(p->al, p->count * sizeof(icmTag))) == NULL) { 9211 sprintf(p->err,"icc_read: Tag table malloc() failed"); 9212 return p->errc = 2; 9213 } 9214 9215 len = 4 + p->count * 12; 9216 if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) { 9217 sprintf(p->err,"icc_read: Tag table read buffer malloc() failed"); 9218 p->al->free(p->al, p->data); 9219 p->data = NULL; 9220 return p->errc = 2; 9221 } 9222 if ( p->fp->seek(p->fp, of + 128) != 0 9223 || p->fp->read(p->fp, buf, 1, len) != len) { 9224 sprintf(p->err,"icc_read: fseek() or fread() failed on tag table"); 9225 p->al->free(p->al, p->data); 9226 p->data = NULL; 9227 p->al->free(p->al, buf); 9228 return p->errc = 1; 9229 } 9230 9231 /* Fill in the tag table structure */ 9232 bp = buf+4; 9233 for (i = 0; i < p->count; i++, bp += 12) { 9234 p->data[i].sig = (icTagSignature)read_SInt32Number(bp + 0); 9235 p->data[i].offset = read_UInt32Number(bp + 4); 9236 p->data[i].size = read_UInt32Number(bp + 8); 9237 if ( p->fp->seek(p->fp, of + p->data[i].offset) != 0 9238 || p->fp->read(p->fp, tcbuf, 1, 4) != 4) { 9239 sprintf(p->err,"icc_read: fseek() or fread() failed on tag headers"); 9240 p->al->free(p->al, p->data); 9241 p->data = NULL; 9242 p->al->free(p->al, buf); 9243 return p->errc = 1; 9244 } 9245 p->data[i].ttype = read_SInt32Number(tcbuf); /* Tag type */ 9246 p->data[i].objp = NULL; /* Read on demand */ 9247 } 9248 p->al->free(p->al, buf); 9249 } /* p->count > 0 */ 9250 9251 return er; 9252 } 9253 9254 #define DO_ALIGN(val) (((val) + 3) & ~3) 9255 9256 /* Return the total size needed for the profile */ 9257 /* Return 0 on error. */ 9258 static unsigned int icc_get_size( 9259 icc *p 9260 ) { 9261 unsigned int size = 0; 9262 int i; 9263 9264 /* Check that the right tags etc. are present for a legal ICC profile */ 9265 if (check_icc_legal(p) != 0) { 9266 return 0; 9267 } 9268 9269 /* Compute the total size and tag element data offsets */ 9270 if (p->header == NULL) { 9271 sprintf(p->err,"icc_get_size: No header defined"); 9272 p->errc = 1; 9273 return 0; 9274 } 9275 9276 size += p->header->get_size(p->header); 9277 9278 size = DO_ALIGN(size); 9279 size += 4 + p->count * 12; /* Tag table length */ 9280 9281 /* Reset touched flag for each tag type */ 9282 for (i = 0; i < p->count; i++) { 9283 if (p->data[i].objp == NULL) { 9284 sprintf(p->err,"icc_get_size: Internal error - NULL tag element"); 9285 p->errc = 1; 9286 return 0; 9287 } 9288 p->data[i].objp->touched = 0; 9289 } 9290 /* Get size for each tag type, skipping links */ 9291 for (i = 0; i < p->count; i++) { 9292 if (p->data[i].objp->touched == 0) { /* Not alllowed for previously */ 9293 size = DO_ALIGN(size); 9294 size += p->data[i].objp->get_size(p->data[i].objp); 9295 p->data[i].objp->touched = 1; /* Don't account for this again */ 9296 } 9297 } 9298 9299 return size; /* Total size needed */ 9300 } 9301 9302 /* Write the contents of the object. Return 0 on sucess, error code on failure */ 9303 static int icc_write( 9304 icc *p, 9305 icmFile *fp, /* File to write to */ 9306 unsigned long of /* File offset to write to */ 9307 ) { 9308 char *bp, *buf; /* Buffer to write to */ 9309 unsigned int len; 9310 int rv = 0; 9311 int i; 9312 unsigned int size = 0; 9313 9314 /* Check that the right tags etc. are present for a legal ICC profile */ 9315 if ((rv = check_icc_legal(p)) != 0) { 9316 return rv; 9317 } 9318 9319 p->fp = fp; /* Open file pointer */ 9320 p->of = of; /* Offset of ICC profile */ 9321 9322 /* Compute the total size and tag element data offsets */ 9323 if (p->header == NULL) { 9324 sprintf(p->err,"icc_write: No header defined"); 9325 return p->errc = 1; 9326 } 9327 9328 size += p->header->get_size(p->header); 9329 9330 len = 4 + p->count * 12; /* Tag table length */ 9331 size = DO_ALIGN(size); 9332 size += len; 9333 9334 /* Allocate memory buffer for tag table */ 9335 if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) { 9336 sprintf(p->err,"icc_write malloc() failed"); 9337 return p->errc = 2; 9338 } 9339 bp = buf; 9340 9341 if ((rv = write_UInt32Number(p->count, bp)) != 0) { /* Tag count */ 9342 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag count"); 9343 p->al->free(p->al, buf); 9344 return p->errc = rv; 9345 } 9346 bp += 4; 9347 /* Reset touched flag for each tag type */ 9348 for (i = 0; i < p->count; i++) { 9349 if (p->data[i].objp == NULL) { 9350 sprintf(p->err,"icc_write: Internal error - NULL tag element"); 9351 p->al->free(p->al, buf); 9352 return p->errc = 1; 9353 } 9354 p->data[i].objp->touched = 0; 9355 } 9356 /* Set the offset and size for each tag type */ 9357 for (i = 0; i < p->count; i++) { 9358 if (p->data[i].objp->touched == 0) { /* Allocate space for tag type */ 9359 size = DO_ALIGN(size); 9360 p->data[i].offset = size; /* Profile relative target */ 9361 p->data[i].size = p->data[i].objp->get_size(p->data[i].objp); 9362 size += p->data[i].size; 9363 p->data[i].objp->touched = 1; /* Allocated space for it */ 9364 } else { /* must be linked - copy allocation */ 9365 int k; 9366 for (k = 0; k < p->count; k++) { /* Find linked tag */ 9367 if (p->data[k].objp == p->data[i].objp) 9368 break; 9369 } 9370 if (k == p->count) { 9371 sprintf(p->err,"icc_write: corrupted link"); 9372 return p->errc = 2; 9373 } 9374 p->data[i].offset = p->data[k].offset; 9375 p->data[i].size = p->data[k].size; 9376 } 9377 /* Write tag table entry for this tag */ 9378 if ((rv = write_SInt32Number((int)p->data[i].sig,bp + 0)) != 0) { 9379 sprintf(p->err,"icc_write: write_SInt32Number() failed on tag signature"); 9380 p->al->free(p->al, buf); 9381 return p->errc = rv; 9382 } 9383 if ((rv = write_UInt32Number(p->data[i].offset, bp + 4)) != 0) { 9384 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag offset"); 9385 p->al->free(p->al, buf); 9386 return p->errc = rv; 9387 } 9388 if ((rv = write_UInt32Number(p->data[i].size, bp + 8)) != 0) { 9389 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag size"); 9390 p->al->free(p->al, buf); 9391 return p->errc = rv; 9392 } 9393 bp += 12; 9394 } 9395 p->header->size = size; /* Record total icc size */ 9396 9397 /* Write the header */ 9398 if ((rv = p->header->write(p->header, of)) != 0) { 9399 p->al->free(p->al, buf); 9400 return rv; 9401 } 9402 9403 /* Write the tag table */ 9404 if ( p->fp->seek(p->fp, of + 128) != 0 9405 || p->fp->write(p->fp, buf, 1, len) != len) { 9406 sprintf(p->err,"icc_write: fseek() or fwrite() failed"); 9407 p->al->free(p->al, buf); 9408 return p->errc = 1; 9409 } 9410 p->al->free(p->al, buf); 9411 9412 /* Write all the tag element data */ 9413 for (i = 0; i < p->count; i++) { /* For all the tag element data */ 9414 if (p->data[i].objp->touched == 0) 9415 continue; /* Must be linked, and we've already written it */ 9416 if ((rv = p->data[i].objp->write(p->data[i].objp, of + p->data[i].offset)) != 0) { 9417 return rv; 9418 } 9419 p->data[i].objp->touched = 0; /* Written it */ 9420 } 9421 9422 if (p->fp->flush(p->fp) != 0) { 9423 sprintf(p->err,"icc_write flush() failed"); 9424 p->al->free(p->al, buf); 9425 return p->errc = 2; 9426 } 9427 return rv; 9428 } 9429 #undef DO_ALIGN 9430 9431 /* Create and add a tag with the given signature. */ 9432 /* Returns a pointer to the element object */ 9433 /* Returns NULL if error - icc->errc will contain */ 9434 /* 2 on system error, */ 9435 /* 3 if unknown tag */ 9436 /* NOTE: that we prevent tag duplication */ 9437 static icmBase *icc_add_tag( 9438 icc *p, 9439 icTagSignature sig, /* Tag signature - may be unknown */ 9440 icTagTypeSignature ttype /* Tag type */ 9441 ) { 9442 icmBase *tp; 9443 icmBase *nob; 9444 int i, j, ok = 1; 9445 9446 /* Check that a known signature has an acceptable type */ 9447 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) { 9448 if (sigtypetable[i].sig == sig) { /* recognized signature */ 9449 ok = 0; 9450 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) { 9451 if (sigtypetable[i].ttypes[j] == ttype) /* recognized type */ 9452 ok = 1; 9453 } 9454 break; 9455 } 9456 } 9457 if (!ok) { 9458 sprintf(p->err,"icc_add_tag: wrong tag type for signature"); 9459 p->errc = 1; 9460 return NULL; 9461 } 9462 9463 /* Check that we know how to handle this type */ 9464 for (i = 0; typetable[i].ttype != icMaxEnumType; i++) { 9465 if (typetable[i].ttype == ttype) 9466 break; 9467 } 9468 if (typetable[i].ttype == icMaxEnumType) { 9469 sprintf(p->err,"icc_add_tag: unsupported tag type"); 9470 p->errc = 1; 9471 return NULL; 9472 } 9473 9474 /* Check that this tag doesn't already exits */ 9475 /* (Perhaps we should simply replace it, rather than erroring ?) */ 9476 for (j = 0; j < p->count; j++) { 9477 if (p->data[j].sig == sig) { 9478 sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig)); 9479 p->errc = 1; 9480 return NULL; 9481 } 9482 } 9483 9484 /* Make space in tag table for new tag item */ 9485 if (p->data == NULL) 9486 tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag)); 9487 else 9488 tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag)); 9489 if (tp == NULL) { 9490 sprintf(p->err,"icc_add_tag: Tag table realloc() failed"); 9491 p->errc = 2; 9492 return NULL; 9493 } 9494 p->data = (icmTag *)tp; 9495 9496 /* Allocate the empty object */ 9497 if ((nob = typetable[i].new_obj(p)) == NULL) 9498 return NULL; 9499 9500 /* Fill out our tag table entry */ 9501 p->data[p->count].sig = sig; /* The tag signature */ 9502 p->data[p->count].ttype = nob->ttype = ttype; /* The tag type signature */ 9503 p->data[p->count].offset = 0; /* Unknown offset yet */ 9504 p->data[p->count].size = 0; /* Unknown size yet */ 9505 p->data[p->count].objp = nob; /* Empty object */ 9506 p->count++; 9507 9508 return nob; 9509 } 9510 9511 /* Create and add a tag which is a link to an existing tag. */ 9512 /* Returns a pointer to the element object */ 9513 /* Returns NULL if error - icc->errc will contain */ 9514 /* 3 if incompatible tag */ 9515 /* NOTE: that we prevent tag duplication */ 9516 static icmBase *icc_link_tag( 9517 icc *p, 9518 icTagSignature sig, /* Tag signature - may be unknown */ 9519 icTagSignature ex_sig /* Tag signature of tag to link to */ 9520 ) { 9521 icmBase *tp; 9522 int i, j, exi, ok = 1; 9523 9524 /* Search for existing signature */ 9525 for (exi = 0; exi < p->count; exi++) { 9526 if (p->data[exi].sig == ex_sig) /* Found it */ 9527 break; 9528 } 9529 if (exi == p->count) { 9530 sprintf(p->err,"icc_link_tag: Can't find existing tag '%s'",tag2str(ex_sig)); 9531 p->errc = 1; 9532 return NULL; 9533 } 9534 9535 if (p->data[exi].objp == NULL) { 9536 sprintf(p->err,"icc_link_tag: Existing tag '%s' isn't loaded",tag2str(ex_sig)); 9537 p->errc = 1; 9538 return NULL; 9539 } 9540 9541 /* Check that a known signature has an acceptable type */ 9542 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) { 9543 if (sigtypetable[i].sig == sig) { /* recognized signature */ 9544 ok = 0; 9545 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) { 9546 if (sigtypetable[i].ttypes[j] == p->data[exi].ttype) /* recognized type */ 9547 ok = 1; 9548 } 9549 break; 9550 } 9551 } 9552 if (!ok) { 9553 sprintf(p->err,"icc_link_tag: wrong tag type for signature"); 9554 p->errc = 1; 9555 return NULL; 9556 } 9557 9558 /* Check that this tag doesn't already exits */ 9559 for (j = 0; j < p->count; j++) { 9560 if (p->data[j].sig == sig) { 9561 sprintf(p->err,"icc_link_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig)); 9562 p->errc = 1; 9563 return NULL; 9564 } 9565 } 9566 9567 /* Make space in tag table for new tag item */ 9568 if (p->data == NULL) 9569 tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag)); 9570 else 9571 tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag)); 9572 if (tp == NULL) { 9573 sprintf(p->err,"icc_link_tag: Tag table realloc() failed"); 9574 p->errc = 2; 9575 return NULL; 9576 } 9577 p->data = (icmTag *)tp; 9578 9579 /* Fill out our tag table entry */ 9580 p->data[p->count].sig = sig; /* The tag signature */ 9581 p->data[p->count].ttype = p->data[exi].ttype; /* The tag type signature */ 9582 p->data[p->count].offset = p->data[exi].offset; /* Same offset (may not be allocated yet) */ 9583 p->data[p->count].size = p->data[exi].size; /* Same size (may not be allocated yet) */ 9584 p->data[p->count].objp = p->data[exi].objp; /* Shared object */ 9585 p->data[exi].objp->refcount++; /* Bump reference count on tag type */ 9586 p->count++; 9587 9588 return p->data[exi].objp; 9589 } 9590 9591 /* Search for tag signature */ 9592 /* return: */ 9593 /* 0 if found */ 9594 /* 1 if found but not handled type */ 9595 /* 2 if not found */ 9596 /* NOTE: doesn't set icc->errc or icc->err[] */ 9597 /* NOTE: we don't handle tag duplication - you'll always get the first in the file. */ 9598 static int icc_find_tag( 9599 icc *p, 9600 icTagSignature sig /* Tag signature - may be unknown */ 9601 ) { 9602 int i,j; 9603 9604 /* Search for signature */ 9605 for (i = 0; i < p->count; i++) { 9606 if (p->data[i].sig == sig) /* Found it */ 9607 break; 9608 } 9609 if (i == p->count) 9610 return 2; 9611 9612 /* See if we can handle this type */ 9613 for (j = 0; typetable[j].ttype != icMaxEnumType; j++) { 9614 if (typetable[j].ttype == p->data[i].ttype) 9615 break; 9616 } 9617 if (typetable[j].ttype == icMaxEnumType) 9618 return 1; 9619 9620 return 0; 9621 } 9622 9623 /* Read the tag element data, and return a pointer to the object */ 9624 /* Returns NULL if error - icc->errc will contain 9625 /* 1 if found but not handled type */ 9626 /* 2 if not found */ 9627 /* NOTE: we don't handle tag duplication - you'll always get the first in the file */ 9628 static icmBase *icc_read_tag( 9629 icc *p, 9630 icTagSignature sig /* Tag signature - may be unknown */ 9631 ) { 9632 icmBase *nob; 9633 int i,j,k; 9634 9635 /* Search for signature */ 9636 for (i = 0; i < p->count; i++) { 9637 if (p->data[i].sig == sig) /* Found it */ 9638 break; 9639 } 9640 if (i >= p->count) { 9641 sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig)); 9642 p->errc = 2; 9643 return NULL; 9644 } 9645 9646 /* See if it's already been read */ 9647 if (p->data[i].objp != NULL) { 9648 return p->data[i].objp; /* Just return it */ 9649 } 9650 9651 /* See if this should be a link */ 9652 for (k = 0; k < p->count; k++) { 9653 if (i == k) 9654 continue; 9655 if (p->data[i].ttype == p->data[k].ttype /* Exact match and already read */ 9656 && p->data[i].offset == p->data[k].offset 9657 && p->data[i].size == p->data[k].size 9658 && p->data[k].objp != NULL) 9659 break; 9660 } 9661 if (k < p->count) { /* Make this a link */ 9662 p->data[i].objp = p->data[k].objp; 9663 p->data[k].objp->refcount++; /* Bump reference count */ 9664 return p->data[k].objp; /* Done */ 9665 } 9666 9667 /* See if we can handle this type */ 9668 for (j = 0; typetable[j].ttype != icMaxEnumType; j++) { 9669 if (typetable[j].ttype == p->data[i].ttype) 9670 break; 9671 } 9672 if (typetable[j].ttype == icMaxEnumType) { 9673 sprintf(p->err,"icc_read_tag: Unhandled tag type '%s'",string_TypeSignature(p->data[i].ttype)); 9674 p->errc = 1; 9675 return NULL; 9676 } 9677 9678 /* Creat and read in the object */ 9679 if ((nob = typetable[j].new_obj(p)) == NULL) 9680 return NULL; 9681 if ((nob->read(nob, p->data[i].size, p->of + p->data[i].offset)) != 0) { 9682 nob->del(nob); /* Failed, so destroy it */ 9683 return NULL; 9684 } 9685 p->data[i].objp = nob; 9686 return nob; 9687 } 9688 9689 /* Rename a tag signature */ 9690 static int icc_rename_tag( 9691 icc *p, 9692 icTagSignature sig, /* Existing Tag signature - may be unknown */ 9693 icTagSignature sigNew /* New Tag signature - may be unknown */ 9694 ) { 9695 int rv; 9696 icmBase *nob; 9697 int i, j, k, ok = 1; 9698 9699 /* Search for signature */ 9700 for (k = 0; k < p->count; k++) { 9701 if (p->data[k].sig == sig) /* Found it */ 9702 break; 9703 } 9704 if (k >= p->count) { 9705 sprintf(p->err,"icc_rename_tag: Tag '%s' not found",string_TagSignature(sig)); 9706 return p->errc = 2; 9707 } 9708 9709 /* Check that a known new signature has an acceptable type */ 9710 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) { 9711 if (sigtypetable[i].sig == sigNew) { /* recognized signature */ 9712 ok = 0; 9713 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) { 9714 if (sigtypetable[i].ttypes[j] == p->data[k].ttype) /* recognized type */ 9715 ok = 1; 9716 } 9717 break; 9718 } 9719 } 9720 9721 if (!ok) { 9722 sprintf(p->err,"icc_rename_tag: wrong signature for tag type"); 9723 p->errc = 1; 9724 return p->errc; 9725 } 9726 9727 /* change its signature */ 9728 p->data[k].sig = sigNew; 9729 9730 return 0; 9731 } 9732 9733 /* Unread the tag, and free the underlying tag type */ 9734 /* if this was the last reference to it. */ 9735 /* Returns non-zero on error: */ 9736 /* tag not found - icc->errc will contain 2 */ 9737 /* tag not read - icc->errc will contain 2 */ 9738 static int icc_unread_tag( 9739 icc *p, 9740 icTagSignature sig /* Tag signature - may be unknown */ 9741 ) { 9742 int rv; 9743 icmBase *nob; 9744 int i; 9745 9746 /* Search for signature */ 9747 for (i = 0; i < p->count; i++) { 9748 if (p->data[i].sig == sig) /* Found it */ 9749 break; 9750 } 9751 if (i >= p->count) { 9752 sprintf(p->err,"icc_unread_tag: Tag '%s' not found",string_TagSignature(sig)); 9753 return p->errc = 2; 9754 } 9755 9756 /* See if it's been read */ 9757 if (p->data[i].objp == NULL) { 9758 sprintf(p->err,"icc_unread_tag: Tag '%s' not currently loaded",string_TagSignature(sig)); 9759 return p->errc = 2; 9760 } 9761 9762 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */ 9763 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */ 9764 p->data[i].objp = NULL; 9765 9766 return 0; 9767 } 9768 9769 /* Delete the tag, and free the underlying tag type */ 9770 /* if this was the last reference to it. */ 9771 /* Returns non-zero on error: */ 9772 /* tag not found - icc->errc will contain 2 */ 9773 static int icc_delete_tag( 9774 icc *p, 9775 icTagSignature sig /* Tag signature - may be unknown */ 9776 ) { 9777 int rv; 9778 icmBase *nob; 9779 int i; 9780 9781 /* Search for signature */ 9782 for (i = 0; i < p->count; i++) { 9783 if (p->data[i].sig == sig) /* Found it */ 9784 break; 9785 } 9786 if (i >= p->count) { 9787 sprintf(p->err,"icc_delete_tag: Tag '%s' not found",string_TagSignature(sig)); 9788 return p->errc = 2; 9789 } 9790 9791 /* If it's been read into memory, decrement the reference count */ 9792 if (p->data[i].objp != NULL) { 9793 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */ 9794 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */ 9795 p->data[i].objp = NULL; 9796 } 9797 9798 /* Now remove it from the tag list */ 9799 for (; i < (p->count-1); i++) 9800 p->data[i] = p->data[i+1]; /* Copy the structure down */ 9801 9802 p->count--; /* One less tag in list */ 9803 9804 return 0; 9805 } 9806 9807 9808 /* Read all the tags into memory. */ 9809 /* Returns non-zero on error. */ 9810 static int icc_read_all_tags( 9811 icc *p 9812 ) { 9813 int i; 9814 9815 for (i = 0; i < p->count; i++) { /* For all the tag element data */ 9816 icmBase *ob; 9817 if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) { 9818 return p->errc; 9819 } 9820 } 9821 return 0; 9822 } 9823 9824 9825 static void icc_dump( 9826 icc *p, 9827 FILE *op, /* Output to dump to */ 9828 int verb /* Verbosity level */ 9829 ) { 9830 int i; 9831 if (verb <= 0) 9832 return; 9833 9834 fprintf(op,"icc:\n"); 9835 9836 /* Dump the header */ 9837 if (p->header != NULL) 9838 p->header->dump(p->header,op,verb); 9839 9840 /* Dump all the tag elements */ 9841 for (i = 0; i < p->count; i++) { /* For all the tag element data */ 9842 icmBase *ob; 9843 int tr; 9844 fprintf(op,"tag %d:\n",i); 9845 fprintf(op," sig %s\n",tag2str(p->data[i].sig)); 9846 fprintf(op," type %s\n",tag2str(p->data[i].ttype)); 9847 fprintf(op," offset %d\n", p->data[i].offset); 9848 fprintf(op," size %d\n", p->data[i].size); 9849 tr = 0; 9850 if ((ob = p->data[i].objp) == NULL) { 9851 /* The object is not loaded, so load it then free it */ 9852 if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) { 9853 fprintf(op,"Unable to read: %d, %s\n",p->errc,p->err); 9854 } 9855 tr = 1; 9856 } 9857 if (ob != NULL) { 9858 /* fprintf(op," refcount %d\n", ob->refcount); */ 9859 ob->dump(ob,op,verb-1); 9860 9861 if (tr != 0) { /* Cleanup if temporary */ 9862 ob->refcount--; 9863 (ob->del)(ob); 9864 p->data[i].objp = NULL; 9865 } 9866 } 9867 fprintf(op,"\n"); 9868 } 9869 } 9870 9871 static void icc_delete( 9872 icc *p 9873 ) { 9874 int i; 9875 icmAlloc *al = p->al; 9876 int del_al = p->del_al; 9877 9878 /* Free up the header */ 9879 if (p->header != NULL) 9880 (p->header->del)(p->header); 9881 9882 /* Free up the tag data objects */ 9883 for (i = 0; i < p->count; i++) { 9884 if (p->data[i].objp != NULL) { 9885 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */ 9886 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */ 9887 p->data[i].objp = NULL; 9888 } 9889 } 9890 9891 /* Free tag table */ 9892 al->free(al, p->data); 9893 9894 /* This object */ 9895 al->free(al, p); 9896 9897 if (del_al) /* We are responsible for deleting allocator */ 9898 al->del(al); 9899 } 9900 9901 /* ================================================== */ 9902 /* Lut Color normalizing and de-normalizing functions */ 9903 9904 /* As a rule, I am representing Lut in memory as values in machine form as real */ 9905 /* numbers in the range 0.0 - 1.0. For many color spaces (ie. RGB, Gray, */ 9906 /* hsv, hls, cmyk and other device coords), this is entirely appropriate. */ 9907 /* For the PCS though, this is not correct, since (I assume!) the binary */ 9908 /* representation will be consistent with the encoding in Annex A, page 74 */ 9909 /* of the standard. Note that the standard doesn't specify the encoding of */ 9910 /* many color spaces (ie. Yuv, Yxy etc.), and is unclear about PCS. */ 9911 9912 /* The following functions convert to and from the PCS spaces (XYZ or Lab) */ 9913 /* and the real Lut input/output values. These are used to convert real color */ 9914 /* space values into/out of the raw lut 0.0-1.0 representation. */ 9915 9916 /* This is used internally to support the Lut->lookup() function, */ 9917 /* and can also be used by someone writing a Lut based profile to determine */ 9918 /* the colorspace range that the input lut indexes cover, as well */ 9919 /* as processing the output luts values into normalized form ready */ 9920 /* for writing. */ 9921 9922 /* These functions should be accessed by calling icc.getNormFuncs() */ 9923 9924 /* - - - - - - - - - - - - - - - - */ 9925 /* According to 6.5.5 and 6.5.6 of the spec., */ 9926 /* XYZ index values are represented the same as their table */ 9927 /* values, ie. as a u1.15 representation, with a value */ 9928 /* range from 0.0 -> 1.999969482422 */ 9929 9930 /* Convert Lut index/value to XYZ coord. */ 9931 static void Lut_Lut2XYZ(double *out, double *in) { 9932 out[0] = in[0] * (1.0 + 32767.0/32768); /* X */ 9933 out[1] = in[1] * (1.0 + 32767.0/32768); /* Y */ 9934 out[2] = in[2] * (1.0 + 32767.0/32768); /* Z */ 9935 } 9936 9937 /* Convert XYZ coord to Lut index/value. */ 9938 static void Lut_XYZ2Lut(double *out, double *in) { 9939 out[0] = in[0] * (1.0/(1.0 + 32767.0/32768)); 9940 out[1] = in[1] * (1.0/(1.0 + 32767.0/32768)); 9941 out[2] = in[2] * (1.0/(1.0 + 32767.0/32768)); 9942 } 9943 9944 /* - - - - - - - - - - - - - - - - */ 9945 /* Convert Lab to Lut numbers */ 9946 /* Annex A specifies 8 and 16 bit encoding, but is */ 9947 /* silent on the Lut index normalization. */ 9948 /* Following Michael Bourgoin's 1998 SIGGRAPH course comment on this, */ 9949 /* we assume here that the index encoding is the same as the */ 9950 /* value encoding. */ 9951 9952 /* Convert Lut16 table index/value to Lab */ 9953 static void Lut_Lut2Lab16(double *out, double *in) { 9954 out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */ 9955 out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0; /* a */ 9956 out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0; /* b */ 9957 } 9958 9959 /* Convert Lab to Lut16 table index/value */ 9960 static void Lut_Lab2Lut16(double *out, double *in) { 9961 out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */ 9962 out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0); /* a */ 9963 out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0); /* b */ 9964 } 9965 9966 /* Convert Lut8 table index/value to Lab */ 9967 static void Lut_Lut2Lab8(double *out, double *in) { 9968 out[0] = in[0] * 100.0; /* L */ 9969 out[1] = (in[1] * 255.0) - 128.0; /* a */ 9970 out[2] = (in[2] * 255.0) - 128.0; /* b */ 9971 } 9972 9973 /* Convert Lab to Lut8 table index/value */ 9974 static void Lut_Lab2Lut8(double *out, double *in) { 9975 out[0] = in[0] * 1.0/100.0; /* L */ 9976 out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */ 9977 out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */ 9978 } 9979 9980 /* - - - - - - - - - - - - - - - - */ 9981 /* Convert Luv to Lut number */ 9982 /* This data normalization is taken from Apples */ 9983 /* Colorsync specification. */ 9984 /* As per other color spaces, we assume that the index */ 9985 /* normalization is the same as the data normalization. */ 9986 9987 /* Convert Lut table index/value to Luv */ 9988 static void Lut_Lut2Luv(double *out, double *in) { 9989 out[0] = in[0] * 100.0; /* L */ 9990 out[1] = (in[1] * 65535.0/256.0) - 128.0; /* u */ 9991 out[2] = (in[2] * 65535.0/256.0) - 128.0; /* v */ 9992 } 9993 9994 /* Convert Luv to Lut table index/value */ 9995 static void Lut_Luv2Lut(double *out, double *in) { 9996 out[0] = in[0] * 1.0/100.0; /* L */ 9997 out[1] = (in[1] + 128.0) * 256.0/65535.0; /* u */ 9998 out[2] = (in[2] + 128.0) * 256.0/65535.0; /* v */ 9999 } 10000 10001 /* - - - - - - - - - - - - - - - - */ 10002 /* Default N component conversions */ 10003 static void Lut_N(double *out, double *in, int nc) { 10004 for (--nc; nc >= 0; nc--) 10005 out[nc] = in[nc]; 10006 } 10007 10008 /* 1 */ 10009 static void Lut_1(double *out, double *in) { 10010 out[0] = in[0]; 10011 } 10012 10013 /* 2 */ 10014 static void Lut_2(double *out, double *in) { 10015 out[0] = in[0]; 10016 out[1] = in[1]; 10017 } 10018 10019 /* 3 */ 10020 static void Lut_3(double *out, double *in) { 10021 out[0] = in[0]; 10022 out[1] = in[1]; 10023 out[2] = in[2]; 10024 } 10025 10026 /* 4 */ 10027 static void Lut_4(double *out, double *in) { 10028 out[0] = in[0]; 10029 out[1] = in[1]; 10030 out[2] = in[2]; 10031 out[3] = in[3]; 10032 } 10033 10034 /* 5 */ 10035 static void Lut_5(double *out, double *in) { 10036 out[0] = in[0]; 10037 out[1] = in[1]; 10038 out[2] = in[2]; 10039 out[3] = in[3]; 10040 out[4] = in[4]; 10041 } 10042 10043 /* 6 */ 10044 static void Lut_6(double *out, double *in) { 10045 out[0] = in[0]; 10046 out[1] = in[1]; 10047 out[2] = in[2]; 10048 out[3] = in[3]; 10049 out[4] = in[4]; 10050 out[5] = in[5]; 10051 } 10052 10053 /* 7 */ 10054 static void Lut_7(double *out, double *in) { 10055 Lut_N(out, in, 7); 10056 } 10057 10058 /* 8 */ 10059 static void Lut_8(double *out, double *in) { 10060 Lut_N(out, in, 8); 10061 } 10062 10063 /* 9 */ 10064 static void Lut_9(double *out, double *in) { 10065 Lut_N(out, in, 9); 10066 } 10067 10068 /* 10 */ 10069 static void Lut_10(double *out, double *in) { 10070 Lut_N(out, in, 10); 10071 } 10072 10073 /* 11 */ 10074 static void Lut_11(double *out, double *in) { 10075 Lut_N(out, in, 11); 10076 } 10077 10078 /* 12 */ 10079 static void Lut_12(double *out, double *in) { 10080 Lut_N(out, in, 12); 10081 } 10082 10083 /* 13 */ 10084 static void Lut_13(double *out, double *in) { 10085 Lut_N(out, in, 13); 10086 } 10087 10088 /* 14 */ 10089 static void Lut_14(double *out, double *in) { 10090 Lut_N(out, in, 14); 10091 } 10092 10093 /* 15 */ 10094 static void Lut_15(double *out, double *in) { 10095 Lut_N(out, in, 15); 10096 } 10097 10098 /* Function table - match conversions to color spaces. */ 10099 /* Anything not here, we don't know how to convert. */ 10100 /* (ie. YCbCr) */ 10101 static struct { 10102 icColorSpaceSignature csig; 10103 void (*fromLut8)(double *out, double *in); /* 8 bit from Lut index/entry */ 10104 void (*fromLut16)(double *out, double *in); /* 16 bit from Lut index/entry */ 10105 void (*toLut8)(double *out, double *in); /* 8 bit to Lut index/entry */ 10106 void (*toLut16)(double *out, double *in); /* 16 bit to Lut index/entry */ 10107 } colnormtable[] = { 10108 {icSigXYZData, NULL, Lut_Lut2XYZ, NULL, Lut_XYZ2Lut }, 10109 {icSigLabData, Lut_Lut2Lab8, Lut_Lut2Lab16, Lut_Lab2Lut8, Lut_Lab2Lut16 }, 10110 {icSigLuvData, Lut_Lut2Luv, Lut_Lut2Luv, Lut_Luv2Lut, Lut_Luv2Lut }, 10111 {icSigYxyData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10112 {icSigRgbData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10113 {icSigGrayData, Lut_1, Lut_1, Lut_1, Lut_1 }, 10114 {icSigHsvData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10115 {icSigHlsData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10116 {icSigCmykData, Lut_4, Lut_4, Lut_4, Lut_4 }, 10117 {icSigCmyData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10118 {icSigMch6Data, Lut_6, Lut_6, Lut_6, Lut_6 }, 10119 {icSig2colorData, Lut_2, Lut_2, Lut_2, Lut_2 }, 10120 {icSig3colorData, Lut_3, Lut_3, Lut_3, Lut_3 }, 10121 {icSig4colorData, Lut_4, Lut_4, Lut_4, Lut_4 }, 10122 {icSig5colorData, Lut_5, Lut_5, Lut_5, Lut_5 }, 10123 {icSig6colorData, Lut_6, Lut_6, Lut_6, Lut_6 }, 10124 {icSig7colorData, Lut_7, Lut_7, Lut_7, Lut_7 }, 10125 {icSig8colorData, Lut_8, Lut_8, Lut_8, Lut_8 }, 10126 {icSig9colorData, Lut_9, Lut_9, Lut_9, Lut_9 }, 10127 {icSig10colorData, Lut_10, Lut_10, Lut_10, Lut_10 }, 10128 {icSig11colorData, Lut_11, Lut_11, Lut_11, Lut_11 }, 10129 {icSig12colorData, Lut_12, Lut_12, Lut_12, Lut_12 }, 10130 {icSig13colorData, Lut_13, Lut_13, Lut_13, Lut_13 }, 10131 {icSig14colorData, Lut_14, Lut_14, Lut_14, Lut_14 }, 10132 {icSig15colorData, Lut_15, Lut_15, Lut_15, Lut_15 }, 10133 {icMaxEnumData, NULL, NULL, NULL, NULL } 10134 }; 10135 10136 /* Find appropriate conversion functions */ 10137 /* given the color space and Lut type */ 10138 /* Return 0 on success, 1 on match failure */ 10139 /* NOTE: doesn't set error value, message etc.! */ 10140 static int getNormFunc( 10141 icColorSpaceSignature csig, 10142 icTagTypeSignature tagSig, 10143 icmNormFlag flag, 10144 void (**nfunc)(double *out, double *in) 10145 ) { 10146 int i; 10147 for (i = 0; colnormtable[i].csig != icMaxEnumData; i++) { 10148 if (colnormtable[i].csig == csig) 10149 break; /* Found it */ 10150 } 10151 if (colnormtable[i].csig == icMaxEnumData) { /* Oops */ 10152 *nfunc = NULL; 10153 return 1; 10154 } 10155 10156 if (flag == icmFromLuti || flag == icmFromLutv) { /* Table index/value decoding functions */ 10157 if (tagSig == icSigLut8Type) { 10158 *nfunc = colnormtable[i].fromLut8; 10159 return 0; 10160 } else if (tagSig == icSigLut16Type) { 10161 *nfunc = colnormtable[i].fromLut16; 10162 return 0; 10163 } else { 10164 *nfunc = NULL; 10165 return 1; 10166 } 10167 } else if (flag == icmToLuti || flag == icmToLutv) { /* Table index/value encoding functions */ 10168 if (tagSig == icSigLut8Type) { 10169 *nfunc = colnormtable[i].toLut8; 10170 return 0; 10171 } else if (tagSig == icSigLut16Type) { 10172 *nfunc = colnormtable[i].toLut16; 10173 return 0; 10174 } else { 10175 *nfunc = NULL; 10176 return 1; 10177 } 10178 } else { 10179 *nfunc = NULL; 10180 return 1; 10181 } 10182 return 0; 10183 } 10184 10185 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10186 10187 /* 10188 Matrix Inversion 10189 by Richard Carling 10190 from "Graphics Gems", Academic Press, 1990 10191 */ 10192 10193 /* 10194 * adjoint( original_matrix, inverse_matrix ) 10195 * 10196 * calculate the adjoint of a 3x3 matrix 10197 * 10198 * Let a denote the minor determinant of matrix A obtained by 10199 * ij 10200 * 10201 * deleting the ith row and jth column from A. 10202 * 10203 * i+j 10204 * Let b = (-1) a 10205 * ij ji 10206 * 10207 * The matrix B = (b ) is the adjoint of A 10208 * ij 10209 */ 10210 10211 #define det2x2(a, b, c, d) (a * d - b * c) 10212 10213 void adjoint( 10214 double out[3][3], 10215 double in[3][3] 10216 ) { 10217 double a1, a2, a3, b1, b2, b3, c1, c2, c3; 10218 10219 /* assign to individual variable names to aid */ 10220 /* selecting correct values */ 10221 10222 a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2]; 10223 a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2]; 10224 a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2]; 10225 10226 /* row column labeling reversed since we transpose rows & columns */ 10227 10228 out[0][0] = det2x2(b2, b3, c2, c3); 10229 out[1][0] = - det2x2(a2, a3, c2, c3); 10230 out[2][0] = det2x2(a2, a3, b2, b3); 10231 10232 out[0][1] = - det2x2(b1, b3, c1, c3); 10233 out[1][1] = det2x2(a1, a3, c1, c3); 10234 out[2][1] = - det2x2(a1, a3, b1, b3); 10235 10236 out[0][2] = det2x2(b1, b2, c1, c2); 10237 out[1][2] = - det2x2(a1, a2, c1, c2); 10238 out[2][2] = det2x2(a1, a2, b1, b2); 10239 } 10240 10241 /* 10242 * double = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 ) 10243 * 10244 * calculate the determinant of a 3x3 matrix 10245 * in the form 10246 * 10247 * | a1, b1, c1 | 10248 * | a2, b2, c2 | 10249 * | a3, b3, c3 | 10250 */ 10251 10252 double det3x3(double in[3][3]) { 10253 double a1, a2, a3, b1, b2, b3, c1, c2, c3; 10254 double ans; 10255 10256 a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2]; 10257 a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2]; 10258 a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2]; 10259 10260 ans = a1 * det2x2(b2, b3, c2, c3) 10261 - b1 * det2x2(a2, a3, c2, c3) 10262 + c1 * det2x2(a2, a3, b2, b3); 10263 return ans; 10264 } 10265 10266 #define SMALL_NUMBER 1.e-8 10267 /* 10268 * inverse( original_matrix, inverse_matrix ) 10269 * 10270 * calculate the inverse of a 4x4 matrix 10271 * 10272 * -1 10273 * A = ___1__ adjoint A 10274 * det A 10275 */ 10276 10277 /* Return non-zero if not invertable */ 10278 int inverse3x3( 10279 double out[3][3], 10280 double in[3][3] 10281 ) { 10282 int i, j; 10283 double det; 10284 10285 /* calculate the 3x3 determinant 10286 * if the determinant is zero, 10287 * then the inverse matrix is not unique. 10288 */ 10289 det = det3x3(in); 10290 10291 if ( fabs(det) < SMALL_NUMBER) 10292 return 1; 10293 10294 /* calculate the adjoint matrix */ 10295 adjoint(out, in); 10296 10297 /* scale the adjoint matrix to get the inverse */ 10298 for (i = 0; i < 3; i++) 10299 for(j = 0; j < 3; j++) 10300 out[i][j] /= det; 10301 return 0; 10302 } 10303 10304 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10305 10306 /* Multuply XYZ array by 3x3 transform matrix */ 10307 static void icmMulBy3x3(double out[3], double mat[3][3], double in[3]) { 10308 double tt[3]; 10309 10310 tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2]; 10311 tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2]; 10312 tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2]; 10313 10314 out[0] = tt[0]; 10315 out[1] = tt[1]; 10316 out[2] = tt[2]; 10317 } 10318 10319 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10320 /* CIE XYZ to perceptual Lab */ 10321 void 10322 icmXYZ2Lab(icmXYZNumber *w, double *out, double *in) { 10323 double X = in[0], Y = in[1], Z = in[2]; 10324 double x,y,z,fx,fy,fz; 10325 double L; 10326 10327 x = X/w->X; 10328 if (x > 0.008856451586) 10329 fx = pow(x,1.0/3.0); 10330 else 10331 fx = 7.787036979 * x + 16.0/116.0; 10332 10333 y = Y/w->Y; 10334 if (y > 0.008856451586) { 10335 fy = pow(y,1.0/3.0); 10336 L = 116.0 * fy - 16.0; 10337 } else { 10338 fy = 7.787036979 * y + 16.0/116.0; 10339 L = 903.2963058 * y; 10340 } 10341 10342 z = Z/w->Z; 10343 if (z > 0.008856451586) 10344 fz = pow(z,1.0/3.0); 10345 else 10346 fz = 7.787036979 * z + 16.0/116.0; 10347 10348 out[0] = L; 10349 out[1] = 500.0 * (fx - fy); 10350 out[2] = 200.0 * (fy - fz); 10351 } 10352 10353 /* Perceptual Lab to CIE XYZ */ 10354 void 10355 icmLab2XYZ(icmXYZNumber *w, double *out, double *in) { 10356 double L = in[0], a = in[1], b = in[2]; 10357 double x,y,z,fx,fy,fz; 10358 10359 if (L > 8.0) { 10360 fy = (L + 16.0)/116.0; 10361 y = pow(fy,3.0); 10362 } else { 10363 y = L/903.2963058; 10364 fy = 7.787036979 * y + 16.0/116.0; 10365 } 10366 10367 fx = a/500.0 + fy; 10368 if (fx > 24.0/116.0) 10369 x = pow(fx,3.0); 10370 else 10371 x = (fx - 16.0/116.0)/7.787036979; 10372 10373 fz = fy - b/200.0; 10374 if (fz > 24.0/116.0) 10375 z = pow(fz,3.0); 10376 else 10377 z = (fz - 16.0/116.0)/7.787036979; 10378 10379 out[0] = x * w->X; 10380 out[1] = y * w->Y; 10381 out[2] = z * w->Z; 10382 } 10383 10384 /* available D50 Illuminant */ 10385 icmXYZNumber icmD50 = { /* Profile illuminant - D50 */ 10386 0.9642, 1.0000, 0.8249 10387 }; 10388 10389 /* Default black point */ 10390 icmXYZNumber icmBlack = { 10391 0.0000, 0.0000, 0.0000 10392 }; 10393 10394 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10395 10396 /* Multiply one 3x3 with another */ 10397 static void mul3x3(double dst[3][3], double src[3][3]) { 10398 int i, j, k; 10399 double td[3][3]; /* Temporary dest */ 10400 10401 for (j = 0; j < 3; j++) { 10402 for (i = 0; i < 3; i++) { 10403 double tt = 0.0; 10404 for (k = 0; k < 3; k++) 10405 tt += src[j][k] * dst[k][i]; 10406 td[j][i] = tt; 10407 } 10408 } 10409 10410 /* Copy result out */ 10411 for (j = 0; j < 3; j++) 10412 for (i = 0; i < 3; i++) 10413 dst[j][i] = td[j][i]; 10414 } 10415 10416 /* Chrmatic Adaption transform utility */ 10417 /* Return a 3x3 chromatic adaption matrix */ 10418 void icmChromAdaptMatrix( 10419 int flags, 10420 icmXYZNumber d_wp, /* Destination white point */ 10421 icmXYZNumber s_wp, /* Source white point */ 10422 double mat[3][3] /* Destination matrix */ 10423 ) { 10424 double dst[3], src[3]; /* Source & destination white points */ 10425 double vkmat[3][3]; /* Von Kries matrix */ 10426 double bradford[3][3] = { /* Bradford cone space matrix */ 10427 { 0.8951, 0.2664, -0.1614 }, 10428 { -0.7502, 1.7135, 0.0367 }, 10429 { 0.0389, -0.0685, 1.0296 } 10430 }; 10431 double ibradford[3][3]; /* Inverse Bradford */ 10432 10433 /* Set initial matrix to unity */ 10434 if (!(flags & ICM_CAM_MULMATRIX)) { 10435 mat[0][0] = mat[1][1] = mat[2][2] = 1.0; 10436 mat[0][1] = mat[0][2] = 0.0; 10437 mat[1][0] = mat[1][2] = 0.0; 10438 mat[2][0] = mat[2][1] = 0.0; 10439 } 10440 10441 icmXYZ2Ary(src, s_wp); 10442 icmXYZ2Ary(dst, d_wp); 10443 10444 if (flags & ICM_CAM_BRADFORD) { 10445 icmMulBy3x3(src, bradford, src); 10446 icmMulBy3x3(dst, bradford, dst); 10447 } 10448 10449 /* Setup the Von Kries white point adaption matrix */ 10450 vkmat[0][0] = dst[0]/src[0]; 10451 vkmat[1][1] = dst[1]/src[1]; 10452 vkmat[2][2] = dst[2]/src[2]; 10453 vkmat[0][1] = vkmat[0][2] = 0.0; 10454 vkmat[1][0] = vkmat[1][2] = 0.0; 10455 vkmat[2][0] = vkmat[2][1] = 0.0; 10456 10457 /* Transform to Bradford space if requested */ 10458 if (flags & ICM_CAM_BRADFORD) { 10459 mul3x3(mat, bradford); 10460 } 10461 10462 /* Apply chromatic adaption */ 10463 mul3x3(mat, vkmat); 10464 10465 /* Transform from Bradford space */ 10466 if (flags & ICM_CAM_BRADFORD) { 10467 inverse3x3(ibradford, bradford); 10468 mul3x3(mat, ibradford); 10469 } 10470 10471 /* We're done */ 10472 } 10473 10474 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10475 10476 /* Return information about the native lut in/out colorspaces. */ 10477 /* Any pointer may be NULL if value is not to be returned */ 10478 static void 10479 icmLutSpaces( 10480 struct _icmLuBase *p, /* This */ 10481 icColorSpaceSignature *ins, /* Return Native input color space */ 10482 int *inn, /* Return number of input components */ 10483 icColorSpaceSignature *outs, /* Return Native output color space */ 10484 int *outn /* Return number of output components */ 10485 ) { 10486 if (ins != NULL) 10487 *ins = p->inSpace; 10488 if (inn != NULL) 10489 *inn = (int)number_ColorSpaceSignature(p->inSpace); 10490 10491 if (outs != NULL) 10492 *outs = p->outSpace; 10493 if (outn != NULL) 10494 *outn = (int)number_ColorSpaceSignature(p->outSpace); 10495 } 10496 10497 /* Return information about the effective lookup in/out colorspaces, */ 10498 /* including allowance for PCS overide. */ 10499 /* Any pointer may be NULL if value is not to be returned */ 10500 static void 10501 icmLuSpaces( 10502 struct _icmLuBase *p, /* This */ 10503 icColorSpaceSignature *ins, /* Return effective input color space */ 10504 int *inn, /* Return number of input components */ 10505 icColorSpaceSignature *outs, /* Return effective output color space */ 10506 int *outn, /* Return number of output components */ 10507 icmLuAlgType *alg, /* Return type of lookup algorithm used */ 10508 icRenderingIntent *intt, /* Return the intent being implented */ 10509 icmLookupFunc *fnc, /* Return the profile function being implimented */ 10510 icColorSpaceSignature *pcs /* Return the profile effective PCS */ 10511 ) { 10512 if (ins != NULL) 10513 *ins = p->e_inSpace; 10514 if (inn != NULL) 10515 *inn = (int)number_ColorSpaceSignature(p->e_inSpace); 10516 10517 if (outs != NULL) 10518 *outs = p->e_outSpace; 10519 if (outn != NULL) 10520 *outn = (int)number_ColorSpaceSignature(p->e_outSpace); 10521 10522 if (alg != NULL) 10523 *alg = p->ttype; 10524 10525 if (intt != NULL) 10526 *intt = p->intent; 10527 10528 if (fnc != NULL) 10529 *fnc = p->function; 10530 10531 if (pcs != NULL) 10532 *pcs = p->e_pcs; 10533 } 10534 10535 /* Return the media white and black points in XYZ space. */ 10536 /* Note that if not in the icc, the black point will be returned as 0, 0, 0 */ 10537 /* Any pointer may be NULL if value is not to be returned */ 10538 static void icmLuWh_bk_points( 10539 struct _icmLuBase *p, 10540 icmXYZNumber *wht, 10541 icmXYZNumber *blk 10542 ) { 10543 if (wht != NULL) 10544 *wht = p->whitePoint; /* Structure copy */ 10545 10546 if (blk != NULL) 10547 *blk = p->blackPoint; /* Structure copy */ 10548 } 10549 10550 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 10551 /* Forward and Backward Monochrome type conversion */ 10552 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 10553 10554 /* Individual components of Fwd conversion: */ 10555 10556 /* Actual device to linearised device */ 10557 static int 10558 icmLuMonoFwd_curve ( 10559 icmLuMono *p, /* This */ 10560 double *out, /* Vector of output values */ 10561 double *in /* Vector of input values */ 10562 ) { 10563 icc *icp = p->icp; 10564 int rv = 0; 10565 10566 /* Translate from device to PCS scale */ 10567 if ((rv |= p->grayCurve->lookup_fwd(p->grayCurve,&out[0],&in[0])) > 1) { 10568 sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed"); 10569 icp->errc = rv; 10570 return 2; 10571 } 10572 10573 return rv; 10574 } 10575 10576 /* Linearised device to relative PCS */ 10577 static int 10578 icmLuMonoFwd_map ( 10579 icmLuMono *p, /* This */ 10580 double *out, /* Vector of output values (native space) */ 10581 double *in /* Vector of input values (native space) */ 10582 ) { 10583 int rv = 0; 10584 double Y = in[0]; /* In case out == in */ 10585 10586 out[0] = p->pcswht.X; 10587 out[1] = p->pcswht.Y; 10588 out[2] = p->pcswht.Z; 10589 if (p->outSpace == icSigLabData) 10590 icmXYZ2Lab(&p->pcswht, out, out); /* in Lab */ 10591 10592 /* Scale linearized device level to PCS white */ 10593 out[0] *= Y; 10594 out[1] *= Y; 10595 out[2] *= Y; 10596 10597 return rv; 10598 } 10599 10600 /* relative PCS to absolute PCS (if required) */ 10601 static int 10602 icmLuMonoFwd_abs ( /* Abs comes last in Fwd conversion */ 10603 icmLuMono *p, /* This */ 10604 double *out, /* Vector of output values in Effective PCS */ 10605 double *in /* Vector of input values in Native PCS */ 10606 ) { 10607 int rv = 0; 10608 10609 if (out != in) { 10610 int i; 10611 for (i = 0; i < 3; i++) /* Don't alter input values */ 10612 out[i] = in[i]; 10613 } 10614 10615 /* Do absolute conversion */ 10616 if (p->intent == icAbsoluteColorimetric) { 10617 10618 if (p->outSpace == icSigLabData) /* Convert L to Y */ 10619 icmLab2XYZ(&p->pcswht, out, out); 10620 10621 /* Convert from Relative to Absolute colorometric */ 10622 icmMulBy3x3(out, p->toAbs, out); 10623 10624 if (p->e_outSpace == icSigLabData) 10625 icmXYZ2Lab(&p->pcswht, out, out); 10626 10627 } else { 10628 10629 /* Convert from Native to Effective output space */ 10630 if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData) 10631 icmLab2XYZ(&p->pcswht, out, out); 10632 else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData) 10633 icmXYZ2Lab(&p->pcswht, out, out); 10634 } 10635 10636 return rv; 10637 } 10638 10639 10640 /* Overall Fwd conversion routine */ 10641 static int 10642 icmLuMonoFwd_lookup ( 10643 icmLuBase *pp, /* This */ 10644 double *out, /* Vector of output values */ 10645 double *in /* Input value */ 10646 ) { 10647 int rv = 0; 10648 icmLuMono *p = (icmLuMono *)pp; 10649 rv |= icmLuMonoFwd_curve(p, out, in); 10650 rv |= icmLuMonoFwd_map(p, out, out); 10651 rv |= icmLuMonoFwd_abs(p, out, out); 10652 return rv; 10653 } 10654 10655 10656 /* Individual components of Bwd conversion: */ 10657 10658 /* Convert from relative PCS to absolute PCS (if required) */ 10659 static int 10660 icmLuMonoBwd_abs ( /* Abs comes first in Bwd conversion */ 10661 icmLuMono *p, /* This */ 10662 double *out, /* Vector of output values in Native PCS */ 10663 double *in /* Vector of input values in Effective PCS */ 10664 ) { 10665 int rv = 0; 10666 10667 if (out != in) { 10668 int i; 10669 for (i = 0; i < 3; i++) /* Don't alter input values */ 10670 out[i] = in[i]; 10671 } 10672 10673 /* Force to monochrome locus in correct space */ 10674 if (p->e_inSpace == icSigLabData) { 10675 double wp[3]; 10676 10677 if (p->intent == icAbsoluteColorimetric) { 10678 wp[0] = p->whitePoint.X; 10679 wp[1] = p->whitePoint.Y; 10680 wp[2] = p->whitePoint.Z; 10681 } else { 10682 wp[0] = p->pcswht.X; 10683 wp[1] = p->pcswht.Y; 10684 wp[2] = p->pcswht.Z; 10685 } 10686 icmXYZ2Lab(&p->pcswht, wp, wp); /* Convert to Lab white point */ 10687 out[1] = out[0]/wp[0] * wp[1]; 10688 out[2] = out[0]/wp[0] * wp[2]; 10689 10690 } else { 10691 if (p->intent == icAbsoluteColorimetric) { 10692 out[0] = out[1]/p->whitePoint.Y * p->whitePoint.X; 10693 out[2] = out[1]/p->whitePoint.Y * p->whitePoint.Z; 10694 } else { 10695 out[0] = out[1]/p->pcswht.Y * p->pcswht.X; 10696 out[2] = out[1]/p->pcswht.Y * p->pcswht.Z; 10697 } 10698 } 10699 10700 /* Do absolute conversion to */ 10701 if (p->intent == icAbsoluteColorimetric) { 10702 10703 if (p->e_inSpace == icSigLabData) 10704 icmLab2XYZ(&p->pcswht, out, out); 10705 10706 icmMulBy3x3(out, p->fromAbs, out); 10707 10708 /* Convert from Effective to Native input space */ 10709 if (p->inSpace == icSigLabData) 10710 icmXYZ2Lab(&p->pcswht, out, out); 10711 10712 } else { 10713 10714 /* Convert from Effective to Native input space */ 10715 if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData) 10716 icmLab2XYZ(&p->pcswht, out, out); 10717 else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData) 10718 icmXYZ2Lab(&p->pcswht, out, out); 10719 } 10720 10721 return rv; 10722 } 10723 10724 /* Map from relative PCS to linearised device */ 10725 static int 10726 icmLuMonoBwd_map ( 10727 icmLuMono *p, /* This */ 10728 double *out, /* Output value */ 10729 double *in /* Vector of input values (native space) */ 10730 ) { 10731 int i, rv = 0; 10732 double pcsw[3]; 10733 10734 pcsw[0] = p->pcswht.X; 10735 pcsw[1] = p->pcswht.Y; 10736 pcsw[2] = p->pcswht.Z; 10737 if (p->inSpace == icSigLabData) 10738 icmXYZ2Lab(&p->pcswht, pcsw, pcsw); /* in Lab (should be 100.0!) */ 10739 10740 /* Divide linearized device level into PCS white luminence */ 10741 if (p->inSpace == icSigLabData) 10742 out[0] = in[0]/pcsw[0]; 10743 else 10744 out[0] = in[1]/pcsw[1]; 10745 10746 return rv; 10747 } 10748 10749 /* Map from linearised device to actual device */ 10750 static int 10751 icmLuMonoBwd_curve ( 10752 icmLuMono *p, /* This */ 10753 double *out, /* Output value */ 10754 double *in /* Input value */ 10755 ) { 10756 icc *icp = p->icp; 10757 int i, rv = 0; 10758 10759 /* Convert to device value through curve */ 10760 if ((rv = p->grayCurve->lookup_bwd(p->grayCurve,&out[0],&in[0])) > 1) { 10761 sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed"); 10762 icp->errc = rv; 10763 return 2; 10764 } 10765 10766 return rv; 10767 } 10768 10769 /* Overall Bwd conversion routine */ 10770 static int 10771 icmLuMonoBwd_lookup ( 10772 icmLuBase *pp, /* This */ 10773 double *out, /* Output value */ 10774 double *in /* Vector of input values */ 10775 ) { 10776 double temp[3]; 10777 int rv = 0; 10778 icmLuMono *p = (icmLuMono *)pp; 10779 rv |= icmLuMonoBwd_abs(p, temp, in); 10780 rv |= icmLuMonoBwd_map(p, out, temp); 10781 rv |= icmLuMonoBwd_curve(p, out, out); 10782 return rv; 10783 } 10784 10785 static void 10786 icmLuMono_delete( 10787 icmLuBase *p 10788 ) { 10789 icc *icp = p->icp; 10790 10791 icp->al->free(icp->al, p); 10792 } 10793 10794 static icmLuBase * 10795 new_icmLuMono( 10796 struct _icc *icp, 10797 icColorSpaceSignature inSpace, /* Native Input color space */ 10798 icColorSpaceSignature outSpace, /* Native Output color space */ 10799 icColorSpaceSignature pcs, /* Native PCS */ 10800 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 10801 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 10802 icColorSpaceSignature e_pcs, /* Effective PCS */ 10803 icmXYZNumber whitePoint, /* Profile absolute white point */ 10804 icmXYZNumber blackPoint, /* Profile absolute black point */ 10805 icRenderingIntent intent, /* Rendering intent */ 10806 icmLookupFunc func, /* Functionality requested */ 10807 int dir /* 0 = fwd, 1 = bwd */ 10808 ) { 10809 icmLuMono *p; 10810 icmXYZArray *redColrnt, *greenColrnt, *blueColrnt; 10811 10812 if ((p = (icmLuMono *) icp->al->calloc(icp->al,1,sizeof(icmLuMono))) == NULL) 10813 return NULL; 10814 p->icp = icp; 10815 p->del = icmLuMono_delete; 10816 p->lutspaces= icmLutSpaces; 10817 p->spaces = icmLuSpaces; 10818 p->wh_bk_points = icmLuWh_bk_points; 10819 p->fwd_lookup = icmLuMonoFwd_lookup; 10820 p->fwd_curve = icmLuMonoFwd_curve; 10821 p->fwd_map = icmLuMonoFwd_map; 10822 p->fwd_abs = icmLuMonoFwd_abs; 10823 p->bwd_lookup = icmLuMonoBwd_lookup; 10824 p->bwd_abs = icmLuMonoFwd_abs; 10825 p->bwd_map = icmLuMonoFwd_map; 10826 p->bwd_curve = icmLuMonoFwd_curve; 10827 if (dir) { 10828 p->ttype = icmMonoBwdType; 10829 p->lookup = icmLuMonoBwd_lookup; 10830 } else { 10831 p->ttype = icmMonoFwdType; 10832 p->lookup = icmLuMonoFwd_lookup; 10833 } 10834 10835 /* See if the color spaces are appropriate for the mono type */ 10836 if (number_ColorSpaceSignature(icp->header->colorSpace) != 1 10837 || ( icp->header->pcs != icSigXYZData && icp->header->pcs != icSigLabData)) { 10838 p->del((icmLuBase *)p); 10839 return NULL; 10840 } 10841 10842 /* Find the appropriate tags */ 10843 if ((p->grayCurve = (icmCurve *)icp->read_tag(icp, icSigGrayTRCTag)) == NULL 10844 || p->grayCurve->ttype != icSigCurveType) { 10845 p->del((icmLuBase *)p); 10846 return NULL; 10847 } 10848 10849 p->pcswht = icp->header->illuminant; 10850 p->whitePoint = whitePoint; 10851 p->blackPoint = blackPoint; 10852 p->intent = intent; 10853 p->function = func; 10854 p->inSpace = inSpace; 10855 p->outSpace = outSpace; 10856 p->pcs = pcs; 10857 p->e_inSpace = e_inSpace; 10858 p->e_outSpace = e_outSpace; 10859 p->e_pcs = e_pcs; 10860 10861 /* Create absolute <-> relative conversion matricies */ 10862 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs); 10863 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs); 10864 10865 return (icmLuBase *)p; 10866 } 10867 10868 static icmLuBase * 10869 new_icmLuMonoFwd( 10870 struct _icc *icp, 10871 icColorSpaceSignature inSpace, /* Native Input color space */ 10872 icColorSpaceSignature outSpace, /* Native Output color space */ 10873 icColorSpaceSignature pcs, /* Native PCS */ 10874 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 10875 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 10876 icColorSpaceSignature e_pcs, /* Effective PCS */ 10877 icmXYZNumber whitePoint, /* Profile absolute white point */ 10878 icmXYZNumber blackPoint, /* Profile absolute black point */ 10879 icRenderingIntent intent, /* Rendering intent */ 10880 icmLookupFunc func /* Functionality requested */ 10881 ) { 10882 return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs, 10883 whitePoint, blackPoint, intent, func, 0); 10884 } 10885 10886 10887 static icmLuBase * 10888 new_icmLuMonoBwd( 10889 struct _icc *icp, 10890 icColorSpaceSignature inSpace, /* Native Input color space */ 10891 icColorSpaceSignature outSpace, /* Native Output color space */ 10892 icColorSpaceSignature pcs, /* Native PCS */ 10893 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 10894 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 10895 icColorSpaceSignature e_pcs, /* Effective PCS */ 10896 icmXYZNumber whitePoint, /* Profile absolute white point */ 10897 icmXYZNumber blackPoint, /* Profile absolute black point */ 10898 icRenderingIntent intent, /* Rendering intent */ 10899 icmLookupFunc func /* Functionality requested */ 10900 ) { 10901 return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs, 10902 whitePoint, blackPoint, intent, func, 1); 10903 } 10904 10905 /* - - - - - - - - - - - - - - - - - - - - - - - */ 10906 /* Forward and Backward Matrix type conversion */ 10907 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 10908 10909 /* Individual components of Fwd conversion: */ 10910 static int 10911 icmLuMatrixFwd_curve ( 10912 icmLuMatrix *p, /* This */ 10913 double *out, /* Vector of output values */ 10914 double *in /* Vector of input values */ 10915 ) { 10916 icc *icp = p->icp; 10917 int rv = 0; 10918 10919 /* Curve lookups */ 10920 if ((rv |= p->redCurve->lookup_fwd( p->redCurve, &out[0],&in[0])) > 1 10921 || (rv |= p->greenCurve->lookup_fwd(p->greenCurve,&out[1],&in[1])) > 1 10922 || (rv |= p->blueCurve->lookup_fwd( p->blueCurve, &out[2],&in[2])) > 1) { 10923 sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed"); 10924 icp->errc = rv; 10925 return 2; 10926 } 10927 10928 return rv; 10929 } 10930 10931 static int 10932 icmLuMatrixFwd_matrix ( 10933 icmLuMatrix *p, /* This */ 10934 double *out, /* Vector of output values */ 10935 double *in /* Vector of input values */ 10936 ) { 10937 int rv = 0; 10938 double tt[3]; 10939 10940 /* Matrix */ 10941 tt[0] = p->mx[0][0] * in[0] + p->mx[0][1] * in[1] + p->mx[0][2] * in[2]; 10942 tt[1] = p->mx[1][0] * in[0] + p->mx[1][1] * in[1] + p->mx[1][2] * in[2]; 10943 tt[2] = p->mx[2][0] * in[0] + p->mx[2][1] * in[1] + p->mx[2][2] * in[2]; 10944 10945 out[0] = tt[0]; 10946 out[1] = tt[1]; 10947 out[2] = tt[2]; 10948 10949 return rv; 10950 } 10951 10952 static int 10953 icmLuMatrixFwd_abs (/* Abs comes last in Fwd conversion */ 10954 icmLuMatrix *p, /* This */ 10955 double *out, /* Vector of output values */ 10956 double *in /* Vector of input values */ 10957 ) { 10958 int rv = 0; 10959 10960 if (out != in) { 10961 int i; 10962 for (i = 0; i < 3; i++) /* Don't alter input values */ 10963 out[i] = in[i]; 10964 } 10965 10966 /* If required, convert from Relative to Absolute colorometric */ 10967 if (p->intent == icAbsoluteColorimetric) { 10968 icmMulBy3x3(out, p->toAbs, out); 10969 } 10970 10971 /* If e_outSpace is Lab (==e_PCS), then convert XYZ to Lab */ 10972 if (p->e_outSpace == icSigLabData) 10973 icmXYZ2Lab(&p->pcswht, out, out); 10974 10975 return rv; 10976 } 10977 10978 10979 /* Overall Fwd conversion */ 10980 static int 10981 icmLuMatrixFwd_lookup ( 10982 icmLuBase *pp, /* This */ 10983 double *out, /* Vector of output values */ 10984 double *in /* Vector of input values */ 10985 ) { 10986 int rv = 0; 10987 icmLuMatrix *p = (icmLuMatrix *)pp; 10988 rv |= icmLuMatrixFwd_curve(p, out, in); 10989 rv |= icmLuMatrixFwd_matrix(p, out, out); 10990 rv |= icmLuMatrixFwd_abs(p, out, out); 10991 return rv; 10992 } 10993 10994 /* Individual components of Bwd conversion: */ 10995 10996 static int 10997 icmLuMatrixBwd_abs (/* Abs comes first in Bwd conversion */ 10998 icmLuMatrix *p, /* This */ 10999 double *out, /* Vector of output values */ 11000 double *in /* Vector of input values */ 11001 ) { 11002 int rv = 0; 11003 11004 if (out != in) { 11005 int i; 11006 for (i = 0; i < 3; i++) /* Don't alter input values */ 11007 out[i] = in[i]; 11008 } 11009 11010 /* If e_inSpace is Lab (==PCS), then convert Lab to XYZ */ 11011 if (p->e_inSpace == icSigLabData) 11012 icmLab2XYZ(&p->pcswht, out, out); 11013 11014 /* If required, convert from Absolute to Relative colorometric */ 11015 if (p->intent == icAbsoluteColorimetric) { 11016 icmMulBy3x3(out, p->fromAbs, out); 11017 } 11018 11019 return rv; 11020 } 11021 11022 static int 11023 icmLuMatrixBwd_matrix ( 11024 icmLuMatrix *p, /* This */ 11025 double *out, /* Vector of output values */ 11026 double *in /* Vector of input values */ 11027 ) { 11028 int rv = 0; 11029 double tt[3]; 11030 11031 /* Matrix */ 11032 tt[0] = p->bmx[0][0] * in[0] + p->bmx[0][1] * in[1] + p->bmx[0][2] * in[2]; 11033 tt[1] = p->bmx[1][0] * in[0] + p->bmx[1][1] * in[1] + p->bmx[1][2] * in[2]; 11034 tt[2] = p->bmx[2][0] * in[0] + p->bmx[2][1] * in[1] + p->bmx[2][2] * in[2]; 11035 11036 out[0] = tt[0]; 11037 out[1] = tt[1]; 11038 out[2] = tt[2]; 11039 11040 return rv; 11041 } 11042 11043 static int 11044 icmLuMatrixBwd_curve ( 11045 icmLuMatrix *p, /* This */ 11046 double *out, /* Vector of output values */ 11047 double *in /* Vector of input values */ 11048 ) { 11049 icc *icp = p->icp; 11050 int rv = 0; 11051 11052 /* Curves */ 11053 if ((rv |= p->redCurve->lookup_bwd(p->redCurve,&out[0],&out[0])) > 1 11054 || (rv |= p->greenCurve->lookup_bwd(p->greenCurve,&out[1],&out[1])) > 1 11055 || (rv |= p->blueCurve->lookup_bwd(p->blueCurve,&out[2],&out[2])) > 1) { 11056 sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed"); 11057 icp->errc = rv; 11058 return 2; 11059 } 11060 return rv; 11061 } 11062 11063 /* Overall Bwd conversion */ 11064 static int 11065 icmLuMatrixBwd_lookup ( 11066 icmLuBase *pp, /* This */ 11067 double *out, /* Vector of output values */ 11068 double *in /* Vector of input values */ 11069 ) { 11070 int rv = 0; 11071 icmLuMatrix *p = (icmLuMatrix *)pp; 11072 rv |= icmLuMatrixBwd_abs(p, out, in); 11073 rv |= icmLuMatrixBwd_matrix(p, out, out); 11074 rv |= icmLuMatrixBwd_curve(p, out, out); 11075 return rv; 11076 } 11077 11078 static void 11079 icmLuMatrix_delete( 11080 icmLuBase *p 11081 ) { 11082 icc *icp = p->icp; 11083 11084 icp->al->free(icp->al, p); 11085 } 11086 11087 /* We setup valid fwd and bwd component conversions, */ 11088 /* but setup only the asked for overal conversion. */ 11089 static icmLuBase * 11090 new_icmLuMatrix( 11091 struct _icc *icp, 11092 icColorSpaceSignature inSpace, /* Native Input color space */ 11093 icColorSpaceSignature outSpace, /* Native Output color space */ 11094 icColorSpaceSignature pcs, /* Native PCS */ 11095 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 11096 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 11097 icColorSpaceSignature e_pcs, /* Effective PCS */ 11098 icmXYZNumber whitePoint, /* Profile absolute white point */ 11099 icmXYZNumber blackPoint, /* Profile absolute black point */ 11100 icRenderingIntent intent, /* Rendering intent */ 11101 icmLookupFunc func, /* Functionality requested */ 11102 int dir /* 0 = fwd, 1 = bwd */ 11103 ) { 11104 icmLuMatrix *p; 11105 11106 if ((p = (icmLuMatrix *) icp->al->calloc(icp->al,1,sizeof(icmLuMatrix))) == NULL) 11107 return NULL; 11108 p->icp = icp; 11109 p->del = icmLuMatrix_delete; 11110 p->lutspaces= icmLutSpaces; 11111 p->spaces = icmLuSpaces; 11112 p->wh_bk_points = icmLuWh_bk_points; 11113 p->fwd_lookup = icmLuMatrixFwd_lookup; 11114 p->fwd_curve = icmLuMatrixFwd_curve; 11115 p->fwd_matrix = icmLuMatrixFwd_matrix; 11116 p->fwd_abs = icmLuMatrixFwd_abs; 11117 p->bwd_lookup = icmLuMatrixBwd_lookup; 11118 p->bwd_abs = icmLuMatrixBwd_abs; 11119 p->bwd_matrix = icmLuMatrixBwd_matrix; 11120 p->bwd_curve = icmLuMatrixBwd_curve; 11121 if (dir) { 11122 p->ttype = icmMatrixBwdType; 11123 p->lookup = icmLuMatrixBwd_lookup; 11124 } else { 11125 p->ttype = icmMatrixFwdType; 11126 p->lookup = icmLuMatrixFwd_lookup; 11127 } 11128 11129 /* Note that we can use matrix type even if PCS is Lab, */ 11130 /* by simply converting it. */ 11131 11132 /* Find the appropriate tags */ 11133 if ((p->redCurve = (icmCurve *)icp->read_tag(icp, icSigRedTRCTag)) == NULL 11134 || p->redCurve->ttype != icSigCurveType 11135 || (p->greenCurve = (icmCurve *)icp->read_tag(icp, icSigGreenTRCTag)) == NULL 11136 || p->greenCurve->ttype != icSigCurveType 11137 || (p->blueCurve = (icmCurve *)icp->read_tag(icp, icSigBlueTRCTag)) == NULL 11138 || p->blueCurve->ttype != icSigCurveType 11139 || (p->redColrnt = (icmXYZArray *)icp->read_tag(icp, icSigRedColorantTag)) == NULL 11140 || p->redColrnt->ttype != icSigXYZType || p->redColrnt->size < 1 11141 || (p->greenColrnt = (icmXYZArray *)icp->read_tag(icp, icSigGreenColorantTag)) == NULL 11142 || p->greenColrnt->ttype != icSigXYZType || p->greenColrnt->size < 1 11143 || (p->blueColrnt = (icmXYZArray *)icp->read_tag(icp, icSigBlueColorantTag)) == NULL 11144 || p->blueColrnt->ttype != icSigXYZType || p->blueColrnt->size < 1) { 11145 p->del((icmLuBase *)p); 11146 return NULL; 11147 } 11148 11149 /* Setup the matrix */ 11150 p->mx[0][0] = p->redColrnt->data[0].X; 11151 p->mx[0][1] = p->greenColrnt->data[0].X; 11152 p->mx[0][2] = p->blueColrnt->data[0].X; 11153 p->mx[1][1] = p->greenColrnt->data[0].Y; 11154 p->mx[1][0] = p->redColrnt->data[0].Y; 11155 p->mx[1][2] = p->blueColrnt->data[0].Y; 11156 p->mx[2][1] = p->greenColrnt->data[0].Z; 11157 p->mx[2][0] = p->redColrnt->data[0].Z; 11158 p->mx[2][2] = p->blueColrnt->data[0].Z; 11159 11160 if (inverse3x3(p->bmx, p->mx) != 0) { /* Compute inverse */ 11161 sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable"); 11162 icp->errc = 2; 11163 p->del((icmLuBase *)p); 11164 return NULL; 11165 } 11166 11167 p->pcswht = icp->header->illuminant; 11168 p->whitePoint = whitePoint; 11169 p->blackPoint = blackPoint; 11170 p->intent = intent; 11171 p->function = func; 11172 p->inSpace = inSpace; 11173 p->outSpace = outSpace; 11174 p->pcs = pcs; 11175 p->e_inSpace = e_inSpace; 11176 p->e_outSpace = e_outSpace; 11177 p->e_pcs = e_pcs; 11178 11179 /* Create absolute <-> relative conversion matricies */ 11180 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs); 11181 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs); 11182 11183 return (icmLuBase *)p; 11184 } 11185 11186 static icmLuBase * 11187 new_icmLuMatrixFwd( 11188 struct _icc *icp, 11189 icColorSpaceSignature inSpace, /* Native Input color space */ 11190 icColorSpaceSignature outSpace, /* Native Output color space */ 11191 icColorSpaceSignature pcs, /* Native PCS */ 11192 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 11193 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 11194 icColorSpaceSignature e_pcs, /* Effective PCS */ 11195 icmXYZNumber whitePoint, /* Profile absolute white point */ 11196 icmXYZNumber blackPoint, /* Profile absolute black point */ 11197 icRenderingIntent intent, /* Rendering intent */ 11198 icmLookupFunc func /* Functionality requested */ 11199 ) { 11200 return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs, 11201 whitePoint, blackPoint, intent, func, 0); 11202 } 11203 11204 11205 static icmLuBase * 11206 new_icmLuMatrixBwd( 11207 struct _icc *icp, 11208 icColorSpaceSignature inSpace, /* Native Input color space */ 11209 icColorSpaceSignature outSpace, /* Native Output color space */ 11210 icColorSpaceSignature pcs, /* Native PCS */ 11211 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 11212 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 11213 icColorSpaceSignature e_pcs, /* Effective PCS */ 11214 icmXYZNumber whitePoint, /* Profile absolute white point */ 11215 icmXYZNumber blackPoint, /* Profile absolute black point */ 11216 icRenderingIntent intent, /* Rendering intent */ 11217 icmLookupFunc func /* Functionality requested */ 11218 ) { 11219 return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs, 11220 whitePoint, blackPoint, intent, func, 1); 11221 } 11222 11223 /* - - - - - - - - - - - - - - - - - - - - - - - */ 11224 /* Forward and Backward Multi-Dimensional Interpolation type conversion */ 11225 /* Return 0 on success, 1 if clipping occured, 2 on other error */ 11226 11227 /* Components of overall lookup, in order */ 11228 int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) { 11229 icmLut *lut = p->lut; 11230 int rv = 0; 11231 11232 if (out != in) { 11233 int i; 11234 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */ 11235 out[i] = in[i]; 11236 } 11237 11238 /* If Bwd Lut, take care of Absolute color space and effective input space */ 11239 if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview) 11240 && p->intent == icAbsoluteColorimetric) { 11241 11242 if (p->e_inSpace == icSigLabData) 11243 icmLab2XYZ(&p->pcswht, out, out); 11244 11245 /* Convert from Absolute to Relative colorometric */ 11246 icmMulBy3x3(out, p->fromAbs, out); 11247 11248 if (p->inSpace == icSigLabData) 11249 icmXYZ2Lab(&p->pcswht, out, out); 11250 11251 } else { 11252 11253 /* Convert from Effective to Native input space */ 11254 if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData) 11255 icmLab2XYZ(&p->pcswht, out, out); 11256 else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData) 11257 icmXYZ2Lab(&p->pcswht, out, out); 11258 } 11259 11260 return rv; 11261 } 11262 11263 /* Possible matrix lookup */ 11264 int icmLuLut_matrix(icmLuLut *p, double *out, double *in) { 11265 icmLut *lut = p->lut; 11266 int rv = 0; 11267 11268 if (p->usematrix) 11269 rv |= lut->lookup_matrix(lut,out,in); 11270 else if (out != in) { 11271 int i; 11272 for (i = 0; i < lut->inputChan; i++) 11273 out[i] = in[i]; 11274 } 11275 return rv; 11276 } 11277 11278 /* Do input -> input' lookup */ 11279 int icmLuLut_input(icmLuLut *p, double *out, double *in) { 11280 icmLut *lut = p->lut; 11281 int rv = 0; 11282 11283 p->in_normf(out, in); /* Normalize from input color space */ 11284 rv |= lut->lookup_input(lut,out,out); /* Lookup though input tables */ 11285 p->in_denormf(out,out); /* De-normalize to input color space */ 11286 return rv; 11287 } 11288 11289 /* Do input'->output' lookup */ 11290 int icmLuLut_clut(icmLuLut *p, double *out, double *in) { 11291 icmLut *lut = p->lut; 11292 double temp[MAX_CHAN]; 11293 int rv = 0; 11294 11295 p->in_normf(temp, in); /* Normalize from input color space */ 11296 rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */ 11297 p->out_denormf(out,out); /* De-normalize to output color space */ 11298 return rv; 11299 } 11300 11301 /* Do output'->output lookup */ 11302 int icmLuLut_output(icmLuLut *p, double *out, double *in) { 11303 icmLut *lut = p->lut; 11304 int rv = 0; 11305 11306 p->out_normf(out,in); /* Normalize from output color space */ 11307 rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */ 11308 p->out_denormf(out, out); /* De-normalize to output color space */ 11309 return rv; 11310 } 11311 11312 int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) { 11313 icmLut *lut = p->lut; 11314 int rv = 0; 11315 11316 if (out != in) { 11317 int i; 11318 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */ 11319 out[i] = in[i]; 11320 } 11321 11322 /* If Fwd Lut, take care of Absolute color space */ 11323 /* and convert from native to effective out PCS */ 11324 if ((p->function == icmFwd || p->function == icmPreview) 11325 && p->intent == icAbsoluteColorimetric) { 11326 11327 if (p->outSpace == icSigLabData) 11328 icmLab2XYZ(&p->pcswht, out, out); 11329 11330 /* Convert from Relative to Absolute colorometric XYZ */ 11331 icmMulBy3x3(out, p->toAbs, out); 11332 11333 if (p->e_outSpace == icSigLabData) 11334 icmXYZ2Lab(&p->pcswht, out, out); 11335 } else { 11336 11337 /* Convert from Native to Effective output space */ 11338 if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData) 11339 icmLab2XYZ(&p->pcswht, out, out); 11340 else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData) 11341 icmXYZ2Lab(&p->pcswht, out, out); 11342 } 11343 return rv; 11344 } 11345 11346 11347 /* Overall lookup */ 11348 static int 11349 icmLuLut_lookup ( 11350 icmLuBase *pp, /* This */ 11351 double *out, /* Vector of output values */ 11352 double *in /* Vector of input values */ 11353 ) { 11354 int i, rv = 0; 11355 icmLuLut *p = (icmLuLut *)pp; 11356 icmLut *lut = p->lut; 11357 double temp[MAX_CHAN]; 11358 11359 rv |= p->in_abs(p,temp,in); /* Possible absolute conversion */ 11360 if (p->usematrix) 11361 rv |= lut->lookup_matrix(lut,temp,temp);/* If XYZ, multiply by non-unity matrix */ 11362 p->in_normf(temp, temp); /* Normalize for input color space */ 11363 rv |= lut->lookup_input(lut,temp,temp); /* Lookup though input tables */ 11364 rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */ 11365 rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */ 11366 p->out_denormf(out,out); /* Normalize for output color space */ 11367 rv |= p->out_abs(p,out,out); /* Possible absolute conversion */ 11368 11369 return rv; 11370 } 11371 11372 #ifdef NEVER /* The following should be identical in effect to the above. */ 11373 11374 /* Overall lookup */ 11375 static int 11376 icmLuLut_lookup ( 11377 icmLuBase *pp, /* This */ 11378 double *out, /* Vector of output values */ 11379 double *in /* Vector of input values */ 11380 ) { 11381 int i, rv = 0; 11382 icmLuLut *p = (icmLuLut *)pp; 11383 icmLut *lut = p->lut; 11384 double temp[MAX_CHAN]; 11385 11386 rv |= p->in_abs(p,temp,in); 11387 rv |= p->matrix(p,temp,temp); 11388 rv |= p->input(p,temp,temp); 11389 rv |= p->clut(p,out,temp); 11390 rv |= p->output(p,out,out); 11391 rv |= p->out_abs(p,out,out); 11392 11393 return rv; 11394 } 11395 #endif /* NEVER */ 11396 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */ 11397 /* Some components of inverse lookup, in order */ 11398 /* ~~ should these be in icmLut (like all the fwd transforms)? */ 11399 11400 int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) { 11401 icmLut *lut = p->lut; 11402 int rv = 0; 11403 11404 if (out != in) { 11405 int i; 11406 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */ 11407 out[i] = in[i]; 11408 } 11409 11410 /* If Fwd Lut, take care of Absolute color space */ 11411 /* and convert from effective to native inverse output PCS */ 11412 /* OutSpace must be PCS: XYZ or Lab */ 11413 if ((p->function == icmFwd || p->function == icmPreview) 11414 && p->intent == icAbsoluteColorimetric) { 11415 11416 if (p->e_outSpace == icSigLabData) 11417 icmLab2XYZ(&p->pcswht, out, out); 11418 11419 /* Convert from Absolute to Relative colorometric */ 11420 icmMulBy3x3(out, p->fromAbs, out); 11421 11422 if (p->outSpace == icSigLabData) 11423 icmXYZ2Lab(&p->pcswht, out, out); 11424 11425 } else { 11426 11427 /* Convert from Effective to Native output space */ 11428 if (p->e_outSpace == icSigLabData && p->outSpace == icSigXYZData) 11429 icmLab2XYZ(&p->pcswht, out, out); 11430 else if (p->e_outSpace == icSigXYZData && p->outSpace == icSigLabData) 11431 icmXYZ2Lab(&p->pcswht, out, out); 11432 } 11433 return rv; 11434 } 11435 11436 /* Do output->output' inverse lookup */ 11437 int icmLuLut_inv_output(icmLuLut *p, double *out, double *in) { 11438 icc *icp = p->icp; 11439 icmLut *lut = p->lut; 11440 int rv = 0; 11441 11442 if (lut->rot.inited == 0) { 11443 rv = icmTable_setup_bwd(icp, &lut->rot, lut->outputEnt, lut->outputTable); 11444 if (rv != 0) { 11445 sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init."); 11446 return icp->errc = rv; 11447 } 11448 } 11449 11450 p->out_normf(out,in); /* Normalize from output color space */ 11451 rv |= icmTable_lookup_bwd(&lut->rot, out, out); /* Reverse lookup though output tables */ 11452 p->out_denormf(out, out); /* De-normalize to output color space */ 11453 return rv; 11454 } 11455 11456 /* No output' -> input inverse lookup. */ 11457 /* This is non-trivial ! */ 11458 11459 /* Do input' -> input inverse lookup */ 11460 int icmLuLut_inv_input(icmLuLut *p, double *out, double *in) { 11461 icc *icp = p->icp; 11462 icmLut *lut = p->lut; 11463 int rv = 0; 11464 11465 if (lut->rit.inited == 0) { 11466 rv = icmTable_setup_bwd(icp, &lut->rit, lut->inputEnt, lut->inputTable); 11467 if (rv != 0) { 11468 sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init."); 11469 return icp->errc = rv; 11470 } 11471 } 11472 11473 p->in_normf(out, in); /* Normalize from input color space */ 11474 rv |= icmTable_lookup_bwd(&lut->rit, out, out); /* Reverse lookup though input tables */ 11475 p->in_denormf(out,out); /* De-normalize to input color space */ 11476 return rv; 11477 } 11478 11479 /* Possible inverse matrix lookup */ 11480 int icmLuLut_inv_matrix(icmLuLut *p, double *out, double *in) { 11481 icc *icp = p->icp; 11482 icmLut *lut = p->lut; 11483 int rv = 0; 11484 11485 if (p->usematrix) { 11486 double tt[3]; 11487 if (p->imx_valid == 0) { 11488 if (inverse3x3(p->imx, lut->e) != 0) { /* Compute inverse */ 11489 sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable"); 11490 icp->errc = 2; 11491 return 2; 11492 } 11493 p->imx_valid = 1; 11494 } 11495 /* Matrix multiply */ 11496 tt[0] = p->imx[0][0] * in[0] + p->imx[0][1] * in[1] + p->imx[0][2] * in[2]; 11497 tt[1] = p->imx[1][0] * in[0] + p->imx[1][1] * in[1] + p->imx[1][2] * in[2]; 11498 tt[2] = p->imx[2][0] * in[0] + p->imx[2][1] * in[1] + p->imx[2][2] * in[2]; 11499 out[0] = tt[0], out[1] = tt[1], out[2] = tt[2]; 11500 } else if (out != in) { 11501 int i; 11502 for (i = 0; i < lut->inputChan; i++) 11503 out[i] = in[i]; 11504 } 11505 return rv; 11506 } 11507 11508 int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) { 11509 icmHeader *header = p->icp->header; 11510 icmLut *lut = p->lut; 11511 int rv = 0; 11512 11513 if (out != in) { 11514 int i; 11515 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */ 11516 out[i] = in[i]; 11517 } 11518 11519 /* If Bwd Lut, take care of Absolute color space, and */ 11520 /* convert from native to effective input space */ 11521 if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview) 11522 && p->intent == icAbsoluteColorimetric) { 11523 11524 if (p->inSpace == icSigLabData) 11525 icmLab2XYZ(&p->pcswht, out, out); 11526 11527 /* Convert from Relative to Absolute colorometric XYZ */ 11528 icmMulBy3x3(out, p->toAbs, out); 11529 11530 if (p->e_inSpace == icSigLabData) 11531 icmXYZ2Lab(&p->pcswht, out, out); 11532 } else { 11533 11534 /* Convert from Native to Effective input space */ 11535 if (p->inSpace == icSigLabData && p->e_inSpace == icSigXYZData) 11536 icmLab2XYZ(&p->pcswht, out, out); 11537 else if (p->inSpace == icSigXYZData && p->e_inSpace == icSigLabData) 11538 icmXYZ2Lab(&p->pcswht, out, out); 11539 } 11540 return rv; 11541 } 11542 11543 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */ 11544 11545 /* Return LuLut information */ 11546 static void icmLuLut_get_info( 11547 icmLuLut *p, /* this */ 11548 icmLut **lutp, /* Pointer to icc lut type */ 11549 icmXYZNumber *pcswhtp, /* Pointer to profile PCS white point */ 11550 icmXYZNumber *whitep, /* Pointer to profile absolute white point */ 11551 icmXYZNumber *blackp /* Pointer to profile absolute black point */ 11552 ) { 11553 if (lutp != NULL) 11554 *lutp = p->lut; 11555 if (pcswhtp != NULL) 11556 *pcswhtp = p->pcswht; 11557 if (whitep != NULL) 11558 *whitep = p->whitePoint; 11559 if (blackp != NULL) 11560 *blackp = p->blackPoint; 11561 } 11562 11563 /* Get the native ranges for the LuLut */ 11564 static void 11565 icmLuLut_get_lutranges ( 11566 struct _icmLuLut *p, 11567 double *inmin, double *inmax, /* Return maximum range of inspace values */ 11568 double *outmin, double *outmax /* Return maximum range of outspace values */ 11569 ) { 11570 int i; 11571 11572 for (i = 0; i < p->lut->inputChan; i++) { 11573 inmin[i] = 0.0; /* Normalized range of input space values */ 11574 inmax[i] = 1.0; 11575 } 11576 p->in_denormf(inmin,inmin); /* Convert to real colorspace range */ 11577 p->in_denormf(inmax,inmax); 11578 11579 /* Make sure min and max are so. */ 11580 for (i = 0; i < p->lut->inputChan; i++) { 11581 if (inmin[i] > inmax[i]) { 11582 double tt; 11583 tt = inmin[i]; 11584 inmin[i] = inmax[i]; 11585 inmax[i] = tt; 11586 } 11587 } 11588 11589 for (i = 0; i < p->lut->outputChan; i++) { 11590 outmin[i] = 0.0; /* Normalized range of output space values */ 11591 outmax[i] = 1.0; 11592 } 11593 p->out_denormf(outmin,outmin); /* Convert to real colorspace range */ 11594 p->out_denormf(outmax,outmax); 11595 11596 /* Make sure min and max are so. */ 11597 for (i = 0; i < p->lut->outputChan; i++) { 11598 if (outmin[i] > outmax[i]) { 11599 double tt; 11600 tt = outmin[i]; 11601 outmin[i] = outmax[i]; 11602 outmax[i] = tt; 11603 } 11604 } 11605 } 11606 11607 /* Get the effective ranges for the LuLut */ 11608 static void 11609 icmLuLut_get_ranges ( 11610 struct _icmLuLut *p, 11611 double *inmin, double *inmax, /* Return maximum range of inspace values */ 11612 double *outmin, double *outmax /* Return maximum range of outspace values */ 11613 ) { 11614 int i; 11615 11616 for (i = 0; i < p->lut->inputChan; i++) { 11617 inmin[i] = 0.0; /* Normalized range of input space values */ 11618 inmax[i] = 1.0; 11619 } 11620 p->e_in_denormf(inmin,inmin); /* Convert to real colorspace range */ 11621 p->e_in_denormf(inmax,inmax); 11622 11623 /* Make sure min and max are so. */ 11624 for (i = 0; i < p->lut->inputChan; i++) { 11625 if (inmin[i] > inmax[i]) { 11626 double tt; 11627 tt = inmin[i]; 11628 inmin[i] = inmax[i]; 11629 inmax[i] = tt; 11630 } 11631 } 11632 11633 for (i = 0; i < p->lut->outputChan; i++) { 11634 outmin[i] = 0.0; /* Normalized range of output space values */ 11635 outmax[i] = 1.0; 11636 } 11637 p->e_out_denormf(outmin,outmin); /* Convert to real colorspace range */ 11638 p->e_out_denormf(outmax,outmax); 11639 11640 /* Make sure min and max are so. */ 11641 for (i = 0; i < p->lut->outputChan; i++) { 11642 if (outmin[i] > outmax[i]) { 11643 double tt; 11644 tt = outmin[i]; 11645 outmin[i] = outmax[i]; 11646 outmax[i] = tt; 11647 } 11648 } 11649 } 11650 11651 /* Return the underlying Lut matrix */ 11652 static void 11653 icmLuLut_get_matrix ( 11654 struct _icmLuLut *p, 11655 double m[3][3] 11656 ) { 11657 int i, j; 11658 icmLut *lut = p->lut; 11659 11660 if (p->usematrix) { 11661 for (i = 0; i < 3; i++) 11662 for (j = 0; j < 3; j++) 11663 m[i][j] = lut->e[i][j]; /* Copy from Lut */ 11664 11665 } else { /* return unity matrix */ 11666 for (i = 0; i < 3; i++) { 11667 for (j = 0; j < 3; j++) { 11668 if (i == j) 11669 m[i][j] = 1.0; 11670 else 11671 m[i][j] = 0.0; 11672 } 11673 } 11674 } 11675 } 11676 11677 11678 static void 11679 icmLuLut_delete( 11680 icmLuBase *p 11681 ) { 11682 icc *icp = p->icp; 11683 11684 icp->al->free(icp->al, p); 11685 } 11686 11687 static icmLuBase * 11688 new_icmLuLut( 11689 icc *icp, 11690 icTagSignature ttag, /* Target Lut tag */ 11691 icColorSpaceSignature inSpace, /* Native Input color space */ 11692 icColorSpaceSignature outSpace, /* Native Output color space */ 11693 icColorSpaceSignature pcs, /* Native PCS */ 11694 icColorSpaceSignature e_inSpace, /* Effective Input color space */ 11695 icColorSpaceSignature e_outSpace, /* Effective Output color space */ 11696 icColorSpaceSignature e_pcs, /* Effective PCS */ 11697 icmXYZNumber whitePoint, /* Profile absolute white point */ 11698 icmXYZNumber blackPoint, /* Profile absolute black point */ 11699 icRenderingIntent intent, /* Rendering intent */ 11700 icmLookupFunc func /* Functionality requested */ 11701 ) { 11702 icmLuLut *p; 11703 11704 if ((p = (icmLuLut *) icp->al->calloc(icp->al,1,sizeof(icmLuLut))) == NULL) 11705 return NULL; 11706 p->ttype = icmLutType; 11707 p->icp = icp; 11708 p->del = icmLuLut_delete; 11709 p->lutspaces= icmLutSpaces; 11710 p->spaces = icmLuSpaces; 11711 p->wh_bk_points = icmLuWh_bk_points; 11712 11713 p->lookup = icmLuLut_lookup; 11714 p->in_abs = icmLuLut_in_abs; 11715 p->matrix = icmLuLut_matrix; 11716 p->input = icmLuLut_input; 11717 p->clut = icmLuLut_clut; 11718 p->output = icmLuLut_output; 11719 p->out_abs = icmLuLut_out_abs; 11720 11721 p->inv_in_abs = icmLuLut_inv_in_abs; 11722 p->inv_matrix = icmLuLut_inv_matrix; 11723 p->inv_input = icmLuLut_inv_input; 11724 p->inv_output = icmLuLut_inv_output; 11725 p->inv_out_abs = icmLuLut_inv_out_abs; 11726 11727 p->pcswht = icp->header->illuminant; 11728 p->whitePoint = whitePoint; 11729 p->blackPoint = blackPoint; 11730 p->intent = intent; 11731 p->function = func; 11732 p->inSpace = inSpace; 11733 p->outSpace = outSpace; 11734 p->pcs = pcs; 11735 p->e_inSpace = e_inSpace; 11736 p->e_outSpace = e_outSpace; 11737 p->e_pcs = e_pcs; 11738 p->get_info = icmLuLut_get_info; 11739 p->get_lutranges = icmLuLut_get_lutranges; 11740 p->get_ranges = icmLuLut_get_ranges; 11741 p->get_matrix = icmLuLut_get_matrix; 11742 11743 /* Create absolute <-> relative conversion matricies */ 11744 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs); 11745 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs); 11746 11747 /* Get the Lut tag, & check that it is expected type */ 11748 if ((p->lut = (icmLut *)icp->read_tag(icp, ttag)) == NULL 11749 || (p->lut->ttype != icSigLut8Type && p->lut->ttype != icSigLut16Type)) { 11750 p->del((icmLuBase *)p); 11751 return NULL; 11752 } 11753 11754 /* Check if matrix should be used */ 11755 if (inSpace == icSigXYZData && p->lut->nu_matrix(p->lut)) 11756 p->usematrix = 1; 11757 else 11758 p->usematrix = 0; 11759 11760 /* Lookup input color space to normalized index function */ 11761 if (getNormFunc(inSpace, p->lut->ttype, icmToLuti, &p->in_normf)) { 11762 sprintf(icp->err,"icc_get_luobj: Unknown colorspace"); 11763 icp->errc = 1; 11764 p->del((icmLuBase *)p); 11765 return NULL; 11766 } 11767 11768 /* Lookup normalized index to input color space function */ 11769 if (getNormFunc(inSpace, p->lut->ttype, icmFromLuti, &p->in_denormf)) { 11770 sprintf(icp->err,"icc_get_luobj: Unknown colorspace"); 11771 icp->errc = 1; 11772 p->del((icmLuBase *)p); 11773 return NULL; 11774 } 11775 11776 /* Lookup output color space to normalized Lut entry value function */ 11777 if (getNormFunc(outSpace, p->lut->ttype, icmToLutv, &p->out_normf)) { 11778 sprintf(icp->err,"icc_get_luobj: Unknown colorspace"); 11779 icp->errc = 1; 11780 p->del((icmLuBase *)p); 11781 return NULL; 11782 } 11783 11784 /* Lookup normalized Lut entry value to output color space function */ 11785 if (getNormFunc(outSpace, p->lut->ttype, icmFromLutv, &p->out_denormf)) { 11786 sprintf(icp->err,"icc_get_luobj: Unknown colorspace"); 11787 icp->errc = 1; 11788 p->del((icmLuBase *)p); 11789 return NULL; 11790 } 11791 11792 /* Lookup normalized index to effective input color space function */ 11793 if (getNormFunc(e_inSpace, p->lut->ttype, icmFromLuti, &p->e_in_denormf)) { 11794 sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace"); 11795 icp->errc = 1; 11796 p->del((icmLuBase *)p); 11797 return NULL; 11798 } 11799 11800 /* Lookup normalized Lut entry value to effective output color space function */ 11801 if (getNormFunc(e_outSpace, p->lut->ttype, icmFromLutv, &p->e_out_denormf)) { 11802 sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace"); 11803 icp->errc = 1; 11804 p->del((icmLuBase *)p); 11805 return NULL; 11806 } 11807 11808 /* Determine appropriate clut lookup algorithm */ 11809 { 11810 int use_sx = -1; /* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */ 11811 icColorSpaceSignature ins, outs; /* In and out Lut color spaces */ 11812 int inn, outn; /* in and out number of Lut components */ 11813 11814 p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn); 11815 11816 /* Determine if the input space is "Device" like, */ 11817 /* ie. luminance will be expected to vary most strongly */ 11818 /* with the diagonal change in input coordinates. */ 11819 switch(ins) { 11820 11821 /* Luminence is carried by the sum of all the output channels, */ 11822 /* so output luminence will dominantly be in diagonal direction. */ 11823 case icSigRgbData: 11824 case icSigGrayData: 11825 case icSigCmykData: 11826 case icSigCmyData: 11827 case icSigMch6Data: 11828 use_sx = 1; /* Simplex interpolation is appropriate */ 11829 break; 11830 11831 /* A single chanel carries the luminence information */ 11832 case icSigLabData: 11833 case icSigLuvData: 11834 case icSigYCbCrData: 11835 case icSigYxyData: 11836 case icSigXYZData: 11837 case icSigHlsData: 11838 case icSigHsvData: 11839 use_sx = 0; /* N-linear interpolation is appropriate */ 11840 break; 11841 } 11842 11843 /* If we couldn't figure it out from the input space, */ 11844 /* check output luminance variation with a diagonal input */ 11845 /* change. */ 11846 if (use_sx == -1) { 11847 int lc; /* Luminance channel */ 11848 11849 /* Determine where the luminence is carried in the output */ 11850 switch(outs) { 11851 11852 /* Luminence is carried by the sum of all the output channels */ 11853 case icSigRgbData: 11854 case icSigGrayData: 11855 case icSigCmykData: 11856 case icSigCmyData: 11857 case icSigMch6Data: 11858 lc = -1; /* Average all chanels */ 11859 break; 11860 11861 /* A single chanel carries the luminence information */ 11862 case icSigLabData: 11863 case icSigLuvData: 11864 case icSigYCbCrData: 11865 case icSigYxyData: 11866 lc = 0; 11867 break; 11868 11869 case icSigXYZData: 11870 case icSigHlsData: 11871 lc = 1; 11872 break; 11873 11874 case icSigHsvData: 11875 lc = 2; 11876 break; 11877 11878 /* default means give up and use N-linear type lookup */ 11879 default: 11880 lc = -2; 11881 break; 11882 } 11883 11884 /* If we know how luminance is represented in output space */ 11885 if (lc != -2) { 11886 double tout1[MAX_CHAN]; /* Test output values */ 11887 double tout2[MAX_CHAN]; 11888 double tt, diag; 11889 int n; 11890 11891 /* Determine input space location of min and max of */ 11892 /* given output chanel (chan = -1 means average of all) */ 11893 p->lut->min_max(p->lut, tout1, tout2, lc); 11894 11895 /* Convert to vector and then calculate normalized */ 11896 /* dot product with diagonal vector (1,1,1...) */ 11897 for (tt = 0.0, n = 0; n < inn; n++) { 11898 tout1[n] = tout2[n] - tout1[n]; 11899 tt += tout1[n] * tout1[n]; 11900 } 11901 if (tt > 0.0) 11902 tt = sqrt(tt); /* normalizing factor for maximum delta */ 11903 else 11904 tt = 1.0; /* Hmm. */ 11905 tt *= sqrt((double)inn); /* Normalizing factor for diagonal vector */ 11906 for (diag = 0.0, n = 0; n < outn; n++) 11907 diag += tout1[n] / tt; 11908 diag = fabs(diag); 11909 11910 /* I'm not really convinced that this is a reliable */ 11911 /* indicator of whether simplex interpolation should be used ... */ 11912 /* It does seem to do the right thing with YCC space though. */ 11913 if (diag > 0.8) /* Diagonal is dominant ? */ 11914 use_sx = 1; 11915 11916 /* If we couldn't figure it out, use N-linear interpolation */ 11917 if (use_sx == -1) 11918 use_sx = 0; 11919 } 11920 } 11921 11922 if (use_sx) { 11923 p->lookup_clut = p->lut->lookup_clut_sx; 11924 } else 11925 p->lookup_clut = p->lut->lookup_clut_nl; 11926 } 11927 return (icmLuBase *)p; 11928 } 11929 11930 /* - - - - - - - - - - - - - - - - - - - - - - - */ 11931 11932 /* Return an appropriate lookup object */ 11933 /* Return NULL on error, and detailed error in icc */ 11934 icmLuBase* icc_get_luobj ( 11935 icc *p, /* ICC */ 11936 icmLookupFunc func, /* Conversion functionality */ 11937 icRenderingIntent intent, /* Rendering intent, including icmAbsoluteColorimetricXYZ */ 11938 icColorSpaceSignature pcsor,/* PCS overide (0 = def) */ 11939 icmLookupOrder order /* Conversion representation search Order */ 11940 ) { 11941 int rv; 11942 icmLuBase *luobj = NULL; /* Lookup object to return */ 11943 icmXYZNumber whitePoint, blackPoint; 11944 icColorSpaceSignature pcs, e_pcs; /* PCS and effective PCS */ 11945 11946 /* Check that the profile is legal, since we depend on it */ 11947 if ((rv = check_icc_legal(p)) != 0) 11948 return NULL; 11949 11950 /* Figure out the native and effective PCS */ 11951 e_pcs = pcs = p->header->pcs; 11952 if (pcsor != icmSigDefaultData) 11953 e_pcs = pcsor; /* Overide */ 11954 11955 /* Get White and Black points from the profile */ 11956 { 11957 icmXYZArray *whitePointTag, *blackPointTag; 11958 11959 if ((whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) == NULL 11960 || whitePointTag->ttype != icSigXYZType || whitePointTag->size < 1) { 11961 if (intent == icAbsoluteColorimetric) { 11962 sprintf(p->err,"icc_lookup: Profile is missing Media White Point Tag"); 11963 p->errc = 1; 11964 return NULL; 11965 } 11966 whitePoint = icmD50; /* safe value */ 11967 } else 11968 whitePoint = whitePointTag->data[0]; /* Copy structure */ 11969 11970 if ((blackPointTag = (icmXYZArray *)p->read_tag(p, icSigMediaBlackPointTag)) == NULL 11971 || blackPointTag->ttype != icSigXYZType || blackPointTag->size < 1) { 11972 blackPoint = icmBlack; /* default */ 11973 } else 11974 blackPoint = blackPointTag->data[0]; /* Copy structure */ 11975 } 11976 11977 /* How we expect to execute the request depends firstly on the type of profile */ 11978 switch (p->header->deviceClass) { 11979 case icSigInputClass: 11980 case icSigDisplayClass: 11981 /* Look for AToB0 based profile + optional BToA0 reverse */ 11982 /* or three component matrix profile (reversable) */ 11983 /* or momochrome table profile (reversable) */ 11984 /* No intent */ 11985 /* Device <-> PCS */ 11986 /* Determine the algorithm and set its parameters */ 11987 11988 if (intent != icmDefaultIntent 11989 && intent != icAbsoluteColorimetric) { 11990 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Input/Display profile"); 11991 p->errc = 1; 11992 return NULL; 11993 } 11994 11995 switch (func) { 11996 case icmFwd: /* Device to PCS */ 11997 if (order != icmLuOrdRev) { 11998 /* Try Lut type lookup first */ 11999 if ((luobj = new_icmLuLut(p, icSigAToB0Tag, 12000 p->header->colorSpace, pcs, pcs, 12001 p->header->colorSpace, e_pcs, e_pcs, 12002 whitePoint, blackPoint, intent, func)) != NULL) 12003 break; 12004 12005 /* See if it could be a matrix lookup */ 12006 if ((luobj = new_icmLuMatrixFwd(p, 12007 p->header->colorSpace, pcs, pcs, 12008 p->header->colorSpace, e_pcs, e_pcs, 12009 whitePoint, blackPoint, intent, func)) != NULL) 12010 break; 12011 12012 /* See if it could be a monochrome lookup */ 12013 if ((luobj = new_icmLuMonoFwd(p, 12014 p->header->colorSpace, pcs, pcs, 12015 p->header->colorSpace, e_pcs, e_pcs, 12016 whitePoint, blackPoint, intent, func)) != NULL) 12017 break; 12018 12019 } else { 12020 /* See if it could be a monochrome lookup */ 12021 if ((luobj = new_icmLuMonoFwd(p, 12022 p->header->colorSpace, pcs, pcs, 12023 p->header->colorSpace, e_pcs, e_pcs, 12024 whitePoint, blackPoint, intent, func)) != NULL) 12025 break; 12026 12027 /* See if it could be a matrix lookup */ 12028 if ((luobj = new_icmLuMatrixFwd(p, 12029 p->header->colorSpace, pcs, pcs, 12030 p->header->colorSpace, e_pcs, e_pcs, 12031 whitePoint, blackPoint, intent, func)) != NULL) 12032 break; 12033 12034 /* Try Lut type lookup last */ 12035 if ((luobj = new_icmLuLut(p, icSigAToB0Tag, 12036 p->header->colorSpace, pcs, pcs, 12037 p->header->colorSpace, e_pcs, e_pcs, 12038 whitePoint, blackPoint, intent, func)) != NULL) 12039 break; 12040 } 12041 break; 12042 12043 case icmBwd: /* PCS to Device */ 12044 if (order != icmLuOrdRev) { 12045 /* Try Lut type lookup first */ 12046 if ((luobj = new_icmLuLut(p, icSigBToA0Tag, 12047 pcs, p->header->colorSpace, pcs, 12048 e_pcs, p->header->colorSpace, e_pcs, 12049 whitePoint, blackPoint, intent, func)) != NULL) 12050 break; 12051 12052 /* See if it could be a matrix lookup */ 12053 if ((luobj = new_icmLuMatrixBwd(p, 12054 pcs, p->header->colorSpace, pcs, 12055 e_pcs, p->header->colorSpace, e_pcs, 12056 whitePoint, blackPoint, intent, func)) != NULL) 12057 break; 12058 12059 /* See if it could be a monochrome lookup */ 12060 if ((luobj = new_icmLuMonoBwd(p, 12061 pcs, p->header->colorSpace, pcs, 12062 e_pcs, p->header->colorSpace, e_pcs, 12063 whitePoint, blackPoint, intent, func)) != NULL) 12064 break; 12065 } else { 12066 /* See if it could be a monochrome lookup */ 12067 if ((luobj = new_icmLuMonoBwd(p, 12068 pcs, p->header->colorSpace, pcs, 12069 e_pcs, p->header->colorSpace, e_pcs, 12070 whitePoint, blackPoint, intent, func)) != NULL) 12071 break; 12072 12073 /* See if it could be a matrix lookup */ 12074 if ((luobj = new_icmLuMatrixBwd(p, 12075 pcs, p->header->colorSpace, pcs, 12076 e_pcs, p->header->colorSpace, e_pcs, 12077 whitePoint, blackPoint, intent, func)) != NULL) 12078 break; 12079 12080 /* Try Lut type lookup last */ 12081 if ((luobj = new_icmLuLut(p, icSigBToA0Tag, 12082 pcs, p->header->colorSpace, pcs, 12083 e_pcs, p->header->colorSpace, e_pcs, 12084 whitePoint, blackPoint, intent, func)) != NULL) 12085 break; 12086 } 12087 break; 12088 12089 default: 12090 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested"); 12091 p->errc = 1; 12092 return NULL; 12093 } 12094 break; 12095 12096 case icSigOutputClass: 12097 /* Expect BToA Lut and optional AToB Lut, All intents, expect gamut */ 12098 /* or momochrome table profile (reversable) */ 12099 /* Device <-> PCS */ 12100 /* Gamut Lut - no intent */ 12101 /* Optional preview links PCS <-> PCS */ 12102 12103 /* Determine the algorithm and set its parameters */ 12104 switch (func) { 12105 icTagSignature ttag; 12106 12107 case icmFwd: /* Device to PCS */ 12108 12109 if (intent == icmDefaultIntent) 12110 intent = icRelativeColorimetric; /* Make this the default */ 12111 12112 switch (intent) { 12113 case icRelativeColorimetric: 12114 case icAbsoluteColorimetric: 12115 ttag = icSigAToB1Tag; 12116 break; 12117 case icPerceptual: 12118 ttag = icSigAToB0Tag; 12119 break; 12120 case icSaturation: 12121 ttag = icSigAToB2Tag; 12122 break; 12123 default: 12124 sprintf(p->err,"icc_get_luobj: Unknown intent"); 12125 p->errc = 1; 12126 return NULL; 12127 } 12128 12129 if (order != icmLuOrdRev) { 12130 /* Try Lut type lookup first */ 12131 if ((luobj = new_icmLuLut(p, ttag, 12132 p->header->colorSpace, pcs, pcs, 12133 p->header->colorSpace, e_pcs, e_pcs, 12134 whitePoint, blackPoint, intent, func)) != NULL) 12135 break; 12136 12137 /* See if it could be a matrix lookup */ 12138 if ((luobj = new_icmLuMatrixFwd(p, 12139 p->header->colorSpace, pcs, pcs, 12140 p->header->colorSpace, e_pcs, e_pcs, 12141 whitePoint, blackPoint, intent, func)) != NULL) 12142 break; 12143 12144 /* See if it could be a monochrome lookup */ 12145 if ((luobj = new_icmLuMonoFwd(p, 12146 p->header->colorSpace, pcs, pcs, 12147 p->header->colorSpace, e_pcs, e_pcs, 12148 whitePoint, blackPoint, intent, func)) != NULL) 12149 break; 12150 } else { 12151 /* See if it could be a monochrome lookup */ 12152 if ((luobj = new_icmLuMonoFwd(p, 12153 p->header->colorSpace, pcs, pcs, 12154 p->header->colorSpace, e_pcs, e_pcs, 12155 whitePoint, blackPoint, intent, func)) != NULL) 12156 break; 12157 12158 /* See if it could be a matrix lookup */ 12159 if ((luobj = new_icmLuMatrixFwd(p, 12160 p->header->colorSpace, pcs, pcs, 12161 p->header->colorSpace, e_pcs, e_pcs, 12162 whitePoint, blackPoint, intent, func)) != NULL) 12163 break; 12164 12165 /* Try Lut type lookup last */ 12166 if ((luobj = new_icmLuLut(p, ttag, 12167 p->header->colorSpace, pcs, pcs, 12168 p->header->colorSpace, e_pcs, e_pcs, 12169 whitePoint, blackPoint, intent, func)) != NULL) 12170 break; 12171 } 12172 break; 12173 12174 case icmBwd: /* PCS to Device */ 12175 12176 if (intent == icmDefaultIntent) 12177 intent = icRelativeColorimetric; /* Make this the default */ 12178 12179 switch (intent) { 12180 case icRelativeColorimetric: 12181 case icAbsoluteColorimetric: 12182 ttag = icSigBToA1Tag; 12183 break; 12184 case icPerceptual: 12185 ttag = icSigBToA0Tag; 12186 break; 12187 case icSaturation: 12188 ttag = icSigBToA2Tag; 12189 break; 12190 default: 12191 sprintf(p->err,"icc_get_luobj: Unknown intent"); 12192 p->errc = 1; 12193 return NULL; 12194 } 12195 12196 if (order != icmLuOrdRev) { 12197 /* Try Lut type lookup first */ 12198 if ((luobj = new_icmLuLut(p, ttag, 12199 pcs, p->header->colorSpace, pcs, 12200 e_pcs, p->header->colorSpace, e_pcs, 12201 whitePoint, blackPoint, intent, func)) != NULL) 12202 break; 12203 12204 /* See if it could be a matrix lookup */ 12205 if ((luobj = new_icmLuMatrixBwd(p, 12206 pcs, p->header->colorSpace, pcs, 12207 e_pcs, p->header->colorSpace, e_pcs, 12208 whitePoint, blackPoint, intent, func)) != NULL) 12209 break; 12210 12211 /* See if it could be a monochrome lookup */ 12212 if ((luobj = new_icmLuMonoBwd(p, 12213 pcs, p->header->colorSpace, pcs, 12214 e_pcs, p->header->colorSpace, e_pcs, 12215 whitePoint, blackPoint, intent, func)) != NULL) 12216 break; 12217 } else { 12218 /* See if it could be a monochrome lookup */ 12219 if ((luobj = new_icmLuMonoBwd(p, 12220 pcs, p->header->colorSpace, pcs, 12221 e_pcs, p->header->colorSpace, e_pcs, 12222 whitePoint, blackPoint, intent, func)) != NULL) 12223 break; 12224 12225 /* See if it could be a matrix lookup */ 12226 if ((luobj = new_icmLuMatrixBwd(p, 12227 pcs, p->header->colorSpace, pcs, 12228 e_pcs, p->header->colorSpace, e_pcs, 12229 whitePoint, blackPoint, intent, func)) != NULL) 12230 break; 12231 12232 /* Try Lut type lookup last */ 12233 if ((luobj = new_icmLuLut(p, ttag, 12234 pcs, p->header->colorSpace, pcs, 12235 e_pcs, p->header->colorSpace, e_pcs, 12236 whitePoint, blackPoint, intent, func)) != NULL) 12237 break; 12238 } 12239 break; 12240 12241 case icmGamut: /* PCS to 1D */ 12242 12243 if (intent != icmDefaultIntent) { 12244 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function"); 12245 p->errc = 1; 12246 return NULL; 12247 } 12248 12249 /* If the target tag exists, and it is a Lut */ 12250 luobj = new_icmLuLut(p, icSigGamutTag, 12251 pcs, icSigGrayData, pcs, 12252 e_pcs, icSigGrayData, e_pcs, 12253 whitePoint, blackPoint, intent, func); 12254 break; 12255 12256 case icmPreview: /* PCS to PCS */ 12257 12258 switch (intent) { 12259 case icRelativeColorimetric: 12260 ttag = icSigPreview1Tag; 12261 break; 12262 case icPerceptual: 12263 ttag = icSigPreview0Tag; 12264 break; 12265 case icSaturation: 12266 ttag = icSigPreview2Tag; 12267 break; 12268 case icAbsoluteColorimetric: 12269 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function"); 12270 p->errc = 1; 12271 return NULL; 12272 default: 12273 sprintf(p->err,"icc_get_luobj: Unknown intent"); 12274 p->errc = 1; 12275 return NULL; 12276 } 12277 12278 /* If the target tag exists, and it is a Lut */ 12279 luobj = new_icmLuLut(p, ttag, 12280 pcs, pcs, pcs, 12281 e_pcs, e_pcs, e_pcs, 12282 whitePoint, blackPoint, intent, func); 12283 break; 12284 12285 default: 12286 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested"); 12287 p->errc = 1; 12288 return NULL; 12289 } 12290 break; 12291 12292 case icSigLinkClass: 12293 /* Expect AToB0 Lut and optional BToA0 Lut, One intent in header */ 12294 /* Device <-> Device */ 12295 12296 if (intent != p->header->renderingIntent 12297 && intent != icmDefaultIntent) { 12298 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Link profile"); 12299 p->errc = 1; 12300 return NULL; 12301 } 12302 intent = p->header->renderingIntent; 12303 12304 /* Determine the algorithm and set its parameters */ 12305 switch (func) { 12306 case icmFwd: /* Device to PCS (== Device) */ 12307 12308 luobj = new_icmLuLut(p, icSigAToB0Tag, 12309 p->header->colorSpace, pcs, pcs, 12310 p->header->colorSpace, pcs, pcs, 12311 whitePoint, blackPoint, intent, func); 12312 break; 12313 12314 case icmBwd: /* PCS (== Device) to Device */ 12315 12316 luobj = new_icmLuLut(p, icSigBToA0Tag, 12317 pcs, p->header->colorSpace, pcs, 12318 pcs, p->header->colorSpace, pcs, 12319 whitePoint, blackPoint, intent, func); 12320 break; 12321 12322 default: 12323 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested"); 12324 p->errc = 1; 12325 return NULL; 12326 } 12327 break; 12328 12329 case icSigAbstractClass: 12330 /* Expect AToB0 Lut and BToA Lut, no intents */ 12331 /* PCS <-> PCS */ 12332 /* Determine the algorithm and set its parameters */ 12333 12334 if (intent != icmDefaultIntent) { 12335 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Abstract profile"); 12336 p->errc = 1; 12337 return NULL; 12338 } 12339 12340 switch (func) { 12341 case icmFwd: /* PCS (== Device) to PCS */ 12342 12343 luobj = new_icmLuLut(p, icSigAToB0Tag, 12344 p->header->colorSpace, pcs, pcs, 12345 e_pcs, e_pcs, e_pcs, 12346 whitePoint, blackPoint, intent, func); 12347 break; 12348 12349 case icmBwd: /* PCS to PCS (== Device) */ 12350 12351 luobj = new_icmLuLut(p, icSigBToA0Tag, 12352 pcs, p->header->colorSpace, pcs, 12353 e_pcs, e_pcs, e_pcs, 12354 whitePoint, blackPoint, intent, func); 12355 break; 12356 12357 default: 12358 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested"); 12359 p->errc = 1; 12360 return NULL; 12361 } 12362 break; 12363 12364 case icSigColorSpaceClass: 12365 /* Expect AToB0 Lut and BToA0 Lut, no intents, */ 12366 /* Device <-> PCS */ 12367 12368 if (intent != icmDefaultIntent) { 12369 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Colorspace profile"); 12370 p->errc = 1; 12371 return NULL; 12372 } 12373 12374 /* Determine the algorithm and set its parameters */ 12375 switch (func) { 12376 case icmFwd: /* Device to PCS */ 12377 12378 luobj = new_icmLuLut(p, icSigAToB0Tag, 12379 p->header->colorSpace, pcs, pcs, 12380 p->header->colorSpace, e_pcs, e_pcs, 12381 whitePoint, blackPoint, intent, func); 12382 break; 12383 12384 case icmBwd: /* PCS to Device */ 12385 12386 luobj = new_icmLuLut(p, icSigBToA0Tag, 12387 pcs, p->header->colorSpace, pcs, 12388 e_pcs, p->header->colorSpace, e_pcs, 12389 whitePoint, blackPoint, intent, func); 12390 break; 12391 12392 default: 12393 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested"); 12394 p->errc = 1; 12395 return NULL; 12396 } 12397 break; 12398 12399 case icSigNamedColorClass: 12400 /* Expect Name -> Device, Optional PCS */ 12401 /* and a reverse lookup would be useful */ 12402 /* (ie. PCS or Device coords to closest named color) */ 12403 /* ~~ to be implimented ~~ */ 12404 12405 /* ~~ Absolute intent is valid for processing of */ 12406 /* PCS from named Colors. Also allow for e_pcs */ 12407 if (intent != icmDefaultIntent) { 12408 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Named Color profile"); 12409 p->errc = 1; 12410 return NULL; 12411 } 12412 12413 sprintf(p->err,"icc_get_luobj: Named Colors not handled yet"); 12414 p->errc = 1; 12415 return NULL; 12416 12417 default: 12418 sprintf(p->err,"icc_get_luobj: Unknown profile class"); 12419 p->errc = 1; 12420 return NULL; 12421 } 12422 12423 return luobj; 12424 } 12425 12426 /* - - - - - - - - - - - - - - - - - - - - - - - - */ 12427 12428 /* Create an empty object. Return null on error */ 12429 icc *new_icc_a( 12430 icmAlloc *al /* Optional memory allocator. NULL for default */ 12431 ) { 12432 icc *p; 12433 int del_al = 0; 12434 12435 if (al == NULL) { /* None provided, create default */ 12436 if ((al = new_icmAllocStd()) == NULL) 12437 return NULL; 12438 del_al = 1; /* We need to delete it */ 12439 } 12440 12441 if ((p = (icc *) al->calloc(al, 1,sizeof(icc))) == NULL) 12442 return NULL; 12443 p->al = al; /* Heap allocator */ 12444 p->del_al = del_al; /* Flag noting whether we delete it */ 12445 12446 p->get_size = icc_get_size; 12447 p->read = icc_read; 12448 p->write = icc_write; 12449 p->dump = icc_dump; 12450 p->del = icc_delete; 12451 p->add_tag = icc_add_tag; 12452 p->link_tag = icc_link_tag; 12453 p->find_tag = icc_find_tag; 12454 p->read_tag = icc_read_tag; 12455 p->rename_tag = icc_rename_tag; 12456 p->unread_tag = icc_unread_tag; 12457 p->read_all_tags = icc_read_all_tags; 12458 p->delete_tag = icc_delete_tag; 12459 12460 p->get_luobj = icc_get_luobj; 12461 12462 #if defined(__IBMC__) && defined(_M_IX86) 12463 _control87(EM_UNDERFLOW, EM_UNDERFLOW); 12464 #endif 12465 12466 /* Allocate a header object */ 12467 if ((p->header = new_icmHeader(p)) == NULL) { 12468 al->free(al, p); 12469 if (del_al) 12470 al->del(al); 12471 return NULL; 12472 } 12473 12474 /* Values that must be set before writing */ 12475 p->header->deviceClass = icMaxEnumClass;/* Type of profile - must be set! */ 12476 p->header->colorSpace = icMaxEnumData; /* Clr space of data - must be set! */ 12477 p->header->pcs = icMaxEnumData; /* PCS: XYZ or Lab - must be set! */ 12478 p->header->renderingIntent = icMaxEnumIntent; /* Rendering intent - must be set ! */ 12479 12480 /* Values that should be set before writing */ 12481 p->header->manufacturer = -1; /* Dev manufacturer - should be set ! */ 12482 p->header->model = -1; /* Dev model number - should be set ! */ 12483 p->header->attributes.l = 0; /* ICC Device attributes - should set ! */ 12484 p->header->flags = 0; /* Embedding flags - should be set ! */ 12485 12486 /* Values that may be set before writing */ 12487 p->header->attributes.h = 0; /* Dev Device attributes - may be set ! */ 12488 p->header->creator = str2tag("argl"); /* Profile creator - Argyll - may be set ! */ 12489 12490 /* Init default values in header */ 12491 p->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */ 12492 p->header->majv = 2; /* Current version 2.1.0 */ 12493 p->header->minv = 1; 12494 p->header->bfv = 0; 12495 setcur_DateTimeNumber(&p->header->date);/* Creation Date */ 12496 p->header->platform = icSigMicrosoft; /* Primary Platform */ 12497 p->header->illuminant = icmD50; /* Profile illuminant - D50 */ 12498 12499 return p; 12500 } 12501 12502 12503 /* For backwards compatibility - a NULL allocator version */ 12504 icc *new_icc(void) { 12505 return new_icc_a(NULL); 12506 } 12507 12508 12509 /* ---------------------------------------------------------- */ 12510