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
79static jas_cmprof_t *jas_cmprof_create(void);
80static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *);
81static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x);
82
83static void jas_cmpxform_destroy(jas_cmpxform_t *pxform);
84static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform);
85
86static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform);
87static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
88  jas_cmreal_t *out, int cnt);
89
90static int jas_cmputint(long **bufptr, int sgnd, int prec, long val);
91static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val);
92static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
93  jas_cmpxformseq_t *othpxformseq);
94static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
95  int, int);
96static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n);
97
98static int mono(jas_iccprof_t *prof, int op, jas_cmpxformseq_t **pxformseq);
99static int triclr(jas_iccprof_t *prof, int op, jas_cmpxformseq_t **retpxformseq);
100
101static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq);
102static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i);
103static jas_cmpxformseq_t *jas_cmpxformseq_create(void);
104static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq);
105static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4]);
106static 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
131static int icctoclrspc(int iccclrspc, int refflag);
132static jas_cmpxform_t *jas_cmpxform_create0(void);
133static jas_cmpxform_t *jas_cmpxform_createshapmat(void);
134static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut);
135static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv);
136
137static jas_cmpxformops_t shapmat_ops = {jas_cmshapmat_destroy, jas_cmshapmat_apply, 0};
138static jas_cmprof_t *jas_cmprof_createsycc(void);
139
140/******************************************************************************\
141* Color profile class.
142\******************************************************************************/
143
144jas_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;
168error:
169    if (iccprof)
170        jas_iccprof_destroy(iccprof);
171    return 0;
172}
173
174static 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;
239error:
240    return 0;
241}
242
243jas_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
297error:
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
311static 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
324void 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
338jas_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;
357error:
358    return 0;
359}
360
361/******************************************************************************\
362* Transform class.
363\******************************************************************************/
364
365jas_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;
460error:
461    return 0;
462}
463
464#define	APPLYBUFSIZ	2048
465int 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;
574error:
575    return -1;
576}
577
578void 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
589static 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;
601error:
602    if (pxformseq)
603        jas_cmpxformseq_destroy(pxformseq);
604    return 0;
605}
606
607static 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;
616error:
617    return 0;
618}
619
620static 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
629static 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
640static 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
651static 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;
675error:
676    return -1;
677}
678
679static 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;
699error:
700    return -1;
701}
702
703static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n)
704{
705    jas_cmpxform_t **p;
706    assert(n >= pxformseq->numpxforms);
707    p = jas_realloc2(pxformseq->pxforms, n, sizeof(jas_cmpxform_t *));
708    if (!p) {
709        return -1;
710    }
711    pxformseq->pxforms = p;
712    pxformseq->maxpxforms = n;
713    return 0;
714}
715
716/******************************************************************************\
717* Primitive transform class.
718\******************************************************************************/
719
720static jas_cmpxform_t *jas_cmpxform_create0()
721{
722    jas_cmpxform_t *pxform;
723    if (!(pxform = jas_malloc(sizeof(jas_cmpxform_t))))
724        return 0;
725    memset(pxform, 0, sizeof(jas_cmpxform_t));
726    pxform->refcnt = 0;
727    pxform->ops = 0;
728    return pxform;
729}
730
731static void jas_cmpxform_destroy(jas_cmpxform_t *pxform)
732{
733    if (--pxform->refcnt <= 0) {
734        (*pxform->ops->destroy)(pxform);
735        jas_free(pxform);
736    }
737}
738
739static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform)
740{
741    ++pxform->refcnt;
742    return pxform;
743}
744
745/******************************************************************************\
746* Shaper matrix class.
747\******************************************************************************/
748
749static jas_cmpxform_t *jas_cmpxform_createshapmat()
750{
751    int i;
752    int j;
753    jas_cmpxform_t *pxform;
754    jas_cmshapmat_t *shapmat;
755    if (!(pxform = jas_cmpxform_create0()))
756        return 0;
757    pxform->ops = &shapmat_ops;
758    shapmat = &pxform->data.shapmat;
759    shapmat->mono = 0;
760    shapmat->order = 0;
761    shapmat->useluts = 0;
762    shapmat->usemat = 0;
763    for (i = 0; i < 3; ++i)
764        jas_cmshapmatlut_init(&shapmat->luts[i]);
765    for (i = 0; i < 3; ++i) {
766        for (j = 0; j < 4; ++j)
767            shapmat->mat[i][j] = 0.0;
768    }
769    ++pxform->refcnt;
770    return pxform;
771}
772
773static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform)
774{
775    jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
776    int i;
777    for (i = 0; i < 3; ++i)
778        jas_cmshapmatlut_cleanup(&shapmat->luts[i]);
779}
780
781static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
782  jas_cmreal_t *out, int cnt)
783{
784    jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
785    jas_cmreal_t *src;
786    jas_cmreal_t *dst;
787    jas_cmreal_t a0;
788    jas_cmreal_t a1;
789    jas_cmreal_t a2;
790    jas_cmreal_t b0;
791    jas_cmreal_t b1;
792    jas_cmreal_t b2;
793    src = in;
794    dst = out;
795    if (!shapmat->mono) {
796        while (--cnt >= 0) {
797            a0 = *src++;
798            a1 = *src++;
799            a2 = *src++;
800            if (!shapmat->order && shapmat->useluts) {
801                a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
802                a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
803                a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
804            }
805            if (shapmat->usemat) {
806                b0 = shapmat->mat[0][0] * a0
807                  + shapmat->mat[0][1] * a1
808                  + shapmat->mat[0][2] * a2
809                  + shapmat->mat[0][3];
810                b1 = shapmat->mat[1][0] * a0
811                  + shapmat->mat[1][1] * a1
812                  + shapmat->mat[1][2] * a2
813                  + shapmat->mat[1][3];
814                b2 = shapmat->mat[2][0] * a0
815                  + shapmat->mat[2][1] * a1
816                  + shapmat->mat[2][2] * a2
817                  + shapmat->mat[2][3];
818                a0 = b0;
819                a1 = b1;
820                a2 = b2;
821            }
822            if (shapmat->order && shapmat->useluts) {
823                a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
824                a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
825                a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
826            }
827            *dst++ = a0;
828            *dst++ = a1;
829            *dst++ = a2;
830        }
831    } else {
832        if (!shapmat->order) {
833            while (--cnt >= 0) {
834                a0 = *src++;
835                if (shapmat->useluts)
836                    a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
837                a2 = a0 * shapmat->mat[2][0];
838                a1 = a0 * shapmat->mat[1][0];
839                a0 = a0 * shapmat->mat[0][0];
840                *dst++ = a0;
841                *dst++ = a1;
842                *dst++ = a2;
843            }
844        } else {
845            while (--cnt >= 0) {
846                a0 = *src++;
847                src++;
848                src++;
849                a0 = a0 * shapmat->mat[0][0];
850                if (shapmat->useluts)
851                    a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
852                *dst++ = a0;
853            }
854        }
855    }
856
857    return 0;
858}
859
860static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
861{
862    lut->data = 0;
863    lut->size = 0;
864}
865
866static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
867{
868    if (lut->data) {
869        jas_free(lut->data);
870        lut->data = 0;
871    }
872    lut->size = 0;
873}
874
875static double gammafn(double x, double gamma)
876{
877    if (x == 0.0)
878        return 0.0;
879    return pow(x, gamma);
880}
881
882static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
883{
884    jas_cmreal_t gamma;
885    int i;
886    gamma = 0;
887    jas_cmshapmatlut_cleanup(lut);
888    if (curv->numents == 0) {
889        lut->size = 2;
890        if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
891            goto error;
892        lut->data[0] = 0.0;
893        lut->data[1] = 1.0;
894    } else if (curv->numents == 1) {
895        lut->size = 256;
896        if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
897            goto error;
898        gamma = curv->ents[0] / 256.0;
899        for (i = 0; i < lut->size; ++i) {
900            lut->data[i] = gammafn(i / (double) (lut->size - 1), gamma);
901        }
902    } else {
903        lut->size = curv->numents;
904        if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
905            goto error;
906        for (i = 0; i < lut->size; ++i) {
907            lut->data[i] = curv->ents[i] / 65535.0;
908        }
909    }
910    return 0;
911error:
912    return -1;
913}
914
915static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
916{
917    jas_cmreal_t t;
918    int lo;
919    int hi;
920    t = x * (lut->size - 1);
921    lo = floor(t);
922    if (lo < 0)
923        return lut->data[0];
924    hi = ceil(t);
925    if (hi >= lut->size)
926        return lut->data[lut->size - 1];
927    return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
928}
929
930static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
931  jas_cmshapmatlut_t *lut, int n)
932{
933    int i;
934    int j;
935    int k;
936    jas_cmreal_t ax;
937    jas_cmreal_t ay;
938    jas_cmreal_t bx;
939    jas_cmreal_t by;
940    jas_cmreal_t sx;
941    jas_cmreal_t sy;
942    assert(n >= 2);
943    if (invlut->data) {
944        jas_free(invlut->data);
945        invlut->data = 0;
946    }
947    /* The sample values should be nondecreasing. */
948    for (i = 1; i < lut->size; ++i) {
949        if (lut->data[i - 1] > lut->data[i]) {
950            assert(0);
951            return -1;
952        }
953    }
954    if (!(invlut->data = jas_alloc2(n, sizeof(jas_cmreal_t))))
955        return -1;
956    invlut->size = n;
957    for (i = 0; i < invlut->size; ++i) {
958        sy = ((double) i) / (invlut->size - 1);
959        sx = 1.0;
960        for (j = 0; j < lut->size; ++j) {
961            ay = lut->data[j];
962            if (sy == ay) {
963                for (k = j + 1; k < lut->size; ++k) {
964                    by = lut->data[k];
965                    if (by != sy)
966                        break;
967#if 0
968assert(0);
969#endif
970                }
971                if (k < lut->size) {
972                    --k;
973                    ax = ((double) j) / (lut->size - 1);
974                    bx = ((double) k) / (lut->size - 1);
975                    sx = (ax + bx) / 2.0;
976                }
977                break;
978            }
979            if (j < lut->size - 1) {
980                by = lut->data[j + 1];
981                if (sy > ay && sy < by) {
982                    ax = ((double) j) / (lut->size - 1);
983                    bx = ((double) j + 1) / (lut->size - 1);
984                    sx = ax +
985                      (sy - ay) / (by - ay) * (bx - ax);
986                    break;
987                }
988            }
989        }
990        invlut->data[i] = sx;
991    }
992#if 0
993for (i=0;i<lut->size;++i)
994    jas_eprintf("lut[%d]=%f ", i, lut->data[i]);
995for (i=0;i<invlut->size;++i)
996    jas_eprintf("invlut[%d]=%f ", i, invlut->data[i]);
997#endif
998    return 0;
999}
1000
1001static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
1002{
1003    jas_cmreal_t d;
1004    d = in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1])
1005      - in[0][1] * (in[1][0] * in[2][2] - in[1][2] * in[2][0])
1006      + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]);
1007#if 0
1008jas_eprintf("delta=%f\n", d);
1009#endif
1010    if (JAS_ABS(d) < 1e-6)
1011        return -1;
1012    out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) / d;
1013    out[1][0] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) / d;
1014    out[2][0] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) / d;
1015    out[0][1] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) / d;
1016    out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) / d;
1017    out[2][1] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) / d;
1018    out[0][2] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) / d;
1019    out[1][2] = -(in[0][0] * in[1][2] - in[1][0] * in[0][2]) / d;
1020    out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) / d;
1021    out[0][3] = -in[0][3];
1022    out[1][3] = -in[1][3];
1023    out[2][3] = -in[2][3];
1024#if 0
1025jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1026in[0][0], in[0][1], in[0][2], in[0][3],
1027in[1][0], in[1][1], in[1][2], in[1][3],
1028in[2][0], in[2][1], in[2][2], in[2][3]);
1029jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1030out[0][0], out[0][1], out[0][2], out[0][3],
1031out[1][0], out[1][1], out[1][2], out[1][3],
1032out[2][0], out[2][1], out[2][2], out[2][3]);
1033#endif
1034    return 0;
1035}
1036
1037/******************************************************************************\
1038*
1039\******************************************************************************/
1040
1041static int icctoclrspc(int iccclrspc, int refflag)
1042{
1043    if (refflag) {
1044        switch (iccclrspc) {
1045        case JAS_ICC_COLORSPC_XYZ:
1046            return JAS_CLRSPC_CIEXYZ;
1047        case JAS_ICC_COLORSPC_LAB:
1048            return JAS_CLRSPC_CIELAB;
1049        default:
1050            abort();
1051            break;
1052        }
1053    } else {
1054        switch (iccclrspc) {
1055        case JAS_ICC_COLORSPC_YCBCR:
1056            return JAS_CLRSPC_GENYCBCR;
1057        case JAS_ICC_COLORSPC_RGB:
1058            return JAS_CLRSPC_GENRGB;
1059        case JAS_ICC_COLORSPC_GRAY:
1060            return JAS_CLRSPC_GENGRAY;
1061        default:
1062            abort();
1063            break;
1064        }
1065    }
1066}
1067
1068static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1069{
1070    jas_iccattrval_t *graytrc;
1071    jas_cmshapmat_t *shapmat;
1072    jas_cmpxform_t *pxform;
1073    jas_cmpxformseq_t *pxformseq;
1074    jas_cmshapmatlut_t lut;
1075
1076    jas_cmshapmatlut_init(&lut);
1077    if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1078      graytrc->type != JAS_ICC_TYPE_CURV)
1079        goto error;
1080    if (!(pxform = jas_cmpxform_createshapmat()))
1081        goto error;
1082    shapmat = &pxform->data.shapmat;
1083    if (!(pxformseq = jas_cmpxformseq_create()))
1084        goto error;
1085    if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1086        goto error;
1087
1088    pxform->numinchans = 1;
1089    pxform->numoutchans = 3;
1090
1091    shapmat->mono = 1;
1092    shapmat->useluts = 1;
1093    shapmat->usemat = 1;
1094    if (!op) {
1095        shapmat->order = 0;
1096        shapmat->mat[0][0] = 0.9642;
1097        shapmat->mat[1][0] = 1.0;
1098        shapmat->mat[2][0] = 0.8249;
1099        if (jas_cmshapmatlut_set(&shapmat->luts[0], &graytrc->data.curv))
1100            goto error;
1101    } else {
1102        shapmat->order = 1;
1103        shapmat->mat[0][0] = 1.0 / 0.9642;
1104        shapmat->mat[1][0] = 1.0;
1105        shapmat->mat[2][0] = 1.0 / 0.8249;
1106        jas_cmshapmatlut_init(&lut);
1107        if (jas_cmshapmatlut_set(&lut, &graytrc->data.curv))
1108            goto error;
1109        if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1110            goto error;
1111        jas_cmshapmatlut_cleanup(&lut);
1112    }
1113    jas_iccattrval_destroy(graytrc);
1114    jas_cmpxform_destroy(pxform);
1115    *retpxformseq = pxformseq;
1116    return 0;
1117error:
1118    return -1;
1119}
1120
1121static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1122{
1123    int i;
1124    jas_iccattrval_t *trcs[3];
1125    jas_iccattrval_t *cols[3];
1126    jas_cmshapmat_t *shapmat;
1127    jas_cmpxform_t *pxform;
1128    jas_cmpxformseq_t *pxformseq;
1129    jas_cmreal_t mat[3][4];
1130    jas_cmshapmatlut_t lut;
1131
1132    pxform = 0;
1133    pxformseq = 0;
1134    for (i = 0; i < 3; ++i) {
1135        trcs[i] = 0;
1136        cols[i] = 0;
1137    }
1138    jas_cmshapmatlut_init(&lut);
1139
1140    if (!(trcs[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDTRC)) ||
1141      !(trcs[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNTRC)) ||
1142      !(trcs[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUTRC)) ||
1143      !(cols[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDMATCOL)) ||
1144      !(cols[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNMATCOL)) ||
1145      !(cols[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUMATCOL)))
1146        goto error;
1147    for (i = 0; i < 3; ++i) {
1148        if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1149          cols[i]->type != JAS_ICC_TYPE_XYZ)
1150            goto error;
1151    }
1152    if (!(pxform = jas_cmpxform_createshapmat()))
1153        goto error;
1154    pxform->numinchans = 3;
1155    pxform->numoutchans = 3;
1156    shapmat = &pxform->data.shapmat;
1157    if (!(pxformseq = jas_cmpxformseq_create()))
1158        goto error;
1159    if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1160        goto error;
1161    shapmat->mono = 0;
1162    shapmat->useluts = 1;
1163    shapmat->usemat = 1;
1164    if (!op) {
1165        shapmat->order = 0;
1166        for (i = 0; i < 3; ++i) {
1167            shapmat->mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1168            shapmat->mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1169            shapmat->mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1170        }
1171        for (i = 0; i < 3; ++i)
1172            shapmat->mat[i][3] = 0.0;
1173        for (i = 0; i < 3; ++i) {
1174            if (jas_cmshapmatlut_set(&shapmat->luts[i], &trcs[i]->data.curv))
1175                goto error;
1176        }
1177    } else {
1178        shapmat->order = 1;
1179        for (i = 0; i < 3; ++i) {
1180            mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1181            mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1182            mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1183        }
1184        for (i = 0; i < 3; ++i)
1185            mat[i][3] = 0.0;
1186        if (jas_cmshapmat_invmat(shapmat->mat, mat))
1187            goto error;
1188        for (i = 0; i < 3; ++i) {
1189            jas_cmshapmatlut_init(&lut);
1190            if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1191                goto error;
1192            if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1193                goto error;
1194            jas_cmshapmatlut_cleanup(&lut);
1195        }
1196    }
1197    for (i = 0; i < 3; ++i) {
1198        jas_iccattrval_destroy(trcs[i]);
1199        jas_iccattrval_destroy(cols[i]);
1200    }
1201    jas_cmpxform_destroy(pxform);
1202    *retpxformseq = pxformseq;
1203    return 0;
1204
1205error:
1206
1207    for (i = 0; i < 3; ++i) {
1208        if (trcs[i]) {
1209            jas_iccattrval_destroy(trcs[i]);
1210        }
1211        if (cols[i]) {
1212            jas_iccattrval_destroy(cols[i]);
1213        }
1214    }
1215    if (pxformseq) {
1216        jas_cmpxformseq_destroy(pxformseq);
1217    }
1218    if (pxform) {
1219        jas_cmpxform_destroy(pxform);
1220    }
1221
1222    return -1;
1223}
1224
1225static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1226{
1227    long v;
1228    int m;
1229    v = **bufptr;
1230    if (sgnd) {
1231        m = (1 << (prec - 1));
1232        if (v < -m || v >= m)
1233            return -1;
1234    } else {
1235        if (v < 0 || v >= (1 << prec))
1236            return -1;
1237    }
1238    ++(*bufptr);
1239    *val = v;
1240    return 0;
1241}
1242
1243static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1244{
1245    int m;
1246    if (sgnd) {
1247        m = (1 << (prec - 1));
1248        if (val < -m || val >= m)
1249            return -1;
1250    } else {
1251        if (val < 0 || val >= (1 << prec))
1252            return -1;
1253    }
1254    **bufptr = val;
1255    ++(*bufptr);
1256    return 0;
1257}
1258
1259int jas_clrspc_numchans(int clrspc)
1260{
1261    switch (jas_clrspc_fam(clrspc)) {
1262    case JAS_CLRSPC_FAM_XYZ:
1263    case JAS_CLRSPC_FAM_LAB:
1264    case JAS_CLRSPC_FAM_RGB:
1265    case JAS_CLRSPC_FAM_YCBCR:
1266        return 3;
1267        break;
1268    case JAS_CLRSPC_FAM_GRAY:
1269        return 1;
1270        break;
1271    default:
1272        abort();
1273        break;
1274    }
1275}
1276
1277jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1278{
1279    return jas_iccprof_copy(prof->iccprof);
1280}
1281