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