1
2 /*
3 * International Color Consortium Format Library (icclib)
4 * For ICC profile version 3.4
5 *
6 * Author: Graeme W. Gill
7 * Date: 2002/04/22
8 * Version: 2.02
9 *
10 * Copyright 1997 - 2002 Graeme W. Gill
11 * See Licence.txt file for conditions of use.
12 */
13
14 /*
15 * TTBD:
16 *
17 * Add a "warning mode" to file reading, in which file format
18 * errors are ignored where possible, rather than generating
19 * a fatal error (see ICM_STRICT #define).
20 *
21 * NameColor Dump doesn't handle device space correctly -
22 * should use appropriate interpretation in case device is Lab etc.
23 *
24 * Should recognise & honour unicode 0xFFFE endian marker.
25 * Should generate it on writing too ?
26 *
27 * Should fix all write_number failure errors to indicate failed value.
28 * (Partially implemented - need to check all write_number functions)
29 *
30 * Make write fail error messages be specific on which element failed.
31 *
32 * Should add named color space lookup function support.
33 *
34 * Should probably reject reading or writing profiles with majv != 2 ?
35 *
36 * Would be nice to add generic ability to add new tag type handling,
37 * so that the base library doesn't need to be modified (ie. VideoCardGamma) ?
38 *
39 * Need to add DeviceSettings and OutputResponse tags to bring up to
40 * ICC.1:1998-09 [started but not complete]
41 *
42 */
43
44 #undef ICM_STRICT /* Not fully implimented - switch off strict checking of file format */
45
46 /* Trial: Make the default grid points of the Lab clut be symetrical about */
47 /* a/b 0.0, and also make L = 100.0 fall on a grid point. */
48 /* This seems a good idea. */
49
50 #define SYMETRICAL_DEFAULT_LAB_RANGE
51
52 /*
53 * Change History:
54 *
55 * 2.02
56 * Merged rename of [u]int64 to icm[Ui][I]nt64 (to work around
57 * AIX 5.1L portability bug) from Raph Levien.
58 *
59 * Fixed stray , in icmLookupOrder structure definition (from Dan Coby)
60 *
61 * 2.01
62 * Change TextDescription code to not barf if #undef ICM_STRICT and
63 * Apple scriptcode not padded to 67 bytes.
64 *
65 * Add get_ranges() method to all Lu types, not just LuLut.
66 * Fix bug in PCS overide logic that was causing
67 * reverse conversions to apply the wrong conversion.
68 *
69 * Added Delta E convenience functions icmLabDE() and
70 * icmCIE94() etc.
71 *
72 * Merged Raph Levien's cleanups, to quiet gcc warnings.
73 *
74 * Merged another couple of warning cleanups from Jouk Jansen.
75 *
76 * 2.00
77 * Change absolute conversion to be white point only, and use
78 * Bradford transform by default. (ie. we are now ignoring the
79 * comment in section 6.4.22 of the 1998 spec. about the
80 * media black point being used for absolute colorimetry,
81 * ignoring the recommendation on page 118 in section E.5,
82 * and are taking up the recommendation on page 124 in section
83 * E.16 that a more sophisticated chromatic adaption model be used.)
84 *
85 * This is for better compatibility with other CMM's, and to
86 * improve the results when using simple links between
87 * profiles with non-D50 white points. Standard profiles
88 * like sRGB will also be more accurate when interpreted
89 * with absolute colorimetric intent.
90 * This will cause some slight incompatibilty with previous
91 * versions of icclib.
92 *
93 * Added ColorSync 2.5 specific VideoCardGamma tag support
94 * (from Neil Okamoto)
95 *
96 * 1.31
97 * Added file I/O class to allow substitution of alternative ICC profile
98 * file access. Provide standard file class instance, and memory image
99 * instance of file I/O class as default and example.
100 * Added an optional new_icc_a() object creator, that takes a memory
101 * allocator class instance. This allows an alternate memory heap to
102 * be used with the icc class.
103 * Renamed object free() methods to del() for more consistency with new().
104 *
105 * 1.30
106 * Added workaround for reading some Adobe profiles with confused header DateTime.
107 * Enhanced tag allocate() methods so that they can resize allocations.
108 * Enhanced icmLut_set_tables() to access grid points in a cache friendly order.
109 * Fixed bug in check_icc_legal() that caused bogus errors, removed
110 * uneccessary static declarations in icc.h, and fixed a bug in
111 * icmTable_lookup_bwd() that effected both accuracy and speed. (Thanks to Andrei Frolov)
112 * Removed icmAbsoluteColorimetricXYZ intent, and replaced it with
113 * a PCS overide capability. This adds a new parameter to get_luobj()
114 * Added Lab translations of some XYZ "dump" strings.
115 * Fix memory leak after failed tag read + rename_tag function
116 * + shared library support changes. (Thanks to Carles Llopis).
117 * Changed all the public 2str utility routines to a single function
118 * that can be used to interpret an enumeration or tag in a human
119 * readable form.
120 *
121 * 1.23
122 * Fixed important bug in Lut read/write. The matrix values had their
123 * rows and columns switched. Not many profiles exercise this code.
124 * Thanks to David Gillman for discovering this problem.
125 * Fixup compiler complains about illegal enum values for icmCurveStyle,
126 * and icmDataStyle. Malloc memory icmLut_lookup_clut_nl for gw[], so that
127 * it is more friendly to systems with a limited stack. (Thanks to Dave White)
128 *
129 * 1.22 99/11/11 Snapshot of current code.
130 * Added more hooks to support inherited implementation of
131 * color conversion, used in Argyll to support reversing
132 * multi-dimentional table lookups.
133 * Cleaned up color conversion code to make it easier to follow.
134 * Adding simplex interpolation for non-Lab style input space interpolation.
135 * Fix Sun misalignment and realloc problems (Thanks to Allan N. Hessenflow)
136 * Fixed endian problem with Unicode on read and write.
137 * Expanded icmTextDescription_dump() to do hex dump of Unicode and ScriptCode.
138 * Changed over to ICC.1:1998-09 .h file.
139 * Started implementing ICC.1:1998-09, but not complete yet!
140 *
141 * 1.21 99/2/14
142 * After re-reading Michael Bourgoin's 1998 SIGGRAPH notes,
143 * I have consolidated the Lut input index, and table value encodings.
144 * The default set_tables() scaling has been adjusted appropriately
145 * for this correction of Lab encoding.
146 * Trying to create an 8 bit XYZ Lut will now fail if icclib helper
147 * functions are used to create it.
148 *
149 * 1.20 99/2/7
150 * Added profile color lookup functon.
151 * Added set_tables() support.
152 * Various bug fixes and enhancements.
153 */
154
155 #include <stdio.h>
156 #include <stdlib.h>
157 #include <stdarg.h>
158 #include <sys/types.h>
159 #include <string.h>
160 #include <ctype.h>
161 #include <math.h>
162 #include <time.h>
163 #ifdef __sun
164 #include <unistd.h>
165 #endif
166 #if defined(__IBMC__) && defined(_M_IX86)
167 #include <float.h>
168 #endif
169 #include "icc.h"
170
171 /* ========================================================== */
172 /* Default system interface object implementations */
173
174 /* Standard Stream file I/O icmFile compatible class */
175 /* Note that this uses malloc, so replace class if */
176 /* you need a different memory allocator. */
177
178 /* Set current position to offset. Return 0 on success, nz on failure. */
icmFileStd_seek(icmFile * pp,long int offset)179 static int icmFileStd_seek(
180 icmFile *pp,
181 long int offset
182 ) {
183 icmFileStd *p = (icmFileStd *)pp;
184
185 return fseek(p->fp, offset, SEEK_SET);
186 }
187
188 /* Read count items of size length. Return number of items successfully read. */
icmFileStd_read(icmFile * pp,void * buffer,size_t size,size_t count)189 static size_t icmFileStd_read(
190 icmFile *pp,
191 void *buffer,
192 size_t size,
193 size_t count
194 ) {
195 icmFileStd *p = (icmFileStd *)pp;
196
197 return fread(buffer, size, count, p->fp);
198 }
199
200 /* write count items of size length. Return number of items successfully written. */
icmFileStd_write(icmFile * pp,void * buffer,size_t size,size_t count)201 static size_t icmFileStd_write(
202 icmFile *pp,
203 void *buffer,
204 size_t size,
205 size_t count
206 ) {
207 icmFileStd *p = (icmFileStd *)pp;
208
209 return fwrite(buffer, size, count, p->fp);
210 }
211
212
213 /* flush all write data out to secondary storage. Return nz on failure. */
icmFileStd_flush(icmFile * pp)214 static int icmFileStd_flush(
215 icmFile *pp
216 ) {
217 icmFileStd *p = (icmFileStd *)pp;
218
219 return fflush(p->fp);
220 }
221
222 /* we're done with the file object, return nz on failure */
icmFileStd_delete(icmFile * pp)223 static int icmFileStd_delete(
224 icmFile *pp
225 ) {
226 icmFileStd *p = (icmFileStd *)pp;
227
228 if (p->doclose != 0) {
229 if (fclose(p->fp) != 0)
230 return 2;
231 }
232
233 free(p);
234 return 0;
235 }
236
237 /* Create icmFile given a (binary) FILE* */
new_icmFileStd_fp(FILE * fp)238 icmFile *new_icmFileStd_fp(
239 FILE *fp
240 ) {
241 icmFileStd *p;
242 if ((p = (icmFileStd *) calloc(1,sizeof(icmFileStd))) == NULL)
243 return NULL;
244 p->seek = icmFileStd_seek;
245 p->read = icmFileStd_read;
246 p->write = icmFileStd_write;
247 p->flush = icmFileStd_flush;
248 p->del = icmFileStd_delete;
249
250 p->fp = fp;
251 p->doclose = 0;
252
253 return (icmFile *)p;
254 }
255
256 /* Create icmFile given a file name */
new_icmFileStd_name(char * name,char * mode)257 icmFile *new_icmFileStd_name(
258 char *name,
259 char *mode
260 ) {
261 FILE *fp;
262 icmFile *p;
263 #if defined(O_BINARY)
264 char nmode[50];
265 #endif
266
267 if ((fp = fopen(name,mode)) == NULL)
268 return NULL;
269
270 #if defined(O_BINARY)
271 strcpy(nmode, mode);
272 strcat(nmode, "b");
273 if ((fp = freopen(name, nmode, fp)) == NULL)
274 return NULL;
275 #endif
276
277 p = new_icmFileStd_fp(fp);
278
279 if (p != NULL) {
280 icmFileStd *pp = (icmFileStd *)p;
281 pp->doclose = 1;
282 }
283 return p;
284 }
285
286 /* ------------------------------------------------- */
287 /* Memory image icmFile compatible class */
288 /* Note that this uses malloc, so replace class if */
289 /* you need a different memory allocator. */
290
291 /* Set current position to offset. Return 0 on success, nz on failure. */
icmFileMem_seek(icmFile * pp,long int offset)292 static int icmFileMem_seek(
293 icmFile *pp,
294 long int offset
295 ) {
296 icmFileMem *p = (icmFileMem *)pp;
297 unsigned char *np;
298
299 np = p->start + offset;
300 if (np < p->start || np >= p->end)
301 return 1;
302 p->cur = np;
303 return 0;
304 }
305
306 /* Read count items of size length. Return number of items successfully read. */
icmFileMem_read(icmFile * pp,void * buffer,size_t size,size_t count)307 static size_t icmFileMem_read(
308 icmFile *pp,
309 void *buffer,
310 size_t size,
311 size_t count
312 ) {
313 icmFileMem *p = (icmFileMem *)pp;
314 size_t len;
315
316 len = size * count;
317 if ((p->cur + len) >= p->end) { /* Too much */
318 if (size > 0)
319 count = (p->end - p->cur)/size;
320 else
321 count = 0;
322 }
323 len = size * count;
324 if (len > 0)
325 memcpy (buffer, p->cur, len);
326 p->cur += len;
327 return count;
328 }
329
330 /* write count items of size length. Return number of items successfully written. */
icmFileMem_write(icmFile * pp,void * buffer,size_t size,size_t count)331 static size_t icmFileMem_write(
332 icmFile *pp,
333 void *buffer,
334 size_t size,
335 size_t count
336 ) {
337 icmFileMem *p = (icmFileMem *)pp;
338 size_t len;
339
340 len = size * count;
341 if ((p->cur + len) >= p->end) { /* Too much */
342 if (size > 0)
343 count = (p->end - p->cur)/size;
344 else
345 count = 0;
346 }
347 len = size * count;
348 if (len > 0)
349 memcpy (p->cur, buffer, len);
350 p->cur += len;
351 return count;
352 }
353
354
355 /* flush all write data out to secondary storage. Return nz on failure. */
icmFileMem_flush(icmFile * pp)356 static int icmFileMem_flush(
357 icmFile *pp
358 ) {
359 return 0;
360 }
361
362 /* we're done with the file object, return nz on failure */
icmFileMem_delete(icmFile * pp)363 static int icmFileMem_delete(
364 icmFile *pp
365 ) {
366 icmFileMem *p = (icmFileMem *)pp;
367
368 free(p);
369 return 0;
370 }
371
372 /* Create a memory image file access class */
new_icmFileMem(void * base,size_t length)373 icmFile *new_icmFileMem(
374 void *base, /* Pointer to base of memory buffer */
375 size_t length /* Number of bytes in buffer */
376 ) {
377 icmFileMem *p;
378 if ((p = (icmFileMem *) calloc(1,sizeof(icmFileMem))) == NULL)
379 return NULL;
380 p->seek = icmFileMem_seek;
381 p->read = icmFileMem_read;
382 p->write = icmFileMem_write;
383 p->flush = icmFileMem_flush;
384 p->del = icmFileMem_delete;
385
386 p->cur = p->start = base;
387 p->end = p->start + length;
388
389 return (icmFile *)p;
390 }
391
392 /* ------------------------------------------------- */
393 /* Standard Heap allocator icmAlloc compatible class */
394 /* Just call the standard system function */
395
icmAllocStd_malloc(struct _icmAlloc * pp,size_t size)396 static void *icmAllocStd_malloc(
397 struct _icmAlloc *pp,
398 size_t size
399 ) {
400 return malloc(size);
401 }
402
icmAllocStd_calloc(struct _icmAlloc * pp,size_t num,size_t size)403 static void *icmAllocStd_calloc(
404 struct _icmAlloc *pp,
405 size_t num,
406 size_t size
407 ) {
408 return calloc(num, size);
409 }
410
icmAllocStd_realloc(struct _icmAlloc * pp,void * ptr,size_t size)411 static void *icmAllocStd_realloc(
412 struct _icmAlloc *pp,
413 void *ptr,
414 size_t size
415 ) {
416 return realloc(ptr, size);
417 }
418
419
icmAllocStd_free(struct _icmAlloc * pp,void * ptr)420 static void icmAllocStd_free(
421 struct _icmAlloc *pp,
422 void *ptr
423 ) {
424 free(ptr);
425 }
426
427 /* we're done with the AllocStd object */
icmAllocStd_delete(icmAlloc * pp)428 static void icmAllocStd_delete(
429 icmAlloc *pp
430 ) {
431 icmAllocStd *p = (icmAllocStd *)pp;
432
433 free(p);
434 }
435
436 /* Create icmAllocStd */
new_icmAllocStd()437 icmAlloc *new_icmAllocStd() {
438 icmAllocStd *p;
439 if ((p = (icmAllocStd *) calloc(1,sizeof(icmAllocStd))) == NULL)
440 return NULL;
441 p->malloc = icmAllocStd_malloc;
442 p->calloc = icmAllocStd_calloc;
443 p->realloc = icmAllocStd_realloc;
444 p->free = icmAllocStd_free;
445 p->del = icmAllocStd_delete;
446
447 return (icmAlloc *)p;
448 }
449
450 /* ========================================================== */
451 /* Conversion support functions */
452 /* Convert between ICC storage types and native C types */
453 /* Write routine return non-zero if numbers can't be represented */
454
455 /* Unsigned */
read_UInt8Number(char * p)456 static unsigned int read_UInt8Number(char *p) {
457 unsigned int rv;
458 rv = (unsigned int)((ORD8 *)p)[0];
459 return rv;
460 }
461
write_UInt8Number(unsigned int d,char * p)462 static int write_UInt8Number(unsigned int d, char *p) {
463 if (d > 255)
464 return 1;
465 ((ORD8 *)p)[0] = (ORD8)d;
466 return 0;
467 }
468
read_UInt16Number(char * p)469 static unsigned int read_UInt16Number(char *p) {
470 unsigned int rv;
471 rv = 256 * (unsigned int)((ORD8 *)p)[0]
472 + (unsigned int)((ORD8 *)p)[1];
473 return rv;
474 }
475
write_UInt16Number(unsigned int d,char * p)476 static int write_UInt16Number(unsigned int d, char *p) {
477 if (d > 65535)
478 return 1;
479 ((ORD8 *)p)[0] = (ORD8)(d >> 8);
480 ((ORD8 *)p)[1] = (ORD8)(d);
481 return 0;
482 }
483
read_UInt32Number(char * p)484 static unsigned int read_UInt32Number(char *p) {
485 unsigned int rv;
486 rv = 16777216 * (unsigned int)((ORD8 *)p)[0]
487 + 65536 * (unsigned int)((ORD8 *)p)[1]
488 + 256 * (unsigned int)((ORD8 *)p)[2]
489 + (unsigned int)((ORD8 *)p)[3];
490 return rv;
491 }
492
write_UInt32Number(unsigned int d,char * p)493 static int write_UInt32Number(unsigned int d, char *p) {
494 ((ORD8 *)p)[0] = (ORD8)(d >> 24);
495 ((ORD8 *)p)[1] = (ORD8)(d >> 16);
496 ((ORD8 *)p)[2] = (ORD8)(d >> 8);
497 ((ORD8 *)p)[3] = (ORD8)(d);
498 return 0;
499 }
500
read_UInt64Number(icmUint64 * d,char * p)501 static void read_UInt64Number(icmUint64 *d, char *p) {
502 d->h = 16777216 * (unsigned int)((ORD8 *)p)[0]
503 + 65536 * (unsigned int)((ORD8 *)p)[1]
504 + 256 * (unsigned int)((ORD8 *)p)[2]
505 + (unsigned int)((ORD8 *)p)[3];
506 d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
507 + 65536 * (unsigned int)((ORD8 *)p)[5]
508 + 256 * (unsigned int)((ORD8 *)p)[6]
509 + (unsigned int)((ORD8 *)p)[7];
510 }
511
write_UInt64Number(icmUint64 * d,char * p)512 static int write_UInt64Number(icmUint64 *d, char *p) {
513 ((ORD8 *)p)[0] = (ORD8)(d->h >> 24);
514 ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
515 ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
516 ((ORD8 *)p)[3] = (ORD8)(d->h);
517 ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
518 ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
519 ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
520 ((ORD8 *)p)[7] = (ORD8)(d->l);
521 return 0;
522 }
523
read_U8Fixed8Number(char * p)524 static double read_U8Fixed8Number(char *p) {
525 ORD32 o32;
526 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
527 + (ORD32)((ORD8 *)p)[1];
528 return (double)o32/256.0;
529 }
530
write_U8Fixed8Number(double d,char * p)531 static int write_U8Fixed8Number(double d, char *p) {
532 ORD32 o32;
533 d = d * 256.0 + 0.5;
534 if (d >= 65536.0)
535 return 1;
536 if (d < 0.0)
537 return 1;
538 o32 = (ORD32)d;
539 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
540 ((ORD8 *)p)[1] = (ORD8)((o32));
541 return 0;
542 }
543
read_U16Fixed16Number(char * p)544 static double read_U16Fixed16Number(char *p) {
545 ORD32 o32;
546 o32 = 16777216 * (ORD32)((ORD8 *)p)[0] /* Read big endian 32 bit unsigned */
547 + 65536 * (ORD32)((ORD8 *)p)[1]
548 + 256 * (ORD32)((ORD8 *)p)[2]
549 + (ORD32)((ORD8 *)p)[3];
550 return (double)o32/65536.0;
551 }
552
write_U16Fixed16Number(double d,char * p)553 static int write_U16Fixed16Number(double d, char *p) {
554 ORD32 o32;
555 d = d * 65536.0 + 0.5;
556 if (d >= 4294967296.0)
557 return 1;
558 if (d < 0.0)
559 return 1;
560 o32 = (ORD32)d;
561 ((ORD8 *)p)[0] = (ORD8)((o32) >> 24);
562 ((ORD8 *)p)[1] = (ORD8)((o32) >> 16);
563 ((ORD8 *)p)[2] = (ORD8)((o32) >> 8);
564 ((ORD8 *)p)[3] = (ORD8)((o32));
565 return 0;
566 }
567
568
569 #ifdef NEVER /* Not currently used anywhere */
570
571 /* Signed numbers */
read_SInt8Number(char * p)572 static int read_SInt8Number(char *p) {
573 int rv;
574 rv = (int)((INR8 *)p)[0];
575 return rv;
576 }
577
write_SInt8Number(int d,char * p)578 static int write_SInt8Number(int d, char *p) {
579 if (d > 127)
580 return 1;
581 else if (d < -128)
582 return 1;
583 ((INR8 *)p)[0] = (INR8)d;
584 return 0;
585 }
586
read_SInt16Number(char * p)587 static int read_SInt16Number(char *p) {
588 int rv;
589 rv = 256 * (int)((INR8 *)p)[0]
590 + (int)((ORD8 *)p)[1];
591 return rv;
592 }
593
write_SInt16Number(int d,char * p)594 static int write_SInt16Number(int d, char *p) {
595 if (d > 32767)
596 return 1;
597 else if (d < -32768)
598 return 1;
599 ((INR8 *)p)[0] = (INR8)(d >> 8);
600 ((ORD8 *)p)[1] = (ORD8)(d);
601 return 0;
602 }
603
604 #endif /* NEVER */
605
read_SInt32Number(char * p)606 static int read_SInt32Number(char *p) {
607 int rv;
608 rv = 16777216 * (int)((INR8 *)p)[0]
609 + 65536 * (int)((ORD8 *)p)[1]
610 + 256 * (int)((ORD8 *)p)[2]
611 + (int)((ORD8 *)p)[3];
612 return rv;
613 }
614
write_SInt32Number(int d,char * p)615 static int write_SInt32Number(int d, char *p) {
616 ((INR8 *)p)[0] = (INR8)(d >> 24);
617 ((ORD8 *)p)[1] = (ORD8)(d >> 16);
618 ((ORD8 *)p)[2] = (ORD8)(d >> 8);
619 ((ORD8 *)p)[3] = (ORD8)(d);
620 return 0;
621 }
622
623 #ifdef NEVER /* Not currently used anywhere */
624
read_SInt64Number(icmInt64 * d,char * p)625 static void read_SInt64Number(icmInt64 *d, char *p) {
626 d->h = 16777216 * (int)((INR8 *)p)[0]
627 + 65536 * (int)((ORD8 *)p)[1]
628 + 256 * (int)((ORD8 *)p)[2]
629 + (int)((ORD8 *)p)[3];
630 d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
631 + 65536 * (unsigned int)((ORD8 *)p)[5]
632 + 256 * (unsigned int)((ORD8 *)p)[6]
633 + (unsigned int)((ORD8 *)p)[7];
634 }
635
write_SInt64Number(icmInt64 * d,char * p)636 static int write_SInt64Number(icmInt64 *d, char *p) {
637 ((INR8 *)p)[0] = (INR8)(d->h >> 24);
638 ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
639 ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
640 ((ORD8 *)p)[3] = (ORD8)(d->h);
641 ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
642 ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
643 ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
644 ((ORD8 *)p)[7] = (ORD8)(d->l);
645 return 0;
646 }
647
648 #endif /* NEVER */
649
read_S15Fixed16Number(char * p)650 static double read_S15Fixed16Number(char *p) {
651 INR32 i32;
652 i32 = 16777216 * (INR32)((INR8 *)p)[0] /* Read big endian 32 bit signed */
653 + 65536 * (INR32)((ORD8 *)p)[1]
654 + 256 * (INR32)((ORD8 *)p)[2]
655 + (INR32)((ORD8 *)p)[3];
656 return (double)i32/65536.0;
657 }
658
write_S15Fixed16Number(double d,char * p)659 static int write_S15Fixed16Number(double d, char *p) {
660 INR32 i32;
661 d = ceil(d * 65536.0); /* Beware! (int)(d + 0.5) doesn't work! */
662 if (d >= 2147483648.0)
663 return 1;
664 if (d < -2147483648.0)
665 return 1;
666 i32 = (INR32)d;
667 ((INR8 *)p)[0] = (INR8)((i32) >> 24); /* Write big endian 32 bit signed */
668 ((ORD8 *)p)[1] = (ORD8)((i32) >> 16);
669 ((ORD8 *)p)[2] = (ORD8)((i32) >> 8);
670 ((ORD8 *)p)[3] = (ORD8)((i32));
671 return 0;
672 }
673
674 /* PCS encoded numbers */
675
676 /* 16 bit XYZ - value range 0.0 - 1.9997 */
read_PCSXYZ16Number(char * p)677 static double read_PCSXYZ16Number(char *p) {
678 ORD32 o32;
679 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
680 + (ORD32)((ORD8 *)p)[1];
681 return (double)o32/32768.0;
682 }
683
write_PCSXYZ16Number(double d,char * p)684 static int write_PCSXYZ16Number(double d, char *p) {
685 ORD32 o32;
686 d = d * 32768.0 + 0.5;
687 if (d >= 65536.0)
688 return 1;
689 if (d < 0.0)
690 return 1;
691 o32 = (ORD32)d;
692 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
693 ((ORD8 *)p)[1] = (ORD8)((o32));
694 return 0;
695 }
696
697 #ifdef NEVER /* Not currently used */
698
699 /* L part of 8 bit Lab - value range 0.0 - 100.0 */
read_PCSL8Number(char * p)700 static double read_PCSL8Number(char *p) {
701 ORD32 o32;
702 o32 = (ORD32)((ORD8 *)p)[0]; /* Read big endian 8 bit unsigned */
703 return (double)o32/2.550;
704 }
705
write_PCSL8Number(double d,char * p)706 static int write_PCSL8Number(double d, char *p) {
707 ORD32 o32;
708 d = d * 2.550 + 0.5;
709 if (d >= 256.0)
710 return 1;
711 if (d < 0.0)
712 return 1;
713 o32 = (ORD32)d;
714 ((ORD8 *)p)[0] = (ORD8)((o32));
715 return 0;
716 }
717
718 /* ab part of 8 bit Lab - value range -128.0 - 127.0 */
read_PCSab8Number(char * p)719 static double read_PCSab8Number(char *p) {
720 ORD32 o32;
721 o32 = (ORD32)((ORD8 *)p)[0]; /* Read big endian 8 bit unsigned */
722 return (double)o32-128.0;
723 }
724
write_PCSab8Number(double d,char * p)725 static int write_PCSab8Number(double d, char *p) {
726 ORD32 o32;
727 d = (d+128.0) + 0.5;
728 if (d >= 256.0)
729 return 1;
730 if (d < 0.0)
731 return 1;
732 o32 = (ORD32)d;
733 ((ORD8 *)p)[0] = (ORD8)((o32));
734 return 0;
735 }
736
737 #endif /* NEVER */
738
739 /* L part of 16 bit Lab - value range 0.0 - 100.0 */
read_PCSL16Number(char * p)740 static double read_PCSL16Number(char *p) {
741 ORD32 o32;
742 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
743 + (ORD32)((ORD8 *)p)[1];
744 return (double)o32/652.800; /* 0xff00/100.0 */
745 }
746
write_PCSL16Number(double d,char * p)747 static int write_PCSL16Number(double d, char *p) {
748 ORD32 o32;
749 d = d * 652.800 + 0.5;
750 if (d >= 65536.0)
751 return 1;
752 if (d < 0.0)
753 return 1;
754 o32 = (ORD32)d;
755 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
756 ((ORD8 *)p)[1] = (ORD8)((o32));
757 return 0;
758 }
759
760 /* ab part of 16 bit Lab - value range -128.0 - 127.9961 */
read_PCSab16Number(char * p)761 static double read_PCSab16Number(char *p) {
762 ORD32 o32;
763 o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
764 + (ORD32)((ORD8 *)p)[1];
765 return ((double)o32/256.0)-128.0;
766 }
767
write_PCSab16Number(double d,char * p)768 static int write_PCSab16Number(double d, char *p) {
769 ORD32 o32;
770 d = (d+128.0) * 256.0 + 0.5;
771 if (d >= 65536.0)
772 return 1;
773 if (d < 0.0)
774 return 1;
775 o32 = (ORD32)d;
776 ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
777 ((ORD8 *)p)[1] = (ORD8)((o32));
778 return 0;
779 }
780
781 /* Device coordinate as 8 bit value range 0.0 - 1.0 */
read_DCS8Number(char * p)782 static double read_DCS8Number(char *p) {
783 unsigned int rv;
784 rv = (unsigned int)((ORD8 *)p)[0];
785 return (double)rv/255.0;
786 }
787
write_DCS8Number(double d,char * p)788 static int write_DCS8Number(double d, char *p) {
789 ORD32 o32;
790 d = d * 255.0 + 0.5;
791 if (d >= 256.0)
792 return 1;
793 if (d < 0.0)
794 return 1;
795 o32 = (ORD32)d;
796 ((ORD8 *)p)[0] = (ORD8)(o32);
797 return 0;
798 }
799
800 /* Device coordinate as 16 bit value range 0.0 - 1.0 */
read_DCS16Number(char * p)801 static double read_DCS16Number(char *p) {
802 unsigned int rv;
803 rv = 256 * (unsigned int)((ORD8 *)p)[0]
804 + (unsigned int)((ORD8 *)p)[1];
805 return (double)rv/65535.0;
806 }
807
write_DCS16Number(double d,char * p)808 static int write_DCS16Number(double d, char *p) {
809 ORD32 o32;
810 d = d * 65535.0 + 0.5;
811 if (d >= 65536.0)
812 return 1;
813 if (d < 0.0)
814 return 1;
815 o32 = (ORD32)d;
816 ((ORD8 *)p)[0] = (ORD8)(o32 >> 8);
817 ((ORD8 *)p)[1] = (ORD8)(o32);
818 return 0;
819 }
820
821 /* ---------------------------------------------------------- */
822 /* Auiliary function - return a string that represents a tag */
823 /* Note - returned buffers are static, can only be used 5 */
824 /* times before buffers get reused. */
tag2str(int tag)825 char *tag2str(
826 int tag
827 ) {
828 int i;
829 static int si = 0; /* String buffer index */
830 static char buf[5][20]; /* String buffers */
831 char *bp;
832 unsigned char c[4];
833
834 bp = buf[si++];
835 si %= 5; /* Rotate through buffers */
836
837 c[0] = 0xff & (tag >> 24);
838 c[1] = 0xff & (tag >> 16);
839 c[2] = 0xff & (tag >> 8);
840 c[3] = 0xff & (tag >> 0);
841 for (i = 0; i < 4; i++) { /* Can we represent it as a string ? */
842 if (!isprint(c[i]))
843 break;
844 }
845 if (i < 4) { /* Not printable - use hex */
846 sprintf(bp,"0x%x",tag);
847 } else { /* Printable */
848 sprintf(bp,"'%c%c%c%c'",c[0],c[1],c[2],c[3]);
849 }
850 return bp;
851 }
852
853 /* Auiliary function - return a tag created from a string */
str2tag(const char * str)854 int str2tag(
855 const char *str
856 ) {
857 unsigned long tag;
858 tag = (((unsigned long)str[0]) << 24)
859 + (((unsigned long)str[1]) << 16)
860 + (((unsigned long)str[2]) << 8)
861 + (((unsigned long)str[3]));
862 return (int)tag;
863 }
864
865 /* helper - return 1 if the string doesn't have a */
866 /* null terminator, return 0 if it does. */
867 /* Note: will return 1 if len == 0 */
check_null_string(char * cp,int len)868 static int check_null_string(char *cp, int len) {
869 for (; len > 0; len--) {
870 if (*cp++ == '\000')
871 break;
872 }
873 if (len == 0)
874 return 1;
875 return 0;
876 }
877
878 /* helper - return 1 if the string doesn't have a */
879 /* null terminator, return 0 if it does. */
880 /* Note: will return 1 if len == 0 */
881 /* Unicode version */
check_null_string16(char * cp,int len)882 static int check_null_string16(char *cp, int len) {
883 for (; len > 0; len--) { /* Length is in characters */
884 if (cp[0] == 0 && cp[1] == 0)
885 break;
886 cp += 2;
887 }
888 if (len == 0)
889 return 1;
890 return 0;
891 }
892
893 /* Color Space to number of component conversion */
894 /* Return 0 on error */
number_ColorSpaceSignature(icColorSpaceSignature sig)895 static unsigned int number_ColorSpaceSignature(icColorSpaceSignature sig) {
896 switch(sig) {
897 case icSigXYZData:
898 return 3;
899 case icSigLabData:
900 return 3;
901 case icSigLuvData:
902 return 3;
903 case icSigYCbCrData:
904 return 3;
905 case icSigYxyData:
906 return 3;
907 case icSigRgbData:
908 return 3;
909 case icSigGrayData:
910 return 1;
911 case icSigHsvData:
912 return 3;
913 case icSigHlsData:
914 return 3;
915 case icSigCmykData:
916 return 4;
917 case icSigCmyData:
918 return 3;
919 case icSig2colorData:
920 return 2;
921 case icSig3colorData:
922 return 3;
923 case icSig4colorData:
924 return 4;
925 case icSig5colorData:
926 case icSigMch5Data:
927 return 5;
928 case icSig6colorData:
929 case icSigMch6Data:
930 return 6;
931 case icSig7colorData:
932 case icSigMch7Data:
933 return 7;
934 case icSig8colorData:
935 case icSigMch8Data:
936 return 8;
937 case icSig9colorData:
938 return 9;
939 case icSig10colorData:
940 return 10;
941 case icSig11colorData:
942 return 11;
943 case icSig12colorData:
944 return 12;
945 case icSig13colorData:
946 return 13;
947 case icSig14colorData:
948 return 14;
949 case icSig15colorData:
950 return 15;
951 default:
952 return 0;
953 }
954 }
955
956 /* ------------------------------------------------------- */
957 /* Flag dump functions */
958 /* Note - returned buffers are static, can only be used 5 */
959 /* times before buffers get reused. */
960
961 /* Screening Encodings */
string_ScreenEncodings(unsigned long flags)962 static char *string_ScreenEncodings(unsigned long flags) {
963 static int si = 0; /* String buffer index */
964 static char buf[5][80]; /* String buffers */
965 char *bp, *cp;
966
967 cp = bp = buf[si++];
968 si %= 5; /* Rotate through buffers */
969
970 if (flags & icPrtrDefaultScreensTrue) {
971 sprintf(cp,"Default Screen");
972 } else {
973 sprintf(cp,"No Default Screen");
974 }
975 cp = cp + strlen(cp);
976 if (flags & icLinesPerInch) {
977 sprintf(cp,", Lines Per Inch");
978 } else {
979 sprintf(cp,", Lines Per cm");
980 }
981 cp = cp + strlen(cp);
982
983 return bp;
984 }
985
986 /* Device attributes */
string_DeviceAttributes(unsigned long flags)987 static char *string_DeviceAttributes(unsigned long flags) {
988 static int si = 0; /* String buffer index */
989 static char buf[5][80]; /* String buffers */
990 char *bp, *cp;
991
992 cp = bp = buf[si++];
993 si %= 5; /* Rotate through buffers */
994
995 if (flags & icTransparency) {
996 sprintf(cp,"Transparency");
997 } else {
998 sprintf(cp,"Reflective");
999 }
1000 cp = cp + strlen(cp);
1001 if (flags & icMatte) {
1002 sprintf(cp,", Matte");
1003 } else {
1004 sprintf(cp,", Glossy");
1005 }
1006 cp = cp + strlen(cp);
1007
1008 return bp;
1009 }
1010
1011 /* Profile header flags */
string_ProfileHeaderFlags(unsigned long flags)1012 static char *string_ProfileHeaderFlags(unsigned long flags) {
1013 static int si = 0; /* String buffer index */
1014 static char buf[5][80]; /* String buffers */
1015 char *bp, *cp;
1016
1017 cp = bp = buf[si++];
1018 si %= 5; /* Rotate through buffers */
1019
1020 if (flags & icEmbeddedProfileTrue) {
1021 sprintf(cp,"Embedded Profile");
1022 } else {
1023 sprintf(cp,"Not Embedded Profile");
1024 }
1025 cp = cp + strlen(cp);
1026 if (flags & icUseWithEmbeddedDataOnly) {
1027 sprintf(cp,", Use with embedded data only");
1028 } else {
1029 sprintf(cp,", Use anywhere");
1030 }
1031 cp = cp + strlen(cp);
1032
1033 return bp;
1034 }
1035
1036
string_AsciiOrBinaryData(unsigned long flags)1037 static char *string_AsciiOrBinaryData(unsigned long flags) {
1038 static int si = 0; /* String buffer index */
1039 static char buf[5][80]; /* String buffers */
1040 char *bp, *cp;
1041
1042 cp = bp = buf[si++];
1043 si %= 5; /* Rotate through buffers */
1044
1045 if (flags & icBinaryData) {
1046 sprintf(cp,"Binary");
1047 } else {
1048 sprintf(cp,"Ascii");
1049 }
1050 cp = cp + strlen(cp);
1051
1052 return bp;
1053 }
1054
1055 /* ------------------------------------------------------------ */
1056 /* Enumeration dump functions */
1057 /* Note - returned buffers are static, can only be used once */
1058 /* before buffers get reused if type is unknown. */
1059
1060 /* public tags and sizes */
string_TagSignature(icTagSignature sig)1061 static const char *string_TagSignature(icTagSignature sig) {
1062 static char buf[80];
1063 switch(sig) {
1064 case icSigAToB0Tag:
1065 return "AToB0 Multidimentional Transform";
1066 case icSigAToB1Tag:
1067 return "AToB1 Multidimentional Transform";
1068 case icSigAToB2Tag:
1069 return "AToB2 Multidimentional Transform";
1070 case icSigBlueColorantTag:
1071 return "Blue Colorant";
1072 case icSigBlueTRCTag:
1073 return "Blue Tone Reproduction Curve";
1074 case icSigBToA0Tag:
1075 return "BToA0 Multidimentional Transform";
1076 case icSigBToA1Tag:
1077 return "BToA1 Multidimentional Transform";
1078 case icSigBToA2Tag:
1079 return "BToA2 Multidimentional Transform";
1080 case icSigCalibrationDateTimeTag:
1081 return "Calibration Date & Time";
1082 case icSigCharTargetTag:
1083 return "Characterization Target";
1084 case icSigCopyrightTag:
1085 return "Copyright";
1086 case icSigCrdInfoTag:
1087 return "CRD Info";
1088 case icSigDeviceMfgDescTag:
1089 return "Device Manufacturer Description";
1090 case icSigDeviceModelDescTag:
1091 return "Device Model Description";
1092 case icSigGamutTag:
1093 return "Gamut";
1094 case icSigGrayTRCTag:
1095 return "Gray Tone Reproduction Curve";
1096 case icSigGreenColorantTag:
1097 return "Green Colorant";
1098 case icSigGreenTRCTag:
1099 return "Green Tone Reproduction Curve";
1100 case icSigLuminanceTag:
1101 return "Luminance";
1102 case icSigMeasurementTag:
1103 return "Measurement";
1104 case icSigMediaBlackPointTag:
1105 return "Media Black Point";
1106 case icSigMediaWhitePointTag:
1107 return "Media White Point";
1108 case icSigNamedColorTag:
1109 return "Named Color";
1110 case icSigNamedColor2Tag:
1111 return "Named Color 2";
1112 case icSigPreview0Tag:
1113 return "Preview0";
1114 case icSigPreview1Tag:
1115 return "Preview1";
1116 case icSigPreview2Tag:
1117 return "Preview2";
1118 case icSigProfileDescriptionTag:
1119 return "Profile Description";
1120 case icSigProfileSequenceDescTag:
1121 return "Profile Sequence";
1122 case icSigPs2CRD0Tag:
1123 return "PS Level 2 CRD perceptual";
1124 case icSigPs2CRD1Tag:
1125 return "PS Level 2 CRD colorimetric";
1126 case icSigPs2CRD2Tag:
1127 return "PS Level 2 CRD saturation";
1128 case icSigPs2CRD3Tag:
1129 return "PS Level 2 CRD absolute";
1130 case icSigPs2CSATag:
1131 return "PS Level 2 color space array";
1132 case icSigPs2RenderingIntentTag:
1133 return "PS Level 2 Rendering Intent";
1134 case icSigRedColorantTag:
1135 return "Red Colorant";
1136 case icSigRedTRCTag:
1137 return "Red Tone Reproduction Curve";
1138 case icSigScreeningDescTag:
1139 return "Screening Description";
1140 case icSigScreeningTag:
1141 return "Screening Attributes";
1142 case icSigTechnologyTag:
1143 return "Device Technology";
1144 case icSigUcrBgTag:
1145 return "Under Color Removal & Black Generation";
1146 case icSigVideoCardGammaTag:
1147 return "Video Card Gamma Curve";
1148 case icSigViewingCondDescTag:
1149 return "Viewing Condition Description";
1150 case icSigViewingConditionsTag:
1151 return "Viewing Condition Paramaters";
1152 default:
1153 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1154 return buf;
1155 }
1156 }
1157
1158 /* technology signature descriptions */
string_TechnologySignature(icTechnologySignature sig)1159 static const char *string_TechnologySignature(icTechnologySignature sig) {
1160 static char buf[80];
1161 switch(sig) {
1162 case icSigDigitalCamera:
1163 return "Digital Camera";
1164 case icSigFilmScanner:
1165 return "Film Scanner";
1166 case icSigReflectiveScanner:
1167 return "Reflective Scanner";
1168 case icSigInkJetPrinter:
1169 return "InkJet Printer";
1170 case icSigThermalWaxPrinter:
1171 return "Thermal WaxPrinter";
1172 case icSigElectrophotographicPrinter:
1173 return "Electrophotographic Printer";
1174 case icSigElectrostaticPrinter:
1175 return "Electrostatic Printer";
1176 case icSigDyeSublimationPrinter:
1177 return "DyeSublimation Printer";
1178 case icSigPhotographicPaperPrinter:
1179 return "Photographic Paper Printer";
1180 case icSigFilmWriter:
1181 return "Film Writer";
1182 case icSigVideoMonitor:
1183 return "Video Monitor";
1184 case icSigVideoCamera:
1185 return "Video Camera";
1186 case icSigProjectionTelevision:
1187 return "Projection Television";
1188 case icSigCRTDisplay:
1189 return "Cathode Ray Tube Display";
1190 case icSigPMDisplay:
1191 return "Passive Matrix Display";
1192 case icSigAMDisplay:
1193 return "Active Matrix Display";
1194 case icSigPhotoCD:
1195 return "Photo CD";
1196 case icSigPhotoImageSetter:
1197 return "Photo ImageSetter";
1198 case icSigGravure:
1199 return "Gravure";
1200 case icSigOffsetLithography:
1201 return "Offset Lithography";
1202 case icSigSilkscreen:
1203 return "Silkscreen";
1204 case icSigFlexography:
1205 return "Flexography";
1206 default:
1207 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1208 return buf;
1209 }
1210 }
1211
1212 /* type signatures */
string_TypeSignature(icTagTypeSignature sig)1213 static const char *string_TypeSignature(icTagTypeSignature sig) {
1214 static char buf[80];
1215 switch(sig) {
1216 case icSigCurveType:
1217 return "Curve";
1218 case icSigDataType:
1219 return "Data";
1220 case icSigDateTimeType:
1221 return "DateTime";
1222 case icSigLut16Type:
1223 return "Lut16";
1224 case icSigLut8Type:
1225 return "Lut8";
1226 case icSigMeasurementType:
1227 return "Measurement";
1228 case icSigNamedColorType:
1229 return "Named Color";
1230 case icSigProfileSequenceDescType:
1231 return "Profile Sequence Desc";
1232 case icSigS15Fixed16ArrayType:
1233 return "S15Fixed16 Array";
1234 case icSigScreeningType:
1235 return "Screening";
1236 case icSigSignatureType:
1237 return "Signature";
1238 case icSigTextType:
1239 return "Text";
1240 case icSigTextDescriptionType:
1241 return "Text Description";
1242 case icSigU16Fixed16ArrayType:
1243 return "U16Fixed16 Array";
1244 case icSigUcrBgType:
1245 return "Under Color Removal & Black Generation";
1246 case icSigUInt16ArrayType:
1247 return "UInt16 Array";
1248 case icSigUInt32ArrayType:
1249 return "UInt32 Array";
1250 case icSigUInt64ArrayType:
1251 return "UInt64 Array";
1252 case icSigUInt8ArrayType:
1253 return "UInt8 Array";
1254 case icSigVideoCardGammaType:
1255 return "Video Card Gamma";
1256 case icSigViewingConditionsType:
1257 return "Viewing Conditions";
1258 case icSigXYZType:
1259 return "XYZ (Array?)";
1260 case icSigNamedColor2Type:
1261 return "Named Color 2";
1262 case icSigCrdInfoType:
1263 return "CRD Info";
1264 default:
1265 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1266 return buf;
1267 }
1268 }
1269
1270 /* Color Space Signatures */
string_ColorSpaceSignature(icColorSpaceSignature sig)1271 static const char *string_ColorSpaceSignature(icColorSpaceSignature sig) {
1272 static char buf[80];
1273 switch(sig) {
1274 case icSigXYZData:
1275 return "XYZ";
1276 case icSigLabData:
1277 return "Lab";
1278 case icSigLuvData:
1279 return "Luv";
1280 case icSigYCbCrData:
1281 return "YCbCr";
1282 case icSigYxyData:
1283 return "Yxy";
1284 case icSigRgbData:
1285 return "RGB";
1286 case icSigGrayData:
1287 return "Gray";
1288 case icSigHsvData:
1289 return "HSV";
1290 case icSigHlsData:
1291 return "HLS";
1292 case icSigCmykData:
1293 return "CMYK";
1294 case icSigCmyData:
1295 return "CMY";
1296 case icSig2colorData:
1297 return "2 Color";
1298 case icSig3colorData:
1299 return "3 Color";
1300 case icSig4colorData:
1301 return "4 Color";
1302 case icSig5colorData:
1303 case icSigMch5Data:
1304 return "5 Color";
1305 case icSig6colorData:
1306 case icSigMch6Data:
1307 return "6 Color";
1308 case icSig7colorData:
1309 case icSigMch7Data:
1310 return "7 Color";
1311 case icSig8colorData:
1312 case icSigMch8Data:
1313 return "8 Color";
1314 case icSig9colorData:
1315 return "9 Color";
1316 case icSig10colorData:
1317 return "10 Color";
1318 case icSig11colorData:
1319 return "11 Color";
1320 case icSig12colorData:
1321 return "12 Color";
1322 case icSig13colorData:
1323 return "13 Color";
1324 case icSig14colorData:
1325 return "14 Color";
1326 case icSig15colorData:
1327 return "15 Color";
1328 default:
1329 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1330 return buf;
1331 }
1332 }
1333
1334 #ifdef NEVER
1335 /* Public version of above */
ColorSpaceSignature2str(icColorSpaceSignature sig)1336 char *ColorSpaceSignature2str(icColorSpaceSignature sig) {
1337 return string_ColorSpaceSignature(sig);
1338 }
1339 #endif
1340
1341
1342 /* profileClass enumerations */
string_ProfileClassSignature(icProfileClassSignature sig)1343 static const char *string_ProfileClassSignature(icProfileClassSignature sig) {
1344 static char buf[80];
1345 switch(sig) {
1346 case icSigInputClass:
1347 return "Input";
1348 case icSigDisplayClass:
1349 return "Display";
1350 case icSigOutputClass:
1351 return "Output";
1352 case icSigLinkClass:
1353 return "Link";
1354 case icSigAbstractClass:
1355 return "Abstract";
1356 case icSigColorSpaceClass:
1357 return "Color Space";
1358 case icSigNamedColorClass:
1359 return "Named Color";
1360 default:
1361 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1362 return buf;
1363 }
1364 }
1365
1366 /* Platform Signatures */
string_PlatformSignature(icPlatformSignature sig)1367 static const char *string_PlatformSignature(icPlatformSignature sig) {
1368 static char buf[80];
1369 switch(sig) {
1370 case icSigMacintosh:
1371 return "Macintosh";
1372 case icSigMicrosoft:
1373 return "Microsoft";
1374 case icSigSolaris:
1375 return "Solaris";
1376 case icSigSGI:
1377 return "SGI";
1378 case icSigTaligent:
1379 return "Taligent";
1380 default:
1381 sprintf(buf,"Unrecognized - %s",tag2str(sig));
1382 return buf;
1383 }
1384 }
1385
1386 /* Measurement Geometry, used in the measurmentType tag */
string_MeasurementGeometry(icMeasurementGeometry sig)1387 static const char *string_MeasurementGeometry(icMeasurementGeometry sig) {
1388 static char buf[30];
1389 switch(sig) {
1390 case icGeometryUnknown:
1391 return "Unknown";
1392 case icGeometry045or450:
1393 return "0/45 or 45/0";
1394 case icGeometry0dord0:
1395 return "0/d or d/0";
1396 default:
1397 sprintf(buf,"Unrecognized - 0x%x",sig);
1398 return buf;
1399 }
1400 }
1401
1402 /* Rendering Intents, used in the profile header */
string_RenderingIntent(icRenderingIntent sig)1403 static const char *string_RenderingIntent(icRenderingIntent sig) {
1404 static char buf[30];
1405 switch(sig) {
1406 case icPerceptual:
1407 return "Perceptual";
1408 case icRelativeColorimetric:
1409 return "Relative Colorimetric";
1410 case icSaturation:
1411 return "Saturation";
1412 case icAbsoluteColorimetric:
1413 return "Absolute Colorimetric";
1414 default:
1415 sprintf(buf,"Unrecognized - 0x%x",sig);
1416 return buf;
1417 }
1418 }
1419
1420 /* Different Spot Shapes currently defined, used for screeningType */
string_SpotShape(icSpotShape sig)1421 static const char *string_SpotShape(icSpotShape sig) {
1422 static char buf[30];
1423 switch(sig) {
1424 case icSpotShapeUnknown:
1425 return "Unknown";
1426 case icSpotShapePrinterDefault:
1427 return "Printer Default";
1428 case icSpotShapeRound:
1429 return "Round";
1430 case icSpotShapeDiamond:
1431 return "Diamond";
1432 case icSpotShapeEllipse:
1433 return "Ellipse";
1434 case icSpotShapeLine:
1435 return "Line";
1436 case icSpotShapeSquare:
1437 return "Square";
1438 case icSpotShapeCross:
1439 return "Cross";
1440 default:
1441 sprintf(buf,"Unrecognized - 0x%x",sig);
1442 return buf;
1443 }
1444 }
1445
1446 /* Standard Observer, used in the measurmentType tag */
string_StandardObserver(icStandardObserver sig)1447 static const char *string_StandardObserver(icStandardObserver sig) {
1448 static char buf[30];
1449 switch(sig) {
1450 case icStdObsUnknown:
1451 return "Unknown";
1452 case icStdObs1931TwoDegrees:
1453 return "1931 Two Degrees";
1454 case icStdObs1964TenDegrees:
1455 return "1964 Ten Degrees";
1456 default:
1457 sprintf(buf,"Unrecognized - 0x%x",sig);
1458 return buf;
1459 }
1460 }
1461
1462 /* Pre-defined illuminants, used in measurement and viewing conditions type */
string_Illuminant(icIlluminant sig)1463 static const char *string_Illuminant(icIlluminant sig) {
1464 static char buf[30];
1465 switch(sig) {
1466 case icIlluminantUnknown:
1467 return "Unknown";
1468 case icIlluminantD50:
1469 return "D50";
1470 case icIlluminantD65:
1471 return "D65";
1472 case icIlluminantD93:
1473 return "D93";
1474 case icIlluminantF2:
1475 return "F2";
1476 case icIlluminantD55:
1477 return "D55";
1478 case icIlluminantA:
1479 return "A";
1480 case icIlluminantEquiPowerE:
1481 return "Equi-Power(E)";
1482 case icIlluminantF8:
1483 return "F8";
1484 default:
1485 sprintf(buf,"Unrecognized - 0x%x",sig);
1486 return buf;
1487 }
1488 }
1489
1490 /* Return a text abreviation of a color lookup algorithm */
string_LuAlg(icmLuAlgType alg)1491 static const char *string_LuAlg(icmLuAlgType alg) {
1492 static char buf[80];
1493
1494 switch(alg) {
1495 case icmMonoFwdType:
1496 return "MonoFwd";
1497 case icmMonoBwdType:
1498 return "MonoBwd";
1499 case icmMatrixFwdType:
1500 return "MatrixFwd";
1501 case icmMatrixBwdType:
1502 return "MatrixBwd";
1503 case icmLutType:
1504 return "Lut";
1505 default:
1506 sprintf(buf,"Unrecognized - %d",alg);
1507 return buf;
1508 }
1509 }
1510
1511 /* Return a string description of the given enumeration value */
1512 /* Public: */
icm2str(icmEnumType etype,int enumval)1513 const char *icm2str(icmEnumType etype, int enumval) {
1514
1515 switch(etype) {
1516 case icmScreenEncodings:
1517 return string_ScreenEncodings((unsigned long) enumval);
1518 case icmDeviceAttributes:
1519 return string_DeviceAttributes((unsigned long) enumval);
1520 case icmProfileHeaderFlags:
1521 return string_ProfileHeaderFlags((unsigned long) enumval);
1522 case icmAsciiOrBinaryData:
1523 return string_AsciiOrBinaryData((unsigned long) enumval);
1524 case icmTagSignature:
1525 return string_TagSignature((icTagSignature) enumval);
1526 case icmTechnologySignature:
1527 return string_TechnologySignature((icTechnologySignature) enumval);
1528 case icmTypeSignature:
1529 return string_TypeSignature((icTagTypeSignature) enumval);
1530 case icmColorSpaceSignature:
1531 return string_ColorSpaceSignature((icColorSpaceSignature) enumval);
1532 case icmProfileClassSignaure:
1533 return string_ProfileClassSignature((icProfileClassSignature) enumval);
1534 case icmPlatformSignature:
1535 return string_PlatformSignature((icPlatformSignature) enumval);
1536 case icmMeasurementGeometry:
1537 return string_MeasurementGeometry((icMeasurementGeometry) enumval);
1538 case icmRenderingIntent:
1539 return string_RenderingIntent((icRenderingIntent) enumval);
1540 case icmSpotShape:
1541 return string_SpotShape((icSpotShape) enumval);
1542 case icmStandardObserver:
1543 return string_StandardObserver((icStandardObserver) enumval);
1544 case icmIlluminant:
1545 return string_Illuminant((icIlluminant) enumval);
1546 case icmLuAlg:
1547 return string_LuAlg((icmLuAlgType) enumval);
1548 default:
1549 return "enum2str got unknown type";
1550 }
1551 }
1552
1553 /* ========================================================== */
1554 /* Object I/O routines */
1555 /* ========================================================== */
1556 /* icmUInt8Array object */
1557
1558 /* Return the number of bytes needed to write this tag */
icmUInt8Array_get_size(icmBase * pp)1559 static unsigned int icmUInt8Array_get_size(
1560 icmBase *pp
1561 ) {
1562 icmUInt8Array *p = (icmUInt8Array *)pp;
1563 unsigned int len = 0;
1564 len += 8; /* 8 bytes for tag and padding */
1565 len += p->size * 1; /* 1 byte for each UInt8 */
1566 return len;
1567 }
1568
1569 /* read the object, return 0 on success, error code on fail */
icmUInt8Array_read(icmBase * pp,unsigned long len,unsigned long of)1570 static int icmUInt8Array_read(
1571 icmBase *pp,
1572 unsigned long len, /* tag length */
1573 unsigned long of /* start offset within file */
1574 ) {
1575 icmUInt8Array *p = (icmUInt8Array *)pp;
1576 icc *icp = p->icp;
1577 int rv = 0;
1578 unsigned long i, size;
1579 char *bp, *buf;
1580
1581 if (len < 8) {
1582 sprintf(icp->err,"icmUInt8Array_read: Tag too small to be legal");
1583 return icp->errc = 1;
1584 }
1585
1586 /* Allocate a file read buffer */
1587 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1588 sprintf(icp->err,"icmUInt8Array_read: malloc() failed");
1589 return icp->errc = 2;
1590 }
1591 bp = buf;
1592
1593 /* Read portion of file into buffer */
1594 if ( icp->fp->seek(icp->fp, of) != 0
1595 || icp->fp->read(icp->fp, bp, 1, len) != len) {
1596 sprintf(icp->err,"icmUInt8Array_read: fseek() or fread() failed");
1597 icp->al->free(icp->al, buf);
1598 return icp->errc = 1;
1599 }
1600 p->size = size = (len - 8)/1; /* Number of elements in the array */
1601
1602 if ((rv = p->allocate((icmBase *)p)) != 0) {
1603 icp->al->free(icp->al, buf);
1604 return rv;
1605 }
1606
1607 /* Read type descriptor from the buffer */
1608 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1609 icp->al->free(icp->al, buf);
1610 sprintf(icp->err,"icmUInt8Array_read: Wrong tag type for icmUInt8Array");
1611 return icp->errc = 1;
1612 }
1613 bp += 8; /* Skip padding */
1614
1615 /* Read all the data from the buffer */
1616 for (i = 0; i < size; i++, bp += 1) {
1617 p->data[i] = read_UInt8Number(bp);
1618 }
1619 icp->al->free(p->icp->al, buf);
1620 return 0;
1621 }
1622
1623 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmUInt8Array_write(icmBase * pp,unsigned long of)1624 static int icmUInt8Array_write(
1625 icmBase *pp,
1626 unsigned long of /* File offset to write from */
1627 ) {
1628 icmUInt8Array *p = (icmUInt8Array *)pp;
1629 icc *icp = p->icp;
1630 unsigned long i;
1631 unsigned int len;
1632 char *bp, *buf; /* Buffer to write from */
1633 int rv = 0;
1634
1635 /* Allocate a file write buffer */
1636 len = p->get_size((icmBase *)p);
1637 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1638 sprintf(icp->err,"icmUInt8Array_write malloc() failed");
1639 return icp->errc = 2;
1640 }
1641 bp = buf;
1642
1643 /* Write type descriptor to the buffer */
1644 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
1645 sprintf(icp->err,"icmUInt8Array_write: write_SInt32Number() failed");
1646 icp->al->free(icp->al, buf);
1647 return icp->errc = rv;
1648 }
1649 write_SInt32Number(0,bp+4); /* Set padding to 0 */
1650 bp += 8; /* Skip padding */
1651
1652 /* Write all the data to the buffer */
1653 for (i = 0; i < p->size; i++, bp += 1) {
1654 if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
1655 sprintf(icp->err,"icmUInt8Array_write: write_UInt8umber() failed");
1656 icp->al->free(icp->al, buf);
1657 return icp->errc = rv;
1658 }
1659 }
1660
1661 /* Write to the file */
1662 if ( icp->fp->seek(icp->fp, of) != 0
1663 || icp->fp->write(icp->fp, buf, 1, len) != len) {
1664 sprintf(icp->err,"icmUInt8Array_write fseek() or fwrite() failed");
1665 icp->al->free(icp->al, buf);
1666 return icp->errc = 2;
1667 }
1668 icp->al->free(icp->al, buf);
1669 return 0;
1670 }
1671
1672 /* Dump a text description of the object */
icmUInt8Array_dump(icmBase * pp,FILE * op,int verb)1673 static void icmUInt8Array_dump(
1674 icmBase *pp,
1675 FILE *op, /* Output to dump to */
1676 int verb /* Verbosity level */
1677 ) {
1678 icmUInt8Array *p = (icmUInt8Array *)pp;
1679 if (verb <= 0)
1680 return;
1681
1682 fprintf(op,"UInt8Array:\n");
1683 fprintf(op," No. elements = %lu\n",p->size);
1684 if (verb >= 2) {
1685 unsigned long i;
1686 for (i = 0; i < p->size; i++)
1687 fprintf(op," %lu: %u\n",i,p->data[i]);
1688 }
1689 }
1690
1691 /* Allocate variable sized data elements */
icmUInt8Array_allocate(icmBase * pp)1692 static int icmUInt8Array_allocate(
1693 icmBase *pp
1694 ) {
1695 icmUInt8Array *p = (icmUInt8Array *)pp;
1696 icc *icp = p->icp;
1697
1698 if (p->size != p->_size) {
1699 if (p->data != NULL)
1700 icp->al->free(icp->al, p->data);
1701 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
1702 sprintf(icp->err,"icmUInt8Array_alloc: malloc() of icmUInt8Array data failed");
1703 return icp->errc = 2;
1704 }
1705 p->_size = p->size;
1706 }
1707 return 0;
1708 }
1709
1710 /* Free all storage in the object */
icmUInt8Array_delete(icmBase * pp)1711 static void icmUInt8Array_delete(
1712 icmBase *pp
1713 ) {
1714 icmUInt8Array *p = (icmUInt8Array *)pp;
1715 icc *icp = p->icp;
1716
1717 if (p->data != NULL)
1718 icp->al->free(icp->al, p->data);
1719 icp->al->free(icp->al, p);
1720 }
1721
1722 /* Create an empty object. Return null on error */
new_icmUInt8Array(icc * icp)1723 static icmBase *new_icmUInt8Array(
1724 icc *icp
1725 ) {
1726 icmUInt8Array *p;
1727 if ((p = (icmUInt8Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt8Array))) == NULL)
1728 return NULL;
1729 p->ttype = icSigUInt8ArrayType;
1730 p->refcount = 1;
1731 p->get_size = icmUInt8Array_get_size;
1732 p->read = icmUInt8Array_read;
1733 p->write = icmUInt8Array_write;
1734 p->dump = icmUInt8Array_dump;
1735 p->allocate = icmUInt8Array_allocate;
1736 p->del = icmUInt8Array_delete;
1737 p->icp = icp;
1738
1739 return (icmBase *)p;
1740 }
1741
1742 /* ---------------------------------------------------------- */
1743 /* icmUInt16Array object */
1744
1745 /* Return the number of bytes needed to write this tag */
icmUInt16Array_get_size(icmBase * pp)1746 static unsigned int icmUInt16Array_get_size(
1747 icmBase *pp
1748 ) {
1749 icmUInt16Array *p = (icmUInt16Array *)pp;
1750 unsigned int len = 0;
1751 len += 8; /* 8 bytes for tag and padding */
1752 len += p->size * 2; /* 2 bytes for each UInt16 */
1753 return len;
1754 }
1755
1756 /* read the object, return 0 on success, error code on fail */
icmUInt16Array_read(icmBase * pp,unsigned long len,unsigned long of)1757 static int icmUInt16Array_read(
1758 icmBase *pp,
1759 unsigned long len, /* tag length */
1760 unsigned long of /* start offset within file */
1761 ) {
1762 icmUInt16Array *p = (icmUInt16Array *)pp;
1763 icc *icp = p->icp;
1764 int rv = 0;
1765 unsigned long i, size;
1766 char *bp, *buf;
1767
1768 if (len < 8) {
1769 sprintf(icp->err,"icmUInt16Array_read: Tag too small to be legal");
1770 return icp->errc = 1;
1771 }
1772
1773 /* Allocate a file read buffer */
1774 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1775 sprintf(icp->err,"icmUInt16Array_read: malloc() failed");
1776 return icp->errc = 2;
1777 }
1778 bp = buf;
1779
1780 /* Read portion of file into buffer */
1781 if ( icp->fp->seek(icp->fp, of) != 0
1782 || icp->fp->read(icp->fp, bp, 1, len) != len) {
1783 sprintf(icp->err,"icmUInt16Array_read: fseek() or fread() failed");
1784 icp->al->free(icp->al, buf);
1785 return icp->errc = 1;
1786 }
1787 p->size = size = (len - 8)/2; /* Number of elements in the array */
1788
1789 if ((rv = p->allocate((icmBase *)p)) != 0) {
1790 icp->al->free(icp->al, buf);
1791 return rv;
1792 }
1793
1794 /* Read type descriptor from the buffer */
1795 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1796 sprintf(icp->err,"icmUInt16Array_read: Wrong tag type for icmUInt16Array");
1797 icp->al->free(icp->al, buf);
1798 return icp->errc = 1;
1799 }
1800 bp += 8; /* Skip padding */
1801
1802 /* Read all the data from the buffer */
1803 for (i = 0; i < size; i++, bp += 2) {
1804 p->data[i] = read_UInt16Number(bp);
1805 }
1806 icp->al->free(icp->al, buf);
1807 return 0;
1808 }
1809
1810 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmUInt16Array_write(icmBase * pp,unsigned long of)1811 static int icmUInt16Array_write(
1812 icmBase *pp,
1813 unsigned long of /* File offset to write from */
1814 ) {
1815 icmUInt16Array *p = (icmUInt16Array *)pp;
1816 icc *icp = p->icp;
1817 unsigned long i;
1818 unsigned int len;
1819 char *bp, *buf; /* Buffer to write from */
1820 int rv = 0;
1821
1822 /* Allocate a file write buffer */
1823 len = p->get_size((icmBase *)p);
1824 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1825 sprintf(icp->err,"icmUInt16Array_write malloc() failed");
1826 return icp->errc = 2;
1827 }
1828 bp = buf;
1829
1830 /* Write type descriptor to the buffer */
1831 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
1832 sprintf(icp->err,"icmUInt16Array_write: write_SInt32Number() failed");
1833 icp->al->free(icp->al, buf);
1834 return icp->errc = rv;
1835 }
1836 write_SInt32Number(0,bp+4); /* Set padding to 0 */
1837
1838 /* Write all the data to the buffer */
1839 bp += 8; /* Skip padding */
1840 for (i = 0; i < p->size; i++, bp += 2) {
1841 if ((rv = write_UInt16Number(p->data[i],bp)) != 0) {
1842 sprintf(icp->err,"icmUInt16Array_write: write_UInt16umber() failed");
1843 icp->al->free(icp->al, buf);
1844 return icp->errc = rv;
1845 }
1846 }
1847
1848 /* Write to the file */
1849 if ( icp->fp->seek(icp->fp, of) != 0
1850 || icp->fp->write(icp->fp, buf, 1, len) != len) {
1851 sprintf(icp->err,"icmUInt16Array_write fseek() or fwrite() failed");
1852 icp->al->free(icp->al, buf);
1853 return icp->errc = 2;
1854 }
1855 icp->al->free(icp->al, buf);
1856 return 0;
1857 }
1858
1859 /* Dump a text description of the object */
icmUInt16Array_dump(icmBase * pp,FILE * op,int verb)1860 static void icmUInt16Array_dump(
1861 icmBase *pp,
1862 FILE *op, /* Output to dump to */
1863 int verb /* Verbosity level */
1864 ) {
1865 icmUInt16Array *p = (icmUInt16Array *)pp;
1866 if (verb <= 0)
1867 return;
1868
1869 fprintf(op,"UInt16Array:\n");
1870 fprintf(op," No. elements = %lu\n",p->size);
1871 if (verb >= 2) {
1872 unsigned long i;
1873 for (i = 0; i < p->size; i++)
1874 fprintf(op," %lu: %u\n",i,p->data[i]);
1875 }
1876 }
1877
1878 /* Allocate variable sized data elements */
icmUInt16Array_allocate(icmBase * pp)1879 static int icmUInt16Array_allocate(
1880 icmBase *pp
1881 ) {
1882 icmUInt16Array *p = (icmUInt16Array *)pp;
1883 icc *icp = p->icp;
1884
1885 if (p->size != p->_size) {
1886 if (p->data != NULL)
1887 icp->al->free(icp->al, p->data);
1888 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
1889 sprintf(icp->err,"icmUInt16Array_alloc: malloc() of icmUInt16Array data failed");
1890 return icp->errc = 2;
1891 }
1892 p->_size = p->size;
1893 }
1894 return 0;
1895 }
1896
1897 /* Free all storage in the object */
icmUInt16Array_delete(icmBase * pp)1898 static void icmUInt16Array_delete(
1899 icmBase *pp
1900 ) {
1901 icmUInt16Array *p = (icmUInt16Array *)pp;
1902 icc *icp = p->icp;
1903
1904 if (p->data != NULL)
1905 icp->al->free(icp->al, p->data);
1906 icp->al->free(icp->al, p);
1907 }
1908
1909 /* Create an empty object. Return null on error */
new_icmUInt16Array(icc * icp)1910 static icmBase *new_icmUInt16Array(
1911 icc *icp
1912 ) {
1913 icmUInt16Array *p;
1914 if ((p = (icmUInt16Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt16Array))) == NULL)
1915 return NULL;
1916 p->ttype = icSigUInt16ArrayType;
1917 p->refcount = 1;
1918 p->get_size = icmUInt16Array_get_size;
1919 p->read = icmUInt16Array_read;
1920 p->write = icmUInt16Array_write;
1921 p->dump = icmUInt16Array_dump;
1922 p->allocate = icmUInt16Array_allocate;
1923 p->del = icmUInt16Array_delete;
1924 p->icp = icp;
1925
1926 return (icmBase *)p;
1927 }
1928
1929 /* ---------------------------------------------------------- */
1930 /* icmUInt32Array object */
1931
1932 /* Return the number of bytes needed to write this tag */
icmUInt32Array_get_size(icmBase * pp)1933 static unsigned int icmUInt32Array_get_size(
1934 icmBase *pp
1935 ) {
1936 icmUInt32Array *p = (icmUInt32Array *)pp;
1937 unsigned int len = 0;
1938 len += 8; /* 8 bytes for tag and padding */
1939 len += p->size * 4; /* 4 bytes for each UInt32 */
1940 return len;
1941 }
1942
1943 /* read the object, return 0 on success, error code on fail */
icmUInt32Array_read(icmBase * pp,unsigned long len,unsigned long of)1944 static int icmUInt32Array_read(
1945 icmBase *pp,
1946 unsigned long len, /* tag length */
1947 unsigned long of /* start offset within file */
1948 ) {
1949 icmUInt32Array *p = (icmUInt32Array *)pp;
1950 icc *icp = p->icp;
1951 int rv = 0;
1952 unsigned long i, size;
1953 char *bp, *buf;
1954
1955 if (len < 8) {
1956 sprintf(icp->err,"icmUInt32Array_read: Tag too small to be legal");
1957 return icp->errc = 1;
1958 }
1959
1960 /* Allocate a file read buffer */
1961 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1962 sprintf(icp->err,"icmUInt32Array_read: malloc() failed");
1963 return icp->errc = 2;
1964 }
1965 bp = buf;
1966
1967 /* Read portion of file into buffer */
1968 if ( icp->fp->seek(icp->fp, of) != 0
1969 || icp->fp->read(icp->fp, bp, 1, len) != len) {
1970 sprintf(icp->err,"icmUInt32Array_read: fseek() or fread() failed");
1971 icp->al->free(icp->al, buf);
1972 return icp->errc = 1;
1973 }
1974 p->size = size = (len - 8)/4; /* Number of elements in the array */
1975
1976 if ((rv = p->allocate((icmBase *)p)) != 0) {
1977 icp->al->free(icp->al, buf);
1978 return rv;
1979 }
1980
1981 /* Read type descriptor from the buffer */
1982 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1983 sprintf(icp->err,"icmUInt32Array_read: Wrong tag type for icmUInt32Array");
1984 icp->al->free(icp->al, buf);
1985 return icp->errc = 1;
1986 }
1987 bp += 8; /* Skip padding */
1988
1989 /* Read all the data from the buffer */
1990 for (i = 0; i < size; i++, bp += 4) {
1991 p->data[i] = read_UInt32Number(bp);
1992 }
1993 icp->al->free(icp->al, buf);
1994 return 0;
1995 }
1996
1997 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmUInt32Array_write(icmBase * pp,unsigned long of)1998 static int icmUInt32Array_write(
1999 icmBase *pp,
2000 unsigned long of /* File offset to write from */
2001 ) {
2002 icmUInt32Array *p = (icmUInt32Array *)pp;
2003 icc *icp = p->icp;
2004 unsigned long i;
2005 unsigned int len;
2006 char *bp, *buf; /* Buffer to write from */
2007 int rv = 0;
2008
2009 /* Allocate a file write buffer */
2010 len = p->get_size((icmBase *)p);
2011 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2012 sprintf(icp->err,"icmUInt32Array_write malloc() failed");
2013 return icp->errc = 2;
2014 }
2015 bp = buf;
2016
2017 /* Write type descriptor to the buffer */
2018 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2019 sprintf(icp->err,"icmUInt32Array_write: write_SInt32Number() failed");
2020 icp->al->free(icp->al, buf);
2021 return icp->errc = rv;
2022 }
2023 write_SInt32Number(0,bp+4); /* Set padding to 0 */
2024
2025 /* Write all the data to the buffer */
2026 bp += 8; /* Skip padding */
2027 for (i = 0; i < p->size; i++, bp += 4) {
2028 if ((rv = write_UInt32Number(p->data[i],bp)) != 0) {
2029 sprintf(icp->err,"icmUInt32Array_write: write_UInt32umber() failed");
2030 icp->al->free(icp->al, buf);
2031 return icp->errc = rv;
2032 }
2033 }
2034
2035 /* Write to the file */
2036 if ( icp->fp->seek(icp->fp, of) != 0
2037 || icp->fp->write(icp->fp, buf, 1, len) != len) {
2038 sprintf(icp->err,"icmUInt32Array_write fseek() or fwrite() failed");
2039 icp->al->free(icp->al, buf);
2040 return icp->errc = 2;
2041 }
2042 icp->al->free(icp->al, buf);
2043 return 0;
2044 }
2045
2046 /* Dump a text description of the object */
icmUInt32Array_dump(icmBase * pp,FILE * op,int verb)2047 static void icmUInt32Array_dump(
2048 icmBase *pp,
2049 FILE *op, /* Output to dump to */
2050 int verb /* Verbosity level */
2051 ) {
2052 icmUInt32Array *p = (icmUInt32Array *)pp;
2053 if (verb <= 0)
2054 return;
2055
2056 fprintf(op,"UInt32Array:\n");
2057 fprintf(op," No. elements = %lu\n",p->size);
2058 if (verb >= 2) {
2059 unsigned long i;
2060 for (i = 0; i < p->size; i++)
2061 fprintf(op," %lu: %u\n",i,p->data[i]);
2062 }
2063 }
2064
2065 /* Allocate variable sized data elements */
icmUInt32Array_allocate(icmBase * pp)2066 static int icmUInt32Array_allocate(
2067 icmBase *pp
2068 ) {
2069 icmUInt32Array *p = (icmUInt32Array *)pp;
2070 icc *icp = p->icp;
2071
2072 if (p->size != p->_size) {
2073 if (p->data != NULL)
2074 icp->al->free(icp->al, p->data);
2075 if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
2076 sprintf(icp->err,"icmUInt32Array_alloc: malloc() of icmUInt32Array data failed");
2077 return icp->errc = 2;
2078 }
2079 p->_size = p->size;
2080 }
2081 return 0;
2082 }
2083
2084 /* Free all storage in the object */
icmUInt32Array_delete(icmBase * pp)2085 static void icmUInt32Array_delete(
2086 icmBase *pp
2087 ) {
2088 icmUInt32Array *p = (icmUInt32Array *)pp;
2089 icc *icp = p->icp;
2090
2091 if (p->data != NULL)
2092 icp->al->free(icp->al, p->data);
2093 icp->al->free(icp->al, p);
2094 }
2095
2096 /* Create an empty object. Return null on error */
new_icmUInt32Array(icc * icp)2097 static icmBase *new_icmUInt32Array(
2098 icc *icp
2099 ) {
2100 icmUInt32Array *p;
2101 if ((p = (icmUInt32Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt32Array))) == NULL)
2102 return NULL;
2103 p->ttype = icSigUInt32ArrayType;
2104 p->refcount = 1;
2105 p->get_size = icmUInt32Array_get_size;
2106 p->read = icmUInt32Array_read;
2107 p->write = icmUInt32Array_write;
2108 p->dump = icmUInt32Array_dump;
2109 p->allocate = icmUInt32Array_allocate;
2110 p->del = icmUInt32Array_delete;
2111 p->icp = icp;
2112
2113 return (icmBase *)p;
2114 }
2115
2116 /* ---------------------------------------------------------- */
2117 /* icmUInt64Array object */
2118
2119 /* Return the number of bytes needed to write this tag */
icmUInt64Array_get_size(icmBase * pp)2120 static unsigned int icmUInt64Array_get_size(
2121 icmBase *pp
2122 ) {
2123 icmUInt64Array *p = (icmUInt64Array *)pp;
2124 unsigned int len = 0;
2125 len += 8; /* 8 bytes for tag and padding */
2126 len += p->size * 8; /* 8 bytes for each UInt64 */
2127 return len;
2128 }
2129
2130 /* read the object, return 0 on success, error code on fail */
icmUInt64Array_read(icmBase * pp,unsigned long len,unsigned long of)2131 static int icmUInt64Array_read(
2132 icmBase *pp,
2133 unsigned long len, /* tag length */
2134 unsigned long of /* start offset within file */
2135 ) {
2136 icmUInt64Array *p = (icmUInt64Array *)pp;
2137 icc *icp = p->icp;
2138 int rv = 0;
2139 unsigned long i, size;
2140 char *bp, *buf;
2141
2142 if (len < 8) {
2143 sprintf(icp->err,"icmUInt64Array_read: Tag too small to be legal");
2144 return icp->errc = 1;
2145 }
2146
2147 /* Allocate a file read buffer */
2148 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2149 sprintf(icp->err,"icmUInt64Array_read: malloc() failed");
2150 return icp->errc = 2;
2151 }
2152 bp = buf;
2153
2154 /* Read portion of file into buffer */
2155 if ( icp->fp->seek(icp->fp, of) != 0
2156 || icp->fp->read(icp->fp, bp, 1, len) != len) {
2157 sprintf(icp->err,"icmUInt64Array_read: fseek() or fread() failed");
2158 icp->al->free(icp->al, buf);
2159 return icp->errc = 1;
2160 }
2161 p->size = size = (len - 8)/8; /* Number of elements in the array */
2162
2163 if ((rv = p->allocate((icmBase *)p)) != 0) {
2164 icp->al->free(icp->al, buf);
2165 return rv;
2166 }
2167
2168 /* Read type descriptor from the buffer */
2169 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2170 sprintf(icp->err,"icmUInt64Array_read: Wrong tag type for icmUInt64Array");
2171 icp->al->free(icp->al, buf);
2172 return icp->errc = 1;
2173 }
2174 bp += 8; /* Skip padding */
2175
2176 /* Read all the data from the buffer */
2177 for (i = 0; i < size; i++, bp += 8) {
2178 read_UInt64Number(&p->data[i], bp);
2179 }
2180 icp->al->free(icp->al, buf);
2181 return 0;
2182 }
2183
2184 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmUInt64Array_write(icmBase * pp,unsigned long of)2185 static int icmUInt64Array_write(
2186 icmBase *pp,
2187 unsigned long of /* File offset to write from */
2188 ) {
2189 icmUInt64Array *p = (icmUInt64Array *)pp;
2190 icc *icp = p->icp;
2191 unsigned long i;
2192 unsigned int len;
2193 char *bp, *buf; /* Buffer to write from */
2194 int rv = 0;
2195
2196 /* Allocate a file write buffer */
2197 len = p->get_size((icmBase *)p);
2198 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2199 sprintf(icp->err,"icmUInt64Array_write malloc() failed");
2200 return icp->errc = 2;
2201 }
2202 bp = buf;
2203
2204 /* Write type descriptor to the buffer */
2205 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2206 sprintf(icp->err,"icmUInt64Array_write: write_SInt32Number() failed");
2207 icp->al->free(icp->al, buf);
2208 return icp->errc = rv;
2209 }
2210 write_SInt32Number(0,bp+4); /* Set padding to 0 */
2211
2212 /* Write all the data to the buffer */
2213 bp += 8; /* Skip padding */
2214 for (i = 0; i < p->size; i++, bp += 8) {
2215 if ((rv = write_UInt64Number(&p->data[i],bp)) != 0) {
2216 sprintf(icp->err,"icmUInt64Array_write: write_UInt64umber() failed");
2217 icp->al->free(icp->al, buf);
2218 return icp->errc = rv;
2219 }
2220 }
2221
2222 /* Write to the file */
2223 if ( icp->fp->seek(icp->fp, of) != 0
2224 || icp->fp->write(icp->fp, buf, 1, len) != len) {
2225 sprintf(icp->err,"icmUInt64Array_write fseek() or fwrite() failed");
2226 icp->al->free(icp->al, buf);
2227 return icp->errc = 2;
2228 }
2229 icp->al->free(icp->al, buf);
2230 return 0;
2231 }
2232
2233 /* Dump a text description of the object */
icmUInt64Array_dump(icmBase * pp,FILE * op,int verb)2234 static void icmUInt64Array_dump(
2235 icmBase *pp,
2236 FILE *op, /* Output to dump to */
2237 int verb /* Verbosity level */
2238 ) {
2239 icmUInt64Array *p = (icmUInt64Array *)pp;
2240 if (verb <= 0)
2241 return;
2242
2243 fprintf(op,"UInt64Array:\n");
2244 fprintf(op," No. elements = %lu\n",p->size);
2245 if (verb >= 2) {
2246 unsigned long i;
2247 for (i = 0; i < p->size; i++)
2248 fprintf(op," %lu: h=%lu, l=%lu\n",i,p->data[i].h,p->data[i].l);
2249 }
2250 }
2251
2252 /* Allocate variable sized data elements */
icmUInt64Array_allocate(icmBase * pp)2253 static int icmUInt64Array_allocate(
2254 icmBase *pp
2255 ) {
2256 icmUInt64Array *p = (icmUInt64Array *)pp;
2257 icc *icp = p->icp;
2258
2259 if (p->size != p->_size) {
2260 if (p->data != NULL)
2261 icp->al->free(icp->al, p->data);
2262 if ((p->data = (icmUint64 *) icp->al->malloc(icp->al, p->size * sizeof(icmUint64))) == NULL) {
2263 sprintf(icp->err,"icmUInt64Array_alloc: malloc() of icmUInt64Array data failed");
2264 return icp->errc = 2;
2265 }
2266 p->_size = p->size;
2267 }
2268 return 0;
2269 }
2270
2271 /* Free all storage in the object */
icmUInt64Array_delete(icmBase * pp)2272 static void icmUInt64Array_delete(
2273 icmBase *pp
2274 ) {
2275 icmUInt64Array *p = (icmUInt64Array *)pp;
2276 icc *icp = p->icp;
2277
2278 if (p->data != NULL)
2279 icp->al->free(icp->al, p->data);
2280 icp->al->free(icp->al, p);
2281 }
2282
2283 /* Create an empty object. Return null on error */
new_icmUInt64Array(icc * icp)2284 static icmBase *new_icmUInt64Array(
2285 icc *icp
2286 ) {
2287 icmUInt64Array *p;
2288 if ((p = (icmUInt64Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt64Array))) == NULL)
2289 return NULL;
2290 p->ttype = icSigUInt64ArrayType;
2291 p->refcount = 1;
2292 p->get_size = icmUInt64Array_get_size;
2293 p->read = icmUInt64Array_read;
2294 p->write = icmUInt64Array_write;
2295 p->dump = icmUInt64Array_dump;
2296 p->allocate = icmUInt64Array_allocate;
2297 p->del = icmUInt64Array_delete;
2298 p->icp = icp;
2299
2300 return (icmBase *)p;
2301 }
2302
2303 /* ---------------------------------------------------------- */
2304 /* icmU16Fixed16Array object */
2305
2306 /* Return the number of bytes needed to write this tag */
icmU16Fixed16Array_get_size(icmBase * pp)2307 static unsigned int icmU16Fixed16Array_get_size(
2308 icmBase *pp
2309 ) {
2310 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2311 unsigned int len = 0;
2312 len += 8; /* 8 bytes for tag and padding */
2313 len += p->size * 4; /* 4 byte for each U16Fixed16 */
2314 return len;
2315 }
2316
2317 /* read the object, return 0 on success, error code on fail */
icmU16Fixed16Array_read(icmBase * pp,unsigned long len,unsigned long of)2318 static int icmU16Fixed16Array_read(
2319 icmBase *pp,
2320 unsigned long len, /* tag length */
2321 unsigned long of /* start offset within file */
2322 ) {
2323 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2324 icc *icp = p->icp;
2325 int rv = 0;
2326 unsigned long i, size;
2327 char *bp, *buf;
2328
2329 if (len < 8) {
2330 sprintf(icp->err,"icmU16Fixed16Array_read: Tag too small to be legal");
2331 return icp->errc = 1;
2332 }
2333
2334 /* Allocate a file read buffer */
2335 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2336 sprintf(icp->err,"icmU16Fixed16Array_read: malloc() failed");
2337 return icp->errc = 2;
2338 }
2339 bp = buf;
2340
2341 /* Read portion of file into buffer */
2342 if ( icp->fp->seek(icp->fp, of) != 0
2343 || icp->fp->read(icp->fp, bp, 1, len) != len) {
2344 sprintf(icp->err,"icmU16Fixed16Array_read: fseek() or fread() failed");
2345 icp->al->free(icp->al, buf);
2346 return icp->errc = 1;
2347 }
2348 p->size = size = (len - 8)/4; /* Number of elements in the array */
2349
2350 if ((rv = p->allocate((icmBase *)p)) != 0) {
2351 icp->al->free(icp->al, buf);
2352 return rv;
2353 }
2354
2355 /* Read type descriptor from the buffer */
2356 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2357 sprintf(icp->err,"icmU16Fixed16Array_read: Wrong tag type for icmU16Fixed16Array");
2358 icp->al->free(icp->al, buf);
2359 return icp->errc = 1;
2360 }
2361 bp += 8; /* Skip padding */
2362
2363 /* Read all the data from the buffer */
2364 for (i = 0; i < size; i++, bp += 4) {
2365 p->data[i] = read_U16Fixed16Number(bp);
2366 }
2367 icp->al->free(icp->al, buf);
2368 return 0;
2369 }
2370
2371 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmU16Fixed16Array_write(icmBase * pp,unsigned long of)2372 static int icmU16Fixed16Array_write(
2373 icmBase *pp,
2374 unsigned long of /* File offset to write from */
2375 ) {
2376 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2377 icc *icp = p->icp;
2378 unsigned long i;
2379 unsigned int len;
2380 char *bp, *buf; /* Buffer to write from */
2381 int rv = 0;
2382
2383 /* Allocate a file write buffer */
2384 len = p->get_size((icmBase *)p);
2385 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2386 sprintf(icp->err,"icmU16Fixed16Array_write malloc() failed");
2387 return icp->errc = 2;
2388 }
2389 bp = buf;
2390
2391 /* Write type descriptor to the buffer */
2392 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2393 sprintf(icp->err,"icmU16Fixed16Array_write: write_SInt32Number() failed");
2394 icp->al->free(icp->al, buf);
2395 return icp->errc = rv;
2396 }
2397 write_SInt32Number(0,bp+4); /* Set padding to 0 */
2398
2399 /* Write all the data to the buffer */
2400 bp += 8; /* Skip padding */
2401 for (i = 0; i < p->size; i++, bp += 4) {
2402 if ((rv = write_U16Fixed16Number(p->data[i],bp)) != 0) {
2403 sprintf(icp->err,"icmU16Fixed16Array_write: write_U16Fixed16umber() failed");
2404 icp->al->free(icp->al, buf);
2405 return icp->errc = rv;
2406 }
2407 }
2408
2409 /* Write to the file */
2410 if ( icp->fp->seek(icp->fp, of) != 0
2411 || icp->fp->write(icp->fp, buf, 1, len) != len) {
2412 sprintf(icp->err,"icmU16Fixed16Array_write fseek() or fwrite() failed");
2413 icp->al->free(icp->al, buf);
2414 return icp->errc = 2;
2415 }
2416 icp->al->free(icp->al, buf);
2417 return 0;
2418 }
2419
2420 /* Dump a text description of the object */
icmU16Fixed16Array_dump(icmBase * pp,FILE * op,int verb)2421 static void icmU16Fixed16Array_dump(
2422 icmBase *pp,
2423 FILE *op, /* Output to dump to */
2424 int verb /* Verbosity level */
2425 ) {
2426 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2427 if (verb <= 0)
2428 return;
2429
2430 fprintf(op,"U16Fixed16Array:\n");
2431 fprintf(op," No. elements = %lu\n",p->size);
2432 if (verb >= 2) {
2433 unsigned long i;
2434 for (i = 0; i < p->size; i++)
2435 fprintf(op," %lu: %f\n",i,p->data[i]);
2436 }
2437 }
2438
2439 /* Allocate variable sized data elements */
icmU16Fixed16Array_allocate(icmBase * pp)2440 static int icmU16Fixed16Array_allocate(
2441 icmBase *pp
2442 ) {
2443 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2444 icc *icp = p->icp;
2445
2446 if (p->size != p->_size) {
2447 if (p->data != NULL)
2448 icp->al->free(icp->al, p->data);
2449 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
2450 sprintf(icp->err,"icmU16Fixed16Array_alloc: malloc() of icmU16Fixed16Array data failed");
2451 return icp->errc = 2;
2452 }
2453 p->_size = p->size;
2454 }
2455 return 0;
2456 }
2457
2458 /* Free all storage in the object */
icmU16Fixed16Array_delete(icmBase * pp)2459 static void icmU16Fixed16Array_delete(
2460 icmBase *pp
2461 ) {
2462 icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2463 icc *icp = p->icp;
2464
2465 if (p->data != NULL)
2466 icp->al->free(icp->al, p->data);
2467 icp->al->free(icp->al, p);
2468 }
2469
2470 /* Create an empty object. Return null on error */
new_icmU16Fixed16Array(icc * icp)2471 static icmBase *new_icmU16Fixed16Array(
2472 icc *icp
2473 ) {
2474 icmU16Fixed16Array *p;
2475 if ((p = (icmU16Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmU16Fixed16Array))) == NULL)
2476 return NULL;
2477 p->ttype = icSigU16Fixed16ArrayType;
2478 p->refcount = 1;
2479 p->get_size = icmU16Fixed16Array_get_size;
2480 p->read = icmU16Fixed16Array_read;
2481 p->write = icmU16Fixed16Array_write;
2482 p->dump = icmU16Fixed16Array_dump;
2483 p->allocate = icmU16Fixed16Array_allocate;
2484 p->del = icmU16Fixed16Array_delete;
2485 p->icp = icp;
2486
2487 return (icmBase *)p;
2488 }
2489
2490 /* ---------------------------------------------------------- */
2491 /* icmS15Fixed16Array object */
2492
2493 /* Return the number of bytes needed to write this tag */
icmS15Fixed16Array_get_size(icmBase * pp)2494 static unsigned int icmS15Fixed16Array_get_size(
2495 icmBase *pp
2496 ) {
2497 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2498 unsigned int len = 0;
2499 len += 8; /* 8 bytes for tag and padding */
2500 len += p->size * 4; /* 4 byte for each S15Fixed16 */
2501 return len;
2502 }
2503
2504 /* read the object, return 0 on success, error code on fail */
icmS15Fixed16Array_read(icmBase * pp,unsigned long len,unsigned long of)2505 static int icmS15Fixed16Array_read(
2506 icmBase *pp,
2507 unsigned long len, /* tag length */
2508 unsigned long of /* start offset within file */
2509 ) {
2510 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2511 icc *icp = p->icp;
2512 int rv = 0;
2513 unsigned long i, size;
2514 char *bp, *buf;
2515
2516 if (len < 8) {
2517 sprintf(icp->err,"icmS15Fixed16Array_read: Tag too small to be legal");
2518 return icp->errc = 1;
2519 }
2520
2521 /* Allocate a file read buffer */
2522 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2523 sprintf(icp->err,"icmS15Fixed16Array_read: malloc() failed");
2524 return icp->errc = 2;
2525 }
2526 bp = buf;
2527
2528 /* Read portion of file into buffer */
2529 if ( icp->fp->seek(icp->fp, of) != 0
2530 || icp->fp->read(icp->fp, bp, 1, len) != len) {
2531 sprintf(icp->err,"icmS15Fixed16Array_read: fseek() or fread() failed");
2532 icp->al->free(icp->al, buf);
2533 return icp->errc = 1;
2534 }
2535 p->size = size = (len - 8)/4; /* Number of elements in the array */
2536
2537 if ((rv = p->allocate((icmBase *)p)) != 0) {
2538 icp->al->free(icp->al, buf);
2539 return rv;
2540 }
2541
2542 /* Read type descriptor from the buffer */
2543 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2544 sprintf(icp->err,"icmS15Fixed16Array_read: Wrong tag type for icmS15Fixed16Array");
2545 icp->al->free(icp->al, buf);
2546 return icp->errc = 1;
2547 }
2548 bp += 8; /* Skip padding */
2549
2550 /* Read all the data from the buffer */
2551 for (i = 0; i < size; i++, bp += 4) {
2552 p->data[i] = read_S15Fixed16Number(bp);
2553 }
2554 icp->al->free(icp->al, buf);
2555 return 0;
2556 }
2557
2558 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmS15Fixed16Array_write(icmBase * pp,unsigned long of)2559 static int icmS15Fixed16Array_write(
2560 icmBase *pp,
2561 unsigned long of /* File offset to write from */
2562 ) {
2563 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2564 icc *icp = p->icp;
2565 unsigned long i;
2566 unsigned int len;
2567 char *bp, *buf; /* Buffer to write from */
2568 int rv = 0;
2569
2570 /* Allocate a file write buffer */
2571 len = p->get_size((icmBase *)p);
2572 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2573 sprintf(icp->err,"icmS15Fixed16Array_write malloc() failed");
2574 return icp->errc = 2;
2575 }
2576 bp = buf;
2577
2578 /* Write type descriptor to the buffer */
2579 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2580 sprintf(icp->err,"icmS15Fixed16Array_write: write_SInt32Number() failed");
2581 icp->al->free(icp->al, buf);
2582 return icp->errc = rv;
2583 }
2584 write_SInt32Number(0,bp+4); /* Set padding to 0 */
2585
2586 /* Write all the data to the buffer */
2587 bp += 8; /* Skip padding */
2588 for (i = 0; i < p->size; i++, bp += 4) {
2589 if ((rv = write_S15Fixed16Number(p->data[i],bp)) != 0) {
2590 sprintf(icp->err,"icmS15Fixed16Array_write: write_S15Fixed16umber() failed");
2591 icp->al->free(icp->al, buf);
2592 return icp->errc = rv;
2593 }
2594 }
2595
2596 /* Write to the file */
2597 if ( icp->fp->seek(icp->fp, of) != 0
2598 || icp->fp->write(icp->fp, buf, 1, len) != len) {
2599 sprintf(icp->err,"icmS15Fixed16Array_write fseek() or fwrite() failed");
2600 icp->al->free(icp->al, buf);
2601 return icp->errc = 2;
2602 }
2603 icp->al->free(icp->al, buf);
2604 return 0;
2605 }
2606
2607 /* Dump a text description of the object */
icmS15Fixed16Array_dump(icmBase * pp,FILE * op,int verb)2608 static void icmS15Fixed16Array_dump(
2609 icmBase *pp,
2610 FILE *op, /* Output to dump to */
2611 int verb /* Verbosity level */
2612 ) {
2613 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2614 if (verb <= 0)
2615 return;
2616
2617 fprintf(op,"S15Fixed16Array:\n");
2618 fprintf(op," No. elements = %lu\n",p->size);
2619 if (verb >= 2) {
2620 unsigned long i;
2621 for (i = 0; i < p->size; i++)
2622 fprintf(op," %lu: %f\n",i,p->data[i]);
2623 }
2624 }
2625
2626 /* Allocate variable sized data elements */
icmS15Fixed16Array_allocate(icmBase * pp)2627 static int icmS15Fixed16Array_allocate(
2628 icmBase *pp
2629 ) {
2630 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2631 icc *icp = p->icp;
2632
2633 if (p->size != p->_size) {
2634 if (p->data != NULL)
2635 icp->al->free(icp->al, p->data);
2636 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
2637 sprintf(icp->err,"icmS15Fixed16Array_alloc: malloc() of icmS15Fixed16Array data failed");
2638 return icp->errc = 2;
2639 }
2640 p->_size = p->size;
2641 }
2642 return 0;
2643 }
2644
2645 /* Free all storage in the object */
icmS15Fixed16Array_delete(icmBase * pp)2646 static void icmS15Fixed16Array_delete(
2647 icmBase *pp
2648 ) {
2649 icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2650 icc *icp = p->icp;
2651
2652 if (p->data != NULL)
2653 icp->al->free(icp->al, p->data);
2654 icp->al->free(icp->al, p);
2655 }
2656
2657 /* Create an empty object. Return null on error */
new_icmS15Fixed16Array(icc * icp)2658 static icmBase *new_icmS15Fixed16Array(
2659 icc *icp
2660 ) {
2661 icmS15Fixed16Array *p;
2662 if ((p = (icmS15Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmS15Fixed16Array))) == NULL)
2663 return NULL;
2664 p->ttype = icSigS15Fixed16ArrayType;
2665 p->refcount = 1;
2666 p->get_size = icmS15Fixed16Array_get_size;
2667 p->read = icmS15Fixed16Array_read;
2668 p->write = icmS15Fixed16Array_write;
2669 p->dump = icmS15Fixed16Array_dump;
2670 p->allocate = icmS15Fixed16Array_allocate;
2671 p->del = icmS15Fixed16Array_delete;
2672 p->icp = icp;
2673
2674 return (icmBase *)p;
2675 }
2676
2677 /* ---------------------------------------------------------- */
2678
2679 /* Data conversion support functions */
write_XYZNumber(icmXYZNumber * p,char * d)2680 static int write_XYZNumber(icmXYZNumber *p, char *d) {
2681 int rv;
2682 if ((rv = write_S15Fixed16Number(p->X, d + 0)) != 0)
2683 return rv;
2684 if ((rv = write_S15Fixed16Number(p->Y, d + 4)) != 0)
2685 return rv;
2686 if ((rv = write_S15Fixed16Number(p->Z, d + 8)) != 0)
2687 return rv;
2688 return 0;
2689 }
2690
read_XYZNumber(icmXYZNumber * p,char * d)2691 static int read_XYZNumber(icmXYZNumber *p, char *d) {
2692 p->X = read_S15Fixed16Number(d + 0);
2693 p->Y = read_S15Fixed16Number(d + 4);
2694 p->Z = read_S15Fixed16Number(d + 8);
2695 return 0;
2696 }
2697
2698
2699 /* Helper: Return a string that shows the XYZ number value */
string_XYZNumber(icmXYZNumber * p)2700 static char *string_XYZNumber(icmXYZNumber *p) {
2701 static char buf[40];
2702
2703 sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z);
2704 return buf;
2705 }
2706
2707 /* Helper: Return a string that shows the XYZ number value, */
2708 /* and the Lab D50 number in paren. */
string_XYZNumber_and_Lab(icmXYZNumber * p)2709 static char *string_XYZNumber_and_Lab(icmXYZNumber *p) {
2710 static char buf[50];
2711 double lab[3];
2712 lab[0] = p->X;
2713 lab[1] = p->Y;
2714 lab[2] = p->Z;
2715 icmXYZ2Lab(&icmD50, lab, lab);
2716 sprintf(buf,"%f, %f, %f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
2717 return buf;
2718 }
2719
2720 /* icmXYZArray object */
2721
2722 /* Return the number of bytes needed to write this tag */
icmXYZArray_get_size(icmBase * pp)2723 static unsigned int icmXYZArray_get_size(
2724 icmBase *pp
2725 ) {
2726 icmXYZArray *p = (icmXYZArray *)pp;
2727 unsigned int len = 0;
2728 len += 8; /* 8 bytes for tag and padding */
2729 len += p->size * 12; /* 12 bytes for each XYZ */
2730 return len;
2731 }
2732
2733 /* read the object, return 0 on success, error code on fail */
icmXYZArray_read(icmBase * pp,unsigned long len,unsigned long of)2734 static int icmXYZArray_read(
2735 icmBase *pp,
2736 unsigned long len, /* tag length */
2737 unsigned long of /* start offset within file */
2738 ) {
2739 icmXYZArray *p = (icmXYZArray *)pp;
2740 icc *icp = p->icp;
2741 int rv = 0;
2742 unsigned long i, size;
2743 char *bp, *buf;
2744
2745 if (len < 8) {
2746 sprintf(icp->err,"icmXYZArray_read: Tag too small to be legal");
2747 return icp->errc = 1;
2748 }
2749
2750 /* Allocate a file read buffer */
2751 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2752 sprintf(icp->err,"icmXYZArray_read: malloc() failed");
2753 return icp->errc = 2;
2754 }
2755 bp = buf;
2756
2757 /* Read portion of file into buffer */
2758 if ( icp->fp->seek(icp->fp, of) != 0
2759 || icp->fp->read(icp->fp, bp, 1, len) != len) {
2760 sprintf(icp->err,"icmXYZArray_read: fseek() or fread() failed");
2761 icp->al->free(icp->al, buf);
2762 return icp->errc = 1;
2763 }
2764 p->size = size = (len - 8)/12; /* Number of elements in the array */
2765
2766 if ((rv = p->allocate((icmBase *)p)) != 0) {
2767 icp->al->free(icp->al, buf);
2768 return rv;
2769 }
2770
2771 /* Read type descriptor from the buffer */
2772 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2773 sprintf(icp->err,"icmXYZArray_read: Wrong tag type for icmXYZArray");
2774 icp->al->free(icp->al, buf);
2775 return icp->errc = 1;
2776 }
2777 bp += 8; /* Skip padding */
2778
2779 /* Read all the data from the buffer */
2780 for (i = 0; i < size; i++, bp += 12) {
2781 read_XYZNumber(&p->data[i], bp);
2782 }
2783 icp->al->free(icp->al, buf);
2784 return 0;
2785 }
2786
2787 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmXYZArray_write(icmBase * pp,unsigned long of)2788 static int icmXYZArray_write(
2789 icmBase *pp,
2790 unsigned long of /* File offset to write from */
2791 ) {
2792 icmXYZArray *p = (icmXYZArray *)pp;
2793 icc *icp = p->icp;
2794 unsigned long i;
2795 unsigned int len;
2796 char *bp, *buf; /* Buffer to write from */
2797 int rv = 0;
2798
2799 /* Allocate a file write buffer */
2800 len = p->get_size((icmBase *)p);
2801 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2802 sprintf(icp->err,"icmXYZArray_write malloc() failed");
2803 return icp->errc = 2;
2804 }
2805 bp = buf;
2806
2807 /* Write type descriptor to the buffer */
2808 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2809 sprintf(icp->err,"icmXYZArray_write: write_SInt32Number() failed");
2810 icp->al->free(icp->al, buf);
2811 return icp->errc = rv;
2812 }
2813 write_SInt32Number(0,bp+4); /* Set padding to 0 */
2814
2815 /* Write all the data to the buffer */
2816 bp += 8; /* Skip padding */
2817 for (i = 0; i < p->size; i++, bp += 12) {
2818 if ((rv = write_XYZNumber(&p->data[i],bp)) != 0) {
2819 sprintf(icp->err,"icmXYZArray_write: write_XYZumber() failed");
2820 icp->al->free(icp->al, buf);
2821 return icp->errc = rv;
2822 }
2823 }
2824
2825 /* Write to the file */
2826 if ( icp->fp->seek(icp->fp, of) != 0
2827 || icp->fp->write(icp->fp, buf, 1, len) != len) {
2828 sprintf(icp->err,"icmXYZArray_write fseek() or fwrite() failed");
2829 icp->al->free(icp->al, buf);
2830 return icp->errc = 2;
2831 }
2832 icp->al->free(icp->al, buf);
2833 return 0;
2834 }
2835
2836 /* Dump a text description of the object */
icmXYZArray_dump(icmBase * pp,FILE * op,int verb)2837 static void icmXYZArray_dump(
2838 icmBase *pp,
2839 FILE *op, /* Output to dump to */
2840 int verb /* Verbosity level */
2841 ) {
2842 icmXYZArray *p = (icmXYZArray *)pp;
2843 if (verb <= 0)
2844 return;
2845
2846 fprintf(op,"XYZArray:\n");
2847 fprintf(op," No. elements = %lu\n",p->size);
2848 if (verb >= 2) {
2849 unsigned long i;
2850 for (i = 0; i < p->size; i++) {
2851 fprintf(op," %lu: %s\n",i,string_XYZNumber_and_Lab(&p->data[i]));
2852
2853 }
2854 }
2855 }
2856
2857
2858 /* Allocate variable sized data elements */
icmXYZArray_allocate(icmBase * pp)2859 static int icmXYZArray_allocate(
2860 icmBase *pp
2861 ) {
2862 icmXYZArray *p = (icmXYZArray *)pp;
2863 icc *icp = p->icp;
2864
2865 if (p->size != p->_size) {
2866 if (p->data != NULL)
2867 icp->al->free(icp->al, p->data);
2868 if ((p->data = (icmXYZNumber *) icp->al->malloc(icp->al, p->size * sizeof(icmXYZNumber))) == NULL) {
2869 sprintf(icp->err,"icmXYZArray_alloc: malloc() of icmXYZArray data failed");
2870 return icp->errc = 2;
2871 }
2872 p->_size = p->size;
2873 }
2874 return 0;
2875 }
2876
2877 /* Free all storage in the object */
icmXYZArray_delete(icmBase * pp)2878 static void icmXYZArray_delete(
2879 icmBase *pp
2880 ) {
2881 icmXYZArray *p = (icmXYZArray *)pp;
2882 icc *icp = p->icp;
2883
2884 if (p->data != NULL)
2885 icp->al->free(icp->al, p->data);
2886 icp->al->free(icp->al, p);
2887 }
2888
2889 /* Create an empty object. Return null on error */
new_icmXYZArray(icc * icp)2890 static icmBase *new_icmXYZArray(
2891 icc *icp
2892 ) {
2893 icmXYZArray *p;
2894 if ((p = (icmXYZArray *) icp->al->calloc(icp->al,1,sizeof(icmXYZArray))) == NULL)
2895 return NULL;
2896 p->ttype = icSigXYZArrayType;
2897 p->refcount = 1;
2898 p->get_size = icmXYZArray_get_size;
2899 p->read = icmXYZArray_read;
2900 p->write = icmXYZArray_write;
2901 p->dump = icmXYZArray_dump;
2902 p->allocate = icmXYZArray_allocate;
2903 p->del = icmXYZArray_delete;
2904 p->icp = icp;
2905
2906 return (icmBase *)p;
2907 }
2908
2909 /* ---------------------------------------------------------- */
2910 /* icmCurve object */
2911
2912 /* Do a forward lookup through the curve */
2913 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmCurve_lookup_fwd(icmCurve * p,double * out,double * in)2914 static int icmCurve_lookup_fwd(
2915 icmCurve *p,
2916 double *out,
2917 double *in
2918 ) {
2919 int rv = 0;
2920 if (p->flag == icmCurveLin) {
2921 *out = *in;
2922 } else if (p->flag == icmCurveGamma) {
2923 double val = *in;
2924 if (val <= 0.0)
2925 *out = 0.0;
2926 else
2927 *out = pow(val, p->data[0]);
2928 } else { /* Use linear interpolation */
2929 int ix;
2930 double val, w;
2931 double inputEnt_1 = (double)(p->size-1);
2932
2933 val = *in * inputEnt_1;
2934 if (val < 0.0) {
2935 val = 0.0;
2936 rv |= 1;
2937 } else if (val > inputEnt_1) {
2938 val = inputEnt_1;
2939 rv |= 1;
2940 }
2941 ix = (int)floor(val); /* Coordinate */
2942 if (ix > (p->size-2))
2943 ix = (p->size-2);
2944 w = val - (double)ix; /* weight */
2945 val = p->data[ix];
2946 *out = val + w * (p->data[ix+1] - val);
2947 }
2948 return rv;
2949 }
2950
2951 /* - - - - - - - - - - - - */
2952 /* Support for reverse interpolation of 1D lookup tables */
2953
2954 /* Create a reverse curve lookup acceleration table */
2955 /* return non-zero on error, 2 = malloc error. */
icmTable_setup_bwd(icc * icp,icmRevTable * rt,unsigned long size,double * data)2956 static int icmTable_setup_bwd(
2957 icc *icp, /* Base icc object */
2958 icmRevTable *rt, /* Reverse table data to setup */
2959 unsigned long size, /* Size of fwd table */
2960 double *data /* Table */
2961 ) {
2962 int i;
2963
2964 rt->size = size; /* Stash pointers to these away */
2965 rt->data = data;
2966
2967 /* Find range of output values */
2968 rt->rmin = 1e300;
2969 rt->rmax = -1e300;
2970 for (i = 0; i < rt->size; i++) {
2971 if (rt->data[i] > rt->rmax)
2972 rt->rmax = rt->data[i];
2973 if (rt->data[i] < rt->rmin)
2974 rt->rmin = rt->data[i];
2975 }
2976
2977 /* Decide on reverse granularity */
2978 rt->rsize = (rt->size+2)/2;
2979 rt->qscale = (double)rt->rsize/(rt->rmax - rt->rmin); /* Scale factor to quantize to */
2980
2981 /* Initialize the reverse lookup structures, and get overall min/max */
2982 if ((rt->rlists = (int **) icp->al->calloc(icp->al, 1, rt->rsize * sizeof(int *))) == NULL) {
2983 return 2;
2984 }
2985
2986 /* Assign each output value range bucket lists it intersects */
2987 for (i = 0; i < (rt->size-1); i++) {
2988 int s, e, j; /* Start and end indexes (inclusive) */
2989 s = (int)((rt->data[i] - rt->rmin) * rt->qscale);
2990 e = (int)((rt->data[i+1] - rt->rmin) * rt->qscale);
2991 if (s > e) { /* swap */
2992 int t;
2993 t = s; s = e; e = t;
2994 }
2995 if (e >= rt->rsize)
2996 e = rt->rsize-1;
2997
2998 /* For all buckets that may contain this output range, add index of this output */
2999 for (j = s; j <= e; j++) {
3000 int as; /* Allocation size */
3001 int nf; /* Next free slot */
3002 if (rt->rlists[j] == NULL) { /* No allocation */
3003 as = 5; /* Start with space for 5 */
3004 if ((rt->rlists[j] = (int *) icp->al->malloc(icp->al, sizeof(int) * as)) == NULL) {
3005 return 2;
3006 }
3007 rt->rlists[j][0] = as;
3008 nf = rt->rlists[j][1] = 2;
3009 } else {
3010 as = rt->rlists[j][0]; /* Allocate space for this list */
3011 nf = rt->rlists[j][1]; /* Next free location in list */
3012 if (nf >= as) { /* need to expand space */
3013 as *= 2;
3014 rt->rlists[j] = (int *) icp->al->realloc(icp->al,rt->rlists[j], sizeof(int) * as);
3015 if (rt->rlists[j] == NULL) {
3016 return 2;
3017 }
3018 rt->rlists[j][0] = as;
3019 }
3020 }
3021 rt->rlists[j][nf++] = i;
3022 rt->rlists[j][1] = nf;
3023 }
3024 }
3025 rt->inited = 1;
3026 return 0;
3027 }
3028
3029 /* Free up any data */
icmTable_delete_bwd(icc * icp,icmRevTable * rt)3030 static void icmTable_delete_bwd(
3031 icc *icp, /* Base icc */
3032 icmRevTable *rt /* Reverse table data to setup */
3033 ) {
3034 if (rt->inited != 0) {
3035 while (rt->rsize > 0)
3036 icp->al->free(icp->al, rt->rlists[--rt->rsize]);
3037 icp->al->free(icp->al, rt->rlists);
3038 rt->size = 0; /* Don't keep these */
3039 rt->data = NULL;
3040 }
3041 }
3042
3043 /* Do a reverse lookup through the curve */
3044 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmTable_lookup_bwd(icmRevTable * rt,double * out,double * in)3045 static int icmTable_lookup_bwd(
3046 icmRevTable *rt,
3047 double *out,
3048 double *in
3049 ) {
3050 int rv = 0;
3051 int ix, i, k;
3052 double oval, ival = *in, val;
3053 double rsize_1;
3054
3055 /* Find appropriate reverse list */
3056 rsize_1 = (double)(rt->rsize-1);
3057 val = ((ival - rt->rmin) * rt->qscale);
3058 if (val < 0.0)
3059 val = 0.0;
3060 else if (val > rsize_1)
3061 val = rsize_1;
3062 ix = (int)floor(val); /* Coordinate */
3063
3064 if (ix > (rt->size-2))
3065 ix = (rt->size-2);
3066 if (rt->rlists[ix] != NULL) { /* There is a list of fwd candidates */
3067 /* For each candidate forward range */
3068 for (i = 2; i < rt->rlists[ix][1]; i++) { /* For all fwd indexes */
3069 double lv,hv;
3070 k = rt->rlists[ix][i]; /* Base index */
3071 lv = rt->data[k];
3072 hv = rt->data[k+1];
3073 if ((ival >= lv && ival <= hv) /* If this slot contains output value */
3074 || (ival >= hv && ival <= lv)) {
3075 /* Reverse linear interpolation */
3076 if (hv == lv) { /* Technically non-monotonic - due to quantization ? */
3077 oval = (k + 0.5)/(rt->size-1.0);
3078 } else
3079 oval = (k + ((ival - lv)/(hv - lv)))/(rt->size-1.0);
3080 /* If we kept looking, we would find multiple */
3081 /* solution for non-monotonic curve */
3082 *out = oval;
3083 return rv;
3084 }
3085 }
3086 }
3087
3088 /* We have failed to find an exact value, so return the nearest value */
3089 /* (This is slow !) */
3090 val = fabs(ival - rt->data[0]);
3091 for (k = 0, i = 1; i < rt->size; i++) {
3092 double er;
3093 er = fabs(ival - rt->data[i]);
3094 if (er < val) { /* new best */
3095 val = er;
3096 k = i;
3097 }
3098 }
3099 *out = k/(rt->size-1.0);
3100 rv |= 1;
3101 return rv;
3102 }
3103
3104
3105 /* - - - - - - - - - - - - */
3106
3107 /* Do a reverse lookup through the curve */
3108 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmCurve_lookup_bwd(icmCurve * p,double * out,double * in)3109 static int icmCurve_lookup_bwd(
3110 icmCurve *p,
3111 double *out,
3112 double *in
3113 ) {
3114 icc *icp = p->icp;
3115 int rv = 0;
3116 if (p->flag == icmCurveLin) {
3117 *out = *in;
3118 } else if (p->flag == icmCurveGamma) {
3119 double val = *in;
3120 if (val <= 0.0)
3121 *out = 0.0;
3122 else
3123 *out = pow(val, 1.0/p->data[0]);
3124 } else { /* Use linear interpolation */
3125 if (p->rt.inited == 0) {
3126 rv = icmTable_setup_bwd(icp, &p->rt, p->size, p->data);
3127 if (rv != 0) {
3128 sprintf(icp->err,"icmCurve_lookup: Malloc failure in reverse lookup init.");
3129 return icp->errc = rv;
3130 }
3131 }
3132 rv = icmTable_lookup_bwd(&p->rt, out, in);
3133 }
3134 return rv;
3135 }
3136
3137 /* Return the number of bytes needed to write this tag */
icmCurve_get_size(icmBase * pp)3138 static unsigned int icmCurve_get_size(
3139 icmBase *pp
3140 ) {
3141 icmCurve *p = (icmCurve *)pp;
3142 unsigned int len = 0;
3143 len += 12; /* 12 bytes for tag, padding and count */
3144 len += p->size * 2; /* 2 bytes for each UInt16 */
3145 return len;
3146 }
3147
3148 /* read the object, return 0 on success, error code on fail */
icmCurve_read(icmBase * pp,unsigned long len,unsigned long of)3149 static int icmCurve_read(
3150 icmBase *pp,
3151 unsigned long len, /* tag length */
3152 unsigned long of /* start offset within file */
3153 ) {
3154 icmCurve *p = (icmCurve *)pp;
3155 icc *icp = p->icp;
3156 int rv = 0;
3157 unsigned long i;
3158 char *bp, *buf, *end;
3159
3160 if (len < 12) {
3161 sprintf(icp->err,"icmCurve_read: Tag too small to be legal");
3162 return icp->errc = 1;
3163 }
3164
3165 /* Allocate a file read buffer */
3166 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3167 sprintf(icp->err,"icmCurve_read: malloc() failed");
3168 return icp->errc = 2;
3169 }
3170 bp = buf;
3171 end = buf + len;
3172
3173 /* Read portion of file into buffer */
3174 if ( icp->fp->seek(icp->fp, of) != 0
3175 || icp->fp->read(icp->fp, bp, 1, len) != len) {
3176 sprintf(icp->err,"icmCurve_read: fseek() or fread() failed");
3177 icp->al->free(icp->al, buf);
3178 return icp->errc = 1;
3179 }
3180
3181 /* Read type descriptor from the buffer */
3182 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3183 sprintf(icp->err,"icmCurve_read: Wrong tag type for icmCurve");
3184 icp->al->free(icp->al, buf);
3185 return icp->errc = 1;
3186 }
3187
3188 p->size = read_UInt32Number(bp+8);
3189 bp = bp + 12;
3190
3191 /* Set flag up before allocating */
3192 if (p->size == 0) { /* Linear curve */
3193 p->flag = icmCurveLin;
3194 } else if (p->size == 1) { /* Gamma curve */
3195 p->flag = icmCurveGamma;
3196 } else {
3197 p->flag = icmCurveSpec;
3198 }
3199
3200 if ((rv = p->allocate((icmBase *)p)) != 0) {
3201 icp->al->free(icp->al, buf);
3202 return rv;
3203 }
3204
3205 if (p->flag == icmCurveGamma) { /* Gamma curve */
3206 if ((bp + 1) > end) {
3207 sprintf(icp->err,"icmCurve_read: Data too short to curve gamma");
3208 icp->al->free(icp->al, buf);
3209 return icp->errc = 1;
3210 }
3211 p->data[0] = read_U8Fixed8Number(bp);
3212 } else if (p->flag == icmCurveSpec) {
3213 /* Read all the data from the buffer */
3214 for (i = 0; i < p->size; i++, bp += 2) {
3215 if ((bp + 2) > end) {
3216 sprintf(icp->err,"icmData_read: Data too short to curve value");
3217 icp->al->free(icp->al, buf);
3218 return icp->errc = 1;
3219 }
3220 p->data[i] = read_DCS16Number(bp);
3221 }
3222 }
3223 icp->al->free(icp->al, buf);
3224 return 0;
3225 }
3226
3227 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmCurve_write(icmBase * pp,unsigned long of)3228 static int icmCurve_write(
3229 icmBase *pp,
3230 unsigned long of /* File offset to write from */
3231 ) {
3232 icmCurve *p = (icmCurve *)pp;
3233 icc *icp = p->icp;
3234 unsigned long i;
3235 unsigned int len;
3236 char *bp, *buf; /* Buffer to write from */
3237 int rv = 0;
3238
3239 /* Allocate a file write buffer */
3240 len = p->get_size((icmBase *)p);
3241 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3242 sprintf(icp->err,"icmCurve_write malloc() failed");
3243 return icp->errc = 2;
3244 }
3245 bp = buf;
3246
3247 /* Write type descriptor to the buffer */
3248 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3249 sprintf(icp->err,"icmCurve_write: write_SInt32Number() failed");
3250 icp->al->free(icp->al, buf);
3251 return icp->errc = rv;
3252 }
3253 write_SInt32Number(0,bp+4); /* Set padding to 0 */
3254 /* Write count */
3255 if ((rv = write_UInt32Number(p->size,bp+8)) != 0) {
3256 sprintf(icp->err,"icmCurve_write: write_UInt32Number() failed");
3257 icp->al->free(icp->al, buf);
3258 return icp->errc = rv;
3259 }
3260
3261 /* Write all the data to the buffer */
3262 bp += 12; /* Skip padding */
3263 if (p->flag == icmCurveLin) {
3264 if (p->size != 0) {
3265 sprintf(icp->err,"icmCurve_write: Must be exactly 0 entry for Linear");
3266 icp->al->free(icp->al, buf);
3267 return icp->errc = 1;
3268 }
3269 } else if (p->flag == icmCurveGamma) {
3270 if (p->size != 1) {
3271 sprintf(icp->err,"icmCurve_write: Must be exactly 1 entry for Gamma");
3272 icp->al->free(icp->al, buf);
3273 return icp->errc = 1;
3274 }
3275 if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) {
3276 sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]);
3277 icp->al->free(icp->al, buf);
3278 return icp->errc = rv;
3279 }
3280 } else if (p->flag == icmCurveSpec) {
3281 if (p->size < 2) {
3282 sprintf(icp->err,"icmCurve_write: Must be 2 or more entries for Specified curve");
3283 icp->al->free(icp->al, buf);
3284 return icp->errc = 1;
3285 }
3286 for (i = 0; i < p->size; i++, bp += 2) {
3287 if ((rv = write_DCS16Number(p->data[i],bp)) != 0) {
3288 sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]);
3289 icp->al->free(icp->al, buf);
3290 return icp->errc = rv;
3291 }
3292 }
3293 }
3294
3295 /* Write to the file */
3296 if ( icp->fp->seek(icp->fp, of) != 0
3297 || icp->fp->write(icp->fp, buf, 1, len) != len) {
3298 sprintf(icp->err,"icmCurve_write fseek() or fwrite() failed");
3299 icp->al->free(icp->al, buf);
3300 return icp->errc = 2;
3301 }
3302 icp->al->free(icp->al, buf);
3303 return 0;
3304 }
3305
3306 /* Dump a text description of the object */
icmCurve_dump(icmBase * pp,FILE * op,int verb)3307 static void icmCurve_dump(
3308 icmBase *pp,
3309 FILE *op, /* Output to dump to */
3310 int verb /* Verbosity level */
3311 ) {
3312 icmCurve *p = (icmCurve *)pp;
3313 if (verb <= 0)
3314 return;
3315
3316 fprintf(op,"Curve:\n");
3317
3318 if (p->flag == icmCurveLin) {
3319 fprintf(op," Curve is linear\n");
3320 } else if (p->flag == icmCurveGamma) {
3321 fprintf(op," Curve is gamma of %f\n",p->data[0]);
3322 } else {
3323 fprintf(op," No. elements = %lu\n",p->size);
3324 if (verb >= 2) {
3325 unsigned long i;
3326 for (i = 0; i < p->size; i++)
3327 fprintf(op," %3lu: %f\n",i,p->data[i]);
3328 }
3329 }
3330 }
3331
3332 /* Allocate variable sized data elements */
icmCurve_allocate(icmBase * pp)3333 static int icmCurve_allocate(
3334 icmBase *pp
3335 ) {
3336 icmCurve *p = (icmCurve *)pp;
3337 icc *icp = p->icp;
3338
3339 if (p->flag == icmCurveUndef) {
3340 sprintf(icp->err,"icmCurve_alloc: flag not set");
3341 return icp->errc = 1;
3342 } else if (p->flag == icmCurveLin) {
3343 p->size = 0;
3344 } else if (p->flag == icmCurveGamma) {
3345 p->size = 1;
3346 }
3347 if (p->size != p->_size) {
3348 if (p->data != NULL)
3349 icp->al->free(icp->al, p->data);
3350 if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
3351 sprintf(icp->err,"icmCurve_alloc: malloc() of icmCurve data failed");
3352 return icp->errc = 2;
3353 }
3354 p->_size = p->size;
3355 }
3356 return 0;
3357 }
3358
3359 /* Free all storage in the object */
icmCurve_delete(icmBase * pp)3360 static void icmCurve_delete(
3361 icmBase *pp
3362 ) {
3363 icmCurve *p = (icmCurve *)pp;
3364 icc *icp = p->icp;
3365
3366 if (p->data != NULL)
3367 icp->al->free(icp->al, p->data);
3368 icmTable_delete_bwd(icp, &p->rt); /* Free reverse table info */
3369 icp->al->free(icp->al, p);
3370 }
3371
3372 /* Create an empty object. Return null on error */
new_icmCurve(icc * icp)3373 static icmBase *new_icmCurve(
3374 icc *icp
3375 ) {
3376 icmCurve *p;
3377 if ((p = (icmCurve *) icp->al->calloc(icp->al,1,sizeof(icmCurve))) == NULL)
3378 return NULL;
3379 p->ttype = icSigCurveType;
3380 p->refcount = 1;
3381 p->get_size = icmCurve_get_size;
3382 p->read = icmCurve_read;
3383 p->write = icmCurve_write;
3384 p->dump = icmCurve_dump;
3385 p->allocate = icmCurve_allocate;
3386 p->del = icmCurve_delete;
3387 p->icp = icp;
3388
3389 p->lookup_fwd = icmCurve_lookup_fwd;
3390 p->lookup_bwd = icmCurve_lookup_bwd;
3391
3392 p->rt.inited = 0;
3393
3394 p->flag = icmCurveUndef;
3395 return (icmBase *)p;
3396 }
3397
3398 /* ---------------------------------------------------------- */
3399 /* icmData object */
3400
3401 /* Return the number of bytes needed to write this tag */
icmData_get_size(icmBase * pp)3402 static unsigned int icmData_get_size(
3403 icmBase *pp
3404 ) {
3405 icmData *p = (icmData *)pp;
3406 unsigned int len = 0;
3407 len += 12; /* 12 bytes for tag and padding */
3408 len += p->size * 1; /* 1 byte for each data element */
3409 return len;
3410 }
3411
3412 /* read the object, return 0 on success, error code on fail */
icmData_read(icmBase * pp,unsigned long len,unsigned long of)3413 static int icmData_read(
3414 icmBase *pp,
3415 unsigned long len, /* tag length */
3416 unsigned long of /* start offset within file */
3417 ) {
3418 icmData *p = (icmData *)pp;
3419 icc *icp = p->icp;
3420 int rv = 0;
3421 unsigned size, f;
3422 char *bp, *buf;
3423
3424 if (len < 12) {
3425 sprintf(icp->err,"icmData_read: Tag too small to be legal");
3426 return icp->errc = 1;
3427 }
3428
3429 /* Allocate a file read buffer */
3430 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3431 sprintf(icp->err,"icmData_read: malloc() failed");
3432 return icp->errc = 2;
3433 }
3434 bp = buf;
3435
3436 /* Read portion of file into buffer */
3437 if ( icp->fp->seek(icp->fp, of) != 0
3438 || icp->fp->read(icp->fp, bp, 1, len) != len) {
3439 sprintf(icp->err,"icmData_read: fseek() or fread() failed");
3440 icp->al->free(icp->al, buf);
3441 return icp->errc = 1;
3442 }
3443 p->size = size = (len - 12)/1; /* Number of elements in the array */
3444
3445 /* Read type descriptor from the buffer */
3446 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3447 sprintf(icp->err,"icmData_read: Wrong tag type for icmData");
3448 icp->al->free(icp->al, buf);
3449 return icp->errc = 1;
3450 }
3451 /* Read the data type flag */
3452 f = read_UInt32Number(bp+8);
3453 if (f == 0) {
3454 p->flag = icmDataASCII;
3455 } else if (f == 1) {
3456 p->flag = icmDataBin;
3457 } else {
3458 sprintf(icp->err,"icmData_read: Unknown flag value 0x%x",f);
3459 icp->al->free(icp->al, buf);
3460 return icp->errc = 1;
3461 }
3462 bp += 12; /* Skip padding and flag */
3463
3464 if (p->size > 0) {
3465 if (p->flag == icmDataASCII) {
3466 if (check_null_string(bp,p->size) != 0) {
3467 sprintf(icp->err,"icmData_read: ACSII is not null terminated");
3468 icp->al->free(icp->al, buf);
3469 return icp->errc = 1;
3470 }
3471 }
3472 if ((rv = p->allocate((icmBase *)p)) != 0) {
3473 icp->al->free(icp->al, buf);
3474 return rv;
3475 }
3476
3477 memcpy((void *)p->data, (void *)bp, p->size);
3478 }
3479 icp->al->free(icp->al, buf);
3480 return 0;
3481 }
3482
3483 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmData_write(icmBase * pp,unsigned long of)3484 static int icmData_write(
3485 icmBase *pp,
3486 unsigned long of /* File offset to write from */
3487 ) {
3488 icmData *p = (icmData *)pp;
3489 icc *icp = p->icp;
3490 unsigned int len, f;
3491 char *bp, *buf; /* Buffer to write from */
3492 int rv = 0;
3493
3494 /* Allocate a file write buffer */
3495 len = p->get_size((icmBase *)p);
3496 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3497 sprintf(icp->err,"icmData_write malloc() failed");
3498 return icp->errc = 2;
3499 }
3500 bp = buf;
3501
3502 /* Write type descriptor to the buffer */
3503 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3504 sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
3505 icp->al->free(icp->al, buf);
3506 return icp->errc = rv;
3507 }
3508 write_SInt32Number(0,bp+4); /* Set padding to 0 */
3509 switch(p->flag) {
3510 case icmDataASCII:
3511 f = 0;
3512 break;
3513 case icmDataBin:
3514 f = 1;
3515 break;
3516 default:
3517 sprintf(icp->err,"icmData_write: Unknown Data Flag value");
3518 icp->al->free(icp->al, buf);
3519 return icp->errc = 1;
3520 }
3521 /* Write data flag descriptor to the buffer */
3522 if ((rv = write_UInt32Number(f,bp+8)) != 0) {
3523 sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
3524 icp->al->free(icp->al, buf);
3525 return icp->errc = rv;
3526 }
3527 bp += 12; /* Skip padding */
3528
3529 if (p->data != NULL) {
3530 if (p->flag == icmDataASCII) {
3531 if ((rv = check_null_string((char *)p->data, p->size)) != 0) {
3532 sprintf(icp->err,"icmData_write: ASCII is not null terminated");
3533 icp->al->free(icp->al, buf);
3534 return icp->errc = 1;
3535 }
3536 }
3537 memcpy((void *)bp, (void *)p->data, p->size);
3538 }
3539
3540 /* Write to the file */
3541 if ( icp->fp->seek(icp->fp, of) != 0
3542 || icp->fp->write(icp->fp, buf, 1, len) != len) {
3543 sprintf(icp->err,"icmData_write fseek() or fwrite() failed");
3544 icp->al->free(icp->al, buf);
3545 return icp->errc = 2;
3546 }
3547 icp->al->free(icp->al, buf);
3548 return 0;
3549 }
3550
3551 /* Dump a text description of the object */
icmData_dump(icmBase * pp,FILE * op,int verb)3552 static void icmData_dump(
3553 icmBase *pp,
3554 FILE *op, /* Output to dump to */
3555 int verb /* Verbosity level */
3556 ) {
3557 icmData *p = (icmData *)pp;
3558 unsigned long i, r, c, size = 0;
3559
3560 if (verb <= 0)
3561 return;
3562
3563 fprintf(op,"Data:\n");
3564 switch(p->flag) {
3565 case icmDataASCII:
3566 fprintf(op," ASCII data\n");
3567 size = p->size > 0 ? p->size-1 : 0;
3568 break;
3569 case icmDataBin:
3570 fprintf(op," Binary data\n");
3571 size = p->size;
3572 break;
3573 case icmDataUndef:
3574 fprintf(op," Undefined data\n");
3575 size = p->size;
3576 break;
3577 }
3578 fprintf(op," No. elements = %lu\n",p->size);
3579
3580 i = 0;
3581 for (r = 1;; r++) { /* count rows */
3582 if (i >= size) {
3583 fprintf(op,"\n");
3584 break;
3585 }
3586 if (r > 1 && verb < 2) {
3587 fprintf(op,"...\n");
3588 break; /* Print 1 row if not verbose */
3589 }
3590 c = 1;
3591 fprintf(op," 0x%04lx: ",i);
3592 c += 10;
3593 while (i < size && c < 75) {
3594 if (p->flag == icmDataASCII) {
3595 if (isprint(p->data[i])) {
3596 fprintf(op,"%c",p->data[i]);
3597 c++;
3598 } else {
3599 fprintf(op,"\\%03o",p->data[i]);
3600 c += 4;
3601 }
3602 } else {
3603 fprintf(op,"%02x ",p->data[i]);
3604 c += 3;
3605 }
3606 i++;
3607 }
3608 if (i < size)
3609 fprintf(op,"\n");
3610 }
3611 }
3612
3613 /* Allocate variable sized data elements */
icmData_allocate(icmBase * pp)3614 static int icmData_allocate(
3615 icmBase *pp
3616 ) {
3617 icmData *p = (icmData *)pp;
3618 icc *icp = p->icp;
3619
3620 if (p->size != p->_size) {
3621 if (p->data != NULL)
3622 icp->al->free(icp->al, p->data);
3623 if ((p->data = (unsigned char *) icp->al->malloc(icp->al, p->size * sizeof(unsigned char))) == NULL) {
3624 sprintf(icp->err,"icmData_alloc: malloc() of icmData data failed");
3625 return icp->errc = 2;
3626 }
3627 p->_size = p->size;
3628 }
3629 return 0;
3630 }
3631
3632 /* Free all storage in the object */
icmData_delete(icmBase * pp)3633 static void icmData_delete(
3634 icmBase *pp
3635 ) {
3636 icmData *p = (icmData *)pp;
3637 icc *icp = p->icp;
3638
3639 if (p->data != NULL)
3640 icp->al->free(icp->al, p->data);
3641 icp->al->free(icp->al, p);
3642 }
3643
3644 /* Create an empty object. Return null on error */
new_icmData(icc * icp)3645 static icmBase *new_icmData(
3646 icc *icp
3647 ) {
3648 icmData *p;
3649 if ((p = (icmData *) icp->al->calloc(icp->al,1,sizeof(icmData))) == NULL)
3650 return NULL;
3651 p->ttype = icSigDataType;
3652 p->refcount = 1;
3653 p->get_size = icmData_get_size;
3654 p->read = icmData_read;
3655 p->write = icmData_write;
3656 p->dump = icmData_dump;
3657 p->allocate = icmData_allocate;
3658 p->del = icmData_delete;
3659 p->icp = icp;
3660
3661 p->flag = icmDataUndef;
3662 return (icmBase *)p;
3663 }
3664
3665 /* ---------------------------------------------------------- */
3666 /* icmText object */
3667
3668 /* Return the number of bytes needed to write this tag */
icmText_get_size(icmBase * pp)3669 static unsigned int icmText_get_size(
3670 icmBase *pp
3671 ) {
3672 icmText *p = (icmText *)pp;
3673 unsigned int len = 0;
3674 len += 8; /* 8 bytes for tag and padding */
3675 len += p->size; /* 1 byte for each character element (inc. null) */
3676 return len;
3677 }
3678
3679 /* read the object, return 0 on success, error code on fail */
icmText_read(icmBase * pp,unsigned long len,unsigned long of)3680 static int icmText_read(
3681 icmBase *pp,
3682 unsigned long len, /* tag length */
3683 unsigned long of /* start offset within file */
3684 ) {
3685 icmText *p = (icmText *)pp;
3686 icc *icp = p->icp;
3687 int rv = 0;
3688 char *bp, *buf;
3689
3690 if (len < 8) {
3691 sprintf(icp->err,"icmText_read: Tag too short to be legal");
3692 return icp->errc = 1;
3693 }
3694
3695 /* Allocate a file read buffer */
3696 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3697 sprintf(icp->err,"icmText_read: malloc() failed");
3698 return icp->errc = 2;
3699 }
3700 bp = buf;
3701
3702 /* Read portion of file into buffer */
3703 if ( icp->fp->seek(icp->fp, of) != 0
3704 || icp->fp->read(icp->fp, bp, 1, len) != len) {
3705 sprintf(icp->err,"icmText_read: fseek() or fread() failed");
3706 icp->al->free(icp->al, buf);
3707 return icp->errc = 1;
3708 }
3709 p->size = (len - 8)/1; /* Number of elements in the array */
3710
3711 /* Read type descriptor from the buffer */
3712 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3713 sprintf(icp->err,"icmText_read: Wrong tag type for icmText");
3714 icp->al->free(icp->al, buf);
3715 return icp->errc = 1;
3716 }
3717 bp = bp + 8;
3718
3719 if (p->size > 0) {
3720 if (check_null_string(bp,p->size) != 0) {
3721 sprintf(icp->err,"icmText_read: text is not null terminated");
3722 icp->al->free(icp->al, buf);
3723 return icp->errc = 1;
3724 }
3725 if ((rv = p->allocate((icmBase *)p)) != 0) {
3726 icp->al->free(icp->al, buf);
3727 return rv;
3728 }
3729 memcpy((void *)p->data, (void *)bp, p->size);
3730 }
3731 icp->al->free(icp->al, buf);
3732 return 0;
3733 }
3734
3735 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmText_write(icmBase * pp,unsigned long of)3736 static int icmText_write(
3737 icmBase *pp,
3738 unsigned long of /* File offset to write from */
3739 ) {
3740 icmText *p = (icmText *)pp;
3741 icc *icp = p->icp;
3742 unsigned int len;
3743 char *bp, *buf; /* Buffer to write from */
3744 int rv = 0;
3745
3746 /* Allocate a file write buffer */
3747 len = p->get_size((icmBase *)p);
3748 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3749 sprintf(icp->err,"icmText_write malloc() failed");
3750 return icp->errc = 2;
3751 }
3752 bp = buf;
3753
3754 /* Write type descriptor to the buffer */
3755 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3756 sprintf(icp->err,"icmText_write: write_SInt32Number() failed");
3757 icp->al->free(icp->al, buf);
3758 return icp->errc = rv;
3759 }
3760 write_SInt32Number(0,bp+4); /* Set padding to 0 */
3761 bp = bp + 8;
3762
3763 if (p->data != NULL) {
3764 if ((rv = check_null_string(p->data, p->size)) != 0) {
3765 sprintf(icp->err,"icmText_write: text is not null terminated");
3766 icp->al->free(icp->al, buf);
3767 return icp->errc = 1;
3768 }
3769 memcpy((void *)bp, (void *)p->data, p->size);
3770 }
3771
3772 /* Write to the file */
3773 if ( icp->fp->seek(icp->fp, of) != 0
3774 || icp->fp->write(icp->fp, buf, 1, len) != len) {
3775 sprintf(icp->err,"icmText_write fseek() or fwrite() failed");
3776 icp->al->free(icp->al, buf);
3777 return icp->errc = 2;
3778 }
3779 icp->al->free(icp->al, buf);
3780 return 0;
3781 }
3782
3783 /* Dump a text description of the object */
icmText_dump(icmBase * pp,FILE * op,int verb)3784 static void icmText_dump(
3785 icmBase *pp,
3786 FILE *op, /* Output to dump to */
3787 int verb /* Verbosity level */
3788 ) {
3789 icmText *p = (icmText *)pp;
3790 unsigned long i, r, c, size;
3791
3792 if (verb <= 0)
3793 return;
3794
3795 fprintf(op,"Text:\n");
3796 fprintf(op," No. chars = %lu\n",p->size);
3797
3798 size = p->size > 0 ? p->size-1 : 0;
3799 i = 0;
3800 for (r = 1;; r++) { /* count rows */
3801 if (i >= size) {
3802 fprintf(op,"\n");
3803 break;
3804 }
3805 if (r > 1 && verb < 2) {
3806 fprintf(op,"...\n");
3807 break; /* Print 1 row if not verbose */
3808 }
3809 c = 1;
3810 fprintf(op," 0x%04lx: ",i);
3811 c += 10;
3812 while (i < size && c < 75) {
3813 if (isprint(p->data[i])) {
3814 fprintf(op,"%c",p->data[i]);
3815 c++;
3816 } else {
3817 fprintf(op,"\\%03o",p->data[i]);
3818 c += 4;
3819 }
3820 i++;
3821 }
3822 if (i < size)
3823 fprintf(op,"\n");
3824 }
3825 }
3826
3827 /* Allocate variable sized data elements */
icmText_allocate(icmBase * pp)3828 static int icmText_allocate(
3829 icmBase *pp
3830 ) {
3831 icmText *p = (icmText *)pp;
3832 icc *icp = p->icp;
3833
3834 if (p->size != p->_size) {
3835 if (p->data != NULL)
3836 icp->al->free(icp->al, p->data);
3837 if ((p->data = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
3838 sprintf(icp->err,"icmText_alloc: malloc() of icmText data failed");
3839 return icp->errc = 2;
3840 }
3841 p->_size = p->size;
3842 }
3843 return 0;
3844 }
3845
3846 /* Free all storage in the object */
icmText_delete(icmBase * pp)3847 static void icmText_delete(
3848 icmBase *pp
3849 ) {
3850 icmText *p = (icmText *)pp;
3851 icc *icp = p->icp;
3852
3853 if (p->data != NULL)
3854 icp->al->free(icp->al, p->data);
3855 icp->al->free(icp->al, p);
3856 }
3857
3858 /* Create an empty object. Return null on error */
new_icmText(icc * icp)3859 static icmBase *new_icmText(
3860 icc *icp
3861 ) {
3862 icmText *p;
3863 if ((p = (icmText *) icp->al->calloc(icp->al,1,sizeof(icmText))) == NULL)
3864 return NULL;
3865 p->ttype = icSigTextType;
3866 p->refcount = 1;
3867 p->get_size = icmText_get_size;
3868 p->read = icmText_read;
3869 p->write = icmText_write;
3870 p->dump = icmText_dump;
3871 p->allocate = icmText_allocate;
3872 p->del = icmText_delete;
3873 p->icp = icp;
3874
3875 return (icmBase *)p;
3876 }
3877
3878 /* ---------------------------------------------------------- */
3879
3880 /* Data conversion support functions */
write_DateTimeNumber(icmDateTimeNumber * p,char * d)3881 static int write_DateTimeNumber(icmDateTimeNumber *p, char *d) {
3882 int rv;
3883 if (p->year < 1900 || p->year > 3000
3884 || p->month == 0 || p->month > 12
3885 || p->day == 0 || p->day > 31
3886 || p->hours > 23
3887 || p->minutes > 59
3888 || p->seconds > 59)
3889 return 1;
3890
3891 if ((rv = write_UInt16Number(p->year, d + 0)) != 0)
3892 return rv;
3893 if ((rv = write_UInt16Number(p->month, d + 2)) != 0)
3894 return rv;
3895 if ((rv = write_UInt16Number(p->day, d + 4)) != 0)
3896 return rv;
3897 if ((rv = write_UInt16Number(p->hours, d + 6)) != 0)
3898 return rv;
3899 if ((rv = write_UInt16Number(p->minutes, d + 8)) != 0)
3900 return rv;
3901 if ((rv = write_UInt16Number(p->seconds, d + 10)) != 0)
3902 return rv;
3903 return 0;
3904 }
3905
read_DateTimeNumber(icmDateTimeNumber * p,char * d)3906 static int read_DateTimeNumber(icmDateTimeNumber *p, char *d) {
3907 p->year = read_UInt16Number(d + 0);
3908 p->month = read_UInt16Number(d + 2);
3909 p->day = read_UInt16Number(d + 4);
3910 p->hours = read_UInt16Number(d + 6);
3911 p->minutes = read_UInt16Number(d + 8);
3912 p->seconds = read_UInt16Number(d + 10);
3913
3914 if (p->year < 1900 || p->year > 3000
3915 || p->month == 0 || p->month > 12
3916 || p->day == 0 || p->day > 31
3917 || p->hours > 23
3918 || p->minutes > 59
3919 || p->seconds > 59) {
3920 unsigned int tt;
3921
3922 /* Check for Adobe problem */
3923 if (p->month < 1900 || p->month > 3000
3924 || p->year == 0 || p->year > 12
3925 || p->hours == 0 || p->hours > 31
3926 || p->day > 23
3927 || p->seconds > 59
3928 || p->minutes > 59)
3929 return 1; /* Nope */
3930
3931 /* Correct Adobe's faulty profile */
3932 tt = p->month; p->month = p->year; p->year = tt;
3933 tt = p->hours; p->hours = p->day; p->day = tt;
3934 tt = p->seconds; p->seconds = p->minutes; p->minutes = tt;
3935 return 0;
3936 }
3937 return 0;
3938 }
3939
3940 /* Return a string that shows the given date and time */
string_DateTimeNumber(icmDateTimeNumber * p)3941 static char *string_DateTimeNumber(icmDateTimeNumber *p) {
3942 static const char *mstring[13] = {"Bad", "Jan","Feb","Mar","Apr","May","Jun",
3943 "Jul","Aug","Sep","Oct","Nov","Dec"};
3944 static char buf[80];
3945
3946 sprintf(buf,"%d %s %4d, %d:%02d:%02d",
3947 p->day, mstring[p->month > 12 ? 0 : p->month], p->year,
3948 p->hours, p->minutes, p->seconds);
3949 return buf;
3950 }
3951
3952 /* Set the DateTime structure to the current date and time */
setcur_DateTimeNumber(icmDateTimeNumber * p)3953 static void setcur_DateTimeNumber(icmDateTimeNumber *p) {
3954 time_t cclk;
3955 struct tm *ctm;
3956
3957 cclk = time(NULL);
3958 ctm = localtime(&cclk);
3959
3960 p->year = ctm->tm_year + 1900;
3961 p->month = ctm->tm_mon + 1;
3962 p->day = ctm->tm_mday;
3963 p->hours = ctm->tm_hour;
3964 p->minutes = ctm->tm_min;
3965 p->seconds = ctm->tm_sec;
3966 }
3967
3968 /* Return the number of bytes needed to write this tag */
icmDateTimeNumber_get_size(icmBase * pp)3969 static unsigned int icmDateTimeNumber_get_size(
3970 icmBase *pp
3971 ) {
3972 unsigned int len = 0;
3973 len += 8; /* 8 bytes for tag and padding */
3974 len += 12; /* 12 bytes for Date & Time */
3975 return len;
3976 }
3977
3978 /* read the object, return 0 on success, error code on fail */
icmDateTimeNumber_read(icmBase * pp,unsigned long len,unsigned long of)3979 static int icmDateTimeNumber_read(
3980 icmBase *pp,
3981 unsigned long len, /* tag length */
3982 unsigned long of /* start offset within file */
3983 ) {
3984 icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
3985 icc *icp = p->icp;
3986 int rv;
3987 char *bp, *buf;
3988
3989 if (len < 20) {
3990 sprintf(icp->err,"icmDateTimeNumber_read: Tag too small to be legal");
3991 return icp->errc = 1;
3992 }
3993
3994 /* Allocate a file read buffer */
3995 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3996 sprintf(icp->err,"icmDateTimeNumber_read: malloc() failed");
3997 return icp->errc = 2;
3998 }
3999 bp = buf;
4000
4001 /* Read portion of file into buffer */
4002 if ( icp->fp->seek(icp->fp, of) != 0
4003 || icp->fp->read(icp->fp, bp, 1, len) != len) {
4004 sprintf(icp->err,"icmDateTimeNumber_read: fseek() or fread() failed");
4005 icp->al->free(icp->al, buf);
4006 return icp->errc = 1;
4007 }
4008
4009 /* Read type descriptor from the buffer */
4010 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
4011 sprintf(icp->err,"icmDateTimeNumber_read: Wrong tag type for icmDateTimeNumber");
4012 icp->al->free(icp->al, buf);
4013 return icp->errc = 1;
4014 }
4015 bp += 8; /* Skip padding */
4016
4017 /* Read the time and date from buffer */
4018 if((rv = read_DateTimeNumber(p, bp)) != 0) {
4019 sprintf(icp->err,"icmDateTimeNumber_read: Corrupted DateTime");
4020 icp->al->free(icp->al, buf);
4021 return icp->errc = rv;
4022 }
4023
4024 icp->al->free(icp->al, buf);
4025 return 0;
4026 }
4027
4028 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmDateTimeNumber_write(icmBase * pp,unsigned long of)4029 static int icmDateTimeNumber_write(
4030 icmBase *pp,
4031 unsigned long of /* File offset to write from */
4032 ) {
4033 icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4034 icc *icp = p->icp;
4035 unsigned int len;
4036 char *bp, *buf; /* Buffer to write from */
4037 int rv = 0;
4038
4039 /* Allocate a file write buffer */
4040 len = p->get_size((icmBase *)p);
4041 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
4042 sprintf(icp->err,"icmDateTimeNumber_write malloc() failed");
4043 return icp->errc = 2;
4044 }
4045 bp = buf;
4046
4047 /* Write type descriptor to the buffer */
4048 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
4049 sprintf(icp->err,"icmDateTimeNumber_write: write_SInt32Number() failed");
4050 icp->al->free(icp->al, buf);
4051 return icp->errc = rv;
4052 }
4053 write_SInt32Number(0,bp+4); /* Set padding to 0 */
4054
4055 /* Write all the data to the buffer */
4056 bp += 8; /* Skip padding */
4057 if ((rv = write_DateTimeNumber(p, bp)) != 0) {
4058 sprintf(icp->err,"icmDateTimeNumber_write: write_DateTimeNumber() failed");
4059 icp->al->free(icp->al, buf);
4060 return icp->errc = rv;
4061 }
4062
4063 /* Write to the file */
4064 if ( icp->fp->seek(icp->fp, of) != 0
4065 || icp->fp->write(icp->fp, buf, 1, len) != len) {
4066 sprintf(icp->err,"icmDateTimeNumber_write fseek() or fwrite() failed");
4067 icp->al->free(icp->al, buf);
4068 return icp->errc = 2;
4069 }
4070 icp->al->free(icp->al, buf);
4071 return 0;
4072 }
4073
4074 /* Dump a text description of the object */
icmDateTimeNumber_dump(icmBase * pp,FILE * op,int verb)4075 static void icmDateTimeNumber_dump(
4076 icmBase *pp,
4077 FILE *op, /* Output to dump to */
4078 int verb /* Verbosity level */
4079 ) {
4080 icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4081 if (verb <= 0)
4082 return;
4083
4084 fprintf(op,"DateTimeNumber:\n");
4085 fprintf(op," Date = %s\n", string_DateTimeNumber(p));
4086 }
4087
4088 /* Allocate variable sized data elements */
icmDateTimeNumber_allocate(icmBase * pp)4089 static int icmDateTimeNumber_allocate(
4090 icmBase *pp
4091 ) {
4092 /* Nothing to do */
4093 return 0;
4094 }
4095
4096 /* Free all storage in the object */
icmDateTimeNumber_delete(icmBase * pp)4097 static void icmDateTimeNumber_delete(
4098 icmBase *pp
4099 ) {
4100 icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4101 icc *icp = p->icp;
4102
4103 icp->al->free(icp->al, p);
4104 }
4105
4106 /* Create an empty object. Return null on error */
new_icmDateTimeNumber(icc * icp)4107 static icmBase *new_icmDateTimeNumber(
4108 icc *icp
4109 ) {
4110 icmDateTimeNumber *p;
4111 if ((p = (icmDateTimeNumber *) icp->al->calloc(icp->al,1,sizeof(icmDateTimeNumber))) == NULL)
4112 return NULL;
4113 p->ttype = icSigDateTimeType;
4114 p->refcount = 1;
4115 p->get_size = icmDateTimeNumber_get_size;
4116 p->read = icmDateTimeNumber_read;
4117 p->write = icmDateTimeNumber_write;
4118 p->dump = icmDateTimeNumber_dump;
4119 p->allocate = icmDateTimeNumber_allocate;
4120 p->del = icmDateTimeNumber_delete;
4121 p->icp = icp;
4122
4123 setcur_DateTimeNumber(p); /* Default to current date and time */
4124 return (icmBase *)p;
4125 }
4126
4127 /* ---------------------------------------------------------- */
4128 /* icmLut object */
4129
4130 /* Utility function - raise one integer to an integer power */
uipow(unsigned int a,unsigned int b)4131 static unsigned int uipow(unsigned int a, unsigned int b) {
4132 unsigned int rv = 1;
4133 for (; b > 0; b--)
4134 rv *= a;
4135 return rv;
4136 }
4137
4138 /* - - - - - - - - - - - - - - - - */
4139 /* Check if the matrix is non-zero */
icmLut_nu_matrix(icmLut * p)4140 static int icmLut_nu_matrix(
4141 icmLut *p /* Pointer to Lut object */
4142 ) {
4143 int i, j;
4144
4145 for (j = 0; j < 3; j++) { /* Rows */
4146 for (i = 0; i < 3; i++) { /* Columns */
4147 if ( (i == j && p->e[j][i] != 1.0)
4148 || (i != j && p->e[j][i] != 0.0))
4149 return 1;
4150 }
4151 }
4152 return 0;
4153 }
4154
4155 /* return the locations of the minimum and */
4156 /* maximum values of the given channel, in the clut */
icmLut_min_max(icmLut * p,double * minp,double * maxp,int chan)4157 static void icmLut_min_max(
4158 icmLut *p, /* Pointer to Lut object */
4159 double *minp, /* Return position of min/max */
4160 double *maxp,
4161 int chan /* Channel, -1 for average of all */
4162 ) {
4163 double *tp;
4164 double minv, maxv; /* Values */
4165 int e, ee, f;
4166 double gc[MAX_CHAN]; /* Grid coordinate */
4167
4168 minv = 1e6;
4169 maxv = -1e6;
4170
4171 for (e = 0; e < p->inputChan; e++)
4172 gc[e] = 0; /* init coords */
4173
4174 /* Search the whole table */
4175 for (tp = p->clutTable, e = 0; e < p->inputChan; tp += p->outputChan) {
4176 double v;
4177 if (chan == -1) {
4178 for (v = 0.0, f = 0; f < p->outputChan; f++)
4179 v += tp[f];
4180 } else {
4181 v = tp[chan];
4182 }
4183 if (v < minv) {
4184 minv = v;
4185 for (ee = 0; ee < p->inputChan; ee++)
4186 minp[ee] = gc[ee]/(p->clutPoints-1.0);
4187 }
4188 if (v > maxv) {
4189 maxv = v;
4190 for (ee = 0; ee < p->inputChan; ee++)
4191 maxp[ee] = gc[ee]/(p->clutPoints-1.0);
4192 }
4193
4194 /* Increment coord */
4195 for (e = 0; e < p->inputChan; e++) {
4196 gc[e]++;
4197 if (gc[e] < p->clutPoints)
4198 break; /* No carry */
4199 gc[e] = 0;
4200 }
4201 }
4202 }
4203
4204 /* Convert XYZ throught Luts matrix */
4205 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmLut_lookup_matrix(icmLut * p,double * out,double * in)4206 static int icmLut_lookup_matrix(
4207 icmLut *p, /* Pointer to Lut object */
4208 double *out, /* Output array[outputChan] in ICC order - see Table 39 in 6.5.5 */
4209 double *in /* Input array[inputChan] */
4210 ) {
4211 double t0,t1; /* Take care if out == in */
4212 t0 = p->e[0][0] * in[0] + p->e[0][1] * in[1] + p->e[0][2] * in[2];
4213 t1 = p->e[1][0] * in[0] + p->e[1][1] * in[1] + p->e[1][2] * in[2];
4214 out[2] = p->e[2][0] * in[0] + p->e[2][1] * in[1] + p->e[2][2] * in[2];
4215 out[0] = t0;
4216 out[1] = t1;
4217
4218 return 0;
4219 }
4220
4221 /* Convert normalized numbers though this Luts input tables. */
4222 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmLut_lookup_input(icmLut * p,double * out,double * in)4223 static int icmLut_lookup_input(
4224 icmLut *p, /* Pointer to Lut object */
4225 double *out, /* Output array[inputChan] */
4226 double *in /* Input array[inputChan] */
4227 ) {
4228 int rv = 0;
4229 int ix,n;
4230 double inputEnt_1 = (double)(p->inputEnt-1);
4231 double *table = p->inputTable;
4232
4233 /* Use linear interpolation */
4234 for (n = 0; n < p->inputChan; n++, table += p->inputEnt) {
4235 double val, w;
4236 val = in[n] * inputEnt_1;
4237 if (val < 0.0) {
4238 val = 0.0;
4239 rv |= 1;
4240 } else if (val > inputEnt_1) {
4241 val = inputEnt_1;
4242 rv |= 1;
4243 }
4244 ix = (int)floor(val); /* Grid coordinate */
4245 if (ix > (p->inputEnt-2))
4246 ix = (p->inputEnt-2);
4247 w = val - (double)ix; /* weight */
4248 val = table[ix];
4249 out[n] = val + w * (table[ix+1] - val);
4250 }
4251 return rv;
4252 }
4253
4254 /* Convert normalized numbers though this Luts multi-dimensional table. */
4255 /* using n-linear interpolation. */
icmLut_lookup_clut_nl(icmLut * p,double * out,double * in)4256 static int icmLut_lookup_clut_nl(
4257 /* Return 0 on success, 1 if clipping occured, 2 on other error */
4258 icmLut *p, /* Pointer to Lut object */
4259 double *out, /* Output array[inputChan] */
4260 double *in /* Input array[outputChan] */
4261 ) {
4262 icc *icp = p->icp;
4263 int rv = 0;
4264 double *gp; /* Pointer to grid cube base */
4265 double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
4266 double *gw, GW[1 << 8]; /* weight for each grid cube corner */
4267
4268 if (p->inputChan <= 8) {
4269 gw = GW; /* Use stack allocation */
4270 } else {
4271 if ((gw = (double *) icp->al->malloc(icp->al, (1 << p->inputChan) * sizeof(double))) == NULL) {
4272 sprintf(icp->err,"icmLut_lookup_clut: malloc() failed");
4273 return icp->errc = 2;
4274 }
4275 }
4276
4277 /* We are using an n-linear (ie. Trilinear for 3D input) interpolation. */
4278 /* The implementation here uses more multiplies that some other schemes, */
4279 /* (for instance, see "Tri-Linear Interpolation" by Steve Hill, */
4280 /* Graphics Gems IV, page 521), but has less involved bookeeping, */
4281 /* needs less local storage for intermediate output values, does fewer */
4282 /* output and intermediate value reads, and fp multiplies are fast on */
4283 /* todays processors! */
4284
4285 /* Compute base index into grid and coordinate offsets */
4286 {
4287 int e;
4288 double clutPoints_1 = (double)(p->clutPoints-1);
4289 int clutPoints_2 = p->clutPoints-2;
4290 gp = p->clutTable; /* Base of grid array */
4291
4292 for (e = 0; e < p->inputChan; e++) {
4293 int x;
4294 double val;
4295 val = in[e] * clutPoints_1;
4296 if (val < 0.0) {
4297 val = 0.0;
4298 rv |= 1;
4299 } else if (val > clutPoints_1) {
4300 val = clutPoints_1;
4301 rv |= 1;
4302 }
4303 x = (int)floor(val); /* Grid coordinate */
4304 if (x > clutPoints_2)
4305 x = clutPoints_2;
4306 co[e] = val - (double)x; /* 1.0 - weight */
4307 gp += x * p->dinc[e]; /* Add index offset for base of cube */
4308 }
4309 }
4310 /* Compute corner weights needed for interpolation */
4311 {
4312 int e, i, g = 1;
4313 gw[0] = 1.0;
4314 for (e = 0; e < p->inputChan; e++) {
4315 for (i = 0; i < g; i++) {
4316 gw[g+i] = gw[i] * co[e];
4317 gw[i] *= (1.0 - co[e]);
4318 }
4319 g *= 2;
4320 }
4321 }
4322 /* Now compute the output values */
4323 {
4324 int i, f;
4325 double w = gw[0];
4326 double *d = gp + p->dcube[0];
4327 for (f = 0; f < p->outputChan; f++) /* Base of cube */
4328 out[f] = w * d[f];
4329 for (i = 1; i < (1 << p->inputChan); i++) { /* For all other corners of cube */
4330 w = gw[i]; /* Strength reduce */
4331 d = gp + p->dcube[i];
4332 for (f = 0; f < p->outputChan; f++) {
4333 out[f] += w * d[f];
4334 }
4335 }
4336 }
4337 if (gw != GW)
4338 icp->al->free(icp->al, (void *)gw);
4339 return rv;
4340 }
4341
4342 /* Convert normalized numbers though this Luts multi-dimensional table */
4343 /* using simplex interpolation. */
icmLut_lookup_clut_sx(icmLut * p,double * out,double * in)4344 static int icmLut_lookup_clut_sx(
4345 /* Return 0 on success, 1 if clipping occured, 2 on other error */
4346 icmLut *p, /* Pointer to Lut object */
4347 double *out, /* Output array[inputChan] */
4348 double *in /* Input array[outputChan] */
4349 ) {
4350 int rv = 0;
4351 double *gp; /* Pointer to grid cube base */
4352 double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
4353 int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
4354
4355 /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
4356 /* This method is more appropriate for XYZ/RGB/CMYK input spaces, */
4357
4358 /* Compute base index into grid and coordinate offsets */
4359 {
4360 int e;
4361 double clutPoints_1 = (double)(p->clutPoints-1);
4362 int clutPoints_2 = p->clutPoints-2;
4363 gp = p->clutTable; /* Base of grid array */
4364
4365 for (e = 0; e < p->inputChan; e++) {
4366 int x;
4367 double val;
4368 val = in[e] * clutPoints_1;
4369 if (val < 0.0) {
4370 val = 0.0;
4371 rv |= 1;
4372 } else if (val > clutPoints_1) {
4373 val = clutPoints_1;
4374 rv |= 1;
4375 }
4376 x = (int)floor(val); /* Grid coordinate */
4377 if (x > clutPoints_2)
4378 x = clutPoints_2;
4379 co[e] = val - (double)x; /* 1.0 - weight */
4380 gp += x * p->dinc[e]; /* Add index offset for base of cube */
4381 }
4382 }
4383 /* Do selection sort on coordinates */
4384 {
4385 int e, f;
4386 for (e = 0; e < p->inputChan; e++)
4387 si[e] = e; /* Initial unsorted indexes */
4388 for (e = 0; e < (p->inputChan-1); e++) {
4389 double cosn;
4390 cosn = co[si[e]]; /* Current smallest value */
4391 for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
4392 int tt;
4393 tt = si[f];
4394 if (cosn > co[tt]) {
4395 si[f] = si[e]; /* Exchange */
4396 si[e] = tt;
4397 cosn = co[tt];
4398 }
4399 }
4400 }
4401 }
4402 /* Now compute the weightings, simplex vertices and output values */
4403 {
4404 int e, f;
4405 double w; /* Current vertex weight */
4406
4407 w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
4408 for (f = 0; f < p->outputChan; f++)
4409 out[f] = w * gp[f];
4410
4411 for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
4412 w = co[si[e]] - co[si[e-1]];
4413 gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
4414 for (f = 0; f < p->outputChan; f++)
4415 out[f] += w * gp[f];
4416 }
4417
4418 w = co[si[0]];
4419 gp += p->dinc[si[0]]; /* Far corner from base of cell */
4420 for (f = 0; f < p->outputChan; f++)
4421 out[f] += w * gp[f];
4422 }
4423 return rv;
4424 }
4425
4426 /* Convert normalized numbers though this Luts output tables. */
4427 /* Return 0 on success, 1 if clipping occured, 2 on other error */
icmLut_lookup_output(icmLut * p,double * out,double * in)4428 static int icmLut_lookup_output(
4429 icmLut *p, /* Pointer to Lut object */
4430 double *out, /* Output array[outputChan] */
4431 double *in /* Input array[outputChan] */
4432 ) {
4433 int rv = 0;
4434 int ix,n;
4435 double outputEnt_1 = (double)(p->outputEnt-1);
4436 double *table = p->outputTable;
4437
4438 /* Use linear interpolation */
4439 for (n = 0; n < p->outputChan; n++, table += p->outputEnt) {
4440 double val, w;
4441 val = in[n] * outputEnt_1;
4442 if (val < 0.0) {
4443 val = 0.0;
4444 rv |= 1;
4445 } else if (val > outputEnt_1) {
4446 val = outputEnt_1;
4447 rv |= 1;
4448 }
4449 ix = (int)floor(val); /* Grid coordinate */
4450 if (ix > (p->outputEnt-2))
4451 ix = (p->outputEnt-2);
4452 w = val - (double)ix; /* weight */
4453 val = table[ix];
4454 out[n] = val + w * (table[ix+1] - val);
4455 }
4456 return rv;
4457 }
4458
4459 /* ----------------------------------------------- */
4460 /* Pseudo - Hilbert count sequencer */
4461
4462 /* This multi-dimensional count sequence is a distributed */
4463 /* Gray code sequence, with direction reversal on every */
4464 /* alternate power of 2 scale. */
4465 /* It is intended to aid cache coherence in multi-dimensional */
4466 /* regular sampling. It approximates the Hilbert curve sequence. */
4467
4468 /* Initialise, returns total usable count */
4469 unsigned
psh_init(psh * p,int di,unsigned res,int co[])4470 psh_init(
4471 psh *p, /* Pointer to structure to initialise */
4472 int di, /* Dimensionality */
4473 unsigned res, /* Size per coordinate */
4474 int co[] /* Coordinates to initialise (May be NULL) */
4475 ) {
4476 int e;
4477
4478 p->di = di;
4479 p->res = res;
4480
4481 /* Compute bits */
4482 for (p->bits = 0; (1 << p->bits) < res; p->bits++)
4483 ;
4484
4485 /* Compute the total count mask */
4486 p->tmask = ((((unsigned)1) << (p->bits * di))-1);
4487
4488 /* Compute usable count */
4489 p->count = 1;
4490 for (e = 0; e < di; e++)
4491 p->count *= res;
4492
4493 p->ix = 0;
4494
4495 if (co != NULL) {
4496 for (e = 0; e < di; e++)
4497 co[e] = 0;
4498 }
4499
4500 return p->count;
4501 }
4502
4503 /* Reset the counter */
4504 void
psh_reset(psh * p)4505 psh_reset(
4506 psh *p /* Pointer to structure */
4507 ) {
4508 p->ix = 0;
4509 }
4510
4511 /* Increment pseudo-hilbert coordinates */
4512 /* Return non-zero if count rolls over to 0 */
4513 int
psh_inc(psh * p,int co[])4514 psh_inc(
4515 psh *p, /* Pointer to structure */
4516 int co[] /* Coordinates to return */
4517 ) {
4518 int di = p->di;
4519 int res = p->res;
4520 int bits = p->bits;
4521 int e;
4522
4523 do {
4524 int b;
4525 int gix; /* Gray code index */
4526
4527 p->ix = (p->ix + 1) & p->tmask;
4528
4529 gix = p->ix ^ (p->ix >> 1); /* Convert to gray code index */
4530
4531 for (e = 0; e < di; e++)
4532 co[e] = 0;
4533
4534 for (b = 0; b < bits; b++) { /* Distribute bits */
4535 if (b & 1) {
4536 for (e = di-1; e >= 0; e--) { /* In reverse order */
4537 co[e] |= (gix & 1) << b;
4538 gix >>= 1;
4539 }
4540 } else {
4541 for (e = 0; e < di; e++) { /* In normal order */
4542 co[e] |= (gix & 1) << b;
4543 gix >>= 1;
4544 }
4545 }
4546 }
4547
4548 /* Convert from Gray to binary coordinates */
4549 for (e = 0; e < di; e++) {
4550 unsigned sh, tv;
4551
4552 for(sh = 1, tv = co[e];; sh <<= 1) {
4553 unsigned ptv = tv;
4554 tv ^= (tv >> sh);
4555 if (ptv <= 1 || sh == 16)
4556 break;
4557 }
4558 if (tv >= res) /* Dumbo filter - increment again if outside cube range */
4559 break;
4560 co[e] = tv;
4561 }
4562
4563 } while (e < di);
4564
4565 return (p->ix == 0);
4566 }
4567
4568 /* ------------------------------------------------------- */
4569 /* Parameter to getNormFunc function */
4570 typedef enum {
4571 icmFromLuti = 0, /* return "fromo Lut normalized index" conversion function */
4572 icmToLuti = 1, /* return "to Lut normalized index" conversion function */
4573 icmFromLutv = 2, /* return "from Lut normalized value" conversion function */
4574 icmToLutv = 3 /* return "to Lut normalized value" conversion function */
4575 } icmNormFlag;
4576
4577 /* Return an appropriate color space normalization function, */
4578 /* given the color space and Lut type */
4579 /* Return 0 on success, 1 on match failure */
4580 static int getNormFunc(
4581 icColorSpaceSignature csig,
4582 icTagTypeSignature tagSig,
4583 icmNormFlag flag,
4584 void (**nfunc)(double *out, double *in)
4585 );
4586
4587 /* Helper function to initialize the three tables contents */
4588 /* from supplied transfer functions. */
4589 /* Set errc and return error number */
icmLut_set_tables(icmLut * p,void * cbctx,icColorSpaceSignature insig,icColorSpaceSignature outsig,void (* infunc)(void * cbcntx,double * out,double * in),double * inmin,double * inmax,void (* clutfunc)(void * cbctx,double * out,double * in),double * clutmin,double * clutmax,void (* outfunc)(void * cbctx,double * out,double * in))4590 static int icmLut_set_tables (
4591 icmLut *p, /* Pointer to Lut object */
4592 void *cbctx, /* Opaque callback context pointer value */
4593 icColorSpaceSignature insig, /* Input color space */
4594 icColorSpaceSignature outsig, /* Output color space */
4595 void (*infunc)(void *cbcntx, double *out, double *in),
4596 /* Input transfer function, inspace->inspace' (NULL = default) */
4597 double *inmin, double *inmax, /* Maximum range of inspace' values (NULL = default) */
4598 void (*clutfunc)(void *cbctx, double *out, double *in),
4599 /* inspace' -> outspace' transfer function */
4600 double *clutmin, double *clutmax, /* Maximum range of outspace' values (NULL = default) */
4601 void (*outfunc)(void *cbctx, double *out, double *in)
4602 /* Output transfer function, outspace'->outspace (NULL = deflt) */
4603 ) {
4604 icc *icp = p->icp;
4605 int n, e;
4606 int ii[MAX_CHAN]; /* Index value */
4607 psh counter; /* Pseudo-Hilbert counter */
4608 double _iv[2 * MAX_CHAN], *iv = &_iv[MAX_CHAN]; /* Real index value/table value */
4609 double imin[MAX_CHAN], imax[MAX_CHAN];
4610 double omin[MAX_CHAN], omax[MAX_CHAN];
4611 void (*ifromindex)(double *out, double *in); /* Index to input color space function */
4612 void (*itoentry)(double *out, double *in); /* Input color space to entry function */
4613 void (*ifromentry)(double *out, double *in); /* Entry to input color space function */
4614 void (*otoentry)(double *out, double *in); /* Output colorspace to table value function */
4615 void (*ofromentry)(double *out, double *in); /* Table value to output color space function */
4616
4617 if (getNormFunc(insig, p->ttype, icmFromLuti, &ifromindex) != 0) {
4618 sprintf(icp->err,"icmLut_set_tables index to input colorspace function lookup failed");
4619 return icp->errc = 1;
4620 }
4621 if (getNormFunc(insig, p->ttype, icmToLutv, &itoentry) != 0) {
4622 sprintf(icp->err,"icmLut_set_tables input colorspace to table entry function lookup failed");
4623 return icp->errc = 1;
4624 }
4625 if (getNormFunc(insig, p->ttype, icmFromLutv, &ifromentry) != 0) {
4626 sprintf(icp->err,"icmLut_set_tables table entry to input colorspace function lookup failed");
4627 return icp->errc = 1;
4628 }
4629
4630 if (getNormFunc(outsig, p->ttype, icmToLutv, &otoentry) != 0) {
4631 sprintf(icp->err,"icmLut_set_tables output colorspace to table entry function lookup failed");
4632 return icp->errc = 1;
4633 }
4634 if (getNormFunc(outsig, p->ttype, icmFromLutv, &ofromentry) != 0) {
4635 sprintf(icp->err,"icmLut_set_tables table entry to output colorspace function lookup failed");
4636 return icp->errc = 1;
4637 }
4638
4639 /* Setup input table value min-max */
4640 if (inmin == NULL) {
4641 #ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Try symetrical range */
4642 if (insig == icSigLabData) { /* Special case Lab */
4643 double mn[3], mx[3];
4644 /* Because the symetric range will cause slight clipping, */
4645 /* only do it if the input table has sufficient resolution */
4646 /* to represent the clipping faithfuly. */
4647 if (p->inputEnt >= 64) {
4648 mn[0] = 0.0, mn[1] = -127.0, mn[2] = -127.0;
4649 mx[0] = 100.0, mx[1] = 127.0, mx[2] = 127.0;
4650 itoentry(imin, mn); /* Convert from input color space to table representation */
4651 itoentry(imax, mx);
4652 } else {
4653 for (e = 0; e < p->inputChan; e++) {
4654 imin[e] = 0.0;
4655 imax[e] = 1.0;
4656 }
4657 }
4658 } else
4659 #endif
4660 {
4661 for (e = 0; e < p->inputChan; e++) {
4662 imin[e] = 0.0; /* We are assuming this is true for all other color spaces. */
4663 imax[e] = 1.0;
4664 }
4665 }
4666 } else {
4667 itoentry(imin, inmin); /* Convert from input color space to table representation */
4668 itoentry(imax, inmax);
4669 }
4670
4671 /* Setup output table value min-max */
4672 if (clutmin == NULL) {
4673 #ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Try symetrical range */
4674 if (outsig == icSigLabData) { /* Special case Lab */
4675 double mn[3], mx[3];
4676 /* Because the symetric range will cause slight clipping, */
4677 /* only do it if the output table has sufficient resolution */
4678 /* to represent the clipping faithfuly. */
4679 if (p->outputEnt >= 64) {
4680 mn[0] = 0.0, mn[1] = -127.0, mn[2] = -127.0;
4681 mx[0] = 100.0, mx[1] = 127.0, mx[2] = 127.0;
4682 otoentry(omin, mn);/* Convert from output color space to table representation */
4683 otoentry(omax, mx);
4684 } else {
4685 for (e = 0; e < p->inputChan; e++) {
4686 omin[e] = 0.0;
4687 omax[e] = 1.0;
4688 }
4689 }
4690 } else
4691 #endif
4692 {
4693 for (e = 0; e < p->outputChan; e++) {
4694 omin[e] = 0.0; /* We are assuming this is true for all other color spaces. */
4695 omax[e] = 1.0;
4696 }
4697 }
4698 } else {
4699 otoentry(omin, clutmin);/* Convert from output color space to table representation */
4700 otoentry(omax, clutmax);
4701 }
4702
4703 /* Create the input table entry values */
4704 for (n = 0; n < p->inputEnt; n++) {
4705 double fv;
4706 fv = n/(p->inputEnt-1.0);
4707 for (e = 0; e < p->inputChan; e++)
4708 iv[e] = fv;
4709
4710 ifromindex(iv,iv); /* Convert from index value to input color space value */
4711
4712 if (infunc != NULL)
4713 infunc(cbctx, iv, iv); /* In colorspace -> input table -> In colorspace. */
4714
4715 itoentry(iv,iv); /* Convert from input color space value to table value */
4716
4717 /* Expand used range to 0.0 - 1.0, and clip to legal values */
4718 /* Note that if the range is reduced, and clipping occurs, */
4719 /* then there should be enough resolution within the input */
4720 /* table, to represent the sharp edges of the clipping. */
4721 for (e = 0; e < p->inputChan; e++) {
4722 double tt;
4723 tt = (iv[e] - imin[e])/(imax[e] - imin[e]);
4724 if (tt < 0.0)
4725 tt = 0.0;
4726 else if (tt > 1.0)
4727 tt = 1.0;
4728 iv[e] = tt;
4729 }
4730
4731 for (e = 0; e < p->inputChan; e++) /* Input tables */
4732 p->inputTable[e * p->inputEnt + n] = iv[e];
4733 }
4734
4735 /* Create the multi-dimensional lookup table values */
4736
4737 /* To make this clut function cache friendly, we use the pseudo-hilbert */
4738 /* count sequence. This keeps each point close to the last in the */
4739 /* multi-dimensional space. */
4740
4741 psh_init(&counter, p->inputChan, p->clutPoints, ii); /* Initialise counter */
4742
4743 /* Itterate through all verticies in the grid */
4744 for (;;) {
4745 int ti; /* Table index */
4746
4747 for (ti = e = 0; e < p->inputChan; e++) { /* Input tables */
4748 ti += ii[e] * p->dinc[e]; /* Clut index */
4749 iv[e] = ii[e]/(p->clutPoints-1.0); /* Vertex coordinates */
4750 iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
4751 *((int *)&iv[-e-1]) = ii[e]; /* Trick to supply grid index in iv[] */
4752 }
4753
4754 ifromentry(iv,iv); /* Convert from table value to input color space */
4755
4756 /* Apply incolor -> outcolor function we want to represent */
4757 clutfunc(cbctx, iv, iv);
4758
4759 otoentry(iv,iv); /* Convert from output color space value to table value */
4760
4761 /* Expand used range to 0.0 - 1.0, and clip to legal values */
4762 for (e = 0; e < p->outputChan; e++) {
4763 double tt;
4764 tt = (iv[e] - omin[e])/(omax[e] - omin[e]);
4765 if (tt < 0.0)
4766 tt = 0.0;
4767 else if (tt > 1.0)
4768 tt = 1.0;
4769 iv[e] = tt;
4770 }
4771
4772 for (e = 0; e < p->outputChan; e++) /* Output chans */
4773 p->clutTable[ti++] = iv[e];
4774
4775 /* Increment index within block (Reverse index significancd) */
4776 if (psh_inc(&counter, ii))
4777 break;
4778 }
4779
4780 /* Create the output table entry values */
4781 for (n = 0; n < p->outputEnt; n++) {
4782 double fv;
4783 fv = n/(p->outputEnt-1.0);
4784 for (e = 0; e < p->outputChan; e++)
4785 iv[e] = fv;
4786
4787 /* Undo expansion to 0.0 - 1.0 */
4788 for (e = 0; e < p->outputChan; e++) /* Output tables */
4789 iv[e] = iv[e] * (omax[e] - omin[e]) + omin[e];
4790
4791 ofromentry(iv,iv); /* Convert from table value to output color space value */
4792
4793 if (outfunc != NULL)
4794 outfunc(cbctx, iv, iv); /* Out colorspace -> output table -> out colorspace. */
4795
4796 otoentry(iv,iv); /* Convert from output color space value to table value */
4797
4798 /* Clip to legal values */
4799 for (e = 0; e < p->outputChan; e++) {
4800 double tt;
4801 tt = iv[e];
4802 if (tt < 0.0)
4803 tt = 0.0;
4804 else if (tt > 1.0)
4805 tt = 1.0;
4806 iv[e] = tt;
4807 }
4808
4809 for (e = 0; e < p->outputChan; e++) /* Input tables */
4810 p->outputTable[e * p->outputEnt + n] = iv[e];
4811 }
4812 return 0;
4813 }
4814
4815 /* - - - - - - - - - - - - - - - - */
4816 /* Return the number of bytes needed to write this tag */
icmLut_get_size(icmBase * pp)4817 static unsigned int icmLut_get_size(
4818 icmBase *pp
4819 ) {
4820 icmLut *p = (icmLut *)pp;
4821 unsigned int len = 0;
4822
4823 if (p->ttype == icSigLut8Type) {
4824 len += 48; /* tag and header */
4825 len += 1 * (p->inputChan * p->inputEnt);
4826 len += 1 * (p->outputChan * uipow(p->clutPoints,p->inputChan));
4827 len += 1 * (p->outputChan * p->outputEnt);
4828 } else {
4829 len += 52; /* tag and header */
4830 len += 2 * (p->inputChan * p->inputEnt);
4831 len += 2 * (p->outputChan * uipow(p->clutPoints,p->inputChan));
4832 len += 2 * (p->outputChan * p->outputEnt);
4833 }
4834 return len;
4835 }
4836
4837 /* read the object, return 0 on success, error code on fail */
icmLut_read(icmBase * pp,unsigned long len,unsigned long of)4838 static int icmLut_read(
4839 icmBase *pp,
4840 unsigned long len, /* tag length */
4841 unsigned long of /* start offset within file */
4842 ) {
4843 icmLut *p = (icmLut *)pp;
4844 icc *icp = p->icp;
4845 int rv = 0;
4846 unsigned long i, j, g, size;
4847 char *bp, *buf;
4848
4849 if (len < 4) {
4850 sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4851 return icp->errc = 1;
4852 }
4853
4854 /* Allocate a file read buffer */
4855 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
4856 sprintf(icp->err,"icmLut_read: malloc() failed");
4857 return icp->errc = 2;
4858 }
4859 bp = buf;
4860
4861 /* Read portion of file into buffer */
4862 if ( icp->fp->seek(icp->fp, of) != 0
4863 || icp->fp->read(icp->fp, bp, 1, len) != len) {
4864 sprintf(icp->err,"icmLut_read: fseek() or fread() failed");
4865 icp->al->free(icp->al, buf);
4866 return icp->errc = 1;
4867 }
4868
4869 /* Read type descriptor from the buffer */
4870 p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
4871 if (p->ttype != icSigLut8Type && p->ttype != icSigLut16Type) {
4872 sprintf(icp->err,"icmLut_read: Wrong tag type for icmLut");
4873 icp->al->free(icp->al, buf);
4874 return icp->errc = 1;
4875 }
4876
4877 if (p->ttype == icSigLut8Type) {
4878 if (len < 48) {
4879 sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4880 icp->al->free(icp->al, buf);
4881 return icp->errc = 1;
4882 }
4883 } else {
4884 if (len < 52) {
4885 sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4886 icp->al->free(icp->al, buf);
4887 return icp->errc = 1;
4888 }
4889 }
4890
4891 /* Read in the info common to 8 and 16 bit Lut */
4892 p->inputChan = read_UInt8Number(bp+8);
4893 p->outputChan = read_UInt8Number(bp+9);
4894 p->clutPoints = read_UInt8Number(bp+10);
4895
4896 /* Sanity check */
4897 if (p->inputChan > MAX_CHAN) {
4898 sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN);
4899 return icp->errc = 1;
4900 }
4901
4902 if (p->outputChan > MAX_CHAN) {
4903 sprintf(icp->err,"icmLut_read: Can't handle > %d output channels\n",MAX_CHAN);
4904 return icp->errc = 1;
4905 }
4906
4907 /* Read 3x3 transform matrix */
4908 for (j = 0; j < 3; j++) { /* Rows */
4909 for (i = 0; i < 3; i++) { /* Columns */
4910 p->e[j][i] = read_S15Fixed16Number(bp + 12 + ((j * 3 + i) * 4));
4911 }
4912 }
4913 /* Read 16 bit specific stuff */
4914 if (p->ttype == icSigLut8Type) {
4915 p->inputEnt = 256; /* By definition */
4916 p->outputEnt = 256; /* By definition */
4917 bp = buf+48;
4918 } else {
4919 p->inputEnt = read_UInt16Number(bp+48);
4920 p->outputEnt = read_UInt16Number(bp+50);
4921 bp = buf+52;
4922 }
4923
4924 if (len < icmLut_get_size((icmBase *)p)) {
4925 sprintf(icp->err,"icmLut_read: Tag too small for contents");
4926 icp->al->free(icp->al, buf);
4927 return icp->errc = 1;
4928 }
4929
4930 /* Read the input tables */
4931 size = (p->inputChan * p->inputEnt);
4932 if ((rv = p->allocate((icmBase *)p)) != 0) {
4933 icp->al->free(icp->al, buf);
4934 return rv;
4935 }
4936 if (p->ttype == icSigLut8Type) {
4937 for (i = 0; i < size; i++, bp += 1)
4938 p->inputTable[i] = read_DCS8Number(bp);
4939 } else {
4940 for (i = 0; i < size; i++, bp += 2)
4941 p->inputTable[i] = read_DCS16Number(bp);
4942 }
4943
4944 /* Read the clut table */
4945 size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
4946 if ((rv = p->allocate((icmBase *)p)) != 0) {
4947 icp->al->free(icp->al, buf);
4948 return rv;
4949 }
4950 if (p->ttype == icSigLut8Type) {
4951 for (i = 0; i < size; i++, bp += 1)
4952 p->clutTable[i] = read_DCS8Number(bp);
4953 } else {
4954 for (i = 0; i < size; i++, bp += 2)
4955 p->clutTable[i] = read_DCS16Number(bp);
4956 }
4957
4958 /* Read the output tables */
4959 size = (p->outputChan * p->outputEnt);
4960 if ((rv = p->allocate((icmBase *)p)) != 0) {
4961 icp->al->free(icp->al, buf);
4962 return rv;
4963 }
4964 if (p->ttype == icSigLut8Type) {
4965 for (i = 0; i < size; i++, bp += 1)
4966 p->outputTable[i] = read_DCS8Number(bp);
4967 } else {
4968 for (i = 0; i < size; i++, bp += 2)
4969 p->outputTable[i] = read_DCS16Number(bp);
4970 }
4971
4972 /* Private: compute dimensional increment though clut */
4973 /* Note that first channel varies least rapidly. */
4974 i = p->inputChan-1;
4975 p->dinc[i--] = p->outputChan;
4976 for (; i < p->inputChan; i--)
4977 p->dinc[i] = p->dinc[i+1] * p->clutPoints;
4978
4979 /* Private: compute offsets from base of cube to other corners */
4980 for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
4981 for (i = 0; i < g; i++)
4982 p->dcube[g+i] = p->dcube[i] + p->dinc[j];
4983 g *= 2;
4984 }
4985
4986 icp->al->free(icp->al, buf);
4987 return 0;
4988 }
4989
4990 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmLut_write(icmBase * pp,unsigned long of)4991 static int icmLut_write(
4992 icmBase *pp,
4993 unsigned long of /* File offset to write from */
4994 ) {
4995 icmLut *p = (icmLut *)pp;
4996 icc *icp = p->icp;
4997 unsigned long i,j;
4998 unsigned int len, size;
4999 char *bp, *buf; /* Buffer to write from */
5000 int rv = 0;
5001
5002 /* Allocate a file write buffer */
5003 len = p->get_size((icmBase *)p);
5004 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5005 sprintf(icp->err,"icmLut_write malloc() failed");
5006 return icp->errc = 2;
5007 }
5008 bp = buf;
5009
5010 /* Write type descriptor to the buffer */
5011 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5012 sprintf(icp->err,"icmLut_write: write_SInt32Number() failed");
5013 icp->al->free(icp->al, buf);
5014 return icp->errc = rv;
5015 }
5016 write_SInt32Number(0,bp+4); /* Set padding to 0 */
5017
5018 /* Write the info common to 8 and 16 bit Lut */
5019 if ((rv = write_UInt8Number(p->inputChan, bp+8)) != 0) {
5020 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5021 icp->al->free(icp->al, buf);
5022 return icp->errc = rv;
5023 }
5024 if ((rv = write_UInt8Number(p->outputChan, bp+9)) != 0) {
5025 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5026 icp->al->free(icp->al, buf);
5027 return icp->errc = rv;
5028 }
5029 if ((rv = write_UInt8Number(p->clutPoints, bp+10)) != 0) {
5030 sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5031 icp->al->free(icp->al, buf);
5032 return icp->errc = rv;
5033 }
5034
5035 /* Write 3x3 transform matrix */
5036 for (j = 0; j < 3; j++) { /* Rows */
5037 for (i = 0; i < 3; i++) { /* Columns */
5038 if ((rv = write_S15Fixed16Number(p->e[j][i],bp + 12 + ((j * 3 + i) * 4))) != 0) {
5039 sprintf(icp->err,"icmLut_write: write_S15Fixed16Number() failed");
5040 icp->al->free(icp->al, buf);
5041 return icp->errc = rv;
5042 }
5043 }
5044 }
5045
5046 /* Write 16 bit specific stuff */
5047 if (p->ttype == icSigLut8Type) {
5048 if (p->inputEnt != 256 || p->outputEnt != 256) {
5049 sprintf(icp->err,"icmLut_write: 8 bit Input and Output tables must be 256 entries");
5050 icp->al->free(icp->al, buf);
5051 return icp->errc = 1;
5052 }
5053 bp = buf+48;
5054 } else {
5055 if ((rv = write_UInt16Number(p->inputEnt, bp+48)) != 0) {
5056 sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
5057 icp->al->free(icp->al, buf);
5058 return icp->errc = rv;
5059 }
5060 if ((rv = write_UInt16Number(p->outputEnt, bp+50)) != 0) {
5061 sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
5062 icp->al->free(icp->al, buf);
5063 return icp->errc = rv;
5064 }
5065 bp = buf+52;
5066 }
5067
5068 /* Write the input tables */
5069 size = (p->inputChan * p->inputEnt);
5070 if (p->ttype == icSigLut8Type) {
5071 for (i = 0; i < size; i++, bp += 1) {
5072 if ((rv = write_DCS8Number(p->inputTable[i], bp)) != 0) {
5073 sprintf(icp->err,"icmLut_write: inputTable write_DCS8Number() failed");
5074 icp->al->free(icp->al, buf);
5075 return icp->errc = rv;
5076 }
5077 }
5078 } else {
5079 for (i = 0; i < size; i++, bp += 2) {
5080 if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) {
5081 sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]);
5082 icp->al->free(icp->al, buf);
5083 return icp->errc = rv;
5084 }
5085 }
5086 }
5087
5088 /* Write the clut table */
5089 size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5090 if (p->ttype == icSigLut8Type) {
5091 for (i = 0; i < size; i++, bp += 1) {
5092 if ((rv = write_DCS8Number(p->clutTable[i], bp)) != 0) {
5093 sprintf(icp->err,"icmLut_write: clutTable write_DCS8Number() failed");
5094 icp->al->free(icp->al, buf);
5095 return icp->errc = rv;
5096 }
5097 }
5098 } else {
5099 for (i = 0; i < size; i++, bp += 2) {
5100 if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) {
5101 sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]);
5102 icp->al->free(icp->al, buf);
5103 return icp->errc = rv;
5104 }
5105 }
5106 }
5107
5108 /* Write the output tables */
5109 size = (p->outputChan * p->outputEnt);
5110 if (p->ttype == icSigLut8Type) {
5111 for (i = 0; i < size; i++, bp += 1) {
5112 if ((rv = write_DCS8Number(p->outputTable[i], bp)) != 0) {
5113 sprintf(icp->err,"icmLut_write: outputTable write_DCS8Number() failed");
5114 icp->al->free(icp->al, buf);
5115 return icp->errc = rv;
5116 }
5117 }
5118 } else {
5119 for (i = 0; i < size; i++, bp += 2) {
5120 if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) {
5121 sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]);
5122 icp->al->free(icp->al, buf);
5123 return icp->errc = rv;
5124 }
5125 }
5126 }
5127
5128 /* Write buffer to the file */
5129 if ( icp->fp->seek(icp->fp, of) != 0
5130 || icp->fp->write(icp->fp, buf, 1, len) != len) {
5131 sprintf(icp->err,"icmLut_write fseek() or fwrite() failed");
5132 icp->al->free(icp->al, buf);
5133 return icp->errc = 2;
5134 }
5135 icp->al->free(icp->al, buf);
5136 return 0;
5137 }
5138
5139 /* Dump a text description of the object */
icmLut_dump(icmBase * pp,FILE * op,int verb)5140 static void icmLut_dump(
5141 icmBase *pp,
5142 FILE *op, /* Output to dump to */
5143 int verb /* Verbosity level */
5144 ) {
5145 icmLut *p = (icmLut *)pp;
5146 if (verb <= 0)
5147 return;
5148
5149 if (p->ttype == icSigLut8Type) {
5150 fprintf(op,"Lut8:\n");
5151 } else {
5152 fprintf(op,"Lut16:\n");
5153 }
5154 fprintf(op," Input Channels = %u\n",p->inputChan);
5155 fprintf(op," Output Channels = %u\n",p->outputChan);
5156 fprintf(op," CLUT resolution = %u\n",p->clutPoints);
5157 fprintf(op," Input Table entries = %u\n",p->inputEnt);
5158 fprintf(op," Output Table entries = %u\n",p->outputEnt);
5159 fprintf(op," XYZ matrix = %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
5160 fprintf(op," %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
5161 fprintf(op," %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
5162
5163 if (verb >= 2) {
5164 unsigned int i,size;
5165 int j;
5166 unsigned int ii[MAX_CHAN]; /* maximum no of input channels */
5167
5168 fprintf(op," Input table:\n");
5169 for (i = 0; i < p->inputEnt; i++) {
5170 fprintf(op," %3u: ",i);
5171 for (j = 0; j < p->inputChan; j++)
5172 fprintf(op," %1.10f",p->inputTable[j * p->inputEnt + i]);
5173 fprintf(op,"\n");
5174 }
5175
5176 fprintf(op,"\n CLUT table:\n");
5177 if (p->inputChan > MAX_CHAN) {
5178 fprintf(op," !!Can't dump > %d input channel CLUT table!!\n",MAX_CHAN);
5179 } else {
5180 size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5181 for (j = 0; j < p->inputChan; j++)
5182 ii[j] = 0;
5183 for (i = 0; i < size;) {
5184 int k;
5185 /* Print table entry index */
5186 fprintf(op," ");
5187 for (j = p->inputChan-1; j >= 0; j--)
5188 fprintf(op," %2u",ii[j]);
5189 fprintf(op,":");
5190 /* Print table entry contents */
5191 for (k = 0; k < p->outputChan; k++, i++)
5192 fprintf(op," %1.10f",p->clutTable[i]);
5193 fprintf(op,"\n");
5194
5195 for (j = 0; j < p->inputChan; j++) { /* Increment index */
5196 ii[j]++;
5197 if (ii[j] < p->clutPoints)
5198 break; /* No carry */
5199 ii[j] = 0;
5200 }
5201 }
5202 }
5203
5204 fprintf(op,"\n Output table:\n");
5205 for (i = 0; i < p->outputEnt; i++) {
5206 fprintf(op," %3u: ",i);
5207 for (j = 0; j < p->outputChan; j++)
5208 fprintf(op," %1.10f",p->outputTable[j * p->outputEnt + i]);
5209 fprintf(op,"\n");
5210 }
5211
5212 }
5213 }
5214
5215 /* Allocate variable sized data elements */
icmLut_allocate(icmBase * pp)5216 static int icmLut_allocate(
5217 icmBase *pp
5218 ) {
5219 unsigned int i, j, g, size;
5220 icmLut *p = (icmLut *)pp;
5221 icc *icp = p->icp;
5222
5223 /* Sanity check */
5224 if (p->inputChan > MAX_CHAN) {
5225 sprintf(icp->err,"icmLut_alloc: Can't handle > %d input channels\n",MAX_CHAN);
5226 return icp->errc = 1;
5227 }
5228
5229 if (p->outputChan > MAX_CHAN) {
5230 sprintf(icp->err,"icmLut_alloc: Can't handle > %d output channels\n",MAX_CHAN);
5231 return icp->errc = 1;
5232 }
5233
5234 size = (p->inputChan * p->inputEnt);
5235 if (size != p->inputTable_size) {
5236 if (p->inputTable != NULL)
5237 icp->al->free(icp->al, p->inputTable);
5238 if ((p->inputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5239 sprintf(icp->err,"icmLut_alloc: calloc() of Lut inputTable data failed");
5240 return icp->errc = 2;
5241 }
5242 p->inputTable_size = size;
5243 }
5244 size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5245 if (size != p->clutTable_size) {
5246 if (p->clutTable != NULL)
5247 icp->al->free(icp->al, p->clutTable);
5248 if ((p->clutTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5249 sprintf(icp->err,"icmLut_alloc: calloc() of Lut clutTable data failed");
5250 return icp->errc = 2;
5251 }
5252 p->clutTable_size = size;
5253 }
5254 size = (p->outputChan * p->outputEnt);
5255 if (size != p->outputTable_size) {
5256 if (p->outputTable != NULL)
5257 icp->al->free(icp->al, p->outputTable);
5258 if ((p->outputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5259 sprintf(icp->err,"icmLut_alloc: calloc() of Lut outputTable data failed");
5260 return icp->errc = 2;
5261 }
5262 p->outputTable_size = size;
5263 }
5264
5265 /* Private: compute dimensional increment though clut */
5266 /* Note that first channel varies least rapidly. */
5267 i = p->inputChan-1;
5268 p->dinc[i--] = p->outputChan;
5269 for (; i < p->inputChan; i--)
5270 p->dinc[i] = p->dinc[i+1] * p->clutPoints;
5271
5272 /* Private: compute offsets from base of cube to other corners */
5273 for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
5274 for (i = 0; i < g; i++)
5275 p->dcube[g+i] = p->dcube[i] + p->dinc[j];
5276 g *= 2;
5277 }
5278
5279 return 0;
5280 }
5281
5282 /* Free all storage in the object */
icmLut_delete(icmBase * pp)5283 static void icmLut_delete(
5284 icmBase *pp
5285 ) {
5286 icmLut *p = (icmLut *)pp;
5287 icc *icp = p->icp;
5288
5289 if (p->inputTable != NULL)
5290 icp->al->free(icp->al, p->inputTable);
5291 if (p->clutTable != NULL)
5292 icp->al->free(icp->al, p->clutTable);
5293 if (p->outputTable != NULL)
5294 icp->al->free(icp->al, p->outputTable);
5295 icmTable_delete_bwd(icp, &p->rit);
5296 icmTable_delete_bwd(icp, &p->rot);
5297 icp->al->free(icp->al, p);
5298 }
5299
5300 /* Create an empty object. Return null on error */
new_icmLut(icc * icp)5301 static icmBase *new_icmLut(
5302 icc *icp
5303 ) {
5304 int i,j;
5305 icmLut *p;
5306 if ((p = (icmLut *) icp->al->calloc(icp->al,1,sizeof(icmLut))) == NULL)
5307 return NULL;
5308 p->ttype = icSigLut16Type;
5309 p->refcount = 1;
5310 p->get_size = icmLut_get_size;
5311 p->read = icmLut_read;
5312 p->write = icmLut_write;
5313 p->dump = icmLut_dump;
5314 p->allocate = icmLut_allocate;
5315 p->del = icmLut_delete;
5316
5317 /* Lookup methods */
5318 p->nu_matrix = icmLut_nu_matrix;
5319 p->min_max = icmLut_min_max;
5320 p->lookup_matrix = icmLut_lookup_matrix;
5321 p->lookup_input = icmLut_lookup_input;
5322 p->lookup_clut_nl = icmLut_lookup_clut_nl;
5323 p->lookup_clut_sx = icmLut_lookup_clut_sx;
5324 p->lookup_output = icmLut_lookup_output;
5325
5326 /* Set method */
5327 p->set_tables = icmLut_set_tables;
5328
5329 p->icp = icp;
5330
5331 /* Set matrix to reasonable default */
5332 for (i = 0; i < 3; i++)
5333 for (j = 0; j < 3; j++) {
5334 if (i == j)
5335 p->e[i][j] = 1.0;
5336 else
5337 p->e[i][j] = 0.0;
5338 }
5339
5340 /* Init lookups to non-dangerous values */
5341 for (i = 0; i < MAX_CHAN; i++)
5342 p->dinc[i] = 0;
5343
5344 for (i = 0; i < (1 << MAX_CHAN); i++)
5345 p->dcube[i] = 0;
5346
5347 p->rit.inited = 0;
5348 p->rot.inited = 0;
5349
5350 return (icmBase *)p;
5351 }
5352
5353 /* ---------------------------------------------------------- */
5354 /* Measurement */
5355
5356 /* Return the number of bytes needed to write this tag */
icmMeasurement_get_size(icmBase * pp)5357 static unsigned int icmMeasurement_get_size(
5358 icmBase *pp
5359 ) {
5360 unsigned int len = 0;
5361 len += 8; /* 8 bytes for tag and padding */
5362 len += 4; /* 4 for standard observer */
5363 len += 12; /* 12 for XYZ of measurement backing */
5364 len += 4; /* 4 for measurement geometry */
5365 len += 4; /* 4 for measurement flare */
5366 len += 4; /* 4 for standard illuminant */
5367 return len;
5368 }
5369
5370 /* read the object, return 0 on success, error code on fail */
icmMeasurement_read(icmBase * pp,unsigned long len,unsigned long of)5371 static int icmMeasurement_read(
5372 icmBase *pp,
5373 unsigned long len, /* tag length */
5374 unsigned long of /* start offset within file */
5375 ) {
5376 icmMeasurement *p = (icmMeasurement *)pp;
5377 icc *icp = p->icp;
5378 int rv;
5379 char *bp, *buf;
5380
5381 if (len < 36) {
5382 sprintf(icp->err,"icmMeasurement_read: Tag too small to be legal");
5383 return icp->errc = 1;
5384 }
5385
5386 /* Allocate a file read buffer */
5387 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5388 sprintf(icp->err,"icmMeasurement_read: malloc() failed");
5389 return icp->errc = 2;
5390 }
5391 bp = buf;
5392
5393 /* Read portion of file into buffer */
5394 if ( icp->fp->seek(icp->fp, of) != 0
5395 || icp->fp->read(icp->fp, bp, 1, len) != len) {
5396 sprintf(icp->err,"icmMeasurement_read: fseek() or fread() failed");
5397 icp->al->free(icp->al, buf);
5398 return icp->errc = 1;
5399 }
5400
5401 /* Read type descriptor from the buffer */
5402 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
5403 sprintf(icp->err,"icmMeasurement_read: Wrong tag type for icmMeasurement");
5404 icp->al->free(icp->al, buf);
5405 return icp->errc = 1;
5406 }
5407
5408 /* Read the encoded standard observer */
5409 p->observer = (icStandardObserver)read_SInt32Number(bp + 8);
5410
5411 /* Read the XYZ values for measurement backing */
5412 if ((rv = read_XYZNumber(&p->backing, bp+12)) != 0) {
5413 sprintf(icp->err,"icmMeasurement: read_XYZNumber error");
5414 icp->al->free(icp->al, buf);
5415 return icp->errc = rv;
5416 }
5417
5418 /* Read the encoded measurement geometry */
5419 p->geometry = (icMeasurementGeometry)read_SInt32Number(bp + 24);
5420
5421 /* Read the proportion of flare */
5422 p->flare = read_U16Fixed16Number(bp + 28);
5423
5424 /* Read the encoded standard illuminant */
5425 p->illuminant = (icIlluminant)read_SInt32Number(bp + 32);
5426
5427 icp->al->free(icp->al, buf);
5428 return 0;
5429 }
5430
5431 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmMeasurement_write(icmBase * pp,unsigned long of)5432 static int icmMeasurement_write(
5433 icmBase *pp,
5434 unsigned long of /* File offset to write from */
5435 ) {
5436 icmMeasurement *p = (icmMeasurement *)pp;
5437 icc *icp = p->icp;
5438 unsigned int len;
5439 char *bp, *buf; /* Buffer to write from */
5440 int rv = 0;
5441
5442 /* Allocate a file write buffer */
5443 len = p->get_size((icmBase *)p);
5444 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5445 sprintf(icp->err,"icmMeasurement_write malloc() failed");
5446 return icp->errc = 2;
5447 }
5448 bp = buf;
5449
5450 /* Write type descriptor to the buffer */
5451 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5452 sprintf(icp->err,"icmMeasurement_write, type: write_SInt32Number() failed");
5453 icp->al->free(icp->al, buf);
5454 return icp->errc = rv;
5455 }
5456 write_SInt32Number(0,bp+4); /* Set padding to 0 */
5457
5458 /* Write the encoded standard observer */
5459 if ((rv = write_SInt32Number((int)p->observer, bp + 8)) != 0) {
5460 sprintf(icp->err,"icmMeasurementa_write, observer: write_SInt32Number() failed");
5461 icp->al->free(icp->al, buf);
5462 return icp->errc = rv;
5463 }
5464
5465 /* Write the XYZ values for measurement backing */
5466 if ((rv = write_XYZNumber(&p->backing, bp+12)) != 0) {
5467 sprintf(icp->err,"icmMeasurement, backing: write_XYZNumber error");
5468 icp->al->free(icp->al, buf);
5469 return icp->errc = rv;
5470 }
5471
5472 /* Write the encoded measurement geometry */
5473 if ((rv = write_SInt32Number((int)p->geometry, bp + 24)) != 0) {
5474 sprintf(icp->err,"icmMeasurementa_write, geometry: write_SInt32Number() failed");
5475 icp->al->free(icp->al, buf);
5476 return icp->errc = rv;
5477 }
5478
5479 /* Write the proportion of flare */
5480 if ((rv = write_U16Fixed16Number(p->flare, bp + 28)) != 0) {
5481 sprintf(icp->err,"icmMeasurementa_write, flare: write_U16Fixed16Number() failed");
5482 icp->al->free(icp->al, buf);
5483 return icp->errc = rv;
5484 }
5485
5486 /* Write the encoded standard illuminant */
5487 if ((rv = write_SInt32Number((int)p->illuminant, bp + 32)) != 0) {
5488 sprintf(icp->err,"icmMeasurementa_write, illuminant: write_SInt32Number() failed");
5489 icp->al->free(icp->al, buf);
5490 return icp->errc = rv;
5491 }
5492
5493 /* Write to the file */
5494 if ( icp->fp->seek(icp->fp, of) != 0
5495 || icp->fp->write(icp->fp, buf, 1, len) != len) {
5496 sprintf(icp->err,"icmMeasurement_write fseek() or fwrite() failed");
5497 icp->al->free(icp->al, buf);
5498 return icp->errc = 2;
5499 }
5500 icp->al->free(icp->al, buf);
5501 return 0;
5502 }
5503
5504 /* Dump a text description of the object */
icmMeasurement_dump(icmBase * pp,FILE * op,int verb)5505 static void icmMeasurement_dump(
5506 icmBase *pp,
5507 FILE *op, /* Output to dump to */
5508 int verb /* Verbosity level */
5509 ) {
5510 icmMeasurement *p = (icmMeasurement *)pp;
5511 if (verb <= 0)
5512 return;
5513
5514 fprintf(op,"Measurement:\n");
5515 fprintf(op," Standard Observer = %s\n", string_StandardObserver(p->observer));
5516 fprintf(op," XYZ for Measurement Backing = %s\n", string_XYZNumber_and_Lab(&p->backing));
5517 fprintf(op," Measurement Geometry = %s\n", string_MeasurementGeometry(p->geometry));
5518 fprintf(op," Measurement Flare = %5.1f%%\n", p->flare * 100.0);
5519 fprintf(op," Standard Illuminant = %s\n", string_Illuminant(p->illuminant));
5520 }
5521
5522 /* Allocate variable sized data elements */
icmMeasurement_allocate(icmBase * pp)5523 static int icmMeasurement_allocate(
5524 icmBase *pp
5525 ) {
5526 /* Nothing to do */
5527 return 0;
5528 }
5529
5530 /* Free all storage in the object */
icmMeasurement_delete(icmBase * pp)5531 static void icmMeasurement_delete(
5532 icmBase *pp
5533 ) {
5534 icmMeasurement *p = (icmMeasurement *)pp;
5535 icc *icp = p->icp;
5536
5537 icp->al->free(icp->al, p);
5538 }
5539
5540 /* Create an empty object. Return null on error */
new_icmMeasurement(icc * icp)5541 static icmBase *new_icmMeasurement(
5542 icc *icp
5543 ) {
5544 icmMeasurement *p;
5545 if ((p = (icmMeasurement *) icp->al->calloc(icp->al,1,sizeof(icmMeasurement))) == NULL)
5546 return NULL;
5547 p->ttype = icSigMeasurementType;
5548 p->refcount = 1;
5549 p->get_size = icmMeasurement_get_size;
5550 p->read = icmMeasurement_read;
5551 p->write = icmMeasurement_write;
5552 p->dump = icmMeasurement_dump;
5553 p->allocate = icmMeasurement_allocate;
5554 p->del = icmMeasurement_delete;
5555 p->icp = icp;
5556
5557 return (icmBase *)p;
5558 }
5559
5560 /* ---------------------------------------------------------- */
5561
5562 /* Named color structure read/write support */
read_NamedColorVal(icmNamedColorVal * p,char * bp,char * end,icColorSpaceSignature pcs,unsigned int ndc)5563 static int read_NamedColorVal(
5564 icmNamedColorVal *p,
5565 char *bp,
5566 char *end,
5567 icColorSpaceSignature pcs, /* Header Profile Connection Space */
5568 unsigned int ndc /* Number of device corrds */
5569 ) {
5570 icc *icp = p->icp;
5571 int i;
5572 unsigned int mxl; /* Max possible string length */
5573
5574 mxl = (end - bp) < 32 ? (end - bp) : 32;
5575 if (check_null_string(bp,mxl)) {
5576 sprintf(icp->err,"icmNamedColorVal_read: Root name string not terminated");
5577 return icp->errc = 1;
5578 }
5579 strcpy((void *)p->root, (void *)bp);
5580 bp += strlen(p->root) + 1;
5581 if ((bp + ndc) > end) {
5582 sprintf(icp->err,"icmNamedColorVal_read: Data too short to read device coords");
5583 return icp->errc = 1;
5584 }
5585 for (i = 0; i < ndc; i++) {
5586 p->deviceCoords[i] = read_DCS8Number(bp);
5587 bp += 1;
5588 }
5589 return 0;
5590 }
5591
read_NamedColorVal2(icmNamedColorVal * p,char * bp,char * end,icColorSpaceSignature pcs,unsigned int ndc)5592 static int read_NamedColorVal2(
5593 icmNamedColorVal *p,
5594 char *bp,
5595 char *end,
5596 icColorSpaceSignature pcs, /* Header Profile Connection Space */
5597 unsigned int ndc /* Number of device corrds */
5598 ) {
5599 icc *icp = p->icp;
5600 int i;
5601 if ((bp + 32 + 6 + ndc * 2) > end) {
5602 sprintf(icp->err,"icmNamedColorVal2_read: Data too short to read");
5603 return icp->errc = 1;
5604 }
5605 if (check_null_string(bp,32)) {
5606 sprintf(icp->err,"icmNamedColorVal2_read: Root name string not terminated");
5607 return icp->errc = 1;
5608 }
5609 memcpy((void *)p->root,(void *)(bp + 0),32);
5610 switch(pcs) {
5611 case icSigXYZData:
5612 p->pcsCoords[0] = read_PCSXYZ16Number(bp+32);
5613 p->pcsCoords[1] = read_PCSXYZ16Number(bp+34);
5614 p->pcsCoords[2] = read_PCSXYZ16Number(bp+36);
5615 break;
5616 case icSigLabData:
5617 p->pcsCoords[0] = read_PCSL16Number(bp+32);
5618 p->pcsCoords[1] = read_PCSab16Number(bp+34);
5619 p->pcsCoords[2] = read_PCSab16Number(bp+36);
5620 break;
5621 default:
5622 return 1; /* Unknown PCS */
5623 }
5624 for (i = 0; i < ndc; i++)
5625 p->deviceCoords[i] = read_DCS16Number(bp + 32 + 6 + 2 * i);
5626 return 0;
5627 }
5628
write_NamedColorVal(icmNamedColorVal * p,char * d,icColorSpaceSignature pcs,unsigned int ndc)5629 static int write_NamedColorVal(
5630 icmNamedColorVal *p,
5631 char *d,
5632 icColorSpaceSignature pcs, /* Header Profile Connection Space */
5633 unsigned int ndc /* Number of device corrds */
5634 ) {
5635 icc *icp = p->icp;
5636 int i, rv = 0;
5637 if (check_null_string(p->root,32) != 0) {
5638 sprintf(icp->err,"icmNamedColorVal_write: Root string names is unterminated");
5639 return icp->errc = 1;
5640 }
5641 strcpy((void *)d,(void *)p->root);
5642 d += strlen(p->root) + 1;
5643 for (i = 0; i < ndc; i++) {
5644 if ((rv = write_DCS8Number(p->deviceCoords[i], d)) != 0) {
5645 sprintf(icp->err,"icmNamedColorVal_write: write of device coord failed");
5646 return icp->errc = 1;
5647 }
5648 d += 1;
5649 }
5650 return 0;
5651 }
5652
write_NamedColorVal2(icmNamedColorVal * p,char * bp,icColorSpaceSignature pcs,unsigned int ndc)5653 static int write_NamedColorVal2(
5654 icmNamedColorVal *p,
5655 char *bp,
5656 icColorSpaceSignature pcs, /* Header Profile Connection Space */
5657 unsigned int ndc /* Number of device corrds */
5658 ) {
5659 icc *icp = p->icp;
5660 int i, rv = 0;
5661 if (check_null_string(p->root,32)) {
5662 sprintf(icp->err,"icmNamedColorVal2_write: Root string names is unterminated");
5663 return icp->errc = 1;
5664 }
5665 memcpy((void *)(bp + 0),(void *)p->root,32);
5666 switch(pcs) {
5667 case icSigXYZData:
5668 rv |= write_PCSXYZ16Number(p->pcsCoords[0], bp+32);
5669 rv |= write_PCSXYZ16Number(p->pcsCoords[1], bp+34);
5670 rv |= write_PCSXYZ16Number(p->pcsCoords[2], bp+36);
5671 break;
5672 case icSigLabData:
5673 rv |= write_PCSL16Number(p->pcsCoords[0], bp+32);
5674 rv |= write_PCSab16Number(p->pcsCoords[1], bp+34);
5675 rv |= write_PCSab16Number(p->pcsCoords[2], bp+36);
5676 break;
5677 default:
5678 sprintf(icp->err,"icmNamedColorVal2_write: Unknown PCS");
5679 return icp->errc = 1;
5680 }
5681 if (rv) {
5682 sprintf(icp->err,"icmNamedColorVal2_write: write of PCS coord failed");
5683 return icp->errc = 1;
5684 }
5685 for (i = 0; i < ndc; i++) {
5686 if ((rv = write_DCS16Number(p->deviceCoords[i], bp + 32 + 6 + 2 * i)) != 0) {
5687 sprintf(icp->err,"icmNamedColorVal2_write: write of device coord failed");
5688 return icp->errc = 1;
5689 }
5690 }
5691 return 0;
5692 }
5693
5694 /* - - - - - - - - - - - */
5695 /* icmNamedColor object */
5696
5697 /* Return the number of bytes needed to write this tag */
icmNamedColor_get_size(icmBase * pp)5698 static unsigned int icmNamedColor_get_size(
5699 icmBase *pp
5700 ) {
5701 icmNamedColor *p = (icmNamedColor *)pp;
5702 unsigned int len = 0;
5703 if (p->ttype == icSigNamedColorType) {
5704 unsigned int i;
5705 len += 8; /* 8 bytes for tag and padding */
5706 len += 4; /* 4 for vendor specific flags */
5707 len += 4; /* 4 for count of named colors */
5708 len += strlen(p->prefix) + 1; /* prefix of color names */
5709 len += strlen(p->suffix) + 1; /* suffix of color names */
5710 for (i = 0; i < p->count; i++) {
5711 len += strlen(p->data[i].root) + 1; /* color names */
5712 len += p->nDeviceCoords * 1; /* bytes for each named color */
5713 }
5714 } else { /* Named Color 2 */
5715 len += 8; /* 8 bytes for tag and padding */
5716 len += 4; /* 4 for vendor specific flags */
5717 len += 4; /* 4 for count of named colors */
5718 len += 4; /* 4 for number of device coords */
5719 len += 32; /* 32 for prefix of color names */
5720 len += 32; /* 32 for suffix of color names */
5721 len += p->count * (32 + 6 + p->nDeviceCoords * 2); /* bytes for each named color */
5722 }
5723 return len;
5724 }
5725
5726 /* read the object, return 0 on success, error code on fail */
icmNamedColor_read(icmBase * pp,unsigned long len,unsigned long of)5727 static int icmNamedColor_read(
5728 icmBase *pp,
5729 unsigned long len, /* tag length */
5730 unsigned long of /* start offset within file */
5731 ) {
5732 icmNamedColor *p = (icmNamedColor *)pp;
5733 icc *icp = p->icp;
5734 unsigned long i;
5735 char *bp, *buf, *end;
5736 int rv = 0;
5737
5738 if (len < 4) {
5739 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5740 return icp->errc = 1;
5741 }
5742
5743 /* Allocate a file read buffer */
5744 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5745 sprintf(icp->err,"icmNamedColor_read: malloc() failed");
5746 return icp->errc = 2;
5747 }
5748 bp = buf;
5749 end = buf + len;
5750
5751 /* Read portion of file into buffer */
5752 if ( icp->fp->seek(icp->fp, of) != 0
5753 || icp->fp->read(icp->fp, bp, 1, len) != len) {
5754 sprintf(icp->err,"icmNamedColor_read: fseek() or fread() failed");
5755 icp->al->free(icp->al, buf);
5756 return icp->errc = 1;
5757 }
5758
5759 /* Read type descriptor from the buffer */
5760 p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
5761 if (p->ttype != icSigNamedColorType && p->ttype != icSigNamedColor2Type) {
5762 sprintf(icp->err,"icmNamedColor_read: Wrong tag type for icmNamedColor");
5763 icp->al->free(icp->al, buf);
5764 return icp->errc = 1;
5765 }
5766
5767 if (p->ttype == icSigNamedColorType) {
5768 if (len < 16) {
5769 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5770 icp->al->free(icp->al, buf);
5771 return icp->errc = 1;
5772 }
5773 /* Make sure that the number of device coords in known */
5774 p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
5775 if (p->nDeviceCoords > MAX_CHAN) {
5776 sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
5777 icp->al->free(icp->al, buf);
5778 return icp->errc = 1;
5779 }
5780
5781 } else { /* icmNC2 */
5782 if (len < 84) {
5783 sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5784 icp->al->free(icp->al, buf);
5785 return icp->errc = 1;
5786 }
5787 }
5788
5789 /* Read vendor specific flag */
5790 p->vendorFlag = read_UInt32Number(bp+8);
5791
5792 /* Read count of named colors */
5793 p->count = read_UInt32Number(bp+12);
5794
5795 if (p->ttype == icSigNamedColorType) {
5796 unsigned int mxl; /* Max possible string length */
5797 bp = bp + 16;
5798
5799 /* Prefix for each color name */
5800 mxl = (end - bp) < 32 ? (end - bp) : 32;
5801 if (check_null_string(bp,mxl) != 0) {
5802 sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
5803 icp->al->free(icp->al, buf);
5804 return icp->errc = 1;
5805 }
5806 strcpy((void *)p->prefix, (void *)bp);
5807 bp += strlen(p->prefix) + 1;
5808
5809 /* Suffix for each color name */
5810 mxl = (end - bp) < 32 ? (end - bp) : 32;
5811 if (check_null_string(bp,mxl) != 0) {
5812 sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
5813 icp->al->free(icp->al, buf);
5814 return icp->errc = 1;
5815 }
5816 strcpy((void *)p->suffix, (void *)bp);
5817 bp += strlen(p->suffix) + 1;
5818
5819 if ((rv = p->allocate((void *)p)) != 0) {
5820 icp->al->free(icp->al, buf);
5821 return rv;
5822 }
5823
5824 /* Read all the data from the buffer */
5825 for (i = 0; i < p->count; i++) {
5826 if ((rv = read_NamedColorVal(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
5827 icp->al->free(icp->al, buf);
5828 return rv;
5829 }
5830 bp += strlen(p->data[i].root) + 1;
5831 bp += p->nDeviceCoords * 1;
5832 }
5833 } else { /* icmNC2 */
5834 /* Number of device coords per color */
5835 p->nDeviceCoords = read_UInt32Number(bp+16);
5836
5837 /* Prefix for each color name */
5838 memcpy((void *)p->prefix, (void *)(bp + 20), 32);
5839 if (check_null_string(p->prefix,32) != 0) {
5840 sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
5841 icp->al->free(icp->al, buf);
5842 return icp->errc = 1;
5843 }
5844
5845 /* Suffix for each color name */
5846 memcpy((void *)p->suffix, (void *)(bp + 52), 32);
5847 if (check_null_string(p->suffix,32) != 0) {
5848 sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
5849 icp->al->free(icp->al, buf);
5850 return icp->errc = 1;
5851 }
5852
5853 if ((rv = p->allocate((icmBase *)p)) != 0) {
5854 icp->al->free(icp->al, buf);
5855 return rv;
5856 }
5857
5858 /* Read all the data from the buffer */
5859 bp = bp + 84;
5860 for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
5861 if ((rv = read_NamedColorVal2(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
5862 icp->al->free(icp->al, buf);
5863 return rv;
5864 }
5865 }
5866 }
5867 icp->al->free(icp->al, buf);
5868 return rv;
5869 }
5870
5871 /* Write the contents of the object. Return 0 on sucess, error code on failure */
icmNamedColor_write(icmBase * pp,unsigned long of)5872 static int icmNamedColor_write(
5873 icmBase *pp,
5874 unsigned long of /* File offset to write from */
5875 ) {
5876 icmNamedColor *p = (icmNamedColor *)pp;
5877 icc *icp = p->icp;
5878 unsigned long i;
5879 unsigned int len;
5880 char *bp, *buf; /* Buffer to write from */
5881 int rv = 0;
5882
5883 /* Allocate a file write buffer */
5884 len = p->get_size((icmBase *)p);
5885 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5886 sprintf(icp->err,"icmNamedColor_write malloc() failed");
5887 return icp->errc = 2;
5888 }
5889 bp = buf;
5890
5891 /* Write type descriptor to the buffer */
5892 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5893 sprintf(icp->err,"icmNamedColor_write: write_SInt32Number() failed");
5894 icp->al->free(icp->al, buf);
5895 return icp->errc = rv;
5896 }
5897 write_SInt32Number(0,bp+4); /* Set padding to 0 */
5898
5899 /* Write vendor specific flag */
5900 if ((rv = write_UInt32Number(p->vendorFlag, bp+8)) != 0) {
5901 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5902 icp->al->free(icp->al, buf);
5903 return icp->errc = rv;
5904 }
5905
5906 /* Write count of named colors */
5907 if ((rv = write_UInt32Number(p->count, bp+12)) != 0) {
5908 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5909 icp->al->free(icp->al, buf);
5910 return icp->errc = rv;
5911 }
5912
5913 if (p->ttype == icSigNamedColorType) {
5914 bp = bp + 16;
5915
5916 /* Prefix for each color name */
5917 if ((rv = check_null_string(p->prefix,32)) != 0) {
5918 sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
5919 icp->al->free(icp->al, buf);
5920 return icp->errc = 1;
5921 }
5922 strcpy((void *)bp, (void *)p->prefix);
5923 bp += strlen(p->prefix) + 1;
5924
5925 /* Suffix for each color name */
5926 if (check_null_string(p->suffix,32)) {
5927 sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
5928 icp->al->free(icp->al, buf);
5929 return icp->errc = 1;
5930 }
5931 strcpy((void *)bp, (void *)p->suffix);
5932 bp += strlen(p->suffix) + 1;
5933
5934 /* Write all the data to the buffer */
5935
5936 for (i = 0; i < p->count; i++) {
5937 if ((rv = write_NamedColorVal(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
5938 icp->al->free(icp->al, buf);
5939 return rv;
5940 }
5941 bp += strlen(p->data[i].root) + 1;
5942 bp += p->nDeviceCoords * 1;
5943 }
5944 } else { /* icmNC2 */
5945 /* Number of device coords per color */
5946 if ((rv = write_UInt32Number(p->nDeviceCoords, bp+16)) != 0) {
5947 sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5948 icp->al->free(icp->al, buf);
5949 return icp->errc = rv;
5950 }
5951
5952 /* Prefix for each color name */
5953 if ((rv = check_null_string(p->prefix,32)) != 0) {
5954 sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
5955 icp->al->free(icp->al, buf);
5956 return icp->errc = 1;
5957 }
5958 memcpy((void *)(bp + 20), (void *)p->prefix, 32);
5959
5960 /* Suffix for each color name */
5961 if (check_null_string(p->suffix,32)) {
5962 sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
5963 icp->al->free(icp->al, buf);
5964 return icp->errc = 1;
5965 }
5966 memcpy((void *)(bp + 52), (void *)p->suffix, 32);
5967
5968 /* Write all the data to the buffer */
5969 bp = bp + 84;
5970 for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
5971 if ((rv = write_NamedColorVal2(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
5972 icp->al->free(icp->al, buf);
5973 return rv;
5974 }
5975 }
5976 }
5977
5978 /* Write to the file */
5979 if ( icp->fp->seek(icp->fp, of) != 0
5980 || icp->fp->write(icp->fp, buf, 1, len) != len) {
5981 sprintf(icp->err,"icmNamedColor_write fseek() or fwrite() failed");
5982 icp->al->free(icp->al, buf);
5983 return icp->errc = 2;
5984 }
5985 icp->al->free(icp->al, buf);
5986 return 0;
5987 }
5988
5989 /* Dump a text description of the object */
icmNamedColor_dump(icmBase * pp,FILE * op,int verb)5990 static void icmNamedColor_dump(
5991 icmBase *pp,
5992 FILE *op, /* Output to dump to */
5993 int verb /* Verbosity level */
5994 ) {
5995 icmNamedColor *p = (icmNamedColor *)pp;
5996 icc *icp = p->icp;
5997 if (verb <= 0)
5998 return;
5999
6000 if (p->ttype == icSigNamedColorType)
6001 fprintf(op,"NamedColor:\n");
6002 else
6003 fprintf(op,"NamedColor2:\n");
6004 fprintf(op," Vendor Flag = 0x%x\n",p->vendorFlag);
6005 fprintf(op," No. colors = %u\n",p->count);
6006 fprintf(op," No. dev. coords = %u\n",p->nDeviceCoords);
6007 fprintf(op," Name prefix = '%s'\n",p->prefix);
6008 fprintf(op," Name suffix = '%s'\n",p->suffix);
6009 if (verb >= 2) {
6010 unsigned long i, n;
6011 icmNamedColorVal *vp;
6012 for (i = 0; i < p->count; i++) {
6013 vp = p->data + i;
6014 fprintf(op," Color %lu:\n",i);
6015 fprintf(op," Name root = '%s'\n",vp->root);
6016
6017 if (p->ttype == icSigNamedColor2Type) {
6018 switch(icp->header->pcs) {
6019 case icSigXYZData:
6020 fprintf(op," XYZ = %f, %f, %f'\n",
6021 vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
6022 break;
6023 case icSigLabData:
6024 fprintf(op," Lab = %f, %f, %f'\n",
6025 vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
6026 break;
6027 default:
6028 fprintf(op," Unexpected PCS\n");
6029 break;
6030 }
6031 }
6032 if (p->nDeviceCoords > 0) {
6033 fprintf(op," Device Coords = ");
6034 for (n = 0; n < p->nDeviceCoords; n++) {
6035 if (n > 0)
6036 printf(", ");
6037 printf("%f",vp->deviceCoords[n]);
6038 }
6039 printf("\n");
6040 }
6041 }
6042 }
6043 }
6044
6045 /* Allocate variable sized data elements */
icmNamedColor_allocate(icmBase * pp)6046 static int icmNamedColor_allocate(
6047 icmBase *pp
6048 ) {
6049 icmNamedColor *p = (icmNamedColor *)pp;
6050 icc *icp = p->icp;
6051
6052 if (p->count != p->_count) {
6053 unsigned int i;
6054 if (p->data != NULL)
6055 icp->al->free(icp->al, p->data);
6056 if ((p->data = (icmNamedColorVal *) icp->al->calloc(icp->al,p->count, sizeof(icmNamedColorVal))) == NULL) {
6057 sprintf(icp->err,"icmNamedColor_alloc: malloc() of icmNamedColor data failed");
6058 return icp->errc = 2;
6059 }
6060 for (i = 0; i < p->count; i++) {
6061 p->data[i].icp = icp; /* Do init */
6062 }
6063 p->_count = p->count;
6064 }
6065 return 0;
6066 }
6067
6068 /* Free all storage in the object */
icmNamedColor_delete(icmBase * pp)6069 static void icmNamedColor_delete(
6070 icmBase *pp
6071 ) {
6072 icmNamedColor *p = (icmNamedColor *)pp;
6073 icc *icp = p->icp;
6074
6075 if (p->data != NULL)
6076 icp->al->free(icp->al, p->data);
6077 icp->al->free(icp->al, p);
6078 }
6079
6080 /* Create an empty object. Return null on error */
new_icmNamedColor(icc * icp)6081 static icmBase *new_icmNamedColor(
6082 icc *icp
6083 ) {
6084 icmNamedColor *p;
6085 if ((p = (icmNamedColor *) icp->al->calloc(icp->al,1,sizeof(icmNamedColor))) == NULL)
6086 return NULL;
6087 p->ttype = icSigNamedColor2Type;
6088 p->refcount = 1;
6089 p->get_size = icmNamedColor_get_size;
6090 p->read = icmNamedColor_read;
6091 p->write = icmNamedColor_write;
6092 p->dump = icmNamedColor_dump;
6093 p->allocate = icmNamedColor_allocate;
6094 p->del = icmNamedColor_delete;
6095 p->icp = icp;
6096
6097 /* Default the the number of device coords appropriately for NamedColorType */
6098 p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
6099
6100 return (icmBase *)p;
6101 }
6102
6103 /* ---------------------------------------------------------- */
6104 /* textDescription */
6105
6106 /* Return the number of bytes needed to write this tag */
icmTextDescription_get_size(icmBase * pp)6107 static unsigned int icmTextDescription_get_size(
6108 icmBase *pp
6109 ) {
6110 icmTextDescription *p = (icmTextDescription *)pp;
6111 unsigned int len = 0;
6112 len += 8; /* 8 bytes for tag and padding */
6113 len += 4 + p->size; /* Ascii string length + ascii string */
6114 len += 8 + 2 * p->ucSize; /* Unicode language code + length + string */
6115 len += 3 + 67; /* ScriptCode code, length string */
6116 return len;
6117 }
6118
6119 /* read the object, return 0 on success, error code on fail */
icmTextDescription_read(icmBase * pp,unsigned long len,unsigned long of)6120 static int icmTextDescription_read(
6121 icmBase *pp,
6122 unsigned long len, /* tag length */
6123 unsigned long of /* start offset within file */
6124 ) {
6125 icmTextDescription *p = (icmTextDescription *)pp;
6126 icc *icp = p->icp;
6127 int rv;
6128 char *bp, *buf, *end;
6129
6130 #ifdef ICM_STRICT
6131 if (len < (8 + 4 + 8 + 3 /* + 67 */)) {
6132 #else
6133 if (len < (8 + 4 + 8 + 3)) {
6134 #endif
6135 sprintf(icp->err,"icmTextDescription_read: Tag too small to be legal");
6136 return icp->errc = 1;
6137 }
6138
6139 /* Allocate a file read buffer */
6140 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6141 sprintf(icp->err,"icmTextDescription_read: malloc() failed");
6142 return icp->errc = 2;
6143 }
6144 bp = buf;
6145 end = buf + len;
6146
6147 /* Read portion of file into buffer */
6148 if ( icp->fp->seek(icp->fp, of) != 0
6149 || icp->fp->read(icp->fp, bp, 1, len) != len) {
6150 sprintf(icp->err,"icmTextDescription_read: fseek() or fread() failed");
6151 icp->al->free(icp->al, buf);
6152 return icp->errc = 1;
6153 }
6154
6155 /* Read from the buffer into the structure */
6156 if ((rv = p->core_read(p, &bp, end)) != 0) {
6157 icp->al->free(icp->al, buf);
6158 return rv;
6159 }
6160
6161 icp->al->free(icp->al, buf);
6162 return 0;
6163 }
6164
6165 /* core read the object, return 0 on success, error code on fail */
6166 static int icmTextDescription_core_read(
6167 icmTextDescription *p,
6168 char **bpp, /* Pointer to buffer pointer, returns next after read */
6169 char *end /* Pointer to past end of read buffer */
6170 ) {
6171 icc *icp = p->icp;
6172 int rv = 0;
6173 char *bp = *bpp;
6174
6175 if ((bp + 8) > end) {
6176 sprintf(icp->err,"icmTextDescription_read: Data too short to type descriptor");
6177 *bpp = bp;
6178 return icp->errc = 1;
6179 }
6180
6181 p->size = read_UInt32Number(bp);
6182 /* Read type descriptor from the buffer */
6183 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
6184 *bpp = bp;
6185 sprintf(icp->err,"icmTextDescription_read: Wrong tag type ('%s') for icmTextDescription",
6186 tag2str((icTagTypeSignature)read_SInt32Number(bp)));
6187 return icp->errc = 1;
6188 }
6189 bp = bp + 8;
6190
6191 /* Read the Ascii string */
6192 if ((bp + 4) > end) {
6193 *bpp = bp;
6194 sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii header");
6195 return icp->errc = 1;
6196 }
6197 p->size = read_UInt32Number(bp);
6198 bp += 4;
6199 if (p->size > 0) {
6200 if ((bp + p->size) > end) {
6201 *bpp = bp;
6202 sprintf(icp->err,"icmTextDescription_read: Data to short to read Ascii string");
6203 return icp->errc = 1;
6204 }
6205 if (check_null_string(bp,p->size)) {
6206 *bpp = bp;
6207 sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated");
6208 return icp->errc = 1;
6209 }
6210 if ((rv = p->allocate((icmBase *)p)) != 0) {
6211 return rv;
6212 }
6213 strcpy((void *)p->desc, (void *)bp);
6214 bp += p->size;
6215 }
6216
6217 /* Read the Unicode string */
6218 if ((bp + 8) > end) {
6219 *bpp = bp;
6220 sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
6221 return icp->errc = 1;
6222 }
6223 p->ucLangCode = read_UInt32Number(bp);
6224 bp += 4;
6225 p->ucSize = read_UInt32Number(bp);
6226 bp += 4;
6227 if (p->ucSize > 0) {
6228 ORD16 *up;
6229 if ((bp + 2 * p->ucSize) > end) {
6230 *bpp = bp;
6231 sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
6232 return icp->errc = 1;
6233 }
6234 if (check_null_string16(bp,p->ucSize)) {
6235 *bpp = bp;
6236 sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated");
6237 return icp->errc = 1;
6238 }
6239 if ((rv = p->allocate((icmBase *)p)) != 0) {
6240 return rv;
6241 }
6242 for(up = p->ucDesc; bp[0] != 0 || bp[1] != 0; up++, bp += 2)
6243 *up = read_UInt16Number(bp);
6244 *up = 0; /* Unicode null */
6245 bp += 2;
6246 }
6247
6248 /* Read the ScriptCode string */
6249 if ((bp + 3) > end) {
6250 *bpp = bp;
6251 sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode header");
6252 return icp->errc = 1;
6253 }
6254 p->scCode = read_UInt16Number(bp);
6255 bp += 2;
6256 p->scSize = read_UInt8Number(bp);
6257 bp += 1;
6258 if (p->scSize > 0) {
6259 if (p->scSize > 67) {
6260 *bpp = bp;
6261 sprintf(icp->err,"icmTextDescription_read: ScriptCode string too long");
6262 return icp->errc = 1;
6263 }
6264 if ((bp + p->scSize) > end) {
6265 *bpp = bp;
6266 sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode string");
6267 return icp->errc = 1;
6268 }
6269 if (check_null_string(bp,p->scSize)) {
6270 *bpp = bp;
6271 sprintf(icp->err,"icmTextDescription_read: ScriptCode string is not terminated");
6272 return icp->errc = 1;
6273 }
6274 memcpy((void *)p->scDesc, (void *)bp, p->scSize);
6275 } else {
6276 memset((void *)p->scDesc, 0, 67);
6277 }
6278 bp += 67;
6279
6280 *bpp = bp;
6281 return 0;
6282 }
6283
6284 /* Write the contents of the object. Return 0 on sucess, error code on failure */
6285 static int icmTextDescription_write(
6286 icmBase *pp,
6287 unsigned long of /* File offset to write from */
6288 ) {
6289 icmTextDescription *p = (icmTextDescription *)pp;
6290 icc *icp = p->icp;
6291 unsigned int len;
6292 char *bp, *buf; /* Buffer to write from */
6293 int rv = 0;
6294
6295 /* Allocate a file write buffer */
6296 len = p->get_size((icmBase *)p);
6297 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6298 sprintf(icp->err,"icmTextDescription_write malloc() failed");
6299 return icp->errc = 2;
6300 }
6301 bp = buf;
6302
6303 /* Write to the buffer from the structure */
6304 if ((rv = p->core_write(p, &bp)) != 0) {
6305 icp->al->free(icp->al, buf);
6306 return rv;
6307 }
6308
6309 /* Write to the file */
6310 if ( icp->fp->seek(icp->fp, of) != 0
6311 || icp->fp->write(icp->fp, buf, 1, len) != len) {
6312 sprintf(icp->err,"icmTextDescription_write fseek() or fwrite() failed");
6313 icp->al->free(icp->al, buf);
6314 return icp->errc = 2;
6315 }
6316 icp->al->free(icp->al, buf);
6317 return 0;
6318 }
6319
6320 /* Core write the contents of the object. Return 0 on sucess, error code on failure */
6321 static int icmTextDescription_core_write(
6322 icmTextDescription *p,
6323 char **bpp /* Pointer to buffer pointer, returns next after read */
6324 ) {
6325 icc *icp = p->icp;
6326 char *bp = *bpp;
6327 int rv = 0;
6328
6329 /* Write type descriptor to the buffer */
6330 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
6331 sprintf(icp->err,"icmTextDescription_write: write_SInt32Number() failed");
6332 *bpp = bp;
6333 return icp->errc = rv;
6334 }
6335 write_SInt32Number(0,bp+4); /* Set padding to 0 */
6336 bp = bp + 8;
6337
6338 /* Write the Ascii string */
6339 if ((rv = write_UInt32Number(p->size,bp)) != 0) {
6340 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6341 *bpp = bp;
6342 return icp->errc = rv;
6343 }
6344 bp += 4;
6345 if (p->size > 0) {
6346 if (check_null_string(p->desc,p->size)) {
6347 *bpp = bp;
6348 sprintf(icp->err,"icmTextDescription_write: ascii string is not terminated");
6349 return icp->errc = 1;
6350 }
6351 strcpy((void *)bp, (void *)p->desc);
6352 bp += p->size;
6353 }
6354
6355 /* Write the Unicode string */
6356 if ((rv = write_UInt32Number(p->ucLangCode, bp)) != 0) {
6357 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6358 *bpp = bp;
6359 return icp->errc = rv;
6360 }
6361 bp += 4;
6362 if ((rv = write_UInt32Number(p->ucSize, bp)) != 0) {
6363 sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6364 *bpp = bp;
6365 return icp->errc = rv;
6366 }
6367 bp += 4;
6368 if (p->ucSize > 0) {
6369 ORD16 *up;
6370 if (check_null_string16((char *)p->ucDesc,p->ucSize)) {
6371 *bpp = bp;
6372 sprintf(icp->err,"icmTextDescription_write: Unicode string is not terminated");
6373 return icp->errc = 1;
6374 }
6375 for(up = p->ucDesc; *up != 0; up++, bp += 2) {
6376 if ((rv = write_UInt16Number(((unsigned int)*up), bp)) != 0) {
6377 sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
6378 *bpp = bp;
6379 return icp->errc = rv;
6380 }
6381 }
6382 bp[0] = 0; /* null */
6383 bp[1] = 0;
6384 bp += 2;
6385 }
6386
6387 /* Write the ScriptCode string */
6388 if ((rv = write_UInt16Number(p->scCode, bp)) != 0) {
6389 sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
6390 *bpp = bp;
6391 return icp->errc = rv;
6392 }
6393 bp += 2;
6394 if ((rv = write_UInt8Number(p->scSize, bp)) != 0) {
6395 sprintf(icp->err,"icmTextDescription_write: write_UInt8Number() failed");
6396 *bpp = bp;
6397 return icp->errc = rv;
6398 }
6399 bp += 1;
6400 if (p->scSize > 0) {
6401 if (p->scSize > 67) {
6402 *bpp = bp;
6403 sprintf(icp->err,"icmTextDescription_write: ScriptCode string too long");
6404 return icp->errc = 1;
6405 }
6406 if (check_null_string((char *)p->scDesc,p->scSize)) {
6407 *bpp = bp;
6408 sprintf(icp->err,"icmTextDescription_write: ScriptCode string is not terminated");
6409 return icp->errc = 1;
6410 }
6411 memcpy((void *)bp, (void *)p->scDesc, 67);
6412 } else {
6413 memset((void *)bp, 0, 67);
6414 }
6415 bp += 67;
6416
6417 *bpp = bp;
6418 return 0;
6419 }
6420
6421 /* Dump a text description of the object */
6422 static void icmTextDescription_dump(
6423 icmBase *pp,
6424 FILE *op, /* Output to dump to */
6425 int verb /* Verbosity level */
6426 ) {
6427 icmTextDescription *p = (icmTextDescription *)pp;
6428 unsigned long i, r, c;
6429
6430 if (verb <= 0)
6431 return;
6432
6433 fprintf(op,"TextDescription:\n");
6434
6435 if (p->size > 0) {
6436 unsigned long size = p->size > 0 ? p->size-1 : 0;
6437 fprintf(op," ASCII data, length %lu chars:\n",p->size);
6438
6439 i = 0;
6440 for (r = 1;; r++) { /* count rows */
6441 if (i >= size) {
6442 fprintf(op,"\n");
6443 break;
6444 }
6445 if (r > 1 && verb < 2) {
6446 fprintf(op,"...\n");
6447 break; /* Print 1 row if not verbose */
6448 }
6449 c = 1;
6450 fprintf(op," 0x%04lx: ",i);
6451 c += 10;
6452 while (i < size && c < 75) {
6453 if (isprint(p->desc[i])) {
6454 fprintf(op,"%c",p->desc[i]);
6455 c++;
6456 } else {
6457 fprintf(op,"\\%03o",p->desc[i]);
6458 c += 4;
6459 }
6460 i++;
6461 }
6462 if (i < size)
6463 fprintf(op,"\n");
6464 }
6465 } else {
6466 fprintf(op," No ASCII data\n");
6467 }
6468
6469 /* Can't dump Unicode or ScriptCode as text with portable code */
6470 if (p->ucSize > 0) {
6471 unsigned long size = p->ucSize;
6472 fprintf(op," Unicode Data, Language code 0x%x, length %lu chars\n",
6473 p->ucLangCode, p->ucSize);
6474 i = 0;
6475 for (r = 1;; r++) { /* count rows */
6476 if (i >= size) {
6477 fprintf(op,"\n");
6478 break;
6479 }
6480 if (r > 1 && verb < 2) {
6481 fprintf(op,"...\n");
6482 break; /* Print 1 row if not verbose */
6483 }
6484 c = 1;
6485 fprintf(op," 0x%04lx: ",i);
6486 c += 10;
6487 while (i < size && c < 75) {
6488 fprintf(op,"%04x ",p->ucDesc[i]);
6489 c += 5;
6490 i++;
6491 }
6492 if (i < size)
6493 fprintf(op,"\n");
6494 }
6495 } else {
6496 fprintf(op," No Unicode data\n");
6497 }
6498 if (p->scSize > 0) {
6499 unsigned long size = p->scSize;
6500 fprintf(op," ScriptCode Data, Code 0x%x, length %lu chars\n",
6501 p->scCode, p->scSize);
6502 i = 0;
6503 for (r = 1;; r++) { /* count rows */
6504 if (i >= size) {
6505 fprintf(op,"\n");
6506 break;
6507 }
6508 if (r > 1 && verb < 2) {
6509 fprintf(op,"...\n");
6510 break; /* Print 1 row if not verbose */
6511 }
6512 c = 1;
6513 fprintf(op," 0x%04lx: ",i);
6514 c += 10;
6515 while (i < size && c < 75) {
6516 fprintf(op,"%02x ",p->scDesc[i]);
6517 c += 3;
6518 i++;
6519 }
6520 if (i < size)
6521 fprintf(op,"\n");
6522 }
6523 } else {
6524 fprintf(op," No ScriptCode data\n");
6525 }
6526 }
6527
6528 /* Allocate variable sized data elements */
6529 static int icmTextDescription_allocate(
6530 icmBase *pp
6531 ) {
6532 icmTextDescription *p = (icmTextDescription *)pp;
6533 icc *icp = p->icp;
6534
6535 if (p->size != p->_size) {
6536 if (p->desc != NULL)
6537 icp->al->free(icp->al, p->desc);
6538 if ((p->desc = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
6539 sprintf(icp->err,"icmTextDescription_alloc: malloc() of Ascii description failed");
6540 return icp->errc = 2;
6541 }
6542 p->_size = p->size;
6543 }
6544 if (p->ucSize != p->uc_size) {
6545 if (p->ucDesc != NULL)
6546 icp->al->free(icp->al, p->ucDesc);
6547 if ((p->ucDesc = (ORD16 *) icp->al->malloc(icp->al, p->ucSize * sizeof(ORD16))) == NULL) {
6548 sprintf(icp->err,"icmTextDescription_alloc: malloc() of Unicode description failed");
6549 return icp->errc = 2;
6550 }
6551 p->uc_size = p->ucSize;
6552 }
6553 return 0;
6554 }
6555
6556 /* Free all variable sized elements */
6557 static void icmTextDescription_unallocate(
6558 icmTextDescription *p
6559 ) {
6560 icc *icp = p->icp;
6561
6562 if (p->desc != NULL)
6563 icp->al->free(icp->al, p->desc);
6564 if (p->ucDesc != NULL)
6565 icp->al->free(icp->al, p->ucDesc);
6566 }
6567
6568 /* Free all storage in the object */
6569 static void icmTextDescription_delete(
6570 icmBase *pp
6571 ) {
6572 icmTextDescription *p = (icmTextDescription *)pp;
6573 icc *icp = p->icp;
6574
6575 icmTextDescription_unallocate(p);
6576 icp->al->free(icp->al, p);
6577 }
6578
6579 /* Initialze a named object */
6580 static void icmTextDescription_init(
6581 icmTextDescription *p,
6582 icc *icp
6583 ) {
6584 memset((void *)p, 0, sizeof(icmTextDescription)); /* Imitate calloc */
6585
6586 p->ttype = icSigTextDescriptionType;
6587 p->refcount = 1;
6588 p->get_size = icmTextDescription_get_size;
6589 p->read = icmTextDescription_read;
6590 p->write = icmTextDescription_write;
6591 p->dump = icmTextDescription_dump;
6592 p->allocate = icmTextDescription_allocate;
6593 p->del = icmTextDescription_delete;
6594 p->icp = icp;
6595
6596 p->core_read = icmTextDescription_core_read;
6597 p->core_write = icmTextDescription_core_write;
6598 }
6599
6600 /* Create an empty object. Return null on error */
6601 static icmBase *new_icmTextDescription(
6602 icc *icp
6603 ) {
6604 icmTextDescription *p;
6605 if ((p = (icmTextDescription *) icp->al->calloc(icp->al,1,sizeof(icmTextDescription))) == NULL)
6606 return NULL;
6607
6608 icmTextDescription_init(p,icp);
6609 return (icmBase *)p;
6610 }
6611
6612 /* ---------------------------------------------------------- */
6613
6614 /* Support for icmDescStruct */
6615
6616 /* Return the number of bytes needed to write this tag */
6617 static unsigned int icmDescStruct_get_size(
6618 icmDescStruct *p
6619 ) {
6620 unsigned int len = 0;
6621 len += 20; /* 20 bytes for header info */
6622 len += p->device.get_size((icmBase *)&p->device);
6623 len += p->model.get_size((icmBase *)&p->model);
6624 return len;
6625 }
6626
6627 /* read the object, return 0 on success, error code on fail */
6628 static int icmDescStruct_read(
6629 icmDescStruct *p,
6630 char **bpp, /* Pointer to buffer pointer, returns next after read */
6631 char *end /* Pointer to past end of read buffer */
6632 ) {
6633 icc *icp = p->icp;
6634 char *bp = *bpp;
6635 int rv = 0;
6636
6637 if ((bp + 20) > end) {
6638 sprintf(icp->err,"icmDescStruct_read: Data too short read header");
6639 *bpp = bp;
6640 return icp->errc = 1;
6641 }
6642
6643 p->deviceMfg = read_SInt32Number(bp + 0);
6644 p->deviceModel = read_UInt32Number(bp + 4);
6645 read_UInt64Number(&p->attributes, bp + 8);
6646 p->technology = read_UInt32Number(bp + 16);
6647 *bpp = bp += 20;
6648
6649 /* Read the device text description */
6650 if ((rv = p->device.core_read(&p->device, bpp, end)) != 0) {
6651 return rv;
6652 }
6653
6654 /* Read the model text description */
6655 if ((rv = p->model.core_read(&p->model, bpp, end)) != 0) {
6656 return rv;
6657 }
6658
6659 return 0;
6660 }
6661
6662 /* Write the contents of the object. Return 0 on sucess, error code on failure */
6663 static int icmDescStruct_write(
6664 icmDescStruct *p,
6665 char **bpp /* Pointer to buffer pointer, returns next after read */
6666 ) {
6667 icc *icp = p->icp;
6668 char *bp = *bpp;
6669 int rv = 0;
6670
6671 if ((rv = write_SInt32Number(p->deviceMfg, bp + 0)) != 0) {
6672 sprintf(icp->err,"icmDescStruct_write: write_SInt32Number() failed");
6673 *bpp = bp;
6674 return icp->errc = rv;
6675 }
6676 if ((rv = write_UInt32Number(p->deviceModel, bp + 4)) != 0) {
6677 sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
6678 *bpp = bp;
6679 return icp->errc = rv;
6680 }
6681 if ((rv = write_UInt64Number(&p->attributes, bp + 8)) != 0) {
6682 sprintf(icp->err,"icmDescStruct_write: write_UInt64Number() failed");
6683 *bpp = bp;
6684 return icp->errc = rv;
6685 }
6686 if ((rv = write_UInt32Number(p->technology, bp + 16)) != 0) {
6687 sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
6688 *bpp = bp;
6689 return icp->errc = rv;
6690 }
6691 *bpp = bp += 20;
6692
6693 /* Write the device text description */
6694 if ((rv = p->device.core_write(&p->device, bpp)) != 0) {
6695 return rv;
6696 }
6697
6698 /* Write the model text description */
6699 if ((rv = p->model.core_write(&p->model, bpp)) != 0) {
6700 return rv;
6701 }
6702
6703 return 0;
6704 }
6705
6706 /* Dump a text description of the object */
6707 static void icmDescStruct_dump(
6708 icmDescStruct *p,
6709 FILE *op, /* Output to dump to */
6710 int verb, /* Verbosity level */
6711 int index /* Description index */
6712 ) {
6713 if (verb <= 0)
6714 return;
6715
6716 fprintf(op,"DescStruct %u:\n",index);
6717 if (verb >= 1) {
6718 fprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->deviceMfg)); /* ~~~ */
6719 fprintf(op," Dev. Model = %s\n",tag2str(p->deviceModel)); /* ~~~ */
6720 fprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
6721 fprintf(op," Dev. Technology = %s\n", string_TechnologySignature(p->technology));
6722 p->device.dump((icmBase *)&p->device, op,verb);
6723 p->model.dump((icmBase *)&p->model, op,verb);
6724 fprintf(op,"\n");
6725 }
6726 }
6727
6728 /* Allocate variable sized data elements (ie. descriptions) */
6729 static int icmDescStruct_allocate(
6730 icmDescStruct *p
6731 ) {
6732 int rv;
6733
6734 if ((rv = p->device.allocate((icmBase *)&p->device)) != 0) {
6735 return rv;
6736 }
6737 if ((rv = p->model.allocate((icmBase *)&p->model)) != 0) {
6738 return rv;
6739 }
6740 return 0;
6741 }
6742
6743 /* Free all storage in the object */
6744 static void icmDescStruct_delete(
6745 icmDescStruct *p
6746 ) {
6747 icmTextDescription_unallocate(&p->device);
6748 icmTextDescription_unallocate(&p->model);
6749 }
6750
6751 /* Init a DescStruct object */
6752 static void icmDescStruct_init(
6753 icmDescStruct *p,
6754 icc *icp
6755 ) {
6756
6757 p->allocate = icmDescStruct_allocate;
6758 p->icp = icp;
6759
6760 icmTextDescription_init(&p->device, icp);
6761 icmTextDescription_init(&p->model, icp);
6762 }
6763
6764 /* - - - - - - - - - - - - - - - */
6765 /* icmProfileSequenceDesc object */
6766
6767 /* Return the number of bytes needed to write this tag */
6768 static unsigned int icmProfileSequenceDesc_get_size(
6769 icmBase *pp
6770 ) {
6771 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6772 unsigned int len = 0;
6773 unsigned int i;
6774 len += 12; /* 8 bytes for tag, padding and count */
6775 for (i = 0; i < p->count; i++) { /* All the description structures */
6776 len += icmDescStruct_get_size(&p->data[i]);
6777 }
6778 return len;
6779 }
6780
6781 /* read the object, return 0 on success, error code on fail */
6782 static int icmProfileSequenceDesc_read(
6783 icmBase *pp,
6784 unsigned long len, /* tag length */
6785 unsigned long of /* start offset within file */
6786 ) {
6787 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6788 icc *icp = p->icp;
6789 unsigned long i;
6790 char *bp, *buf, *end;
6791 int rv = 0;
6792
6793 if (len < 12) {
6794 sprintf(icp->err,"icmProfileSequenceDesc_read: Tag too small to be legal");
6795 return icp->errc = 1;
6796 }
6797
6798 /* Allocate a file read buffer */
6799 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6800 sprintf(icp->err,"icmProfileSequenceDesc_read: malloc() failed");
6801 return icp->errc = 2;
6802 }
6803 bp = buf;
6804 end = buf + len;
6805
6806 /* Read portion of file into buffer */
6807 if ( icp->fp->seek(icp->fp, of) != 0
6808 || icp->fp->read(icp->fp, bp, 1, len) != len) {
6809 sprintf(icp->err,"icmProfileSequenceDesc_read: fseek() or fread() failed");
6810 icp->al->free(icp->al, buf);
6811 return icp->errc = 1;
6812 }
6813
6814 /* Read type descriptor from the buffer */
6815 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
6816 sprintf(icp->err,"icmProfileSequenceDesc_read: Wrong tag type for icmProfileSequenceDesc");
6817 icp->al->free(icp->al, buf);
6818 return icp->errc = 1;
6819 }
6820 bp += 8; /* Skip padding */
6821
6822 p->count = read_UInt32Number(bp); /* Number of sequence descriptions */
6823 bp += 4;
6824
6825 /* Read all the sequence descriptions */
6826 if ((rv = p->allocate((icmBase *)p)) != 0) {
6827 icp->al->free(icp->al, buf);
6828 return rv;
6829 }
6830 for (i = 0; i < p->count; i++) {
6831 if ((rv = icmDescStruct_read(&p->data[i], &bp, end)) != 0) {
6832 icp->al->free(icp->al, buf);
6833 return rv;
6834 }
6835 }
6836
6837 icp->al->free(icp->al, buf);
6838 return 0;
6839 }
6840
6841 /* Write the contents of the object. Return 0 on sucess, error code on failure */
6842 static int icmProfileSequenceDesc_write(
6843 icmBase *pp,
6844 unsigned long of /* File offset to write from */
6845 ) {
6846 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6847 icc *icp = p->icp;
6848 unsigned long i;
6849 unsigned int len;
6850 char *bp, *buf; /* Buffer to write from */
6851 int rv = 0;
6852
6853 /* Allocate a file write buffer */
6854 len = p->get_size((icmBase *)p);
6855 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6856 sprintf(icp->err,"icmProfileSequenceDesc_write malloc() failed");
6857 return icp->errc = 2;
6858 }
6859 bp = buf;
6860
6861 /* Write type descriptor to the buffer */
6862 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
6863 sprintf(icp->err,"icmProfileSequenceDesc_write: write_SInt32Number() failed");
6864 icp->al->free(icp->al, buf);
6865 return icp->errc = rv;
6866 }
6867 write_SInt32Number(0,bp+4); /* Set padding to 0 */
6868
6869 if ((rv = write_UInt32Number(p->count,bp+8)) != 0) {
6870 sprintf(icp->err,"icmProfileSequenceDesc_write: write_UInt32Number() failed");
6871 icp->al->free(icp->al, buf);
6872 return icp->errc = rv;
6873 }
6874 bp = bp + 12;
6875
6876 /* Write all the description structures */
6877 for (i = 0; i < p->count; i++) {
6878 if ((rv = icmDescStruct_write(&p->data[i], &bp)) != 0) {
6879 icp->al->free(icp->al, buf);
6880 return rv;
6881 }
6882 }
6883
6884 /* Write to the file */
6885 if ( icp->fp->seek(icp->fp, of) != 0
6886 || icp->fp->write(icp->fp, buf, 1, len) != len) {
6887 sprintf(icp->err,"icmProfileSequenceDesc_write fseek() or fwrite() failed");
6888 icp->al->free(icp->al, buf);
6889 return icp->errc = 2;
6890 }
6891 icp->al->free(icp->al, buf);
6892 return 0;
6893 }
6894
6895 /* Dump a text description of the object */
6896 static void icmProfileSequenceDesc_dump(
6897 icmBase *pp,
6898 FILE *op, /* Output to dump to */
6899 int verb /* Verbosity level */
6900 ) {
6901 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6902 if (verb <= 0)
6903 return;
6904
6905 fprintf(op,"ProfileSequenceDesc:\n");
6906 fprintf(op," No. elements = %u\n",p->count);
6907 if (verb >= 2) {
6908 unsigned long i;
6909 for (i = 0; i < p->count; i++)
6910 icmDescStruct_dump(&p->data[i], op, verb-1, i);
6911 }
6912 }
6913
6914 /* Allocate variable sized data elements (ie. count of profile descriptions) */
6915 static int icmProfileSequenceDesc_allocate(
6916 icmBase *pp
6917 ) {
6918 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6919 icc *icp = p->icp;
6920 unsigned int i;
6921
6922 if (p->count != p->_count) {
6923 if (p->data != NULL)
6924 icp->al->free(icp->al, p->data);
6925 if ((p->data = (icmDescStruct *) icp->al->malloc(icp->al, p->count * sizeof(icmDescStruct))) == NULL) {
6926 sprintf(icp->err,"icmProfileSequenceDesc_allocate Allocation of DescStruct array failed");
6927 return icp->errc = 2;
6928 }
6929 /* Now init the DescStructs */
6930 for (i = 0; i < p->count; i++) {
6931 icmDescStruct_init(&p->data[i], icp);
6932 }
6933 p->_count = p->count;
6934 }
6935 return 0;
6936 }
6937
6938 /* Free all storage in the object */
6939 static void icmProfileSequenceDesc_delete(
6940 icmBase *pp
6941 ) {
6942 icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6943 icc *icp = p->icp;
6944 unsigned int i;
6945
6946 for (i = 0; i < p->count; i++) {
6947 icmDescStruct_delete(&p->data[i]); /* Free allocated contents */
6948 }
6949 if (p->data != NULL)
6950 icp->al->free(icp->al, p->data);
6951 icp->al->free(icp->al, p);
6952 }
6953
6954 /* Create an empty object. Return null on error */
6955 static icmBase *new_icmProfileSequenceDesc(
6956 icc *icp
6957 ) {
6958 icmProfileSequenceDesc *p;
6959 if ((p = (icmProfileSequenceDesc *) icp->al->calloc(icp->al,1,sizeof(icmProfileSequenceDesc))) == NULL)
6960 return NULL;
6961 p->ttype = icSigProfileSequenceDescType;
6962 p->refcount = 1;
6963 p->get_size = icmProfileSequenceDesc_get_size;
6964 p->read = icmProfileSequenceDesc_read;
6965 p->write = icmProfileSequenceDesc_write;
6966 p->dump = icmProfileSequenceDesc_dump;
6967 p->allocate = icmProfileSequenceDesc_allocate;
6968 p->del = icmProfileSequenceDesc_delete;
6969 p->icp = icp;
6970
6971 return (icmBase *)p;
6972 }
6973
6974 /* ---------------------------------------------------------- */
6975 /* Signature */
6976
6977 /* Return the number of bytes needed to write this tag */
6978 static unsigned int icmSignature_get_size(
6979 icmBase *pp
6980 ) {
6981 unsigned int len = 0;
6982 len += 8; /* 8 bytes for tag and padding */
6983 len += 4; /* 4 for signature */
6984 return len;
6985 }
6986
6987 /* read the object, return 0 on success, error code on fail */
6988 static int icmSignature_read(
6989 icmBase *pp,
6990 unsigned long len, /* tag length */
6991 unsigned long of /* start offset within file */
6992 ) {
6993 icmSignature *p = (icmSignature *)pp;
6994 icc *icp = p->icp;
6995 char *bp, *buf;
6996
6997 if (len < 12) {
6998 sprintf(icp->err,"icmSignature_read: Tag too small to be legal");
6999 return icp->errc = 1;
7000 }
7001
7002 /* Allocate a file read buffer */
7003 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7004 sprintf(icp->err,"icmSignature_read: malloc() failed");
7005 return icp->errc = 2;
7006 }
7007 bp = buf;
7008
7009 /* Read portion of file into buffer */
7010 if ( icp->fp->seek(icp->fp, of) != 0
7011 || icp->fp->read(icp->fp, bp, 1, len) != len) {
7012 sprintf(icp->err,"icmSignature_read: fseek() or fread() failed");
7013 icp->al->free(icp->al, buf);
7014 return icp->errc = 1;
7015 }
7016
7017 /* Read type descriptor from the buffer */
7018 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7019 sprintf(icp->err,"icmSignaturSignatureng tag type for icmSignature");
7020 icp->al->free(icp->al, buf);
7021 return icp->errc = 1;
7022 }
7023
7024 /* Read the encoded measurement geometry */
7025 p->sig = (icTechnologySignature)read_SInt32Number(bp + 8);
7026
7027 icp->al->free(icp->al, buf);
7028 return 0;
7029 }
7030
7031 /* Write the contents of the object. Return 0 on sucess, error code on failure */
7032 static int icmSignature_write(
7033 icmBase *pp,
7034 unsigned long of /* File offset to write from */
7035 ) {
7036 icmSignature *p = (icmSignature *)pp;
7037 icc *icp = p->icp;
7038 unsigned int len;
7039 char *bp, *buf; /* Buffer to write from */
7040 int rv = 0;
7041
7042 /* Allocate a file write buffer */
7043 len = p->get_size((icmBase *)p);
7044 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7045 sprintf(icp->err,"icmSignature_write malloc() failed");
7046 return icp->errc = 2;
7047 }
7048 bp = buf;
7049
7050 /* Write type descriptor to the buffer */
7051 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7052 sprintf(icp->err,"icmSignature_write: write_SInt32Number() failed");
7053 icp->al->free(icp->al, buf);
7054 return icp->errc = rv;
7055 }
7056 write_SInt32Number(0,bp+4); /* Set padding to 0 */
7057
7058 /* Write the signature */
7059 if ((rv = write_SInt32Number((int)p->sig, bp + 8)) != 0) {
7060 sprintf(icp->err,"icmSignaturea_write: write_SInt32Number() failed");
7061 icp->al->free(icp->al, buf);
7062 return icp->errc = rv;
7063 }
7064
7065 /* Write to the file */
7066 if ( icp->fp->seek(icp->fp, of) != 0
7067 || icp->fp->write(icp->fp, buf, 1, len) != len) {
7068 sprintf(icp->err,"icmSignature_write fseek() or fwrite() failed");
7069 icp->al->free(icp->al, buf);
7070 return icp->errc = 2;
7071 }
7072 icp->al->free(icp->al, buf);
7073 return 0;
7074 }
7075
7076 /* Dump a text description of the object */
7077 static void icmSignature_dump(
7078 icmBase *pp,
7079 FILE *op, /* Output to dump to */
7080 int verb /* Verbosity level */
7081 ) {
7082 icmSignature *p = (icmSignature *)pp;
7083 if (verb <= 0)
7084 return;
7085
7086 fprintf(op,"Signature\n");
7087 fprintf(op," Technology = %s\n", string_TechnologySignature(p->sig));
7088 }
7089
7090 /* Allocate variable sized data elements */
7091 static int icmSignature_allocate(
7092 icmBase *pp
7093 ) {
7094 /* Nothing to do */
7095 return 0;
7096 }
7097
7098 /* Free all storage in the object */
7099 static void icmSignature_delete(
7100 icmBase *pp
7101 ) {
7102 icmSignature *p = (icmSignature *)pp;
7103 icc *icp = p->icp;
7104
7105 icp->al->free(icp->al, p);
7106 }
7107
7108 /* Create an empty object. Return null on error */
7109 static icmBase *new_icmSignature(
7110 icc *icp
7111 ) {
7112 icmSignature *p;
7113 if ((p = (icmSignature *) icp->al->calloc(icp->al,1,sizeof(icmSignature))) == NULL)
7114 return NULL;
7115 p->ttype = icSigSignatureType;
7116 p->refcount = 1;
7117 p->get_size = icmSignature_get_size;
7118 p->read = icmSignature_read;
7119 p->write = icmSignature_write;
7120 p->dump = icmSignature_dump;
7121 p->allocate = icmSignature_allocate;
7122 p->del = icmSignature_delete;
7123 p->icp = icp;
7124
7125 return (icmBase *)p;
7126 }
7127
7128 /* ---------------------------------------------------------- */
7129
7130 /* Data conversion support functions */
7131 static int read_ScreeningData(icmScreeningData *p, char *d) {
7132 p->frequency = read_S15Fixed16Number(d + 0);
7133 p->angle = read_S15Fixed16Number(d + 4);
7134 p->spotShape = (icSpotShape)read_SInt32Number(d + 8);
7135 return 0;
7136 }
7137
7138 static int write_ScreeningData(icmScreeningData *p, char *d) {
7139 int rv;
7140 if ((rv = write_S15Fixed16Number(p->frequency, d + 0)) != 0)
7141 return rv;
7142 if ((rv = write_S15Fixed16Number(p->angle, d + 4)) != 0)
7143 return rv;
7144 if ((rv = write_SInt32Number((int)p->spotShape, d + 8)) != 0)
7145 return rv;
7146 return 0;
7147 }
7148
7149
7150 /* icmScreening object */
7151
7152 /* Return the number of bytes needed to write this tag */
7153 static unsigned int icmScreening_get_size(
7154 icmBase *pp
7155 ) {
7156 icmScreening *p = (icmScreening *)pp;
7157 unsigned int len = 0;
7158 len += 16; /* 16 bytes for tag, padding, flag & channeles */
7159 len += p->channels * 12; /* 12 bytes for each channel */
7160 return len;
7161 }
7162
7163 /* read the object, return 0 on success, error code on fail */
7164 static int icmScreening_read(
7165 icmBase *pp,
7166 unsigned long len, /* tag length */
7167 unsigned long of /* start offset within file */
7168 ) {
7169 icmScreening *p = (icmScreening *)pp;
7170 icc *icp = p->icp;
7171 int rv = 0;
7172 unsigned long i;
7173 char *bp, *buf, *end;
7174
7175 if (len < 12) {
7176 sprintf(icp->err,"icmScreening_read: Tag too small to be legal");
7177 return icp->errc = 1;
7178 }
7179
7180 /* Allocate a file read buffer */
7181 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7182 sprintf(icp->err,"icmScreening_read: malloc() failed");
7183 return icp->errc = 2;
7184 }
7185 bp = buf;
7186 end = buf + len;
7187
7188 /* Read portion of file into buffer */
7189 if ( icp->fp->seek(icp->fp, of) != 0
7190 || icp->fp->read(icp->fp, bp, 1, len) != len) {
7191 sprintf(icp->err,"icmScreening_read: fseek() or fread() failed");
7192 icp->al->free(icp->al, buf);
7193 return icp->errc = 1;
7194 }
7195
7196 /* Read type descriptor from the buffer */
7197 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7198 sprintf(icp->err,"icmScreening_read: Wrong tag type for icmScreening");
7199 icp->al->free(icp->al, buf);
7200 return icp->errc = 1;
7201 }
7202 p->screeningFlag = read_UInt32Number(bp+8); /* Flags */
7203 p->channels = read_UInt32Number(bp+12); /* Number of channels */
7204 bp = bp + 16;
7205
7206 if ((rv = p->allocate((icmBase *)p)) != 0) {
7207 icp->al->free(icp->al, buf);
7208 return rv;
7209 }
7210
7211 /* Read all the data from the buffer */
7212 for (i = 0; i < p->channels; i++, bp += 12) {
7213 if ((bp + 12) > end) {
7214 sprintf(icp->err,"icmScreening_read: Data too short to read Screening Data");
7215 icp->al->free(icp->al, buf);
7216 return icp->errc = 1;
7217 }
7218 read_ScreeningData(&p->data[i], bp);
7219 }
7220 icp->al->free(icp->al, buf);
7221 return 0;
7222 }
7223
7224 /* Write the contents of the object. Return 0 on sucess, error code on failure */
7225 static int icmScreening_write(
7226 icmBase *pp,
7227 unsigned long of /* File offset to write from */
7228 ) {
7229 icmScreening *p = (icmScreening *)pp;
7230 icc *icp = p->icp;
7231 unsigned long i;
7232 unsigned int len;
7233 char *bp, *buf; /* Buffer to write from */
7234 int rv = 0;
7235
7236 /* Allocate a file write buffer */
7237 len = p->get_size((icmBase *)p);
7238 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7239 sprintf(icp->err,"icmScreening_write malloc() failed");
7240 return icp->errc = 2;
7241 }
7242 bp = buf;
7243
7244 /* Write type descriptor to the buffer */
7245 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7246 sprintf(icp->err,"icmScreening_write: write_SInt32Number() failed");
7247 icp->al->free(icp->al, buf);
7248 return icp->errc = rv;
7249 }
7250 write_SInt32Number(0,bp+4); /* Set padding to 0 */
7251
7252 if ((rv = write_UInt32Number(p->screeningFlag,bp+8)) != 0) {
7253 sprintf(icp->err,"icmScreening_write: write_UInt32Number() failed");
7254 icp->al->free(icp->al, buf);
7255 return icp->errc = rv;
7256 }
7257 if ((rv = write_UInt32Number(p->channels,bp+12)) != 0) {
7258 sprintf(icp->err,"icmScreening_write: write_UInt32NumberXYZumber() failed");
7259 icp->al->free(icp->al, buf);
7260 return icp->errc = rv;
7261 }
7262 bp = bp + 16;
7263
7264 /* Write all the data to the buffer */
7265 for (i = 0; i < p->channels; i++, bp += 12) {
7266 if ((rv = write_ScreeningData(&p->data[i],bp)) != 0) {
7267 sprintf(icp->err,"icmScreening_write: write_ScreeningData() failed");
7268 icp->al->free(icp->al, buf);
7269 return icp->errc = rv;
7270 }
7271 }
7272
7273 /* Write to the file */
7274 if ( icp->fp->seek(icp->fp, of) != 0
7275 || icp->fp->write(icp->fp, buf, 1, len) != len) {
7276 sprintf(icp->err,"icmScreening_write fseek() or fwrite() failed");
7277 icp->al->free(icp->al, buf);
7278 return icp->errc = 2;
7279 }
7280 icp->al->free(icp->al, buf);
7281 return 0;
7282 }
7283
7284 /* Dump a text description of the object */
7285 static void icmScreening_dump(
7286 icmBase *pp,
7287 FILE *op, /* Output to dump to */
7288 int verb /* Verbosity level */
7289 ) {
7290 icmScreening *p = (icmScreening *)pp;
7291 if (verb <= 0)
7292 return;
7293
7294 fprintf(op,"Screening:\n");
7295 fprintf(op," Flags = %s\n", string_ScreenEncodings(p->screeningFlag));
7296 fprintf(op," No. channels = %u\n",p->channels);
7297 if (verb >= 2) {
7298 unsigned long i;
7299 for (i = 0; i < p->channels; i++) {
7300 fprintf(op," %lu:\n",i);
7301 fprintf(op," Frequency: %f\n",p->data[i].frequency);
7302 fprintf(op," Angle: %f\n",p->data[i].angle);
7303 fprintf(op," Spot shape: %s\n", string_SpotShape(p->data[i].spotShape));
7304 }
7305 }
7306 }
7307
7308 /* Allocate variable sized data elements */
7309 static int icmScreening_allocate(
7310 icmBase *pp
7311 ) {
7312 icmScreening *p = (icmScreening *)pp;
7313 icc *icp = p->icp;
7314
7315 if (p->channels != p->_channels) {
7316 if (p->data != NULL)
7317 icp->al->free(icp->al, p->data);
7318 if ((p->data = (icmScreeningData *) icp->al->malloc(icp->al, p->channels * sizeof(icmScreeningData))) == NULL) {
7319 sprintf(icp->err,"icmScreening_alloc: malloc() of icmScreening data failed");
7320 return icp->errc = 2;
7321 }
7322 p->_channels = p->channels;
7323 }
7324 return 0;
7325 }
7326
7327 /* Free all storage in the object */
7328 static void icmScreening_delete(
7329 icmBase *pp
7330 ) {
7331 icmScreening *p = (icmScreening *)pp;
7332 icc *icp = p->icp;
7333
7334 if (p->data != NULL)
7335 icp->al->free(icp->al, p->data);
7336 icp->al->free(icp->al, p);
7337 }
7338
7339 /* Create an empty object. Return null on error */
7340 static icmBase *new_icmScreening(
7341 icc *icp
7342 ) {
7343 icmScreening *p;
7344 if ((p = (icmScreening *) icp->al->calloc(icp->al,1,sizeof(icmScreening))) == NULL)
7345 return NULL;
7346 p->ttype = icSigScreeningType;
7347 p->refcount = 1;
7348 p->get_size = icmScreening_get_size;
7349 p->read = icmScreening_read;
7350 p->write = icmScreening_write;
7351 p->dump = icmScreening_dump;
7352 p->allocate = icmScreening_allocate;
7353 p->del = icmScreening_delete;
7354 p->icp = icp;
7355
7356 return (icmBase *)p;
7357 }
7358
7359 /* ---------------------------------------------------------- */
7360 /* icmUcrBg object */
7361
7362 /* Return the number of bytes needed to write this tag */
7363 static unsigned int icmUcrBg_get_size(
7364 icmBase *pp
7365 ) {
7366 icmUcrBg *p = (icmUcrBg *)pp;
7367 unsigned int len = 0;
7368 len += 8; /* 8 bytes for tag and padding */
7369 len += 4 + p->UCRcount * 2; /* Undercolor Removal */
7370 len += 4 + p->BGcount * 2; /* Black Generation */
7371 len += p->size; /* Description string */
7372 return len;
7373 }
7374
7375 /* read the object, return 0 on success, error code on fail */
7376 static int icmUcrBg_read(
7377 icmBase *pp,
7378 unsigned long len, /* tag length */
7379 unsigned long of /* start offset within file */
7380 ) {
7381 icmUcrBg *p = (icmUcrBg *)pp;
7382 icc *icp = p->icp;
7383 unsigned long i;
7384 int rv = 0;
7385 char *bp, *buf, *end;
7386
7387 if (len < 16) {
7388 sprintf(icp->err,"icmUcrBg_read: Tag too small to be legal");
7389 return icp->errc = 1;
7390 }
7391
7392 /* Allocate a file read buffer */
7393 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7394 sprintf(icp->err,"icmUcrBg_read: malloc() failed");
7395 return icp->errc = 2;
7396 }
7397 bp = buf;
7398 end = buf + len;
7399
7400 /* Read portion of file into buffer */
7401 if ( icp->fp->seek(icp->fp, of) != 0
7402 || icp->fp->read(icp->fp, bp, 1, len) != len) {
7403 sprintf(icp->err,"icmUcrBg_read: fseek() or fread() failed");
7404 icp->al->free(icp->al, buf);
7405 return icp->errc = 1;
7406 }
7407
7408 /* Read type descriptor from the buffer */
7409 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7410 sprintf(icp->err,"icmUcrBg_read: Wrong tag type for icmUcrBg");
7411 icp->al->free(icp->al, buf);
7412 return icp->errc = 1;
7413 }
7414 p->UCRcount = read_UInt32Number(bp+8); /* First curve count */
7415 bp = bp + 12;
7416
7417 if (p->UCRcount > 0) {
7418 if ((rv = p->allocate((icmBase *)p)) != 0) {
7419 icp->al->free(icp->al, buf);
7420 return rv;
7421 }
7422 for (i = 0; i < p->UCRcount; i++, bp += 2) {
7423 if ((bp + 2) > end) {
7424 sprintf(icp->err,"icmUcrBg_read: Data too short to read UCR Data");
7425 icp->al->free(icp->al, buf);
7426 return icp->errc = 1;
7427 }
7428 if (p->UCRcount == 1) /* % */
7429 p->UCRcurve[i] = (double)read_UInt16Number(bp);
7430 else /* 0.0 - 1.0 */
7431 p->UCRcurve[i] = read_DCS16Number(bp);
7432 }
7433 } else {
7434 p->UCRcurve = NULL;
7435 }
7436
7437 if ((bp + 4) > end) {
7438 sprintf(icp->err,"icmData_read: Data too short to read Black Gen count");
7439 icp->al->free(icp->al, buf);
7440 return icp->errc = 1;
7441 }
7442 p->BGcount = read_UInt32Number(bp); /* First curve count */
7443 bp += 4;
7444
7445 if (p->BGcount > 0) {
7446 if ((rv = p->allocate((icmBase *)p)) != 0) {
7447 icp->al->free(icp->al, buf);
7448 return rv;
7449 }
7450 for (i = 0; i < p->BGcount; i++, bp += 2) {
7451 if ((bp + 2) > end) {
7452 sprintf(icp->err,"icmUcrBg_read: Data too short to read BG Data");
7453 icp->al->free(icp->al, buf);
7454 return icp->errc = 1;
7455 }
7456 if (p->BGcount == 1) /* % */
7457 p->BGcurve[i] = (double)read_UInt16Number(bp);
7458 else /* 0.0 - 1.0 */
7459 p->BGcurve[i] = read_DCS16Number(bp);
7460 }
7461 } else {
7462 p->BGcurve = NULL;
7463 }
7464
7465 p->size = end - bp; /* Nominal string length */
7466 if (p->size > 0) {
7467 if (check_null_string(bp, p->size) != 0) {
7468 sprintf(icp->err,"icmUcrBg_read: string is not null terminated");
7469 icp->al->free(icp->al, buf);
7470 return icp->errc = 1;
7471 }
7472 p->size = strlen(bp) + 1;
7473 if ((rv = p->allocate((icmBase *)p)) != 0) {
7474 icp->al->free(icp->al, buf);
7475 return rv;
7476 }
7477 memcpy((void *)p->string, (void *)bp, p->size);
7478 bp += p->size;
7479 } else {
7480 p->string = NULL;
7481 }
7482
7483 icp->al->free(icp->al, buf);
7484 return 0;
7485 }
7486
7487 /* Write the contents of the object. Return 0 on sucess, error code on failure */
7488 static int icmUcrBg_write(
7489 icmBase *pp,
7490 unsigned long of /* File offset to write from */
7491 ) {
7492 icmUcrBg *p = (icmUcrBg *)pp;
7493 icc *icp = p->icp;
7494 unsigned long i;
7495 unsigned int len;
7496 char *bp, *buf; /* Buffer to write from */
7497 int rv = 0;
7498
7499 /* Allocate a file write buffer */
7500 len = p->get_size((icmBase *)p);
7501 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7502 sprintf(icp->err,"icmUcrBg_write malloc() failed");
7503 return icp->errc = 2;
7504 }
7505 bp = buf;
7506
7507 /* Write type descriptor to the buffer */
7508 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7509 sprintf(icp->err,"icmUcrBg_write: write_SInt32Number() failed");
7510 icp->al->free(icp->al, buf);
7511 return icp->errc = rv;
7512 }
7513 write_SInt32Number(0,bp+4); /* Set padding to 0 */
7514 bp = bp + 8;
7515
7516 /* Write UCR curve */
7517 if ((rv = write_UInt32Number(p->UCRcount,bp)) != 0) {
7518 sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
7519 icp->al->free(icp->al, buf);
7520 return icp->errc = rv;
7521 }
7522 bp += 4;
7523
7524 for (i = 0; i < p->UCRcount; i++, bp += 2) {
7525 if (p->UCRcount == 1) { /* % */
7526 if ((rv = write_UInt16Number((unsigned int)(p->UCRcurve[i]+0.5),bp)) != 0) {
7527 sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
7528 icp->al->free(icp->al, buf);
7529 return icp->errc = rv;
7530 }
7531 } else {
7532 if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) {
7533 sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]);
7534 icp->al->free(icp->al, buf);
7535 return icp->errc = rv;
7536 }
7537 }
7538 }
7539
7540 /* Write BG curve */
7541 if ((rv = write_UInt32Number(p->BGcount,bp)) != 0) {
7542 sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
7543 icp->al->free(icp->al, buf);
7544 return icp->errc = rv;
7545 }
7546 bp += 4;
7547
7548 for (i = 0; i < p->BGcount; i++, bp += 2) {
7549 if (p->BGcount == 1) { /* % */
7550 if ((rv = write_UInt16Number((unsigned int)(p->BGcurve[i]+0.5),bp)) != 0) {
7551 sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
7552 icp->al->free(icp->al, buf);
7553 return icp->errc = rv;
7554 }
7555 } else {
7556 if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) {
7557 sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]);
7558 icp->al->free(icp->al, buf);
7559 return icp->errc = rv;
7560 }
7561 }
7562 }
7563
7564 if (p->string != NULL) {
7565 if ((rv = check_null_string(p->string,p->size)) != 0) {
7566 sprintf(icp->err,"icmUcrBg_write: text is not null terminated");
7567 icp->al->free(icp->al, buf);
7568 return icp->errc = 1;
7569 }
7570 memcpy((void *)bp, (void *)p->string, p->size);
7571 }
7572
7573 /* Write to the file */
7574 if ( icp->fp->seek(icp->fp, of) != 0
7575 || icp->fp->write(icp->fp, buf, 1, len) != len) {
7576 sprintf(icp->err,"icmUcrBg_write fseek() or fwrite() failed");
7577 icp->al->free(icp->al, buf);
7578 return icp->errc = 2;
7579 }
7580 icp->al->free(icp->al, buf);
7581 return 0;
7582 }
7583
7584 /* Dump a text description of the object */
7585 static void icmUcrBg_dump(
7586 icmBase *pp,
7587 FILE *op, /* Output to dump to */
7588 int verb /* Verbosity level */
7589 ) {
7590 icmUcrBg *p = (icmUcrBg *)pp;
7591 if (verb <= 0)
7592 return;
7593
7594 fprintf(op,"Undercolor Removal Curve & Black Generation:\n");
7595
7596 if (p->UCRcount == 0) {
7597 fprintf(op," UCR: Not specified\n");
7598 } else if (p->UCRcount == 1) {
7599 fprintf(op," UCR: %f%%\n",p->UCRcurve[0]);
7600 } else {
7601 fprintf(op," UCR curve no. elements = %u\n",p->UCRcount);
7602 if (verb >= 2) {
7603 unsigned long i;
7604 for (i = 0; i < p->UCRcount; i++)
7605 fprintf(op," %3lu: %f\n",i,p->UCRcurve[i]);
7606 }
7607 }
7608 if (p->BGcount == 0) {
7609 fprintf(op," BG: Not specified\n");
7610 } else if (p->BGcount == 1) {
7611 fprintf(op," BG: %f%%\n",p->BGcurve[0]);
7612 } else {
7613 fprintf(op," BG curve no. elements = %u\n",p->BGcount);
7614 if (verb >= 2) {
7615 unsigned long i;
7616 for (i = 0; i < p->BGcount; i++)
7617 fprintf(op," %3lu: %f\n",i,p->BGcurve[i]);
7618 }
7619 }
7620
7621 {
7622 unsigned long i, r, c, size;
7623 fprintf(op," Description:\n");
7624 fprintf(op," No. chars = %lu\n",p->size);
7625
7626 size = p->size > 0 ? p->size-1 : 0;
7627 i = 0;
7628 for (r = 1;; r++) { /* count rows */
7629 if (i >= size) {
7630 fprintf(op,"\n");
7631 break;
7632 }
7633 if (r > 1 && verb < 2) {
7634 fprintf(op,"...\n");
7635 break; /* Print 1 row if not verbose */
7636 }
7637 c = 1;
7638 fprintf(op," 0x%04lx: ",i);
7639 c += 10;
7640 while (i < size && c < 73) {
7641 if (isprint(p->string[i])) {
7642 fprintf(op,"%c",p->string[i]);
7643 c++;
7644 } else {
7645 fprintf(op,"\\%03o",p->string[i]);
7646 c += 4;
7647 }
7648 i++;
7649 }
7650 if (i < size)
7651 fprintf(op,"\n");
7652 }
7653 }
7654 }
7655
7656 /* Allocate variable sized data elements */
7657 static int icmUcrBg_allocate(
7658 icmBase *pp
7659 ) {
7660 icmUcrBg *p = (icmUcrBg *)pp;
7661 icc *icp = p->icp;
7662
7663 if (p->UCRcount != p->UCR_count) {
7664 if (p->UCRcurve != NULL)
7665 icp->al->free(icp->al, p->UCRcurve);
7666 if ((p->UCRcurve = (double *) icp->al->malloc(icp->al, p->UCRcount * sizeof(double))) == NULL) {
7667 sprintf(icp->err,"icmUcrBg_allocate: malloc() of UCR curve data failed");
7668 return icp->errc = 2;
7669 }
7670 p->UCR_count = p->UCRcount;
7671 }
7672 if (p->BGcount != p->BG_count) {
7673 if (p->BGcurve != NULL)
7674 icp->al->free(icp->al, p->BGcurve);
7675 if ((p->BGcurve = (double *) icp->al->malloc(icp->al, p->BGcount * sizeof(double))) == NULL) {
7676 sprintf(icp->err,"icmUcrBg_allocate: malloc() of BG curve data failed");
7677 return icp->errc = 2;
7678 }
7679 p->BG_count = p->BGcount;
7680 }
7681 if (p->size != p->_size) {
7682 if (p->string != NULL)
7683 icp->al->free(icp->al, p->string);
7684 if ((p->string = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
7685 sprintf(icp->err,"icmUcrBg_allocate: malloc() of string data failed");
7686 return icp->errc = 2;
7687 }
7688 p->_size = p->size;
7689 }
7690 return 0;
7691 }
7692
7693 /* Free all storage in the object */
7694 static void icmUcrBg_delete(
7695 icmBase *pp
7696 ) {
7697 icmUcrBg *p = (icmUcrBg *)pp;
7698 icc *icp = p->icp;
7699
7700 if (p->UCRcurve != NULL)
7701 icp->al->free(icp->al, p->UCRcurve);
7702 if (p->BGcurve != NULL)
7703 icp->al->free(icp->al, p->BGcurve);
7704 if (p->string != NULL)
7705 icp->al->free(icp->al, p->string);
7706 icp->al->free(icp->al, p);
7707 }
7708
7709 /* Create an empty object. Return null on error */
7710 static icmBase *new_icmUcrBg(
7711 icc *icp
7712 ) {
7713 icmUcrBg *p;
7714 if ((p = (icmUcrBg *) icp->al->calloc(icp->al,1,sizeof(icmUcrBg))) == NULL)
7715 return NULL;
7716 p->ttype = icSigUcrBgType;
7717 p->refcount = 1;
7718 p->get_size = icmUcrBg_get_size;
7719 p->read = icmUcrBg_read;
7720 p->write = icmUcrBg_write;
7721 p->dump = icmUcrBg_dump;
7722 p->allocate = icmUcrBg_allocate;
7723 p->del = icmUcrBg_delete;
7724 p->icp = icp;
7725
7726 return (icmBase *)p;
7727 }
7728
7729 /* ---------------------------------------------------------- */
7730 /* VideoCardGamma (ColorSync 2.5 specific - c/o Neil Okamoto) */
7731
7732 static unsigned int icmVideoCardGamma_get_size(
7733 icmBase *pp
7734 ) {
7735 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7736 unsigned int len = 0;
7737
7738 len += 8; /* 8 bytes for tag and padding */
7739 len += 4; /* 4 for gamma type */
7740
7741 /* compute size of remainder */
7742 if (p->tagType == icmVideoCardGammaTableType) {
7743 len += 2; /* 2 bytes for channels */
7744 len += 2; /* 2 for entry count */
7745 len += 2; /* 2 for entry size */
7746 len += ( p->u.table.channels * /* compute table size */
7747 p->u.table.entryCount *
7748 p->u.table.entrySize );
7749 }
7750 else if (p->tagType == icmVideoCardGammaFormulaType) {
7751 len += 12; /* 4 bytes each for red gamma, min, & max */
7752 len += 12; /* 4 bytes each for green gamma, min & max */
7753 len += 12; /* 4 bytes each for blue gamma, min & max */
7754 }
7755 return len;
7756 }
7757 /* read the object, return 0 on success, error code on fail */
7758 static int icmVideoCardGamma_read(
7759 icmBase *pp,
7760 unsigned long len, /* tag length */
7761 unsigned long of /* start offset within file */
7762 ) {
7763 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7764 icc *icp = p->icp;
7765 int rv, c;
7766 char *bp, *buf;
7767 unsigned char *pchar;
7768 unsigned short *pshort;
7769
7770 if (len < 18) {
7771 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7772 return icp->errc = 1;
7773 }
7774
7775 /* Allocate a file read buffer */
7776 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7777 sprintf(icp->err,"icmVideoCardGamma_read: malloc() failed");
7778 return icp->errc = 2;
7779 }
7780 bp = buf;
7781
7782 /* Read portion of file into buffer */
7783 if ( icp->fp->seek(icp->fp, of) != 0
7784 || icp->fp->read(icp->fp, bp, 1, len) != len) {
7785 sprintf(icp->err,"icmVideoCardGamma_read: fseek() or fread() failed");
7786 icp->al->free(icp->al, buf);
7787 return icp->errc = 1;
7788 }
7789
7790 /* Read type descriptor from the buffer */
7791 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7792 sprintf(icp->err,"icmVideoCardGamma_read: Wrong tag type for icmVideoCardGamma");
7793 icp->al->free(icp->al, buf);
7794 return icp->errc = 1;
7795 }
7796
7797 /* Read gamma format (eg. table or formula) from the buffer */
7798 p->tagType = read_UInt32Number(bp+8);
7799
7800 /* Read remaining gamma data based on format */
7801 switch ((int)p->tagType) {
7802 case icmVideoCardGammaTableType:
7803 p->u.table.channels = read_UInt16Number(bp+12);
7804 p->u.table.entryCount = read_UInt16Number(bp+14);
7805 p->u.table.entrySize = read_UInt16Number(bp+16);
7806 if (len-18 < p->u.table.channels*p->u.table.entryCount*p->u.table.entrySize) {
7807 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7808 return icp->errc = 1;
7809 }
7810 if ((rv = pp->allocate(pp)) != 0) { /* make space for table */
7811 icp->al->free(icp->al, buf);
7812 return icp->errc = rv;
7813 }
7814 pchar = (unsigned char*)p->u.table.data;
7815 pshort = (unsigned short*)p->u.table.data;
7816 for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
7817 switch (p->u.table.entrySize) {
7818 case 1:
7819 *pchar++ = read_UInt8Number(bp);
7820 bp++;
7821 break;
7822 case 2:
7823 *pshort++ = read_UInt16Number(bp);
7824 bp+=2;
7825 break;
7826 default:
7827 sprintf(icp->err,"icmVideoCardGamma_read: unsupported table entry size");
7828 pp->del(pp);
7829 icp->al->free(icp->al, buf);
7830 return icp->errc = 1;
7831 }
7832 }
7833 break;
7834 case icmVideoCardGammaFormulaType:
7835 if (len < 48) {
7836 sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7837 return icp->errc = 1;
7838 }
7839 p->u.formula.redGamma = read_S15Fixed16Number(bp+12);
7840 p->u.formula.redMin = read_S15Fixed16Number(bp+16);
7841 p->u.formula.redMax = read_S15Fixed16Number(bp+20);
7842 p->u.formula.greenGamma = read_S15Fixed16Number(bp+24);
7843 p->u.formula.greenMin = read_S15Fixed16Number(bp+28);
7844 p->u.formula.greenMax = read_S15Fixed16Number(bp+32);
7845 p->u.formula.blueGamma = read_S15Fixed16Number(bp+36);
7846 p->u.formula.blueMin = read_S15Fixed16Number(bp+40);
7847 p->u.formula.blueMax = read_S15Fixed16Number(bp+44);
7848 break;
7849 default:
7850 sprintf(icp->err,"icmVideoCardGammaTable_read: Unknown gamma format for icmVideoCardGamma");
7851 icp->al->free(icp->al, buf);
7852 return icp->errc = 1;
7853 }
7854
7855 icp->al->free(icp->al, buf);
7856 return 0;
7857 }
7858
7859 /* Write the contents of the object. Return 0 on sucess, error code on failure */
7860 static int icmVideoCardGamma_write(
7861 icmBase *pp,
7862 unsigned long of /* File offset to write from */
7863 ) {
7864 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7865 icc *icp = p->icp;
7866 unsigned int len;
7867 char *bp, *buf; /* Buffer to write from */
7868 int rv = 0, c;
7869 unsigned char *pchar;
7870 unsigned short *pshort;
7871
7872 /* Allocate a file write buffer */
7873 len = p->get_size((icmBase *)p);
7874 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7875 sprintf(icp->err,"icmViewingConditions_write malloc() failed");
7876 return icp->errc = 2;
7877 }
7878 bp = buf;
7879
7880 /* Write type descriptor to the buffer */
7881 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7882 sprintf(icp->err,"icmVideoCardGamma_write: write_SInt32Number() failed");
7883 icp->al->free(icp->al, buf);
7884 return icp->errc = rv;
7885 }
7886 write_SInt32Number(0,bp+4); /* Set padding to 0 */
7887
7888 /* Write gamma format (eg. table of formula) */
7889 if ((rv = write_UInt32Number(p->tagType,bp+8)) != 0) {
7890 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt32Number() failed");
7891 icp->al->free(icp->al, buf);
7892 return icp->errc = rv;
7893 }
7894
7895 /* Write remaining gamma data based on format */
7896 switch ((int)p->tagType) {
7897 case icmVideoCardGammaTableType:
7898 if ((rv = write_UInt16Number(p->u.table.channels,bp+12)) != 0) {
7899 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7900 icp->al->free(icp->al, buf);
7901 return icp->errc = rv;
7902 }
7903 if ((rv = write_UInt16Number(p->u.table.entryCount,bp+14)) != 0) {
7904 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7905 icp->al->free(icp->al, buf);
7906 return icp->errc = rv;
7907 }
7908 if ((rv = write_UInt16Number(p->u.table.entrySize,bp+16)) != 0) {
7909 sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7910 icp->al->free(icp->al, buf);
7911 return icp->errc = rv;
7912 }
7913 pchar = (unsigned char*)p->u.table.data;
7914 pshort = (unsigned short*)p->u.table.data;
7915 for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
7916 switch (p->u.table.entrySize) {
7917 case 1:
7918 write_UInt8Number(*pchar++,bp);
7919 bp++;
7920 break;
7921 case 2:
7922 write_UInt16Number(*pshort++,bp);
7923 bp+=2;
7924 break;
7925 default:
7926 sprintf(icp->err,"icmVideoCardGamma_write: unsupported table entry size");
7927 icp->al->free(icp->al, buf);
7928 return icp->errc = 1;
7929 }
7930 }
7931 break;
7932 case icmVideoCardGammaFormulaType:
7933 if ((rv = write_S15Fixed16Number(p->u.formula.redGamma,bp+12)) != 0) {
7934 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7935 icp->al->free(icp->al, buf);
7936 return icp->errc = rv;
7937 }
7938 if ((rv = write_S15Fixed16Number(p->u.formula.redMin,bp+16)) != 0) {
7939 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7940 icp->al->free(icp->al, buf);
7941 return icp->errc = rv;
7942 }
7943 if ((rv = write_S15Fixed16Number(p->u.formula.redMax,bp+20)) != 0) {
7944 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7945 icp->al->free(icp->al, buf);
7946 return icp->errc = rv;
7947 }
7948 if ((rv = write_S15Fixed16Number(p->u.formula.greenGamma,bp+24)) != 0) {
7949 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7950 icp->al->free(icp->al, buf);
7951 return icp->errc = rv;
7952 }
7953 if ((rv = write_S15Fixed16Number(p->u.formula.greenMin,bp+28)) != 0) {
7954 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7955 icp->al->free(icp->al, buf);
7956 return icp->errc = rv;
7957 }
7958 if ((rv = write_S15Fixed16Number(p->u.formula.greenMax,bp+32)) != 0) {
7959 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7960 icp->al->free(icp->al, buf);
7961 return icp->errc = rv;
7962 }
7963 if ((rv = write_S15Fixed16Number(p->u.formula.blueGamma,bp+36)) != 0) {
7964 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7965 icp->al->free(icp->al, buf);
7966 return icp->errc = rv;
7967 }
7968 if ((rv = write_S15Fixed16Number(p->u.formula.blueMin,bp+40)) != 0) {
7969 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7970 icp->al->free(icp->al, buf);
7971 return icp->errc = rv;
7972 }
7973 if ((rv = write_S15Fixed16Number(p->u.formula.blueMax,bp+44)) != 0) {
7974 sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7975 icp->al->free(icp->al, buf);
7976 return icp->errc = rv;
7977 }
7978 break;
7979 default:
7980 sprintf(icp->err,"icmVideoCardGammaTable_write: Unknown gamma format for icmVideoCardGamma");
7981 icp->al->free(icp->al, buf);
7982 return icp->errc = 1;
7983 }
7984
7985 /* Write to the file */
7986 if ( icp->fp->seek(icp->fp, of) != 0
7987 || icp->fp->write(icp->fp, buf, 1, len) != len) {
7988 sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
7989 icp->al->free(icp->al, buf);
7990 return icp->errc = 2;
7991 }
7992 icp->al->free(icp->al, buf);
7993 return 0;
7994 }
7995
7996 /* Dump a text description of the object */
7997 static void icmVideoCardGamma_dump(
7998 icmBase *pp,
7999 FILE *op, /* Output to dump to */
8000 int verb /* Verbosity level */
8001 ) {
8002 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8003 int c,i;
8004
8005 if (verb <= 0)
8006 return;
8007
8008 switch ((int)p->tagType) {
8009 case icmVideoCardGammaTableType:
8010 fprintf(op,"VideoCardGammaTable:\n");
8011 fprintf(op," channels = %d\n", p->u.table.channels);
8012 fprintf(op," entries = %d\n", p->u.table.entryCount);
8013 fprintf(op," entrysize = %d\n", p->u.table.entrySize);
8014 if (verb >= 2) {
8015 /* dump array contents also */
8016 for (c=0; c<p->u.table.channels; c++) {
8017 fprintf(op," channel #%d\n",c);
8018 for (i=0; i<p->u.table.entryCount; i++) {
8019 if (p->u.table.entrySize == 1) {
8020 fprintf(op," %d: %d\n",i,((unsigned char*)p->u.table.data)[c*p->u.table.entryCount+i]);
8021 }
8022 else if (p->u.table.entrySize == 2) {
8023 fprintf(op," %d: %d\n",i,((unsigned short*)p->u.table.data)[c*p->u.table.entryCount+i]);
8024 }
8025 }
8026 }
8027 }
8028 break;
8029 case icmVideoCardGammaFormulaType:
8030 fprintf(op,"VideoCardGammaFormula:\n");
8031 fprintf(op," red gamma = %f\n", p->u.formula.redGamma);
8032 fprintf(op," red min = %f\n", p->u.formula.redMin);
8033 fprintf(op," red max = %f\n", p->u.formula.redMax);
8034 fprintf(op," green gamma = %f\n", p->u.formula.greenGamma);
8035 fprintf(op," green min = %f\n", p->u.formula.greenMin);
8036 fprintf(op," green max = %f\n", p->u.formula.greenMax);
8037 fprintf(op," blue gamma = %f\n", p->u.formula.blueGamma);
8038 fprintf(op," blue min = %f\n", p->u.formula.blueMin);
8039 fprintf(op," blue max = %f\n", p->u.formula.blueMax);
8040 break;
8041 default:
8042 fprintf(op," Unknown tag format\n");
8043 }
8044 }
8045
8046 /* Allocate variable sized data elements */
8047 static int icmVideoCardGamma_allocate(
8048 icmBase *pp
8049 ) {
8050 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8051 icc *icp = p->icp;
8052 int size;
8053
8054 /* note: allocation is only relevant for table type
8055 * and in that case the channels, entryCount, and entrySize
8056 * fields must all be set prior to getting here
8057 */
8058
8059 if (p->tagType == icmVideoCardGammaTableType) {
8060 if (p->u.table.data != NULL)
8061 icp->al->free(icp->al, p->u.table.data);
8062 size = (p->u.table.channels *
8063 p->u.table.entryCount);
8064 switch (p->u.table.entrySize) {
8065 case 1:
8066 size *= sizeof(unsigned char);
8067 break;
8068 case 2:
8069 size *= sizeof(unsigned short);
8070 break;
8071 default:
8072 sprintf(icp->err,"icmVideoCardGamma_alloc: unsupported table entry size");
8073 return icp->errc = 1;
8074 }
8075 if ((p->u.table.data = (void*) icp->al->malloc(icp->al, size)) == NULL) {
8076 sprintf(icp->err,"icmVideoCardGamma_alloc: malloc() of table data failed");
8077 return icp->errc = 2;
8078 }
8079 }
8080
8081 return 0;
8082 }
8083
8084 /* Free all storage in the object */
8085 static void icmVideoCardGamma_delete(
8086 icmBase *pp
8087 ) {
8088 icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8089 icc *icp = p->icp;
8090
8091 if (p->tagType == icmVideoCardGammaTableType && p->u.table.data != NULL)
8092 icp->al->free(icp->al, p->u.table.data);
8093
8094 icp->al->free(icp->al, p);
8095 }
8096
8097 /* Create an empty object. Return null on error */
8098 static icmBase *new_icmVideoCardGamma(
8099 icc *icp
8100 ) {
8101 icmVideoCardGamma *p;
8102 if ((p = (icmVideoCardGamma *) icp->al->calloc(icp->al,1,sizeof(icmVideoCardGamma))) == NULL)
8103 return NULL;
8104 p->ttype = icSigVideoCardGammaType;
8105 p->refcount = 1;
8106 p->get_size = icmVideoCardGamma_get_size;
8107 p->read = icmVideoCardGamma_read;
8108 p->write = icmVideoCardGamma_write;
8109 p->dump = icmVideoCardGamma_dump;
8110 p->allocate = icmVideoCardGamma_allocate;
8111 p->del = icmVideoCardGamma_delete;
8112 p->icp = icp;
8113
8114 return (icmBase *)p;
8115 }
8116
8117 /* ---------------------------------------------------------- */
8118 /* ViewingConditions */
8119
8120 /* Return the number of bytes needed to write this tag */
8121 static unsigned int icmViewingConditions_get_size(
8122 icmBase *pp
8123 ) {
8124 unsigned int len = 0;
8125 len += 8; /* 8 bytes for tag and padding */
8126 len += 12; /* 12 for XYZ of illuminant */
8127 len += 12; /* 12 for XYZ of surround */
8128 len += 4; /* 4 for illuminant type */
8129 return len;
8130 }
8131
8132 /* read the object, return 0 on success, error code on fail */
8133 static int icmViewingConditions_read(
8134 icmBase *pp,
8135 unsigned long len, /* tag length */
8136 unsigned long of /* start offset within file */
8137 ) {
8138 icmViewingConditions *p = (icmViewingConditions *)pp;
8139 icc *icp = p->icp;
8140 int rv;
8141 char *bp, *buf;
8142
8143 if (len < 36) {
8144 sprintf(icp->err,"icmViewingConditions_read: Tag too small to be legal");
8145 return icp->errc = 1;
8146 }
8147
8148 /* Allocate a file read buffer */
8149 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8150 sprintf(icp->err,"icmViewingConditions_read: malloc() failed");
8151 return icp->errc = 2;
8152 }
8153 bp = buf;
8154
8155 /* Read portion of file into buffer */
8156 if ( icp->fp->seek(icp->fp, of) != 0
8157 || icp->fp->read(icp->fp, bp, 1, len) != len) {
8158 sprintf(icp->err,"icmViewingConditions_read: fseek() or fread() failed");
8159 icp->al->free(icp->al, buf);
8160 return icp->errc = 1;
8161 }
8162
8163 /* Read type descriptor from the buffer */
8164 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
8165 sprintf(icp->err,"icmViewingConditions_read: Wrong tag type for icmViewingConditions");
8166 icp->al->free(icp->al, buf);
8167 return icp->errc = 1;
8168 }
8169
8170 /* Read the XYZ values for the illuminant */
8171 if ((rv = read_XYZNumber(&p->illuminant, bp+8)) != 0) {
8172 sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
8173 icp->al->free(icp->al, buf);
8174 return icp->errc = rv;
8175 }
8176
8177 /* Read the XYZ values for the surround */
8178 if ((rv = read_XYZNumber(&p->surround, bp+20)) != 0) {
8179 sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
8180 icp->al->free(icp->al, buf);
8181 return icp->errc = rv;
8182 }
8183
8184 /* Read the encoded standard illuminant */
8185 p->stdIlluminant = (icIlluminant)read_SInt32Number(bp + 32);
8186
8187 icp->al->free(icp->al, buf);
8188 return 0;
8189 }
8190
8191 /* Write the contents of the object. Return 0 on sucess, error code on failure */
8192 static int icmViewingConditions_write(
8193 icmBase *pp,
8194 unsigned long of /* File offset to write from */
8195 ) {
8196 icmViewingConditions *p = (icmViewingConditions *)pp;
8197 icc *icp = p->icp;
8198 unsigned int len;
8199 char *bp, *buf; /* Buffer to write from */
8200 int rv = 0;
8201
8202 /* Allocate a file write buffer */
8203 len = p->get_size((icmBase *)p);
8204 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8205 sprintf(icp->err,"icmViewingConditions_write malloc() failed");
8206 return icp->errc = 2;
8207 }
8208 bp = buf;
8209
8210 /* Write type descriptor to the buffer */
8211 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
8212 sprintf(icp->err,"icmViewingConditions_write: write_SInt32Number() failed");
8213 icp->al->free(icp->al, buf);
8214 return icp->errc = rv;
8215 }
8216 write_SInt32Number(0,bp+4); /* Set padding to 0 */
8217
8218 /* Write the XYZ values for the illuminant */
8219 if ((rv = write_XYZNumber(&p->illuminant, bp+8)) != 0) {
8220 sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
8221 icp->al->free(icp->al, buf);
8222 return icp->errc = rv;
8223 }
8224
8225 /* Write the XYZ values for the surround */
8226 if ((rv = write_XYZNumber(&p->surround, bp+20)) != 0) {
8227 sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
8228 icp->al->free(icp->al, buf);
8229 return icp->errc = rv;
8230 }
8231
8232 /* Write the encoded standard illuminant */
8233 if ((rv = write_SInt32Number((int)p->stdIlluminant, bp + 32)) != 0) {
8234 sprintf(icp->err,"icmViewingConditionsa_write: write_SInt32Number() failed");
8235 icp->al->free(icp->al, buf);
8236 return icp->errc = rv;
8237 }
8238
8239 /* Write to the file */
8240 if ( icp->fp->seek(icp->fp, of) != 0
8241 || icp->fp->write(icp->fp, buf, 1, len) != len) {
8242 sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
8243 icp->al->free(icp->al, buf);
8244 return icp->errc = 2;
8245 }
8246 icp->al->free(icp->al, buf);
8247 return 0;
8248 }
8249
8250 /* Dump a text description of the object */
8251 static void icmViewingConditions_dump(
8252 icmBase *pp,
8253 FILE *op, /* Output to dump to */
8254 int verb /* Verbosity level */
8255 ) {
8256 icmViewingConditions *p = (icmViewingConditions *)pp;
8257 if (verb <= 0)
8258 return;
8259
8260 fprintf(op,"Viewing Conditions:\n");
8261 fprintf(op," XYZ value of illuminant in cd/m^2 = %s\n", string_XYZNumber(&p->illuminant));
8262 fprintf(op," XYZ value of surround in cd/m^2 = %s\n", string_XYZNumber(&p->surround));
8263 fprintf(op," Illuminant type = %s\n", string_Illuminant(p->stdIlluminant));
8264 }
8265
8266 /* Allocate variable sized data elements */
8267 static int icmViewingConditions_allocate(
8268 icmBase *pp
8269 ) {
8270 /* Nothing to do */
8271 return 0;
8272 }
8273
8274 /* Free all storage in the object */
8275 static void icmViewingConditions_delete(
8276 icmBase *pp
8277 ) {
8278 icmViewingConditions *p = (icmViewingConditions *)pp;
8279 icc *icp = p->icp;
8280
8281 icp->al->free(icp->al, p);
8282 }
8283
8284 /* Create an empty object. Return null on error */
8285 static icmBase *new_icmViewingConditions(
8286 icc *icp
8287 ) {
8288 icmViewingConditions *p;
8289 if ((p = (icmViewingConditions *) icp->al->calloc(icp->al,1,sizeof(icmViewingConditions))) == NULL)
8290 return NULL;
8291 p->ttype = icSigViewingConditionsType;
8292 p->refcount = 1;
8293 p->get_size = icmViewingConditions_get_size;
8294 p->read = icmViewingConditions_read;
8295 p->write = icmViewingConditions_write;
8296 p->dump = icmViewingConditions_dump;
8297 p->allocate = icmViewingConditions_allocate;
8298 p->del = icmViewingConditions_delete;
8299 p->icp = icp;
8300
8301 return (icmBase *)p;
8302 }
8303
8304 /* ---------------------------------------------------------- */
8305 /* icmCrdInfo object */
8306
8307 /* Return the number of bytes needed to write this tag */
8308 static unsigned int icmCrdInfo_get_size(
8309 icmBase *pp
8310 ) {
8311 icmCrdInfo *p = (icmCrdInfo *)pp;
8312 unsigned int len = 0, t;
8313 len += 8; /* 8 bytes for tag and padding */
8314 len += 4 + p->ppsize; /* Postscript product name */
8315 for (t = 0; t < 4; t++) { /* For all 4 intents */
8316 len += 4 + p->crdsize[t]; /* crd names */
8317 }
8318 return len;
8319 }
8320
8321 /* read the object, return 0 on success, error code on fail */
8322 static int icmCrdInfo_read(
8323 icmBase *pp,
8324 unsigned long len, /* tag length */
8325 unsigned long of /* start offset within file */
8326 ) {
8327 icmCrdInfo *p = (icmCrdInfo *)pp;
8328 icc *icp = p->icp;
8329 unsigned long t;
8330 int rv = 0;
8331 char *bp, *buf, *end;
8332
8333 if (len < 28) {
8334 sprintf(icp->err,"icmCrdInfo_read: Tag too small to be legal");
8335 return icp->errc = 1;
8336 }
8337
8338 /* Allocate a file read buffer */
8339 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8340 sprintf(icp->err,"icmCrdInfo_read: malloc() failed");
8341 return icp->errc = 2;
8342 }
8343 bp = buf;
8344 end = buf + len;
8345
8346 /* Read portion of file into buffer */
8347 if ( icp->fp->seek(icp->fp, of) != 0
8348 || icp->fp->read(icp->fp, bp, 1, len) != len) {
8349 sprintf(icp->err,"icmCrdInfo_read: fseek() or fread() failed");
8350 icp->al->free(icp->al, buf);
8351 return icp->errc = 1;
8352 }
8353
8354 /* Read type descriptor from the buffer */
8355 if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
8356 sprintf(icp->err,"icmCrdInfo_read: Wrong tag type for icmCrdInfo");
8357 icp->al->free(icp->al, buf);
8358 return icp->errc = 1;
8359 }
8360 bp = bp + 8;
8361
8362 /* Postscript product name */
8363 if ((bp + 4) > end) {
8364 sprintf(icp->err,"icmCrdInfo_read: Data too short to read Postscript product name");
8365 icp->al->free(icp->al, buf);
8366 return icp->errc = 1;
8367 }
8368 p->ppsize = read_UInt32Number(bp);
8369 bp += 4;
8370 if (p->ppsize > 0) {
8371 if ((bp + p->ppsize) > end) {
8372 sprintf(icp->err,"icmCrdInfo_read: Data to short to read Postscript product string");
8373 icp->al->free(icp->al, buf);
8374 return icp->errc = 1;
8375 }
8376 if (check_null_string(bp,p->ppsize)) {
8377 sprintf(icp->err,"icmCrdInfo_read: Postscript product name is not terminated");
8378 icp->al->free(icp->al, buf);
8379 return icp->errc = 1;
8380 }
8381 if ((rv = p->allocate((icmBase *)p)) != 0) {
8382 icp->al->free(icp->al, buf);
8383 return rv;
8384 }
8385 memcpy((void *)p->ppname, (void *)bp, p->ppsize);
8386 bp += p->ppsize;
8387 }
8388
8389 /* CRD names for the four rendering intents */
8390 for (t = 0; t < 4; t++) { /* For all 4 intents */
8391 if ((bp + 4) > end) {
8392 sprintf(icp->err,"icmCrdInfo_read: Data too short to read CRD%ld name",t);
8393 icp->al->free(icp->al, buf);
8394 return icp->errc = 1;
8395 }
8396 p->crdsize[t] = read_UInt32Number(bp);
8397 bp += 4;
8398 if (p->crdsize[t] > 0) {
8399 if ((bp + p->crdsize[t]) > end) {
8400 sprintf(icp->err,"icmCrdInfo_read: Data to short to read CRD%ld string",t);
8401 icp->al->free(icp->al, buf);
8402 return icp->errc = 1;
8403 }
8404 if (check_null_string(bp,p->crdsize[t])) {
8405 sprintf(icp->err,"icmCrdInfo_read: CRD%ld name is not terminated",t);
8406 icp->al->free(icp->al, buf);
8407 return icp->errc = 1;
8408 }
8409 if ((rv = p->allocate((icmBase *)p)) != 0) {
8410 icp->al->free(icp->al, buf);
8411 return rv;
8412 }
8413 memcpy((void *)p->crdname[t], (void *)bp, p->crdsize[t]);
8414 bp += p->crdsize[t];
8415 }
8416 }
8417
8418 icp->al->free(icp->al, buf);
8419 return 0;
8420 }
8421
8422 /* Write the contents of the object. Return 0 on sucess, error code on failure */
8423 static int icmCrdInfo_write(
8424 icmBase *pp,
8425 unsigned long of /* File offset to write from */
8426 ) {
8427 icmCrdInfo *p = (icmCrdInfo *)pp;
8428 icc *icp = p->icp;
8429 unsigned long t;
8430 unsigned int len;
8431 char *bp, *buf; /* Buffer to write from */
8432 int rv = 0;
8433
8434 /* Allocate a file write buffer */
8435 len = p->get_size((icmBase *)p);
8436 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8437 sprintf(icp->err,"icmCrdInfo_write malloc() failed");
8438 return icp->errc = 2;
8439 }
8440 bp = buf;
8441
8442 /* Write type descriptor to the buffer */
8443 if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
8444 sprintf(icp->err,"icmCrdInfo_write: write_SInt32Number() failed");
8445 icp->al->free(icp->al, buf);
8446 return icp->errc = rv;
8447 }
8448 write_SInt32Number(0,bp+4); /* Set padding to 0 */
8449 bp = bp + 8;
8450
8451 /* Postscript product name */
8452 if ((rv = write_UInt32Number(p->ppsize,bp)) != 0) {
8453 sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
8454 icp->al->free(icp->al, buf);
8455 return icp->errc = rv;
8456 }
8457 bp += 4;
8458 if (p->ppsize > 0) {
8459 if ((rv = check_null_string(p->ppname,p->ppsize)) != 0) {
8460 sprintf(icp->err,"icmCrdInfo_write: Postscript product name is not terminated");
8461 icp->al->free(icp->al, buf);
8462 return icp->errc = 1;
8463 }
8464 memcpy((void *)bp, (void *)p->ppname, p->ppsize);
8465 bp += p->ppsize;
8466 }
8467
8468 /* CRD names for the four rendering intents */
8469 for (t = 0; t < 4; t++) { /* For all 4 intents */
8470 if ((rv = write_UInt32Number(p->crdsize[t],bp)) != 0) {
8471 sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
8472 icp->al->free(icp->al, buf);
8473 return icp->errc = rv;
8474 }
8475 bp += 4;
8476 if (p->ppsize > 0) {
8477 if ((rv = check_null_string(p->crdname[t],p->crdsize[t])) != 0) {
8478 sprintf(icp->err,"icmCrdInfo_write: CRD%ld name is not terminated",t);
8479 icp->al->free(icp->al, buf);
8480 return icp->errc = 1;
8481 }
8482 memcpy((void *)bp, (void *)p->crdname[t], p->crdsize[t]);
8483 bp += p->crdsize[t];
8484 }
8485 }
8486
8487 /* Write to the file */
8488 if ( icp->fp->seek(icp->fp, of) != 0
8489 || icp->fp->write(icp->fp, buf, 1, len) != len) {
8490 sprintf(icp->err,"icmCrdInfo_write fseek() or fwrite() failed");
8491 icp->al->free(icp->al, buf);
8492 return icp->errc = 2;
8493 }
8494 icp->al->free(icp->al, buf);
8495 return 0;
8496 }
8497
8498 /* Dump a text description of the object */
8499 static void icmCrdInfo_dump(
8500 icmBase *pp,
8501 FILE *op, /* Output to dump to */
8502 int verb /* Verbosity level */
8503 ) {
8504 icmCrdInfo *p = (icmCrdInfo *)pp;
8505 unsigned long i, r, c, size, t;
8506
8507 if (verb <= 0)
8508 return;
8509
8510 fprintf(op,"PostScript Product name and CRD names:\n");
8511
8512 fprintf(op," Product name:\n");
8513 fprintf(op," No. chars = %lu\n",p->ppsize);
8514
8515 size = p->ppsize > 0 ? p->ppsize-1 : 0;
8516 i = 0;
8517 for (r = 1;; r++) { /* count rows */
8518 if (i >= size) {
8519 fprintf(op,"\n");
8520 break;
8521 }
8522 if (r > 1 && verb < 2) {
8523 fprintf(op,"...\n");
8524 break; /* Print 1 row if not verbose */
8525 }
8526 c = 1;
8527 fprintf(op," 0x%04lx: ",i);
8528 c += 10;
8529 while (i < size && c < 73) {
8530 if (isprint(p->ppname[i])) {
8531 fprintf(op,"%c",p->ppname[i]);
8532 c++;
8533 } else {
8534 fprintf(op,"\\%03o",p->ppname[i]);
8535 c += 4;
8536 }
8537 i++;
8538 }
8539 if (i < size)
8540 fprintf(op,"\n");
8541 }
8542
8543 for (t = 0; t < 4; t++) { /* For all 4 intents */
8544 fprintf(op," CRD%ld name:\n",t);
8545 fprintf(op," No. chars = %lu\n",p->crdsize[t]);
8546
8547 size = p->crdsize[t] > 0 ? p->crdsize[t]-1 : 0;
8548 i = 0;
8549 for (r = 1;; r++) { /* count rows */
8550 if (i >= size) {
8551 fprintf(op,"\n");
8552 break;
8553 }
8554 if (r > 1 && verb < 2) {
8555 fprintf(op,"...\n");
8556 break; /* Print 1 row if not verbose */
8557 }
8558 c = 1;
8559 fprintf(op," 0x%04lx: ",i);
8560 c += 10;
8561 while (i < size && c < 73) {
8562 if (isprint(p->crdname[t][i])) {
8563 fprintf(op,"%c",p->crdname[t][i]);
8564 c++;
8565 } else {
8566 fprintf(op,"\\%03o",p->crdname[t][i]);
8567 c += 4;
8568 }
8569 i++;
8570 }
8571 if (i < size)
8572 fprintf(op,"\n");
8573 }
8574 }
8575 }
8576
8577 /* Allocate variable sized data elements */
8578 static int icmCrdInfo_allocate(
8579 icmBase *pp
8580 ) {
8581 icmCrdInfo *p = (icmCrdInfo *)pp;
8582 icc *icp = p->icp;
8583 unsigned int t;
8584
8585 if (p->ppsize != p->_ppsize) {
8586 if (p->ppname != NULL)
8587 icp->al->free(icp->al, p->ppname);
8588 if ((p->ppname = (char *) icp->al->malloc(icp->al, p->ppsize * sizeof(char))) == NULL) {
8589 sprintf(icp->err,"icmCrdInfo_alloc: malloc() of string data failed");
8590 return icp->errc = 2;
8591 }
8592 p->_ppsize = p->ppsize;
8593 }
8594 for (t = 0; t < 4; t++) { /* For all 4 intents */
8595 if (p->crdsize[t] != p->_crdsize[t]) {
8596 if (p->crdname[t] != NULL)
8597 icp->al->free(icp->al, p->crdname[t]);
8598 if ((p->crdname[t] = (char *) icp->al->malloc(icp->al, p->crdsize[t] * sizeof(char))) == NULL) {
8599 sprintf(icp->err,"icmCrdInfo_alloc: malloc() of CRD%d name string failed",t);
8600 return icp->errc = 2;
8601 }
8602 p->_crdsize[t] = p->crdsize[t];
8603 }
8604 }
8605 return 0;
8606 }
8607
8608 /* Free all storage in the object */
8609 static void icmCrdInfo_delete(
8610 icmBase *pp
8611 ) {
8612 icmCrdInfo *p = (icmCrdInfo *)pp;
8613 icc *icp = p->icp;
8614 unsigned int t;
8615
8616 if (p->ppname != NULL)
8617 icp->al->free(icp->al, p->ppname);
8618 for (t = 0; t < 4; t++) { /* For all 4 intents */
8619 if (p->crdname[t] != NULL)
8620 icp->al->free(icp->al, p->crdname[t]);
8621 }
8622 icp->al->free(icp->al, p);
8623 }
8624
8625 /* Create an empty object. Return null on error */
8626 static icmBase *new_icmCrdInfo(
8627 icc *icp
8628 ) {
8629 icmCrdInfo *p;
8630 if ((p = (icmCrdInfo *) icp->al->calloc(icp->al,1,sizeof(icmCrdInfo))) == NULL)
8631 return NULL;
8632 p->ttype = icSigCrdInfoType;
8633 p->refcount = 1;
8634 p->get_size = icmCrdInfo_get_size;
8635 p->read = icmCrdInfo_read;
8636 p->write = icmCrdInfo_write;
8637 p->dump = icmCrdInfo_dump;
8638 p->allocate = icmCrdInfo_allocate;
8639 p->del = icmCrdInfo_delete;
8640 p->icp = icp;
8641
8642 return (icmBase *)p;
8643 }
8644
8645 /* ========================================================== */
8646 /* icmHeader object */
8647 /* ========================================================== */
8648
8649 /* Return the number of bytes needed to write this tag */
8650 static unsigned int icmHeader_get_size(
8651 icmHeader *p
8652 ) {
8653 return 128; /* By definition */
8654 }
8655
8656 /* read the object, return 0 on success, error code on fail */
8657 static int icmHeader_read(
8658 icmHeader *p,
8659 unsigned long len, /* tag length */
8660 unsigned long of /* start offset within file */
8661 ) {
8662 icc *icp = p->icp;
8663 char *buf;
8664 unsigned int tt;
8665 int rv = 0;
8666
8667 if (len != 128) {
8668 sprintf(icp->err,"icmHeader_read: Length expected to be 128");
8669 return icp->errc = 1;
8670 }
8671
8672 if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8673 sprintf(icp->err,"icmHeader_read: malloc() failed");
8674 return icp->errc = 2;
8675 }
8676 if ( icp->fp->seek(icp->fp, of) != 0
8677 || icp->fp->read(icp->fp, buf, 1, len) != len) {
8678 sprintf(icp->err,"icmHeader_read: fseek() or fread() failed");
8679 icp->al->free(icp->al, buf);
8680 return icp->errc = 1;
8681 }
8682
8683 /* Fill in the in-memory structure */
8684 p->size = read_UInt32Number(buf + 0); /* Profile size in bytes */
8685 p->cmmId = read_SInt32Number(buf + 4); /* CMM for profile */
8686 tt = read_UInt8Number(buf + 8); /* Raw major version number */
8687 p->majv = (tt >> 4) * 10 + (tt & 0xf); /* Integer major version number */
8688 tt = read_UInt8Number(buf + 9); /* Raw minor/bug fix version numbers */
8689 p->minv = (tt >> 4); /* Integer minor version number */
8690 p->bfv = (tt & 0xf); /* Integer bug fix version number */
8691 p->deviceClass = (icProfileClassSignature)
8692 read_SInt32Number(buf + 12); /* Type of profile */
8693 p->colorSpace = (icColorSpaceSignature)
8694 read_SInt32Number(buf + 16); /* Color space of data */
8695 p->pcs = (icColorSpaceSignature)
8696 read_SInt32Number(buf + 20); /* PCS: XYZ or Lab */
8697 if ((rv = read_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
8698 sprintf(icp->err,"icmHeader_read: read_DateTimeNumber corrupted");
8699 icp->al->free(icp->al, buf);
8700 return icp->errc = rv;
8701 }
8702 tt = read_SInt32Number(buf+36);
8703 if (tt != icMagicNumber) { /* Check magic number */
8704 sprintf(icp->err,"icmHeader_read: wrong magic number 0x%x",tt);
8705 icp->al->free(icp->al, buf);
8706 return icp->errc = 1;
8707 }
8708 p->platform = (icPlatformSignature)
8709 read_SInt32Number(buf + 40); /* Primary platform */
8710 p->flags = read_UInt32Number(buf + 44); /* Various bits */
8711 p->manufacturer = read_SInt32Number(buf + 48); /* Dev manufacturer */
8712 p->model = read_SInt32Number(buf + 52); /* Dev model */
8713 read_UInt64Number(&p->attributes, buf + 56); /* Device attributes */
8714 p->renderingIntent = (icRenderingIntent)
8715 read_SInt32Number(buf + 64); /* Rendering intent */
8716 if ((rv = read_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
8717 sprintf(icp->err,"icmHeader_read: read_XYZNumber error");
8718 icp->al->free(icp->al, buf);
8719 return icp->errc = rv;
8720 }
8721 p->creator = read_SInt32Number(buf + 80); /* Profile creator */
8722
8723 icp->al->free(icp->al, buf);
8724 return 0;
8725 }
8726
8727 /* Write the contents of the object. Return 0 on sucess, error code on failure */
8728 static int icmHeader_write(
8729 icmHeader *p,
8730 unsigned long of /* File offset to write from */
8731 ) {
8732 icc *icp = p->icp;
8733 char *buf; /* Buffer to write from */
8734 unsigned int len;
8735 unsigned int tt;
8736 int rv = 0;
8737
8738 len = p->get_size(p);
8739 if ((buf = (char *) icp->al->calloc(icp->al,1,len)) == NULL) { /* Zero it - some CMS are fussy */
8740 sprintf(icp->err,"icmHeader_write calloc() failed");
8741 return icp->errc = 2;
8742 }
8743
8744 /* Fill in the write buffer */
8745 if ((rv = write_UInt32Number(p->size, buf + 0)) != 0) { /* Profile size in bytes */
8746 sprintf(icp->err,"icmHeader_write: profile size");
8747 icp->al->free(icp->al, buf);
8748 return icp->errc = rv;
8749 }
8750
8751 if ((rv = write_SInt32Number(p->cmmId, buf + 4)) != 0) { /* CMM for profile */
8752 sprintf(icp->err,"icmHeader_write: cmmId");
8753 icp->al->free(icp->al, buf);
8754 return icp->errc = rv;
8755 }
8756 if (p->majv < 0 || p->majv > 99 /* Sanity check version numbers */
8757 || p->minv < 0 || p->minv > 9
8758 || p->bfv < 0 || p->bfv > 9) {
8759 sprintf(icp->err,"icmHeader_write: version number");
8760 icp->al->free(icp->al, buf);
8761 return icp->errc = 1;
8762 }
8763 tt = ((p->majv/10) << 4) + (p->majv % 10);
8764 if ((rv = write_UInt8Number(tt, buf + 8)) != 0) { /* Raw major version number */
8765 sprintf(icp->err,"icmHeader_write: Uint8Number major version");
8766 icp->al->free(icp->al, buf);
8767 return icp->errc = rv;
8768 }
8769 tt = (p->minv << 4) + p->bfv;
8770 if ((rv = write_UInt8Number(tt, buf + 9)) != 0) { /* Raw minor/bug fix version numbers */
8771 sprintf(icp->err,"icmHeader_write: Uint8Number minor/bug fix");
8772 icp->al->free(icp->al, buf);
8773 return icp->errc = rv;
8774 }
8775 if ((rv = write_SInt32Number((int)p->deviceClass, buf + 12)) != 0) { /* Type of profile */
8776 sprintf(icp->err,"icmHeader_write: SInt32Number deviceClass");
8777 icp->al->free(icp->al, buf);
8778 return icp->errc = rv;
8779 }
8780 if ((rv = write_SInt32Number((int)p->colorSpace, buf + 16)) != 0) { /* Color space of data */
8781 sprintf(icp->err,"icmHeader_write: SInt32Number data color space");
8782 icp->al->free(icp->al, buf);
8783 return icp->errc = rv;
8784 }
8785 if ((rv = write_SInt32Number((int)p->pcs, buf + 20)) != 0) { /* PCS: XYZ or Lab */
8786 sprintf(icp->err,"icmHeader_write: SInt32Number PCS");
8787 icp->al->free(icp->al, buf);
8788 return icp->errc = rv;
8789 }
8790 if ((rv = write_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
8791 sprintf(icp->err,"icmHeader_write: DateTimeNumber creation");
8792 icp->al->free(icp->al, buf);
8793 return icp->errc = rv;
8794 }
8795 if ((rv = write_SInt32Number(icMagicNumber, buf+36)) != 0) { /* Magic number */
8796 sprintf(icp->err,"icmHeader_write: SInt32Number magic");
8797 icp->al->free(icp->al, buf);
8798 return icp->errc = rv;
8799 }
8800 if ((rv = write_SInt32Number((int)p->platform, buf + 40)) != 0) { /* Primary platform */
8801 sprintf(icp->err,"icmHeader_write: SInt32Number platform");
8802 icp->al->free(icp->al, buf);
8803 return icp->errc = rv;
8804 }
8805 if ((rv = write_UInt32Number(p->flags, buf + 44)) != 0) { /* Various bits */
8806 sprintf(icp->err,"icmHeader_write: UInt32Number flags");
8807 icp->al->free(icp->al, buf);
8808 return icp->errc = rv;
8809 }
8810 if ((rv = write_SInt32Number(p->manufacturer, buf + 48)) != 0) { /* Dev manufacturer */
8811 sprintf(icp->err,"icmHeader_write: SInt32Number manufaturer");
8812 icp->al->free(icp->al, buf);
8813 return icp->errc = rv;
8814 }
8815 if ((write_SInt32Number(p->model, buf + 52)) != 0) { /* Dev model */
8816 sprintf(icp->err,"icmHeader_write: SInt32Number model");
8817 icp->al->free(icp->al, buf);
8818 return icp->errc = rv;
8819 }
8820 if ((rv = write_UInt64Number(&p->attributes, buf + 56)) != 0) { /* Device attributes */
8821 sprintf(icp->err,"icmHeader_write: UInt64Number attributes");
8822 icp->al->free(icp->al, buf);
8823 return icp->errc = rv;
8824 }
8825 if ((rv = write_SInt32Number((int)p->renderingIntent, buf + 64)) != 0) { /* Rendering intent */
8826 sprintf(icp->err,"icmHeader_write: SInt32Number rendering intent");
8827 icp->al->free(icp->al, buf);
8828 return icp->errc = rv;
8829 }
8830 if ((rv = write_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
8831 sprintf(icp->err,"icmHeader_write: XYZNumber illuminant");
8832 icp->al->free(icp->al, buf);
8833 return icp->errc = rv;
8834 }
8835 if ((rv = write_SInt32Number(p->creator, buf + 80)) != 0) { /* Profile creator */
8836 sprintf(icp->err,"icmHeader_write: SInt32Number creator");
8837 icp->al->free(icp->al, buf);
8838 return icp->errc = rv;
8839 }
8840
8841 if ( icp->fp->seek(icp->fp, of) != 0
8842 || icp->fp->write(icp->fp, buf, 1, len) != len) {
8843 sprintf(icp->err,"icmHeader_write fseek() or fwrite() failed");
8844 icp->al->free(icp->al, buf);
8845 return icp->errc = 2;
8846 }
8847
8848 icp->al->free(icp->al, buf);
8849 return rv;
8850 }
8851
8852 static void icmHeader_dump(
8853 icmHeader *p,
8854 FILE *op, /* Output to dump to */
8855 int verb /* Verbosity level */
8856 ) {
8857 if (verb <= 0)
8858 return;
8859
8860 fprintf(op,"Header:\n");
8861 fprintf(op," size = %d bytes\n",p->size);
8862 fprintf(op," CMM = %s\n",tag2str(p->cmmId));
8863 fprintf(op," Version = %d.%d.%d\n",p->majv, p->minv, p->bfv);
8864 fprintf(op," Device Class = %s\n", string_ProfileClassSignature(p->deviceClass));
8865 fprintf(op," Color Space = %s\n", string_ColorSpaceSignature(p->colorSpace));
8866 fprintf(op," Conn. Space = %s\n", string_ColorSpaceSignature(p->pcs));
8867 fprintf(op," Date, Time = %s\n", string_DateTimeNumber(&p->date));
8868 fprintf(op," Platform = %s\n", string_PlatformSignature(p->platform));
8869 fprintf(op," Flags = %s\n", string_ProfileHeaderFlags(p->flags));
8870 fprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->manufacturer)); /* ~~~ */
8871 fprintf(op," Dev. Model = %s\n",tag2str(p->model)); /* ~~~ */
8872 fprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
8873 fprintf(op," Rndrng Intnt = %s\n", string_RenderingIntent(p->renderingIntent));
8874 fprintf(op," Illuminant = %s\n", string_XYZNumber_and_Lab(&p->illuminant));
8875 fprintf(op," Creator = %s\n",tag2str(p->creator)); /* ~~~ */
8876 fprintf(op,"\n");
8877 }
8878
8879 static void icmHeader_delete(
8880 icmHeader *p
8881 ) {
8882 icc *icp = p->icp;
8883
8884 icp->al->free(icp->al, p);
8885 }
8886
8887 /* Create an empty object. Return null on error */
8888 static icmHeader *new_icmHeader(
8889 icc *icp
8890 ) {
8891 icmHeader *p;
8892 if ((p = (icmHeader *) icp->al->calloc(icp->al,1,sizeof(icmHeader))) == NULL)
8893 return NULL;
8894 p->icp = icp;
8895 p->get_size = icmHeader_get_size;
8896 p->read = icmHeader_read;
8897 p->write = icmHeader_write;
8898 p->dump = icmHeader_dump;
8899 p->del = icmHeader_delete;
8900
8901 return p;
8902 }
8903
8904 /* ---------------------------------------------------------- */
8905 /* Type vector table. Match the Tag type against the object creator */
8906 static struct {
8907 icTagTypeSignature ttype; /* The tag type signature */
8908 icmBase * (*new_obj)(icc *icp);
8909 } typetable[] = {
8910 {icSigCrdInfoType, new_icmCrdInfo},
8911 {icSigCurveType, new_icmCurve},
8912 {icSigDataType, new_icmData},
8913 {icSigDateTimeType, new_icmDateTimeNumber},
8914 {icSigLut16Type, new_icmLut},
8915 {icSigLut8Type, new_icmLut},
8916 {icSigMeasurementType, new_icmMeasurement},
8917 {icSigNamedColorType, new_icmNamedColor},
8918 {icSigNamedColor2Type, new_icmNamedColor},
8919 {icSigProfileSequenceDescType, new_icmProfileSequenceDesc},
8920 {icSigS15Fixed16ArrayType, new_icmS15Fixed16Array},
8921 {icSigScreeningType, new_icmScreening},
8922 {icSigSignatureType, new_icmSignature},
8923 {icSigTextDescriptionType, new_icmTextDescription},
8924 {icSigTextType, new_icmText},
8925 {icSigU16Fixed16ArrayType, new_icmU16Fixed16Array},
8926 {icSigUcrBgType, new_icmUcrBg},
8927 {icSigVideoCardGammaType, new_icmVideoCardGamma},
8928 {icSigUInt16ArrayType, new_icmUInt16Array},
8929 {icSigUInt32ArrayType, new_icmUInt32Array},
8930 {icSigUInt64ArrayType, new_icmUInt64Array},
8931 {icSigUInt8ArrayType, new_icmUInt8Array},
8932 {icSigViewingConditionsType, new_icmViewingConditions},
8933 {icSigXYZArrayType, new_icmXYZArray},
8934 {icMaxEnumType, NULL}
8935 };
8936
8937 /* Table that lists the legal Types for each Tag Signature */
8938 static struct {
8939 icTagSignature sig;
8940 icTagTypeSignature ttypes[4]; /* Arbitrary max of 4 */
8941 } sigtypetable[] = {
8942 {icSigAToB0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8943 {icSigAToB1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8944 {icSigAToB2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8945 {icSigBlueColorantTag, {icSigXYZType,icMaxEnumType}},
8946 {icSigBlueTRCTag, {icSigCurveType,icMaxEnumType}},
8947 {icSigBToA0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8948 {icSigBToA1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8949 {icSigBToA2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8950 {icSigCalibrationDateTimeTag, {icSigDateTimeType,icMaxEnumType}},
8951 {icSigCharTargetTag, {icSigTextType,icMaxEnumType}},
8952 {icSigCopyrightTag, {icSigTextType,icMaxEnumType}},
8953 {icSigCrdInfoTag, {icSigCrdInfoType,icMaxEnumType}},
8954 {icSigDeviceMfgDescTag, {icSigTextDescriptionType,icMaxEnumType}},
8955 {icSigDeviceModelDescTag, {icSigTextDescriptionType,icMaxEnumType}},
8956 {icSigGamutTag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8957 {icSigGrayTRCTag, {icSigCurveType,icMaxEnumType}},
8958 {icSigGreenColorantTag, {icSigXYZType,icMaxEnumType}},
8959 {icSigGreenTRCTag, {icSigCurveType,icMaxEnumType}},
8960 {icSigLuminanceTag, {icSigXYZType,icMaxEnumType}},
8961 {icSigMeasurementTag, {icSigMeasurementType,icMaxEnumType}},
8962 {icSigMediaBlackPointTag, {icSigXYZType,icMaxEnumType}},
8963 {icSigMediaWhitePointTag, {icSigXYZType,icMaxEnumType}},
8964 {icSigNamedColorTag, {icSigNamedColorType,icMaxEnumType}},
8965 {icSigNamedColor2Tag, {icSigNamedColor2Type,icMaxEnumType}},
8966 {icSigPreview0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8967 {icSigPreview1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8968 {icSigPreview2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8969 {icSigProfileDescriptionTag, {icSigTextDescriptionType,icMaxEnumType}},
8970 {icSigProfileSequenceDescTag, {icSigProfileSequenceDescType,icMaxEnumType}},
8971 {icSigPs2CRD0Tag, {icSigDataType,icMaxEnumType}},
8972 {icSigPs2CRD1Tag, {icSigDataType,icMaxEnumType}},
8973 {icSigPs2CRD2Tag, {icSigDataType,icMaxEnumType}},
8974 {icSigPs2CRD3Tag, {icSigDataType,icMaxEnumType}},
8975 {icSigPs2CSATag, {icSigDataType,icMaxEnumType}},
8976 {icSigPs2RenderingIntentTag, {icSigDataType,icMaxEnumType}},
8977 {icSigRedColorantTag, {icSigXYZType,icMaxEnumType}},
8978 {icSigRedTRCTag, {icSigCurveType,icMaxEnumType}},
8979 {icSigScreeningDescTag, {icSigTextDescriptionType,icMaxEnumType}},
8980 {icSigScreeningTag, {icSigScreeningType,icMaxEnumType}},
8981 {icSigTechnologyTag, {icSigSignatureType,icMaxEnumType}},
8982 {icSigUcrBgTag, {icSigUcrBgType,icMaxEnumType}},
8983 {icSigVideoCardGammaTag, {icSigVideoCardGammaType,icMaxEnumType}},
8984 {icSigViewingCondDescTag, {icSigTextDescriptionType,icMaxEnumType}},
8985 {icSigViewingConditionsTag, {icSigViewingConditionsType,icMaxEnumType}},
8986 {icMaxEnumType, {icMaxEnumType}}
8987 };
8988
8989 /* Fake color tag for specifying PCS */
8990 #define icSigPCSData ((icColorSpaceSignature) 0x50435320L)
8991
8992 /* Table that lists the required tags for various profiles */
8993 static struct {
8994 icProfileClassSignature sig; /* Profile signature */
8995 int chans; /* Data Color channels, -ve for match but try next, */
8996 /* -100 for ignore, -200 for ignore and try next */
8997 icColorSpaceSignature colsig; /* Data Color space signature, icMaxEnumData for ignore, */
8998 /* icSigPCSData for XYZ of Lab */
8999 icColorSpaceSignature pcssig; /* PCS Color space signature, icMaxEnumData for ignore, */
9000 /* icSigPCSData for XYZ or Lab */
9001 icTagSignature tags[12]; /* Arbitrary max of 12 */
9002 } tagchecktable[] = {
9003 {icSigInputClass, -1, icMaxEnumData, icSigPCSData,
9004 {icSigProfileDescriptionTag,
9005 icSigGrayTRCTag,
9006 icSigMediaWhitePointTag,
9007 icSigCopyrightTag, icMaxEnumType}},
9008
9009 {icSigInputClass, -3, icMaxEnumData, icSigXYZData,
9010 {icSigProfileDescriptionTag,
9011 icSigRedColorantTag,
9012 icSigGreenColorantTag,
9013 icSigBlueColorantTag,
9014 icSigRedTRCTag,
9015 icSigGreenTRCTag,
9016 icSigBlueTRCTag,
9017 icSigMediaWhitePointTag,
9018 icSigCopyrightTag, icMaxEnumType}},
9019
9020 {icSigInputClass, -100, icMaxEnumData, icSigPCSData,
9021 {icSigProfileDescriptionTag,
9022 icSigAToB0Tag,
9023 icSigMediaWhitePointTag,
9024 icSigCopyrightTag, icMaxEnumType}},
9025
9026 {icSigDisplayClass, -1, icMaxEnumData, icSigPCSData,
9027 {icSigProfileDescriptionTag,
9028 icSigGrayTRCTag,
9029 icSigMediaWhitePointTag,
9030 icSigCopyrightTag, icMaxEnumType}},
9031
9032 {icSigDisplayClass, -3, icSigRgbData, icSigXYZData, /* Rgb or any 3 component space ?? */
9033 {icSigProfileDescriptionTag,
9034 icSigRedColorantTag,
9035 icSigGreenColorantTag,
9036 icSigBlueColorantTag,
9037 icSigRedTRCTag,
9038 icSigGreenTRCTag,
9039 icSigBlueTRCTag,
9040 icSigMediaWhitePointTag,
9041 icSigCopyrightTag, icMaxEnumType}},
9042
9043 /* Non-3 component Display device */
9044 {icSigDisplayClass, -100, icMaxEnumData, icSigPCSData,
9045 {icSigProfileDescriptionTag,
9046 icSigAToB0Tag, /* BToA doesn't seem to be required, which is strange... */
9047 icSigMediaWhitePointTag,
9048 icSigCopyrightTag, icMaxEnumType}},
9049
9050 {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
9051 {icSigProfileDescriptionTag,
9052 icSigGrayTRCTag,
9053 icSigMediaWhitePointTag,
9054 icSigCopyrightTag, icMaxEnumType}},
9055
9056 {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
9057 {icSigProfileDescriptionTag,
9058 icSigAToB0Tag,
9059 icSigBToA0Tag,
9060 icSigGamutTag,
9061 icSigAToB1Tag,
9062 icSigBToA1Tag,
9063 icSigAToB2Tag,
9064 icSigBToA2Tag,
9065 icSigMediaWhitePointTag,
9066 icSigCopyrightTag, icMaxEnumType}},
9067
9068 {icSigOutputClass, -2, icMaxEnumData, icSigPCSData,
9069 {icSigProfileDescriptionTag,
9070 icSigAToB0Tag,
9071 icSigBToA0Tag,
9072 icSigGamutTag,
9073 icSigAToB1Tag,
9074 icSigBToA1Tag,
9075 icSigAToB2Tag,
9076 icSigBToA2Tag,
9077 icSigMediaWhitePointTag,
9078 icSigCopyrightTag, icMaxEnumType}},
9079
9080 {icSigOutputClass, -3, icMaxEnumData, icSigPCSData,
9081 {icSigProfileDescriptionTag,
9082 icSigAToB0Tag,
9083 icSigBToA0Tag,
9084 icSigGamutTag,
9085 icSigAToB1Tag,
9086 icSigBToA1Tag,
9087 icSigAToB2Tag,
9088 icSigBToA2Tag,
9089 icSigMediaWhitePointTag,
9090 icSigCopyrightTag, icMaxEnumType}},
9091
9092 {icSigOutputClass, -4, icMaxEnumData, icSigPCSData,
9093 {icSigProfileDescriptionTag,
9094 icSigAToB0Tag,
9095 icSigBToA0Tag,
9096 icSigGamutTag,
9097 icSigAToB1Tag,
9098 icSigBToA1Tag,
9099 icSigAToB2Tag,
9100 icSigBToA2Tag,
9101 icSigMediaWhitePointTag,
9102 icSigCopyrightTag, icMaxEnumType}},
9103
9104 {icSigOutputClass, -100, icMaxEnumData, icSigPCSData, /* Assumed from Hexachrome examples */
9105 {icSigProfileDescriptionTag,
9106 icSigBToA0Tag,
9107 icSigBToA1Tag,
9108 icSigBToA2Tag,
9109 icSigMediaWhitePointTag,
9110 icSigCopyrightTag, icMaxEnumType}},
9111
9112 {icSigLinkClass, -100, icMaxEnumData, icMaxEnumData,
9113 {icSigProfileDescriptionTag,
9114 icSigAToB0Tag,
9115 icSigProfileSequenceDescTag,
9116 icSigCopyrightTag, icMaxEnumType}},
9117
9118 {icSigColorSpaceClass, -100, icMaxEnumData, icSigPCSData,
9119 {icSigProfileDescriptionTag,
9120 icSigBToA0Tag,
9121 icSigAToB0Tag,
9122 icSigMediaWhitePointTag,
9123 icSigCopyrightTag, icMaxEnumType}},
9124
9125 {icSigAbstractClass, -100, icSigPCSData, icSigPCSData,
9126 {icSigProfileDescriptionTag,
9127 icSigAToB0Tag,
9128 icSigMediaWhitePointTag,
9129 icSigCopyrightTag, icMaxEnumType}},
9130
9131 {icSigNamedColorClass, -200, icMaxEnumData, icMaxEnumData,
9132 {icSigProfileDescriptionTag,
9133 icSigNamedColor2Tag,
9134 icSigMediaWhitePointTag,
9135 icSigCopyrightTag, icMaxEnumType}},
9136
9137 {icSigNamedColorClass, -100, icMaxEnumData, icMaxEnumData,
9138 {icSigProfileDescriptionTag,
9139 icSigNamedColorTag, /* Not strictly V3.4 */
9140 icSigMediaWhitePointTag,
9141 icSigCopyrightTag, icMaxEnumType}},
9142
9143 {icMaxEnumType,-1,icMaxEnumData, icMaxEnumData, {icMaxEnumType}}
9144 };
9145
9146 /* ------------------------------------------------------------- */
9147 /* Check that the ICC profile looks like it will be legal. */
9148 /* Return non-zero and set error string if not */
9149 static int check_icc_legal(
9150 icc *p
9151 ) {
9152 int i, j;
9153 icProfileClassSignature sig;
9154 icColorSpaceSignature colsig;
9155 icColorSpaceSignature pcssig;
9156 int dchans;
9157
9158 if (p->header == NULL) {
9159 sprintf(p->err,"icc_check_legal: Header is missing");
9160 return p->errc = 1;
9161 }
9162
9163 sig = p->header->deviceClass;
9164 colsig = p->header->colorSpace;
9165 dchans = number_ColorSpaceSignature(colsig);
9166 pcssig = p->header->pcs;
9167
9168 /* Find a matching table entry */
9169 for (i = 0; tagchecktable[i].sig != icMaxEnumType; i++) {
9170 if ( tagchecktable[i].sig == sig
9171 && ( tagchecktable[i].chans == dchans /* Exactly matches */
9172 || tagchecktable[i].chans == -dchans /* Exactly matches, but can try next table */
9173 || tagchecktable[i].chans < -99) /* Doesn't have to match or try next table */
9174 && ( tagchecktable[i].colsig == colsig
9175 || (tagchecktable[i].colsig == icSigPCSData
9176 && (colsig == icSigXYZData || colsig == icSigLabData))
9177 || tagchecktable[i].colsig == icMaxEnumData)
9178 && ( tagchecktable[i].pcssig == pcssig
9179 || (tagchecktable[i].pcssig == icSigPCSData
9180 && (pcssig == icSigXYZData || pcssig == icSigLabData))
9181 || tagchecktable[i].pcssig == icMaxEnumData)) {
9182
9183 /* Found entry, so now check that all the required tags are present. */
9184 for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) {
9185 if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) { /* Not present! */
9186 if (tagchecktable[i].chans == -200
9187 || tagchecktable[i].chans == -dchans) { /* But can try next table */
9188 break;
9189 }
9190 sprintf(p->err,"icc_check_legal: deviceClass %s is missing required tag %s",
9191 tag2str(sig), tag2str(tagchecktable[i].tags[j]));
9192 return p->errc = 1;
9193 }
9194 }
9195 if (tagchecktable[i].tags[j] == icMaxEnumType) {
9196 break; /* Fount all required tags */
9197 }
9198 }
9199 }
9200
9201 /* According to the spec. if the deviceClass is:
9202 an Abstract Class: both in and out color spaces should be PCS
9203 an Link Class: both in and out color spaces can be any, and should
9204 be the input space of the first profile in the link, and the
9205 input space of the last profile in the link respectively.
9206 a Named Class: in and out color spaces are not defined in the spec.
9207 Input, Display, Output and ColorSpace Classes, input color
9208 space can be any, and the output space must be PCS.
9209 ~~ should check this here ???
9210 */
9211
9212 return 0; /* Assume anything is ok */
9213 }
9214
9215
9216 /* read the object, return 0 on success, error code on fail */
9217 /* NOTE: this doesn't read the tag types, they should be read on demand. */
9218 static int icc_read(
9219 icc *p,
9220 icmFile *fp, /* File to read from */
9221 unsigned long of /* File offset to read from */
9222 ) {
9223 char tcbuf[4]; /* Tag count read buffer */
9224 int i;
9225 unsigned int len;
9226 int er = 0; /* Error code */
9227
9228 p->fp = fp;
9229 p->of = of;
9230 if (p->header == NULL) {
9231 sprintf(p->err,"icc_read: No header defined");
9232 return p->errc = 1;
9233 }
9234
9235 /* Read the header */
9236 if (p->header->read(p->header, 128, of)) {
9237 return 1;
9238 }
9239
9240 /* Read the tag count */
9241 if ( p->fp->seek(p->fp, of + 128) != 0
9242 || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
9243 sprintf(p->err,"icc_read: fseek() or fread() failed on tag count");
9244 return p->errc = 1;
9245 }
9246
9247 p->count = read_UInt32Number(tcbuf); /* Tag count */
9248 if (p->count > 0) {
9249 char *bp, *buf;
9250 if ((p->data = (icmTag *) p->al->malloc(p->al, p->count * sizeof(icmTag))) == NULL) {
9251 sprintf(p->err,"icc_read: Tag table malloc() failed");
9252 return p->errc = 2;
9253 }
9254
9255 len = 4 + p->count * 12;
9256 if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
9257 sprintf(p->err,"icc_read: Tag table read buffer malloc() failed");
9258 p->al->free(p->al, p->data);
9259 p->data = NULL;
9260 return p->errc = 2;
9261 }
9262 if ( p->fp->seek(p->fp, of + 128) != 0
9263 || p->fp->read(p->fp, buf, 1, len) != len) {
9264 sprintf(p->err,"icc_read: fseek() or fread() failed on tag table");
9265 p->al->free(p->al, p->data);
9266 p->data = NULL;
9267 p->al->free(p->al, buf);
9268 return p->errc = 1;
9269 }
9270
9271 /* Fill in the tag table structure */
9272 bp = buf+4;
9273 for (i = 0; i < p->count; i++, bp += 12) {
9274 p->data[i].sig = (icTagSignature)read_SInt32Number(bp + 0);
9275 p->data[i].offset = read_UInt32Number(bp + 4);
9276 p->data[i].size = read_UInt32Number(bp + 8);
9277 if ( p->fp->seek(p->fp, of + p->data[i].offset) != 0
9278 || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
9279 sprintf(p->err,"icc_read: fseek() or fread() failed on tag headers");
9280 p->al->free(p->al, p->data);
9281 p->data = NULL;
9282 p->al->free(p->al, buf);
9283 return p->errc = 1;
9284 }
9285 p->data[i].ttype = read_SInt32Number(tcbuf); /* Tag type */
9286 p->data[i].objp = NULL; /* Read on demand */
9287 }
9288 p->al->free(p->al, buf);
9289 } /* p->count > 0 */
9290
9291 return er;
9292 }
9293
9294 #define DO_ALIGN(val) (((val) + 3) & ~3)
9295
9296 /* Return the total size needed for the profile */
9297 /* Return 0 on error. */
9298 static unsigned int icc_get_size(
9299 icc *p
9300 ) {
9301 unsigned int size = 0;
9302 int i;
9303
9304 /* Check that the right tags etc. are present for a legal ICC profile */
9305 if (check_icc_legal(p) != 0) {
9306 return 0;
9307 }
9308
9309 /* Compute the total size and tag element data offsets */
9310 if (p->header == NULL) {
9311 sprintf(p->err,"icc_get_size: No header defined");
9312 p->errc = 1;
9313 return 0;
9314 }
9315
9316 size += p->header->get_size(p->header);
9317
9318 size = DO_ALIGN(size);
9319 size += 4 + p->count * 12; /* Tag table length */
9320
9321 /* Reset touched flag for each tag type */
9322 for (i = 0; i < p->count; i++) {
9323 if (p->data[i].objp == NULL) {
9324 sprintf(p->err,"icc_get_size: Internal error - NULL tag element");
9325 p->errc = 1;
9326 return 0;
9327 }
9328 p->data[i].objp->touched = 0;
9329 }
9330 /* Get size for each tag type, skipping links */
9331 for (i = 0; i < p->count; i++) {
9332 if (p->data[i].objp->touched == 0) { /* Not alllowed for previously */
9333 size = DO_ALIGN(size);
9334 size += p->data[i].objp->get_size(p->data[i].objp);
9335 p->data[i].objp->touched = 1; /* Don't account for this again */
9336 }
9337 }
9338
9339 return size; /* Total size needed */
9340 }
9341
9342 /* Write the contents of the object. Return 0 on sucess, error code on failure */
9343 static int icc_write(
9344 icc *p,
9345 icmFile *fp, /* File to write to */
9346 unsigned long of /* File offset to write to */
9347 ) {
9348 char *bp, *buf; /* Buffer to write to */
9349 unsigned int len;
9350 int rv = 0;
9351 int i;
9352 unsigned int size = 0;
9353
9354 /* Check that the right tags etc. are present for a legal ICC profile */
9355 if ((rv = check_icc_legal(p)) != 0) {
9356 return rv;
9357 }
9358
9359 p->fp = fp; /* Open file pointer */
9360 p->of = of; /* Offset of ICC profile */
9361
9362 /* Compute the total size and tag element data offsets */
9363 if (p->header == NULL) {
9364 sprintf(p->err,"icc_write: No header defined");
9365 return p->errc = 1;
9366 }
9367
9368 size += p->header->get_size(p->header);
9369
9370 len = 4 + p->count * 12; /* Tag table length */
9371 size = DO_ALIGN(size);
9372 size += len;
9373
9374 /* Allocate memory buffer for tag table */
9375 if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
9376 sprintf(p->err,"icc_write malloc() failed");
9377 return p->errc = 2;
9378 }
9379 bp = buf;
9380
9381 if ((rv = write_UInt32Number(p->count, bp)) != 0) { /* Tag count */
9382 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag count");
9383 p->al->free(p->al, buf);
9384 return p->errc = rv;
9385 }
9386 bp += 4;
9387 /* Reset touched flag for each tag type */
9388 for (i = 0; i < p->count; i++) {
9389 if (p->data[i].objp == NULL) {
9390 sprintf(p->err,"icc_write: Internal error - NULL tag element");
9391 p->al->free(p->al, buf);
9392 return p->errc = 1;
9393 }
9394 p->data[i].objp->touched = 0;
9395 }
9396 /* Set the offset and size for each tag type */
9397 for (i = 0; i < p->count; i++) {
9398 if (p->data[i].objp->touched == 0) { /* Allocate space for tag type */
9399 size = DO_ALIGN(size);
9400 p->data[i].offset = size; /* Profile relative target */
9401 p->data[i].size = p->data[i].objp->get_size(p->data[i].objp);
9402 size += p->data[i].size;
9403 p->data[i].objp->touched = 1; /* Allocated space for it */
9404 } else { /* must be linked - copy allocation */
9405 int k;
9406 for (k = 0; k < p->count; k++) { /* Find linked tag */
9407 if (p->data[k].objp == p->data[i].objp)
9408 break;
9409 }
9410 if (k == p->count) {
9411 sprintf(p->err,"icc_write: corrupted link");
9412 return p->errc = 2;
9413 }
9414 p->data[i].offset = p->data[k].offset;
9415 p->data[i].size = p->data[k].size;
9416 }
9417 /* Write tag table entry for this tag */
9418 if ((rv = write_SInt32Number((int)p->data[i].sig,bp + 0)) != 0) {
9419 sprintf(p->err,"icc_write: write_SInt32Number() failed on tag signature");
9420 p->al->free(p->al, buf);
9421 return p->errc = rv;
9422 }
9423 if ((rv = write_UInt32Number(p->data[i].offset, bp + 4)) != 0) {
9424 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag offset");
9425 p->al->free(p->al, buf);
9426 return p->errc = rv;
9427 }
9428 if ((rv = write_UInt32Number(p->data[i].size, bp + 8)) != 0) {
9429 sprintf(p->err,"icc_write: write_UInt32Number() failed on tag size");
9430 p->al->free(p->al, buf);
9431 return p->errc = rv;
9432 }
9433 bp += 12;
9434 }
9435 p->header->size = size; /* Record total icc size */
9436
9437 /* Write the header */
9438 if ((rv = p->header->write(p->header, of)) != 0) {
9439 p->al->free(p->al, buf);
9440 return rv;
9441 }
9442
9443 /* Write the tag table */
9444 if ( p->fp->seek(p->fp, of + 128) != 0
9445 || p->fp->write(p->fp, buf, 1, len) != len) {
9446 sprintf(p->err,"icc_write: fseek() or fwrite() failed");
9447 p->al->free(p->al, buf);
9448 return p->errc = 1;
9449 }
9450 p->al->free(p->al, buf);
9451
9452 /* Write all the tag element data */
9453 for (i = 0; i < p->count; i++) { /* For all the tag element data */
9454 if (p->data[i].objp->touched == 0)
9455 continue; /* Must be linked, and we've already written it */
9456 if ((rv = p->data[i].objp->write(p->data[i].objp, of + p->data[i].offset)) != 0) {
9457 return rv;
9458 }
9459 p->data[i].objp->touched = 0; /* Written it */
9460 }
9461
9462 if (p->fp->flush(p->fp) != 0) {
9463 sprintf(p->err,"icc_write flush() failed");
9464 p->al->free(p->al, buf);
9465 return p->errc = 2;
9466 }
9467 return rv;
9468 }
9469 #undef DO_ALIGN
9470
9471 /* Create and add a tag with the given signature. */
9472 /* Returns a pointer to the element object */
9473 /* Returns NULL if error - icc->errc will contain */
9474 /* 2 on system error, */
9475 /* 3 if unknown tag */
9476 /* NOTE: that we prevent tag duplication */
9477 static icmBase *icc_add_tag(
9478 icc *p,
9479 icTagSignature sig, /* Tag signature - may be unknown */
9480 icTagTypeSignature ttype /* Tag type */
9481 ) {
9482 icmBase *tp;
9483 icmBase *nob;
9484 int i, j, ok = 1;
9485
9486 /* Check that a known signature has an acceptable type */
9487 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9488 if (sigtypetable[i].sig == sig) { /* recognized signature */
9489 ok = 0;
9490 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9491 if (sigtypetable[i].ttypes[j] == ttype) /* recognized type */
9492 ok = 1;
9493 }
9494 break;
9495 }
9496 }
9497 if (!ok) {
9498 sprintf(p->err,"icc_add_tag: wrong tag type for signature");
9499 p->errc = 1;
9500 return NULL;
9501 }
9502
9503 /* Check that we know how to handle this type */
9504 for (i = 0; typetable[i].ttype != icMaxEnumType; i++) {
9505 if (typetable[i].ttype == ttype)
9506 break;
9507 }
9508 if (typetable[i].ttype == icMaxEnumType) {
9509 sprintf(p->err,"icc_add_tag: unsupported tag type");
9510 p->errc = 1;
9511 return NULL;
9512 }
9513
9514 /* Check that this tag doesn't already exits */
9515 /* (Perhaps we should simply replace it, rather than erroring ?) */
9516 for (j = 0; j < p->count; j++) {
9517 if (p->data[j].sig == sig) {
9518 sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
9519 p->errc = 1;
9520 return NULL;
9521 }
9522 }
9523
9524 /* Make space in tag table for new tag item */
9525 if (p->data == NULL)
9526 tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
9527 else
9528 tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
9529 if (tp == NULL) {
9530 sprintf(p->err,"icc_add_tag: Tag table realloc() failed");
9531 p->errc = 2;
9532 return NULL;
9533 }
9534 p->data = (icmTag *)tp;
9535
9536 /* Allocate the empty object */
9537 if ((nob = typetable[i].new_obj(p)) == NULL)
9538 return NULL;
9539
9540 /* Fill out our tag table entry */
9541 p->data[p->count].sig = sig; /* The tag signature */
9542 p->data[p->count].ttype = nob->ttype = ttype; /* The tag type signature */
9543 p->data[p->count].offset = 0; /* Unknown offset yet */
9544 p->data[p->count].size = 0; /* Unknown size yet */
9545 p->data[p->count].objp = nob; /* Empty object */
9546 p->count++;
9547
9548 return nob;
9549 }
9550
9551 /* Create and add a tag which is a link to an existing tag. */
9552 /* Returns a pointer to the element object */
9553 /* Returns NULL if error - icc->errc will contain */
9554 /* 3 if incompatible tag */
9555 /* NOTE: that we prevent tag duplication */
9556 static icmBase *icc_link_tag(
9557 icc *p,
9558 icTagSignature sig, /* Tag signature - may be unknown */
9559 icTagSignature ex_sig /* Tag signature of tag to link to */
9560 ) {
9561 icmBase *tp;
9562 int i, j, exi, ok = 1;
9563
9564 /* Search for existing signature */
9565 for (exi = 0; exi < p->count; exi++) {
9566 if (p->data[exi].sig == ex_sig) /* Found it */
9567 break;
9568 }
9569 if (exi == p->count) {
9570 sprintf(p->err,"icc_link_tag: Can't find existing tag '%s'",tag2str(ex_sig));
9571 p->errc = 1;
9572 return NULL;
9573 }
9574
9575 if (p->data[exi].objp == NULL) {
9576 sprintf(p->err,"icc_link_tag: Existing tag '%s' isn't loaded",tag2str(ex_sig));
9577 p->errc = 1;
9578 return NULL;
9579 }
9580
9581 /* Check that a known signature has an acceptable type */
9582 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9583 if (sigtypetable[i].sig == sig) { /* recognized signature */
9584 ok = 0;
9585 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9586 if (sigtypetable[i].ttypes[j] == p->data[exi].ttype) /* recognized type */
9587 ok = 1;
9588 }
9589 break;
9590 }
9591 }
9592 if (!ok) {
9593 sprintf(p->err,"icc_link_tag: wrong tag type for signature");
9594 p->errc = 1;
9595 return NULL;
9596 }
9597
9598 /* Check that this tag doesn't already exits */
9599 for (j = 0; j < p->count; j++) {
9600 if (p->data[j].sig == sig) {
9601 sprintf(p->err,"icc_link_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
9602 p->errc = 1;
9603 return NULL;
9604 }
9605 }
9606
9607 /* Make space in tag table for new tag item */
9608 if (p->data == NULL)
9609 tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
9610 else
9611 tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
9612 if (tp == NULL) {
9613 sprintf(p->err,"icc_link_tag: Tag table realloc() failed");
9614 p->errc = 2;
9615 return NULL;
9616 }
9617 p->data = (icmTag *)tp;
9618
9619 /* Fill out our tag table entry */
9620 p->data[p->count].sig = sig; /* The tag signature */
9621 p->data[p->count].ttype = p->data[exi].ttype; /* The tag type signature */
9622 p->data[p->count].offset = p->data[exi].offset; /* Same offset (may not be allocated yet) */
9623 p->data[p->count].size = p->data[exi].size; /* Same size (may not be allocated yet) */
9624 p->data[p->count].objp = p->data[exi].objp; /* Shared object */
9625 p->data[exi].objp->refcount++; /* Bump reference count on tag type */
9626 p->count++;
9627
9628 return p->data[exi].objp;
9629 }
9630
9631 /* Search for tag signature */
9632 /* return: */
9633 /* 0 if found */
9634 /* 1 if found but not handled type */
9635 /* 2 if not found */
9636 /* NOTE: doesn't set icc->errc or icc->err[] */
9637 /* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
9638 static int icc_find_tag(
9639 icc *p,
9640 icTagSignature sig /* Tag signature - may be unknown */
9641 ) {
9642 int i,j;
9643
9644 /* Search for signature */
9645 for (i = 0; i < p->count; i++) {
9646 if (p->data[i].sig == sig) /* Found it */
9647 break;
9648 }
9649 if (i == p->count)
9650 return 2;
9651
9652 /* See if we can handle this type */
9653 for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
9654 if (typetable[j].ttype == p->data[i].ttype)
9655 break;
9656 }
9657 if (typetable[j].ttype == icMaxEnumType)
9658 return 1;
9659
9660 return 0;
9661 }
9662
9663 /* Read the tag element data, and return a pointer to the object */
9664 /**
9665 * Returns NULL if error - icc->errc will contain:
9666 * 1 if found but not handled type
9667 * 2 if not found
9668 **/
9669 /* NOTE: we don't handle tag duplication - you'll always get the first in the file */
9670 static icmBase *icc_read_tag(
9671 icc *p,
9672 icTagSignature sig /* Tag signature - may be unknown */
9673 ) {
9674 icmBase *nob;
9675 int i,j,k;
9676
9677 /* Search for signature */
9678 for (i = 0; i < p->count; i++) {
9679 if (p->data[i].sig == sig) /* Found it */
9680 break;
9681 }
9682 if (i >= p->count) {
9683 sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
9684 p->errc = 2;
9685 return NULL;
9686 }
9687
9688 /* See if it's already been read */
9689 if (p->data[i].objp != NULL) {
9690 return p->data[i].objp; /* Just return it */
9691 }
9692
9693 /* See if this should be a link */
9694 for (k = 0; k < p->count; k++) {
9695 if (i == k)
9696 continue;
9697 if (p->data[i].ttype == p->data[k].ttype /* Exact match and already read */
9698 && p->data[i].offset == p->data[k].offset
9699 && p->data[i].size == p->data[k].size
9700 && p->data[k].objp != NULL)
9701 break;
9702 }
9703 if (k < p->count) { /* Make this a link */
9704 p->data[i].objp = p->data[k].objp;
9705 p->data[k].objp->refcount++; /* Bump reference count */
9706 return p->data[k].objp; /* Done */
9707 }
9708
9709 /* See if we can handle this type */
9710 for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
9711 if (typetable[j].ttype == p->data[i].ttype)
9712 break;
9713 }
9714 if (typetable[j].ttype == icMaxEnumType) {
9715 sprintf(p->err,"icc_read_tag: Unhandled tag type '%s'",string_TypeSignature(p->data[i].ttype));
9716 p->errc = 1;
9717 return NULL;
9718 }
9719
9720 /* Creat and read in the object */
9721 if ((nob = typetable[j].new_obj(p)) == NULL)
9722 return NULL;
9723 if ((nob->read(nob, p->data[i].size, p->of + p->data[i].offset)) != 0) {
9724 nob->del(nob); /* Failed, so destroy it */
9725 return NULL;
9726 }
9727 p->data[i].objp = nob;
9728 return nob;
9729 }
9730
9731 /* Rename a tag signature */
9732 static int icc_rename_tag(
9733 icc *p,
9734 icTagSignature sig, /* Existing Tag signature - may be unknown */
9735 icTagSignature sigNew /* New Tag signature - may be unknown */
9736 ) {
9737 int i, j, k, ok = 1;
9738
9739 /* Search for signature */
9740 for (k = 0; k < p->count; k++) {
9741 if (p->data[k].sig == sig) /* Found it */
9742 break;
9743 }
9744 if (k >= p->count) {
9745 sprintf(p->err,"icc_rename_tag: Tag '%s' not found",string_TagSignature(sig));
9746 return p->errc = 2;
9747 }
9748
9749 /* Check that a known new signature has an acceptable type */
9750 for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9751 if (sigtypetable[i].sig == sigNew) { /* recognized signature */
9752 ok = 0;
9753 for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9754 if (sigtypetable[i].ttypes[j] == p->data[k].ttype) /* recognized type */
9755 ok = 1;
9756 }
9757 break;
9758 }
9759 }
9760
9761 if (!ok) {
9762 sprintf(p->err,"icc_rename_tag: wrong signature for tag type");
9763 p->errc = 1;
9764 return p->errc;
9765 }
9766
9767 /* change its signature */
9768 p->data[k].sig = sigNew;
9769
9770 return 0;
9771 }
9772
9773 /* Unread the tag, and free the underlying tag type */
9774 /* if this was the last reference to it. */
9775 /* Returns non-zero on error: */
9776 /* tag not found - icc->errc will contain 2 */
9777 /* tag not read - icc->errc will contain 2 */
9778 static int icc_unread_tag(
9779 icc *p,
9780 icTagSignature sig /* Tag signature - may be unknown */
9781 ) {
9782 int i;
9783
9784 /* Search for signature */
9785 for (i = 0; i < p->count; i++) {
9786 if (p->data[i].sig == sig) /* Found it */
9787 break;
9788 }
9789 if (i >= p->count) {
9790 sprintf(p->err,"icc_unread_tag: Tag '%s' not found",string_TagSignature(sig));
9791 return p->errc = 2;
9792 }
9793
9794 /* See if it's been read */
9795 if (p->data[i].objp == NULL) {
9796 sprintf(p->err,"icc_unread_tag: Tag '%s' not currently loaded",string_TagSignature(sig));
9797 return p->errc = 2;
9798 }
9799
9800 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
9801 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
9802 p->data[i].objp = NULL;
9803
9804 return 0;
9805 }
9806
9807 /* Delete the tag, and free the underlying tag type */
9808 /* if this was the last reference to it. */
9809 /* Returns non-zero on error: */
9810 /* tag not found - icc->errc will contain 2 */
9811 static int icc_delete_tag(
9812 icc *p,
9813 icTagSignature sig /* Tag signature - may be unknown */
9814 ) {
9815 int i;
9816
9817 /* Search for signature */
9818 for (i = 0; i < p->count; i++) {
9819 if (p->data[i].sig == sig) /* Found it */
9820 break;
9821 }
9822 if (i >= p->count) {
9823 sprintf(p->err,"icc_delete_tag: Tag '%s' not found",string_TagSignature(sig));
9824 return p->errc = 2;
9825 }
9826
9827 /* If it's been read into memory, decrement the reference count */
9828 if (p->data[i].objp != NULL) {
9829 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
9830 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
9831 p->data[i].objp = NULL;
9832 }
9833
9834 /* Now remove it from the tag list */
9835 for (; i < (p->count-1); i++)
9836 p->data[i] = p->data[i+1]; /* Copy the structure down */
9837
9838 p->count--; /* One less tag in list */
9839
9840 return 0;
9841 }
9842
9843
9844 /* Read all the tags into memory. */
9845 /* Returns non-zero on error. */
9846 static int icc_read_all_tags(
9847 icc *p
9848 ) {
9849 int i;
9850
9851 for (i = 0; i < p->count; i++) { /* For all the tag element data */
9852 icmBase *ob;
9853 if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) {
9854 return p->errc;
9855 }
9856 }
9857 return 0;
9858 }
9859
9860
9861 static void icc_dump(
9862 icc *p,
9863 FILE *op, /* Output to dump to */
9864 int verb /* Verbosity level */
9865 ) {
9866 int i;
9867 if (verb <= 0)
9868 return;
9869
9870 fprintf(op,"icc:\n");
9871
9872 /* Dump the header */
9873 if (p->header != NULL)
9874 p->header->dump(p->header,op,verb);
9875
9876 /* Dump all the tag elements */
9877 for (i = 0; i < p->count; i++) { /* For all the tag element data */
9878 icmBase *ob;
9879 int tr;
9880 fprintf(op,"tag %d:\n",i);
9881 fprintf(op," sig %s\n",tag2str(p->data[i].sig));
9882 fprintf(op," type %s\n",tag2str(p->data[i].ttype));
9883 fprintf(op," offset %d\n", p->data[i].offset);
9884 fprintf(op," size %d\n", p->data[i].size);
9885 tr = 0;
9886 if ((ob = p->data[i].objp) == NULL) {
9887 /* The object is not loaded, so load it then free it */
9888 if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) {
9889 fprintf(op,"Unable to read: %d, %s\n",p->errc,p->err);
9890 }
9891 tr = 1;
9892 }
9893 if (ob != NULL) {
9894 /* fprintf(op," refcount %d\n", ob->refcount); */
9895 ob->dump(ob,op,verb-1);
9896
9897 if (tr != 0) { /* Cleanup if temporary */
9898 ob->refcount--;
9899 (ob->del)(ob);
9900 p->data[i].objp = NULL;
9901 }
9902 }
9903 fprintf(op,"\n");
9904 }
9905 }
9906
9907 static void icc_delete(
9908 icc *p
9909 ) {
9910 int i;
9911 icmAlloc *al = p->al;
9912 int del_al = p->del_al;
9913
9914 /* Free up the header */
9915 if (p->header != NULL)
9916 (p->header->del)(p->header);
9917
9918 /* Free up the tag data objects */
9919 for (i = 0; i < p->count; i++) {
9920 if (p->data[i].objp != NULL) {
9921 if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
9922 (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
9923 p->data[i].objp = NULL;
9924 }
9925 }
9926
9927 /* Free tag table */
9928 al->free(al, p->data);
9929
9930 /* This object */
9931 al->free(al, p);
9932
9933 if (del_al) /* We are responsible for deleting allocator */
9934 al->del(al);
9935 }
9936
9937 /* ================================================== */
9938 /* Lut Color normalizing and de-normalizing functions */
9939
9940 /* As a rule, I am representing Lut in memory as values in machine form as real */
9941 /* numbers in the range 0.0 - 1.0. For many color spaces (ie. RGB, Gray, */
9942 /* hsv, hls, cmyk and other device coords), this is entirely appropriate. */
9943 /* For the PCS though, this is not correct, since (I assume!) the binary */
9944 /* representation will be consistent with the encoding in Annex A, page 74 */
9945 /* of the standard. Note that the standard doesn't specify the encoding of */
9946 /* many color spaces (ie. Yuv, Yxy etc.), and is unclear about PCS. */
9947
9948 /* The following functions convert to and from the PCS spaces (XYZ or Lab) */
9949 /* and the real Lut input/output values. These are used to convert real color */
9950 /* space values into/out of the raw lut 0.0-1.0 representation. */
9951
9952 /* This is used internally to support the Lut->lookup() function, */
9953 /* and can also be used by someone writing a Lut based profile to determine */
9954 /* the colorspace range that the input lut indexes cover, as well */
9955 /* as processing the output luts values into normalized form ready */
9956 /* for writing. */
9957
9958 /* These functions should be accessed by calling icc.getNormFuncs() */
9959
9960 /* - - - - - - - - - - - - - - - - */
9961 /* According to 6.5.5 and 6.5.6 of the spec., */
9962 /* XYZ index values are represented the same as their table */
9963 /* values, ie. as a u1.15 representation, with a value */
9964 /* range from 0.0 -> 1.999969482422 */
9965
9966 /* Convert Lut index/value to XYZ coord. */
9967 static void Lut_Lut2XYZ(double *out, double *in) {
9968 out[0] = in[0] * (1.0 + 32767.0/32768); /* X */
9969 out[1] = in[1] * (1.0 + 32767.0/32768); /* Y */
9970 out[2] = in[2] * (1.0 + 32767.0/32768); /* Z */
9971 }
9972
9973 /* Convert XYZ coord to Lut index/value. */
9974 static void Lut_XYZ2Lut(double *out, double *in) {
9975 out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
9976 out[1] = in[1] * (1.0/(1.0 + 32767.0/32768));
9977 out[2] = in[2] * (1.0/(1.0 + 32767.0/32768));
9978 }
9979
9980 /* - - - - - - - - - - - - - - - - */
9981 /* Convert Lab to Lut numbers */
9982 /* Annex A specifies 8 and 16 bit encoding, but is */
9983 /* silent on the Lut index normalization. */
9984 /* Following Michael Bourgoin's 1998 SIGGRAPH course comment on this, */
9985 /* we assume here that the index encoding is the same as the */
9986 /* value encoding. */
9987
9988 /* Convert Lut16 table index/value to Lab */
9989 static void Lut_Lut2Lab16(double *out, double *in) {
9990 out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */
9991 out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0; /* a */
9992 out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0; /* b */
9993 }
9994
9995 /* Convert Lab to Lut16 table index/value */
9996 static void Lut_Lab2Lut16(double *out, double *in) {
9997 out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */
9998 out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0); /* a */
9999 out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0); /* b */
10000 }
10001
10002 /* Convert Lut8 table index/value to Lab */
10003 static void Lut_Lut2Lab8(double *out, double *in) {
10004 out[0] = in[0] * 100.0; /* L */
10005 out[1] = (in[1] * 255.0) - 128.0; /* a */
10006 out[2] = (in[2] * 255.0) - 128.0; /* b */
10007 }
10008
10009 /* Convert Lab to Lut8 table index/value */
10010 static void Lut_Lab2Lut8(double *out, double *in) {
10011 out[0] = in[0] * 1.0/100.0; /* L */
10012 out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */
10013 out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */
10014 }
10015
10016 /* - - - - - - - - - - - - - - - - */
10017 /* Convert Luv to Lut number */
10018 /* This data normalization is taken from Apples */
10019 /* Colorsync specification. */
10020 /* As per other color spaces, we assume that the index */
10021 /* normalization is the same as the data normalization. */
10022
10023 /* Convert Lut table index/value to Luv */
10024 static void Lut_Lut2Luv(double *out, double *in) {
10025 out[0] = in[0] * 100.0; /* L */
10026 out[1] = (in[1] * 65535.0/256.0) - 128.0; /* u */
10027 out[2] = (in[2] * 65535.0/256.0) - 128.0; /* v */
10028 }
10029
10030 /* Convert Luv to Lut table index/value */
10031 static void Lut_Luv2Lut(double *out, double *in) {
10032 out[0] = in[0] * 1.0/100.0; /* L */
10033 out[1] = (in[1] + 128.0) * 256.0/65535.0; /* u */
10034 out[2] = (in[2] + 128.0) * 256.0/65535.0; /* v */
10035 }
10036
10037 /* - - - - - - - - - - - - - - - - */
10038 /* Default N component conversions */
10039 static void Lut_N(double *out, double *in, int nc) {
10040 for (--nc; nc >= 0; nc--)
10041 out[nc] = in[nc];
10042 }
10043
10044 /* 1 */
10045 static void Lut_1(double *out, double *in) {
10046 out[0] = in[0];
10047 }
10048
10049 /* 2 */
10050 static void Lut_2(double *out, double *in) {
10051 out[0] = in[0];
10052 out[1] = in[1];
10053 }
10054
10055 /* 3 */
10056 static void Lut_3(double *out, double *in) {
10057 out[0] = in[0];
10058 out[1] = in[1];
10059 out[2] = in[2];
10060 }
10061
10062 /* 4 */
10063 static void Lut_4(double *out, double *in) {
10064 out[0] = in[0];
10065 out[1] = in[1];
10066 out[2] = in[2];
10067 out[3] = in[3];
10068 }
10069
10070 /* 5 */
10071 static void Lut_5(double *out, double *in) {
10072 out[0] = in[0];
10073 out[1] = in[1];
10074 out[2] = in[2];
10075 out[3] = in[3];
10076 out[4] = in[4];
10077 }
10078
10079 /* 6 */
10080 static void Lut_6(double *out, double *in) {
10081 out[0] = in[0];
10082 out[1] = in[1];
10083 out[2] = in[2];
10084 out[3] = in[3];
10085 out[4] = in[4];
10086 out[5] = in[5];
10087 }
10088
10089 /* 7 */
10090 static void Lut_7(double *out, double *in) {
10091 Lut_N(out, in, 7);
10092 }
10093
10094 /* 8 */
10095 static void Lut_8(double *out, double *in) {
10096 Lut_N(out, in, 8);
10097 }
10098
10099 /* 9 */
10100 static void Lut_9(double *out, double *in) {
10101 Lut_N(out, in, 9);
10102 }
10103
10104 /* 10 */
10105 static void Lut_10(double *out, double *in) {
10106 Lut_N(out, in, 10);
10107 }
10108
10109 /* 11 */
10110 static void Lut_11(double *out, double *in) {
10111 Lut_N(out, in, 11);
10112 }
10113
10114 /* 12 */
10115 static void Lut_12(double *out, double *in) {
10116 Lut_N(out, in, 12);
10117 }
10118
10119 /* 13 */
10120 static void Lut_13(double *out, double *in) {
10121 Lut_N(out, in, 13);
10122 }
10123
10124 /* 14 */
10125 static void Lut_14(double *out, double *in) {
10126 Lut_N(out, in, 14);
10127 }
10128
10129 /* 15 */
10130 static void Lut_15(double *out, double *in) {
10131 Lut_N(out, in, 15);
10132 }
10133
10134 /* Function table - match conversions to color spaces. */
10135 /* Anything not here, we don't know how to convert. */
10136 /* (ie. YCbCr) */
10137 static struct {
10138 icColorSpaceSignature csig;
10139 void (*fromLut8)(double *out, double *in); /* 8 bit from Lut index/entry */
10140 void (*fromLut16)(double *out, double *in); /* 16 bit from Lut index/entry */
10141 void (*toLut8)(double *out, double *in); /* 8 bit to Lut index/entry */
10142 void (*toLut16)(double *out, double *in); /* 16 bit to Lut index/entry */
10143 } colnormtable[] = {
10144 {icSigXYZData, NULL, Lut_Lut2XYZ, NULL, Lut_XYZ2Lut },
10145 {icSigLabData, Lut_Lut2Lab8, Lut_Lut2Lab16, Lut_Lab2Lut8, Lut_Lab2Lut16 },
10146 {icSigLuvData, Lut_Lut2Luv, Lut_Lut2Luv, Lut_Luv2Lut, Lut_Luv2Lut },
10147 {icSigYxyData, Lut_3, Lut_3, Lut_3, Lut_3 },
10148 {icSigRgbData, Lut_3, Lut_3, Lut_3, Lut_3 },
10149 {icSigGrayData, Lut_1, Lut_1, Lut_1, Lut_1 },
10150 {icSigHsvData, Lut_3, Lut_3, Lut_3, Lut_3 },
10151 {icSigHlsData, Lut_3, Lut_3, Lut_3, Lut_3 },
10152 {icSigCmykData, Lut_4, Lut_4, Lut_4, Lut_4 },
10153 {icSigCmyData, Lut_3, Lut_3, Lut_3, Lut_3 },
10154 {icSigMch6Data, Lut_6, Lut_6, Lut_6, Lut_6 },
10155 {icSig2colorData, Lut_2, Lut_2, Lut_2, Lut_2 },
10156 {icSig3colorData, Lut_3, Lut_3, Lut_3, Lut_3 },
10157 {icSig4colorData, Lut_4, Lut_4, Lut_4, Lut_4 },
10158 {icSig5colorData, Lut_5, Lut_5, Lut_5, Lut_5 },
10159 {icSig6colorData, Lut_6, Lut_6, Lut_6, Lut_6 },
10160 {icSig7colorData, Lut_7, Lut_7, Lut_7, Lut_7 },
10161 {icSig8colorData, Lut_8, Lut_8, Lut_8, Lut_8 },
10162 {icSig9colorData, Lut_9, Lut_9, Lut_9, Lut_9 },
10163 {icSig10colorData, Lut_10, Lut_10, Lut_10, Lut_10 },
10164 {icSig11colorData, Lut_11, Lut_11, Lut_11, Lut_11 },
10165 {icSig12colorData, Lut_12, Lut_12, Lut_12, Lut_12 },
10166 {icSig13colorData, Lut_13, Lut_13, Lut_13, Lut_13 },
10167 {icSig14colorData, Lut_14, Lut_14, Lut_14, Lut_14 },
10168 {icSig15colorData, Lut_15, Lut_15, Lut_15, Lut_15 },
10169 {icMaxEnumData, NULL, NULL, NULL, NULL }
10170 };
10171
10172 /* Find appropriate conversion functions */
10173 /* given the color space and Lut type */
10174 /* Return 0 on success, 1 on match failure */
10175 /* NOTE: doesn't set error value, message etc.! */
10176 static int getNormFunc(
10177 icColorSpaceSignature csig,
10178 icTagTypeSignature tagSig,
10179 icmNormFlag flag,
10180 void (**nfunc)(double *out, double *in)
10181 ) {
10182 int i;
10183 for (i = 0; colnormtable[i].csig != icMaxEnumData; i++) {
10184 if (colnormtable[i].csig == csig)
10185 break; /* Found it */
10186 }
10187 if (colnormtable[i].csig == icMaxEnumData) { /* Oops */
10188 *nfunc = NULL;
10189 return 1;
10190 }
10191
10192 if (flag == icmFromLuti || flag == icmFromLutv) { /* Table index/value decoding functions */
10193 if (tagSig == icSigLut8Type) {
10194 *nfunc = colnormtable[i].fromLut8;
10195 return 0;
10196 } else if (tagSig == icSigLut16Type) {
10197 *nfunc = colnormtable[i].fromLut16;
10198 return 0;
10199 } else {
10200 *nfunc = NULL;
10201 return 1;
10202 }
10203 } else if (flag == icmToLuti || flag == icmToLutv) { /* Table index/value encoding functions */
10204 if (tagSig == icSigLut8Type) {
10205 *nfunc = colnormtable[i].toLut8;
10206 return 0;
10207 } else if (tagSig == icSigLut16Type) {
10208 *nfunc = colnormtable[i].toLut16;
10209 return 0;
10210 } else {
10211 *nfunc = NULL;
10212 return 1;
10213 }
10214 } else {
10215 *nfunc = NULL;
10216 return 1;
10217 }
10218 return 0;
10219 }
10220
10221 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10222 /* Colorspace ranges - used instead of norm/denorm by Mono & Matrix */
10223
10224 /* Function table - match ranges to color spaces. */
10225 /* Anything not here, we don't know how to convert. */
10226 /* (ie. YCbCr) */
10227 static struct {
10228 icColorSpaceSignature csig;
10229 int same; /* Non zero if first entry applies to all channels */
10230 double min[15]; /* Minimum value for this colorspace */
10231 double max[15]; /* Maximum value for this colorspace */
10232 } colorrangetable[] = {
10233 {icSigXYZData, 1, { 0.0 } , { 1.0 + 32767.0/32768.0 } },
10234 {icSigLabData, 0, { 0.0, -128.0, -128.0 },
10235 { 100.0 + 25500.0/65280.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
10236 {icSigLuvData, 0, { 0.0, -128.0, -128.0 },
10237 { 100.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
10238 {icSigYxyData, 1, { 0.0 }, { 1.0 } },
10239 {icSigRgbData, 1, { 0.0 }, { 1.0 } },
10240 {icSigGrayData, 1, { 0.0 }, { 1.0 } },
10241 {icSigHsvData, 1, { 0.0 }, { 1.0 } },
10242 {icSigHlsData, 1, { 0.0 }, { 1.0 } },
10243 {icSigCmykData, 1, { 0.0 }, { 1.0 } },
10244 {icSigCmyData, 1, { 0.0 }, { 1.0 } },
10245 {icSigMch6Data, 1, { 0.0 }, { 1.0 } },
10246 {icSig2colorData, 1, { 0.0 }, { 1.0 } },
10247 {icSig3colorData, 1, { 0.0 }, { 1.0 } },
10248 {icSig4colorData, 1, { 0.0 }, { 1.0 } },
10249 {icSig5colorData, 1, { 0.0 }, { 1.0 } },
10250 {icSig6colorData, 1, { 0.0 }, { 1.0 } },
10251 {icSig7colorData, 1, { 0.0 }, { 1.0 } },
10252 {icSig8colorData, 1, { 0.0 }, { 1.0 } },
10253 {icSig9colorData, 1, { 0.0 }, { 1.0 } },
10254 {icSig10colorData, 1, { 0.0 }, { 1.0 } },
10255 {icSig11colorData, 1, { 0.0 }, { 1.0 } },
10256 {icSig12colorData, 1, { 0.0 }, { 1.0 } },
10257 {icSig13colorData, 1, { 0.0 }, { 1.0 } },
10258 {icSig14colorData, 1, { 0.0 }, { 1.0 } },
10259 {icSig15colorData, 1, { 0.0 }, { 1.0 } },
10260 {icMaxEnumData }
10261 };
10262
10263 /* Find appropriate typical encoding ranges for a */
10264 /* colorspace given the color space. */
10265 /* Return 0 on success, 1 on match failure */
10266 static int getRange(
10267 icColorSpaceSignature csig,
10268 double *min, double *max
10269 ) {
10270 int i, e, ee;
10271 for (i = 0; colorrangetable[i].csig != icMaxEnumData; i++) {
10272 if (colorrangetable[i].csig == csig)
10273 break; /* Found it */
10274 }
10275 if (colorrangetable[i].csig == icMaxEnumData) { /* Oops */
10276 return 1;
10277 }
10278 ee = number_ColorSpaceSignature(csig); /* Get number of components */
10279
10280 if (colorrangetable[i].same) { /* All channels are the same */
10281 for (e = 0; e < ee; e++) {
10282 if (min != NULL)
10283 min[e] = colorrangetable[i].min[0];
10284 if (max != NULL)
10285 max[e] = colorrangetable[i].max[0];
10286 }
10287 } else {
10288 for (e = 0; e < ee; e++) {
10289 if (min != NULL)
10290 min[e] = colorrangetable[i].min[e];
10291 if (max != NULL)
10292 max[e] = colorrangetable[i].max[e];
10293 }
10294 }
10295 return 0;
10296 }
10297
10298 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10299
10300 /*
10301 Matrix Inversion
10302 by Richard Carling
10303 from "Graphics Gems", Academic Press, 1990
10304 */
10305
10306 /*
10307 * adjoint( original_matrix, inverse_matrix )
10308 *
10309 * calculate the adjoint of a 3x3 matrix
10310 *
10311 * Let a denote the minor determinant of matrix A obtained by
10312 * ij
10313 *
10314 * deleting the ith row and jth column from A.
10315 *
10316 * i+j
10317 * Let b = (-1) a
10318 * ij ji
10319 *
10320 * The matrix B = (b ) is the adjoint of A
10321 * ij
10322 */
10323
10324 #define det2x2(a, b, c, d) (a * d - b * c)
10325
10326 static void adjoint(
10327 double out[3][3],
10328 double in[3][3]
10329 ) {
10330 double a1, a2, a3, b1, b2, b3, c1, c2, c3;
10331
10332 /* assign to individual variable names to aid */
10333 /* selecting correct values */
10334
10335 a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
10336 a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
10337 a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
10338
10339 /* row column labeling reversed since we transpose rows & columns */
10340
10341 out[0][0] = det2x2(b2, b3, c2, c3);
10342 out[1][0] = - det2x2(a2, a3, c2, c3);
10343 out[2][0] = det2x2(a2, a3, b2, b3);
10344
10345 out[0][1] = - det2x2(b1, b3, c1, c3);
10346 out[1][1] = det2x2(a1, a3, c1, c3);
10347 out[2][1] = - det2x2(a1, a3, b1, b3);
10348
10349 out[0][2] = det2x2(b1, b2, c1, c2);
10350 out[1][2] = - det2x2(a1, a2, c1, c2);
10351 out[2][2] = det2x2(a1, a2, b1, b2);
10352 }
10353
10354 /*
10355 * double = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 )
10356 *
10357 * calculate the determinant of a 3x3 matrix
10358 * in the form
10359 *
10360 * | a1, b1, c1 |
10361 * | a2, b2, c2 |
10362 * | a3, b3, c3 |
10363 */
10364
10365 static double det3x3(double in[3][3]) {
10366 double a1, a2, a3, b1, b2, b3, c1, c2, c3;
10367 double ans;
10368
10369 a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
10370 a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
10371 a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
10372
10373 ans = a1 * det2x2(b2, b3, c2, c3)
10374 - b1 * det2x2(a2, a3, c2, c3)
10375 + c1 * det2x2(a2, a3, b2, b3);
10376 return ans;
10377 }
10378
10379 #define SMALL_NUMBER 1.e-8
10380 /*
10381 * inverse( original_matrix, inverse_matrix )
10382 *
10383 * calculate the inverse of a 4x4 matrix
10384 *
10385 * -1
10386 * A = ___1__ adjoint A
10387 * det A
10388 */
10389
10390 /* Return non-zero if not invertable */
10391 static int inverse3x3(
10392 double out[3][3],
10393 double in[3][3]
10394 ) {
10395 int i, j;
10396 double det;
10397
10398 /* calculate the 3x3 determinant
10399 * if the determinant is zero,
10400 * then the inverse matrix is not unique.
10401 */
10402 det = det3x3(in);
10403
10404 if ( fabs(det) < SMALL_NUMBER)
10405 return 1;
10406
10407 /* calculate the adjoint matrix */
10408 adjoint(out, in);
10409
10410 /* scale the adjoint matrix to get the inverse */
10411 for (i = 0; i < 3; i++)
10412 for(j = 0; j < 3; j++)
10413 out[i][j] /= det;
10414 return 0;
10415 }
10416
10417 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10418
10419 /* Multuply XYZ array by 3x3 transform matrix */
10420 static void icmMulBy3x3(double out[3], double mat[3][3], double in[3]) {
10421 double tt[3];
10422
10423 tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
10424 tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
10425 tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
10426
10427 out[0] = tt[0];
10428 out[1] = tt[1];
10429 out[2] = tt[2];
10430 }
10431
10432 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10433 /* CIE XYZ to perceptual Lab */
10434 void
10435 icmXYZ2Lab(icmXYZNumber *w, double *out, double *in) {
10436 double X = in[0], Y = in[1], Z = in[2];
10437 double x,y,z,fx,fy,fz;
10438 double L;
10439
10440 x = X/w->X;
10441 if (x > 0.008856451586)
10442 fx = pow(x,1.0/3.0);
10443 else
10444 fx = 7.787036979 * x + 16.0/116.0;
10445
10446 y = Y/w->Y;
10447 if (y > 0.008856451586) {
10448 fy = pow(y,1.0/3.0);
10449 L = 116.0 * fy - 16.0;
10450 } else {
10451 fy = 7.787036979 * y + 16.0/116.0;
10452 L = 903.2963058 * y;
10453 }
10454
10455 z = Z/w->Z;
10456 if (z > 0.008856451586)
10457 fz = pow(z,1.0/3.0);
10458 else
10459 fz = 7.787036979 * z + 16.0/116.0;
10460
10461 out[0] = L;
10462 out[1] = 500.0 * (fx - fy);
10463 out[2] = 200.0 * (fy - fz);
10464 }
10465
10466 /* Perceptual Lab to CIE XYZ */
10467 void
10468 icmLab2XYZ(icmXYZNumber *w, double *out, double *in) {
10469 double L = in[0], a = in[1], b = in[2];
10470 double x,y,z,fx,fy,fz;
10471
10472 if (L > 8.0) {
10473 fy = (L + 16.0)/116.0;
10474 y = pow(fy,3.0);
10475 } else {
10476 y = L/903.2963058;
10477 fy = 7.787036979 * y + 16.0/116.0;
10478 }
10479
10480 fx = a/500.0 + fy;
10481 if (fx > 24.0/116.0)
10482 x = pow(fx,3.0);
10483 else
10484 x = (fx - 16.0/116.0)/7.787036979;
10485
10486 fz = fy - b/200.0;
10487 if (fz > 24.0/116.0)
10488 z = pow(fz,3.0);
10489 else
10490 z = (fz - 16.0/116.0)/7.787036979;
10491
10492 out[0] = x * w->X;
10493 out[1] = y * w->Y;
10494 out[2] = z * w->Z;
10495 }
10496
10497 /* available D50 Illuminant */
10498 icmXYZNumber icmD50 = { /* Profile illuminant - D50 */
10499 0.9642, 1.0000, 0.8249
10500 };
10501
10502 /* available D65 Illuminant */
10503 icmXYZNumber icmD65 = { /* Profile illuminant - D65 */
10504 0.9505, 1.0000, 1.0890
10505 };
10506
10507 /* Default black point */
10508 icmXYZNumber icmBlack = {
10509 0.0000, 0.0000, 0.0000
10510 };
10511
10512 /* Return the normal Delta E given two Lab values */
10513 double icmLabDE(double *Lab1, double *Lab2) {
10514 double rv = 0.0, tt;
10515
10516 tt = Lab1[0] - Lab2[0];
10517 rv += tt * tt;
10518 tt = Lab1[1] - Lab2[1];
10519 rv += tt * tt;
10520 tt = Lab1[2] - Lab2[2];
10521 rv += tt * tt;
10522
10523 return sqrt(rv);
10524 }
10525
10526 /* Return the normal Delta E squared, given two Lab values */
10527 double icmLabDEsq(double *Lab1, double *Lab2) {
10528 double rv = 0.0, tt;
10529
10530 tt = Lab1[0] - Lab2[0];
10531 rv += tt * tt;
10532 tt = Lab1[1] - Lab2[1];
10533 rv += tt * tt;
10534 tt = Lab1[2] - Lab2[2];
10535 rv += tt * tt;
10536
10537 return rv;
10538 }
10539
10540 /* Return the CIE94 Delta E color difference measure */
10541 double icmCIE94(double Lab1[3], double Lab2[3]) {
10542 double desq, dhsq;
10543 double dlsq, dcsq;
10544 double c12;
10545
10546 {
10547 double dl, da, db;
10548 dl = Lab1[0] - Lab2[0];
10549 dlsq = dl * dl; /* dl squared */
10550 da = Lab1[1] - Lab2[1];
10551 db = Lab1[2] - Lab2[2];
10552
10553 /* Compute normal Lab delta E squared */
10554 desq = dlsq + da * da + db * db;
10555 }
10556
10557 {
10558 double c1, c2, dc;
10559
10560 /* Compute chromanance for the two colors */
10561 c1 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
10562 c2 = sqrt(Lab2[1] * Lab2[1] + Lab2[2] * Lab2[2]);
10563 c12 = sqrt(c1 * c2); /* Symetric chromanance */
10564
10565 /* delta chromanance squared */
10566 dc = c2 - c1;
10567 dcsq = dc * dc;
10568 }
10569
10570 /* Compute delta hue squared */
10571 if ((dhsq = desq - dlsq - dcsq) < 0.0)
10572 dhsq = 0.0;
10573
10574 {
10575 double sc, sh;
10576
10577 /* Weighting factors for delta chromanance & delta hue */
10578 sc = 1.0 + 0.048 * c12;
10579 sh = 1.0 + 0.014 * c12;
10580
10581 return sqrt(dlsq + dcsq/(sc * sc) + dhsq/(sh * sh));
10582 }
10583 }
10584
10585 /* Return the CIE94 Delta E color difference measure, squared */
10586 double icmCIE94sq(double Lab1[3], double Lab2[3]) {
10587 double desq, dhsq;
10588 double dlsq, dcsq;
10589 double c12;
10590
10591 {
10592 double dl, da, db;
10593 dl = Lab1[0] - Lab2[0];
10594 dlsq = dl * dl; /* dl squared */
10595 da = Lab1[1] - Lab2[1];
10596 db = Lab1[2] - Lab2[2];
10597
10598 /* Compute normal Lab delta E squared */
10599 desq = dlsq + da * da + db * db;
10600 }
10601
10602 {
10603 double c1, c2, dc;
10604
10605 /* Compute chromanance for the two colors */
10606 c1 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
10607 c2 = sqrt(Lab2[1] * Lab2[1] + Lab2[2] * Lab2[2]);
10608 c12 = sqrt(c1 * c2); /* Symetric chromanance */
10609
10610 /* delta chromanance squared */
10611 dc = c2 - c1;
10612 dcsq = dc * dc;
10613 }
10614
10615 /* Compute delta hue squared */
10616 if ((dhsq = desq - dlsq - dcsq) < 0.0)
10617 dhsq = 0.0;
10618
10619 {
10620 double sc, sh;
10621
10622 /* Weighting factors for delta chromanance & delta hue */
10623 sc = 1.0 + 0.048 * c12;
10624 sh = 1.0 + 0.014 * c12;
10625
10626 return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
10627 }
10628 }
10629
10630 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10631
10632 /* Multiply one 3x3 with another */
10633 static void mul3x3(double dst[3][3], double src[3][3]) {
10634 int i, j, k;
10635 double td[3][3]; /* Temporary dest */
10636
10637 for (j = 0; j < 3; j++) {
10638 for (i = 0; i < 3; i++) {
10639 double tt = 0.0;
10640 for (k = 0; k < 3; k++)
10641 tt += src[j][k] * dst[k][i];
10642 td[j][i] = tt;
10643 }
10644 }
10645
10646 /* Copy result out */
10647 for (j = 0; j < 3; j++)
10648 for (i = 0; i < 3; i++)
10649 dst[j][i] = td[j][i];
10650 }
10651
10652 /* Chrmatic Adaption transform utility */
10653 /* Return a 3x3 chromatic adaption matrix */
10654 void icmChromAdaptMatrix(
10655 int flags,
10656 icmXYZNumber d_wp, /* Destination white point */
10657 icmXYZNumber s_wp, /* Source white point */
10658 double mat[3][3] /* Destination matrix */
10659 ) {
10660 double dst[3], src[3]; /* Source & destination white points */
10661 double vkmat[3][3]; /* Von Kries matrix */
10662 double bradford[3][3] = { /* Bradford cone space matrix */
10663 { 0.8951, 0.2664, -0.1614 },
10664 { -0.7502, 1.7135, 0.0367 },
10665 { 0.0389, -0.0685, 1.0296 }
10666 };
10667 double ibradford[3][3]; /* Inverse Bradford */
10668
10669 /* Set initial matrix to unity */
10670 if (!(flags & ICM_CAM_MULMATRIX)) {
10671 mat[0][0] = mat[1][1] = mat[2][2] = 1.0;
10672 mat[0][1] = mat[0][2] = 0.0;
10673 mat[1][0] = mat[1][2] = 0.0;
10674 mat[2][0] = mat[2][1] = 0.0;
10675 }
10676
10677 icmXYZ2Ary(src, s_wp);
10678 icmXYZ2Ary(dst, d_wp);
10679
10680 if (flags & ICM_CAM_BRADFORD) {
10681 icmMulBy3x3(src, bradford, src);
10682 icmMulBy3x3(dst, bradford, dst);
10683 }
10684
10685 /* Setup the Von Kries white point adaption matrix */
10686 vkmat[0][0] = dst[0]/src[0];
10687 vkmat[1][1] = dst[1]/src[1];
10688 vkmat[2][2] = dst[2]/src[2];
10689 vkmat[0][1] = vkmat[0][2] = 0.0;
10690 vkmat[1][0] = vkmat[1][2] = 0.0;
10691 vkmat[2][0] = vkmat[2][1] = 0.0;
10692
10693 /* Transform to Bradford space if requested */
10694 if (flags & ICM_CAM_BRADFORD) {
10695 mul3x3(mat, bradford);
10696 }
10697
10698 /* Apply chromatic adaption */
10699 mul3x3(mat, vkmat);
10700
10701 /* Transform from Bradford space */
10702 if (flags & ICM_CAM_BRADFORD) {
10703 inverse3x3(ibradford, bradford);
10704 mul3x3(mat, ibradford);
10705 }
10706
10707 /* We're done */
10708 }
10709
10710 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10711
10712 /* Return information about the native lut in/out colorspaces. */
10713 /* Any pointer may be NULL if value is not to be returned */
10714 static void
10715 icmLutSpaces(
10716 struct _icmLuBase *p, /* This */
10717 icColorSpaceSignature *ins, /* Return Native input color space */
10718 int *inn, /* Return number of input components */
10719 icColorSpaceSignature *outs, /* Return Native output color space */
10720 int *outn /* Return number of output components */
10721 ) {
10722 if (ins != NULL)
10723 *ins = p->inSpace;
10724 if (inn != NULL)
10725 *inn = (int)number_ColorSpaceSignature(p->inSpace);
10726
10727 if (outs != NULL)
10728 *outs = p->outSpace;
10729 if (outn != NULL)
10730 *outn = (int)number_ColorSpaceSignature(p->outSpace);
10731 }
10732
10733 /* Return information about the effective lookup in/out colorspaces, */
10734 /* including allowance for PCS overide. */
10735 /* Any pointer may be NULL if value is not to be returned */
10736 static void
10737 icmLuSpaces(
10738 struct _icmLuBase *p, /* This */
10739 icColorSpaceSignature *ins, /* Return effective input color space */
10740 int *inn, /* Return number of input components */
10741 icColorSpaceSignature *outs, /* Return effective output color space */
10742 int *outn, /* Return number of output components */
10743 icmLuAlgType *alg, /* Return type of lookup algorithm used */
10744 icRenderingIntent *intt, /* Return the intent being implented */
10745 icmLookupFunc *fnc, /* Return the profile function being implemented */
10746 icColorSpaceSignature *pcs /* Return the profile effective PCS */
10747 ) {
10748 if (ins != NULL)
10749 *ins = p->e_inSpace;
10750 if (inn != NULL)
10751 *inn = (int)number_ColorSpaceSignature(p->e_inSpace);
10752
10753 if (outs != NULL)
10754 *outs = p->e_outSpace;
10755 if (outn != NULL)
10756 *outn = (int)number_ColorSpaceSignature(p->e_outSpace);
10757
10758 if (alg != NULL)
10759 *alg = p->ttype;
10760
10761 if (intt != NULL)
10762 *intt = p->intent;
10763
10764 if (fnc != NULL)
10765 *fnc = p->function;
10766
10767 if (pcs != NULL)
10768 *pcs = p->e_pcs;
10769 }
10770
10771 /* Return the media white and black points in XYZ space. */
10772 /* Note that if not in the icc, the black point will be returned as 0, 0, 0 */
10773 /* Any pointer may be NULL if value is not to be returned */
10774 static void icmLuWh_bk_points(
10775 struct _icmLuBase *p,
10776 icmXYZNumber *wht,
10777 icmXYZNumber *blk
10778 ) {
10779 if (wht != NULL)
10780 *wht = p->whitePoint; /* Structure copy */
10781
10782 if (blk != NULL)
10783 *blk = p->blackPoint; /* Structure copy */
10784 }
10785
10786 /* Get the effective (externally visible) ranges for the Monochrome or Matrix profile */
10787 /* Arguments may be NULL */
10788 static void
10789 icmLu_get_ranges (
10790 struct _icmLuBase *p,
10791 double *inmin, double *inmax, /* Return maximum range of inspace values */
10792 double *outmin, double *outmax /* Return maximum range of outspace values */
10793 ) {
10794 /* Hmm. we have no way of handlin an error from getRange. */
10795 /* It shouldn't ever return one unless there is a mismatch between */
10796 /* getRange and Lu creation... */
10797 getRange(p->e_inSpace, inmin, inmax);
10798 getRange(p->e_outSpace, outmin, outmax);
10799 }
10800
10801 /* - - - - - - - - - - - - - - - - - - - - - - - - */
10802 /* Forward and Backward Monochrome type conversion */
10803 /* Return 0 on success, 1 if clipping occured, 2 on other error */
10804
10805 /* Individual components of Fwd conversion: */
10806
10807 /* Actual device to linearised device */
10808 static int
10809 icmLuMonoFwd_curve (
10810 icmLuMono *p, /* This */
10811 double *out, /* Vector of output values */
10812 double *in /* Vector of input values */
10813 ) {
10814 icc *icp = p->icp;
10815 int rv = 0;
10816
10817 /* Translate from device to PCS scale */
10818 if ((rv |= p->grayCurve->lookup_fwd(p->grayCurve,&out[0],&in[0])) > 1) {
10819 sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
10820 icp->errc = rv;
10821 return 2;
10822 }
10823
10824 return rv;
10825 }
10826
10827 /* Linearised device to relative PCS */
10828 static int
10829 icmLuMonoFwd_map (
10830 icmLuMono *p, /* This */
10831 double *out, /* Vector of output values (native space) */
10832 double *in /* Vector of input values (native space) */
10833 ) {
10834 int rv = 0;
10835 double Y = in[0]; /* In case out == in */
10836
10837 out[0] = p->pcswht.X;
10838 out[1] = p->pcswht.Y;
10839 out[2] = p->pcswht.Z;
10840 if (p->pcs == icSigLabData)
10841 icmXYZ2Lab(&p->pcswht, out, out); /* in Lab */
10842
10843 /* Scale linearized device level to PCS white */
10844 out[0] *= Y;
10845 out[1] *= Y;
10846 out[2] *= Y;
10847
10848 return rv;
10849 }
10850
10851 /* relative PCS to absolute PCS (if required) */
10852 static int
10853 icmLuMonoFwd_abs ( /* Abs comes last in Fwd conversion */
10854 icmLuMono *p, /* This */
10855 double *out, /* Vector of output values in Effective PCS */
10856 double *in /* Vector of input values in Native PCS */
10857 ) {
10858 int rv = 0;
10859
10860 if (out != in) {
10861 int i;
10862 for (i = 0; i < 3; i++) /* Don't alter input values */
10863 out[i] = in[i];
10864 }
10865
10866 /* Do absolute conversion */
10867 if (p->intent == icAbsoluteColorimetric) {
10868
10869 if (p->pcs == icSigLabData) /* Convert L to Y */
10870 icmLab2XYZ(&p->pcswht, out, out);
10871
10872 /* Convert from Relative to Absolute colorometric */
10873 icmMulBy3x3(out, p->toAbs, out);
10874
10875 if (p->e_pcs == icSigLabData)
10876 icmXYZ2Lab(&p->pcswht, out, out);
10877
10878 } else {
10879
10880 /* Convert from Native to Effective output space */
10881 if (p->pcs == icSigLabData && p->e_pcs == icSigXYZData)
10882 icmLab2XYZ(&p->pcswht, out, out);
10883 else if (p->pcs == icSigXYZData && p->e_pcs == icSigLabData)
10884 icmXYZ2Lab(&p->pcswht, out, out);
10885 }
10886
10887 return rv;
10888 }
10889
10890
10891 /* Overall Fwd conversion routine */
10892 static int
10893 icmLuMonoFwd_lookup (
10894 icmLuBase *pp, /* This */
10895 double *out, /* Vector of output values */
10896 double *in /* Input value */
10897 ) {
10898 int rv = 0;
10899 icmLuMono *p = (icmLuMono *)pp;
10900 rv |= icmLuMonoFwd_curve(p, out, in);
10901 rv |= icmLuMonoFwd_map(p, out, out);
10902 rv |= icmLuMonoFwd_abs(p, out, out);
10903 return rv;
10904 }
10905
10906
10907 /* Individual components of Bwd conversion: */
10908
10909 /* Convert from relative PCS to absolute PCS (if required) */
10910 static int
10911 icmLuMonoBwd_abs ( /* Abs comes first in Bwd conversion */
10912 icmLuMono *p, /* This */
10913 double *out, /* Vector of output values in Native PCS */
10914 double *in /* Vector of input values in Effective PCS */
10915 ) {
10916 int rv = 0;
10917
10918 if (out != in) {
10919 int i;
10920 for (i = 0; i < 3; i++) /* Don't alter input values */
10921 out[i] = in[i];
10922 }
10923
10924 /* Force to monochrome locus in correct space */
10925 if (p->e_pcs == icSigLabData) {
10926 double wp[3];
10927
10928 if (p->intent == icAbsoluteColorimetric) {
10929 wp[0] = p->whitePoint.X;
10930 wp[1] = p->whitePoint.Y;
10931 wp[2] = p->whitePoint.Z;
10932 } else {
10933 wp[0] = p->pcswht.X;
10934 wp[1] = p->pcswht.Y;
10935 wp[2] = p->pcswht.Z;
10936 }
10937 icmXYZ2Lab(&p->pcswht, wp, wp); /* Convert to Lab white point */
10938 out[1] = out[0]/wp[0] * wp[1];
10939 out[2] = out[0]/wp[0] * wp[2];
10940
10941 } else {
10942 if (p->intent == icAbsoluteColorimetric) {
10943 out[0] = out[1]/p->whitePoint.Y * p->whitePoint.X;
10944 out[2] = out[1]/p->whitePoint.Y * p->whitePoint.Z;
10945 } else {
10946 out[0] = out[1]/p->pcswht.Y * p->pcswht.X;
10947 out[2] = out[1]/p->pcswht.Y * p->pcswht.Z;
10948 }
10949 }
10950
10951 /* Do absolute conversion to */
10952 if (p->intent == icAbsoluteColorimetric) {
10953
10954 if (p->e_pcs == icSigLabData)
10955 icmLab2XYZ(&p->pcswht, out, out);
10956
10957 icmMulBy3x3(out, p->fromAbs, out);
10958
10959 /* Convert from Effective to Native input space */
10960 if (p->pcs == icSigLabData)
10961 icmXYZ2Lab(&p->pcswht, out, out);
10962
10963 } else {
10964
10965 /* Convert from Effective to Native input space */
10966 if (p->e_pcs == icSigLabData && p->pcs == icSigXYZData)
10967 icmLab2XYZ(&p->pcswht, out, out);
10968 else if (p->e_pcs == icSigXYZData && p->pcs == icSigLabData)
10969 icmXYZ2Lab(&p->pcswht, out, out);
10970 }
10971
10972 return rv;
10973 }
10974
10975 /* Map from relative PCS to linearised device */
10976 static int
10977 icmLuMonoBwd_map (
10978 icmLuMono *p, /* This */
10979 double *out, /* Output value */
10980 double *in /* Vector of input values (native space) */
10981 ) {
10982 int rv = 0;
10983 double pcsw[3];
10984
10985 pcsw[0] = p->pcswht.X;
10986 pcsw[1] = p->pcswht.Y;
10987 pcsw[2] = p->pcswht.Z;
10988 if (p->pcs == icSigLabData)
10989 icmXYZ2Lab(&p->pcswht, pcsw, pcsw); /* in Lab (should be 100.0!) */
10990
10991 /* Divide linearized device level into PCS white luminence */
10992 if (p->pcs == icSigLabData)
10993 out[0] = in[0]/pcsw[0];
10994 else
10995 out[0] = in[1]/pcsw[1];
10996
10997 return rv;
10998 }
10999
11000 /* Map from linearised device to actual device */
11001 static int
11002 icmLuMonoBwd_curve (
11003 icmLuMono *p, /* This */
11004 double *out, /* Output value */
11005 double *in /* Input value */
11006 ) {
11007 icc *icp = p->icp;
11008 int rv = 0;
11009
11010 /* Convert to device value through curve */
11011 if ((rv = p->grayCurve->lookup_bwd(p->grayCurve,&out[0],&in[0])) > 1) {
11012 sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
11013 icp->errc = rv;
11014 return 2;
11015 }
11016
11017 return rv;
11018 }
11019
11020 /* Overall Bwd conversion routine */
11021 static int
11022 icmLuMonoBwd_lookup (
11023 icmLuBase *pp, /* This */
11024 double *out, /* Output value */
11025 double *in /* Vector of input values */
11026 ) {
11027 double temp[3];
11028 int rv = 0;
11029 icmLuMono *p = (icmLuMono *)pp;
11030 rv |= icmLuMonoBwd_abs(p, temp, in);
11031 rv |= icmLuMonoBwd_map(p, out, temp);
11032 rv |= icmLuMonoBwd_curve(p, out, out);
11033 return rv;
11034 }
11035
11036 static void
11037 icmLuMono_delete(
11038 icmLuBase *p
11039 ) {
11040 icc *icp = p->icp;
11041
11042 icp->al->free(icp->al, p);
11043 }
11044
11045 static icmLuBase *
11046 new_icmLuMono(
11047 struct _icc *icp,
11048 icColorSpaceSignature inSpace, /* Native Input color space */
11049 icColorSpaceSignature outSpace, /* Native Output color space */
11050 icColorSpaceSignature pcs, /* Native PCS */
11051 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11052 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11053 icColorSpaceSignature e_pcs, /* Effective PCS */
11054 icmXYZNumber whitePoint, /* Profile absolute white point */
11055 icmXYZNumber blackPoint, /* Profile absolute black point */
11056 icRenderingIntent intent, /* Rendering intent */
11057 icmLookupFunc func, /* Functionality requested */
11058 int dir /* 0 = fwd, 1 = bwd */
11059 ) {
11060 icmLuMono *p;
11061
11062 if ((p = (icmLuMono *) icp->al->calloc(icp->al,1,sizeof(icmLuMono))) == NULL)
11063 return NULL;
11064 p->icp = icp;
11065 p->del = icmLuMono_delete;
11066 p->lutspaces= icmLutSpaces;
11067 p->spaces = icmLuSpaces;
11068 p->get_ranges = icmLu_get_ranges;
11069 p->wh_bk_points = icmLuWh_bk_points;
11070 p->fwd_lookup = icmLuMonoFwd_lookup;
11071 p->fwd_curve = icmLuMonoFwd_curve;
11072 p->fwd_map = icmLuMonoFwd_map;
11073 p->fwd_abs = icmLuMonoFwd_abs;
11074 p->bwd_lookup = icmLuMonoBwd_lookup;
11075 p->bwd_abs = icmLuMonoFwd_abs;
11076 p->bwd_map = icmLuMonoFwd_map;
11077 p->bwd_curve = icmLuMonoFwd_curve;
11078 if (dir) {
11079 p->ttype = icmMonoBwdType;
11080 p->lookup = icmLuMonoBwd_lookup;
11081 } else {
11082 p->ttype = icmMonoFwdType;
11083 p->lookup = icmLuMonoFwd_lookup;
11084 }
11085
11086 /* See if the color spaces are appropriate for the mono type */
11087 if (number_ColorSpaceSignature(icp->header->colorSpace) != 1
11088 || ( icp->header->pcs != icSigXYZData && icp->header->pcs != icSigLabData)) {
11089 p->del((icmLuBase *)p);
11090 return NULL;
11091 }
11092
11093 /* Find the appropriate tags */
11094 if ((p->grayCurve = (icmCurve *)icp->read_tag(icp, icSigGrayTRCTag)) == NULL
11095 || p->grayCurve->ttype != icSigCurveType) {
11096 p->del((icmLuBase *)p);
11097 return NULL;
11098 }
11099
11100 p->pcswht = icp->header->illuminant;
11101 p->whitePoint = whitePoint;
11102 p->blackPoint = blackPoint;
11103 p->intent = intent;
11104 p->function = func;
11105 p->inSpace = inSpace;
11106 p->outSpace = outSpace;
11107 p->pcs = pcs;
11108 p->e_inSpace = e_inSpace;
11109 p->e_outSpace = e_outSpace;
11110 p->e_pcs = e_pcs;
11111
11112 /* Create absolute <-> relative conversion matricies */
11113 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
11114 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs);
11115
11116 return (icmLuBase *)p;
11117 }
11118
11119 static icmLuBase *
11120 new_icmLuMonoFwd(
11121 struct _icc *icp,
11122 icColorSpaceSignature inSpace, /* Native Input color space */
11123 icColorSpaceSignature outSpace, /* Native Output color space */
11124 icColorSpaceSignature pcs, /* Native PCS */
11125 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11126 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11127 icColorSpaceSignature e_pcs, /* Effective PCS */
11128 icmXYZNumber whitePoint, /* Profile absolute white point */
11129 icmXYZNumber blackPoint, /* Profile absolute black point */
11130 icRenderingIntent intent, /* Rendering intent */
11131 icmLookupFunc func /* Functionality requested */
11132 ) {
11133 return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11134 whitePoint, blackPoint, intent, func, 0);
11135 }
11136
11137
11138 static icmLuBase *
11139 new_icmLuMonoBwd(
11140 struct _icc *icp,
11141 icColorSpaceSignature inSpace, /* Native Input color space */
11142 icColorSpaceSignature outSpace, /* Native Output color space */
11143 icColorSpaceSignature pcs, /* Native PCS */
11144 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11145 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11146 icColorSpaceSignature e_pcs, /* Effective PCS */
11147 icmXYZNumber whitePoint, /* Profile absolute white point */
11148 icmXYZNumber blackPoint, /* Profile absolute black point */
11149 icRenderingIntent intent, /* Rendering intent */
11150 icmLookupFunc func /* Functionality requested */
11151 ) {
11152 return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11153 whitePoint, blackPoint, intent, func, 1);
11154 }
11155
11156 /* - - - - - - - - - - - - - - - - - - - - - - - */
11157 /* Forward and Backward Matrix type conversion */
11158 /* Return 0 on success, 1 if clipping occured, 2 on other error */
11159
11160 /* Individual components of Fwd conversion: */
11161 static int
11162 icmLuMatrixFwd_curve (
11163 icmLuMatrix *p, /* This */
11164 double *out, /* Vector of output values */
11165 double *in /* Vector of input values */
11166 ) {
11167 icc *icp = p->icp;
11168 int rv = 0;
11169
11170 /* Curve lookups */
11171 if ((rv |= p->redCurve->lookup_fwd( p->redCurve, &out[0],&in[0])) > 1
11172 || (rv |= p->greenCurve->lookup_fwd(p->greenCurve,&out[1],&in[1])) > 1
11173 || (rv |= p->blueCurve->lookup_fwd( p->blueCurve, &out[2],&in[2])) > 1) {
11174 sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
11175 icp->errc = rv;
11176 return 2;
11177 }
11178
11179 return rv;
11180 }
11181
11182 static int
11183 icmLuMatrixFwd_matrix (
11184 icmLuMatrix *p, /* This */
11185 double *out, /* Vector of output values */
11186 double *in /* Vector of input values */
11187 ) {
11188 int rv = 0;
11189 double tt[3];
11190
11191 /* Matrix */
11192 tt[0] = p->mx[0][0] * in[0] + p->mx[0][1] * in[1] + p->mx[0][2] * in[2];
11193 tt[1] = p->mx[1][0] * in[0] + p->mx[1][1] * in[1] + p->mx[1][2] * in[2];
11194 tt[2] = p->mx[2][0] * in[0] + p->mx[2][1] * in[1] + p->mx[2][2] * in[2];
11195
11196 out[0] = tt[0];
11197 out[1] = tt[1];
11198 out[2] = tt[2];
11199
11200 return rv;
11201 }
11202
11203 static int
11204 icmLuMatrixFwd_abs (/* Abs comes last in Fwd conversion */
11205 icmLuMatrix *p, /* This */
11206 double *out, /* Vector of output values */
11207 double *in /* Vector of input values */
11208 ) {
11209 int rv = 0;
11210
11211 if (out != in) {
11212 int i;
11213 for (i = 0; i < 3; i++) /* Don't alter input values */
11214 out[i] = in[i];
11215 }
11216
11217 /* If required, convert from Relative to Absolute colorometric */
11218 if (p->intent == icAbsoluteColorimetric) {
11219 icmMulBy3x3(out, p->toAbs, out);
11220 }
11221
11222 /* If e_pcs is Lab, then convert XYZ to Lab */
11223 if (p->e_pcs == icSigLabData)
11224 icmXYZ2Lab(&p->pcswht, out, out);
11225
11226 return rv;
11227 }
11228
11229
11230 /* Overall Fwd conversion */
11231 static int
11232 icmLuMatrixFwd_lookup (
11233 icmLuBase *pp, /* This */
11234 double *out, /* Vector of output values */
11235 double *in /* Vector of input values */
11236 ) {
11237 int rv = 0;
11238 icmLuMatrix *p = (icmLuMatrix *)pp;
11239 rv |= icmLuMatrixFwd_curve(p, out, in);
11240 rv |= icmLuMatrixFwd_matrix(p, out, out);
11241 rv |= icmLuMatrixFwd_abs(p, out, out);
11242 return rv;
11243 }
11244
11245 /* Individual components of Bwd conversion: */
11246
11247 static int
11248 icmLuMatrixBwd_abs (/* Abs comes first in Bwd conversion */
11249 icmLuMatrix *p, /* This */
11250 double *out, /* Vector of output values */
11251 double *in /* Vector of input values */
11252 ) {
11253 int rv = 0;
11254
11255 if (out != in) {
11256 int i;
11257 for (i = 0; i < 3; i++) /* Don't alter input values */
11258 out[i] = in[i];
11259 }
11260
11261 /* If e_pcs is Lab, then convert Lab to XYZ */
11262 if (p->e_pcs == icSigLabData)
11263 icmLab2XYZ(&p->pcswht, out, out);
11264
11265 /* If required, convert from Absolute to Relative colorometric */
11266 if (p->intent == icAbsoluteColorimetric) {
11267 icmMulBy3x3(out, p->fromAbs, out);
11268 }
11269
11270 return rv;
11271 }
11272
11273 static int
11274 icmLuMatrixBwd_matrix (
11275 icmLuMatrix *p, /* This */
11276 double *out, /* Vector of output values */
11277 double *in /* Vector of input values */
11278 ) {
11279 int rv = 0;
11280 double tt[3];
11281
11282 /* Matrix */
11283 tt[0] = p->bmx[0][0] * in[0] + p->bmx[0][1] * in[1] + p->bmx[0][2] * in[2];
11284 tt[1] = p->bmx[1][0] * in[0] + p->bmx[1][1] * in[1] + p->bmx[1][2] * in[2];
11285 tt[2] = p->bmx[2][0] * in[0] + p->bmx[2][1] * in[1] + p->bmx[2][2] * in[2];
11286
11287 out[0] = tt[0];
11288 out[1] = tt[1];
11289 out[2] = tt[2];
11290
11291 return rv;
11292 }
11293
11294 static int
11295 icmLuMatrixBwd_curve (
11296 icmLuMatrix *p, /* This */
11297 double *out, /* Vector of output values */
11298 double *in /* Vector of input values */
11299 ) {
11300 icc *icp = p->icp;
11301 int rv = 0;
11302
11303 /* Curves */
11304 if ((rv |= p->redCurve->lookup_bwd(p->redCurve,&out[0],&out[0])) > 1
11305 || (rv |= p->greenCurve->lookup_bwd(p->greenCurve,&out[1],&out[1])) > 1
11306 || (rv |= p->blueCurve->lookup_bwd(p->blueCurve,&out[2],&out[2])) > 1) {
11307 sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
11308 icp->errc = rv;
11309 return 2;
11310 }
11311 return rv;
11312 }
11313
11314 /* Overall Bwd conversion */
11315 static int
11316 icmLuMatrixBwd_lookup (
11317 icmLuBase *pp, /* This */
11318 double *out, /* Vector of output values */
11319 double *in /* Vector of input values */
11320 ) {
11321 int rv = 0;
11322 icmLuMatrix *p = (icmLuMatrix *)pp;
11323 rv |= icmLuMatrixBwd_abs(p, out, in);
11324 rv |= icmLuMatrixBwd_matrix(p, out, out);
11325 rv |= icmLuMatrixBwd_curve(p, out, out);
11326 return rv;
11327 }
11328
11329 static void
11330 icmLuMatrix_delete(
11331 icmLuBase *p
11332 ) {
11333 icc *icp = p->icp;
11334
11335 icp->al->free(icp->al, p);
11336 }
11337
11338 /* We setup valid fwd and bwd component conversions, */
11339 /* but setup only the asked for overal conversion. */
11340 static icmLuBase *
11341 new_icmLuMatrix(
11342 struct _icc *icp,
11343 icColorSpaceSignature inSpace, /* Native Input color space */
11344 icColorSpaceSignature outSpace, /* Native Output color space */
11345 icColorSpaceSignature pcs, /* Native PCS */
11346 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11347 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11348 icColorSpaceSignature e_pcs, /* Effective PCS */
11349 icmXYZNumber whitePoint, /* Profile absolute white point */
11350 icmXYZNumber blackPoint, /* Profile absolute black point */
11351 icRenderingIntent intent, /* Rendering intent */
11352 icmLookupFunc func, /* Functionality requested */
11353 int dir /* 0 = fwd, 1 = bwd */
11354 ) {
11355 icmLuMatrix *p;
11356
11357 if ((p = (icmLuMatrix *) icp->al->calloc(icp->al,1,sizeof(icmLuMatrix))) == NULL)
11358 return NULL;
11359 p->icp = icp;
11360 p->del = icmLuMatrix_delete;
11361 p->lutspaces= icmLutSpaces;
11362 p->spaces = icmLuSpaces;
11363 p->get_ranges = icmLu_get_ranges;
11364 p->wh_bk_points = icmLuWh_bk_points;
11365 p->fwd_lookup = icmLuMatrixFwd_lookup;
11366 p->fwd_curve = icmLuMatrixFwd_curve;
11367 p->fwd_matrix = icmLuMatrixFwd_matrix;
11368 p->fwd_abs = icmLuMatrixFwd_abs;
11369 p->bwd_lookup = icmLuMatrixBwd_lookup;
11370 p->bwd_abs = icmLuMatrixBwd_abs;
11371 p->bwd_matrix = icmLuMatrixBwd_matrix;
11372 p->bwd_curve = icmLuMatrixBwd_curve;
11373 if (dir) {
11374 p->ttype = icmMatrixBwdType;
11375 p->lookup = icmLuMatrixBwd_lookup;
11376 } else {
11377 p->ttype = icmMatrixFwdType;
11378 p->lookup = icmLuMatrixFwd_lookup;
11379 }
11380
11381 /* Note that we can use matrix type even if PCS is Lab, */
11382 /* by simply converting it. */
11383
11384 /* Find the appropriate tags */
11385 if ((p->redCurve = (icmCurve *)icp->read_tag(icp, icSigRedTRCTag)) == NULL
11386 || p->redCurve->ttype != icSigCurveType
11387 || (p->greenCurve = (icmCurve *)icp->read_tag(icp, icSigGreenTRCTag)) == NULL
11388 || p->greenCurve->ttype != icSigCurveType
11389 || (p->blueCurve = (icmCurve *)icp->read_tag(icp, icSigBlueTRCTag)) == NULL
11390 || p->blueCurve->ttype != icSigCurveType
11391 || (p->redColrnt = (icmXYZArray *)icp->read_tag(icp, icSigRedColorantTag)) == NULL
11392 || p->redColrnt->ttype != icSigXYZType || p->redColrnt->size < 1
11393 || (p->greenColrnt = (icmXYZArray *)icp->read_tag(icp, icSigGreenColorantTag)) == NULL
11394 || p->greenColrnt->ttype != icSigXYZType || p->greenColrnt->size < 1
11395 || (p->blueColrnt = (icmXYZArray *)icp->read_tag(icp, icSigBlueColorantTag)) == NULL
11396 || p->blueColrnt->ttype != icSigXYZType || p->blueColrnt->size < 1) {
11397 p->del((icmLuBase *)p);
11398 return NULL;
11399 }
11400
11401 /* Setup the matrix */
11402 p->mx[0][0] = p->redColrnt->data[0].X;
11403 p->mx[0][1] = p->greenColrnt->data[0].X;
11404 p->mx[0][2] = p->blueColrnt->data[0].X;
11405 p->mx[1][1] = p->greenColrnt->data[0].Y;
11406 p->mx[1][0] = p->redColrnt->data[0].Y;
11407 p->mx[1][2] = p->blueColrnt->data[0].Y;
11408 p->mx[2][1] = p->greenColrnt->data[0].Z;
11409 p->mx[2][0] = p->redColrnt->data[0].Z;
11410 p->mx[2][2] = p->blueColrnt->data[0].Z;
11411
11412 if (inverse3x3(p->bmx, p->mx) != 0) { /* Compute inverse */
11413 sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
11414 icp->errc = 2;
11415 p->del((icmLuBase *)p);
11416 return NULL;
11417 }
11418
11419 p->pcswht = icp->header->illuminant;
11420 p->whitePoint = whitePoint;
11421 p->blackPoint = blackPoint;
11422 p->intent = intent;
11423 p->function = func;
11424 p->inSpace = inSpace;
11425 p->outSpace = outSpace;
11426 p->pcs = pcs;
11427 p->e_inSpace = e_inSpace;
11428 p->e_outSpace = e_outSpace;
11429 p->e_pcs = e_pcs;
11430
11431 /* Create absolute <-> relative conversion matricies */
11432 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
11433 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs);
11434
11435 return (icmLuBase *)p;
11436 }
11437
11438 static icmLuBase *
11439 new_icmLuMatrixFwd(
11440 struct _icc *icp,
11441 icColorSpaceSignature inSpace, /* Native Input color space */
11442 icColorSpaceSignature outSpace, /* Native Output color space */
11443 icColorSpaceSignature pcs, /* Native PCS */
11444 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11445 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11446 icColorSpaceSignature e_pcs, /* Effective PCS */
11447 icmXYZNumber whitePoint, /* Profile absolute white point */
11448 icmXYZNumber blackPoint, /* Profile absolute black point */
11449 icRenderingIntent intent, /* Rendering intent */
11450 icmLookupFunc func /* Functionality requested */
11451 ) {
11452 return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11453 whitePoint, blackPoint, intent, func, 0);
11454 }
11455
11456
11457 static icmLuBase *
11458 new_icmLuMatrixBwd(
11459 struct _icc *icp,
11460 icColorSpaceSignature inSpace, /* Native Input color space */
11461 icColorSpaceSignature outSpace, /* Native Output color space */
11462 icColorSpaceSignature pcs, /* Native PCS */
11463 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11464 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11465 icColorSpaceSignature e_pcs, /* Effective PCS */
11466 icmXYZNumber whitePoint, /* Profile absolute white point */
11467 icmXYZNumber blackPoint, /* Profile absolute black point */
11468 icRenderingIntent intent, /* Rendering intent */
11469 icmLookupFunc func /* Functionality requested */
11470 ) {
11471 return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11472 whitePoint, blackPoint, intent, func, 1);
11473 }
11474
11475 /* - - - - - - - - - - - - - - - - - - - - - - - */
11476 /* Forward and Backward Multi-Dimensional Interpolation type conversion */
11477 /* Return 0 on success, 1 if clipping occured, 2 on other error */
11478
11479 /* Components of overall lookup, in order */
11480 static int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) {
11481 icmLut *lut = p->lut;
11482 int rv = 0;
11483
11484 if (out != in) {
11485 int i;
11486 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
11487 out[i] = in[i];
11488 }
11489
11490 /* If Bwd Lut, take care of Absolute color space and effective input space */
11491 if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
11492 && p->intent == icAbsoluteColorimetric) {
11493
11494 if (p->e_inSpace == icSigLabData)
11495 icmLab2XYZ(&p->pcswht, out, out);
11496
11497 /* Convert from Absolute to Relative colorometric */
11498 icmMulBy3x3(out, p->fromAbs, out);
11499
11500 if (p->inSpace == icSigLabData)
11501 icmXYZ2Lab(&p->pcswht, out, out);
11502
11503 } else {
11504
11505 /* Convert from Effective to Native input space */
11506 if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData)
11507 icmLab2XYZ(&p->pcswht, out, out);
11508 else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData)
11509 icmXYZ2Lab(&p->pcswht, out, out);
11510 }
11511
11512 return rv;
11513 }
11514
11515 /* Possible matrix lookup */
11516 static int icmLuLut_matrix(icmLuLut *p, double *out, double *in) {
11517 icmLut *lut = p->lut;
11518 int rv = 0;
11519
11520 if (p->usematrix)
11521 rv |= lut->lookup_matrix(lut,out,in);
11522 else if (out != in) {
11523 int i;
11524 for (i = 0; i < lut->inputChan; i++)
11525 out[i] = in[i];
11526 }
11527 return rv;
11528 }
11529
11530 /* Do input -> input' lookup */
11531 static int icmLuLut_input(icmLuLut *p, double *out, double *in) {
11532 icmLut *lut = p->lut;
11533 int rv = 0;
11534
11535 p->in_normf(out, in); /* Normalize from input color space */
11536 rv |= lut->lookup_input(lut,out,out); /* Lookup though input tables */
11537 p->in_denormf(out,out); /* De-normalize to input color space */
11538 return rv;
11539 }
11540
11541 /* Do input'->output' lookup */
11542 static int icmLuLut_clut(icmLuLut *p, double *out, double *in) {
11543 icmLut *lut = p->lut;
11544 double temp[MAX_CHAN];
11545 int rv = 0;
11546
11547 p->in_normf(temp, in); /* Normalize from input color space */
11548 rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
11549 p->out_denormf(out,out); /* De-normalize to output color space */
11550 return rv;
11551 }
11552
11553 /* Do output'->output lookup */
11554 static int icmLuLut_output(icmLuLut *p, double *out, double *in) {
11555 icmLut *lut = p->lut;
11556 int rv = 0;
11557
11558 p->out_normf(out,in); /* Normalize from output color space */
11559 rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
11560 p->out_denormf(out, out); /* De-normalize to output color space */
11561 return rv;
11562 }
11563
11564 static int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) {
11565 icmLut *lut = p->lut;
11566 int rv = 0;
11567
11568 if (out != in) {
11569 int i;
11570 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
11571 out[i] = in[i];
11572 }
11573
11574 /* If Fwd Lut, take care of Absolute color space */
11575 /* and convert from native to effective out PCS */
11576 if ((p->function == icmFwd || p->function == icmPreview)
11577 && p->intent == icAbsoluteColorimetric) {
11578
11579 if (p->outSpace == icSigLabData)
11580 icmLab2XYZ(&p->pcswht, out, out);
11581
11582 /* Convert from Relative to Absolute colorometric XYZ */
11583 icmMulBy3x3(out, p->toAbs, out);
11584
11585 if (p->e_outSpace == icSigLabData)
11586 icmXYZ2Lab(&p->pcswht, out, out);
11587 } else {
11588
11589 /* Convert from Native to Effective output space */
11590 if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData)
11591 icmLab2XYZ(&p->pcswht, out, out);
11592 else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData)
11593 icmXYZ2Lab(&p->pcswht, out, out);
11594 }
11595 return rv;
11596 }
11597
11598
11599 /* Overall lookup */
11600 static int
11601 icmLuLut_lookup (
11602 icmLuBase *pp, /* This */
11603 double *out, /* Vector of output values */
11604 double *in /* Vector of input values */
11605 ) {
11606 int rv = 0;
11607 icmLuLut *p = (icmLuLut *)pp;
11608 icmLut *lut = p->lut;
11609 double temp[MAX_CHAN];
11610
11611 rv |= p->in_abs(p,temp,in); /* Possible absolute conversion */
11612 if (p->usematrix)
11613 rv |= lut->lookup_matrix(lut,temp,temp);/* If XYZ, multiply by non-unity matrix */
11614 p->in_normf(temp, temp); /* Normalize for input color space */
11615 rv |= lut->lookup_input(lut,temp,temp); /* Lookup though input tables */
11616 rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
11617 rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
11618 p->out_denormf(out,out); /* Normalize for output color space */
11619 rv |= p->out_abs(p,out,out); /* Possible absolute conversion */
11620
11621 return rv;
11622 }
11623
11624 #ifdef NEVER /* The following should be identical in effect to the above. */
11625
11626 /* Overall lookup */
11627 static int
11628 icmLuLut_lookup (
11629 icmLuBase *pp, /* This */
11630 double *out, /* Vector of output values */
11631 double *in /* Vector of input values */
11632 ) {
11633 int i, rv = 0;
11634 icmLuLut *p = (icmLuLut *)pp;
11635 icmLut *lut = p->lut;
11636 double temp[MAX_CHAN];
11637
11638 rv |= p->in_abs(p,temp,in);
11639 rv |= p->matrix(p,temp,temp);
11640 rv |= p->input(p,temp,temp);
11641 rv |= p->clut(p,out,temp);
11642 rv |= p->output(p,out,out);
11643 rv |= p->out_abs(p,out,out);
11644
11645 return rv;
11646 }
11647 #endif /* NEVER */
11648 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */
11649 /* Some components of inverse lookup, in order */
11650 /* ~~ should these be in icmLut (like all the fwd transforms)? */
11651
11652 static int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) {
11653 icmLut *lut = p->lut;
11654 int rv = 0;
11655
11656 if (out != in) {
11657 int i;
11658 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
11659 out[i] = in[i];
11660 }
11661
11662 /* If Fwd Lut, take care of Absolute color space */
11663 /* and convert from effective to native inverse output PCS */
11664 /* OutSpace must be PCS: XYZ or Lab */
11665 if ((p->function == icmFwd || p->function == icmPreview)
11666 && p->intent == icAbsoluteColorimetric) {
11667
11668 if (p->e_outSpace == icSigLabData)
11669 icmLab2XYZ(&p->pcswht, out, out);
11670
11671 /* Convert from Absolute to Relative colorometric */
11672 icmMulBy3x3(out, p->fromAbs, out);
11673
11674 if (p->outSpace == icSigLabData)
11675 icmXYZ2Lab(&p->pcswht, out, out);
11676
11677 } else {
11678
11679 /* Convert from Effective to Native output space */
11680 if (p->e_outSpace == icSigLabData && p->outSpace == icSigXYZData)
11681 icmLab2XYZ(&p->pcswht, out, out);
11682 else if (p->e_outSpace == icSigXYZData && p->outSpace == icSigLabData)
11683 icmXYZ2Lab(&p->pcswht, out, out);
11684 }
11685 return rv;
11686 }
11687
11688 /* Do output->output' inverse lookup */
11689 static int icmLuLut_inv_output(icmLuLut *p, double *out, double *in) {
11690 icc *icp = p->icp;
11691 icmLut *lut = p->lut;
11692 int rv = 0;
11693
11694 if (lut->rot.inited == 0) {
11695 rv = icmTable_setup_bwd(icp, &lut->rot, lut->outputEnt, lut->outputTable);
11696 if (rv != 0) {
11697 sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
11698 return icp->errc = rv;
11699 }
11700 }
11701
11702 p->out_normf(out,in); /* Normalize from output color space */
11703 rv |= icmTable_lookup_bwd(&lut->rot, out, out); /* Reverse lookup though output tables */
11704 p->out_denormf(out, out); /* De-normalize to output color space */
11705 return rv;
11706 }
11707
11708 /* No output' -> input inverse lookup. */
11709 /* This is non-trivial ! */
11710
11711 /* Do input' -> input inverse lookup */
11712 static int icmLuLut_inv_input(icmLuLut *p, double *out, double *in) {
11713 icc *icp = p->icp;
11714 icmLut *lut = p->lut;
11715 int rv = 0;
11716
11717 if (lut->rit.inited == 0) {
11718 rv = icmTable_setup_bwd(icp, &lut->rit, lut->inputEnt, lut->inputTable);
11719 if (rv != 0) {
11720 sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
11721 return icp->errc = rv;
11722 }
11723 }
11724
11725 p->in_normf(out, in); /* Normalize from input color space */
11726 rv |= icmTable_lookup_bwd(&lut->rit, out, out); /* Reverse lookup though input tables */
11727 p->in_denormf(out,out); /* De-normalize to input color space */
11728 return rv;
11729 }
11730
11731 /* Possible inverse matrix lookup */
11732 static int icmLuLut_inv_matrix(icmLuLut *p, double *out, double *in) {
11733 icc *icp = p->icp;
11734 icmLut *lut = p->lut;
11735 int rv = 0;
11736
11737 if (p->usematrix) {
11738 double tt[3];
11739 if (p->imx_valid == 0) {
11740 if (inverse3x3(p->imx, lut->e) != 0) { /* Compute inverse */
11741 sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
11742 icp->errc = 2;
11743 return 2;
11744 }
11745 p->imx_valid = 1;
11746 }
11747 /* Matrix multiply */
11748 tt[0] = p->imx[0][0] * in[0] + p->imx[0][1] * in[1] + p->imx[0][2] * in[2];
11749 tt[1] = p->imx[1][0] * in[0] + p->imx[1][1] * in[1] + p->imx[1][2] * in[2];
11750 tt[2] = p->imx[2][0] * in[0] + p->imx[2][1] * in[1] + p->imx[2][2] * in[2];
11751 out[0] = tt[0], out[1] = tt[1], out[2] = tt[2];
11752 } else if (out != in) {
11753 int i;
11754 for (i = 0; i < lut->inputChan; i++)
11755 out[i] = in[i];
11756 }
11757 return rv;
11758 }
11759
11760 static int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) {
11761 icmLut *lut = p->lut;
11762 int rv = 0;
11763
11764 if (out != in) {
11765 int i;
11766 for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
11767 out[i] = in[i];
11768 }
11769
11770 /* If Bwd Lut, take care of Absolute color space, and */
11771 /* convert from native to effective input space */
11772 if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
11773 && p->intent == icAbsoluteColorimetric) {
11774
11775 if (p->inSpace == icSigLabData)
11776 icmLab2XYZ(&p->pcswht, out, out);
11777
11778 /* Convert from Relative to Absolute colorometric XYZ */
11779 icmMulBy3x3(out, p->toAbs, out);
11780
11781 if (p->e_inSpace == icSigLabData)
11782 icmXYZ2Lab(&p->pcswht, out, out);
11783 } else {
11784
11785 /* Convert from Native to Effective input space */
11786 if (p->inSpace == icSigLabData && p->e_inSpace == icSigXYZData)
11787 icmLab2XYZ(&p->pcswht, out, out);
11788 else if (p->inSpace == icSigXYZData && p->e_inSpace == icSigLabData)
11789 icmXYZ2Lab(&p->pcswht, out, out);
11790 }
11791 return rv;
11792 }
11793
11794 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */
11795
11796 /* Return LuLut information */
11797 static void icmLuLut_get_info(
11798 icmLuLut *p, /* this */
11799 icmLut **lutp, /* Pointer to icc lut type */
11800 icmXYZNumber *pcswhtp, /* Pointer to profile PCS white point */
11801 icmXYZNumber *whitep, /* Pointer to profile absolute white point */
11802 icmXYZNumber *blackp /* Pointer to profile absolute black point */
11803 ) {
11804 if (lutp != NULL)
11805 *lutp = p->lut;
11806 if (pcswhtp != NULL)
11807 *pcswhtp = p->pcswht;
11808 if (whitep != NULL)
11809 *whitep = p->whitePoint;
11810 if (blackp != NULL)
11811 *blackp = p->blackPoint;
11812 }
11813
11814 /* Get the native ranges for the LuLut */
11815 static void
11816 icmLuLut_get_lutranges (
11817 struct _icmLuLut *p,
11818 double *inmin, double *inmax, /* Return maximum range of inspace values */
11819 double *outmin, double *outmax /* Return maximum range of outspace values */
11820 ) {
11821 int i;
11822
11823 for (i = 0; i < p->lut->inputChan; i++) {
11824 inmin[i] = 0.0; /* Normalized range of input space values */
11825 inmax[i] = 1.0;
11826 }
11827 p->in_denormf(inmin,inmin); /* Convert to real colorspace range */
11828 p->in_denormf(inmax,inmax);
11829
11830 /* Make sure min and max are so. */
11831 for (i = 0; i < p->lut->inputChan; i++) {
11832 if (inmin[i] > inmax[i]) {
11833 double tt;
11834 tt = inmin[i];
11835 inmin[i] = inmax[i];
11836 inmax[i] = tt;
11837 }
11838 }
11839
11840 for (i = 0; i < p->lut->outputChan; i++) {
11841 outmin[i] = 0.0; /* Normalized range of output space values */
11842 outmax[i] = 1.0;
11843 }
11844 p->out_denormf(outmin,outmin); /* Convert to real colorspace range */
11845 p->out_denormf(outmax,outmax);
11846
11847 /* Make sure min and max are so. */
11848 for (i = 0; i < p->lut->outputChan; i++) {
11849 if (outmin[i] > outmax[i]) {
11850 double tt;
11851 tt = outmin[i];
11852 outmin[i] = outmax[i];
11853 outmax[i] = tt;
11854 }
11855 }
11856 }
11857
11858 /* Get the effective (externally visible) ranges for the LuLut */
11859 /* Arguments may be NULL */
11860 static void
11861 icmLuLut_get_ranges (
11862 struct _icmLuBase *pp,
11863 double *inmin, double *inmax, /* Return maximum range of inspace values */
11864 double *outmin, double *outmax /* Return maximum range of outspace values */
11865 ) {
11866 icmLuLut *p = (icmLuLut *)pp;
11867 double tinmin[MAX_CHAN], tinmax[MAX_CHAN], toutmin[MAX_CHAN], toutmax[MAX_CHAN];
11868 int i;
11869
11870 /* fudge NULL arguments so that they don't bomb */
11871 if (inmin == NULL)
11872 inmin = tinmin;
11873 if (inmax == NULL)
11874 inmax = tinmax;
11875 if (outmin == NULL)
11876 outmin = toutmin;
11877 if (outmax == NULL)
11878 outmax = toutmax;
11879
11880 for (i = 0; i < p->lut->inputChan; i++) {
11881 inmin[i] = 0.0; /* Normalized range of input space values */
11882 inmax[i] = 1.0;
11883 }
11884 p->e_in_denormf(inmin,inmin); /* Convert to real colorspace range */
11885 p->e_in_denormf(inmax,inmax);
11886
11887 /* Make sure min and max are so. */
11888 for (i = 0; i < p->lut->inputChan; i++) {
11889 if (inmin[i] > inmax[i]) {
11890 double tt;
11891 tt = inmin[i];
11892 inmin[i] = inmax[i];
11893 inmax[i] = tt;
11894 }
11895 }
11896
11897 for (i = 0; i < p->lut->outputChan; i++) {
11898 outmin[i] = 0.0; /* Normalized range of output space values */
11899 outmax[i] = 1.0;
11900 }
11901 p->e_out_denormf(outmin,outmin); /* Convert to real colorspace range */
11902 p->e_out_denormf(outmax,outmax);
11903
11904 /* Make sure min and max are so. */
11905 for (i = 0; i < p->lut->outputChan; i++) {
11906 if (outmin[i] > outmax[i]) {
11907 double tt;
11908 tt = outmin[i];
11909 outmin[i] = outmax[i];
11910 outmax[i] = tt;
11911 }
11912 }
11913 }
11914
11915 /* Return the underlying Lut matrix */
11916 static void
11917 icmLuLut_get_matrix (
11918 struct _icmLuLut *p,
11919 double m[3][3]
11920 ) {
11921 int i, j;
11922 icmLut *lut = p->lut;
11923
11924 if (p->usematrix) {
11925 for (i = 0; i < 3; i++)
11926 for (j = 0; j < 3; j++)
11927 m[i][j] = lut->e[i][j]; /* Copy from Lut */
11928
11929 } else { /* return unity matrix */
11930 for (i = 0; i < 3; i++) {
11931 for (j = 0; j < 3; j++) {
11932 if (i == j)
11933 m[i][j] = 1.0;
11934 else
11935 m[i][j] = 0.0;
11936 }
11937 }
11938 }
11939 }
11940
11941
11942 static void
11943 icmLuLut_delete(
11944 icmLuBase *p
11945 ) {
11946 icc *icp = p->icp;
11947
11948 icp->al->free(icp->al, p);
11949 }
11950
11951 static icmLuBase *
11952 new_icmLuLut(
11953 icc *icp,
11954 icTagSignature ttag, /* Target Lut tag */
11955 icColorSpaceSignature inSpace, /* Native Input color space */
11956 icColorSpaceSignature outSpace, /* Native Output color space */
11957 icColorSpaceSignature pcs, /* Native PCS */
11958 icColorSpaceSignature e_inSpace, /* Effective Input color space */
11959 icColorSpaceSignature e_outSpace, /* Effective Output color space */
11960 icColorSpaceSignature e_pcs, /* Effective PCS */
11961 icmXYZNumber whitePoint, /* Profile absolute white point */
11962 icmXYZNumber blackPoint, /* Profile absolute black point */
11963 icRenderingIntent intent, /* Rendering intent */
11964 icmLookupFunc func /* Functionality requested */
11965 ) {
11966 icmLuLut *p;
11967
11968 if ((p = (icmLuLut *) icp->al->calloc(icp->al,1,sizeof(icmLuLut))) == NULL)
11969 return NULL;
11970 p->ttype = icmLutType;
11971 p->icp = icp;
11972 p->del = icmLuLut_delete;
11973 p->lutspaces= icmLutSpaces;
11974 p->spaces = icmLuSpaces;
11975 p->wh_bk_points = icmLuWh_bk_points;
11976
11977 p->lookup = icmLuLut_lookup;
11978 p->in_abs = icmLuLut_in_abs;
11979 p->matrix = icmLuLut_matrix;
11980 p->input = icmLuLut_input;
11981 p->clut = icmLuLut_clut;
11982 p->output = icmLuLut_output;
11983 p->out_abs = icmLuLut_out_abs;
11984
11985 p->inv_in_abs = icmLuLut_inv_in_abs;
11986 p->inv_matrix = icmLuLut_inv_matrix;
11987 p->inv_input = icmLuLut_inv_input;
11988 p->inv_output = icmLuLut_inv_output;
11989 p->inv_out_abs = icmLuLut_inv_out_abs;
11990
11991 p->pcswht = icp->header->illuminant;
11992 p->whitePoint = whitePoint;
11993 p->blackPoint = blackPoint;
11994 p->intent = intent;
11995 p->function = func;
11996 p->inSpace = inSpace;
11997 p->outSpace = outSpace;
11998 p->pcs = pcs;
11999 p->e_inSpace = e_inSpace;
12000 p->e_outSpace = e_outSpace;
12001 p->e_pcs = e_pcs;
12002 p->get_info = icmLuLut_get_info;
12003 p->get_lutranges = icmLuLut_get_lutranges;
12004 p->get_ranges = icmLuLut_get_ranges;
12005 p->get_matrix = icmLuLut_get_matrix;
12006
12007 /* Create absolute <-> relative conversion matricies */
12008 icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
12009 icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint, p->fromAbs);
12010
12011 /* Get the Lut tag, & check that it is expected type */
12012 if ((p->lut = (icmLut *)icp->read_tag(icp, ttag)) == NULL
12013 || (p->lut->ttype != icSigLut8Type && p->lut->ttype != icSigLut16Type)) {
12014 p->del((icmLuBase *)p);
12015 return NULL;
12016 }
12017
12018 /* Check if matrix should be used */
12019 if (inSpace == icSigXYZData && p->lut->nu_matrix(p->lut))
12020 p->usematrix = 1;
12021 else
12022 p->usematrix = 0;
12023
12024 /* Lookup input color space to normalized index function */
12025 if (getNormFunc(inSpace, p->lut->ttype, icmToLuti, &p->in_normf)) {
12026 sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12027 icp->errc = 1;
12028 p->del((icmLuBase *)p);
12029 return NULL;
12030 }
12031
12032 /* Lookup normalized index to input color space function */
12033 if (getNormFunc(inSpace, p->lut->ttype, icmFromLuti, &p->in_denormf)) {
12034 sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12035 icp->errc = 1;
12036 p->del((icmLuBase *)p);
12037 return NULL;
12038 }
12039
12040 /* Lookup output color space to normalized Lut entry value function */
12041 if (getNormFunc(outSpace, p->lut->ttype, icmToLutv, &p->out_normf)) {
12042 sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12043 icp->errc = 1;
12044 p->del((icmLuBase *)p);
12045 return NULL;
12046 }
12047
12048 /* Lookup normalized Lut entry value to output color space function */
12049 if (getNormFunc(outSpace, p->lut->ttype, icmFromLutv, &p->out_denormf)) {
12050 sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12051 icp->errc = 1;
12052 p->del((icmLuBase *)p);
12053 return NULL;
12054 }
12055
12056 /* Lookup normalized index to effective input color space function */
12057 if (getNormFunc(e_inSpace, p->lut->ttype, icmFromLuti, &p->e_in_denormf)) {
12058 sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
12059 icp->errc = 1;
12060 p->del((icmLuBase *)p);
12061 return NULL;
12062 }
12063
12064 /* Lookup normalized Lut entry value to effective output color space function */
12065 if (getNormFunc(e_outSpace, p->lut->ttype, icmFromLutv, &p->e_out_denormf)) {
12066 sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
12067 icp->errc = 1;
12068 p->del((icmLuBase *)p);
12069 return NULL;
12070 }
12071
12072 /* Determine appropriate clut lookup algorithm */
12073 {
12074 int use_sx; /* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */
12075 icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
12076 int inn, outn; /* in and out number of Lut components */
12077
12078 p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn);
12079
12080 /* Determine if the input space is "Device" like, */
12081 /* ie. luminance will be expected to vary most strongly */
12082 /* with the diagonal change in input coordinates. */
12083 switch(ins) {
12084
12085 /* Luminence is carried by the sum of all the output channels, */
12086 /* so output luminence will dominantly be in diagonal direction. */
12087 case icSigRgbData:
12088 case icSigGrayData:
12089 case icSigCmykData:
12090 case icSigCmyData:
12091 case icSigMch6Data:
12092 use_sx = 1; /* Simplex interpolation is appropriate */
12093 break;
12094
12095 /* A single channel carries the luminence information */
12096 case icSigLabData:
12097 case icSigLuvData:
12098 case icSigYCbCrData:
12099 case icSigYxyData:
12100 case icSigXYZData:
12101 case icSigHlsData:
12102 case icSigHsvData:
12103 use_sx = 0; /* N-linear interpolation is appropriate */
12104 break;
12105 default:
12106 use_sx = -1; /* undecided */
12107 break;
12108 }
12109
12110 /* If we couldn't figure it out from the input space, */
12111 /* check output luminance variation with a diagonal input */
12112 /* change. */
12113 if (use_sx == -1) {
12114 int lc; /* Luminance channel */
12115
12116 /* Determine where the luminence is carried in the output */
12117 switch(outs) {
12118
12119 /* Luminence is carried by the sum of all the output channels */
12120 case icSigRgbData:
12121 case icSigGrayData:
12122 case icSigCmykData:
12123 case icSigCmyData:
12124 case icSigMch6Data:
12125 lc = -1; /* Average all channels */
12126 break;
12127
12128 /* A single channel carries the luminence information */
12129 case icSigLabData:
12130 case icSigLuvData:
12131 case icSigYCbCrData:
12132 case icSigYxyData:
12133 lc = 0;
12134 break;
12135
12136 case icSigXYZData:
12137 case icSigHlsData:
12138 lc = 1;
12139 break;
12140
12141 case icSigHsvData:
12142 lc = 2;
12143 break;
12144
12145 /* default means give up and use N-linear type lookup */
12146 default:
12147 lc = -2;
12148 break;
12149 }
12150
12151 /* If we know how luminance is represented in output space */
12152 if (lc != -2) {
12153 double tout1[MAX_CHAN]; /* Test output values */
12154 double tout2[MAX_CHAN];
12155 double tt, diag;
12156 int n;
12157
12158 /* Determine input space location of min and max of */
12159 /* given output channel (chan = -1 means average of all) */
12160 p->lut->min_max(p->lut, tout1, tout2, lc);
12161
12162 /* Convert to vector and then calculate normalized */
12163 /* dot product with diagonal vector (1,1,1...) */
12164 for (tt = 0.0, n = 0; n < inn; n++) {
12165 tout1[n] = tout2[n] - tout1[n];
12166 tt += tout1[n] * tout1[n];
12167 }
12168 if (tt > 0.0)
12169 tt = sqrt(tt); /* normalizing factor for maximum delta */
12170 else
12171 tt = 1.0; /* Hmm. */
12172 tt *= sqrt((double)inn); /* Normalizing factor for diagonal vector */
12173 for (diag = 0.0, n = 0; n < outn; n++)
12174 diag += tout1[n] / tt;
12175 diag = fabs(diag);
12176
12177 /* I'm not really convinced that this is a reliable */
12178 /* indicator of whether simplex interpolation should be used ... */
12179 /* It does seem to do the right thing with YCC space though. */
12180 if (diag > 0.8) /* Diagonal is dominant ? */
12181 use_sx = 1;
12182
12183 /* If we couldn't figure it out, use N-linear interpolation */
12184 if (use_sx == -1)
12185 use_sx = 0;
12186 }
12187 }
12188
12189 if (use_sx) {
12190 p->lookup_clut = p->lut->lookup_clut_sx;
12191 } else
12192 p->lookup_clut = p->lut->lookup_clut_nl;
12193 }
12194 return (icmLuBase *)p;
12195 }
12196
12197 /* - - - - - - - - - - - - - - - - - - - - - - - */
12198
12199 /* Return an appropriate lookup object */
12200 /* Return NULL on error, and detailed error in icc */
12201 static icmLuBase* icc_get_luobj (
12202 icc *p, /* ICC */
12203 icmLookupFunc func, /* Conversion functionality */
12204 icRenderingIntent intent, /* Rendering intent, including icmAbsoluteColorimetricXYZ */
12205 icColorSpaceSignature pcsor,/* PCS overide (0 = def) */
12206 icmLookupOrder order /* Conversion representation search Order */
12207 ) {
12208 int rv;
12209 icmLuBase *luobj = NULL; /* Lookup object to return */
12210 icmXYZNumber whitePoint, blackPoint;
12211 icColorSpaceSignature pcs, e_pcs; /* PCS and effective PCS */
12212
12213 /* Check that the profile is legal, since we depend on it */
12214 if ((rv = check_icc_legal(p)) != 0)
12215 return NULL;
12216
12217 /* Figure out the native and effective PCS */
12218 e_pcs = pcs = p->header->pcs;
12219 if (pcsor != icmSigDefaultData)
12220 e_pcs = pcsor; /* Overide */
12221
12222 /* Get White and Black points from the profile */
12223 {
12224 icmXYZArray *whitePointTag, *blackPointTag;
12225
12226 if ((whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) == NULL
12227 || whitePointTag->ttype != icSigXYZType || whitePointTag->size < 1) {
12228 if (intent == icAbsoluteColorimetric) {
12229 sprintf(p->err,"icc_lookup: Profile is missing Media White Point Tag");
12230 p->errc = 1;
12231 return NULL;
12232 }
12233 whitePoint = icmD50; /* safe value */
12234 } else
12235 whitePoint = whitePointTag->data[0]; /* Copy structure */
12236
12237 if ((blackPointTag = (icmXYZArray *)p->read_tag(p, icSigMediaBlackPointTag)) == NULL
12238 || blackPointTag->ttype != icSigXYZType || blackPointTag->size < 1) {
12239 blackPoint = icmBlack; /* default */
12240 } else
12241 blackPoint = blackPointTag->data[0]; /* Copy structure */
12242 }
12243
12244 /* How we expect to execute the request depends firstly on the type of profile */
12245 switch (p->header->deviceClass) {
12246 case icSigInputClass:
12247 case icSigDisplayClass:
12248 /* Look for AToB0 based profile + optional BToA0 reverse */
12249 /* or three component matrix profile (reversable) */
12250 /* or momochrome table profile (reversable) */
12251 /* No intent */
12252 /* Device <-> PCS */
12253 /* Determine the algorithm and set its parameters */
12254
12255 if (intent != icmDefaultIntent
12256 && intent != icAbsoluteColorimetric) {
12257 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Input/Display profile");
12258 p->errc = 1;
12259 return NULL;
12260 }
12261
12262 switch (func) {
12263 case icmFwd: /* Device to PCS */
12264 if (order != icmLuOrdRev) {
12265 /* Try Lut type lookup first */
12266 if ((luobj = new_icmLuLut(p, icSigAToB0Tag,
12267 p->header->colorSpace, pcs, pcs,
12268 p->header->colorSpace, e_pcs, e_pcs,
12269 whitePoint, blackPoint, intent, func)) != NULL)
12270 break;
12271
12272 /* See if it could be a matrix lookup */
12273 if ((luobj = new_icmLuMatrixFwd(p,
12274 p->header->colorSpace, pcs, pcs,
12275 p->header->colorSpace, e_pcs, e_pcs,
12276 whitePoint, blackPoint, intent, func)) != NULL)
12277 break;
12278
12279 /* See if it could be a monochrome lookup */
12280 if ((luobj = new_icmLuMonoFwd(p,
12281 p->header->colorSpace, pcs, pcs,
12282 p->header->colorSpace, e_pcs, e_pcs,
12283 whitePoint, blackPoint, intent, func)) != NULL)
12284 break;
12285
12286 } else {
12287 /* See if it could be a monochrome lookup */
12288 if ((luobj = new_icmLuMonoFwd(p,
12289 p->header->colorSpace, pcs, pcs,
12290 p->header->colorSpace, e_pcs, e_pcs,
12291 whitePoint, blackPoint, intent, func)) != NULL)
12292 break;
12293
12294 /* See if it could be a matrix lookup */
12295 if ((luobj = new_icmLuMatrixFwd(p,
12296 p->header->colorSpace, pcs, pcs,
12297 p->header->colorSpace, e_pcs, e_pcs,
12298 whitePoint, blackPoint, intent, func)) != NULL)
12299 break;
12300
12301 /* Try Lut type lookup last */
12302 if ((luobj = new_icmLuLut(p, icSigAToB0Tag,
12303 p->header->colorSpace, pcs, pcs,
12304 p->header->colorSpace, e_pcs, e_pcs,
12305 whitePoint, blackPoint, intent, func)) != NULL)
12306 break;
12307 }
12308 break;
12309
12310 case icmBwd: /* PCS to Device */
12311 if (order != icmLuOrdRev) {
12312 /* Try Lut type lookup first */
12313 if ((luobj = new_icmLuLut(p, icSigBToA0Tag,
12314 pcs, p->header->colorSpace, pcs,
12315 e_pcs, p->header->colorSpace, e_pcs,
12316 whitePoint, blackPoint, intent, func)) != NULL)
12317 break;
12318
12319 /* See if it could be a matrix lookup */
12320 if ((luobj = new_icmLuMatrixBwd(p,
12321 pcs, p->header->colorSpace, pcs,
12322 e_pcs, p->header->colorSpace, e_pcs,
12323 whitePoint, blackPoint, intent, func)) != NULL)
12324 break;
12325
12326 /* See if it could be a monochrome lookup */
12327 if ((luobj = new_icmLuMonoBwd(p,
12328 pcs, p->header->colorSpace, pcs,
12329 e_pcs, p->header->colorSpace, e_pcs,
12330 whitePoint, blackPoint, intent, func)) != NULL)
12331 break;
12332 } else {
12333 /* See if it could be a monochrome lookup */
12334 if ((luobj = new_icmLuMonoBwd(p,
12335 pcs, p->header->colorSpace, pcs,
12336 e_pcs, p->header->colorSpace, e_pcs,
12337 whitePoint, blackPoint, intent, func)) != NULL)
12338 break;
12339
12340 /* See if it could be a matrix lookup */
12341 if ((luobj = new_icmLuMatrixBwd(p,
12342 pcs, p->header->colorSpace, pcs,
12343 e_pcs, p->header->colorSpace, e_pcs,
12344 whitePoint, blackPoint, intent, func)) != NULL)
12345 break;
12346
12347 /* Try Lut type lookup last */
12348 if ((luobj = new_icmLuLut(p, icSigBToA0Tag,
12349 pcs, p->header->colorSpace, pcs,
12350 e_pcs, p->header->colorSpace, e_pcs,
12351 whitePoint, blackPoint, intent, func)) != NULL)
12352 break;
12353 }
12354 break;
12355
12356 default:
12357 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12358 p->errc = 1;
12359 return NULL;
12360 }
12361 break;
12362
12363 case icSigOutputClass:
12364 /* Expect BToA Lut and optional AToB Lut, All intents, expect gamut */
12365 /* or momochrome table profile (reversable) */
12366 /* Device <-> PCS */
12367 /* Gamut Lut - no intent */
12368 /* Optional preview links PCS <-> PCS */
12369
12370 /* Determine the algorithm and set its parameters */
12371 switch (func) {
12372 icTagSignature ttag;
12373
12374 case icmFwd: /* Device to PCS */
12375
12376 if (intent == icmDefaultIntent)
12377 intent = icRelativeColorimetric; /* Make this the default */
12378
12379 switch (intent) {
12380 case icRelativeColorimetric:
12381 case icAbsoluteColorimetric:
12382 ttag = icSigAToB1Tag;
12383 break;
12384 case icPerceptual:
12385 ttag = icSigAToB0Tag;
12386 break;
12387 case icSaturation:
12388 ttag = icSigAToB2Tag;
12389 break;
12390 default:
12391 sprintf(p->err,"icc_get_luobj: Unknown intent");
12392 p->errc = 1;
12393 return NULL;
12394 }
12395
12396 if (order != icmLuOrdRev) {
12397 /* Try Lut type lookup first */
12398 if ((luobj = new_icmLuLut(p, ttag,
12399 p->header->colorSpace, pcs, pcs,
12400 p->header->colorSpace, e_pcs, e_pcs,
12401 whitePoint, blackPoint, intent, func)) != NULL)
12402 break;
12403
12404 /* See if it could be a matrix lookup */
12405 if ((luobj = new_icmLuMatrixFwd(p,
12406 p->header->colorSpace, pcs, pcs,
12407 p->header->colorSpace, e_pcs, e_pcs,
12408 whitePoint, blackPoint, intent, func)) != NULL)
12409 break;
12410
12411 /* See if it could be a monochrome lookup */
12412 if ((luobj = new_icmLuMonoFwd(p,
12413 p->header->colorSpace, pcs, pcs,
12414 p->header->colorSpace, e_pcs, e_pcs,
12415 whitePoint, blackPoint, intent, func)) != NULL)
12416 break;
12417 } else {
12418 /* See if it could be a monochrome lookup */
12419 if ((luobj = new_icmLuMonoFwd(p,
12420 p->header->colorSpace, pcs, pcs,
12421 p->header->colorSpace, e_pcs, e_pcs,
12422 whitePoint, blackPoint, intent, func)) != NULL)
12423 break;
12424
12425 /* See if it could be a matrix lookup */
12426 if ((luobj = new_icmLuMatrixFwd(p,
12427 p->header->colorSpace, pcs, pcs,
12428 p->header->colorSpace, e_pcs, e_pcs,
12429 whitePoint, blackPoint, intent, func)) != NULL)
12430 break;
12431
12432 /* Try Lut type lookup last */
12433 if ((luobj = new_icmLuLut(p, ttag,
12434 p->header->colorSpace, pcs, pcs,
12435 p->header->colorSpace, e_pcs, e_pcs,
12436 whitePoint, blackPoint, intent, func)) != NULL)
12437 break;
12438 }
12439 break;
12440
12441 case icmBwd: /* PCS to Device */
12442
12443 if (intent == icmDefaultIntent)
12444 intent = icRelativeColorimetric; /* Make this the default */
12445
12446 switch (intent) {
12447 case icRelativeColorimetric:
12448 case icAbsoluteColorimetric:
12449 ttag = icSigBToA1Tag;
12450 break;
12451 case icPerceptual:
12452 ttag = icSigBToA0Tag;
12453 break;
12454 case icSaturation:
12455 ttag = icSigBToA2Tag;
12456 break;
12457 default:
12458 sprintf(p->err,"icc_get_luobj: Unknown intent");
12459 p->errc = 1;
12460 return NULL;
12461 }
12462
12463 if (order != icmLuOrdRev) {
12464 /* Try Lut type lookup first */
12465 if ((luobj = new_icmLuLut(p, ttag,
12466 pcs, p->header->colorSpace, pcs,
12467 e_pcs, p->header->colorSpace, e_pcs,
12468 whitePoint, blackPoint, intent, func)) != NULL)
12469 break;
12470
12471 /* See if it could be a matrix lookup */
12472 if ((luobj = new_icmLuMatrixBwd(p,
12473 pcs, p->header->colorSpace, pcs,
12474 e_pcs, p->header->colorSpace, e_pcs,
12475 whitePoint, blackPoint, intent, func)) != NULL)
12476 break;
12477
12478 /* See if it could be a monochrome lookup */
12479 if ((luobj = new_icmLuMonoBwd(p,
12480 pcs, p->header->colorSpace, pcs,
12481 e_pcs, p->header->colorSpace, e_pcs,
12482 whitePoint, blackPoint, intent, func)) != NULL)
12483 break;
12484 } else {
12485 /* See if it could be a monochrome lookup */
12486 if ((luobj = new_icmLuMonoBwd(p,
12487 pcs, p->header->colorSpace, pcs,
12488 e_pcs, p->header->colorSpace, e_pcs,
12489 whitePoint, blackPoint, intent, func)) != NULL)
12490 break;
12491
12492 /* See if it could be a matrix lookup */
12493 if ((luobj = new_icmLuMatrixBwd(p,
12494 pcs, p->header->colorSpace, pcs,
12495 e_pcs, p->header->colorSpace, e_pcs,
12496 whitePoint, blackPoint, intent, func)) != NULL)
12497 break;
12498
12499 /* Try Lut type lookup last */
12500 if ((luobj = new_icmLuLut(p, ttag,
12501 pcs, p->header->colorSpace, pcs,
12502 e_pcs, p->header->colorSpace, e_pcs,
12503 whitePoint, blackPoint, intent, func)) != NULL)
12504 break;
12505 }
12506 break;
12507
12508 case icmGamut: /* PCS to 1D */
12509
12510 if (intent != icmDefaultIntent) {
12511 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function");
12512 p->errc = 1;
12513 return NULL;
12514 }
12515
12516 /* If the target tag exists, and it is a Lut */
12517 luobj = new_icmLuLut(p, icSigGamutTag,
12518 pcs, icSigGrayData, pcs,
12519 e_pcs, icSigGrayData, e_pcs,
12520 whitePoint, blackPoint, intent, func);
12521 break;
12522
12523 case icmPreview: /* PCS to PCS */
12524
12525 switch (intent) {
12526 case icRelativeColorimetric:
12527 ttag = icSigPreview1Tag;
12528 break;
12529 case icPerceptual:
12530 ttag = icSigPreview0Tag;
12531 break;
12532 case icSaturation:
12533 ttag = icSigPreview2Tag;
12534 break;
12535 case icAbsoluteColorimetric:
12536 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function");
12537 p->errc = 1;
12538 return NULL;
12539 default:
12540 sprintf(p->err,"icc_get_luobj: Unknown intent");
12541 p->errc = 1;
12542 return NULL;
12543 }
12544
12545 /* If the target tag exists, and it is a Lut */
12546 luobj = new_icmLuLut(p, ttag,
12547 pcs, pcs, pcs,
12548 e_pcs, e_pcs, e_pcs,
12549 whitePoint, blackPoint, intent, func);
12550 break;
12551
12552 default:
12553 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12554 p->errc = 1;
12555 return NULL;
12556 }
12557 break;
12558
12559 case icSigLinkClass:
12560 /* Expect AToB0 Lut and optional BToA0 Lut, One intent in header */
12561 /* Device <-> Device */
12562
12563 if (intent != p->header->renderingIntent
12564 && intent != icmDefaultIntent) {
12565 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Link profile");
12566 p->errc = 1;
12567 return NULL;
12568 }
12569 intent = p->header->renderingIntent;
12570
12571 /* Determine the algorithm and set its parameters */
12572 switch (func) {
12573 case icmFwd: /* Device to PCS (== Device) */
12574
12575 luobj = new_icmLuLut(p, icSigAToB0Tag,
12576 p->header->colorSpace, pcs, pcs,
12577 p->header->colorSpace, pcs, pcs,
12578 whitePoint, blackPoint, intent, func);
12579 break;
12580
12581 case icmBwd: /* PCS (== Device) to Device */
12582
12583 luobj = new_icmLuLut(p, icSigBToA0Tag,
12584 pcs, p->header->colorSpace, pcs,
12585 pcs, p->header->colorSpace, pcs,
12586 whitePoint, blackPoint, intent, func);
12587 break;
12588
12589 default:
12590 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12591 p->errc = 1;
12592 return NULL;
12593 }
12594 break;
12595
12596 case icSigAbstractClass:
12597 /* Expect AToB0 Lut and BToA Lut, no intents */
12598 /* PCS <-> PCS */
12599 /* Determine the algorithm and set its parameters */
12600
12601 if (intent != icmDefaultIntent) {
12602 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Abstract profile");
12603 p->errc = 1;
12604 return NULL;
12605 }
12606
12607 switch (func) {
12608 case icmFwd: /* PCS (== Device) to PCS */
12609
12610 luobj = new_icmLuLut(p, icSigAToB0Tag,
12611 p->header->colorSpace, pcs, pcs,
12612 e_pcs, e_pcs, e_pcs,
12613 whitePoint, blackPoint, intent, func);
12614 break;
12615
12616 case icmBwd: /* PCS to PCS (== Device) */
12617
12618 luobj = new_icmLuLut(p, icSigBToA0Tag,
12619 pcs, p->header->colorSpace, pcs,
12620 e_pcs, e_pcs, e_pcs,
12621 whitePoint, blackPoint, intent, func);
12622 break;
12623
12624 default:
12625 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12626 p->errc = 1;
12627 return NULL;
12628 }
12629 break;
12630
12631 case icSigColorSpaceClass:
12632 /* Expect AToB0 Lut and BToA0 Lut, no intents, */
12633 /* Device <-> PCS */
12634
12635 if (intent != icmDefaultIntent) {
12636 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Colorspace profile");
12637 p->errc = 1;
12638 return NULL;
12639 }
12640
12641 /* Determine the algorithm and set its parameters */
12642 switch (func) {
12643 case icmFwd: /* Device to PCS */
12644
12645 luobj = new_icmLuLut(p, icSigAToB0Tag,
12646 p->header->colorSpace, pcs, pcs,
12647 p->header->colorSpace, e_pcs, e_pcs,
12648 whitePoint, blackPoint, intent, func);
12649 break;
12650
12651 case icmBwd: /* PCS to Device */
12652
12653 luobj = new_icmLuLut(p, icSigBToA0Tag,
12654 pcs, p->header->colorSpace, pcs,
12655 e_pcs, p->header->colorSpace, e_pcs,
12656 whitePoint, blackPoint, intent, func);
12657 break;
12658
12659 default:
12660 sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12661 p->errc = 1;
12662 return NULL;
12663 }
12664 break;
12665
12666 case icSigNamedColorClass:
12667 /* Expect Name -> Device, Optional PCS */
12668 /* and a reverse lookup would be useful */
12669 /* (ie. PCS or Device coords to closest named color) */
12670 /* ~~ to be implemented ~~ */
12671
12672 /* ~~ Absolute intent is valid for processing of */
12673 /* PCS from named Colors. Also allow for e_pcs */
12674 if (intent != icmDefaultIntent) {
12675 sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Named Color profile");
12676 p->errc = 1;
12677 return NULL;
12678 }
12679
12680 sprintf(p->err,"icc_get_luobj: Named Colors not handled yet");
12681 p->errc = 1;
12682 return NULL;
12683
12684 default:
12685 sprintf(p->err,"icc_get_luobj: Unknown profile class");
12686 p->errc = 1;
12687 return NULL;
12688 }
12689
12690 return luobj;
12691 }
12692
12693 /* - - - - - - - - - - - - - - - - - - - - - - - - */
12694
12695 /* Create an empty object. Return null on error */
12696 icc *new_icc_a(
12697 icmAlloc *al /* Optional memory allocator. NULL for default */
12698 ) {
12699 icc *p;
12700 int del_al = 0;
12701
12702 if (al == NULL) { /* None provided, create default */
12703 if ((al = new_icmAllocStd()) == NULL)
12704 return NULL;
12705 del_al = 1; /* We need to delete it */
12706 }
12707
12708 if ((p = (icc *) al->calloc(al, 1,sizeof(icc))) == NULL)
12709 return NULL;
12710 p->al = al; /* Heap allocator */
12711 p->del_al = del_al; /* Flag noting whether we delete it */
12712
12713 p->get_size = icc_get_size;
12714 p->read = icc_read;
12715 p->write = icc_write;
12716 p->dump = icc_dump;
12717 p->del = icc_delete;
12718 p->add_tag = icc_add_tag;
12719 p->link_tag = icc_link_tag;
12720 p->find_tag = icc_find_tag;
12721 p->read_tag = icc_read_tag;
12722 p->rename_tag = icc_rename_tag;
12723 p->unread_tag = icc_unread_tag;
12724 p->read_all_tags = icc_read_all_tags;
12725 p->delete_tag = icc_delete_tag;
12726
12727 p->get_luobj = icc_get_luobj;
12728
12729 #if defined(__IBMC__) && defined(_M_IX86)
12730 _control87(EM_UNDERFLOW, EM_UNDERFLOW);
12731 #endif
12732
12733 /* Allocate a header object */
12734 if ((p->header = new_icmHeader(p)) == NULL) {
12735 al->free(al, p);
12736 if (del_al)
12737 al->del(al);
12738 return NULL;
12739 }
12740
12741 /* Values that must be set before writing */
12742 p->header->deviceClass = icMaxEnumClass;/* Type of profile - must be set! */
12743 p->header->colorSpace = icMaxEnumData; /* Clr space of data - must be set! */
12744 p->header->pcs = icMaxEnumData; /* PCS: XYZ or Lab - must be set! */
12745 p->header->renderingIntent = icMaxEnumIntent; /* Rendering intent - must be set ! */
12746
12747 /* Values that should be set before writing */
12748 p->header->manufacturer = -1; /* Dev manufacturer - should be set ! */
12749 p->header->model = -1; /* Dev model number - should be set ! */
12750 p->header->attributes.l = 0; /* ICC Device attributes - should set ! */
12751 p->header->flags = 0; /* Embedding flags - should be set ! */
12752
12753 /* Values that may be set before writing */
12754 p->header->attributes.h = 0; /* Dev Device attributes - may be set ! */
12755 p->header->creator = str2tag("argl"); /* Profile creator - Argyll - may be set ! */
12756
12757 /* Init default values in header */
12758 p->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
12759 p->header->majv = 2; /* Current version 2.1.0 */
12760 p->header->minv = 1;
12761 p->header->bfv = 0;
12762 setcur_DateTimeNumber(&p->header->date);/* Creation Date */
12763 p->header->platform = icSigMicrosoft; /* Primary Platform */
12764 p->header->illuminant = icmD50; /* Profile illuminant - D50 */
12765
12766 return p;
12767 }
12768
12769
12770 /* For backwards compatibility - a NULL allocator version */
12771 icc *new_icc(void) {
12772 return new_icc_a(NULL);
12773 }
12774
12775
12776 /* ---------------------------------------------------------- */
12777