2 * Copyright (c) 2002-2003 Michael David Adams.
6 /* __START_OF_JASPER_LICENSE__
8 * JasPer License Version 2.0
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
14 * All rights reserved.
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:
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.
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
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.
59 * __END_OF_JASPER_LICENSE__
65 * $Id: jas_cm.c,v 1.1 2005/05/22 18:32:58 malaterre Exp $
68 #include <jasper/jas_config.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>
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);
83 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform);
84 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform);
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);
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,
96 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n);
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);
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);
109 #define SEQFWD(intent) (intent)
110 #define SEQREV(intent) (4 + (intent))
111 #define SEQSIM(intent) (8 + (intent))
114 #define fwdpxformseq(prof, intent) \
115 (((prof)->pxformseqs[SEQFWD(intent)]) ? \
116 ((prof)->pxformseqs[SEQFWD(intent)]) : \
117 ((prof)->pxformseqs[SEQFWD(0)]))
119 #define revpxformseq(prof, intent) \
120 (((prof)->pxformseqs[SEQREV(intent)]) ? \
121 ((prof)->pxformseqs[SEQREV(intent)]) : \
122 ((prof)->pxformseqs[SEQREV(0)]))
124 #define simpxformseq(prof, intent) \
125 (((prof)->pxformseqs[SEQSIM(intent)]) ? \
126 ((prof)->pxformseqs[SEQSIM(intent)]) : \
127 ((prof)->pxformseqs[SEQSIM(0)]))
129 #define gampxformseq(prof) ((prof)->pxformseqs[SEQGAM])
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);
137 static jas_cmpxformops_t shapmat_ops = {jas_cmshapmat_destroy, jas_cmshapmat_apply, 0};
138 static jas_cmprof_t *jas_cmprof_createsycc(void);
140 /******************************************************************************\
141 * Color profile class.
142 \******************************************************************************/
144 jas_cmprof_t *jas_cmprof_createfromclrspc(int clrspc)
146 jas_iccprof_t *iccprof;
152 case JAS_CLRSPC_SYCBCR:
153 if (!(prof = jas_cmprof_createsycc()))
157 if (!(iccprof = jas_iccprof_createfromclrspc(clrspc)))
159 if (!(prof = jas_cmprof_createfromiccprof(iccprof)))
162 jas_iccprof_destroy(iccprof);
164 prof->iccprof = iccprof;
166 if (!jas_clrspc_isgeneric(clrspc))
167 prof->clrspc = clrspc;
173 jas_iccprof_destroy(iccprof);
177 static jas_cmprof_t *jas_cmprof_createsycc()
180 jas_cmpxform_t *fwdpxform;
181 jas_cmpxform_t *revpxform;
182 jas_cmshapmat_t *fwdshapmat;
183 jas_cmshapmat_t *revshapmat;
187 if (!(prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
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()))
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()))
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);
224 for (i = 0; i < JAS_CMXFORM_NUMINTENTS; ++i) {
226 if (prof->pxformseqs[j]) {
227 if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j], 0,
232 if (prof->pxformseqs[j]) {
233 if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j],
239 jas_cmpxform_destroy(fwdpxform);
240 jas_cmpxform_destroy(revpxform);
246 jas_cmprof_t *jas_cmprof_createfromiccprof(jas_iccprof_t *iccprof)
250 jas_cmpxformseq_t *fwdpxformseq;
251 jas_cmpxformseq_t *revpxformseq;
253 if (!(prof = jas_cmprof_create()))
255 jas_iccprof_gethdr(iccprof, &icchdr);
256 if (!(prof->iccprof = jas_iccprof_copy(iccprof)))
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);
263 if (prof->numchans == 1) {
264 if (mono(prof->iccprof, 0, &fwdpxformseq))
266 if (mono(prof->iccprof, 1, &revpxformseq))
268 } else if (prof->numchans == 3) {
269 if (triclr(prof->iccprof, 0, &fwdpxformseq))
271 if (triclr(prof->iccprof, 1, &revpxformseq))
274 prof->pxformseqs[SEQFWD(0)] = fwdpxformseq;
275 prof->pxformseqs[SEQREV(0)] = revpxformseq;
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);
299 static jas_cmprof_t *jas_cmprof_create()
303 if (!(prof = jas_malloc(sizeof(jas_cmprof_t))))
305 memset(prof, 0, sizeof(jas_cmprof_t));
307 for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i)
308 prof->pxformseqs[i] = 0;
312 void jas_cmprof_destroy(jas_cmprof_t *prof)
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;
322 jas_iccprof_destroy(prof->iccprof);
326 jas_cmprof_t *jas_cmprof_copy(jas_cmprof_t *prof)
328 jas_cmprof_t *newprof;
331 if (!(newprof = jas_cmprof_create()))
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])))
349 /******************************************************************************\
351 \******************************************************************************/
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)
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;
363 /* Avoid compiler warnings about unused parameters. */
368 if (!(xform = jas_malloc(sizeof(jas_cmxform_t))))
370 if (!(xform->pxformseq = jas_cmpxformseq_create()))
374 case JAS_CMXFORM_OP_FWD:
375 inpxformseq = fwdpxformseq(inprof, intent);
376 outpxformseq = revpxformseq(outprof, intent);
377 if (!inpxformseq || !outpxformseq)
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))
384 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
385 xform->numoutchans = jas_clrspc_numchans(outprof->clrspc);
387 case JAS_CMXFORM_OP_REV:
388 outpxformseq = fwdpxformseq(outprof, intent);
389 inpxformseq = revpxformseq(inprof, intent);
390 if (!outpxformseq || !inpxformseq)
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))
397 xform->numinchans = jas_clrspc_numchans(outprof->clrspc);
398 xform->numoutchans = jas_clrspc_numchans(inprof->clrspc);
400 case JAS_CMXFORM_OP_PROOF:
402 inpxformseq = fwdpxformseq(inprof, intent);
403 prfpxformseq = fwdpxformseq(prfprof, prfintent);
404 if (!inpxformseq || !prfpxformseq)
406 outpxformseq = simpxformseq(outprof, intent);
409 outpxformseq = revpxformseq(outprof, intent);
410 altoutpxformseq = fwdpxformseq(outprof, intent);
411 if (!outpxformseq || !altoutpxformseq)
414 if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
415 jas_cmpxformseq_appendcnvt(xform->pxformseq,
416 inprof->refclrspc, outprof->refclrspc))
418 if (altoutpxformseq) {
419 if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
420 jas_cmpxformseq_append(xform->pxformseq, altoutpxformseq))
423 if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
426 if (jas_cmpxformseq_appendcnvt(xform->pxformseq,
427 outprof->refclrspc, inprof->refclrspc) ||
428 jas_cmpxformseq_append(xform->pxformseq, prfpxformseq))
430 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
431 xform->numoutchans = jas_clrspc_numchans(prfprof->clrspc);
433 case JAS_CMXFORM_OP_GAMUT:
434 inpxformseq = fwdpxformseq(inprof, intent);
435 outpxformseq = gampxformseq(outprof);
436 if (!inpxformseq || !outpxformseq)
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))
443 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
444 xform->numoutchans = 1;
452 #define APPLYBUFSIZ 2048
453 int jas_cmxform_apply(jas_cmxform_t *xform, jas_cmpixmap_t *in, jas_cmpixmap_t *out)
455 jas_cmcmptfmt_t *fmt;
456 jas_cmreal_t buf[2][APPLYBUFSIZ];
457 jas_cmpxformseq_t *pxformseq;
465 jas_cmreal_t *outbuf;
466 jas_cmpxform_t *pxform;
474 jas_cmreal_t *bufptr;
476 if (xform->numinchans > in->numcmpts || xform->numoutchans > out->numcmpts)
479 fmt = &in->cmptfmts[0];
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) {
488 for (i = 0; i < xform->numoutchans; ++i) {
489 fmt = &out->cmptfmts[i];
490 if (fmt->width != width || fmt->height != height) {
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;
502 if (pxform->numoutchans > maxchans) {
503 maxchans = pxform->numoutchans;
506 bufmax = APPLYBUFSIZ / maxchans;
509 total = width * height;
514 m = JAS_MIN(total - n, bufmax);
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];
522 for (j = 0; j < m; ++j) {
523 if (jas_cmgetint(&dataptr, fmt->sgnd, fmt->prec, &v))
525 *bufptr = (v - bias) / scale;
526 bufptr += xform->numinchans;
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];
539 if ((*pxform->ops->apply)(pxform, inbuf, outbuf, m))
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;
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))
566 void jas_cmxform_destroy(jas_cmxform_t *xform)
568 if (xform->pxformseq)
569 jas_cmpxformseq_destroy(xform->pxformseq);
573 /******************************************************************************\
574 * Primitive transform sequence class.
575 \******************************************************************************/
577 static jas_cmpxformseq_t *jas_cmpxformseq_create()
579 jas_cmpxformseq_t *pxformseq;
581 if (!(pxformseq = jas_malloc(sizeof(jas_cmpxformseq_t))))
583 pxformseq->pxforms = 0;
584 pxformseq->numpxforms = 0;
585 pxformseq->maxpxforms = 0;
586 if (jas_cmpxformseq_resize(pxformseq, 16))
591 jas_cmpxformseq_destroy(pxformseq);
595 static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq)
597 jas_cmpxformseq_t *newpxformseq;
599 if (!(newpxformseq = jas_cmpxformseq_create()))
601 if (jas_cmpxformseq_append(newpxformseq, pxformseq))
608 static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq)
610 while (pxformseq->numpxforms > 0)
611 jas_cmpxformseq_delete(pxformseq, pxformseq->numpxforms - 1);
612 if (pxformseq->pxforms)
613 jas_free(pxformseq->pxforms);
617 static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i)
619 assert(i >= 0 && i < pxformseq->numpxforms);
620 if (i != pxformseq->numpxforms - 1)
622 jas_cmpxform_destroy(pxformseq->pxforms[i]);
623 pxformseq->pxforms[i] = 0;
624 --pxformseq->numpxforms;
628 static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
629 int dstclrspc, int srcclrspc)
631 if (dstclrspc == srcclrspc)
634 /* Avoid compiler warnings about unused parameters. */
639 static int jas_cmpxformseq_insertpxform(jas_cmpxformseq_t *pxformseq,
640 int i, jas_cmpxform_t *pxform)
642 jas_cmpxform_t *tmppxform;
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 +
652 assert(pxformseq->numpxforms < pxformseq->maxpxforms);
653 if (!(tmppxform = jas_cmpxform_copy(pxform)))
655 n = pxformseq->numpxforms - i;
657 memmove(&pxformseq->pxforms[i + 1], &pxformseq->pxforms[i],
658 n * sizeof(jas_cmpxform_t *));
660 pxformseq->pxforms[i] = tmppxform;
661 ++pxformseq->numpxforms;
667 static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
668 jas_cmpxformseq_t *othpxformseq)
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))
679 for (i = 0; i < othpxformseq->numpxforms; ++i) {
680 othpxform = othpxformseq->pxforms[i];
681 if (!(pxform = jas_cmpxform_copy(othpxform)))
683 pxformseq->pxforms[pxformseq->numpxforms] = pxform;
684 ++pxformseq->numpxforms;
691 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n)
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 *));
700 pxformseq->pxforms = p;
701 pxformseq->maxpxforms = n;
705 /******************************************************************************\
706 * Primitive transform class.
707 \******************************************************************************/
709 static jas_cmpxform_t *jas_cmpxform_create0()
711 jas_cmpxform_t *pxform;
712 if (!(pxform = jas_malloc(sizeof(jas_cmpxform_t))))
714 memset(pxform, 0, sizeof(jas_cmpxform_t));
720 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform)
722 if (--pxform->refcnt <= 0) {
723 (*pxform->ops->destroy)(pxform);
728 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform)
734 /******************************************************************************\
735 * Shaper matrix class.
736 \******************************************************************************/
738 static jas_cmpxform_t *jas_cmpxform_createshapmat()
742 jas_cmpxform_t *pxform;
743 jas_cmshapmat_t *shapmat;
744 if (!(pxform = jas_cmpxform_create0()))
746 pxform->ops = &shapmat_ops;
747 shapmat = &pxform->data.shapmat;
750 shapmat->useluts = 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;
762 static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform)
764 jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
766 for (i = 0; i < 3; ++i)
767 jas_cmshapmatlut_cleanup(&shapmat->luts[i]);
770 static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
771 jas_cmreal_t *out, int cnt)
773 jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
784 if (!shapmat->mono) {
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);
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];
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);
821 if (!shapmat->order) {
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];
839 a0 = a0 * shapmat->mat[0][0];
840 if (shapmat->useluts)
841 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
850 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
856 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
865 static double gammafn(double x, double gamma)
869 return pow(x, gamma);
872 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
877 jas_cmshapmatlut_cleanup(lut);
878 if (curv->numents == 0) {
880 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
884 } else if (curv->numents == 1) {
886 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
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);
893 lut->size = curv->numents;
894 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
896 for (i = 0; i < lut->size; ++i) {
897 lut->data[i] = curv->ents[i] / 65535.0;
905 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
910 t = x * (lut->size - 1);
916 return lut->data[lut->size - 1];
917 return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
920 static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
921 jas_cmshapmatlut_t *lut, int n)
934 jas_free(invlut->data);
937 /* The sample values should be nondecreasing. */
938 for (i = 1; i < lut->size; ++i) {
939 if (lut->data[i - 1] > lut->data[i]) {
944 if (!(invlut->data = jas_malloc(n * sizeof(jas_cmreal_t))))
947 for (i = 0; i < invlut->size; ++i) {
948 sy = ((double) i) / (invlut->size - 1);
950 for (j = 0; j < lut->size; ++j) {
953 for (k = j + 1; k < lut->size; ++k) {
963 ax = ((double) j) / (lut->size - 1);
964 bx = ((double) k) / (lut->size - 1);
965 sx = (ax + bx) / 2.0;
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);
975 (sy - ay) / (by - ay) * (bx - ax);
980 invlut->data[i] = sx;
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]);
991 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
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]);
998 fprintf(stderr, "delta=%f\n", d);
1000 if (JAS_ABS(d) < 1e-6)
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];
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]);
1027 /******************************************************************************\
1029 \******************************************************************************/
1031 static int icctoclrspc(int iccclrspc, int 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;
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;
1058 static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
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;
1066 jas_cmshapmatlut_init(&lut);
1067 if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1068 graytrc->type != JAS_ICC_TYPE_CURV)
1070 if (!(pxform = jas_cmpxform_createshapmat()))
1072 shapmat = &pxform->data.shapmat;
1073 if (!(pxformseq = jas_cmpxformseq_create()))
1075 if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1078 pxform->numinchans = 1;
1079 pxform->numoutchans = 3;
1082 shapmat->useluts = 1;
1083 shapmat->usemat = 1;
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))
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))
1099 if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1101 jas_cmshapmatlut_cleanup(&lut);
1103 jas_iccattrval_destroy(graytrc);
1104 jas_cmpxform_destroy(pxform);
1105 *retpxformseq = pxformseq;
1111 static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
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) {
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)))
1133 for (i = 0; i < 3; ++i) {
1134 if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1135 cols[i]->type != JAS_ICC_TYPE_XYZ)
1138 if (!(pxform = jas_cmpxform_createshapmat()))
1140 pxform->numinchans = 3;
1141 pxform->numoutchans = 3;
1142 shapmat = &pxform->data.shapmat;
1143 if (!(pxformseq = jas_cmpxformseq_create()))
1145 if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1148 shapmat->useluts = 1;
1149 shapmat->usemat = 1;
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;
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))
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;
1170 for (i = 0; i < 3; ++i)
1172 if (jas_cmshapmat_invmat(shapmat->mat, mat))
1174 for (i = 0; i < 3; ++i) {
1175 jas_cmshapmatlut_init(&lut);
1176 if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1178 if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1180 jas_cmshapmatlut_cleanup(&lut);
1183 for (i = 0; i < 3; ++i) {
1184 jas_iccattrval_destroy(trcs[i]);
1185 jas_iccattrval_destroy(cols[i]);
1187 jas_cmpxform_destroy(pxform);
1188 *retpxformseq = pxformseq;
1194 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1200 m = (1 << (prec - 1));
1201 if (v < -m || v >= m)
1204 if (v < 0 || v >= (1 << prec))
1212 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1216 m = (1 << (prec - 1));
1217 if (val < -m || val >= m)
1220 if (val < 0 || val >= (1 << prec))
1228 int jas_clrspc_numchans(int clrspc)
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:
1237 case JAS_CLRSPC_FAM_GRAY:
1246 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1248 return jas_iccprof_copy(prof->iccprof);