1 /* Copyright (C) 2001 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /* $Id: gsicc.c,v 1.5.2.1.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* Implementation of the ICCBased color space family */
21 
22 #include "math_.h"
23 #include "memory_.h"
24 #include "gx.h"
25 #include "gserrors.h"
26 #include "gsstruct.h"
27 #include "stream.h"
28 #include "gxcspace.h"		/* for gxcie.c */
29 #include "gxarith.h"
30 #include "gxcie.h"
31 #include "gzstate.h"
32 #include "stream.h"
33 #include "icc.h"		/* must precede icc.h */
34 #include "gsicc.h"
35 
36 
37 typedef struct _icmFileGs icmFileGs;
38 
39 struct _icmFileGs {
40     ICM_FILE_BASE
41 
42     /* Private: */
43     stream *strp;
44 };
45 
46 /* Garbage collection code */
47 
48 /*
49  * Discard a gs_cie_icc_s structure. This requires that we call the
50  * destructor for ICC profile, lookup, and file objects (which are
51  * stored in "foreign" memory).
52  *
53  * No special action is taken with respect to the stream pointer; that is
54  * the responsibility of the client.  */
55 private void
cie_icc_finalize(void * pvicc_info)56 cie_icc_finalize(void * pvicc_info)
57 {
58     gs_cie_icc *    picc_info = (gs_cie_icc *)pvicc_info;
59 
60     if (picc_info->plu != NULL) {
61         picc_info->plu->del(picc_info->plu);
62         picc_info->plu = NULL;
63     }
64     if (picc_info->picc != NULL) {
65         picc_info->picc->del(picc_info->picc);
66         picc_info->picc = NULL;
67     }
68     if (picc_info->pfile != NULL) {
69         picc_info->pfile->del(picc_info->pfile);
70         picc_info->pfile = NULL;
71     }
72 }
73 
74 private_st_cie_icc();
75 
76 /*
77  * Because the color space structure stores alternative color space in-line,
78  * we must enumerate and relocate pointers in these space explicity.
79  */
80 gs_private_st_composite( st_color_space_CIEICC,
81                          gs_paint_color_space,
82                          "gs_color_space_CIEICC",
83                          cs_CIEICC_enum_ptrs,
84                          cs_CIEICC_reloc_ptrs );
85 
86 /* pointer enumeration routine */
87 private
88 ENUM_PTRS_WITH(cs_CIEICC_enum_ptrs, gs_color_space * pcs)
89         return ENUM_USING( *pcs->params.icc.alt_space.type->stype,
90                            &pcs->params.icc.alt_space,
91                            sizeof(pcs->params.separation.alt_space),
92                            index - 1 );
93 
94         ENUM_PTR(0, gs_color_space, params.icc.picc_info);
95 ENUM_PTRS_END
96 
97 /* pointer relocation routine */
98 private
99 RELOC_PTRS_WITH(cs_CIEICC_reloc_ptrs, gs_color_space * pcs)
100     RELOC_PTR(gs_color_space, params.icc.picc_info);
101     RELOC_USING( *pcs->params.icc.alt_space.type->stype,
102                  &pcs->params.icc.alt_space,
103                  sizeof(pcs->params.separation.alt_space) );
104 RELOC_PTRS_END
105 
106 
107 /*
108  * Color space methods for ICCBased color spaces.
109  *
110  * As documented, ICCBased color spaces may be used as both base and
111  * alternative color spaces. Futhermore,, they can themselves contain paint
112  * color spaces as alternative color space. In this implementation we allow
113  * them to be used as base and alternative color spaces, but only to contain
114  * "small" base color spaces (CIEBased or smaller). This arrangement avoids
115  * breaking the color space heirarchy. Providing a more correct arrangement
116  * requires a major change in the color space mechanism.
117  *
118  * Several of the methods used by ICCBased color space apply as well to
119  * DeviceN color spaces, in that they are generic to color spaces having
120  * a variable number of components. We have elected not to attempt to
121  * extract and combine these operations, because this would save only a
122  * small amount of code, and much more could be saved by intorducing certain
123  * common elements (ranges, number of components, etc.) into the color space
124  * root class.
125  */
126 private cs_proc_num_components(gx_num_components_CIEICC);
127 private cs_proc_base_space(gx_alt_space_CIEICC);
128 private cs_proc_equal(gx_equal_CIEICC);
129 private cs_proc_init_color(gx_init_CIEICC);
130 private cs_proc_restrict_color(gx_restrict_CIEICC);
131 private cs_proc_concrete_space(gx_concrete_space_CIEICC);
132 private cs_proc_concretize_color(gx_concretize_CIEICC);
133 private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEICC);
134 
135 private const gs_color_space_type gs_color_space_type_CIEICC = {
136     gs_color_space_index_CIEICC,    /* index */
137     true,                           /* can_be_base_space */
138     true,                           /* can_be_alt_space */
139     &st_color_space_CIEICC,         /* stype - structure descriptor */
140     gx_num_components_CIEICC,       /* num_components */
141     gx_alt_space_CIEICC,            /* base_space */
142     gx_equal_CIEICC,                /* equal */
143     gx_init_CIEICC,                 /* init_color */
144     gx_restrict_CIEICC,             /* restrict_color */
145     gx_concrete_space_CIEICC,       /* concrete_space */
146     gx_concretize_CIEICC,           /* concreteize_color */
147     NULL,                           /* remap_concrete_color */
148     gx_default_remap_color,         /* remap_color */
149     gx_install_CIE,                 /* install_cpsace */
150     gx_adjust_cspace_CIEICC,        /* adjust_cspace_count */
151     gx_no_adjust_color_count        /* adjust_color_count */
152 };
153 
154 
155 /*
156  * Return the number of components used by a ICCBased color space - 1, 3, or 4
157  */
158 private int
gx_num_components_CIEICC(const gs_color_space * pcs)159 gx_num_components_CIEICC(const gs_color_space * pcs)
160 {
161     return pcs->params.icc.picc_info->num_components;
162 }
163 
164 /*
165  * Return the alternative space for an ICCBasee color space, but only if
166  * that space is being used.
167  */
168 private const gs_color_space *
gx_alt_space_CIEICC(const gs_color_space * pcs)169 gx_alt_space_CIEICC(const gs_color_space * pcs)
170 {
171     return (pcs->params.icc.picc_info->picc == NULL)
172                 ? (const gs_color_space *)&pcs->params.icc.alt_space
173                 : NULL;
174 }
175 
176 /*
177  * Return true if two ICCBased color spaces are equal. This routine is allowed
178  * to return false even if the color spaces are equal (but not the converse),
179  * so the following simple algorithm is used:
180  *
181  *   1. If one color space uses its alternative space, but the other does not,
182  *      the two spaces are not the same.
183  *
184  *   2. If both color spaces use the alternative space, we recursively apply
185  *      the question of equality to the base spaces.
186  *
187  *   3. If neither color space uses the alternative color space, the two
188  *      spaces are considered the same only if they reference the same
189  *      data stream (which implies they must have the same number of
190  *      components), and make use of the same ranges. No attempt is made to
191  *      look into the stream (profile) contents.
192  */
193 private bool
gx_equal_CIEICC(const gs_color_space * pcs0,const gs_color_space * pcs1)194 gx_equal_CIEICC(const gs_color_space * pcs0, const gs_color_space * pcs1)
195 {
196     const gs_icc_params *   picc_params0 = &pcs0->params.icc;
197     const gs_icc_params *   picc_params1 = &pcs1->params.icc;
198     const gs_cie_icc *      picc_info0 = picc_params0->picc_info;
199     const gs_cie_icc *      picc_info1 = picc_params1->picc_info;
200 
201     if (picc_info0->picc == NULL) {
202         if (picc_info1->picc != NULL)
203             return false;
204         return picc_params0->alt_space.type->equal(
205                         (const gs_color_space *)&picc_params0->alt_space,
206                         (const gs_color_space *)&picc_params1->alt_space );
207     } else if (picc_info1->picc == NULL)
208         return false;
209     else {
210         const gs_range *    pranges0 = picc_info0->Range.ranges;
211         const gs_range *    pranges1 = picc_info1->Range.ranges;
212         int                 i, ncomps = picc_info0->num_components;
213 
214         if   ( picc_info0->instrp != picc_info1->instrp  ||
215                picc_info0->file_id != picc_info1->file_id  )
216             return false;
217 
218         for ( i = 0;
219                i < ncomps &&
220                pranges0[i].rmin == pranges1[i].rmin &&
221                pranges0[i].rmax == pranges1[i].rmax;
222                i++ )
223             ;
224         return i == ncomps;
225     }
226 }
227 
228 /*
229  * Set the initial client color for an ICCBased color space. The convention
230  * suggested by the ICC specification is to set all components to 0.
231  */
232 private void
gx_init_CIEICC(gs_client_color * pcc,const gs_color_space * pcs)233 gx_init_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
234 {
235     int     i, ncomps = pcs->params.icc.picc_info->num_components;
236 
237     for (i = 0; i < ncomps; ++i)
238 	pcc->paint.values[i] = 0.0;
239 
240     /* make sure that [ 0, ... 0] is in range */
241     gx_restrict_CIEICC(pcc, pcs);
242 }
243 
244 /*
245  * Restrict an color to the range specified for an ICCBased color space.
246  */
247 private void
gx_restrict_CIEICC(gs_client_color * pcc,const gs_color_space * pcs)248 gx_restrict_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
249 {
250     int                 i, ncomps = pcs->params.icc.picc_info->num_components;
251     const gs_range *    ranges = pcs->params.icc.picc_info->Range.ranges;
252 
253     for (i = 0; i < ncomps; ++i) {
254         floatp  v = pcc->paint.values[i];
255         floatp  rmin = ranges[i].rmin, rmax = ranges[i].rmax;
256 
257         if (v < rmin)
258             pcc->paint.values[i] = rmin;
259         else if (v > rmax)
260             pcc->paint.values[i] = rmax;
261     }
262 }
263 
264 /*
265  * Return the conrecte space to which this color space will map. If the
266  * ICCBased color space is being used in native mode, the concrete space
267  * will be dependent on the current color rendering dictionary, as it is
268  * for all CIE bases. If the alternate color space is being used, then
269  * this question is passed on the the appropriate method of that space.
270  */
271 private const gs_color_space *
gx_concrete_space_CIEICC(const gs_color_space * pcs,const gs_imager_state * pis)272 gx_concrete_space_CIEICC(const gs_color_space * pcs, const gs_imager_state * pis)
273 {
274     if (pcs->params.icc.picc_info->picc == NULL) {
275         const gs_color_space *  pacs = (const gs_color_space *)
276                                         &pcs->params.icc.alt_space;
277 
278         return cs_concrete_space(pacs, pis);
279     } else
280         return gx_concrete_space_CIE(NULL, pis);
281 }
282 
283 /*
284  * Convert an ICCBased color space to a concrete color space.
285  */
286 private int
gx_concretize_CIEICC(const gs_client_color * pcc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)287 gx_concretize_CIEICC(
288     const gs_client_color * pcc,
289     const gs_color_space *  pcs,
290     frac *                  pconc,
291     const gs_imager_state * pis )
292 {
293     const gs_icc_params *   picc_params = &pcs->params.icc;
294     const gs_cie_icc *      picc_info = picc_params->picc_info;
295     stream *                instrp = picc_info->instrp;
296     icc *                   picc = picc_info->picc;
297     double                  inv[4], outv[3];
298     cie_cached_vector3      vlmn;
299     gs_client_color         lcc = *pcc;
300     int                     i, ncomps = picc_info->num_components;
301 
302     /* use the altenate space concretize if appropriate */
303     if (picc == NULL)
304         return picc_params->alt_space.type->concretize_color(
305                             pcc,
306                             (const gs_color_space *)&picc_params->alt_space,
307                             pconc,
308                             pis );
309 
310     /* set up joint cache as required */
311     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
312 
313     /* verify and update the stream pointer */
314     if (picc_info->file_id != (instrp->read_id | instrp->write_id))
315         return_error(gs_error_ioerror);
316     ((icmFileGs *)picc->fp)->strp = instrp;
317 
318     /* translate the input components */
319     gx_restrict_CIEICC(&lcc, pcs);
320     for (i = 0; i < ncomps; i++)
321         inv[i] = lcc.paint.values[i];
322 
323     /*
324      * Perform the lookup operation. A return value of 1 indicates that
325      * clipping occurred somewhere in the operation, but the result is
326      * legitimate. Other non-zero return values indicate an error, which
327      * should not occur in practice.
328      */
329     if (picc_info->plu->lookup(picc_info->plu, outv, inv) > 1)
330         return_error(gs_error_unregistered);
331 
332     /* if the output is in the CIE L*a*b* space, convert to XYZ */
333     if (picc_info->pcs_is_cielab) {
334         floatp              f[3];
335         const gs_vector3 *  pwhtpt = &picc_info->common.points.WhitePoint;
336 
337 
338         f[1] = (outv[0] + 16.0) / 116.0;
339         f[0] = f[1] + outv[1] / 500.0;
340         f[2] = f[1] - outv[2] / 200;
341 
342         for (i = 0; i < 3; i++) {
343             if (f[i] >= 6.0 / 29.0)
344                 outv[i] = f[i] * f[i] * f[i];
345             else
346                 outv[i] = 108.0 * (f[i] - 4.0 / 29.0) / 841.0;
347         }
348 
349         /*
350          * The connection space white-point is known to be D50, but we
351          * use the more general form in case of future revisions.
352          */
353         outv[0] *= pwhtpt->u;
354         outv[1] *= pwhtpt->v;
355         outv[2] *= pwhtpt->w;
356     }
357 
358     /* translate the output */
359     vlmn.u = float2cie_cached(outv[0]);
360     vlmn.v = float2cie_cached(outv[1]);
361     vlmn.w = float2cie_cached(outv[2]);
362 
363     gx_cie_remap_finish(vlmn, pconc, pis, pcs);
364     return 0;
365 }
366 
367 /*
368  * Handle a reference or de-reference of the prameter structure of an
369  * ICCBased color space. For the purposes of this routine, the color space
370  * is considered a reference rather than an object, and is not itself
371  * reference counted (an unintuitive but otherwise legitimate state of
372  * affairs).
373  *
374  * Because color spaces store alternative/base color space inline, these
375  * need to have their reference count adjusted explicitly.
376  */
377 private void
gx_adjust_cspace_CIEICC(const gs_color_space * pcs,int delta)378 gx_adjust_cspace_CIEICC(const gs_color_space * pcs, int delta)
379 {
380     const gs_icc_params *   picc_params = &pcs->params.icc;
381 
382     rc_adjust_const(picc_params->picc_info, delta, "gx_adjust_cspace_CIEICC");
383     picc_params->alt_space.type->adjust_cspace_count(
384                 (const gs_color_space *)&picc_params->alt_space, delta );
385 }
386 
387 private int
icmFileGs_seek(icmFile * pp,long int offset)388 icmFileGs_seek(icmFile *pp, long int offset)
389 {
390     icmFileGs *p = (icmFileGs *)pp;
391 
392     return spseek(p->strp, offset);
393 }
394 
395 private size_t
icmFileGs_read(icmFile * pp,void * buffer,size_t size,size_t count)396 icmFileGs_read(icmFile *pp, void *buffer, size_t size, size_t count)
397 {
398     icmFileGs *p = (icmFileGs *)pp;
399     uint    tot;
400     int     status = sgets(p->strp, buffer, size * count, &tot);
401 
402     return (status < 0) ? status : tot;
403 }
404 
405 private size_t
icmFileGs_write(icmFile * pp,void * buffer,size_t size,size_t count)406 icmFileGs_write(icmFile *pp, void *buffer, size_t size, size_t count)
407 {
408     icmFileGs *p = (icmFileGs *)pp;
409     uint    tot;
410     int     status = sputs(p->strp, buffer, size * count, &tot);
411 
412     return (status < 0) ? status : tot;
413 }
414 
415 private int
icmFileGs_flush(icmFile * pp)416 icmFileGs_flush(icmFile *pp)
417 {
418     icmFileGs *p = (icmFileGs *)pp;
419 
420     return s_std_write_flush(p->strp);
421 }
422 
423 private int
icmFileGs_delete(icmFile * pp)424 icmFileGs_delete(icmFile *pp)
425 {
426     free(pp);
427     return 0;
428 }
429 
430 /**
431  * gx_wrap_icc_stream: Wrap a Ghostscript stream as an icclib file.
432  * @strp: The Ghostscript stream.
433  *
434  * Creates an icmFile object that wraps @stream.
435  *
436  * Note: the memory for this object is allocated using malloc, and the
437  * relocation of the stream pointer is done lazily, before an icclu
438  * operation. It would probably be cleaner to allocate the icmFile in
439  * garbage collected memory, and have the relocation happen there, but
440  * I wanted to minimally modify Jan's working code.
441  *
442  * Return value: the stream wrapped as an icmFile object, or NULL on
443  * error.
444  **/
445 private icmFile *
gx_wrap_icc_stream(stream * strp)446 gx_wrap_icc_stream(stream *strp)
447 {
448     icmFileGs *p;
449 
450     if ((p = (icmFileGs *) calloc(1,sizeof(icmFileGs))) == NULL)
451 	return NULL;
452     p->seek  = icmFileGs_seek;
453     p->read  = icmFileGs_read;
454     p->write = icmFileGs_write;
455     p->flush = icmFileGs_flush;
456     p->del   = icmFileGs_delete;
457 
458     p->strp = strp;
459 
460     return (icmFile *)p;
461 }
462 
463 int
gx_load_icc_profile(gs_cie_icc * picc_info)464 gx_load_icc_profile(gs_cie_icc *picc_info)
465 {
466     stream *        instrp = picc_info->instrp;
467     icc *           picc;
468     icmLuBase * plu = NULL;
469     icmFile *pfile = NULL;
470 
471     /* verify that the file is legitimate */
472     if (picc_info->file_id != (instrp->read_id | instrp->write_id))
473 	return_error(gs_error_ioerror);
474     /*
475      * Load the top-level ICC profile.
476      *
477      * If an ICC profile fails to load, generate an error.
478      *
479      * Testing demonstrates, however, Acrobat Reader silently
480      * ignores the error and uses the alternate color space.
481      * This behaviour is implemented by catching the error using
482      * a stopped context from within the interpreter (gs_icc.ps).
483      *
484      * Failure to allocate the top-level profile object is considered
485      * a limitcheck rather than a VMerror, as profile data structures
486      * are stored in "foreign" memory.
487      */
488     if ((picc = new_icc()) == NULL)
489 	return_error(gs_error_limitcheck);
490     {
491 	icProfileClassSignature profile_class;
492 	icColorSpaceSignature   cspace_type;
493 	gs_vector3 *            ppt;
494 
495 	pfile = gx_wrap_icc_stream (instrp);
496 
497 	if ((picc->read(picc, pfile, 0)) != 0)
498 	    goto return_rangecheck;
499 
500 	/* verify the profile type */
501 	profile_class = picc->header->deviceClass;
502 	if ( profile_class != icSigInputClass     &&
503 	     profile_class != icSigDisplayClass   &&
504 	     profile_class != icSigOutputClass    &&
505 	     profile_class != icSigColorSpaceClass  )
506 	    goto return_rangecheck;
507 
508 	/* verify the profile connection space */
509 	cspace_type = picc->header->pcs;
510 	if (cspace_type == icSigLabData)
511 	    picc_info->pcs_is_cielab = true;
512 	else if (cspace_type == icSigXYZData)
513 	    picc_info->pcs_is_cielab = false;
514 	else
515 	    goto return_rangecheck;
516 
517 	/* verify the source color space */
518 	cspace_type = picc->header->colorSpace;
519 	if (cspace_type == icSigCmykData) {
520 	    if (picc_info->num_components != 4)
521 		goto return_rangecheck;
522 	} else if ( cspace_type == icSigRgbData ||
523 		    cspace_type == icSigLabData   ) {
524 	    if (picc_info->num_components != 3)
525 		goto return_rangecheck;
526 	} else if (cspace_type == icSigGrayData) {
527 	    if (picc_info->num_components != 1)
528 		goto return_rangecheck;
529 	}
530 
531 	/*
532 	 * Fetch the lookup object.
533 	 *
534 	 * PostScript and PDF deal with rendering intent as strictly a
535 	 * rendering dictionary facility. ICC profiles allow a rendering
536 	 * intent to be specified for both the input (device ==> pcs) and
537 	 * output (pcs ==> device) operations. Hence, when using ICCBased
538 	 * color spaces with PDF, no clue is provided as to which source
539 	 * mapping to select.
540 	 *
541 	 * In the absence of other information, there are two possible
542 	 * selections. If our understanding is correct, when relative
543 	 * colorimetry is specified, the icclib code will map source
544 	 * color values to XYZ or L*a*b* values such that the relationship
545 	 * of the source color, relative to the source white and black
546 	 * points, will be the same as the output colors and the
547 	 * profile connection space illuminant (currently always D50)
548 	 * and pure black ([0, 0, 0]). In this case, the white and black
549 	 * points that should be listed in the color space are the
550 	 * profile connection space illuminant (D50) and pure black.
551 	 *
552 	 * If absolute colorimetry is employed, the XYZ or L*a*b* values
553 	 * generated will be absolute in the chromatic sense (they are
554 	 * not literally "absolute", as we still must have overall
555 	 * intensity information inorder to determine weighted spectral
556 	 * power levels). To achieve relative colorimetry for the output,
557 	 * these colors must be evaluated relative to the source white
558 	 * and black points. Hence, in this case, the appropriate white
559 	 * and black points to list in the color space are the source
560 	 * white and black points provided in the profile tag array.
561 	 *
562 	 * In this implementation, we will always request relative
563 	 * colorimetry from the icclib, and so will use the profile
564 	 * connection space illuminant and pure black as the white and
565 	 * black points of the color space. This approach is somewhat
566 	 * simpler, as it allows the color space white point to also
567 	 * be used for L*a*b* to XYZ conversion (otherwise we would
568 	 * need to store the profile connection space illuminant
569 	 * separately for that purpose). The approach does reduce to
570 	 * to some extent the range of mappings that can be achieved
571 	 * via the color rendering dictionary, but for now we believe
572 	 * this loss is not significant.
573 	 *
574 	 * For reasons that are not clear to us, the icclib code does
575 	 * not support relative colorimetry for all color profiles. For
576 	 * this reason, we specify icmDefaultIntent rather than
577 	 * icRelativeColormetric.
578 	 *
579 	 * NB: We are not color experts; our understanding of this area
580 	 *     may well be incorrect.
581 	 */
582 	plu = picc->get_luobj( picc,
583 			       icmFwd,
584 			       icmDefaultIntent,
585 			       0, /* PCS override */
586 			       icmLuOrdNorm );
587 	if (plu == NULL)
588 	    goto return_rangecheck;
589 
590 	/*
591 	 * Get the appropriate white and black points. See the note on
592 	 * rendering intent above for a discussion of why we are using
593 	 * the profile space illuminant and pure black. (Pure black need
594 	 * not be set explicitly, as it is the default.)
595 	 */
596 	ppt = &picc_info->common.points.WhitePoint;
597 	ppt->u = picc->header->illuminant.X;
598 	ppt->v = picc->header->illuminant.Y;
599 	ppt->w = picc->header->illuminant.Z;
600 
601 	picc_info->picc = picc;
602 	picc_info->plu = plu;
603 	picc_info->pfile = pfile;
604     }
605 
606     return 0;
607 
608  return_rangecheck:
609     if (plu != NULL)
610 	plu->del(plu);
611     if (picc != NULL)
612 	picc->del(picc);
613     if (pfile != NULL)
614 	pfile->del(pfile);
615     return_error(gs_error_rangecheck);
616 }
617 
618 /*
619  * Install an ICCBased color space.
620  *
621  * Note that an ICCBased color space must be installed before it is known if
622  * the ICC profile or the alternate color space is to be used.
623  */
624 private int
gx_install_CIEICC(const gs_color_space * pcs,gs_state * pgs)625 gx_install_CIEICC(const gs_color_space * pcs, gs_state * pgs)
626 {
627     const gs_icc_params * picc_params = (const gs_icc_params *)&pcs->params.icc;
628     gs_cie_icc *    picc_info = picc_params->picc_info;
629 
630     /* update the stub information used by the joint caches */
631     gx_cie_load_common_cache(&picc_info->common, pgs);
632     gx_cie_common_complete(&picc_info->common);
633     return gs_cie_cs_complete(pgs, true);
634 }
635 
636 
637 /*
638  * Constructor for ICCBased color space. As with the other color space
639  * constructors, this provides only minimal initialization.
640  */
641 int
gs_cspace_build_CIEICC(gs_color_space ** ppcspace,void * client_data,gs_memory_t * pmem)642 gs_cspace_build_CIEICC(
643     gs_color_space **   ppcspace,
644     void *              client_data,
645     gs_memory_t *       pmem )
646 {
647     gs_cie_icc *        picc_info;
648     gs_color_space *    pcs;
649 
650     /*
651      * The gs_cie_icc_s structure is the only CIE-based color space structure
652      * which accesses additional memory for which it is responsible. We make
653      * use of the finalization procedure to handle this task, so we can use
654      * the generic CIE space build routine (otherwise we would need a
655      * separate build routine that provided its own reference count freeing
656      * procedure).
657      */
658     picc_info = gx_build_cie_space( ppcspace,
659                                     &gs_color_space_type_CIEICC,
660                                     &st_cie_icc,
661                                     pmem );
662 
663     if (picc_info == NULL)
664         return_error(gs_error_VMerror);
665 
666     gx_set_common_cie_defaults(&picc_info->common, client_data);
667     /*
668      * Now set the D50 WhitePoint. The above function does not set any
669      * valid WhitepPoint since PostScript always requires this, but ICC
670      * assumes a D50 WhitePoint as a default
671      */
672     picc_info->common.points.WhitePoint.u = 0.9642;		/* Profile illuminant - D50 */
673     picc_info->common.points.WhitePoint.v = 1.0000;
674     picc_info->common.points.WhitePoint.w = 0.8249;
675     picc_info->common.install_cspace = gx_install_CIEICC;
676     picc_info->num_components = 0;
677     picc_info->Range = Range4_default;
678     picc_info->instrp = NULL;
679     picc_info->pcs_is_cielab = false;
680     picc_info->picc = NULL;
681     picc_info->plu = NULL;
682     picc_info->pfile = NULL;
683 
684     pcs = *ppcspace;
685     pcs->params.icc.picc_info = picc_info;
686     return 0;
687 }
688