Coverage Report

Created: 2025-06-24 07:01

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