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$
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 
jas_cmprof_createfromclrspc(int clrspc)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 
jas_cmprof_createsycc()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 
jas_cmprof_createfromiccprof(jas_iccprof_t * iccprof)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 
jas_cmprof_create()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 
jas_cmprof_destroy(jas_cmprof_t * prof)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 
jas_cmprof_copy(jas_cmprof_t * prof)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 
jas_cmxform_create(jas_cmprof_t * inprof,jas_cmprof_t * outprof,jas_cmprof_t * prfprof,int op,int intent,int optimize)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
jas_cmxform_apply(jas_cmxform_t * xform,jas_cmpixmap_t * in,jas_cmpixmap_t * out)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 
jas_cmxform_destroy(jas_cmxform_t * xform)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 
jas_cmpxformseq_create()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 
jas_cmpxformseq_copy(jas_cmpxformseq_t * pxformseq)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 
jas_cmpxformseq_destroy(jas_cmpxformseq_t * pxformseq)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 
jas_cmpxformseq_delete(jas_cmpxformseq_t * pxformseq,int i)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 
jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t * pxformseq,int dstclrspc,int srcclrspc)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 
jas_cmpxformseq_insertpxform(jas_cmpxformseq_t * pxformseq,int i,jas_cmpxform_t * pxform)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 
jas_cmpxformseq_append(jas_cmpxformseq_t * pxformseq,jas_cmpxformseq_t * othpxformseq)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 
jas_cmpxformseq_resize(jas_cmpxformseq_t * pxformseq,int n)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 
jas_cmpxform_create0()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 
jas_cmpxform_destroy(jas_cmpxform_t * pxform)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 
jas_cmpxform_copy(jas_cmpxform_t * pxform)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 
jas_cmpxform_createshapmat()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 
jas_cmshapmat_destroy(jas_cmpxform_t * pxform)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 
jas_cmshapmat_apply(jas_cmpxform_t * pxform,jas_cmreal_t * in,jas_cmreal_t * out,int cnt)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 assert(0);
846 			while (--cnt >= 0) {
847 				a0 = *src++;
848 				src++;
849 				src++;
850 				a0 = a0 * shapmat->mat[0][0];
851 				if (shapmat->useluts)
852 					a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
853 				*dst++ = a0;
854 			}
855 		}
856 	}
857 
858 	return 0;
859 }
860 
jas_cmshapmatlut_init(jas_cmshapmatlut_t * lut)861 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
862 {
863 	lut->data = 0;
864 	lut->size = 0;
865 }
866 
jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t * lut)867 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
868 {
869 	if (lut->data) {
870 		jas_free(lut->data);
871 		lut->data = 0;
872 	}
873 	lut->size = 0;
874 }
875 
gammafn(double x,double gamma)876 static double gammafn(double x, double gamma)
877 {
878 	if (x == 0.0)
879 		return 0.0;
880 	return pow(x, gamma);
881 }
882 
jas_cmshapmatlut_set(jas_cmshapmatlut_t * lut,jas_icccurv_t * curv)883 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
884 {
885 	jas_cmreal_t gamma;
886 	int i;
887 	gamma = 0;
888 	jas_cmshapmatlut_cleanup(lut);
889 	if (curv->numents == 0) {
890 		lut->size = 2;
891 		if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
892 			goto error;
893 		lut->data[0] = 0.0;
894 		lut->data[1] = 1.0;
895 	} else if (curv->numents == 1) {
896 		lut->size = 256;
897 		if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
898 			goto error;
899 		gamma = curv->ents[0] / 256.0;
900 		for (i = 0; i < lut->size; ++i) {
901 			lut->data[i] = gammafn(i / (double) (lut->size - 1), gamma);
902 		}
903 	} else {
904 		lut->size = curv->numents;
905 		if (!(lut->data = jas_alloc2(lut->size, sizeof(jas_cmreal_t))))
906 			goto error;
907 		for (i = 0; i < lut->size; ++i) {
908 			lut->data[i] = curv->ents[i] / 65535.0;
909 		}
910 	}
911 	return 0;
912 error:
913 	return -1;
914 }
915 
jas_cmshapmatlut_lookup(jas_cmshapmatlut_t * lut,jas_cmreal_t x)916 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
917 {
918 	jas_cmreal_t t;
919 	int lo;
920 	int hi;
921 	t = x * (lut->size - 1);
922 	lo = floor(t);
923 	if (lo < 0)
924 		return lut->data[0];
925 	hi = ceil(t);
926 	if (hi >= lut->size)
927 		return lut->data[lut->size - 1];
928 	return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
929 }
930 
jas_cmshapmatlut_invert(jas_cmshapmatlut_t * invlut,jas_cmshapmatlut_t * lut,int n)931 static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
932   jas_cmshapmatlut_t *lut, int n)
933 {
934 	int i;
935 	int j;
936 	int k;
937 	jas_cmreal_t ax;
938 	jas_cmreal_t ay;
939 	jas_cmreal_t bx;
940 	jas_cmreal_t by;
941 	jas_cmreal_t sx;
942 	jas_cmreal_t sy;
943 	assert(n >= 2);
944 	if (invlut->data) {
945 		jas_free(invlut->data);
946 		invlut->data = 0;
947 	}
948 	/* The sample values should be nondecreasing. */
949 	for (i = 1; i < lut->size; ++i) {
950 		if (lut->data[i - 1] > lut->data[i]) {
951 			assert(0);
952 			return -1;
953 		}
954 	}
955 	if (!(invlut->data = jas_alloc2(n, sizeof(jas_cmreal_t))))
956 		return -1;
957 	invlut->size = n;
958 	for (i = 0; i < invlut->size; ++i) {
959 		sy = ((double) i) / (invlut->size - 1);
960 		sx = 1.0;
961 		for (j = 0; j < lut->size; ++j) {
962 			ay = lut->data[j];
963 			if (sy == ay) {
964 				for (k = j + 1; k < lut->size; ++k) {
965 					by = lut->data[k];
966 					if (by != sy)
967 						break;
968 #if 0
969 assert(0);
970 #endif
971 				}
972 				if (k < lut->size) {
973 					--k;
974 					ax = ((double) j) / (lut->size - 1);
975 					bx = ((double) k) / (lut->size - 1);
976 					sx = (ax + bx) / 2.0;
977 				}
978 				break;
979 			}
980 			if (j < lut->size - 1) {
981 				by = lut->data[j + 1];
982 				if (sy > ay && sy < by) {
983 					ax = ((double) j) / (lut->size - 1);
984 					bx = ((double) j + 1) / (lut->size - 1);
985 					sx = ax +
986 					  (sy - ay) / (by - ay) * (bx - ax);
987 					break;
988 				}
989 			}
990 		}
991 		invlut->data[i] = sx;
992 	}
993 #if 0
994 for (i=0;i<lut->size;++i)
995 	jas_eprintf("lut[%d]=%f ", i, lut->data[i]);
996 for (i=0;i<invlut->size;++i)
997 	jas_eprintf("invlut[%d]=%f ", i, invlut->data[i]);
998 #endif
999 	return 0;
1000 }
1001 
jas_cmshapmat_invmat(jas_cmreal_t out[3][4],jas_cmreal_t in[3][4])1002 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
1003 {
1004 	jas_cmreal_t d;
1005 	d = in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1])
1006 	  - in[0][1] * (in[1][0] * in[2][2] - in[1][2] * in[2][0])
1007 	  + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]);
1008 #if 0
1009 jas_eprintf("delta=%f\n", d);
1010 #endif
1011 	if (JAS_ABS(d) < 1e-6)
1012 		return -1;
1013 	out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) / d;
1014 	out[1][0] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) / d;
1015 	out[2][0] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) / d;
1016 	out[0][1] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) / d;
1017 	out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) / d;
1018 	out[2][1] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) / d;
1019 	out[0][2] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) / d;
1020 	out[1][2] = -(in[0][0] * in[1][2] - in[1][0] * in[0][2]) / d;
1021 	out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) / d;
1022 	out[0][3] = -in[0][3];
1023 	out[1][3] = -in[1][3];
1024 	out[2][3] = -in[2][3];
1025 #if 0
1026 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1027 in[0][0], in[0][1], in[0][2], in[0][3],
1028 in[1][0], in[1][1], in[1][2], in[1][3],
1029 in[2][0], in[2][1], in[2][2], in[2][3]);
1030 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1031 out[0][0], out[0][1], out[0][2], out[0][3],
1032 out[1][0], out[1][1], out[1][2], out[1][3],
1033 out[2][0], out[2][1], out[2][2], out[2][3]);
1034 #endif
1035 	return 0;
1036 }
1037 
1038 /******************************************************************************\
1039 *
1040 \******************************************************************************/
1041 
icctoclrspc(int iccclrspc,int refflag)1042 static int icctoclrspc(int iccclrspc, int refflag)
1043 {
1044 	if (refflag) {
1045 		switch (iccclrspc) {
1046 		case JAS_ICC_COLORSPC_XYZ:
1047 			return JAS_CLRSPC_CIEXYZ;
1048 		case JAS_ICC_COLORSPC_LAB:
1049 			return JAS_CLRSPC_CIELAB;
1050 		default:
1051 			abort();
1052 			break;
1053 		}
1054 	} else {
1055 		switch (iccclrspc) {
1056 		case JAS_ICC_COLORSPC_YCBCR:
1057 			return JAS_CLRSPC_GENYCBCR;
1058 		case JAS_ICC_COLORSPC_RGB:
1059 			return JAS_CLRSPC_GENRGB;
1060 		case JAS_ICC_COLORSPC_GRAY:
1061 			return JAS_CLRSPC_GENGRAY;
1062 		default:
1063 			abort();
1064 			break;
1065 		}
1066 	}
1067 	return JAS_CLRSPC_UNKNOWN;
1068 }
1069 
mono(jas_iccprof_t * iccprof,int op,jas_cmpxformseq_t ** retpxformseq)1070 static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1071 {
1072 	jas_iccattrval_t *graytrc;
1073 	jas_cmshapmat_t *shapmat;
1074 	jas_cmpxform_t *pxform;
1075 	jas_cmpxformseq_t *pxformseq;
1076 	jas_cmshapmatlut_t lut;
1077 
1078 	jas_cmshapmatlut_init(&lut);
1079 	if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1080 	  graytrc->type != JAS_ICC_TYPE_CURV)
1081 		goto error;
1082 	if (!(pxform = jas_cmpxform_createshapmat()))
1083 		goto error;
1084 	shapmat = &pxform->data.shapmat;
1085 	if (!(pxformseq = jas_cmpxformseq_create()))
1086 		goto error;
1087 	if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1088 		goto error;
1089 
1090 	pxform->numinchans = 1;
1091 	pxform->numoutchans = 3;
1092 
1093 	shapmat->mono = 1;
1094 	shapmat->useluts = 1;
1095 	shapmat->usemat = 1;
1096 	if (!op) {
1097 		shapmat->order = 0;
1098 		shapmat->mat[0][0] = 0.9642;
1099 		shapmat->mat[1][0] = 1.0;
1100 		shapmat->mat[2][0] = 0.8249;
1101 		if (jas_cmshapmatlut_set(&shapmat->luts[0], &graytrc->data.curv))
1102 			goto error;
1103 	} else {
1104 		shapmat->order = 1;
1105 		shapmat->mat[0][0] = 1.0 / 0.9642;
1106 		shapmat->mat[1][0] = 1.0;
1107 		shapmat->mat[2][0] = 1.0 / 0.8249;
1108 		jas_cmshapmatlut_init(&lut);
1109 		if (jas_cmshapmatlut_set(&lut, &graytrc->data.curv))
1110 			goto error;
1111 		if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1112 			goto error;
1113 		jas_cmshapmatlut_cleanup(&lut);
1114 	}
1115 	jas_iccattrval_destroy(graytrc);
1116 	jas_cmpxform_destroy(pxform);
1117 	*retpxformseq = pxformseq;
1118 	return 0;
1119 error:
1120 	return -1;
1121 }
1122 
triclr(jas_iccprof_t * iccprof,int op,jas_cmpxformseq_t ** retpxformseq)1123 static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
1124 {
1125 	int i;
1126 	jas_iccattrval_t *trcs[3];
1127 	jas_iccattrval_t *cols[3];
1128 	jas_cmshapmat_t *shapmat;
1129 	jas_cmpxform_t *pxform;
1130 	jas_cmpxformseq_t *pxformseq;
1131 	jas_cmreal_t mat[3][4];
1132 	jas_cmshapmatlut_t lut;
1133 
1134 	pxform = 0;
1135 	pxformseq = 0;
1136 	for (i = 0; i < 3; ++i) {
1137 		trcs[i] = 0;
1138 		cols[i] = 0;
1139 	}
1140 	jas_cmshapmatlut_init(&lut);
1141 
1142 	if (!(trcs[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDTRC)) ||
1143 	  !(trcs[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNTRC)) ||
1144 	  !(trcs[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUTRC)) ||
1145 	  !(cols[0] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_REDMATCOL)) ||
1146 	  !(cols[1] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRNMATCOL)) ||
1147 	  !(cols[2] = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_BLUMATCOL)))
1148 		goto error;
1149 	for (i = 0; i < 3; ++i) {
1150 		if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1151 		  cols[i]->type != JAS_ICC_TYPE_XYZ)
1152 			goto error;
1153 	}
1154 	if (!(pxform = jas_cmpxform_createshapmat()))
1155 		goto error;
1156 	pxform->numinchans = 3;
1157 	pxform->numoutchans = 3;
1158 	shapmat = &pxform->data.shapmat;
1159 	if (!(pxformseq = jas_cmpxformseq_create()))
1160 		goto error;
1161 	if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1162 		goto error;
1163 	shapmat->mono = 0;
1164 	shapmat->useluts = 1;
1165 	shapmat->usemat = 1;
1166 	if (!op) {
1167 		shapmat->order = 0;
1168 		for (i = 0; i < 3; ++i) {
1169 			shapmat->mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1170 			shapmat->mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1171 			shapmat->mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1172 		}
1173 		for (i = 0; i < 3; ++i)
1174 			shapmat->mat[i][3] = 0.0;
1175 		for (i = 0; i < 3; ++i) {
1176 			if (jas_cmshapmatlut_set(&shapmat->luts[i], &trcs[i]->data.curv))
1177 				goto error;
1178 		}
1179 	} else {
1180 		shapmat->order = 1;
1181 		for (i = 0; i < 3; ++i) {
1182 			mat[0][i] = cols[i]->data.xyz.x / 65536.0;
1183 			mat[1][i] = cols[i]->data.xyz.y / 65536.0;
1184 			mat[2][i] = cols[i]->data.xyz.z / 65536.0;
1185 		}
1186 		for (i = 0; i < 3; ++i)
1187 			mat[i][3] = 0.0;
1188 		if (jas_cmshapmat_invmat(shapmat->mat, mat))
1189 			goto error;
1190 		for (i = 0; i < 3; ++i) {
1191 			jas_cmshapmatlut_init(&lut);
1192 			if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1193 				goto error;
1194 			if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1195 				goto error;
1196 			jas_cmshapmatlut_cleanup(&lut);
1197 		}
1198 	}
1199 	for (i = 0; i < 3; ++i) {
1200 		jas_iccattrval_destroy(trcs[i]);
1201 		jas_iccattrval_destroy(cols[i]);
1202 	}
1203 	jas_cmpxform_destroy(pxform);
1204 	*retpxformseq = pxformseq;
1205 	return 0;
1206 
1207 error:
1208 
1209 	for (i = 0; i < 3; ++i) {
1210 		if (trcs[i]) {
1211 			jas_iccattrval_destroy(trcs[i]);
1212 		}
1213 		if (cols[i]) {
1214 			jas_iccattrval_destroy(cols[i]);
1215 		}
1216 	}
1217 	if (pxformseq) {
1218 		jas_cmpxformseq_destroy(pxformseq);
1219 	}
1220 	if (pxform) {
1221 		jas_cmpxform_destroy(pxform);
1222 	}
1223 
1224 	return -1;
1225 }
1226 
jas_cmgetint(long ** bufptr,int sgnd,int prec,long * val)1227 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1228 {
1229 	long v;
1230 	int m;
1231 	v = **bufptr;
1232 	if (sgnd) {
1233 		m = (1 << (prec - 1));
1234 		if (v < -m || v >= m)
1235 			return -1;
1236 	} else {
1237 		if (v < 0 || v >= (1 << prec))
1238 			return -1;
1239 	}
1240 	++(*bufptr);
1241 	*val = v;
1242 	return 0;
1243 }
1244 
jas_cmputint(long ** bufptr,int sgnd,int prec,long val)1245 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1246 {
1247 	int m;
1248 	if (sgnd) {
1249 		m = (1 << (prec - 1));
1250 		if (val < -m || val >= m)
1251 			return -1;
1252 	} else {
1253 		if (val < 0 || val >= (1 << prec))
1254 			return -1;
1255 	}
1256 	**bufptr = val;
1257 	++(*bufptr);
1258 	return 0;
1259 }
1260 
jas_clrspc_numchans(int clrspc)1261 int jas_clrspc_numchans(int clrspc)
1262 {
1263 	switch (jas_clrspc_fam(clrspc)) {
1264 	case JAS_CLRSPC_FAM_XYZ:
1265 	case JAS_CLRSPC_FAM_LAB:
1266 	case JAS_CLRSPC_FAM_RGB:
1267 	case JAS_CLRSPC_FAM_YCBCR:
1268 		return 3;
1269 		break;
1270 	case JAS_CLRSPC_FAM_GRAY:
1271 		return 1;
1272 		break;
1273 	default:
1274 		abort();
1275 		break;
1276 	}
1277 	return 0;
1278 }
1279 
jas_iccprof_createfromcmprof(jas_cmprof_t * prof)1280 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1281 {
1282 	return jas_iccprof_copy(prof->iccprof);
1283 }
1284