]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/base/jas_cm.c
COMP: Snap, forgot this one...
[gdcm.git] / src / gdcmjasper / src / libjasper / base / 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) 1999-2000 Image Power, Inc.
11  * Copyright (c) 1999-2000 The University of British Columbia
12  * Copyright (c) 2001-2003 Michael David Adams
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.1 2005/05/22 18:32:58 malaterre 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 #if 0
162     jas_iccprof_destroy(iccprof);
163 #else
164     prof->iccprof = iccprof;
165 #endif
166     if (!jas_clrspc_isgeneric(clrspc))
167       prof->clrspc = clrspc;
168     break;
169   }
170   return prof;
171 error:
172   if (iccprof)
173     jas_iccprof_destroy(iccprof);
174   return 0;
175 }
176
177 static jas_cmprof_t *jas_cmprof_createsycc()
178 {
179   jas_cmprof_t *prof;
180   jas_cmpxform_t *fwdpxform;
181   jas_cmpxform_t *revpxform;
182   jas_cmshapmat_t *fwdshapmat;
183   jas_cmshapmat_t *revshapmat;
184   int i;
185   int j;
186
187   if (!(prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
188     goto error;
189   prof->clrspc = JAS_CLRSPC_SYCBCR;
190   assert(prof->numchans == 3 && prof->numrefchans == 3);
191   assert(prof->refclrspc == JAS_CLRSPC_CIEXYZ);
192   if (!(fwdpxform = jas_cmpxform_createshapmat()))
193     goto error;
194   fwdpxform->numinchans = 3;
195   fwdpxform->numoutchans = 3;
196   fwdshapmat = &fwdpxform->data.shapmat;
197   fwdshapmat->mono = 0;
198   fwdshapmat->order = 0;
199   fwdshapmat->useluts = 0;
200   fwdshapmat->usemat = 1;
201   fwdshapmat->mat[0][0] = 1.0;
202   fwdshapmat->mat[0][1] = 0.0;
203   fwdshapmat->mat[0][2] = 1.402;
204   fwdshapmat->mat[1][0] = 1.0;
205   fwdshapmat->mat[1][1] = -0.34413;
206   fwdshapmat->mat[1][2] = -0.71414;
207   fwdshapmat->mat[2][0] = 1.0;
208   fwdshapmat->mat[2][1] = 1.772;
209   fwdshapmat->mat[2][2] = 0.0;
210   fwdshapmat->mat[0][3] = -0.5 * (1.402);
211   fwdshapmat->mat[1][3] = -0.5 * (-0.34413 - 0.71414);
212   fwdshapmat->mat[2][3] = -0.5 * (1.772);
213   if (!(revpxform = jas_cmpxform_createshapmat()))
214     goto error;
215   revpxform->numinchans = 3;
216   revpxform->numoutchans = 3;
217   revshapmat = &revpxform->data.shapmat;
218   revshapmat->mono = 0;
219   revshapmat->order = 1;
220   revshapmat->useluts = 0;
221   revshapmat->usemat = 1;
222   jas_cmshapmat_invmat(revshapmat->mat, fwdshapmat->mat);
223
224   for (i = 0; i < JAS_CMXFORM_NUMINTENTS; ++i) {
225     j = SEQFWD(i);
226     if (prof->pxformseqs[j]) {
227       if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j], 0,
228         fwdpxform))
229         goto error;
230     }
231     j = SEQREV(i);
232     if (prof->pxformseqs[j]) {
233       if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j],
234         -1, revpxform))
235         goto error;
236     }
237   }
238
239   jas_cmpxform_destroy(fwdpxform);
240   jas_cmpxform_destroy(revpxform);
241   return prof;
242 error:
243   return 0;
244 }
245
246 jas_cmprof_t *jas_cmprof_createfromiccprof(jas_iccprof_t *iccprof)
247 {
248   jas_cmprof_t *prof;
249   jas_icchdr_t icchdr;
250   jas_cmpxformseq_t *fwdpxformseq;
251   jas_cmpxformseq_t *revpxformseq;
252
253   if (!(prof = jas_cmprof_create()))
254     goto error;
255   jas_iccprof_gethdr(iccprof, &icchdr);
256   if (!(prof->iccprof = jas_iccprof_copy(iccprof)))
257     goto error;
258   prof->clrspc = icctoclrspc(icchdr.colorspc, 0);
259   prof->refclrspc = icctoclrspc(icchdr.refcolorspc, 1);
260   prof->numchans = jas_clrspc_numchans(prof->clrspc);
261   prof->numrefchans = jas_clrspc_numchans(prof->refclrspc);
262
263   if (prof->numchans == 1) {
264     if (mono(prof->iccprof, 0, &fwdpxformseq))
265       goto error;
266     if (mono(prof->iccprof, 1, &revpxformseq))
267       goto error;
268   } else if (prof->numchans == 3) {
269     if (triclr(prof->iccprof, 0, &fwdpxformseq))
270       goto error;
271     if (triclr(prof->iccprof, 1, &revpxformseq))
272       goto error;
273   }
274   prof->pxformseqs[SEQFWD(0)] = fwdpxformseq;
275   prof->pxformseqs[SEQREV(0)] = revpxformseq;
276
277 #if 0
278   if (prof->numchans > 1) {
279     lut(prof->iccprof, 0, PER, &pxformseq);
280     pxformseqs_set(prof, SEQFWD(PER), pxformseq);
281     lut(prof->iccprof, 1, PER, &pxformseq);
282     pxformseqs_set(prof, SEQREV(PER), pxformseq);
283     lut(prof->iccprof, 0, CLR, &pxformseq);
284     pxformseqs_set(prof, SEQREV(CLR), pxformseq);
285     lut(prof->iccprof, 1, CLR, &pxformseq);
286     pxformseqs_set(prof, SEQREV(CLR), pxformseq);
287     lut(prof->iccprof, 0, SAT, &pxformseq);
288     pxformseqs_set(prof, SEQREV(SAT), pxformseq);
289     lut(prof->iccprof, 1, SAT, &pxformseq);
290     pxformseqs_set(prof, SEQREV(SAT), pxformseq);
291   }
292 #endif
293
294   return prof;
295 error:
296   return 0;
297 }
298
299 static jas_cmprof_t *jas_cmprof_create()
300 {
301   int i;
302   jas_cmprof_t *prof;
303   if (!(prof = jas_malloc(sizeof(jas_cmprof_t))))
304     return 0;
305   memset(prof, 0, sizeof(jas_cmprof_t));
306   prof->iccprof = 0;
307   for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i)
308     prof->pxformseqs[i] = 0;
309   return prof;
310 }
311
312 void jas_cmprof_destroy(jas_cmprof_t *prof)
313
314   int i;
315   for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i) {
316     if (prof->pxformseqs[i]) {
317       jas_cmpxformseq_destroy(prof->pxformseqs[i]);
318       prof->pxformseqs[i] = 0;
319     }
320   }
321   if (prof->iccprof)
322     jas_iccprof_destroy(prof->iccprof);
323   jas_free(prof);
324 }
325
326 jas_cmprof_t *jas_cmprof_copy(jas_cmprof_t *prof)
327 {
328   jas_cmprof_t *newprof;
329   int i;
330
331   if (!(newprof = jas_cmprof_create()))
332     goto error;
333   newprof->clrspc = prof->clrspc;
334   newprof->numchans = prof->numchans;
335   newprof->refclrspc = prof->refclrspc;
336   newprof->numrefchans = prof->numrefchans;
337   newprof->iccprof = jas_iccprof_copy(prof->iccprof);
338   for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i) {
339     if (prof->pxformseqs[i]) {
340       if (!(newprof->pxformseqs[i] = jas_cmpxformseq_copy(prof->pxformseqs[i])))
341         goto error;
342     }
343   }
344   return newprof;
345 error:
346   return 0;
347 }
348
349 /******************************************************************************\
350 * Transform class.
351 \******************************************************************************/
352
353 jas_cmxform_t *jas_cmxform_create(jas_cmprof_t *inprof, jas_cmprof_t *outprof,
354   jas_cmprof_t *prfprof, int op, int intent, int optimize)
355 {
356   jas_cmxform_t *xform;
357   jas_cmpxformseq_t *inpxformseq;
358   jas_cmpxformseq_t *outpxformseq;
359   jas_cmpxformseq_t *altoutpxformseq;
360   jas_cmpxformseq_t *prfpxformseq;
361   int prfintent;
362
363   /* Avoid compiler warnings about unused parameters. */
364   optimize = 0;
365
366   prfintent = intent;
367
368   if (!(xform = jas_malloc(sizeof(jas_cmxform_t))))
369     goto error;
370   if (!(xform->pxformseq = jas_cmpxformseq_create()))
371     goto error;
372
373   switch (op) {
374   case JAS_CMXFORM_OP_FWD:
375     inpxformseq = fwdpxformseq(inprof, intent);
376     outpxformseq = revpxformseq(outprof, intent);
377     if (!inpxformseq || !outpxformseq)
378       goto error;
379     if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
380       jas_cmpxformseq_appendcnvt(xform->pxformseq,
381       inprof->refclrspc, outprof->refclrspc) ||
382       jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
383       goto error;
384     xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
385     xform->numoutchans = jas_clrspc_numchans(outprof->clrspc);
386     break;
387   case JAS_CMXFORM_OP_REV:
388     outpxformseq = fwdpxformseq(outprof, intent);
389     inpxformseq = revpxformseq(inprof, intent);
390     if (!outpxformseq || !inpxformseq)
391       goto error;
392     if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
393       jas_cmpxformseq_appendcnvt(xform->pxformseq,
394       outprof->refclrspc, inprof->refclrspc) ||
395       jas_cmpxformseq_append(xform->pxformseq, inpxformseq))
396       goto error;
397     xform->numinchans = jas_clrspc_numchans(outprof->clrspc);
398     xform->numoutchans = jas_clrspc_numchans(inprof->clrspc);
399     break;
400   case JAS_CMXFORM_OP_PROOF:
401     assert(prfprof);
402     inpxformseq = fwdpxformseq(inprof, intent);
403     prfpxformseq = fwdpxformseq(prfprof, prfintent);
404     if (!inpxformseq || !prfpxformseq)
405       goto error;
406     outpxformseq = simpxformseq(outprof, intent);
407     altoutpxformseq = 0;
408     if (!outpxformseq) {
409       outpxformseq = revpxformseq(outprof, intent);
410       altoutpxformseq = fwdpxformseq(outprof, intent);
411       if (!outpxformseq || !altoutpxformseq)
412         goto error;
413     }
414     if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
415       jas_cmpxformseq_appendcnvt(xform->pxformseq,
416       inprof->refclrspc, outprof->refclrspc))
417       goto error;
418     if (altoutpxformseq) {
419       if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
420         jas_cmpxformseq_append(xform->pxformseq, altoutpxformseq))
421         goto error;
422     } else {
423       if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
424         goto error;
425     }
426     if (jas_cmpxformseq_appendcnvt(xform->pxformseq,
427       outprof->refclrspc, inprof->refclrspc) ||
428       jas_cmpxformseq_append(xform->pxformseq, prfpxformseq))
429       goto error;
430     xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
431     xform->numoutchans = jas_clrspc_numchans(prfprof->clrspc);
432     break;
433   case JAS_CMXFORM_OP_GAMUT:
434     inpxformseq = fwdpxformseq(inprof, intent);
435     outpxformseq = gampxformseq(outprof);
436     if (!inpxformseq || !outpxformseq)
437       goto error;
438     if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
439       jas_cmpxformseq_appendcnvt(xform->pxformseq,
440       inprof->refclrspc, outprof->refclrspc) ||
441       jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
442       goto error;
443     xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
444     xform->numoutchans = 1;
445     break;
446   }
447   return xform;
448 error:
449   return 0;
450 }
451
452 #define  APPLYBUFSIZ  2048
453 int jas_cmxform_apply(jas_cmxform_t *xform, jas_cmpixmap_t *in, jas_cmpixmap_t *out)
454 {
455   jas_cmcmptfmt_t *fmt;
456   jas_cmreal_t buf[2][APPLYBUFSIZ];
457   jas_cmpxformseq_t *pxformseq;
458   int i;
459   int j;
460   int width;
461   int height;
462   int total;
463   int n;
464   jas_cmreal_t *inbuf;
465   jas_cmreal_t *outbuf;
466   jas_cmpxform_t *pxform;
467   long *dataptr;
468   int maxchans;
469   int bufmax;
470   int m;
471   int bias;
472   jas_cmreal_t scale;
473   long v;
474   jas_cmreal_t *bufptr;
475
476   if (xform->numinchans > in->numcmpts || xform->numoutchans > out->numcmpts)
477     goto error;
478
479   fmt = &in->cmptfmts[0];
480   width = fmt->width;
481   height = fmt->height;
482   for (i = 1; i < xform->numinchans; ++i) {
483     fmt = &in->cmptfmts[i];
484     if (fmt->width != width || fmt->height != height) {
485       goto error;
486     }
487   }
488   for (i = 0; i < xform->numoutchans; ++i) {
489     fmt = &out->cmptfmts[i];
490     if (fmt->width != width || fmt->height != height) {
491       goto error;
492     }
493   }
494
495   maxchans = 0;
496   pxformseq = xform->pxformseq;
497   for (i = 0; i < pxformseq->numpxforms; ++i) {
498     pxform = pxformseq->pxforms[i];
499     if (pxform->numinchans > maxchans) {
500       maxchans = pxform->numinchans;
501     }
502     if (pxform->numoutchans > maxchans) {
503       maxchans = pxform->numoutchans;
504     }
505   }
506   bufmax = APPLYBUFSIZ / maxchans;
507   assert(bufmax > 0);
508
509   total = width * height;
510   n = 0;
511   while (n < total) {
512
513     inbuf = &buf[0][0];
514     m = JAS_MIN(total - n, bufmax);
515
516     for (i = 0; i < xform->numinchans; ++i) {
517       fmt = &in->cmptfmts[i];
518       scale = (double)((1 << fmt->prec) - 1);
519       bias = fmt->sgnd ? (1 << (fmt->prec - 1)) : 0;
520       dataptr = &fmt->buf[n];
521       bufptr = &inbuf[i];
522       for (j = 0; j < m; ++j) {
523         if (jas_cmgetint(&dataptr, fmt->sgnd, fmt->prec, &v))
524           goto error;
525         *bufptr = (v - bias) / scale;
526         bufptr += xform->numinchans;
527       }
528     }
529
530     inbuf = &buf[0][0];
531     outbuf = inbuf;
532     for (i = 0; i < pxformseq->numpxforms; ++i) {
533       pxform = pxformseq->pxforms[i];
534       if (pxform->numoutchans > pxform->numinchans) {
535         outbuf = (inbuf == &buf[0][0]) ? &buf[1][0] : &buf[0][0];
536       } else {
537         outbuf = inbuf;
538       }
539       if ((*pxform->ops->apply)(pxform, inbuf, outbuf, m))
540         goto error;
541       inbuf = outbuf;
542     }
543
544     for (i = 0; i < xform->numoutchans; ++i) {
545       fmt = &out->cmptfmts[i];
546       scale = (double)((1 << fmt->prec) - 1);
547       bias = fmt->sgnd ? (1 << (fmt->prec - 1)) : 0;
548       bufptr = &outbuf[i];
549       dataptr = &fmt->buf[n];
550       for (j = 0; j < m; ++j) {
551         v = (*bufptr) * scale + bias;
552         bufptr += xform->numoutchans;
553         if (jas_cmputint(&dataptr, fmt->sgnd, fmt->prec, v))
554           goto error;
555       }
556     }
557   
558     n += m;
559   }
560   
561   return 0;
562 error:
563   return -1;
564 }
565
566 void jas_cmxform_destroy(jas_cmxform_t *xform)
567 {
568   if (xform->pxformseq)
569     jas_cmpxformseq_destroy(xform->pxformseq);
570   jas_free(xform);
571 }
572
573 /******************************************************************************\
574 * Primitive transform sequence class.
575 \******************************************************************************/
576
577 static jas_cmpxformseq_t *jas_cmpxformseq_create()
578 {
579   jas_cmpxformseq_t *pxformseq;
580   pxformseq = 0;
581   if (!(pxformseq = jas_malloc(sizeof(jas_cmpxformseq_t))))
582     goto error;
583   pxformseq->pxforms = 0;
584   pxformseq->numpxforms = 0;
585   pxformseq->maxpxforms = 0;
586   if (jas_cmpxformseq_resize(pxformseq, 16))
587     goto error;
588   return pxformseq;
589 error:
590   if (pxformseq)
591     jas_cmpxformseq_destroy(pxformseq);
592   return 0;
593 }
594
595 static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq)
596 {
597   jas_cmpxformseq_t *newpxformseq;
598
599   if (!(newpxformseq = jas_cmpxformseq_create()))
600     goto error;
601   if (jas_cmpxformseq_append(newpxformseq, pxformseq))
602     goto error;
603   return newpxformseq;
604 error:
605   return 0;
606 }
607
608 static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq)
609 {
610   while (pxformseq->numpxforms > 0)
611     jas_cmpxformseq_delete(pxformseq, pxformseq->numpxforms - 1);
612   if (pxformseq->pxforms)
613     jas_free(pxformseq->pxforms);
614   jas_free(pxformseq);
615 }
616
617 static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i)
618 {
619   assert(i >= 0 && i < pxformseq->numpxforms);
620   if (i != pxformseq->numpxforms - 1)
621     abort();
622   jas_cmpxform_destroy(pxformseq->pxforms[i]);
623   pxformseq->pxforms[i] = 0;
624   --pxformseq->numpxforms;
625   return 0;
626 }
627
628 static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
629   int dstclrspc, int srcclrspc)
630 {
631   if (dstclrspc == srcclrspc)
632     return 0;
633   abort();
634   /* Avoid compiler warnings about unused parameters. */
635   pxformseq = 0;
636   return -1;
637 }
638
639 static int jas_cmpxformseq_insertpxform(jas_cmpxformseq_t *pxformseq,
640   int i, jas_cmpxform_t *pxform)
641 {
642   jas_cmpxform_t *tmppxform;
643   int n;
644   if (i < 0)
645     i = pxformseq->numpxforms;
646   assert(i >= 0 && i <= pxformseq->numpxforms);
647   if (pxformseq->numpxforms >= pxformseq->maxpxforms) {
648     if (jas_cmpxformseq_resize(pxformseq, pxformseq->numpxforms +
649       16))
650       goto error;
651   }
652   assert(pxformseq->numpxforms < pxformseq->maxpxforms);
653   if (!(tmppxform = jas_cmpxform_copy(pxform)))
654     goto error;
655   n = pxformseq->numpxforms - i;
656   if (n > 0) {
657     memmove(&pxformseq->pxforms[i + 1], &pxformseq->pxforms[i],
658       n * sizeof(jas_cmpxform_t *));
659   }
660   pxformseq->pxforms[i] = tmppxform;
661   ++pxformseq->numpxforms;
662   return 0;
663 error:
664   return -1;
665 }
666
667 static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
668   jas_cmpxformseq_t *othpxformseq)
669 {
670   int n;
671   int i;
672   jas_cmpxform_t *pxform;
673   jas_cmpxform_t *othpxform;
674   n = pxformseq->numpxforms + othpxformseq->numpxforms;
675   if (n > pxformseq->maxpxforms) {
676     if (jas_cmpxformseq_resize(pxformseq, n))
677       goto error;
678   }
679   for (i = 0; i < othpxformseq->numpxforms; ++i) {
680     othpxform = othpxformseq->pxforms[i];
681     if (!(pxform = jas_cmpxform_copy(othpxform)))
682       goto error;
683     pxformseq->pxforms[pxformseq->numpxforms] = pxform;
684     ++pxformseq->numpxforms;
685   }
686   return 0;
687 error:
688   return -1;
689 }
690
691 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n)
692 {
693   jas_cmpxform_t **p;
694   assert(n >= pxformseq->numpxforms);
695   p = (!pxformseq->pxforms) ? jas_malloc(n * sizeof(jas_cmpxform_t *)) :
696     jas_realloc(pxformseq->pxforms, n * sizeof(jas_cmpxform_t *));
697   if (!p) {
698     return -1;
699   }
700   pxformseq->pxforms = p;
701   pxformseq->maxpxforms = n;
702   return 0;
703 }
704
705 /******************************************************************************\
706 * Primitive transform class.
707 \******************************************************************************/
708
709 static jas_cmpxform_t *jas_cmpxform_create0()
710 {
711   jas_cmpxform_t *pxform;
712   if (!(pxform = jas_malloc(sizeof(jas_cmpxform_t))))
713     return 0;
714   memset(pxform, 0, sizeof(jas_cmpxform_t));
715   pxform->refcnt = 0;
716   pxform->ops = 0;
717   return pxform;
718 }
719
720 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform)
721 {
722   if (--pxform->refcnt <= 0) {
723     (*pxform->ops->destroy)(pxform);
724     jas_free(pxform);
725   }
726 }
727
728 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform)
729 {
730   ++pxform->refcnt;
731   return pxform;
732 }
733
734 /******************************************************************************\
735 * Shaper matrix class.
736 \******************************************************************************/
737
738 static jas_cmpxform_t *jas_cmpxform_createshapmat()
739 {
740   int i;
741   int j;
742   jas_cmpxform_t *pxform;
743   jas_cmshapmat_t *shapmat;
744   if (!(pxform = jas_cmpxform_create0()))
745     return 0;
746   pxform->ops = &shapmat_ops;
747   shapmat = &pxform->data.shapmat;
748   shapmat->mono = 0;
749   shapmat->order = 0;
750   shapmat->useluts = 0;
751   shapmat->usemat = 0;
752   for (i = 0; i < 3; ++i)
753     jas_cmshapmatlut_init(&shapmat->luts[i]);
754   for (i = 0; i < 3; ++i) {
755     for (j = 0; j < 4; ++j)
756       shapmat->mat[i][j] = 0.0;
757   }
758   ++pxform->refcnt;
759   return pxform;
760 }
761
762 static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform)
763 {
764   jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
765   int i;
766   for (i = 0; i < 3; ++i)
767     jas_cmshapmatlut_cleanup(&shapmat->luts[i]);
768 }
769
770 static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
771   jas_cmreal_t *out, int cnt)
772 {
773   jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
774   jas_cmreal_t *src;
775   jas_cmreal_t *dst;
776   jas_cmreal_t a0;
777   jas_cmreal_t a1;
778   jas_cmreal_t a2;
779   jas_cmreal_t b0;
780   jas_cmreal_t b1;
781   jas_cmreal_t b2;
782   src = in;
783   dst = out;
784   if (!shapmat->mono) {
785     while (--cnt >= 0) {
786       a0 = *src++;
787       a1 = *src++;
788       a2 = *src++;
789       if (!shapmat->order && shapmat->useluts) {
790         a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
791         a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
792         a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
793       }
794       if (shapmat->usemat) {
795         b0 = shapmat->mat[0][0] * a0
796           + shapmat->mat[0][1] * a1
797           + shapmat->mat[0][2] * a2
798           + shapmat->mat[0][3];
799         b1 = shapmat->mat[1][0] * a0
800           + shapmat->mat[1][1] * a1
801           + shapmat->mat[1][2] * a2
802           + shapmat->mat[1][3];
803         b2 = shapmat->mat[2][0] * a0
804           + shapmat->mat[2][1] * a1
805           + shapmat->mat[2][2] * a2
806           + shapmat->mat[2][3];
807         a0 = b0;
808         a1 = b1;
809         a2 = b2;
810       }
811       if (shapmat->order && shapmat->useluts) {
812         a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
813         a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
814         a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
815       }
816       *dst++ = a0;
817       *dst++ = a1;
818       *dst++ = a2;
819     }
820   } else {
821     if (!shapmat->order) {
822       while (--cnt >= 0) {
823         a0 = *src++;
824         if (shapmat->useluts)
825           a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
826         a2 = a0 * shapmat->mat[2][0];
827         a1 = a0 * shapmat->mat[1][0];
828         a0 = a0 * shapmat->mat[0][0];
829         *dst++ = a0;
830         *dst++ = a1;
831         *dst++ = a2;
832       }
833     } else {
834 assert(0);
835       while (--cnt >= 0) {
836         a0 = *src++;
837         src++;
838         src++;
839         a0 = a0 * shapmat->mat[0][0];
840         if (shapmat->useluts)
841           a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
842         *dst++ = a0;
843       }
844     }
845   }
846
847   return 0;
848 }
849
850 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
851 {
852   lut->data = 0;
853   lut->size = 0;
854 }
855
856 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
857 {
858   if (lut->data) {
859     jas_free(lut->data);
860     lut->data = 0;
861   }
862   lut->size = 0;
863 }
864
865 static double gammafn(double x, double gamma)
866 {
867   if (x == 0.0)
868     return 0.0;
869   return pow(x, gamma);
870 }
871
872 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
873 {
874   jas_cmreal_t gamma;
875   int i;
876   gamma = 0;
877   jas_cmshapmatlut_cleanup(lut);
878   if (curv->numents == 0) {
879     lut->size = 2;
880     if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
881       goto error;
882     lut->data[0] = 0.0;
883     lut->data[1] = 1.0;
884   } else if (curv->numents == 1) {
885     lut->size = 256;
886     if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
887       goto error;
888     gamma = curv->ents[0] / 256.0;
889     for (i = 0; i < lut->size; ++i) {
890       lut->data[i] = gammafn(i / (double) (lut->size - 1), gamma);
891     }
892   } else {
893     lut->size = curv->numents;
894     if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
895       goto error;
896     for (i = 0; i < lut->size; ++i) {
897       lut->data[i] = curv->ents[i] / 65535.0;
898     }
899   }
900   return 0;
901 error:
902   return -1;
903 }
904
905 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
906 {
907   jas_cmreal_t t;
908   int lo;
909   int hi;
910   t = x * (lut->size - 1);
911   lo = floor(t);
912   if (lo < 0)
913     return lut->data[0];
914   hi = ceil(t);
915   if (hi >= lut->size)
916     return lut->data[lut->size - 1];
917   return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
918 }
919
920 static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
921   jas_cmshapmatlut_t *lut, int n)
922 {
923   int i;
924   int j;
925   int k;
926   jas_cmreal_t ax;
927   jas_cmreal_t ay;
928   jas_cmreal_t bx;
929   jas_cmreal_t by;
930   jas_cmreal_t sx;
931   jas_cmreal_t sy;
932   assert(n >= 2);
933   if (invlut->data) {
934     jas_free(invlut->data);
935     invlut->data = 0;
936   }
937   /* The sample values should be nondecreasing. */
938   for (i = 1; i < lut->size; ++i) {
939     if (lut->data[i - 1] > lut->data[i]) {
940       assert(0);
941       return -1;
942     }
943   }
944   if (!(invlut->data = jas_malloc(n * sizeof(jas_cmreal_t))))
945     return -1;
946   invlut->size = n;
947   for (i = 0; i < invlut->size; ++i) {
948     sy = ((double) i) / (invlut->size - 1);
949     sx = 1.0;
950     for (j = 0; j < lut->size; ++j) {
951       ay = lut->data[j];
952       if (sy == ay) {
953         for (k = j + 1; k < lut->size; ++k) {
954           by = lut->data[k];
955           if (by != sy)
956             break;
957 #if 0
958 assert(0);
959 #endif
960         }
961         if (k < lut->size) {
962           --k;
963           ax = ((double) j) / (lut->size - 1);
964           bx = ((double) k) / (lut->size - 1);
965           sx = (ax + bx) / 2.0;
966         }
967         break;
968       }
969       if (j < lut->size - 1) {
970         by = lut->data[j + 1];
971         if (sy > ay && sy < by) {
972           ax = ((double) j) / (lut->size - 1);
973           bx = ((double) j + 1) / (lut->size - 1);
974           sx = ax +
975             (sy - ay) / (by - ay) * (bx - ax);
976           break;
977         }
978       }
979     }
980     invlut->data[i] = sx;
981   }
982 #if 0
983 for (i=0;i<lut->size;++i)
984   fprintf(stderr, "lut[%d]=%f ", i, lut->data[i]);
985 for (i=0;i<invlut->size;++i)
986   fprintf(stderr, "invlut[%d]=%f ", i, invlut->data[i]);
987 #endif
988   return 0;
989 }
990
991 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
992 {
993   jas_cmreal_t d;
994   d = in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1])
995     - in[0][1] * (in[1][0] * in[2][2] - in[1][2] * in[2][0])
996     + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]);
997 #if 0
998 fprintf(stderr, "delta=%f\n", d);
999 #endif
1000   if (JAS_ABS(d) < 1e-6)
1001     return -1;
1002   out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) / d;
1003   out[1][0] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) / d;
1004   out[2][0] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) / d;
1005   out[0][1] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) / d;
1006   out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) / d;
1007   out[2][1] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) / d;
1008   out[0][2] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) / d;
1009   out[1][2] = -(in[0][0] * in[1][2] - in[1][0] * in[0][2]) / d;
1010   out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) / d;
1011   out[0][3] = -in[0][3];
1012   out[1][3] = -in[1][3];
1013   out[2][3] = -in[2][3];
1014 #if 0
1015 fprintf(stderr, "[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1016 in[0][0], in[0][1], in[0][2], in[0][3],
1017 in[1][0], in[1][1], in[1][2], in[1][3],
1018 in[2][0], in[2][1], in[2][2], in[2][3]);
1019 fprintf(stderr, "[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1020 out[0][0], out[0][1], out[0][2], out[0][3],
1021 out[1][0], out[1][1], out[1][2], out[1][3],
1022 out[2][0], out[2][1], out[2][2], out[2][3]);
1023 #endif
1024   return 0;
1025 }
1026
1027 /******************************************************************************\
1028 *
1029 \******************************************************************************/
1030
1031 static int icctoclrspc(int iccclrspc, int refflag)
1032 {
1033   if (refflag) {
1034     switch (iccclrspc) {
1035     case JAS_ICC_COLORSPC_XYZ:
1036       return JAS_CLRSPC_CIEXYZ;
1037     case JAS_ICC_COLORSPC_LAB:
1038       return JAS_CLRSPC_CIELAB;
1039     default:
1040       abort();
1041       break;
1042     }
1043   } else {
1044     switch (iccclrspc) {
1045     case JAS_ICC_COLORSPC_YCBCR:
1046       return JAS_CLRSPC_GENYCBCR;
1047     case JAS_ICC_COLORSPC_RGB:
1048       return JAS_CLRSPC_GENRGB;
1049     case JAS_ICC_COLORSPC_GRAY:
1050       return JAS_CLRSPC_GENGRAY;
1051     default:
1052       abort();
1053       break;
1054     }
1055   }
1056 }
1057
1058 static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1059 {
1060   jas_iccattrval_t *graytrc;
1061   jas_cmshapmat_t *shapmat;
1062   jas_cmpxform_t *pxform;
1063   jas_cmpxformseq_t *pxformseq;
1064   jas_cmshapmatlut_t lut;
1065
1066   jas_cmshapmatlut_init(&lut);
1067   if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1068     graytrc->type != JAS_ICC_TYPE_CURV)
1069     goto error;
1070   if (!(pxform = jas_cmpxform_createshapmat()))
1071     goto error;
1072   shapmat = &pxform->data.shapmat;
1073   if (!(pxformseq = jas_cmpxformseq_create()))
1074     goto error;
1075   if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1076     goto error;
1077
1078   pxform->numinchans = 1;
1079   pxform->numoutchans = 3;
1080
1081   shapmat->mono = 1;
1082   shapmat->useluts = 1;
1083   shapmat->usemat = 1;
1084   if (!op) {
1085     shapmat->order = 0;
1086     shapmat->mat[0][0] = 0.9642;
1087     shapmat->mat[1][0] = 1.0;
1088     shapmat->mat[2][0] = 0.8249;
1089     if (jas_cmshapmatlut_set(&shapmat->luts[0], &graytrc->data.curv))
1090       goto error;
1091   } else {
1092     shapmat->order = 1;
1093     shapmat->mat[0][0] = 1.0 / 0.9642;
1094     shapmat->mat[1][0] = 1.0;
1095     shapmat->mat[2][0] = 1.0 / 0.8249;
1096     jas_cmshapmatlut_init(&lut);
1097     if (jas_cmshapmatlut_set(&lut, &graytrc->data.curv))
1098       goto error;
1099     if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1100       goto error;
1101     jas_cmshapmatlut_cleanup(&lut);
1102   }
1103   jas_iccattrval_destroy(graytrc);
1104   jas_cmpxform_destroy(pxform);
1105   *retpxformseq = pxformseq;
1106   return 0;
1107 error:
1108   return -1;
1109 }
1110
1111 static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1112 {
1113   int i;
1114   jas_iccattrval_t *trcs[3];
1115   jas_iccattrval_t *cols[3];
1116   jas_cmshapmat_t *shapmat;
1117   jas_cmpxform_t *pxform;
1118   jas_cmpxformseq_t *pxformseq;
1119   jas_cmreal_t mat[3][4];
1120   jas_cmshapmatlut_t lut;
1121   jas_cmshapmatlut_init(&lut);
1122   for (i = 0; i < 3; ++i) {
1123     trcs[i] = 0;
1124     cols[i] = 0;
1125   }
1126   if (!(trcs[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDTRC)) ||
1127     !(trcs[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNTRC)) ||
1128     !(trcs[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUTRC)) ||
1129     !(cols[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDMATCOL)) ||
1130     !(cols[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNMATCOL)) ||
1131     !(cols[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUMATCOL)))
1132     goto error;
1133   for (i = 0; i < 3; ++i) {
1134     if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1135       cols[i]->type != JAS_ICC_TYPE_XYZ)
1136       goto error;
1137   }
1138   if (!(pxform = jas_cmpxform_createshapmat()))
1139     goto error;
1140   pxform->numinchans = 3;
1141   pxform->numoutchans = 3;
1142   shapmat = &pxform->data.shapmat;
1143   if (!(pxformseq = jas_cmpxformseq_create()))
1144     goto error;
1145   if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1146     goto error;
1147   shapmat->mono = 0;
1148   shapmat->useluts = 1;
1149   shapmat->usemat = 1;
1150   if (!op) {
1151     shapmat->order = 0;
1152     for (i = 0; i < 3; ++i) {
1153       shapmat->mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1154       shapmat->mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1155       shapmat->mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1156     }
1157     for (i = 0; i < 3; ++i)
1158       shapmat->mat[i][3] = 0.0;
1159     for (i = 0; i < 3; ++i) {
1160       if (jas_cmshapmatlut_set(&shapmat->luts[i], &trcs[i]->data.curv))
1161         goto error;
1162     }
1163   } else {
1164     shapmat->order = 1;
1165     for (i = 0; i < 3; ++i) {
1166       mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1167       mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1168       mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1169     }
1170     for (i = 0; i < 3; ++i)
1171       mat[i][3] = 0.0;
1172     if (jas_cmshapmat_invmat(shapmat->mat, mat))
1173       goto error;
1174     for (i = 0; i < 3; ++i) {
1175       jas_cmshapmatlut_init(&lut);
1176       if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1177         goto error;
1178       if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1179         goto error;
1180       jas_cmshapmatlut_cleanup(&lut);
1181     }
1182   }
1183   for (i = 0; i < 3; ++i) {
1184     jas_iccattrval_destroy(trcs[i]);
1185     jas_iccattrval_destroy(cols[i]);
1186   }
1187   jas_cmpxform_destroy(pxform);
1188   *retpxformseq = pxformseq;
1189   return 0;
1190 error:
1191   return -1;
1192 }
1193
1194 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1195 {
1196   long v;
1197   int m;
1198   v = **bufptr;
1199   if (sgnd) {
1200     m = (1 << (prec - 1));
1201     if (v < -m || v >= m)
1202       return -1;
1203   } else {
1204     if (v < 0 || v >= (1 << prec))
1205       return -1;
1206   }
1207   ++(*bufptr);
1208   *val = v;
1209   return 0;
1210 }
1211
1212 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1213 {
1214   int m;
1215   if (sgnd) {
1216     m = (1 << (prec - 1));
1217     if (val < -m || val >= m)
1218       return -1;
1219   } else {
1220     if (val < 0 || val >= (1 << prec))
1221       return -1;
1222   }
1223   **bufptr = val;
1224   ++(*bufptr);
1225   return 0;
1226 }
1227
1228 int jas_clrspc_numchans(int clrspc)
1229 {
1230   switch (jas_clrspc_fam(clrspc)) {
1231   case JAS_CLRSPC_FAM_XYZ:
1232   case JAS_CLRSPC_FAM_LAB:
1233   case JAS_CLRSPC_FAM_RGB:
1234   case JAS_CLRSPC_FAM_YCBCR:
1235     return 3;
1236     break;
1237   case JAS_CLRSPC_FAM_GRAY:
1238     return 1;
1239     break;
1240   default:
1241     abort();
1242     break;
1243   }
1244 }
1245
1246 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1247 {
1248   return jas_iccprof_copy(prof->iccprof);
1249 }