1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13 CA 94903, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* CIE color rendering */
18 #include "math_.h"
19 #include "gx.h"
20 #include "gserrors.h"
21 #include "gxcspace.h" /* for gxcie.c */
22 #include "gxarith.h"
23 #include "gxcie.h"
24 #include "gxdevice.h" /* for gxcmap.h */
25 #include "gxcmap.h"
26 #include "gxistate.h"
27 #include "gscolor2.h"
28 #include "gsicc_create.h" /* Needed for delayed creation of ICC profiles from CIE color spaces */
29 #include "gsicc_manage.h"
30 #include "gsicc.h"
31 #include "gscspace.h"
32
33 /*
34 * Compute a cache index as (vin - base) * factor.
35 * vin, base, factor, and the result are cie_cached_values.
36 * We know that the result doesn't exceed (gx_cie_cache_size - 1) << fbits.
37 *
38 * Since this operation is extremely time-critical, we don't rely on the
39 * compiler providing 'inline'.
40 */
41 #define LOOKUP_INDEX_(vin, pcache, fbits)\
42 (cie_cached_value)\
43 ((vin) <= (pcache)->vecs.params.base ? 0 :\
44 (vin) >= (pcache)->vecs.params.limit ? (gx_cie_cache_size - 1) << (fbits) :\
45 cie_cached_product2int( ((vin) - (pcache)->vecs.params.base),\
46 (pcache)->vecs.params.factor, fbits ))
47 #define LOOKUP_ENTRY_(vin, pcache)\
48 (&(pcache)->vecs.values[(int)LOOKUP_INDEX(vin, pcache, 0)])
49 #ifdef DEBUG
50 static cie_cached_value
LOOKUP_INDEX(cie_cached_value vin,const gx_cie_vector_cache * pcache,int fbits)51 LOOKUP_INDEX(cie_cached_value vin, const gx_cie_vector_cache *pcache,
52 int fbits)
53 {
54 return LOOKUP_INDEX_(vin, pcache, fbits);
55 }
56 static const cie_cached_vector3 *
LOOKUP_ENTRY(cie_cached_value vin,const gx_cie_vector_cache * pcache)57 LOOKUP_ENTRY(cie_cached_value vin, const gx_cie_vector_cache *pcache)
58 {
59 return LOOKUP_ENTRY_(vin, pcache);
60 }
61 #else /* !DEBUG */
62 # define LOOKUP_INDEX(vin, pcache, fbits) LOOKUP_INDEX_(vin, pcache, fbits)
63 # define LOOKUP_ENTRY(vin, pcache) LOOKUP_ENTRY_(vin, pcache)
64 #endif /* DEBUG */
65
66 /*
67 * Call the remap_finish procedure in the structure without going through
68 * the extra level of procedure.
69 */
70 #ifdef DEBUG
71 # define GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs)\
72 gx_cie_remap_finish(vec3, pconc, pis, pcs)
73 #else
74 # define GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs)\
75 ((pis)->cie_joint_caches->remap_finish(vec3, pconc, pis, pcs))
76 #endif
77
78 /* Forward references */
79 static void cie_lookup_mult3(cie_cached_vector3 *,
80 const gx_cie_vector_cache3_t *);
81
82 #ifdef DEBUG
83 static void
cie_lookup_map3(cie_cached_vector3 * pvec,const gx_cie_vector_cache3_t * pc,const char * cname)84 cie_lookup_map3(cie_cached_vector3 * pvec,
85 const gx_cie_vector_cache3_t * pc, const char *cname)
86 {
87 if_debug5('c', "[c]lookup %s 0x%lx [%g %g %g]\n",
88 (const char *)cname, (ulong) pc,
89 cie_cached2float(pvec->u), cie_cached2float(pvec->v),
90 cie_cached2float(pvec->w));
91 cie_lookup_mult3(pvec, pc);
92 if_debug3('c', " =[%g %g %g]\n",
93 cie_cached2float(pvec->u), cie_cached2float(pvec->v),
94 cie_cached2float(pvec->w));
95 }
96 #else
97 # define cie_lookup_map3(pvec, pc, cname) cie_lookup_mult3(pvec, pc)
98 #endif
99
100 /* Check used for internal ranges to determine if we need to create a
101 CLUT for the ICC profile and if we need to rescale the incoming
102 CIE data.*/
103 bool
check_range(gs_range * ranges,int num_colorants)104 check_range(gs_range *ranges, int num_colorants)
105 {
106 int k;
107
108 for (k = 0; k < num_colorants; k++) {
109 if (ranges[k].rmin != 0) return false;
110 if (ranges[k].rmax != 1) return false;
111 }
112 return(true);
113 }
114
115 /* Returns false if range is not 0 1 */
116 bool
check_cie_range(const gs_color_space * pcs)117 check_cie_range( const gs_color_space * pcs )
118 {
119 switch(gs_color_space_get_index(pcs)){
120 case gs_color_space_index_CIEDEFG:
121 return(check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4));
122 case gs_color_space_index_CIEDEF:
123 return(check_range(&(pcs->params.def->RangeDEF.ranges[0]), 3));
124 case gs_color_space_index_CIEABC:
125 return(check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3));
126 case gs_color_space_index_CIEA:
127 return(check_range(&(pcs->params.a->RangeA), 1));
128 default:
129 return true;
130 }
131 }
132
133 gs_range*
get_cie_range(const gs_color_space * pcs)134 get_cie_range( const gs_color_space * pcs )
135 {
136 switch(gs_color_space_get_index(pcs)){
137 case gs_color_space_index_CIEDEFG:
138 return(&(pcs->params.defg->RangeDEFG.ranges[0]));
139 case gs_color_space_index_CIEDEF:
140 return(&(pcs->params.def->RangeDEF.ranges[0]));
141 case gs_color_space_index_CIEABC:
142 return(&(pcs->params.abc->RangeABC.ranges[0]));
143 case gs_color_space_index_CIEA:
144 return(&(pcs->params.a->RangeA));
145 default:
146 return NULL;
147 }
148 }
149
150 static void
rescale_input_color(gs_range * ranges,int num_colorants,const gs_client_color * src,gs_client_color * des)151 rescale_input_color(gs_range *ranges, int num_colorants,
152 const gs_client_color *src, gs_client_color *des)
153 {
154 int k;
155
156 for (k = 0; k < num_colorants; k++) {
157 des->paint.values[k] =
158 (src->paint.values[k]-ranges[k].rmin)/
159 (ranges[k].rmax-ranges[k].rmin);
160 }
161 }
162
163 /*
164 * Test whether a CIE rendering has been defined; ensure that the joint
165 * caches are loaded. Note that the procedure may return 1 if no rendering
166 * has been defined. The 'cie_to_xyz' flag indicates that we don't need a CRD
167 */
168 static inline int
gx_cie_check_rendering_inline(const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)169 gx_cie_check_rendering_inline(const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis)
170 {
171 if (pis->cie_render == 0 && !pis->cie_to_xyz) {
172 /* No rendering has been defined yet: return black. */
173 pconc[0] = pconc[1] = pconc[2] = frac_0;
174 return 1;
175 }
176 if (pis->cie_joint_caches->status == CIE_JC_STATUS_COMPLETED) {
177 if (pis->cie_joint_caches->cspace_id != pcs->id)
178 pis->cie_joint_caches->status = CIE_JC_STATUS_BUILT;
179 }
180 if (pis->cie_joint_caches->status != CIE_JC_STATUS_COMPLETED) {
181 int code = gs_cie_jc_complete(pis, pcs);
182
183 if (code < 0)
184 return code;
185 }
186 return 0;
187 }
188 int
gx_cie_check_rendering(const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)189 gx_cie_check_rendering(const gs_color_space * pcs, frac * pconc, const gs_imager_state * pis)
190 {
191 return gx_cie_check_rendering_inline(pcs, pconc, pis);
192 }
193
194 /* Common code shared between remap and concretize for defg */
195 static int
gx_ciedefg_to_icc(gs_color_space ** ppcs_icc,gs_color_space * pcs,gs_memory_t * memory)196 gx_ciedefg_to_icc(gs_color_space **ppcs_icc, gs_color_space *pcs, gs_memory_t *memory)
197 {
198 int code = 0;
199 gs_color_space *palt_cs = pcs->base_space;
200 gx_cie_vector_cache *abc_caches = &(pcs->params.abc->caches.DecodeABC.caches[0]);
201 gx_cie_scalar_cache *lmn_caches = &(pcs->params.abc->common.caches.DecodeLMN[0]);
202 gx_cie_scalar_cache *defg_caches = &(pcs->params.defg->caches_defg.DecodeDEFG[0]);
203
204 if_debug0(gs_debug_flag_icc,"[icc] Creating ICC profile from defg object");
205 /* build the ICC color space object */
206 code = gs_cspace_build_ICC(ppcs_icc, NULL, memory->stable_memory);
207 /* record the cie alt space as the icc alternative color space */
208 (*ppcs_icc)->base_space = palt_cs;
209 rc_increment_cs(palt_cs);
210 (*ppcs_icc)->cmm_icc_profile_data = gsicc_profile_new(NULL, memory, NULL, 0);
211 code = gsicc_create_fromdefg(pcs, &((*ppcs_icc)->cmm_icc_profile_data->buffer),
212 &((*ppcs_icc)->cmm_icc_profile_data->buffer_size), memory,
213 abc_caches, lmn_caches, defg_caches);
214 gsicc_init_profile_info((*ppcs_icc)->cmm_icc_profile_data);
215 (*ppcs_icc)->cmm_icc_profile_data->default_match = CIE_DEFG;
216 pcs->icc_equivalent = *ppcs_icc;
217 pcs->icc_equivalent->cmm_icc_profile_data->data_cs = gsCMYK;
218 return(0);
219 }
220
221 int
gx_remap_CIEDEFG(const gs_client_color * pc,const gs_color_space * pcs_in,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)222 gx_remap_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs_in,
223 gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
224 gs_color_select_t select)
225 {
226 gs_color_space *pcs_icc;
227 int code, i;
228 gs_client_color scale_pc;
229 gs_color_space *pcs = (gs_color_space *) pcs_in;
230
231 if_debug4('c', "[c]remap CIEDEFG [%g %g %g %g]\n",
232 pc->paint.values[0], pc->paint.values[1],
233 pc->paint.values[2], pc->paint.values[3]);
234 /* If we are comming in here then we have not completed
235 the conversion of the DEFG space to an ICC type. We
236 will finish that process now. */
237 if (pcs->icc_equivalent == NULL) {
238 code = gx_ciedefg_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
239 } else {
240 pcs_icc = pcs->icc_equivalent;
241 }
242 /* Rescale the input based upon the input range since profile is
243 created to remap this range from 0 to 1 */
244 if (check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4)) {
245 return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select));
246 }
247 /* Do the rescale from 0 to 1 */
248 rescale_input_color(&(pcs->params.defg->RangeDEFG.ranges[0]), 4, pc, &scale_pc);
249 /* Now the icc remap */
250 code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select);
251 /* Save unscaled data for high level device (e.g. pdfwrite) */
252 for (i = 0; i < 4; i++)
253 pdc->ccolor.paint.values[i] = pc->paint.values[i];
254 pdc->ccolor_valid = true;
255 return(code);
256 }
257
258 /* Render a CIEBasedDEFG color. */
259 int
gx_concretize_CIEDEFG(const gs_client_color * pc,const gs_color_space * pcs_in,frac * pconc,const gs_imager_state * pis,gx_device * dev)260 gx_concretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs_in,
261 frac * pconc, const gs_imager_state * pis, gx_device *dev)
262 {
263 int code;
264 gs_color_space *pcs_icc;
265 gs_client_color scale_pc;
266 gs_color_space *pcs = (gs_color_space *) pcs_in;
267
268 if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n",
269 pc->paint.values[0], pc->paint.values[1],
270 pc->paint.values[2], pc->paint.values[3]);
271 /* If we are comming in here then we have not completed
272 the conversion of the DEFG space to an ICC type. We
273 will finish that process now. */
274 if (pcs->icc_equivalent == NULL) {
275 code = gx_ciedefg_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
276 } else {
277 pcs_icc = pcs->icc_equivalent;
278 }
279 /* Rescale the input based upon the input range since profile is
280 created to remap this range from 0 to 1 */
281 if (check_range(&(pcs->params.defg->RangeDEFG.ranges[0]), 4)) {
282 return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev));
283 }
284 /* Do the rescale from 0 to 1 */
285 rescale_input_color(&(pcs->params.defg->RangeDEFG.ranges[0]), 4, pc, &scale_pc);
286 /* Now the icc remap */
287 return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev));
288 }
289
290 /* Used for when we have to mash entire transform to CIEXYZ */
291 int
gx_psconcretize_CIEA(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)292 gx_psconcretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs,
293 frac * pconc, const gs_imager_state * pis)
294 {
295 const gs_cie_a *pcie = pcs->params.a;
296 cie_cached_value a = float2cie_cached(pc->paint.values[0]);
297 cie_cached_vector3 vlmn;
298 int code;
299
300 if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
301 code = gx_cie_check_rendering_inline(pcs, pconc, pis);
302 if (code < 0)
303 return code;
304 if (code == 1)
305 return 0;
306
307 /* Apply DecodeA and MatrixA. */
308 if (!pis->cie_joint_caches->skipDecodeABC)
309 vlmn = *LOOKUP_ENTRY(a, &pcie->caches.DecodeA);
310 else
311 vlmn.u = vlmn.v = vlmn.w = a;
312 GX_CIE_REMAP_FINISH(vlmn, pconc, pis, pcs);
313 return 0;
314 }
315
316 /* Used for when we have to mash entire transform to CIEXYZ */
317 int
gx_psconcretize_CIEABC(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)318 gx_psconcretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs,
319 frac * pconc, const gs_imager_state * pis)
320 {
321 const gs_cie_abc *pcie = pcs->params.abc;
322 cie_cached_vector3 vec3;
323 int code;
324
325 if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
326 pc->paint.values[0], pc->paint.values[1],
327 pc->paint.values[2]);
328 code = gx_cie_check_rendering_inline(pcs, pconc, pis);
329 if (code < 0)
330 return code;
331 if (code == 1)
332 return 0;
333
334 vec3.u = float2cie_cached(pc->paint.values[0]);
335 vec3.v = float2cie_cached(pc->paint.values[1]);
336 vec3.w = float2cie_cached(pc->paint.values[2]);
337 if (!pis->cie_joint_caches->skipDecodeABC)
338 cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
339 "Decode/MatrixABC");
340 GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
341 return 0;
342 }
343
344 /* Used for when we have to mash entire transform to CIEXYZ */
345 int
gx_psconcretize_CIEDEFG(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)346 gx_psconcretize_CIEDEFG(const gs_client_color * pc, const gs_color_space * pcs,
347 frac * pconc, const gs_imager_state * pis)
348 {
349 const gs_cie_defg *pcie = pcs->params.defg;
350 int i;
351 fixed hijk[4];
352 frac abc[3];
353 cie_cached_vector3 vec3;
354 int code;
355
356 if_debug4('c', "[c]concretize DEFG [%g %g %g %g]\n",
357 pc->paint.values[0], pc->paint.values[1],
358 pc->paint.values[2], pc->paint.values[3]);
359 code = gx_cie_check_rendering_inline(pcs, pconc, pis);
360 if (code < 0)
361 return code;
362 if (code == 1)
363 return 0;
364 /*
365 * Apply DecodeDEFG, including restriction to RangeHIJK and scaling to
366 * the Table dimensions.
367 */
368 for (i = 0; i < 4; ++i) {
369 int tdim = pcie->Table.dims[i] - 1;
370 double factor = pcie->caches_defg.DecodeDEFG[i].floats.params.factor;
371 double v0 = pc->paint.values[i];
372 const gs_range *const rangeDEFG = &pcie->RangeDEFG.ranges[i];
373 double value =
374 (v0 < rangeDEFG->rmin ? 0.0 : factor *
375 (v0 > rangeDEFG->rmax ? rangeDEFG->rmax - rangeDEFG->rmin :
376 v0 - rangeDEFG->rmin ));
377 int vi = (int)value;
378 double vf = value - vi;
379 double v = pcie->caches_defg.DecodeDEFG[i].floats.values[vi];
380
381 if (vf != 0 && vi < factor)
382 v += vf *
383 (pcie->caches_defg.DecodeDEFG[i].floats.values[vi + 1] - v);
384 v = (v < 0 ? 0 : v > tdim ? tdim : v);
385 hijk[i] = float2fixed(v);
386 }
387 /* Apply Table. */
388 gx_color_interpolate_linear(hijk, &pcie->Table, abc);
389
390 #define SCALE_TO_RANGE(range, frac) ( \
391 float2cie_cached(((range).rmax - (range).rmin) * frac2float(frac) + \
392 (range).rmin) \
393 )
394 /* Scale the abc[] frac values to RangeABC cie_cached result */
395 vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]);
396 vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]);
397 vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]);
398 /* Apply DecodeABC and MatrixABC. */
399 if (!pis->cie_joint_caches->skipDecodeABC)
400 cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
401 "Decode/MatrixABC");
402 GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
403 return 0;
404 }
405
406 /* Render a CIEBasedDEF color. */
407 int
gx_psconcretize_CIEDEF(const gs_client_color * pc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)408 gx_psconcretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs,
409 frac * pconc, const gs_imager_state * pis)
410 {
411 const gs_cie_def *pcie = pcs->params.def;
412 int i;
413 fixed hij[3];
414 frac abc[3];
415 cie_cached_vector3 vec3;
416 int code;
417
418 if_debug3('c', "[c]concretize DEF [%g %g %g]\n",
419 pc->paint.values[0], pc->paint.values[1],
420 pc->paint.values[2]);
421 code = gx_cie_check_rendering_inline(pcs, pconc, pis);
422 if (code < 0)
423 return code;
424 if (code == 1)
425 return 0;
426
427 /*
428 * Apply DecodeDEF, including restriction to RangeHIJ and scaling to
429 * the Table dimensions.
430 */
431 for (i = 0; i < 3; ++i) {
432 int tdim = pcie->Table.dims[i] - 1;
433 double factor = pcie->caches_def.DecodeDEF[i].floats.params.factor;
434 double v0 = pc->paint.values[i];
435 const gs_range *const rangeDEF = &pcie->RangeDEF.ranges[i];
436 double value =
437 (v0 < rangeDEF->rmin ? 0.0 : factor *
438 (v0 > rangeDEF->rmax ? rangeDEF->rmax - rangeDEF->rmin :
439 v0 - rangeDEF->rmin ));
440 int vi = (int)value;
441 double vf = value - vi;
442 double v = pcie->caches_def.DecodeDEF[i].floats.values[vi];
443
444 if (vf != 0 && vi < factor)
445 v += vf *
446 (pcie->caches_def.DecodeDEF[i].floats.values[vi + 1] - v);
447 v = (v < 0 ? 0 : v > tdim ? tdim : v);
448 hij[i] = float2fixed(v);
449 }
450 /* Apply Table. */
451 gx_color_interpolate_linear(hij, &pcie->Table, abc);
452 /* Scale the abc[] frac values to RangeABC cie_cached result */
453 vec3.u = SCALE_TO_RANGE(pcie->RangeABC.ranges[0], abc[0]);
454 vec3.v = SCALE_TO_RANGE(pcie->RangeABC.ranges[1], abc[1]);
455 vec3.w = SCALE_TO_RANGE(pcie->RangeABC.ranges[2], abc[2]);
456 /* Apply DecodeABC and MatrixABC. */
457 if (!pis->cie_joint_caches->skipDecodeABC)
458 cie_lookup_map3(&vec3 /* ABC => LMN */, &pcie->caches.DecodeABC,
459 "Decode/MatrixABC");
460 GX_CIE_REMAP_FINISH(vec3, pconc, pis, pcs);
461 return 0;
462 }
463 #undef SCALE_TO_RANGE
464
465 /* Common code shared between remap and concretize for def */
466 static int
gx_ciedef_to_icc(gs_color_space ** ppcs_icc,gs_color_space * pcs,gs_memory_t * memory)467 gx_ciedef_to_icc(gs_color_space **ppcs_icc, gs_color_space *pcs, gs_memory_t *memory)
468 {
469 int code = 0;
470 gs_color_space *palt_cs = pcs->base_space;
471 gx_cie_vector_cache *abc_caches = &(pcs->params.abc->caches.DecodeABC.caches[0]);
472 gx_cie_scalar_cache *lmn_caches = &(pcs->params.abc->common.caches.DecodeLMN[0]);
473 gx_cie_scalar_cache *def_caches = &(pcs->params.def->caches_def.DecodeDEF[0]);
474
475 if_debug0(gs_debug_flag_icc,"[icc] Creating ICC profile from def object");
476 /* build the ICC color space object */
477 code = gs_cspace_build_ICC(ppcs_icc, NULL, memory->stable_memory);
478 /* record the cie alt space as the icc alternative color space */
479 (*ppcs_icc)->base_space = palt_cs;
480 rc_increment_cs(palt_cs);
481 (*ppcs_icc)->cmm_icc_profile_data = gsicc_profile_new(NULL, memory, NULL, 0);
482 code = gsicc_create_fromdef(pcs, &((*ppcs_icc)->cmm_icc_profile_data->buffer),
483 &((*ppcs_icc)->cmm_icc_profile_data->buffer_size), memory,
484 abc_caches, lmn_caches, def_caches);
485 gsicc_init_profile_info((*ppcs_icc)->cmm_icc_profile_data);
486 (*ppcs_icc)->cmm_icc_profile_data->default_match = CIE_DEF;
487 /* Assign to the icc_equivalent member variable */
488 pcs->icc_equivalent = *ppcs_icc;
489 pcs->icc_equivalent->cmm_icc_profile_data->data_cs = gsUNDEFINED;
490 return(0);
491 }
492
493 int
gx_remap_CIEDEF(const gs_client_color * pc,const gs_color_space * pcs_in,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)494 gx_remap_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs_in,
495 gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
496 gs_color_select_t select)
497 {
498 gs_color_space *pcs_icc;
499 gs_client_color scale_pc;
500 int i,code;
501 gs_color_space *pcs = (gs_color_space *) pcs_in;
502
503 if_debug3('c', "[c]remap CIEDEF [%g %g %g]\n",
504 pc->paint.values[0], pc->paint.values[1],
505 pc->paint.values[2]);
506 /* If we are comming in here then we have not completed
507 the conversion of the DEF space to an ICC type. We
508 will finish that process now. */
509 if (pcs->icc_equivalent == NULL) {
510 gx_ciedef_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
511 } else {
512 pcs_icc = pcs->icc_equivalent;
513 }
514 /* Rescale the input based upon the input range since profile is
515 created to remap this range from 0 to 1 */
516 if (check_range(&(pcs->params.def->RangeDEF.ranges[0]), 3)) {
517 return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select));
518 }
519 /* Do the rescale from 0 to 1 */
520 rescale_input_color(&(pcs->params.def->RangeDEF.ranges[0]), 3, pc, &scale_pc);
521 /* Now the icc remap */
522 code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select);
523 /* Save unscaled data for high level device (e.g. pdfwrite) */
524 for (i = 0; i < 3; i++)
525 pdc->ccolor.paint.values[i] = pc->paint.values[i];
526 pdc->ccolor_valid = true;
527 return(code);
528 }
529
530 /* Render a CIEBasedDEF color. */
531 int
gx_concretize_CIEDEF(const gs_client_color * pc,const gs_color_space * pcs_in,frac * pconc,const gs_imager_state * pis,gx_device * dev)532 gx_concretize_CIEDEF(const gs_client_color * pc, const gs_color_space * pcs_in,
533 frac * pconc, const gs_imager_state * pis, gx_device *dev)
534 {
535 int code;
536 gs_color_space *pcs_icc;
537 gs_client_color scale_pc;
538 gs_color_space *pcs = (gs_color_space *) pcs_in;
539
540 if_debug3('c', "[c]concretize DEF [%g %g %g]\n",
541 pc->paint.values[0], pc->paint.values[1],
542 pc->paint.values[2]);
543 /* If we are comming in here then we have not completed
544 the conversion of the DEF space to an ICC type. We
545 will finish that process now. */
546 if (pcs->icc_equivalent == NULL) {
547 code = gx_ciedef_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
548 } else {
549 pcs_icc = pcs->icc_equivalent;
550 }
551 /* Rescale the input based upon the input range since profile is
552 created to remap this range from 0 to 1 */
553 if (check_range(&(pcs->params.def->RangeDEF.ranges[0]), 3)) {
554 return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev));
555 }
556 /* Do the rescale from 0 to 1 */
557 rescale_input_color(&(pcs->params.def->RangeDEF.ranges[0]), 3, pc, &scale_pc);
558 /* Now the icc remap */
559 return((pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev));
560 }
561 #undef SCALE_TO_RANGE
562
563 /* Common code shared between remap and concretize */
564 static int
gx_cieabc_to_icc(gs_color_space ** ppcs_icc,gs_color_space * pcs,bool * islab,gs_memory_t * memory)565 gx_cieabc_to_icc(gs_color_space **ppcs_icc, gs_color_space *pcs, bool *islab,
566 gs_memory_t *memory)
567 {
568 int code = 0;
569 gs_color_space *palt_cs = pcs->base_space;
570 gx_cie_vector_cache *abc_caches = &(pcs->params.abc->caches.DecodeABC.caches[0]);
571 gx_cie_scalar_cache *lmn_caches = &(pcs->params.abc->common.caches.DecodeLMN[0]);
572
573 if_debug0(gs_debug_flag_icc,"[icc] Creating ICC profile from abc object");
574 /* build the ICC color space object */
575 code = gs_cspace_build_ICC(ppcs_icc, NULL, memory);
576 /* record the cie alt space as the icc alternative color space */
577 (*ppcs_icc)->base_space = palt_cs;
578 rc_increment_cs(palt_cs);
579 (*ppcs_icc)->cmm_icc_profile_data = gsicc_profile_new(NULL, memory, NULL, 0);
580 code = gsicc_create_fromabc(pcs, &((*ppcs_icc)->cmm_icc_profile_data->buffer),
581 &((*ppcs_icc)->cmm_icc_profile_data->buffer_size), memory,
582 abc_caches, lmn_caches, islab);
583 gsicc_init_profile_info((*ppcs_icc)->cmm_icc_profile_data);
584 (*ppcs_icc)->cmm_icc_profile_data->default_match = CIE_ABC;
585 /* Assign to the icc_equivalent member variable */
586 pcs->icc_equivalent = *ppcs_icc;
587 pcs->icc_equivalent->cmm_icc_profile_data->data_cs = gsRGB;
588 return(0);
589 }
590
591 /* Render a CIEBasedABC color. */
592 /* We provide both remap and concretize, but only the former */
593 /* needs to be efficient. */
594 int
gx_remap_CIEABC(const gs_client_color * pc,const gs_color_space * pcs_in,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)595 gx_remap_CIEABC(const gs_client_color * pc, const gs_color_space * pcs_in,
596 gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
597 gs_color_select_t select)
598 {
599 gs_color_space *pcs_icc;
600 gs_client_color scale_pc;
601 bool islab;
602 int i,code;
603 gs_color_space *pcs = (gs_color_space *) pcs_in;
604
605
606 if_debug3('c', "[c]remap CIEABC [%g %g %g]\n",
607 pc->paint.values[0], pc->paint.values[1],
608 pc->paint.values[2]);
609 /* If we are comming in here then we have not completed
610 the conversion of the ABC space to an ICC type. We
611 will finish that process now. */
612 if (pcs->icc_equivalent == NULL) {
613 gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory);
614 } else {
615 pcs_icc = pcs->icc_equivalent;
616 }
617 /* Rescale the input based upon the input range since profile is
618 created to remap this range from 0 to 1 */
619 if (check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3)) {
620 return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select));
621 }
622 /* Do the rescale from 0 to 1 */
623 rescale_input_color(&(pcs->params.abc->RangeABC.ranges[0]), 3, pc, &scale_pc);
624 /* Now the icc remap */
625 code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select);
626 /* Save unscaled data for high level device (e.g. pdfwrite) */
627 for (i = 0; i < 3; i++)
628 pdc->ccolor.paint.values[i] = pc->paint.values[i];
629 pdc->ccolor_valid = true;
630 /* Now the icc remap */
631 return(code);
632 }
633
634 int
gx_concretize_CIEABC(const gs_client_color * pc,const gs_color_space * pcs_in,frac * pconc,const gs_imager_state * pis,gx_device * dev)635 gx_concretize_CIEABC(const gs_client_color * pc, const gs_color_space * pcs_in,
636 frac * pconc, const gs_imager_state * pis, gx_device *dev)
637 {
638 gs_color_space *pcs_icc;
639 gs_client_color scale_pc;
640 bool islab;
641 gs_color_space *pcs = (gs_color_space *) pcs_in;
642
643 if_debug3('c', "[c]concretize CIEABC [%g %g %g]\n",
644 pc->paint.values[0], pc->paint.values[1],
645 pc->paint.values[2]);
646 /* If we are comming in here then we have not completed
647 the conversion of the ABC space to an ICC type. We
648 will finish that process now. */
649 if (pcs->icc_equivalent == NULL) {
650 gx_cieabc_to_icc(&pcs_icc, pcs, &islab, pis->memory->stable_memory);
651 } else {
652 pcs_icc = pcs->icc_equivalent;
653 }
654 /* Rescale the input based upon the input range since profile is
655 created to remap this range from 0 to 1 */
656 if (check_range(&(pcs->params.abc->RangeABC.ranges[0]), 3)) {
657 return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev));
658 }
659 /* Do the rescale from 0 to 1 */
660 rescale_input_color(&(pcs->params.abc->RangeABC.ranges[0]), 3, pc, &scale_pc);
661 /* Now the icc remap */
662 return((pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev));
663 }
664
665 /* Common code shared between remap and concretize */
666 static int
gx_ciea_to_icc(gs_color_space ** ppcs_icc,gs_color_space * pcs,gs_memory_t * memory)667 gx_ciea_to_icc(gs_color_space **ppcs_icc, gs_color_space *pcs, gs_memory_t *memory)
668 {
669 int code = 0;
670 gs_color_space *palt_cs = pcs->base_space;
671 gx_cie_vector_cache *a_cache = &(pcs->params.a->caches.DecodeA);
672 gx_cie_scalar_cache *lmn_caches = &(pcs->params.a->common.caches.DecodeLMN[0]);
673
674 if_debug0(gs_debug_flag_icc,"[icc] Creating ICC profile from CIEA object");
675 /* build the ICC color space object */
676 code = gs_cspace_build_ICC(ppcs_icc, NULL, memory);
677 /* record the cie alt space as the icc alternative color space */
678 (*ppcs_icc)->base_space = palt_cs;
679 rc_increment_cs(palt_cs);
680 (*ppcs_icc)->cmm_icc_profile_data = gsicc_profile_new(NULL, memory, NULL, 0);
681 code = gsicc_create_froma(pcs, &((*ppcs_icc)->cmm_icc_profile_data->buffer),
682 &((*ppcs_icc)->cmm_icc_profile_data->buffer_size), memory,
683 a_cache, lmn_caches);
684 gsicc_init_profile_info((*ppcs_icc)->cmm_icc_profile_data);
685 (*ppcs_icc)->cmm_icc_profile_data->default_match = CIE_A;
686 /* Assign to the icc_equivalent member variable */
687 pcs->icc_equivalent = *ppcs_icc;
688 pcs->icc_equivalent->cmm_icc_profile_data->data_cs = gsGRAY;
689 return(code);
690 }
691
692 int
gx_remap_CIEA(const gs_client_color * pc,const gs_color_space * pcs_in,gx_device_color * pdc,const gs_imager_state * pis,gx_device * dev,gs_color_select_t select)693 gx_remap_CIEA(const gs_client_color * pc, const gs_color_space * pcs_in,
694 gx_device_color * pdc, const gs_imager_state * pis, gx_device * dev,
695 gs_color_select_t select)
696 {
697 int code;
698 gs_color_space *pcs_icc;
699 gs_client_color scale_pc;
700 gs_color_space *pcs = (gs_color_space *) pcs_in;
701
702 if_debug1('c', "[c]remap CIEA [%g]\n",pc->paint.values[0]);
703 /* If we are coming in here then we may have not completed
704 the conversion of the CIE A space to an ICC type. We
705 will finish that process now. */
706 if (pcs->icc_equivalent == NULL) {
707 code = gx_ciea_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
708 } else {
709 /* Once the ICC color space is set, we should be doing all the remaps through the ICC equivalent */
710 pcs_icc = pcs->icc_equivalent;
711 }
712 /* Rescale the input based upon the input range since profile is
713 created to remap this range from 0 to 1 */
714 if (check_range(&(pcs->params.a->RangeA), 1)) {
715 return((pcs_icc->type->remap_color)(pc,pcs_icc,pdc,pis,dev,select));
716 }
717 /* Do the rescale from 0 to 1 */
718 rescale_input_color(&(pcs->params.a->RangeA), 1, pc, &scale_pc);
719 /* Now the icc remap */
720 code = (pcs_icc->type->remap_color)(&scale_pc,pcs_icc,pdc,pis,dev,select);
721 /* Save unscaled data for high level device (e.g. pdfwrite) */
722 pdc->ccolor.paint.values[0] = pc->paint.values[0];
723 pdc->ccolor_valid = true;
724 return(code);
725 }
726
727 /* Render a CIEBasedA color. */
728 int
gx_concretize_CIEA(const gs_client_color * pc,const gs_color_space * pcs_in,frac * pconc,const gs_imager_state * pis,gx_device * dev)729 gx_concretize_CIEA(const gs_client_color * pc, const gs_color_space * pcs_in,
730 frac * pconc, const gs_imager_state * pis, gx_device *dev)
731 {
732 int code;
733 gs_color_space *pcs_icc;
734 gs_client_color scale_pc;
735 gs_color_space *pcs = (gs_color_space *) pcs_in;
736
737 if_debug1('c', "[c]concretize CIEA %g\n", pc->paint.values[0]);
738 /* If we are comming in here then we have not completed
739 the conversion of the CIE A space to an ICC type. We
740 will finish that process now. */
741 if (pcs->icc_equivalent == NULL) {
742 code = gx_ciea_to_icc(&pcs_icc, pcs, pis->memory->stable_memory);
743 } else {
744 /* Once the ICC color space is set, we should be doing all the remaps through the ICC equivalent */
745 pcs_icc = pcs->icc_equivalent;
746 }
747 /* Rescale the input based upon the input range since profile is
748 created to remap this range from 0 to 1 */
749 if (check_range(&(pcs->params.a->RangeA), 1)) {
750 return((pcs_icc->type->concretize_color)(pc, pcs_icc, pconc, pis, dev));
751 }
752 /* Do the rescale from 0 to 1 */
753 rescale_input_color(&(pcs->params.a->RangeA), 1, pc, &scale_pc);
754 /* Now the icc remap */
755 return((pcs_icc->type->concretize_color)(&scale_pc, pcs_icc, pconc, pis, dev));
756 }
757
758 /* Call for cases where the equivalent icc color space needs to be set */
759 int
gs_colorspace_set_icc_equivalent(gs_color_space * pcs,bool * islab,gs_memory_t * memory)760 gs_colorspace_set_icc_equivalent(gs_color_space *pcs, bool *islab,
761 gs_memory_t *memory)
762 {
763 gs_color_space_index color_space_index = gs_color_space_get_index(pcs);
764 gs_color_space *picc_cs;
765
766 *islab = false; /* For non CIEABC cases */
767 if (pcs->icc_equivalent != NULL || !gs_color_space_is_PSCIE(pcs)) {
768 return(0);
769 }
770 switch( color_space_index ) {
771 case gs_color_space_index_CIEDEFG:
772 gx_ciedefg_to_icc(&picc_cs, pcs, memory->stable_memory);
773 break;
774 case gs_color_space_index_CIEDEF:
775 gx_ciedef_to_icc(&picc_cs, pcs, memory->stable_memory);
776 break;
777 case gs_color_space_index_CIEABC:
778 gx_cieabc_to_icc(&picc_cs, pcs, islab, memory->stable_memory);
779 break;
780 case gs_color_space_index_CIEA:
781 gx_ciea_to_icc(&picc_cs, pcs, memory->stable_memory);
782 break;
783 default:
784 /* do nothing. Sould never happen */
785 break;
786 }
787 return(0);
788 }
789
790 /* Call the remap_finish procedure in the joint_caches structure. */
791 int
gx_cie_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)792 gx_cie_remap_finish(cie_cached_vector3 vec3, frac * pconc,
793 const gs_imager_state * pis,
794 const gs_color_space *pcs)
795 {
796 return pis->cie_joint_caches->remap_finish(vec3, pconc, pis, pcs);
797 }
798
799 /* Finish remapping a CIEBased color. */
800 /* Return 3 if RGB, 4 if CMYK. */
801 /* this procedure is exported for the benefit of gsicc.c */
802 int
gx_cie_real_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)803 gx_cie_real_remap_finish(cie_cached_vector3 vec3, frac * pconc,
804 const gs_imager_state * pis,
805 const gs_color_space *pcs)
806 {
807 const gs_cie_render *pcrd = pis->cie_render;
808 const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
809 const gs_const_string *table = pcrd->RenderTable.lookup.table;
810 int tabc[3]; /* indices for final EncodeABC lookup */
811
812 /* Apply DecodeLMN, MatrixLMN(decode), and MatrixPQR. */
813 if (!pjc->skipDecodeLMN)
814 cie_lookup_map3(&vec3 /* LMN => PQR */, &pjc->DecodeLMN,
815 "Decode/MatrixLMN+MatrixPQR");
816
817 /* Apply TransformPQR, MatrixPQR', and MatrixLMN(encode). */
818 if (!pjc->skipPQR)
819 cie_lookup_map3(&vec3 /* PQR => LMN */, &pjc->TransformPQR,
820 "Transform/Matrix'PQR+MatrixLMN");
821
822 /* Apply EncodeLMN and MatrixABC(encode). */
823 if (!pjc->skipEncodeLMN)
824 cie_lookup_map3(&vec3 /* LMN => ABC */, &pcrd->caches.EncodeLMN,
825 "EncodeLMN+MatrixABC");
826
827 /* MatrixABCEncode includes the scaling of the EncodeABC */
828 /* cache index. */
829 #define SET_TABC(i, t)\
830 BEGIN\
831 tabc[i] = cie_cached2int(vec3 /*ABC*/.t - pcrd->EncodeABC_base[i],\
832 _cie_interpolate_bits);\
833 if ((uint)tabc[i] > (gx_cie_cache_size - 1) << _cie_interpolate_bits)\
834 tabc[i] = (tabc[i] < 0 ? 0 :\
835 (gx_cie_cache_size - 1) << _cie_interpolate_bits);\
836 END
837 SET_TABC(0, u);
838 SET_TABC(1, v);
839 SET_TABC(2, w);
840 #undef SET_TABC
841 if (table == 0) {
842 /*
843 * No further transformation.
844 * The final mapping step includes both restriction to
845 * the range [0..1] and conversion to fracs.
846 */
847 #define EABC(i)\
848 cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.fracs.values, tabc[i])
849 pconc[0] = EABC(0);
850 pconc[1] = EABC(1);
851 pconc[2] = EABC(2);
852 #undef EABC
853 return 3;
854 } else {
855 /*
856 * Use the RenderTable.
857 */
858 int m = pcrd->RenderTable.lookup.m;
859
860 #define RT_LOOKUP(j, i) pcrd->caches.RenderTableT[j].fracs.values[i]
861 #ifdef CIE_RENDER_TABLE_INTERPOLATE
862
863 /*
864 * The final mapping step includes restriction to the
865 * ranges [0..dims[c]] as ints with interpolation bits.
866 */
867 fixed rfix[3];
868 const int s = _fixed_shift - _cie_interpolate_bits;
869
870 #define EABC(i)\
871 cie_interpolate_fracs(pcrd->caches.EncodeABC[i].fixeds.ints.values, tabc[i])
872 #define FABC(i, s)\
873 ((s) > 0) ? (EABC(i) << (s)) : (EABC(i) >> -(s))
874 rfix[0] = FABC(0, s);
875 rfix[1] = FABC(1, s);
876 rfix[2] = FABC(2, s);
877 #undef FABC
878 #undef EABC
879 if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%g,%g,%g\n",
880 cie_cached2float(vec3.u), cie_cached2float(vec3.v),
881 cie_cached2float(vec3.w), fixed2float(rfix[0]),
882 fixed2float(rfix[1]), fixed2float(rfix[2]));
883 gx_color_interpolate_linear(rfix, &pcrd->RenderTable.lookup,
884 pconc);
885 if_debug3('c', "[c] interpolated => %g,%g,%g\n",
886 frac2float(pconc[0]), frac2float(pconc[1]),
887 frac2float(pconc[2]));
888 if (!pcrd->caches.RenderTableT_is_identity) {
889 /* Map the interpolated values. */
890 #define frac2cache_index(v) frac2bits(v, gx_cie_log2_cache_size)
891 pconc[0] = RT_LOOKUP(0, frac2cache_index(pconc[0]));
892 pconc[1] = RT_LOOKUP(1, frac2cache_index(pconc[1]));
893 pconc[2] = RT_LOOKUP(2, frac2cache_index(pconc[2]));
894 if (m > 3)
895 pconc[3] = RT_LOOKUP(3, frac2cache_index(pconc[3]));
896 #undef frac2cache_index
897 }
898
899 #else /* !CIE_RENDER_TABLE_INTERPOLATE */
900
901 /*
902 * The final mapping step includes restriction to the ranges
903 * [0..dims[c]], plus scaling of the indices in the strings.
904 */
905 #define RI(i)\
906 pcrd->caches.EncodeABC[i].ints.values[tabc[i] >> _cie_interpolate_bits]
907 int ia = RI(0);
908 int ib = RI(1); /* pre-multiplied by m * NC */
909 int ic = RI(2); /* pre-multiplied by m */
910 const byte *prtc = table[ia].data + ib + ic;
911
912 /* (*pcrd->RenderTable.T)(prtc, m, pcrd, pconc); */
913
914 if_debug6('c', "[c]ABC=%g,%g,%g => iabc=%d,%d,%d\n",
915 cie_cached2float(vec3.u), cie_cached2float(vec3.v),
916 cie_cached2float(vec3.w), ia, ib, ic);
917 if (pcrd->caches.RenderTableT_is_identity) {
918 pconc[0] = byte2frac(prtc[0]);
919 pconc[1] = byte2frac(prtc[1]);
920 pconc[2] = byte2frac(prtc[2]);
921 if (m > 3)
922 pconc[3] = byte2frac(prtc[3]);
923 } else {
924 #if gx_cie_log2_cache_size == 8
925 # define byte2cache_index(b) (b)
926 #else
927 # if gx_cie_log2_cache_size > 8
928 # define byte2cache_index(b)\
929 ( ((b) << (gx_cie_log2_cache_size - 8)) +\
930 ((b) >> (16 - gx_cie_log2_cache_size)) )
931 # else /* < 8 */
932 # define byte2cache_index(b) ((b) >> (8 - gx_cie_log2_cache_size))
933 # endif
934 #endif
935 pconc[0] = RT_LOOKUP(0, byte2cache_index(prtc[0]));
936 pconc[1] = RT_LOOKUP(1, byte2cache_index(prtc[1]));
937 pconc[2] = RT_LOOKUP(2, byte2cache_index(prtc[2]));
938 if (m > 3)
939 pconc[3] = RT_LOOKUP(3, byte2cache_index(prtc[3]));
940 #undef byte2cache_index
941 }
942
943 #endif /* !CIE_RENDER_TABLE_INTERPOLATE */
944 #undef RI
945 #undef RT_LOOKUP
946 return m;
947 }
948 }
949
950 /*
951 * Finish "remapping" a CIEBased color only to the XYZ intermediate values.
952 * Note that we can't currently represent values outside the range [0..1]:
953 * this is a bug that we will have to address someday.
954 */
955 static frac
float2frac_clamp(floatp x)956 float2frac_clamp(floatp x)
957 {
958 return float2frac((x <= 0 ? 0 : x >= 1 ? 1 : x));
959 }
960 int
gx_cie_xyz_remap_finish(cie_cached_vector3 vec3,frac * pconc,const gs_imager_state * pis,const gs_color_space * pcs)961 gx_cie_xyz_remap_finish(cie_cached_vector3 vec3, frac * pconc,
962 const gs_imager_state * pis,
963 const gs_color_space *pcs)
964 {
965 const gx_cie_joint_caches *pjc = pis->cie_joint_caches;
966
967 /*
968 * All the steps through DecodeABC/MatrixABC have been applied, i.e.,
969 * vec3 is LMN values. Just apply DecodeLMN/MatrixLMN.
970 */
971 if (!pjc->skipDecodeLMN)
972 cie_lookup_map3(&vec3 /* LMN => XYZ */, &pjc->DecodeLMN,
973 "Decode/MatrixLMN");
974
975 pconc[0] = float2frac_clamp(cie_cached2float(vec3.u));
976 pconc[1] = float2frac_clamp(cie_cached2float(vec3.v));
977 pconc[2] = float2frac_clamp(cie_cached2float(vec3.w));
978 return 3;
979 }
980
981 /* Look up 3 values in a cache, with cached post-multiplication. */
982 static void
cie_lookup_mult3(cie_cached_vector3 * pvec,const gx_cie_vector_cache3_t * pc)983 cie_lookup_mult3(cie_cached_vector3 * pvec,
984 const gx_cie_vector_cache3_t * pc)
985 {
986 #ifdef CIE_CACHE_INTERPOLATE
987 cie_cached_value u, v, w;
988
989 #ifdef CIE_CACHE_USE_FIXED
990 # define LOOKUP_INTERPOLATE_BETWEEN(v0, v1, i)\
991 cie_interpolate_between(v0, v1, i)
992 #else
993 float ftemp;
994
995 # define LOOKUP_INTERPOLATE_BETWEEN(v0, v1, i)\
996 ((v0) + ((v1) - (v0)) *\
997 ((ftemp = float_rshift(i, _cie_interpolate_bits)), ftemp - (int)ftemp))
998 #endif
999
1000 /*
1001 * Defining a macro for the entire component calculation would
1002 * minimize source code, but it would make the result impossible
1003 * to trace or debug. We use smaller macros instead, and run
1004 * the usual risks associated with having 3 copies of the code.
1005 * Note that pvec and pc are free variables in these macros.
1006 */
1007
1008 #define I_IN_RANGE(j, n)\
1009 (pvec->n >= pc->interpolation_ranges[j].rmin &&\
1010 pvec->n < pc->interpolation_ranges[j].rmax)
1011 #define I_INDEX(j, n)\
1012 LOOKUP_INDEX(pvec->n, &pc->caches[j], _cie_interpolate_bits)
1013 #define I_ENTRY(i, j)\
1014 &pc->caches[j].vecs.values[(int)cie_cached_rshift(i, _cie_interpolate_bits)]
1015 #define I_ENTRY1(i, p)\
1016 (i >= (gx_cie_cache_size - 1) << _cie_interpolate_bits ? p : p + 1)
1017
1018 if (I_IN_RANGE(0, u)) {
1019 cie_cached_value i = I_INDEX(0, u);
1020 const cie_cached_vector3 *p = I_ENTRY(i, 0);
1021 const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
1022
1023 if_debug0('C', "[c]Interpolating u.\n");
1024 u = LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
1025 v = LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
1026 w = LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
1027 } else {
1028 const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->u, &pc->caches[0]);
1029
1030 if_debug0('C', "[c]Not interpolating u.\n");
1031 u = p->u, v = p->v, w = p->w;
1032 }
1033
1034 if (I_IN_RANGE(1, v)) {
1035 cie_cached_value i = I_INDEX(1, v);
1036 const cie_cached_vector3 *p = I_ENTRY(i, 1);
1037 const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
1038
1039 if_debug0('C', "[c]Interpolating v.\n");
1040 u += LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
1041 v += LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
1042 w += LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
1043 } else {
1044 const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->v, &pc->caches[1]);
1045
1046 if_debug0('C', "[c]Not interpolating v.\n");
1047 u += p->u, v += p->v, w += p->w;
1048 }
1049
1050 if (I_IN_RANGE(2, w)) {
1051 cie_cached_value i = I_INDEX(2, w);
1052 const cie_cached_vector3 *p = I_ENTRY(i, 2);
1053 const cie_cached_vector3 *p1 = I_ENTRY1(i, p);
1054
1055 if_debug0('C', "[c]Interpolating w.\n");
1056 u += LOOKUP_INTERPOLATE_BETWEEN(p->u, p1->u, i);
1057 v += LOOKUP_INTERPOLATE_BETWEEN(p->v, p1->v, i);
1058 w += LOOKUP_INTERPOLATE_BETWEEN(p->w, p1->w, i);
1059 } else {
1060 const cie_cached_vector3 *p = LOOKUP_ENTRY(pvec->w, &pc->caches[2]);
1061
1062 if_debug0('C', "[c]Not interpolating w.\n");
1063 u += p->u, v += p->v, w += p->w;
1064 }
1065
1066 #undef I_IN_RANGE
1067 #undef I_INDEX
1068 #undef I_ENTRY
1069 #undef I_ENTRY1
1070
1071 pvec->u = u;
1072 pvec->v = v;
1073 pvec->w = w;
1074
1075 #else /* no interpolation */
1076
1077 const cie_cached_vector3 *pu = LOOKUP_ENTRY(pvec->u, &pc->caches[0]);
1078 const cie_cached_vector3 *pv = LOOKUP_ENTRY(pvec->v, &pc->caches[1]);
1079 const cie_cached_vector3 *pw = LOOKUP_ENTRY(pvec->w, &pc->caches[2]);
1080
1081 if_debug0('C', "[c]Not interpolating.\n");
1082
1083 pvec->u = pu->u + pv->u + pw->u;
1084 pvec->v = pu->v + pv->v + pw->v;
1085 pvec->w = pu->w + pv->w + pw->w;
1086
1087 #endif /* (no) interpolation */
1088 }
1089