vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

jas_cm.c (34364B)


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