Home | History | Annotate | Download | only in libjasper
      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 = 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 
    720 static 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 
    731 static 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 
    739 static 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 
    749 static 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 
    773 static 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 
    781 static 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 
    860 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
    861 {
    862     lut->data = 0;
    863     lut->size = 0;
    864 }
    865 
    866 static 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 
    875 static double gammafn(double x, double gamma)
    876 {
    877     if (x == 0.0)
    878         return 0.0;
    879     return pow(x, gamma);
    880 }
    881 
    882 static 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;
    911 error:
    912     return -1;
    913 }
    914 
    915 static 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 
    930 static 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
    968 assert(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
    993 for (i=0;i<lut->size;++i)
    994     jas_eprintf("lut[%d]=%f ", i, lut->data[i]);
    995 for (i=0;i<invlut->size;++i)
    996     jas_eprintf("invlut[%d]=%f ", i, invlut->data[i]);
    997 #endif
    998     return 0;
    999 }
   1000 
   1001 static 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
   1008 jas_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
   1025 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
   1026 in[0][0], in[0][1], in[0][2], in[0][3],
   1027 in[1][0], in[1][1], in[1][2], in[1][3],
   1028 in[2][0], in[2][1], in[2][2], in[2][3]);
   1029 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
   1030 out[0][0], out[0][1], out[0][2], out[0][3],
   1031 out[1][0], out[1][1], out[1][2], out[1][3],
   1032 out[2][0], out[2][1], out[2][2], out[2][3]);
   1033 #endif
   1034     return 0;
   1035 }
   1036 
   1037 /******************************************************************************\
   1038 *
   1039 \******************************************************************************/
   1040 
   1041 static 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 
   1068 static 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;
   1117 error:
   1118     return -1;
   1119 }
   1120 
   1121 static 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 
   1205 error:
   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 
   1225 static 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 
   1243 static 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 
   1259 int 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 
   1277 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
   1278 {
   1279     return jas_iccprof_copy(prof->iccprof);
   1280 }
   1281