Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pcl/pcl/pccsbase.c
Line
Count
Source
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
/* pccsbase.h - base color space code for PCL 5c */
18
19
#include "gx.h"
20
#include "math_.h"
21
#include "gstypes.h"
22
#include "gsmatrix.h"
23
#include "gsstruct.h"
24
#include "gsrefct.h"
25
#include "gscspace.h"
26
#include "gscolor2.h"
27
#include "gscie.h"
28
#include "pcmtx3.h"
29
#include "pccsbase.h"
30
#include "pcstate.h"
31
32
/* for RC structures */
33
gs_private_st_simple(st_cs_base_t, pcl_cs_base_t, "pcl base color space");
34
35
36
/*
37
 * Handle min/max values for device-independent color spaces.
38
 *
39
 * Examples in HP's "PCL 5 Color Technical Reference Manual"  are unclear
40
 * about the interpretation of minimum/maximum value for components for the
41
 * device independent color spaces. It is clear that the "raw" input range
42
 * for these parameters is always [ 0, 255 ], but how this range is mapped
43
 * is not fully obvious.
44
 *
45
 * Empirical observations with both the CIE L*a*b* and the luminance-
46
 * chrominance color space do little to clear up this confusion. In the range
47
 * [ 0, 255 ] (as suggested in the "PCL 5 Color Technical Reference Manual"),
48
 * integer arithmetic overflow seems to occur at some points, leading to
49
 * rather curious color progressions (a moderate brown changes abruptly to
50
 * a dark green at the half-intensity point of a "gray" scale).
51
 *
52
 * Side Note:
53
 *      Device dependent color spaces in PCL 5c are not provided with
54
 *      ranges, but are assigned white and black points. The interpretation of
55
 *      these points is clear: specify the white point to get the maximum
56
 *      intensity value for all components on the device, and the black point
57
 *      to achieve the minimum value (for printers these are reasonably white
58
 *      and black; most screens are adjusted to achieve the same result,
59
 *      though there is no strict requirement for this to be the case).
60
 *      Values within this range [black_point, white_point] are mapped
61
 *      by the obvious linear transformation; values outside of the range
62
 *      are clamped to the nearest boundary point.
63
 *
64
 *      Two items of note for device dependent color spaces:
65
 *
66
 *          a CMY color space is just an RGB color space with the white and
67
 *          black points inverted.
68
 *
69
 *          For a given value of bits-per-primary, it is quite possible to
70
 *          set the white and black points so that one or both may not be
71
 *          achievable
72
 *
73
 *      In this implementation, the white and black points of the device-
74
 *      specific color spaces are handled in the initial "normalization"
75
 *      step, before colors are entered into the palette.
76
 *
77
 * To do something sensible for device independent color space ranges, it is
78
 * ncessary to ignore HP's implementation and ask what applications might
79
 * reasonably want to do with the range parameters. The answer depends on the
80
 * particular color space:
81
 *
82
 * a.  For colorimetric RGB spaces, the reasonable assumption is that the
83
 *     parameters correspond to the range of the input primaries, from
84
 *     minimal 0 to full intensity. Furthermore, the white point corresponds
85
 *     to the full intensity for each primary, the black point to minimum
86
 *     intensity.
87
 *
88
 *     The difficulty with this interpretation is that it renders the range
89
 *     parameters meaningless. PCL requires input data for device-independent
90
 *     color spaces to be in the range [0, 255], with 0 ==> minimum value and
91
 *     255 ==> maximum value. Combined with the assumption above, this will
92
 *     always map the "raw" input values {0, 0, 0} and {255, 255, 255} to
93
 *     the black and white points, respectively.
94
 *
95
 *     To avoid making the range parameters completely meaningless in this
96
 *     case, we will actually use a different interpretation. The modification
97
 *     continues to map the raw input values such that 0 ==> minimum value
98
 *     and 255 ==> maximum value, but the black and white points continue
99
 *     to be {0, 0, 0} and {1, 1, 1}. Values outside of this range are
100
 *     clipped.
101
 *
102
 *     To the extent that we can determine, this interpretation bears some
103
 *     relationship to that used by HP.
104
 *
105
 * b.  For the CIE L*a*b* space, the interpretation of the value of each
106
 *     component is fixed by standards, so the ranges specified in the
107
 *     Configure Image Data command can only be interpreted as indicating
108
 *     which set of values the "raw" input range [0, 255] should be mapped
109
 *     to (0 ==> min_value, 255 ==> max value)
110
 *
111
 * c.  For consistency it is necessary to handle the range parameters for
112
 *     luminance-chrominance in the same manner as they are handled for the
113
 *     colorimetric RGB case. This approach makes even less sense in this
114
 *     case than for the colorimetric RGB case, as the region of input space
115
 *     that corresponds to real colors for luminance-chrominance spaces is
116
 *     not a cube (i.e.: it is possible for each of the components to be
117
 *     in a reasonable range, but for the combination to yield primary
118
 *     component values < 0 or > 1). There is not much choice about this
119
 *     arrangement, however, because a luminance-chrominance space can be
120
 *     set up to directly mimic a colorimetric RGB space by setting the
121
 *     transformation between the two to the identity transformation.
122
 *
123
 * For all of these range mappings, the initial step is to map the "raw" input
124
 * range to [min_val, max_val], and incorporate the effect of the lookup
125
 * table for the particular color space (if any). This is accomplished by the
126
 * following macro. Note that the initial normalization step has already
127
 * converted the "raw" input range to [0, 1] (the same range as is used by
128
 * device-dependent color spaces).
129
 */
130
131
#define convert_val(val, min_val, range, plktbl)            \
132
0
    BEGIN                                                   \
133
0
    if ((plktbl) != 0)                                      \
134
0
        val = (double)(plktbl)[(int)(255 * val)] / 255.0;   \
135
0
    val = min_val + val * range;                            \
136
0
    END
137
138
/*
139
 * Default Configure Image Data information for the various color spaces.
140
 *
141
 * The black and white points for device dependent color spaces are not included
142
 * here as those are handled via palette value normalization, not via the color
143
 * space. Since the black and white points are the only parameters for the
144
 * device-specific color spaces, there is no default information here for them
145
 * at all.
146
 *
147
 * Other color spaces have up to three sets of default information:
148
 *
149
 *     default parameter ranges (all device-independent color spaces)
150
 *
151
 *     the default chromaticity of the primaries (colorimetric RGB and
152
 *         luminance-chrominance spaces)
153
 *
154
 *     the default conversion between the color components and the primaries
155
 *         for which chromaticities have been provided (only luminance-
156
 *         chrominance space)
157
 */
158
static const pcl_cid_minmax_t cielab_range_default = {
159
    {{0.0f, 100.0f}, {-100.0f, 100.0f}, {-100.0f, 100.0f}}
160
};
161
162
static const pcl_cid_minmax_t colmet_range_default = {
163
    {{0.0f, 1.0f}, {0.0f, 1.0f}, {0.0f, 1.0f}}
164
};
165
166
static const pcl_cid_minmax_t lumchrom_range_default = {
167
    {{0.0f, 1.0f}, {-0.89f, 0.89f}, {-0.70f, 0.70f}}
168
};
169
170
static const pcl_cid_col_common_t chroma_default = {
171
    {
172
     {0.640f, 0.340f},          /* "red" primary chromaticity */
173
     {0.310f, 0.595f},          /* "green" primary chromaticity */
174
     {0.155f, 0.070f},          /* "blue" chromaticity */
175
     {0.313f, 0.329f}           /* white chromaticity */
176
     },
177
    {{1, 1.0f}, {1, 1.0f}, {1, 1.0f}}
178
};
179
180
static const float lumchrom_xform_default[9] = {
181
    0.30f, 0.59f, 0.11f, -0.30f, -0.59f, 0.89f, 0.70f, -0.59f, -0.11f
182
};
183
184
/* structure of default values for all color spaces */
185
static const struct
186
{
187
    const pcl_cid_minmax_t *pminmax;
188
    const pcl_cid_col_common_t *pchroma;
189
    const float *pxform;
190
} cid_data_default[(int)pcl_cspace_num] = {
191
    {0, 0, 0},                   /* pcl_cspace_RGB */
192
    {0, 0, 0},                   /* pcl_cspace_CMY */
193
    {&colmet_range_default, &chroma_default, 0}, /* pcl_cspace_Colorimetric */
194
    {&cielab_range_default, 0, 0},       /* pcl_cspace_CIELab */
195
    {&lumchrom_range_default, &chroma_default, lumchrom_xform_default} /* pcl_cspace_LumChrom */
196
};
197
198
/*
199
 * Code for constructing/modifying the client data structure of PCL base
200
 * color spaces.
201
 */
202
203
/*
204
 * Set the range parameters for a color space.
205
 */
206
static void
207
set_client_info_range(pcl_cs_client_data_t * pdata,
208
                      const pcl_cid_minmax_t * pminmax)
209
0
{
210
0
    int i;
211
212
0
    for (i = 0; i < 3; i++) {
213
0
        pdata->min_val[i] = pminmax->val_range[i].min_val;
214
0
        pdata->range[i] = pminmax->val_range[i].max_val
215
0
            - pminmax->val_range[i].min_val;
216
0
    }
217
0
}
218
219
/*
220
 * Set the gamma/gain information for a color space.
221
 */
222
static void
223
set_client_info_chroma(pcl_cs_client_data_t * pdata,
224
                       const pcl_cid_col_common_t * pchroma)
225
0
{
226
0
    int i;
227
228
0
    for (i = 0; i < 3; i++) {
229
0
        double gamma = pchroma->nonlin[i].gamma;
230
231
0
        double gain = pchroma->nonlin[i].gain;
232
233
0
        pdata->inv_gamma[i] = (gamma == 0.0 ? 1.0 : 1.0 / gamma);
234
0
        pdata->inv_gain[i] = (gain == 0.0 ? 1.0 : 1.0 / gain);
235
0
    }
236
0
}
237
238
/*
239
 * Build the client information structure for a color space.
240
 */
241
static void
242
build_client_data(pcl_cs_client_data_t * pdata,
243
                  const pcl_cid_data_t * pcid, gs_memory_t * pmem)
244
12.5k
{
245
12.5k
    pcl_cspace_type_t type = pcl_cid_get_cspace(pcid);
246
12.5k
    const pcl_cid_minmax_t *pminmax = cid_data_default[type].pminmax;
247
12.5k
    const pcl_cid_col_common_t *pchroma = cid_data_default[type].pchroma;
248
249
    /* see if we have long-form information for device-independent spaces */
250
12.5k
    if (pcid->len > 6) {
251
0
        if (type == pcl_cspace_Colorimetric) {
252
0
            pminmax = &(pcid->u.col.minmax);
253
0
            pchroma = &(pcid->u.col.colmet);
254
0
        } else if (type == pcl_cspace_CIELab)
255
0
            pminmax = &(pcid->u.lab.minmax);
256
0
        else if (type == pcl_cspace_LumChrom) {
257
0
            pminmax = &(pcid->u.lum.minmax);
258
0
            pchroma = &(pcid->u.col.colmet);
259
0
        }
260
0
    }
261
262
    /* set the range and gamma/gain parameters, as required */
263
12.5k
    if (pminmax != 0)
264
0
        set_client_info_range(pdata, pminmax);
265
12.5k
    if (pchroma != 0)
266
0
        set_client_info_chroma(pdata, pchroma);
267
12.5k
}
268
269
/*
270
 * Init a client data structure from an existing client data structure.
271
 */
272
static void
273
init_client_data_from(pcl_cs_client_data_t * pnew,
274
                      const pcl_cs_client_data_t * pfrom)
275
0
{
276
0
    *pnew = *pfrom;
277
0
    pcl_lookup_tbl_init_from(pnew->plktbl1, pfrom->plktbl1);
278
0
    pcl_lookup_tbl_init_from(pnew->plktbl2, pfrom->plktbl2);
279
0
}
280
281
/*
282
 * Update the lookup table information in a PCL base color space.
283
 */
284
static void
285
update_lookup_tbls(pcl_cs_client_data_t * pdata,
286
                   pcl_lookup_tbl_t * plktbl1, pcl_lookup_tbl_t * plktbl2)
287
0
{
288
0
    pcl_lookup_tbl_copy_from(pdata->plktbl1, plktbl1);
289
0
    pcl_lookup_tbl_copy_from(pdata->plktbl2, plktbl2);
290
0
}
291
292
/*
293
 * Free a client data structure. This releases the lookup tables, if they
294
 * are present.
295
 */
296
#define free_lookup_tbls(pdata)               \
297
    update_lookup_tbls((pdata), NULL, NULL)
298
299
/*
300
 * The colorimetric case.
301
 *
302
 * The information provided with this color space consists of the CIE (x, y)
303
 * chromaticities of the three primaries, and the white point. In order to
304
 * derive a color space from this information, three additional assumptions
305
 * are required:
306
 *
307
 *     the intensity (Y value) or the white point is 1.0 (identical to the
308
 *         convention used by PostScript)
309
 *
310
 *     the white point is achieved by setting each of the primaries to its
311
 *         maximum value (1.0)
312
 *
313
 *     the black point (in this case, { 0, 0, 0 }, since it is not specified)
314
 *         is achieved by setting each of the primaries to its minimum value
315
 *         (0.0)
316
 *
317
 * Relaxing the former assumption would only modify the mapping provided by the
318
 * color space by a multiplicative constant. The assumption is also reasonable
319
 * for a printing device: even under the strongest reasonable assumptions, the
320
 * actual intensity achieved by printed output is determined by the intensity
321
 * of the illuminant and the reflectivity of the paper, neither one of which is
322
 * known to the color space. Hence, the value of Y selected is arbitrary (so
323
 * long as it is > 0), and using 1.0 simplifies the calculations a bit.
324
 *
325
 * The second and third assumptions are standard and, in fact, define the
326
 * concept of "white point" and "black point" for the purposes of this color
327
 * space. These assumptions are, however, often either poorly documented or
328
 * not documented at all. At least the former is also not particularly intuitive:
329
 * in an additive color arrangement (such as a display), the color achieved by
330
 * full intensity on each of the primaries may be colored, and its color need
331
 * not correspond to any of the standard "color temperatures" usually used
332
 * as white points.
333
 *
334
 * The assumption is, unfortunately, critical to allow derivation of the
335
 * transformation from the primaries provided to the XYZ color space. If we
336
 * let {Xr, Yr, Zr}, {Xg, Yg, Z,}, and {Xb, Yb, Zb} denote the XYZ coordinates
337
 * of the red, green, and blue primaries, respectively, then the desired
338
 * conversion is:
339
 *
340
 *                              -          -
341
 *     {X, Y, Z} = {R, G, B} * | Xr  Yr  Zr |
342
 *                             | Xg  Yg  Zg |
343
 *                             | Xb  Yb  Zb |
344
 *                              -          -
345
 *
346
 * The chromaticities of the primaries and the white point are derived by
347
 * adjusting the X, Y, and Z coordinates such that x + y + z = 1. Hence:
348
 *
349
 *     x = X / (X + Y + Z)
350
 *
351
 *     y = Y / (X + Y + Z)
352
 *
353
 *     z = Z / (X + Y + Z)
354
 *
355
 * Note that these relationships preserve the ratios between components:
356
 *
357
 *     x / y = X / Y
358
 *
359
 * Hence:
360
 *
361
 *    X = (x / y) * Y
362
 *
363
 *    Z = ((1 - (x + y)) / y) * Y
364
 *
365
 * Using this relationship, the conversion equation above can be restated as:
366
 *
367
 *                            -                                -
368
 *   {X, Y, Z} = {R, G, B} * | Yr * xr / yr   Yr   Yr * zr / yr |
369
 *                           | Yg * xg / yg   Yg   Yg * zg / yg |
370
 *                           | Yb * xb / yb   Yb   Yb * zb / yb |
371
 *                            -                                -
372
 *
373
 * Where zr = 1.0 - (xr + yr), zg = 1.0 - (xg + yg), and zb = 1.0 - (xb + yb).
374
 *
375
 * As discussed above, in order to make the range parameters of the long form
376
 * Configure Image Data command meaningful, we must use the convention that
377
 * full intensity for all components is {1, 1, 1}, and no intensity is
378
 * {0, 0, 0}. Because the transformation is linear, the latter point provides
379
 * no information, but the former establishes the following relationship.
380
 *
381
 *                               -                                -
382
 *   {Xw, Yw, Zw} = {1, 1, 1} * | Yr * xr / yr   Yr   Yr * zr / yr |
383
 *                              | Yg * xg / yg   Yg   Yg * zg / yg |
384
 *                              | Yb * xb / yb   Yb   Yb * zb / yb |
385
 *                               -                                -
386
 *
387
 * This is equivalent to:
388
 *
389
 *                                  -                     -
390
 *   {Xw, Yw, Zw} = {Yr, Yg, Yb} * | xr / yr  1.0  zr / yr |
391
 *                                 | xg / yg  1.0  zg / yg |
392
 *                                 | xb / yb  1.0  zb / yb |
393
 *                                  -                     -
394
 *
395
 *                = {Yr, Yg, Yb} * mtx
396
 *
397
 * Using the assumption that Yw = 1.0, we have Xw = xw / yw and Zw = zw / yw
398
 * (zw = 1 - (xw + yw)), so:
399
 *
400
 *    {Yr, Yg, Yb} = {xw / yw, 1.0, zw / yw} * mtx^-1
401
 *
402
 * Since Yr, Yg, and Yb are now known, it is possible to generate the
403
 * RGB ==> XYZ transformation.
404
 *
405
 * HP also provides for a gamma and gain parameter to be applied to each
406
 * primary, though it does not specify exactly what these mean. The
407
 * interpretation provided below (in the EncodeABC procedures) seems to
408
 * correspond with the observed phenomena, though it is not clear that this
409
 * interpretation is correct. Note also that the interpretation of gamma
410
 * requires that component intensities be positive.
411
 */
412
413
/*
414
 * The EncodeABC procedures for colorimetric RGB spaces. All three procedures
415
 * are the same, except for the array index used.
416
 */
417
#define colmet_DecodeABC_proc(procname, indx)                               \
418
      static float                                                         \
419
    procname(                                                               \
420
        double                          val,                                \
421
        const gs_cie_abc *              pabc                                \
422
    )                                                                       \
423
0
    {                                                                       \
424
0
        const pcl_cs_client_data_t *    pdata =                             \
425
0
                                             (const pcl_cs_client_data_t *) \
426
0
                                             pabc->common.client_data;      \
427
0
        double                          inv_gamma = pdata->inv_gamma[indx]; \
428
0
        double                          inv_gain = pdata->inv_gain[indx];   \
429
0
                                                                            \
430
0
        convert_val( val,                                                   \
431
0
                     pdata->min_val[indx],                                  \
432
0
                     pdata->range[indx],                                    \
433
0
                     pcl_lookup_tbl_get_tbl(pdata->plktbl1, indx)           \
434
0
                     );                                                     \
435
0
        if (val < 0.0)                                                      \
436
0
            val = 0.0;                                                      \
437
0
        if (inv_gamma != 1.0)                                               \
438
0
            val = pow(val, inv_gamma);                                      \
439
0
        if (inv_gain != 1.0)                                                \
440
0
            val = 1.0 - (1.0 - val) * inv_gain;                            \
441
0
        return val;                                                         \
442
0
    }
Unexecuted instantiation: pccsbase.c:colmet_DecodeABC_0
Unexecuted instantiation: pccsbase.c:colmet_DecodeABC_1
Unexecuted instantiation: pccsbase.c:colmet_DecodeABC_2
443
444
colmet_DecodeABC_proc(colmet_DecodeABC_0, 0)
445
    colmet_DecodeABC_proc(colmet_DecodeABC_1, 1)
446
    colmet_DecodeABC_proc(colmet_DecodeABC_2, 2)
447
448
     static const gs_cie_abc_proc3 colmet_DecodeABC = {
449
         {colmet_DecodeABC_0, colmet_DecodeABC_1, colmet_DecodeABC_2}
450
     };
451
452
/*
453
 * Build the matrix to convert a calibrated RGB color space to XYZ space; see
454
 * the discussion above for the reasoning behind this derivation.
455
 *
456
 * Returns 0 on success, < 0 in the event of an error.
457
 */
458
static int
459
build_colmet_conv_mtx(const pcl_cid_col_common_t * pdata,
460
                      pcl_vec3_t * pwhite_pt, pcl_mtx3_t * pmtx)
461
0
{
462
0
    pcl_vec3_t tmp_vec;
463
0
    pcl_mtx3_t inv_mtx;
464
0
    const float *pf = (float *)pdata->chroma;
465
0
    int i, code;
466
467
0
    for (i = 0; i < 3; i++) {
468
0
        double x = pf[2 * i];
469
0
        double y = pf[2 * i + 1];
470
471
0
        pmtx->a[3 * i] = x / y;
472
0
        pmtx->a[3 * i + 1] = 1.0;
473
0
        pmtx->a[3 * i + 2] = (1.0 - x - y) / y;
474
0
    }
475
0
    if ((code = pcl_mtx3_invert(pmtx, &inv_mtx)) < 0)
476
0
        return code;
477
478
0
    pwhite_pt->vc.v1 = pdata->chroma[3].x / pdata->chroma[3].y;
479
0
    pwhite_pt->vc.v2 = 1.0;
480
0
    pwhite_pt->vc.v3 = (1.0 - pdata->chroma[3].x - pdata->chroma[3].y)
481
0
        / pdata->chroma[3].y;
482
0
    pcl_vec3_xform(pwhite_pt, &tmp_vec, &inv_mtx);
483
484
0
    for (i = 0; i < 9; i++)
485
0
        pmtx->a[i] *= tmp_vec.va[i / 3];
486
0
    return 0;
487
0
}
488
489
/*
490
 * Finish the creation of a colorimetric RGB color space.
491
 */
492
static int
493
finish_colmet_cspace(gs_color_space * pcspace, const pcl_cid_data_t * pcid)
494
0
{
495
0
    pcl_mtx3_t mtxABC;
496
0
    pcl_vec3_t white_pt;
497
0
    const pcl_cid_col_common_t *pcoldata;
498
0
    int code = 0;
499
500
0
    if (pcid->len == 6)
501
0
        pcoldata = cid_data_default[pcl_cspace_Colorimetric].pchroma;
502
0
    else
503
0
        pcoldata = &(pcid->u.col.colmet);
504
0
    if ((code = build_colmet_conv_mtx(pcoldata, &white_pt, &mtxABC)) < 0)
505
0
        return code;
506
507
    /* RangeABC has the default value */
508
0
    *(gs_cie_abc_DecodeABC(pcspace)) = colmet_DecodeABC;
509
0
    pcl_mtx3_convert_to_gs(&mtxABC, gs_cie_abc_MatrixABC(pcspace));
510
511
0
    gs_cie_RangeLMN(pcspace)->ranges[0].rmin = 0;
512
0
    gs_cie_RangeLMN(pcspace)->ranges[0].rmax = white_pt.va[0];
513
0
    gs_cie_RangeLMN(pcspace)->ranges[1].rmin = 0;
514
0
    gs_cie_RangeLMN(pcspace)->ranges[1].rmax = white_pt.va[1];
515
0
    gs_cie_RangeLMN(pcspace)->ranges[2].rmin = 0;
516
0
    gs_cie_RangeLMN(pcspace)->ranges[2].rmax = white_pt.va[2];
517
    /* DecodeLMN and MatrixLMN have the default values */
518
519
0
    pcl_vec3_to_gs_vector3(gs_cie_WhitePoint(pcspace), white_pt);
520
    /* BlackPoint has the default value */
521
522
0
    return 0;
523
0
}
524
525
/*
526
 * The CIE L*a*b* case.
527
 *
528
 * The mapping from L*a*b* space to XYZ space is fairly simple over most of
529
 * its range, but becomes complicated in the range of dark grays because the
530
 * dominant cubic/cube root relationship changes to linear in this region.
531
 *
532
 * Let:
533
 *
534
 *    f(h) = (h > (6/29)^3 ? h^(1/3) : (29^2 / (3 * 6^2))  * h + 4/29)
535
 *
536
 *    g(h) = (h > (6/29)^3 ? 116 * h^(1/3) - 16 : (29/3)^3 * h)
537
 *
538
 * Note that, for h = (6/29)^3, the two different expressions for g(h) yield
539
 * the same result:
540
 *
541
 *    116 * h^(1.3) - 16 = (116 * 6 / 29) - 16 = 24 - 16 = 8, and
542
 *
543
 *    (29/3)^3 * h = (29 * 6 / 3 * 29)^3 = 2^3 = 8
544
 *
545
 * Since each part of g is monotonically increasing, g(h) is itself
546
 * monotonically increasing, and therefore invertible. Similarly, for
547
 * this value of h both expressions for f yield the same result:
548
 *
549
 *    h^(1/3) = 6/29, and
550
 *
551
 *    (29^2 / (3 * 6^2)) * h + 4/29 = (29^2 * 6^3) / (29^3 * 3 * 6^2) + 4/29
552
 *
553
 *                                  = 2/29 + 4/29 = 6/29
554
 *
555
 * Again, the individual parts of f are monotonically increasing, hence f is
556
 * monotonically increasing and therefore invertible.
557
 *
558
 * Let { Xw, 1.0, Yw } be the desired white-point. Then, the conversion from
559
 * XYZ ==> L*a*b* is given by:
560
 *
561
 *    L* = g(Y)
562
 *
563
 *    a* = 500 * (f(X/Xw) - f(Y))
564
 *
565
 *    b* = 200 * (f(Y) - f(Z/Zw))
566
 *
567
 * Inverting this relationship, we find that:
568
 *
569
 *    Y = g^-1(L*)
570
 *
571
 *    X = Xw * f^-1(a* / 500 + f(Y)) = Xw * f^-1(a* / 500 + f(g^-1(L*)))
572
 *
573
 *    Z = Zw * f^-1(b* / 200 + f(Y)) = Zw * f^-1(f(g^-1(L*)) - b* / 200)
574
 *
575
 * Before providing expressions for f^-1 and g^-1 (we know from the argument
576
 * above that these functions exist), we should note that the structure of the
577
 * PostScript CIE color spaces cannot deal directly with a relationship such as
578
 * described above, because all cross-component steps (operations that depend
579
 * more than one component) must be linear. It is possible, however, to convert
580
 * the relationship to the required form by extracting the value of Y in two
581
 * steps. This is accomplished by the following algorithm:
582
 *
583
 *    T1 = f(g^-1(L*))
584
 *    a1 = a* / 500
585
 *    b1 = b* / 200
586
 *                                       -         -
587
 *    { a2, T1, b2 } = { T1, a1, b1 } * | 1   1   1 |
588
 *                                      | 1   0   0 |
589
 *                                      | 0   0  -1 |
590
 *                                       -         -
591
 *    X = Xw * f^-1(a2)
592
 *    Y = f^-1(f(g^-1(L*)))
593
 *    Z = Zw * f^-1(b2)
594
 *
595
 * While the handling of the L* ==> Y conversion in this algorithm may seem a
596
 * bit overly complex, it is perfectly legitimate and, as shown below, results
597
 * in a very simple expression.
598
 *
599
 * To complete the algorithm, expressions for f^-1 and g^-1 must be provided.
600
 * These are derived directly from the forward expressions:
601
 *
602
 *    f^-1(h) = (h > 6/29 ? h^3 : (3 * 6^2) * (h - 4/29) / 29^2)
603
 *
604
 *    g^-1(h) = (h > 8 ? ((h + 16) / 116)^3 : (3/29)^3 * h)
605
 *
606
 * Note that because both f and g change representations at the same point,
607
 * there is only a single representation of f(g^-1(h)) required. Specifically,
608
 * if h > 8, then
609
 *
610
 *     g-1(h) = ((h + 16) / 116)^3 > (24 / 116)^3 = (6/29)^3
611
 *
612
 * so
613
 *
614
 *     f(g^-1(h)) = (g^-1(h))^(1/3) = (h + 16) / 116
615
 *
616
 * while if h <= 8
617
 *
618
 *     g-1(h) = (3/29)^3 * h <= (6/29)^3
619
 *
620
 * so
621
 *
622
 *     f(g-1(h)) = (29^2 / (3 * 6^2)) * g^-1(h) + 4/29
623
 *
624
 *               = ((29^2 * 3^3) / (29^3 * 3 * 6^2)) * h + 4/29
625
 *
626
 *               = h/116 + 16/116 = (h + 16) / 116
627
 *
628
 * This is the algorithm used below, with the Encode procedures also responsible
629
 * for implementing the color lookup tables (if present).
630
 */
631
632
/*
633
 * Unlike the other color spaces, the DecodeABC procedures for the CIE L*a*b*
634
 * color space have slightly different code for the different components. The
635
 * conv_code operand allows for this difference.
636
 */
637
#define lab_DecodeABC_proc(procname, indx, conv_code)                       \
638
      static float                                                         \
639
    procname(                                                               \
640
        double                          val,                                \
641
        const gs_cie_abc *              pabc                                \
642
    )                                                                       \
643
0
    {                                                                       \
644
0
        const pcl_cs_client_data_t *    pdata =                             \
645
0
                                              (const pcl_cs_client_data_t *)\
646
0
                                              pabc->common.client_data;     \
647
0
                                                                            \
648
0
        convert_val( val,                                                   \
649
0
                     pdata->min_val[indx],                                  \
650
0
                     pdata->range[indx],                                    \
651
0
                     pcl_lookup_tbl_get_tbl(pdata->plktbl1, indx)           \
652
0
                     );                                                     \
653
0
        conv_code;                                                          \
654
0
        return val;                                                         \
655
0
    }
Unexecuted instantiation: pccsbase.c:lab_DecodeABC_0
Unexecuted instantiation: pccsbase.c:lab_DecodeABC_1
Unexecuted instantiation: pccsbase.c:lab_DecodeABC_2
656
657
lab_DecodeABC_proc(lab_DecodeABC_0, 0, (val = (val + 16.0) / 116.0))
658
    lab_DecodeABC_proc(lab_DecodeABC_1, 1, (val /= 500))
659
    lab_DecodeABC_proc(lab_DecodeABC_2, 2, (val /= 200))
660
661
     static const gs_cie_abc_proc3 lab_DecodeABC = {
662
         {lab_DecodeABC_0, lab_DecodeABC_1, lab_DecodeABC_2}
663
     };
664
665
static const gs_matrix3 lab_MatrixABC = {
666
    {1, 1, 1}, {1, 0, 0}, {0, 0, -1},
667
    false
668
};
669
670
/*
671
 * The DecodeLMN procedures for CIE L*a*b* color spaces are all identical
672
 * except for the index. The explicit use of the white point is overkill,
673
 * since we know this will always be the D65 white point with Y normalized
674
 * to 1.0, but it guards against future variations.
675
 */
676
#define lab_DecodeLMN_proc(procname, indx)                          \
677
      static float                                                 \
678
    procname(                                                       \
679
        double                  val,                                \
680
        const gs_cie_common *   pcie                                \
681
    )                                                               \
682
0
    {                                                               \
683
0
        if (val > 6.0 / 29.0)                                       \
684
0
            val = val * val * val;                                  \
685
0
        else                                                        \
686
0
            val = 108 * (29.0 * val + 4) / (29.0 * 29.0 * 29.0);    \
687
0
        val *= (&(pcie->points.WhitePoint.u))[indx];                \
688
0
        return val;                                                 \
689
0
    }
Unexecuted instantiation: pccsbase.c:lab_DecodeLMN_0
Unexecuted instantiation: pccsbase.c:lab_DecodeLMN_1
Unexecuted instantiation: pccsbase.c:lab_DecodeLMN_2
690
691
lab_DecodeLMN_proc(lab_DecodeLMN_0, 0)
692
lab_DecodeLMN_proc(lab_DecodeLMN_1, 1)
693
lab_DecodeLMN_proc(lab_DecodeLMN_2, 2)
694
695
static const gs_cie_common_proc3 lab_DecodeLMN = {
696
    {lab_DecodeLMN_0, lab_DecodeLMN_1, lab_DecodeLMN_2}
697
};
698
699
static const gs_vector3 lab_WhitePoint = { .9504f, 1.0f, 1.0889f };
700
701
/*
702
 * Finish the creation of a CIE L*a*b* color space.
703
 */
704
static int
705
finish_lab_cspace(gs_color_space * pcspace, const pcl_cid_data_t * pcid)
706
0
{
707
    /* RangeABC has the default value */
708
0
    *(gs_cie_abc_DecodeABC(pcspace)) = lab_DecodeABC;
709
0
    *(gs_cie_abc_MatrixABC(pcspace)) = lab_MatrixABC;
710
711
    /* RangeLMN and MatrixLMN have the default values */
712
0
    *(gs_cie_DecodeLMN(pcspace)) = lab_DecodeLMN;
713
714
0
    gs_cie_WhitePoint(pcspace) = lab_WhitePoint;
715
    /* BlackPoint has the default value */
716
0
    return 0;
717
0
}
718
719
/*
720
 * The luminance-chrominance color space
721
 *
722
 * As HP would have it, the matrix provided in the long-form luminance-
723
 * chrominance color space specification maps the calibrated RGB coordinates
724
 * to the coordinates of the source space. This is, of course, the inverse
725
 * of the transform that is useful: from the desired color space to calibrated
726
 * RGB.
727
 *
728
 * The rest of the handling of luminance-chrominance spaces is similar to
729
 * that for colorimetric RGB spaces. Note, however, that in this case the
730
 * RangeLMN is the default value (primary components must be clipped to
731
 * [0, 1]), and the DecodeLMN function must verify that its output is still
732
 * in this range.
733
 *
734
 * As commented upon elsewhere, HP allows multiple lookup tables to be attached
735
 * to the same color space, but does not clarify what this should do. The
736
 * lookup table for the device dependent color spaces is not a problem; this
737
 * is implemented as a transfer function. The situation with device independent
738
 * color spaces is not as clear. The choice made here is to allow two device
739
 * independent lookup tables to be applied to the luminance-chrominance color
740
 * space: the luminance-chrominance lookup table and the colorimetric RGB
741
 * lookup table. This does not match HP's behavior, but the latter does not
742
 * make any sense, so this should not be an issue.
743
 */
744
745
/*
746
 * The DecodeABC procedures for luminance-chrominance color space are simple.
747
 */
748
#define lumchrom_DecodeABC_proc(procname, indx)                             \
749
      static float                                                         \
750
    procname(                                                               \
751
        double                          val,                                \
752
        const gs_cie_abc *              pabc                                \
753
    )                                                                       \
754
0
    {                                                                       \
755
0
        const pcl_cs_client_data_t *    pdata =                             \
756
0
                                             (const pcl_cs_client_data_t *) \
757
0
                                             pabc->common.client_data;      \
758
0
                                                                            \
759
0
        convert_val( val,                                                   \
760
0
                     pdata->min_val[indx],                                  \
761
0
                     pdata->range[indx],                                    \
762
0
                     pcl_lookup_tbl_get_tbl(pdata->plktbl1, indx)           \
763
0
                   );                                                       \
764
0
        return val;                                                         \
765
0
    }
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeABC_0
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeABC_1
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeABC_2
766
767
lumchrom_DecodeABC_proc(lumchrom_DecodeABC_0, 0)
768
lumchrom_DecodeABC_proc(lumchrom_DecodeABC_1, 1)
769
lumchrom_DecodeABC_proc(lumchrom_DecodeABC_2, 2)
770
771
static const gs_cie_abc_proc3 lumchrom_DecodeABC = {
772
    {lumchrom_DecodeABC_0, lumchrom_DecodeABC_1, lumchrom_DecodeABC_2}
773
};
774
775
/*
776
 * The DecodeLMN procedures for luminance-chrominance spaces are similar
777
 * to the colorimetric DecodeABC procedures. Since there is no Range* parameter
778
 * for the XYZ components, this procedure checks the range of its output.
779
 */
780
#define lumchrom_DecodeLMN_proc(procname, indx)                             \
781
      static float                                                         \
782
    procname(                                                               \
783
        double                          val,                                \
784
        const gs_cie_common *           pcie                                \
785
    )                                                                       \
786
0
    {                                                                       \
787
0
        const pcl_cs_client_data_t *    pdata =                             \
788
0
                                              (const pcl_cs_client_data_t *)\
789
0
                                              pcie->client_data;            \
790
0
        double                          inv_gamma = pdata->inv_gamma[indx]; \
791
0
        double                          inv_gain = pdata->inv_gain[indx];   \
792
0
                                                                            \
793
0
        convert_val( val,                                                   \
794
0
                     0.0,                                                   \
795
0
                     1.0,                                                   \
796
0
                     pcl_lookup_tbl_get_tbl(pdata->plktbl2, indx));         \
797
0
        if (inv_gamma != 1.0)                                               \
798
0
            val = pow(val, inv_gamma);                                      \
799
0
        if (inv_gain != 1.0)                                                \
800
0
            val = 1.0 - (1.0 - val) * inv_gain;                             \
801
0
        if (val < 0.0)                                                      \
802
0
            val = 0.0;                                                      \
803
0
        else if (val > 1.0)                                                 \
804
0
            val = 1.0;                                                      \
805
0
        return val;                                                         \
806
0
    }
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeLMN_0
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeLMN_1
Unexecuted instantiation: pccsbase.c:lumchrom_DecodeLMN_2
807
808
lumchrom_DecodeLMN_proc(lumchrom_DecodeLMN_0, 0)
809
lumchrom_DecodeLMN_proc(lumchrom_DecodeLMN_1, 1)
810
lumchrom_DecodeLMN_proc(lumchrom_DecodeLMN_2, 2)
811
812
static const gs_cie_common_proc3 lumchrom_DecodeLMN = {
813
    {lumchrom_DecodeLMN_0, lumchrom_DecodeLMN_1, lumchrom_DecodeLMN_2}
814
};
815
816
/*
817
 * Build the MatrixABC value for a luminance/chrominance color space. Note that
818
 * this is the inverse of the matrix provided in the Configure Image Data
819
 * command.
820
 *
821
 * Return 0 on success, < 0 in the event of an error.
822
 */
823
static int
824
build_lum_chrom_mtxABC(const float pin_mtx[9], pcl_mtx3_t * pmtxABC)
825
0
{
826
0
    int i;
827
0
    pcl_mtx3_t tmp_mtx;
828
829
    /* transpose the input to create a row-order matrix */
830
0
    for (i = 0; i < 3; i++) {
831
0
        int j;
832
833
0
        for (j = 0; j < 3; j++)
834
0
            tmp_mtx.a[i * 3 + j] = pin_mtx[i + 3 * j];
835
0
    }
836
837
0
    return pcl_mtx3_invert(&tmp_mtx, pmtxABC);
838
0
}
839
840
/*
841
 * Finish the creation of a luminance-chrominance color space.
842
 */
843
static int
844
finish_lumchrom_cspace(gs_color_space * pcspace, const pcl_cid_data_t * pcid)
845
0
{
846
0
    const float *pin_mtx;
847
0
    pcl_mtx3_t mtxABC, mtxLMN;
848
0
    pcl_vec3_t white_pt;
849
0
    const pcl_cid_col_common_t *pcoldata;
850
0
    int code = 0;
851
852
0
    if (pcid->len == 6) {
853
0
        pcoldata = cid_data_default[pcl_cspace_LumChrom].pchroma;
854
0
        pin_mtx = cid_data_default[pcl_cspace_LumChrom].pxform;
855
0
    } else {
856
0
        pcoldata = &(pcid->u.lum.colmet);
857
0
        pin_mtx = pcid->u.lum.matrix;
858
0
    }
859
860
0
    if (((code = build_lum_chrom_mtxABC(pin_mtx, &mtxABC)) < 0) ||
861
0
        ((code = build_colmet_conv_mtx(pcoldata, &white_pt, &mtxLMN)) < 0))
862
0
        return code;
863
864
    /* RangeABC has the default value */
865
0
    *(gs_cie_abc_DecodeABC(pcspace)) = lumchrom_DecodeABC;
866
0
    pcl_mtx3_convert_to_gs(&mtxABC, gs_cie_abc_MatrixABC(pcspace));
867
868
    /* RangeLMN has the default value */
869
0
    *(gs_cie_DecodeLMN(pcspace)) = lumchrom_DecodeLMN;
870
0
    pcl_mtx3_convert_to_gs(&mtxLMN, gs_cie_MatrixLMN(pcspace));
871
872
0
    pcl_vec3_to_gs_vector3(gs_cie_WhitePoint(pcspace), white_pt);
873
    /* BlackPoint has the default value */
874
875
0
    return 0;
876
0
}
877
878
static int (*const finish_cspace[(int)pcl_cspace_num]) (gs_color_space *,
879
                                                        const pcl_cid_data_t
880
                                                        *) = {
881
    0,                      /* pcl_cspace_RGB */
882
    0,                      /* pcl_cspace_CMY */
883
    finish_colmet_cspace,   /* pcl_cspace_Colorimetric */
884
    finish_lab_cspace,      /* pcl_cspace_CIELab */
885
    finish_lumchrom_cspace  /* pcl_cspace_LumChrom */
886
};
887
888
/*
889
 * Free a PCL base color space. This decrements the reference count for the
890
 * GS color space, and frees any lookup tables that might have been
891
 * used (device independent color spaces only).
892
 */
893
static void
894
free_base_cspace(gs_memory_t * pmem, void *pvbase, client_name_t cname)
895
19.7k
{
896
19.7k
    pcl_cs_base_t *pbase = (pcl_cs_base_t *) pvbase;
897
898
19.7k
    rc_decrement(pbase->pcspace, "free_base_cspace");
899
19.7k
    rc_decrement(pbase->client_data.plktbl1, "free_base_cspace");
900
19.7k
    rc_decrement(pbase->client_data.plktbl2, "free_base_cspace");
901
19.7k
    gs_free_object(pmem, pvbase, cname);
902
19.7k
}
903
904
/*
905
 * Allocate a PCL base color space.
906
 *
907
 * Because a PCL base color space and the associated graphic-library color
908
 * space must be kept in a one-to-one relationship, the latter color space is
909
 * allocated here as well. For this reason the PCL color space type is
910
 * an operand.
911
 *
912
 * Returns 0 on success, e_Memory in the event of a memory error.
913
 */
914
static int
915
alloc_base_cspace(pcl_cs_base_t ** ppbase,
916
                  pcl_cspace_type_t type, gs_memory_t * pmem)
917
19.7k
{
918
19.7k
    pcl_cs_base_t *pbase = 0;
919
19.7k
    int code = 0;
920
921
19.7k
    *ppbase = 0;
922
19.7k
    rc_alloc_struct_1(pbase,
923
19.7k
                      pcl_cs_base_t,
924
19.7k
                      &st_cs_base_t,
925
19.7k
                      pmem, return e_Memory, "allocate pcl base color space");
926
19.7k
    pbase->rc.free = free_base_cspace;
927
19.7k
    pbase->type = type;
928
19.7k
    pbase->client_data.plktbl1 = 0;
929
19.7k
    pbase->client_data.plktbl2 = 0;
930
19.7k
    pbase->pcspace = 0;
931
932
19.7k
    if (type == pcl_cspace_White)
933
7.25k
        pbase->pcspace = gs_cspace_new_DeviceGray(pmem);
934
12.5k
    else if (type <= pcl_cspace_CMY)
935
12.5k
        pbase->pcspace = gs_cspace_new_DeviceRGB(pmem);
936
0
    else
937
0
        code = gs_cspace_build_CIEABC(&(pbase->pcspace),
938
0
                                      &(pbase->client_data), pmem);
939
19.7k
    if (code < 0 || pbase->pcspace == NULL)
940
0
        free_base_cspace(pmem, pbase, "allocate pcl base color space");
941
19.7k
    else
942
19.7k
        *ppbase = pbase;
943
19.7k
    return code;
944
19.7k
}
945
946
/*
947
 * Create a unique instance of a pcl_cs_base_t object (if one does not already
948
 * exist).
949
 *
950
 * This code is not fully legitimate. To assure that a PCL base color space is
951
 * unique, it is also necessary to assure that the associated graphics library
952
 * color space is unique. Unfortunately, that is not a simple matter, because
953
 * graphic library color spaces are not themselves reference counted, though
954
 * they have reference-counted elements.
955
 *
956
 * We can get away with this arrangement for now by relying on a one-to-one
957
 * association between PCL base color spaces and the associated graphic library
958
 * color spaces. For all current implementations of the graphic library this
959
 * will work. The code may fail, however, for implementations that use a
960
 * "lazy evaluation" technique, as these may require access to the graphics
961
 * library color space after the PCL base color space has been released (the
962
 * graphic library color space will still be present in this case, but its
963
 * client data may have been changed).
964
 */
965
static int
966
unshare_base_cspace(const gs_memory_t * mem, pcl_cs_base_t ** ppbase)
967
0
{
968
0
    pcl_cs_base_t *pbase = *ppbase;
969
0
    pcl_cs_base_t *pnew = 0;
970
0
    int code;
971
972
    /* check if there is anything to do */
973
0
    if (pbase->rc.ref_count == 1)
974
0
        return 0;
975
0
    rc_decrement(pbase, "unshare PCL base color space");
976
977
    /* allocate a new gs_color_space */
978
0
    if ((code = alloc_base_cspace(ppbase, pbase->type, pbase->rc.memory)) < 0)
979
0
        return code;
980
0
    pnew = *ppbase;
981
982
    /* copy the client data */
983
0
    init_client_data_from(&(pnew->client_data), &(pbase->client_data));
984
985
    /* copy the color space (primarily for CIE color spaces; UGLY!!!) */
986
0
    if (pbase->type > pcl_cspace_CMY) {
987
0
        gs_cie_abc *pcs1 = pbase->pcspace->params.abc;
988
0
        gs_cie_abc *pcs2 = pnew->pcspace->params.abc;
989
0
        pcs2->common.install_cspace = pcs1->common.install_cspace;
990
0
        pcs2->common.RangeLMN = pcs1->common.RangeLMN;
991
0
        pcs2->common.DecodeLMN = pcs1->common.DecodeLMN;
992
0
        pcs2->common.MatrixLMN = pcs1->common.MatrixLMN;
993
0
        pcs2->common.points = pcs1->common.points;
994
0
        pcs2->RangeABC = pcs1->RangeABC;
995
0
        pcs2->DecodeABC = pcs1->DecodeABC;
996
0
        pcs2->MatrixABC = pcs1->MatrixABC;
997
0
    } else
998
0
        pnew->pcspace->params.pixel = pbase->pcspace->params.pixel;
999
0
    return 0;
1000
0
}
1001
1002
/*
1003
 * Build a PCL base color space. This should be invoked whenever a color space
1004
 * is required, typically after a Configure Image Data (CID) command.
1005
 *
1006
 * Returns 0 on success, < 0 in the event of an error.
1007
 */
1008
int
1009
pcl_cs_base_build_cspace(pcl_cs_base_t ** ppbase,
1010
                         const pcl_cid_data_t * pcid, gs_memory_t * pmem)
1011
12.5k
{
1012
12.5k
    pcl_cs_base_t *pbase = *ppbase;
1013
12.5k
    pcl_cspace_type_t type = pcl_cid_get_cspace(pcid);
1014
12.5k
    int code = 0;
1015
1016
    /* release the existing color space, if present */
1017
12.5k
    if (pbase != 0) {
1018
0
        if_debug1m('c', pmem, "[c]releasing color space:%s\n",
1019
0
                   pcl_cid_cspace_get_debug_name(pmem, pbase->type));
1020
0
        rc_decrement(pbase, "build base pcl color space");
1021
0
    }
1022
    /* build basic structure and client info. structure */
1023
12.5k
    if ((code = alloc_base_cspace(ppbase, type, pmem)) < 0)
1024
0
        return code;
1025
12.5k
    pbase = *ppbase;
1026
12.5k
    build_client_data(&(pbase->client_data), pcid, pmem);
1027
1028
    /* fill in color space parameters */
1029
12.5k
    if ((finish_cspace[type] != 0) &&
1030
0
        ((code = finish_cspace[type] (pbase->pcspace, pcid)) < 0))
1031
0
        free_base_cspace(pmem, pbase, "build base pcl color space");
1032
12.5k
    return code;
1033
12.5k
}
1034
1035
/*
1036
 * Build a special base color space, used for setting the color white.
1037
 * This base space is unique in that it uses the DeviceGray graphic library
1038
 * color space.
1039
 *
1040
 * This routine is usually called once at initialization.
1041
 */
1042
int
1043
pcl_cs_base_build_white_cspace(pcl_state_t * pcs,
1044
                               pcl_cs_base_t ** ppbase, gs_memory_t * pmem)
1045
29.9k
{
1046
29.9k
    int code = 0;
1047
1048
29.9k
    if (pcs->pwhite_cs == 0)
1049
7.25k
        code = alloc_base_cspace(&pcs->pwhite_cs, pcl_cspace_White, pmem);
1050
29.9k
    if (code >= 0)
1051
29.9k
        pcl_cs_base_copy_from(*ppbase, pcs->pwhite_cs);
1052
29.9k
    return code;
1053
29.9k
}
1054
1055
/*
1056
 * Update the lookup table information for a base color space. This applies
1057
 * only to device-independent color spaces (updating device dependent color
1058
 * spaces updates the transfer function in the current halftone). Passing a
1059
 * null pointer for the lookup table operand resets the tables for ALL color
1060
 * spaces to be the identity table.
1061
 *
1062
 * See the comments in pclookup.h for a description of how device independent
1063
 * lookup tables are interpreted in this implementation.
1064
 *
1065
 * Returns > 0 if the update changed the color space, 0 if the update did not
1066
 * change the color space, and < 0 in the event of an error. If the base color
1067
 * Space was updated, the current PCL indexed color space (which includes this
1068
 * color space as a base color space) must also be updated.
1069
 */
1070
int
1071
pcl_cs_base_update_lookup_tbl(pcl_cs_base_t ** ppbase,
1072
                              pcl_lookup_tbl_t * plktbl)
1073
0
{
1074
0
    pcl_cs_base_t *pbase = *ppbase;
1075
0
    pcl_lookup_tbl_t *plktbl1 = pbase->client_data.plktbl1;
1076
0
    pcl_lookup_tbl_t *plktbl2 = pbase->client_data.plktbl2;
1077
0
    int code = 0;
1078
1079
0
    if (plktbl == 0) {
1080
0
        if ((pbase->client_data.plktbl1 == 0) &&
1081
0
            (pbase->client_data.plktbl2 == 0))
1082
0
            return 0;
1083
0
        plktbl1 = 0;
1084
0
        plktbl2 = 0;
1085
1086
0
    } else {
1087
0
        pcl_cspace_type_t cstype = pbase->type;
1088
0
        pcl_cspace_type_t lktype = pcl_lookup_tbl_get_cspace(plktbl);
1089
1090
        /* lookup tables for "higher" color spaces are always ignored */
1091
0
        if ((cstype < lktype) ||
1092
0
            (lktype == pcl_cspace_RGB) || (lktype == pcl_cspace_CMY))
1093
0
            return 0;
1094
1095
        /* CIE L*a*b* space and the L*a*b* lookup table must match */
1096
0
        if ((cstype == pcl_cspace_CIELab) || (lktype == pcl_cspace_CIELab)) {
1097
0
            plktbl1 = plktbl;
1098
0
        } else if (cstype == lktype)
1099
0
            plktbl1 = plktbl;
1100
0
        else
1101
0
            plktbl2 = plktbl;
1102
0
    }
1103
1104
    /* make a unique copy of the base color space */
1105
0
    if ((code = unshare_base_cspace(pbase->rc.memory, ppbase)) < 0)
1106
0
        return code;
1107
0
    pbase = *ppbase;
1108
1109
    /* update the lookup table information */
1110
0
    update_lookup_tbls(&(pbase->client_data), plktbl1, plktbl2);
1111
1112
0
    return 1;
1113
0
}
1114
1115
/*
1116
 * Install a base color space into the graphic state.
1117
 *
1118
 * The pointer-pointer form of the first operand is for consistency with the
1119
 * other "install" procedures.
1120
 *
1121
 * Returns 0 on success, < 0 in the event of an error.
1122
 */
1123
int
1124
pcl_cs_base_install(pcl_cs_base_t ** ppbase, pcl_state_t * pcs)
1125
34.5k
{
1126
34.5k
    return gs_setcolorspace(pcs->pgs, (*ppbase)->pcspace);
1127
34.5k
}
1128
1129
/*
1130
 * One-time initialization routine. This exists only to handle possible non-
1131
 * initialization of BSS.
1132
 */
1133
void
1134
pcl_cs_base_init(pcl_state_t * pcs)
1135
8.97k
{
1136
8.97k
    pcs->pwhite_cs = 0;
1137
8.97k
}