Update to 2.0.0 tree from current Fremantle build
[opencv] / 3rdparty / libjasper / jas_cm.c
1 /*
2  * Copyright (c) 2002-2003 Michael David Adams.
3  * All rights reserved.
4  */
5
6 /* __START_OF_JASPER_LICENSE__
7  * 
8  * JasPer License Version 2.0
9  * 
10  * Copyright (c) 2001-2006 Michael David Adams
11  * Copyright (c) 1999-2000 Image Power, Inc.
12  * Copyright (c) 1999-2000 The University of British Columbia
13  * 
14  * All rights reserved.
15  * 
16  * Permission is hereby granted, free of charge, to any person (the
17  * "User") obtaining a copy of this software and associated documentation
18  * files (the "Software"), to deal in the Software without restriction,
19  * including without limitation the rights to use, copy, modify, merge,
20  * publish, distribute, and/or sell copies of the Software, and to permit
21  * persons to whom the Software is furnished to do so, subject to the
22  * following conditions:
23  * 
24  * 1.  The above copyright notices and this permission notice (which
25  * includes the disclaimer below) shall be included in all copies or
26  * substantial portions of the Software.
27  * 
28  * 2.  The name of a copyright holder shall not be used to endorse or
29  * promote products derived from the Software without specific prior
30  * written permission.
31  * 
32  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
33  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
34  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
35  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
37  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
38  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
39  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
40  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
41  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
42  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
43  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
44  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
45  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
46  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
47  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
48  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
49  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
50  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
51  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
52  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
53  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
54  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
55  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
56  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
57  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
58  * 
59  * __END_OF_JASPER_LICENSE__
60  */
61
62 /*
63  * Color Management
64  *
65  * $Id: jas_cm.c,v 1.2 2008-05-26 09:40:52 vp153 Exp $
66  */
67
68 #include <jasper/jas_config.h>
69 #include <math.h>
70 #include <stdlib.h>
71 #include <assert.h>
72 #include <jasper/jas_cm.h>
73 #include <jasper/jas_icc.h>
74 #include <jasper/jas_init.h>
75 #include <jasper/jas_stream.h>
76 #include <jasper/jas_malloc.h>
77 #include <jasper/jas_math.h>
78
79 static jas_cmprof_t *jas_cmprof_create(void);
80 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *);
81 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x);
82
83 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform);
84 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform);
85
86 static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform);
87 static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
88   jas_cmreal_t *out, int cnt);
89
90 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val);
91 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val);
92 static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
93   jas_cmpxformseq_t *othpxformseq);
94 static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
95   int, int);
96 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n);
97
98 static int mono(jas_iccprof_t *prof, int op, jas_cmpxformseq_t **pxformseq);
99 static int triclr(jas_iccprof_t *prof, int op, jas_cmpxformseq_t **retpxformseq);
100
101 static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq);
102 static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i);
103 static jas_cmpxformseq_t *jas_cmpxformseq_create(void);
104 static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq);
105 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4]);
106 static int jas_cmpxformseq_insertpxform(jas_cmpxformseq_t *pxformseq,
107   int i, jas_cmpxform_t *pxform);
108
109 #define SEQFWD(intent)  (intent)
110 #define SEQREV(intent)  (4 + (intent))
111 #define SEQSIM(intent)  (8 + (intent))
112 #define SEQGAM          12
113
114 #define fwdpxformseq(prof, intent) \
115   (((prof)->pxformseqs[SEQFWD(intent)]) ? \
116   ((prof)->pxformseqs[SEQFWD(intent)]) : \
117   ((prof)->pxformseqs[SEQFWD(0)]))
118
119 #define revpxformseq(prof, intent) \
120   (((prof)->pxformseqs[SEQREV(intent)]) ? \
121   ((prof)->pxformseqs[SEQREV(intent)]) : \
122   ((prof)->pxformseqs[SEQREV(0)]))
123
124 #define simpxformseq(prof, intent) \
125   (((prof)->pxformseqs[SEQSIM(intent)]) ? \
126   ((prof)->pxformseqs[SEQSIM(intent)]) : \
127   ((prof)->pxformseqs[SEQSIM(0)]))
128
129 #define gampxformseq(prof)      ((prof)->pxformseqs[SEQGAM])
130
131 static int icctoclrspc(int iccclrspc, int refflag);
132 static jas_cmpxform_t *jas_cmpxform_create0(void);
133 static jas_cmpxform_t *jas_cmpxform_createshapmat(void);
134 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut);
135 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv);
136
137 static jas_cmpxformops_t shapmat_ops = {jas_cmshapmat_destroy, jas_cmshapmat_apply, 0};
138 static jas_cmprof_t *jas_cmprof_createsycc(void);
139
140 /******************************************************************************\
141 * Color profile class.
142 \******************************************************************************/
143
144 jas_cmprof_t *jas_cmprof_createfromclrspc(int clrspc)
145 {
146         jas_iccprof_t *iccprof;
147         jas_cmprof_t *prof;
148
149         iccprof = 0;
150         prof = 0;
151         switch (clrspc) {
152         case JAS_CLRSPC_SYCBCR:
153                 if (!(prof = jas_cmprof_createsycc()))
154                         goto error;
155                 break;
156         default:
157                 if (!(iccprof = jas_iccprof_createfromclrspc(clrspc)))
158                         goto error;
159                 if (!(prof = jas_cmprof_createfromiccprof(iccprof)))
160                         goto error;
161                 jas_iccprof_destroy(iccprof);
162                 iccprof = 0;
163                 if (!jas_clrspc_isgeneric(clrspc))
164                         prof->clrspc = clrspc;
165                 break;
166         }
167         return prof;
168 error:
169         if (iccprof)
170                 jas_iccprof_destroy(iccprof);
171         return 0;
172 }
173
174 static jas_cmprof_t *jas_cmprof_createsycc()
175 {
176         jas_cmprof_t *prof;
177         jas_cmpxform_t *fwdpxform;
178         jas_cmpxform_t *revpxform;
179         jas_cmshapmat_t *fwdshapmat;
180         jas_cmshapmat_t *revshapmat;
181         int i;
182         int j;
183
184         if (!(prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
185                 goto error;
186         prof->clrspc = JAS_CLRSPC_SYCBCR;
187         assert(prof->numchans == 3 && prof->numrefchans == 3);
188         assert(prof->refclrspc == JAS_CLRSPC_CIEXYZ);
189         if (!(fwdpxform = jas_cmpxform_createshapmat()))
190                 goto error;
191         fwdpxform->numinchans = 3;
192         fwdpxform->numoutchans = 3;
193         fwdshapmat = &fwdpxform->data.shapmat;
194         fwdshapmat->mono = 0;
195         fwdshapmat->order = 0;
196         fwdshapmat->useluts = 0;
197         fwdshapmat->usemat = 1;
198         fwdshapmat->mat[0][0] = 1.0;
199         fwdshapmat->mat[0][1] = 0.0;
200         fwdshapmat->mat[0][2] = 1.402;
201         fwdshapmat->mat[1][0] = 1.0;
202         fwdshapmat->mat[1][1] = -0.34413;
203         fwdshapmat->mat[1][2] = -0.71414;
204         fwdshapmat->mat[2][0] = 1.0;
205         fwdshapmat->mat[2][1] = 1.772;
206         fwdshapmat->mat[2][2] = 0.0;
207         fwdshapmat->mat[0][3] = -0.5 * (1.402);
208         fwdshapmat->mat[1][3] = -0.5 * (-0.34413 - 0.71414);
209         fwdshapmat->mat[2][3] = -0.5 * (1.772);
210         if (!(revpxform = jas_cmpxform_createshapmat()))
211                 goto error;
212         revpxform->numinchans = 3;
213         revpxform->numoutchans = 3;
214         revshapmat = &revpxform->data.shapmat;
215         revshapmat->mono = 0;
216         revshapmat->order = 1;
217         revshapmat->useluts = 0;
218         revshapmat->usemat = 1;
219         jas_cmshapmat_invmat(revshapmat->mat, fwdshapmat->mat);
220
221         for (i = 0; i < JAS_CMXFORM_NUMINTENTS; ++i) {
222                 j = SEQFWD(i);
223                 if (prof->pxformseqs[j]) {
224                         if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j], 0,
225                           fwdpxform))
226                                 goto error;
227                 }
228                 j = SEQREV(i);
229                 if (prof->pxformseqs[j]) {
230                         if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j],
231                           -1, revpxform))
232                                 goto error;
233                 }
234         }
235
236         jas_cmpxform_destroy(fwdpxform);
237         jas_cmpxform_destroy(revpxform);
238         return prof;
239 error:
240         return 0;
241 }
242
243 jas_cmprof_t *jas_cmprof_createfromiccprof(jas_iccprof_t *iccprof)
244 {
245         jas_cmprof_t *prof;
246         jas_icchdr_t icchdr;
247         jas_cmpxformseq_t *fwdpxformseq;
248         jas_cmpxformseq_t *revpxformseq;
249
250         prof = 0;
251         fwdpxformseq = 0;
252         revpxformseq = 0;
253
254         if (!(prof = jas_cmprof_create()))
255                 goto error;
256         jas_iccprof_gethdr(iccprof, &icchdr);
257         if (!(prof->iccprof = jas_iccprof_copy(iccprof)))
258                 goto error;
259         prof->clrspc = icctoclrspc(icchdr.colorspc, 0);
260         prof->refclrspc = icctoclrspc(icchdr.refcolorspc, 1);
261         prof->numchans = jas_clrspc_numchans(prof->clrspc);
262         prof->numrefchans = jas_clrspc_numchans(prof->refclrspc);
263
264         if (prof->numchans == 1) {
265                 if (mono(prof->iccprof, 0, &fwdpxformseq))
266                         goto error;
267                 if (mono(prof->iccprof, 1, &revpxformseq))
268                         goto error;
269         } else if (prof->numchans == 3) {
270                 if (triclr(prof->iccprof, 0, &fwdpxformseq))
271                         goto error;
272                 if (triclr(prof->iccprof, 1, &revpxformseq))
273                         goto error;
274         }
275         prof->pxformseqs[SEQFWD(0)] = fwdpxformseq;
276         prof->pxformseqs[SEQREV(0)] = revpxformseq;
277
278 #if 0
279         if (prof->numchans > 1) {
280                 lut(prof->iccprof, 0, PER, &pxformseq);
281                 pxformseqs_set(prof, SEQFWD(PER), pxformseq);
282                 lut(prof->iccprof, 1, PER, &pxformseq);
283                 pxformseqs_set(prof, SEQREV(PER), pxformseq);
284                 lut(prof->iccprof, 0, CLR, &pxformseq);
285                 pxformseqs_set(prof, SEQREV(CLR), pxformseq);
286                 lut(prof->iccprof, 1, CLR, &pxformseq);
287                 pxformseqs_set(prof, SEQREV(CLR), pxformseq);
288                 lut(prof->iccprof, 0, SAT, &pxformseq);
289                 pxformseqs_set(prof, SEQREV(SAT), pxformseq);
290                 lut(prof->iccprof, 1, SAT, &pxformseq);
291                 pxformseqs_set(prof, SEQREV(SAT), pxformseq);
292         }
293 #endif
294
295         return prof;
296
297 error:
298         if (fwdpxformseq) {
299                 jas_cmpxformseq_destroy(fwdpxformseq);
300         }
301         if (revpxformseq) {
302                 jas_cmpxformseq_destroy(revpxformseq);
303         }
304         if (prof) {
305                 jas_cmprof_destroy(prof);
306         }
307
308         return 0;
309 }
310
311 static jas_cmprof_t *jas_cmprof_create()
312 {
313         int i;
314         jas_cmprof_t *prof;
315         if (!(prof = jas_malloc(sizeof(jas_cmprof_t))))
316                 return 0;
317         memset(prof, 0, sizeof(jas_cmprof_t));
318         prof->iccprof = 0;
319         for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i)
320                 prof->pxformseqs[i] = 0;
321         return prof;
322 }
323
324 void jas_cmprof_destroy(jas_cmprof_t *prof)
325
326         int i;
327         for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i) {
328                 if (prof->pxformseqs[i]) {
329                         jas_cmpxformseq_destroy(prof->pxformseqs[i]);
330                         prof->pxformseqs[i] = 0;
331                 }
332         }
333         if (prof->iccprof)
334                 jas_iccprof_destroy(prof->iccprof);
335         jas_free(prof);
336 }
337
338 jas_cmprof_t *jas_cmprof_copy(jas_cmprof_t *prof)
339 {
340         jas_cmprof_t *newprof;
341         int i;
342
343         if (!(newprof = jas_cmprof_create()))
344                 goto error;
345         newprof->clrspc = prof->clrspc;
346         newprof->numchans = prof->numchans;
347         newprof->refclrspc = prof->refclrspc;
348         newprof->numrefchans = prof->numrefchans;
349         newprof->iccprof = jas_iccprof_copy(prof->iccprof);
350         for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i) {
351                 if (prof->pxformseqs[i]) {
352                         if (!(newprof->pxformseqs[i] = jas_cmpxformseq_copy(prof->pxformseqs[i])))
353                                 goto error;
354                 }
355         }
356         return newprof;
357 error:
358         return 0;
359 }
360
361 /******************************************************************************\
362 * Transform class.
363 \******************************************************************************/
364
365 jas_cmxform_t *jas_cmxform_create(jas_cmprof_t *inprof, jas_cmprof_t *outprof,
366   jas_cmprof_t *prfprof, int op, int intent, int optimize)
367 {
368         jas_cmxform_t *xform;
369         jas_cmpxformseq_t *inpxformseq;
370         jas_cmpxformseq_t *outpxformseq;
371         jas_cmpxformseq_t *altoutpxformseq;
372         jas_cmpxformseq_t *prfpxformseq;
373         int prfintent;
374
375         /* Avoid compiler warnings about unused parameters. */
376         optimize = 0;
377
378         prfintent = intent;
379
380         if (!(xform = jas_malloc(sizeof(jas_cmxform_t))))
381                 goto error;
382         if (!(xform->pxformseq = jas_cmpxformseq_create()))
383                 goto error;
384
385         switch (op) {
386         case JAS_CMXFORM_OP_FWD:
387                 inpxformseq = fwdpxformseq(inprof, intent);
388                 outpxformseq = revpxformseq(outprof, intent);
389                 if (!inpxformseq || !outpxformseq)
390                         goto error;
391                 if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
392                   jas_cmpxformseq_appendcnvt(xform->pxformseq,
393                   inprof->refclrspc, outprof->refclrspc) ||
394                   jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
395                         goto error;
396                 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
397                 xform->numoutchans = jas_clrspc_numchans(outprof->clrspc);
398                 break;
399         case JAS_CMXFORM_OP_REV:
400                 outpxformseq = fwdpxformseq(outprof, intent);
401                 inpxformseq = revpxformseq(inprof, intent);
402                 if (!outpxformseq || !inpxformseq)
403                         goto error;
404                 if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
405                   jas_cmpxformseq_appendcnvt(xform->pxformseq,
406                   outprof->refclrspc, inprof->refclrspc) ||
407                   jas_cmpxformseq_append(xform->pxformseq, inpxformseq))
408                         goto error;
409                 xform->numinchans = jas_clrspc_numchans(outprof->clrspc);
410                 xform->numoutchans = jas_clrspc_numchans(inprof->clrspc);
411                 break;
412         case JAS_CMXFORM_OP_PROOF:
413                 assert(prfprof);
414                 inpxformseq = fwdpxformseq(inprof, intent);
415                 prfpxformseq = fwdpxformseq(prfprof, prfintent);
416                 if (!inpxformseq || !prfpxformseq)
417                         goto error;
418                 outpxformseq = simpxformseq(outprof, intent);
419                 altoutpxformseq = 0;
420                 if (!outpxformseq) {
421                         outpxformseq = revpxformseq(outprof, intent);
422                         altoutpxformseq = fwdpxformseq(outprof, intent);
423                         if (!outpxformseq || !altoutpxformseq)
424                                 goto error;
425                 }
426                 if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
427                   jas_cmpxformseq_appendcnvt(xform->pxformseq,
428                   inprof->refclrspc, outprof->refclrspc))
429                         goto error;
430                 if (altoutpxformseq) {
431                         if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
432                           jas_cmpxformseq_append(xform->pxformseq, altoutpxformseq))
433                                 goto error;
434                 } else {
435                         if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
436                                 goto error;
437                 }
438                 if (jas_cmpxformseq_appendcnvt(xform->pxformseq,
439                   outprof->refclrspc, inprof->refclrspc) ||
440                   jas_cmpxformseq_append(xform->pxformseq, prfpxformseq))
441                         goto error;
442                 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
443                 xform->numoutchans = jas_clrspc_numchans(prfprof->clrspc);
444                 break;
445         case JAS_CMXFORM_OP_GAMUT:
446                 inpxformseq = fwdpxformseq(inprof, intent);
447                 outpxformseq = gampxformseq(outprof);
448                 if (!inpxformseq || !outpxformseq)
449                         goto error;
450                 if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
451                   jas_cmpxformseq_appendcnvt(xform->pxformseq,
452                   inprof->refclrspc, outprof->refclrspc) ||
453                   jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
454                         goto error;
455                 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
456                 xform->numoutchans = 1;
457                 break;
458         }
459         return xform;
460 error:
461         return 0;
462 }
463
464 #define APPLYBUFSIZ     2048
465 int jas_cmxform_apply(jas_cmxform_t *xform, jas_cmpixmap_t *in, jas_cmpixmap_t *out)
466 {
467         jas_cmcmptfmt_t *fmt;
468         jas_cmreal_t buf[2][APPLYBUFSIZ];
469         jas_cmpxformseq_t *pxformseq;
470         int i;
471         int j;
472         int width;
473         int height;
474         int total;
475         int n;
476         jas_cmreal_t *inbuf;
477         jas_cmreal_t *outbuf;
478         jas_cmpxform_t *pxform;
479         long *dataptr;
480         int maxchans;
481         int bufmax;
482         int m;
483         int bias;
484         jas_cmreal_t scale;
485         long v;
486         jas_cmreal_t *bufptr;
487
488         if (xform->numinchans > in->numcmpts || xform->numoutchans > out->numcmpts)
489                 goto error;
490
491         fmt = &in->cmptfmts[0];
492         width = fmt->width;
493         height = fmt->height;
494         for (i = 1; i < xform->numinchans; ++i) {
495                 fmt = &in->cmptfmts[i];
496                 if (fmt->width != width || fmt->height != height) {
497                         goto error;
498                 }
499         }
500         for (i = 0; i < xform->numoutchans; ++i) {
501                 fmt = &out->cmptfmts[i];
502                 if (fmt->width != width || fmt->height != height) {
503                         goto error;
504                 }
505         }
506
507         maxchans = 0;
508         pxformseq = xform->pxformseq;
509         for (i = 0; i < pxformseq->numpxforms; ++i) {
510                 pxform = pxformseq->pxforms[i];
511                 if (pxform->numinchans > maxchans) {
512                         maxchans = pxform->numinchans;
513                 }
514                 if (pxform->numoutchans > maxchans) {
515                         maxchans = pxform->numoutchans;
516                 }
517         }
518         bufmax = APPLYBUFSIZ / maxchans;
519         assert(bufmax > 0);
520
521         total = width * height;
522         n = 0;
523         while (n < total) {
524
525                 inbuf = &buf[0][0];
526                 m = JAS_MIN(total - n, bufmax);
527
528                 for (i = 0; i < xform->numinchans; ++i) {
529                         fmt = &in->cmptfmts[i];
530                         scale = (double)((1 << fmt->prec) - 1);
531                         bias = fmt->sgnd ? (1 << (fmt->prec - 1)) : 0;
532                         dataptr = &fmt->buf[n];
533                         bufptr = &inbuf[i];
534                         for (j = 0; j < m; ++j) {
535                                 if (jas_cmgetint(&dataptr, fmt->sgnd, fmt->prec, &v))
536                                         goto error;
537                                 *bufptr = (v - bias) / scale;
538                                 bufptr += xform->numinchans;
539                         }
540                 }
541
542                 inbuf = &buf[0][0];
543                 outbuf = inbuf;
544                 for (i = 0; i < pxformseq->numpxforms; ++i) {
545                         pxform = pxformseq->pxforms[i];
546                         if (pxform->numoutchans > pxform->numinchans) {
547                                 outbuf = (inbuf == &buf[0][0]) ? &buf[1][0] : &buf[0][0];
548                         } else {
549                                 outbuf = inbuf;
550                         }
551                         if ((*pxform->ops->apply)(pxform, inbuf, outbuf, m))
552                                 goto error;
553                         inbuf = outbuf;
554                 }
555
556                 for (i = 0; i < xform->numoutchans; ++i) {
557                         fmt = &out->cmptfmts[i];
558                         scale = (double)((1 << fmt->prec) - 1);
559                         bias = fmt->sgnd ? (1 << (fmt->prec - 1)) : 0;
560                         bufptr = &outbuf[i];
561                         dataptr = &fmt->buf[n];
562                         for (j = 0; j < m; ++j) {
563                                 v = (*bufptr) * scale + bias;
564                                 bufptr += xform->numoutchans;
565                                 if (jas_cmputint(&dataptr, fmt->sgnd, fmt->prec, v))
566                                         goto error;
567                         }
568                 }
569         
570                 n += m;
571         }
572         
573         return 0;
574 error:
575         return -1;
576 }
577
578 void jas_cmxform_destroy(jas_cmxform_t *xform)
579 {
580         if (xform->pxformseq)
581                 jas_cmpxformseq_destroy(xform->pxformseq);
582         jas_free(xform);
583 }
584
585 /******************************************************************************\
586 * Primitive transform sequence class.
587 \******************************************************************************/
588
589 static jas_cmpxformseq_t *jas_cmpxformseq_create()
590 {
591         jas_cmpxformseq_t *pxformseq;
592         pxformseq = 0;
593         if (!(pxformseq = jas_malloc(sizeof(jas_cmpxformseq_t))))
594                 goto error;
595         pxformseq->pxforms = 0;
596         pxformseq->numpxforms = 0;
597         pxformseq->maxpxforms = 0;
598         if (jas_cmpxformseq_resize(pxformseq, 16))
599                 goto error;
600         return pxformseq;
601 error:
602         if (pxformseq)
603                 jas_cmpxformseq_destroy(pxformseq);
604         return 0;
605 }
606
607 static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq)
608 {
609         jas_cmpxformseq_t *newpxformseq;
610
611         if (!(newpxformseq = jas_cmpxformseq_create()))
612                 goto error;
613         if (jas_cmpxformseq_append(newpxformseq, pxformseq))
614                 goto error;
615         return newpxformseq;
616 error:
617         return 0;
618 }
619
620 static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq)
621 {
622         while (pxformseq->numpxforms > 0)
623                 jas_cmpxformseq_delete(pxformseq, pxformseq->numpxforms - 1);
624         if (pxformseq->pxforms)
625                 jas_free(pxformseq->pxforms);
626         jas_free(pxformseq);
627 }
628
629 static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i)
630 {
631         assert(i >= 0 && i < pxformseq->numpxforms);
632         if (i != pxformseq->numpxforms - 1)
633                 abort();
634         jas_cmpxform_destroy(pxformseq->pxforms[i]);
635         pxformseq->pxforms[i] = 0;
636         --pxformseq->numpxforms;
637         return 0;
638 }
639
640 static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
641   int dstclrspc, int srcclrspc)
642 {
643         if (dstclrspc == srcclrspc)
644                 return 0;
645         abort();
646         /* Avoid compiler warnings about unused parameters. */
647         pxformseq = 0;
648         return -1;
649 }
650
651 static int jas_cmpxformseq_insertpxform(jas_cmpxformseq_t *pxformseq,
652   int i, jas_cmpxform_t *pxform)
653 {
654         jas_cmpxform_t *tmppxform;
655         int n;
656         if (i < 0)
657                 i = pxformseq->numpxforms;
658         assert(i >= 0 && i <= pxformseq->numpxforms);
659         if (pxformseq->numpxforms >= pxformseq->maxpxforms) {
660                 if (jas_cmpxformseq_resize(pxformseq, pxformseq->numpxforms +
661                   16))
662                         goto error;
663         }
664         assert(pxformseq->numpxforms < pxformseq->maxpxforms);
665         if (!(tmppxform = jas_cmpxform_copy(pxform)))
666                 goto error;
667         n = pxformseq->numpxforms - i;
668         if (n > 0) {
669                 memmove(&pxformseq->pxforms[i + 1], &pxformseq->pxforms[i],
670                   n * sizeof(jas_cmpxform_t *));
671         }
672         pxformseq->pxforms[i] = tmppxform;
673         ++pxformseq->numpxforms;
674         return 0;
675 error:
676         return -1;
677 }
678
679 static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
680   jas_cmpxformseq_t *othpxformseq)
681 {
682         int n;
683         int i;
684         jas_cmpxform_t *pxform;
685         jas_cmpxform_t *othpxform;
686         n = pxformseq->numpxforms + othpxformseq->numpxforms;
687         if (n > pxformseq->maxpxforms) {
688                 if (jas_cmpxformseq_resize(pxformseq, n))
689                         goto error;
690         }
691         for (i = 0; i < othpxformseq->numpxforms; ++i) {
692                 othpxform = othpxformseq->pxforms[i];
693                 if (!(pxform = jas_cmpxform_copy(othpxform)))
694                         goto error;
695                 pxformseq->pxforms[pxformseq->numpxforms] = pxform;
696                 ++pxformseq->numpxforms;
697         }
698         return 0;
699 error:
700         return -1;
701 }
702
703 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n)
704 {
705         jas_cmpxform_t **p;
706         assert(n >= pxformseq->numpxforms);
707         p = (!pxformseq->pxforms) ? jas_malloc(n * sizeof(jas_cmpxform_t *)) :
708           jas_realloc(pxformseq->pxforms, n * sizeof(jas_cmpxform_t *));
709         if (!p) {
710                 return -1;
711         }
712         pxformseq->pxforms = p;
713         pxformseq->maxpxforms = n;
714         return 0;
715 }
716
717 /******************************************************************************\
718 * Primitive transform class.
719 \******************************************************************************/
720
721 static jas_cmpxform_t *jas_cmpxform_create0()
722 {
723         jas_cmpxform_t *pxform;
724         if (!(pxform = jas_malloc(sizeof(jas_cmpxform_t))))
725                 return 0;
726         memset(pxform, 0, sizeof(jas_cmpxform_t));
727         pxform->refcnt = 0;
728         pxform->ops = 0;
729         return pxform;
730 }
731
732 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform)
733 {
734         if (--pxform->refcnt <= 0) {
735                 (*pxform->ops->destroy)(pxform);
736                 jas_free(pxform);
737         }
738 }
739
740 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform)
741 {
742         ++pxform->refcnt;
743         return pxform;
744 }
745
746 /******************************************************************************\
747 * Shaper matrix class.
748 \******************************************************************************/
749
750 static jas_cmpxform_t *jas_cmpxform_createshapmat()
751 {
752         int i;
753         int j;
754         jas_cmpxform_t *pxform;
755         jas_cmshapmat_t *shapmat;
756         if (!(pxform = jas_cmpxform_create0()))
757                 return 0;
758         pxform->ops = &shapmat_ops;
759         shapmat = &pxform->data.shapmat;
760         shapmat->mono = 0;
761         shapmat->order = 0;
762         shapmat->useluts = 0;
763         shapmat->usemat = 0;
764         for (i = 0; i < 3; ++i)
765                 jas_cmshapmatlut_init(&shapmat->luts[i]);
766         for (i = 0; i < 3; ++i) {
767                 for (j = 0; j < 4; ++j)
768                         shapmat->mat[i][j] = 0.0;
769         }
770         ++pxform->refcnt;
771         return pxform;
772 }
773
774 static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform)
775 {
776         jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
777         int i;
778         for (i = 0; i < 3; ++i)
779                 jas_cmshapmatlut_cleanup(&shapmat->luts[i]);
780 }
781
782 static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
783   jas_cmreal_t *out, int cnt)
784 {
785         jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
786         jas_cmreal_t *src;
787         jas_cmreal_t *dst;
788         jas_cmreal_t a0;
789         jas_cmreal_t a1;
790         jas_cmreal_t a2;
791         jas_cmreal_t b0;
792         jas_cmreal_t b1;
793         jas_cmreal_t b2;
794         src = in;
795         dst = out;
796         if (!shapmat->mono) {
797                 while (--cnt >= 0) {
798                         a0 = *src++;
799                         a1 = *src++;
800                         a2 = *src++;
801                         if (!shapmat->order && shapmat->useluts) {
802                                 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
803                                 a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
804                                 a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
805                         }
806                         if (shapmat->usemat) {
807                                 b0 = shapmat->mat[0][0] * a0
808                                   + shapmat->mat[0][1] * a1
809                                   + shapmat->mat[0][2] * a2
810                                   + shapmat->mat[0][3];
811                                 b1 = shapmat->mat[1][0] * a0
812                                   + shapmat->mat[1][1] * a1
813                                   + shapmat->mat[1][2] * a2
814                                   + shapmat->mat[1][3];
815                                 b2 = shapmat->mat[2][0] * a0
816                                   + shapmat->mat[2][1] * a1
817                                   + shapmat->mat[2][2] * a2
818                                   + shapmat->mat[2][3];
819                                 a0 = b0;
820                                 a1 = b1;
821                                 a2 = b2;
822                         }
823                         if (shapmat->order && shapmat->useluts) {
824                                 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
825                                 a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
826                                 a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
827                         }
828                         *dst++ = a0;
829                         *dst++ = a1;
830                         *dst++ = a2;
831                 }
832         } else {
833                 if (!shapmat->order) {
834                         while (--cnt >= 0) {
835                                 a0 = *src++;
836                                 if (shapmat->useluts)
837                                         a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
838                                 a2 = a0 * shapmat->mat[2][0];
839                                 a1 = a0 * shapmat->mat[1][0];
840                                 a0 = a0 * shapmat->mat[0][0];
841                                 *dst++ = a0;
842                                 *dst++ = a1;
843                                 *dst++ = a2;
844                         }
845                 } else {
846 assert(0);
847                         while (--cnt >= 0) {
848                                 a0 = *src++;
849                                 src++;
850                                 src++;
851                                 a0 = a0 * shapmat->mat[0][0];
852                                 if (shapmat->useluts)
853                                         a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
854                                 *dst++ = a0;
855                         }
856                 }
857         }
858
859         return 0;
860 }
861
862 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
863 {
864         lut->data = 0;
865         lut->size = 0;
866 }
867
868 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
869 {
870         if (lut->data) {
871                 jas_free(lut->data);
872                 lut->data = 0;
873         }
874         lut->size = 0;
875 }
876
877 static double gammafn(double x, double gamma)
878 {
879         if (x == 0.0)
880                 return 0.0;
881         return pow(x, gamma);
882 }
883
884 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
885 {
886         jas_cmreal_t gamma;
887         int i;
888         gamma = 0;
889         jas_cmshapmatlut_cleanup(lut);
890         if (curv->numents == 0) {
891                 lut->size = 2;
892                 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
893                         goto error;
894                 lut->data[0] = 0.0;
895                 lut->data[1] = 1.0;
896         } else if (curv->numents == 1) {
897                 lut->size = 256;
898                 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
899                         goto error;
900                 gamma = curv->ents[0] / 256.0;
901                 for (i = 0; i < lut->size; ++i) {
902                         lut->data[i] = gammafn(i / (double) (lut->size - 1), gamma);
903                 }
904         } else {
905                 lut->size = curv->numents;
906                 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
907                         goto error;
908                 for (i = 0; i < lut->size; ++i) {
909                         lut->data[i] = curv->ents[i] / 65535.0;
910                 }
911         }
912         return 0;
913 error:
914         return -1;
915 }
916
917 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
918 {
919         jas_cmreal_t t;
920         int lo;
921         int hi;
922         t = x * (lut->size - 1);
923         lo = floor(t);
924         if (lo < 0)
925                 return lut->data[0];
926         hi = ceil(t);
927         if (hi >= lut->size)
928                 return lut->data[lut->size - 1];
929         return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
930 }
931
932 static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
933   jas_cmshapmatlut_t *lut, int n)
934 {
935         int i;
936         int j;
937         int k;
938         jas_cmreal_t ax;
939         jas_cmreal_t ay;
940         jas_cmreal_t bx;
941         jas_cmreal_t by;
942         jas_cmreal_t sx;
943         jas_cmreal_t sy;
944         assert(n >= 2);
945         if (invlut->data) {
946                 jas_free(invlut->data);
947                 invlut->data = 0;
948         }
949         /* The sample values should be nondecreasing. */
950         for (i = 1; i < lut->size; ++i) {
951                 if (lut->data[i - 1] > lut->data[i]) {
952                         assert(0);
953                         return -1;
954                 }
955         }
956         if (!(invlut->data = jas_malloc(n * sizeof(jas_cmreal_t))))
957                 return -1;
958         invlut->size = n;
959         for (i = 0; i < invlut->size; ++i) {
960                 sy = ((double) i) / (invlut->size - 1);
961                 sx = 1.0;
962                 for (j = 0; j < lut->size; ++j) {
963                         ay = lut->data[j];
964                         if (sy == ay) {
965                                 for (k = j + 1; k < lut->size; ++k) {
966                                         by = lut->data[k];
967                                         if (by != sy)
968                                                 break;
969 #if 0
970 assert(0);
971 #endif
972                                 }
973                                 if (k < lut->size) {
974                                         --k;
975                                         ax = ((double) j) / (lut->size - 1);
976                                         bx = ((double) k) / (lut->size - 1);
977                                         sx = (ax + bx) / 2.0;
978                                 }
979                                 break;
980                         }
981                         if (j < lut->size - 1) {
982                                 by = lut->data[j + 1];
983                                 if (sy > ay && sy < by) {
984                                         ax = ((double) j) / (lut->size - 1);
985                                         bx = ((double) j + 1) / (lut->size - 1);
986                                         sx = ax +
987                                           (sy - ay) / (by - ay) * (bx - ax);
988                                         break;
989                                 }
990                         }
991                 }
992                 invlut->data[i] = sx;
993         }
994 #if 0
995 for (i=0;i<lut->size;++i)
996         jas_eprintf("lut[%d]=%f ", i, lut->data[i]);
997 for (i=0;i<invlut->size;++i)
998         jas_eprintf("invlut[%d]=%f ", i, invlut->data[i]);
999 #endif
1000         return 0;
1001 }
1002
1003 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
1004 {
1005         jas_cmreal_t d;
1006         d = in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1])
1007           - in[0][1] * (in[1][0] * in[2][2] - in[1][2] * in[2][0])
1008           + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]);
1009 #if 0
1010 jas_eprintf("delta=%f\n", d);
1011 #endif
1012         if (JAS_ABS(d) < 1e-6)
1013                 return -1;
1014         out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) / d;
1015         out[1][0] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) / d;
1016         out[2][0] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) / d;
1017         out[0][1] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) / d;
1018         out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) / d;
1019         out[2][1] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) / d;
1020         out[0][2] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) / d;
1021         out[1][2] = -(in[0][0] * in[1][2] - in[1][0] * in[0][2]) / d;
1022         out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) / d;
1023         out[0][3] = -in[0][3];
1024         out[1][3] = -in[1][3];
1025         out[2][3] = -in[2][3];
1026 #if 0
1027 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1028 in[0][0], in[0][1], in[0][2], in[0][3],
1029 in[1][0], in[1][1], in[1][2], in[1][3],
1030 in[2][0], in[2][1], in[2][2], in[2][3]);
1031 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1032 out[0][0], out[0][1], out[0][2], out[0][3],
1033 out[1][0], out[1][1], out[1][2], out[1][3],
1034 out[2][0], out[2][1], out[2][2], out[2][3]);
1035 #endif
1036         return 0;
1037 }
1038
1039 /******************************************************************************\
1040 *
1041 \******************************************************************************/
1042
1043 static int icctoclrspc(int iccclrspc, int refflag)
1044 {
1045         if (refflag) {
1046                 switch (iccclrspc) {
1047                 case JAS_ICC_COLORSPC_XYZ:
1048                         return JAS_CLRSPC_CIEXYZ;
1049                 case JAS_ICC_COLORSPC_LAB:
1050                         return JAS_CLRSPC_CIELAB;
1051                 default:
1052                         abort();
1053                         break;
1054                 }
1055         } else {
1056                 switch (iccclrspc) {
1057                 case JAS_ICC_COLORSPC_YCBCR:
1058                         return JAS_CLRSPC_GENYCBCR;
1059                 case JAS_ICC_COLORSPC_RGB:
1060                         return JAS_CLRSPC_GENRGB;
1061                 case JAS_ICC_COLORSPC_GRAY:
1062                         return JAS_CLRSPC_GENGRAY;
1063                 default:
1064                         abort();
1065                         break;
1066                 }
1067         }
1068 }
1069
1070 static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1071 {
1072         jas_iccattrval_t *graytrc;
1073         jas_cmshapmat_t *shapmat;
1074         jas_cmpxform_t *pxform;
1075         jas_cmpxformseq_t *pxformseq;
1076         jas_cmshapmatlut_t lut;
1077
1078         jas_cmshapmatlut_init(&lut);
1079         if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1080           graytrc->type != JAS_ICC_TYPE_CURV)
1081                 goto error;
1082         if (!(pxform = jas_cmpxform_createshapmat()))
1083                 goto error;
1084         shapmat = &pxform->data.shapmat;
1085         if (!(pxformseq = jas_cmpxformseq_create()))
1086                 goto error;
1087         if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1088                 goto error;
1089
1090         pxform->numinchans = 1;
1091         pxform->numoutchans = 3;
1092
1093         shapmat->mono = 1;
1094         shapmat->useluts = 1;
1095         shapmat->usemat = 1;
1096         if (!op) {
1097                 shapmat->order = 0;
1098                 shapmat->mat[0][0] = 0.9642;
1099                 shapmat->mat[1][0] = 1.0;
1100                 shapmat->mat[2][0] = 0.8249;
1101                 if (jas_cmshapmatlut_set(&shapmat->luts[0], &graytrc->data.curv))
1102                         goto error;
1103         } else {
1104                 shapmat->order = 1;
1105                 shapmat->mat[0][0] = 1.0 / 0.9642;
1106                 shapmat->mat[1][0] = 1.0;
1107                 shapmat->mat[2][0] = 1.0 / 0.8249;
1108                 jas_cmshapmatlut_init(&lut);
1109                 if (jas_cmshapmatlut_set(&lut, &graytrc->data.curv))
1110                         goto error;
1111                 if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1112                         goto error;
1113                 jas_cmshapmatlut_cleanup(&lut);
1114         }
1115         jas_iccattrval_destroy(graytrc);
1116         jas_cmpxform_destroy(pxform);
1117         *retpxformseq = pxformseq;
1118         return 0;
1119 error:
1120         return -1;
1121 }
1122
1123 static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1124 {
1125         int i;
1126         jas_iccattrval_t *trcs[3];
1127         jas_iccattrval_t *cols[3];
1128         jas_cmshapmat_t *shapmat;
1129         jas_cmpxform_t *pxform;
1130         jas_cmpxformseq_t *pxformseq;
1131         jas_cmreal_t mat[3][4];
1132         jas_cmshapmatlut_t lut;
1133
1134         pxform = 0;
1135         pxformseq = 0;
1136         for (i = 0; i < 3; ++i) {
1137                 trcs[i] = 0;
1138                 cols[i] = 0;
1139         }
1140         jas_cmshapmatlut_init(&lut);
1141
1142         if (!(trcs[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDTRC)) ||
1143           !(trcs[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNTRC)) ||
1144           !(trcs[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUTRC)) ||
1145           !(cols[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDMATCOL)) ||
1146           !(cols[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNMATCOL)) ||
1147           !(cols[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUMATCOL)))
1148                 goto error;
1149         for (i = 0; i < 3; ++i) {
1150                 if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1151                   cols[i]->type != JAS_ICC_TYPE_XYZ)
1152                         goto error;
1153         }
1154         if (!(pxform = jas_cmpxform_createshapmat()))
1155                 goto error;
1156         pxform->numinchans = 3;
1157         pxform->numoutchans = 3;
1158         shapmat = &pxform->data.shapmat;
1159         if (!(pxformseq = jas_cmpxformseq_create()))
1160                 goto error;
1161         if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1162                 goto error;
1163         shapmat->mono = 0;
1164         shapmat->useluts = 1;
1165         shapmat->usemat = 1;
1166         if (!op) {
1167                 shapmat->order = 0;
1168                 for (i = 0; i < 3; ++i) {
1169                         shapmat->mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1170                         shapmat->mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1171                         shapmat->mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1172                 }
1173                 for (i = 0; i < 3; ++i)
1174                         shapmat->mat[i][3] = 0.0;
1175                 for (i = 0; i < 3; ++i) {
1176                         if (jas_cmshapmatlut_set(&shapmat->luts[i], &trcs[i]->data.curv))
1177                                 goto error;
1178                 }
1179         } else {
1180                 shapmat->order = 1;
1181                 for (i = 0; i < 3; ++i) {
1182                         mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1183                         mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1184                         mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1185                 }
1186                 for (i = 0; i < 3; ++i)
1187                         mat[i][3] = 0.0;
1188                 if (jas_cmshapmat_invmat(shapmat->mat, mat))
1189                         goto error;
1190                 for (i = 0; i < 3; ++i) {
1191                         jas_cmshapmatlut_init(&lut);
1192                         if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1193                                 goto error;
1194                         if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1195                                 goto error;
1196                         jas_cmshapmatlut_cleanup(&lut);
1197                 }
1198         }
1199         for (i = 0; i < 3; ++i) {
1200                 jas_iccattrval_destroy(trcs[i]);
1201                 jas_iccattrval_destroy(cols[i]);
1202         }
1203         jas_cmpxform_destroy(pxform);
1204         *retpxformseq = pxformseq;
1205         return 0;
1206
1207 error:
1208
1209         for (i = 0; i < 3; ++i) {
1210                 if (trcs[i]) {
1211                         jas_iccattrval_destroy(trcs[i]);
1212                 }
1213                 if (cols[i]) {
1214                         jas_iccattrval_destroy(cols[i]);
1215                 }
1216         }
1217         if (pxformseq) {
1218                 jas_cmpxformseq_destroy(pxformseq);
1219         }
1220         if (pxform) {
1221                 jas_cmpxform_destroy(pxform);
1222         }
1223
1224         return -1;
1225 }
1226
1227 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1228 {
1229         long v;
1230         int m;
1231         v = **bufptr;
1232         if (sgnd) {
1233                 m = (1 << (prec - 1));
1234                 if (v < -m || v >= m)
1235                         return -1;
1236         } else {
1237                 if (v < 0 || v >= (1 << prec))
1238                         return -1;
1239         }
1240         ++(*bufptr);
1241         *val = v;
1242         return 0;
1243 }
1244
1245 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1246 {
1247         int m;
1248         if (sgnd) {
1249                 m = (1 << (prec - 1));
1250                 if (val < -m || val >= m)
1251                         return -1;
1252         } else {
1253                 if (val < 0 || val >= (1 << prec))
1254                         return -1;
1255         }
1256         **bufptr = val;
1257         ++(*bufptr);
1258         return 0;
1259 }
1260
1261 int jas_clrspc_numchans(int clrspc)
1262 {
1263         switch (jas_clrspc_fam(clrspc)) {
1264         case JAS_CLRSPC_FAM_XYZ:
1265         case JAS_CLRSPC_FAM_LAB:
1266         case JAS_CLRSPC_FAM_RGB:
1267         case JAS_CLRSPC_FAM_YCBCR:
1268                 return 3;
1269                 break;
1270         case JAS_CLRSPC_FAM_GRAY:
1271                 return 1;
1272                 break;
1273         default:
1274                 abort();
1275                 break;
1276         }
1277 }
1278
1279 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1280 {
1281         return jas_iccprof_copy(prof->iccprof);
1282 }