2 * Copyright (c) 2002-2003 Michael David Adams.
6 /* __START_OF_JASPER_LICENSE__
8 * JasPer License Version 2.0
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
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.2 2008/05/26 09:40:52 vp153 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)))
161 jas_iccprof_destroy(iccprof);
163 if (!jas_clrspc_isgeneric(clrspc))
164 prof->clrspc = clrspc;
170 jas_iccprof_destroy(iccprof);
174 static jas_cmprof_t *jas_cmprof_createsycc()
177 jas_cmpxform_t *fwdpxform;
178 jas_cmpxform_t *revpxform;
179 jas_cmshapmat_t *fwdshapmat;
180 jas_cmshapmat_t *revshapmat;
184 if (!(prof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB)))
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()))
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()))
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);
221 for (i = 0; i < JAS_CMXFORM_NUMINTENTS; ++i) {
223 if (prof->pxformseqs[j]) {
224 if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j], 0,
229 if (prof->pxformseqs[j]) {
230 if (jas_cmpxformseq_insertpxform(prof->pxformseqs[j],
236 jas_cmpxform_destroy(fwdpxform);
237 jas_cmpxform_destroy(revpxform);
243 jas_cmprof_t *jas_cmprof_createfromiccprof(jas_iccprof_t *iccprof)
247 jas_cmpxformseq_t *fwdpxformseq;
248 jas_cmpxformseq_t *revpxformseq;
254 if (!(prof = jas_cmprof_create()))
256 jas_iccprof_gethdr(iccprof, &icchdr);
257 if (!(prof->iccprof = jas_iccprof_copy(iccprof)))
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);
264 if (prof->numchans == 1) {
265 if (mono(prof->iccprof, 0, &fwdpxformseq))
267 if (mono(prof->iccprof, 1, &revpxformseq))
269 } else if (prof->numchans == 3) {
270 if (triclr(prof->iccprof, 0, &fwdpxformseq))
272 if (triclr(prof->iccprof, 1, &revpxformseq))
275 prof->pxformseqs[SEQFWD(0)] = fwdpxformseq;
276 prof->pxformseqs[SEQREV(0)] = revpxformseq;
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);
299 jas_cmpxformseq_destroy(fwdpxformseq);
302 jas_cmpxformseq_destroy(revpxformseq);
305 jas_cmprof_destroy(prof);
311 static jas_cmprof_t *jas_cmprof_create()
315 if (!(prof = jas_malloc(sizeof(jas_cmprof_t))))
317 memset(prof, 0, sizeof(jas_cmprof_t));
319 for (i = 0; i < JAS_CMPROF_NUMPXFORMSEQS; ++i)
320 prof->pxformseqs[i] = 0;
324 void jas_cmprof_destroy(jas_cmprof_t *prof)
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;
334 jas_iccprof_destroy(prof->iccprof);
338 jas_cmprof_t *jas_cmprof_copy(jas_cmprof_t *prof)
340 jas_cmprof_t *newprof;
343 if (!(newprof = jas_cmprof_create()))
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])))
361 /******************************************************************************\
363 \******************************************************************************/
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)
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;
375 /* Avoid compiler warnings about unused parameters. */
380 if (!(xform = jas_malloc(sizeof(jas_cmxform_t))))
382 if (!(xform->pxformseq = jas_cmpxformseq_create()))
386 case JAS_CMXFORM_OP_FWD:
387 inpxformseq = fwdpxformseq(inprof, intent);
388 outpxformseq = revpxformseq(outprof, intent);
389 if (!inpxformseq || !outpxformseq)
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))
396 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
397 xform->numoutchans = jas_clrspc_numchans(outprof->clrspc);
399 case JAS_CMXFORM_OP_REV:
400 outpxformseq = fwdpxformseq(outprof, intent);
401 inpxformseq = revpxformseq(inprof, intent);
402 if (!outpxformseq || !inpxformseq)
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))
409 xform->numinchans = jas_clrspc_numchans(outprof->clrspc);
410 xform->numoutchans = jas_clrspc_numchans(inprof->clrspc);
412 case JAS_CMXFORM_OP_PROOF:
414 inpxformseq = fwdpxformseq(inprof, intent);
415 prfpxformseq = fwdpxformseq(prfprof, prfintent);
416 if (!inpxformseq || !prfpxformseq)
418 outpxformseq = simpxformseq(outprof, intent);
421 outpxformseq = revpxformseq(outprof, intent);
422 altoutpxformseq = fwdpxformseq(outprof, intent);
423 if (!outpxformseq || !altoutpxformseq)
426 if (jas_cmpxformseq_append(xform->pxformseq, inpxformseq) ||
427 jas_cmpxformseq_appendcnvt(xform->pxformseq,
428 inprof->refclrspc, outprof->refclrspc))
430 if (altoutpxformseq) {
431 if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq) ||
432 jas_cmpxformseq_append(xform->pxformseq, altoutpxformseq))
435 if (jas_cmpxformseq_append(xform->pxformseq, outpxformseq))
438 if (jas_cmpxformseq_appendcnvt(xform->pxformseq,
439 outprof->refclrspc, inprof->refclrspc) ||
440 jas_cmpxformseq_append(xform->pxformseq, prfpxformseq))
442 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
443 xform->numoutchans = jas_clrspc_numchans(prfprof->clrspc);
445 case JAS_CMXFORM_OP_GAMUT:
446 inpxformseq = fwdpxformseq(inprof, intent);
447 outpxformseq = gampxformseq(outprof);
448 if (!inpxformseq || !outpxformseq)
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))
455 xform->numinchans = jas_clrspc_numchans(inprof->clrspc);
456 xform->numoutchans = 1;
464 #define APPLYBUFSIZ 2048
465 int jas_cmxform_apply(jas_cmxform_t *xform, jas_cmpixmap_t *in, jas_cmpixmap_t *out)
467 jas_cmcmptfmt_t *fmt;
468 jas_cmreal_t buf[2][APPLYBUFSIZ];
469 jas_cmpxformseq_t *pxformseq;
477 jas_cmreal_t *outbuf;
478 jas_cmpxform_t *pxform;
486 jas_cmreal_t *bufptr;
488 if (xform->numinchans > in->numcmpts || xform->numoutchans > out->numcmpts)
491 fmt = &in->cmptfmts[0];
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) {
500 for (i = 0; i < xform->numoutchans; ++i) {
501 fmt = &out->cmptfmts[i];
502 if (fmt->width != width || fmt->height != height) {
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;
514 if (pxform->numoutchans > maxchans) {
515 maxchans = pxform->numoutchans;
518 bufmax = APPLYBUFSIZ / maxchans;
521 total = width * height;
526 m = JAS_MIN(total - n, bufmax);
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];
534 for (j = 0; j < m; ++j) {
535 if (jas_cmgetint(&dataptr, fmt->sgnd, fmt->prec, &v))
537 *bufptr = (v - bias) / scale;
538 bufptr += xform->numinchans;
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];
551 if ((*pxform->ops->apply)(pxform, inbuf, outbuf, m))
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;
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))
578 void jas_cmxform_destroy(jas_cmxform_t *xform)
580 if (xform->pxformseq)
581 jas_cmpxformseq_destroy(xform->pxformseq);
585 /******************************************************************************\
586 * Primitive transform sequence class.
587 \******************************************************************************/
589 static jas_cmpxformseq_t *jas_cmpxformseq_create()
591 jas_cmpxformseq_t *pxformseq;
593 if (!(pxformseq = jas_malloc(sizeof(jas_cmpxformseq_t))))
595 pxformseq->pxforms = 0;
596 pxformseq->numpxforms = 0;
597 pxformseq->maxpxforms = 0;
598 if (jas_cmpxformseq_resize(pxformseq, 16))
603 jas_cmpxformseq_destroy(pxformseq);
607 static jas_cmpxformseq_t *jas_cmpxformseq_copy(jas_cmpxformseq_t *pxformseq)
609 jas_cmpxformseq_t *newpxformseq;
611 if (!(newpxformseq = jas_cmpxformseq_create()))
613 if (jas_cmpxformseq_append(newpxformseq, pxformseq))
620 static void jas_cmpxformseq_destroy(jas_cmpxformseq_t *pxformseq)
622 while (pxformseq->numpxforms > 0)
623 jas_cmpxformseq_delete(pxformseq, pxformseq->numpxforms - 1);
624 if (pxformseq->pxforms)
625 jas_free(pxformseq->pxforms);
629 static int jas_cmpxformseq_delete(jas_cmpxformseq_t *pxformseq, int i)
631 assert(i >= 0 && i < pxformseq->numpxforms);
632 if (i != pxformseq->numpxforms - 1)
634 jas_cmpxform_destroy(pxformseq->pxforms[i]);
635 pxformseq->pxforms[i] = 0;
636 --pxformseq->numpxforms;
640 static int jas_cmpxformseq_appendcnvt(jas_cmpxformseq_t *pxformseq,
641 int dstclrspc, int srcclrspc)
643 if (dstclrspc == srcclrspc)
646 /* Avoid compiler warnings about unused parameters. */
651 static int jas_cmpxformseq_insertpxform(jas_cmpxformseq_t *pxformseq,
652 int i, jas_cmpxform_t *pxform)
654 jas_cmpxform_t *tmppxform;
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 +
664 assert(pxformseq->numpxforms < pxformseq->maxpxforms);
665 if (!(tmppxform = jas_cmpxform_copy(pxform)))
667 n = pxformseq->numpxforms - i;
669 memmove(&pxformseq->pxforms[i + 1], &pxformseq->pxforms[i],
670 n * sizeof(jas_cmpxform_t *));
672 pxformseq->pxforms[i] = tmppxform;
673 ++pxformseq->numpxforms;
679 static int jas_cmpxformseq_append(jas_cmpxformseq_t *pxformseq,
680 jas_cmpxformseq_t *othpxformseq)
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))
691 for (i = 0; i < othpxformseq->numpxforms; ++i) {
692 othpxform = othpxformseq->pxforms[i];
693 if (!(pxform = jas_cmpxform_copy(othpxform)))
695 pxformseq->pxforms[pxformseq->numpxforms] = pxform;
696 ++pxformseq->numpxforms;
703 static int jas_cmpxformseq_resize(jas_cmpxformseq_t *pxformseq, int n)
706 assert(n >= pxformseq->numpxforms);
707 p = (!pxformseq->pxforms) ? jas_malloc(n * sizeof(jas_cmpxform_t *)) :
708 jas_realloc(pxformseq->pxforms, n * sizeof(jas_cmpxform_t *));
712 pxformseq->pxforms = p;
713 pxformseq->maxpxforms = n;
717 /******************************************************************************\
718 * Primitive transform class.
719 \******************************************************************************/
721 static jas_cmpxform_t *jas_cmpxform_create0()
723 jas_cmpxform_t *pxform;
724 if (!(pxform = jas_malloc(sizeof(jas_cmpxform_t))))
726 memset(pxform, 0, sizeof(jas_cmpxform_t));
732 static void jas_cmpxform_destroy(jas_cmpxform_t *pxform)
734 if (--pxform->refcnt <= 0) {
735 (*pxform->ops->destroy)(pxform);
740 static jas_cmpxform_t *jas_cmpxform_copy(jas_cmpxform_t *pxform)
746 /******************************************************************************\
747 * Shaper matrix class.
748 \******************************************************************************/
750 static jas_cmpxform_t *jas_cmpxform_createshapmat()
754 jas_cmpxform_t *pxform;
755 jas_cmshapmat_t *shapmat;
756 if (!(pxform = jas_cmpxform_create0()))
758 pxform->ops = &shapmat_ops;
759 shapmat = &pxform->data.shapmat;
762 shapmat->useluts = 0;
764 for (i = 0; i < 3; ++i)
765 jas_cmshapmatlut_init(&shapmat->luts[i]);
766 for (i = 0; i < 3; ++i) {
767 for (j = 0; j < 4; ++j)
768 shapmat->mat[i][j] = 0.0;
774 static void jas_cmshapmat_destroy(jas_cmpxform_t *pxform)
776 jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
778 for (i = 0; i < 3; ++i)
779 jas_cmshapmatlut_cleanup(&shapmat->luts[i]);
782 static int jas_cmshapmat_apply(jas_cmpxform_t *pxform, jas_cmreal_t *in,
783 jas_cmreal_t *out, int cnt)
785 jas_cmshapmat_t *shapmat = &pxform->data.shapmat;
796 if (!shapmat->mono) {
801 if (!shapmat->order && shapmat->useluts) {
802 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
803 a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
804 a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
806 if (shapmat->usemat) {
807 b0 = shapmat->mat[0][0] * a0
808 + shapmat->mat[0][1] * a1
809 + shapmat->mat[0][2] * a2
810 + shapmat->mat[0][3];
811 b1 = shapmat->mat[1][0] * a0
812 + shapmat->mat[1][1] * a1
813 + shapmat->mat[1][2] * a2
814 + shapmat->mat[1][3];
815 b2 = shapmat->mat[2][0] * a0
816 + shapmat->mat[2][1] * a1
817 + shapmat->mat[2][2] * a2
818 + shapmat->mat[2][3];
823 if (shapmat->order && shapmat->useluts) {
824 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
825 a1 = jas_cmshapmatlut_lookup(&shapmat->luts[1], a1);
826 a2 = jas_cmshapmatlut_lookup(&shapmat->luts[2], a2);
833 if (!shapmat->order) {
836 if (shapmat->useluts)
837 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
838 a2 = a0 * shapmat->mat[2][0];
839 a1 = a0 * shapmat->mat[1][0];
840 a0 = a0 * shapmat->mat[0][0];
851 a0 = a0 * shapmat->mat[0][0];
852 if (shapmat->useluts)
853 a0 = jas_cmshapmatlut_lookup(&shapmat->luts[0], a0);
862 static void jas_cmshapmatlut_init(jas_cmshapmatlut_t *lut)
868 static void jas_cmshapmatlut_cleanup(jas_cmshapmatlut_t *lut)
877 static double gammafn(double x, double gamma)
881 return pow(x, gamma);
884 static int jas_cmshapmatlut_set(jas_cmshapmatlut_t *lut, jas_icccurv_t *curv)
889 jas_cmshapmatlut_cleanup(lut);
890 if (curv->numents == 0) {
892 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
896 } else if (curv->numents == 1) {
898 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
900 gamma = curv->ents[0] / 256.0;
901 for (i = 0; i < lut->size; ++i) {
902 lut->data[i] = gammafn(i / (double) (lut->size - 1), gamma);
905 lut->size = curv->numents;
906 if (!(lut->data = jas_malloc(lut->size * sizeof(jas_cmreal_t))))
908 for (i = 0; i < lut->size; ++i) {
909 lut->data[i] = curv->ents[i] / 65535.0;
917 static jas_cmreal_t jas_cmshapmatlut_lookup(jas_cmshapmatlut_t *lut, jas_cmreal_t x)
922 t = x * (lut->size - 1);
928 return lut->data[lut->size - 1];
929 return lut->data[lo] + (t - lo) * (lut->data[hi] - lut->data[lo]);
932 static int jas_cmshapmatlut_invert(jas_cmshapmatlut_t *invlut,
933 jas_cmshapmatlut_t *lut, int n)
946 jas_free(invlut->data);
949 /* The sample values should be nondecreasing. */
950 for (i = 1; i < lut->size; ++i) {
951 if (lut->data[i - 1] > lut->data[i]) {
956 if (!(invlut->data = jas_malloc(n * sizeof(jas_cmreal_t))))
959 for (i = 0; i < invlut->size; ++i) {
960 sy = ((double) i) / (invlut->size - 1);
962 for (j = 0; j < lut->size; ++j) {
965 for (k = j + 1; k < lut->size; ++k) {
975 ax = ((double) j) / (lut->size - 1);
976 bx = ((double) k) / (lut->size - 1);
977 sx = (ax + bx) / 2.0;
981 if (j < lut->size - 1) {
982 by = lut->data[j + 1];
983 if (sy > ay && sy < by) {
984 ax = ((double) j) / (lut->size - 1);
985 bx = ((double) j + 1) / (lut->size - 1);
987 (sy - ay) / (by - ay) * (bx - ax);
992 invlut->data[i] = sx;
995 for (i=0;i<lut->size;++i)
996 jas_eprintf("lut[%d]=%f ", i, lut->data[i]);
997 for (i=0;i<invlut->size;++i)
998 jas_eprintf("invlut[%d]=%f ", i, invlut->data[i]);
1003 static int jas_cmshapmat_invmat(jas_cmreal_t out[3][4], jas_cmreal_t in[3][4])
1006 d = in[0][0] * (in[1][1] * in[2][2] - in[1][2] * in[2][1])
1007 - in[0][1] * (in[1][0] * in[2][2] - in[1][2] * in[2][0])
1008 + in[0][2] * (in[1][0] * in[2][1] - in[1][1] * in[2][0]);
1010 jas_eprintf("delta=%f\n", d);
1012 if (JAS_ABS(d) < 1e-6)
1014 out[0][0] = (in[1][1] * in[2][2] - in[1][2] * in[2][1]) / d;
1015 out[1][0] = -(in[1][0] * in[2][2] - in[1][2] * in[2][0]) / d;
1016 out[2][0] = (in[1][0] * in[2][1] - in[1][1] * in[2][0]) / d;
1017 out[0][1] = -(in[0][1] * in[2][2] - in[0][2] * in[2][1]) / d;
1018 out[1][1] = (in[0][0] * in[2][2] - in[0][2] * in[2][0]) / d;
1019 out[2][1] = -(in[0][0] * in[2][1] - in[0][1] * in[2][0]) / d;
1020 out[0][2] = (in[0][1] * in[1][2] - in[0][2] * in[1][1]) / d;
1021 out[1][2] = -(in[0][0] * in[1][2] - in[1][0] * in[0][2]) / d;
1022 out[2][2] = (in[0][0] * in[1][1] - in[0][1] * in[1][0]) / d;
1023 out[0][3] = -in[0][3];
1024 out[1][3] = -in[1][3];
1025 out[2][3] = -in[2][3];
1027 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1028 in[0][0], in[0][1], in[0][2], in[0][3],
1029 in[1][0], in[1][1], in[1][2], in[1][3],
1030 in[2][0], in[2][1], in[2][2], in[2][3]);
1031 jas_eprintf("[ %f %f %f %f ]\n[ %f %f %f %f ]\n[ %f %f %f %f ]\n",
1032 out[0][0], out[0][1], out[0][2], out[0][3],
1033 out[1][0], out[1][1], out[1][2], out[1][3],
1034 out[2][0], out[2][1], out[2][2], out[2][3]);
1039 /******************************************************************************\
1041 \******************************************************************************/
1043 static int icctoclrspc(int iccclrspc, int refflag)
1046 switch (iccclrspc) {
1047 case JAS_ICC_COLORSPC_XYZ:
1048 return JAS_CLRSPC_CIEXYZ;
1049 case JAS_ICC_COLORSPC_LAB:
1050 return JAS_CLRSPC_CIELAB;
1056 switch (iccclrspc) {
1057 case JAS_ICC_COLORSPC_YCBCR:
1058 return JAS_CLRSPC_GENYCBCR;
1059 case JAS_ICC_COLORSPC_RGB:
1060 return JAS_CLRSPC_GENRGB;
1061 case JAS_ICC_COLORSPC_GRAY:
1062 return JAS_CLRSPC_GENGRAY;
1070 static int mono(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
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;
1078 jas_cmshapmatlut_init(&lut);
1079 if (!(graytrc = jas_iccprof_getattr(iccprof, JAS_ICC_TAG_GRYTRC)) ||
1080 graytrc->type != JAS_ICC_TYPE_CURV)
1082 if (!(pxform = jas_cmpxform_createshapmat()))
1084 shapmat = &pxform->data.shapmat;
1085 if (!(pxformseq = jas_cmpxformseq_create()))
1087 if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1090 pxform->numinchans = 1;
1091 pxform->numoutchans = 3;
1094 shapmat->useluts = 1;
1095 shapmat->usemat = 1;
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))
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))
1111 if (jas_cmshapmatlut_invert(&shapmat->luts[0], &lut, lut.size))
1113 jas_cmshapmatlut_cleanup(&lut);
1115 jas_iccattrval_destroy(graytrc);
1116 jas_cmpxform_destroy(pxform);
1117 *retpxformseq = pxformseq;
1123 static int triclr(jas_iccprof_t *iccprof, int op, jas_cmpxformseq_t **retpxformseq)
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;
1136 for (i = 0; i < 3; ++i) {
1140 jas_cmshapmatlut_init(&lut);
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)))
1149 for (i = 0; i < 3; ++i) {
1150 if (trcs[i]->type != JAS_ICC_TYPE_CURV ||
1151 cols[i]->type != JAS_ICC_TYPE_XYZ)
1154 if (!(pxform = jas_cmpxform_createshapmat()))
1156 pxform->numinchans = 3;
1157 pxform->numoutchans = 3;
1158 shapmat = &pxform->data.shapmat;
1159 if (!(pxformseq = jas_cmpxformseq_create()))
1161 if (jas_cmpxformseq_insertpxform(pxformseq, -1, pxform))
1164 shapmat->useluts = 1;
1165 shapmat->usemat = 1;
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;
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))
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;
1186 for (i = 0; i < 3; ++i)
1188 if (jas_cmshapmat_invmat(shapmat->mat, mat))
1190 for (i = 0; i < 3; ++i) {
1191 jas_cmshapmatlut_init(&lut);
1192 if (jas_cmshapmatlut_set(&lut, &trcs[i]->data.curv))
1194 if (jas_cmshapmatlut_invert(&shapmat->luts[i], &lut, lut.size))
1196 jas_cmshapmatlut_cleanup(&lut);
1199 for (i = 0; i < 3; ++i) {
1200 jas_iccattrval_destroy(trcs[i]);
1201 jas_iccattrval_destroy(cols[i]);
1203 jas_cmpxform_destroy(pxform);
1204 *retpxformseq = pxformseq;
1209 for (i = 0; i < 3; ++i) {
1211 jas_iccattrval_destroy(trcs[i]);
1214 jas_iccattrval_destroy(cols[i]);
1218 jas_cmpxformseq_destroy(pxformseq);
1221 jas_cmpxform_destroy(pxform);
1227 static int jas_cmgetint(long **bufptr, int sgnd, int prec, long *val)
1233 m = (1 << (prec - 1));
1234 if (v < -m || v >= m)
1237 if (v < 0 || v >= (1 << prec))
1245 static int jas_cmputint(long **bufptr, int sgnd, int prec, long val)
1249 m = (1 << (prec - 1));
1250 if (val < -m || val >= m)
1253 if (val < 0 || val >= (1 << prec))
1261 int jas_clrspc_numchans(int clrspc)
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:
1270 case JAS_CLRSPC_FAM_GRAY:
1279 jas_iccprof_t *jas_iccprof_createfromcmprof(jas_cmprof_t *prof)
1281 return jas_iccprof_copy(prof->iccprof);