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 
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             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 
jas_cmshapmatlut_init(jas_cmshapmatlut_t * lut)860 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
861 {
862     lut->data = 0;
863     lut->size = 0;
864 }
865 
jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t * lut)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 
gammafn(double x,double gamma)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 
jas_cmshapmatlut_set(jas_cmshapmatlut_t * lut,jas_icccurv_t * curv)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 
jas_cmshapmatlut_lookup(jas_cmshapmatlut_t * lut,jas_cmreal_t x)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 
jas_cmshapmatlut_invert(jas_cmshapmatlut_t * invlut,jas_cmshapmatlut_t * lut,int n)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 
jas_cmshapmat_invmat(jas_cmreal_t out[3][4],jas_cmreal_t in[3][4])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 
icctoclrspc(int iccclrspc,int refflag)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 
mono(jas_iccprof_t * iccprof,int op,jas_cmpxformseq_t ** retpxformseq)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 
triclr(jas_iccprof_t * iccprof,int op,jas_cmpxformseq_t ** retpxformseq)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 
jas_cmgetint(long ** bufptr,int sgnd,int prec,long * val)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 
jas_cmputint(long ** bufptr,int sgnd,int prec,long val)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 
jas_clrspc_numchans(int clrspc)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 
jas_iccprof_createfromcmprof(jas_cmprof_t * prof)1277 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1278 {
1279     return jas_iccprof_copy(prof->iccprof);
1280 }
1281