xref: /plan9/sys/src/cmd/gs/src/gsicc.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 2001 1999 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gsicc.c,v 1.13 2004/04/08 07:59:19 igor Exp $ */
183ff48bf5SDavid du Colombier /* Implementation of the ICCBased color space family */
193ff48bf5SDavid du Colombier 
203ff48bf5SDavid du Colombier #include "math_.h"
213ff48bf5SDavid du Colombier #include "memory_.h"
223ff48bf5SDavid du Colombier #include "gx.h"
233ff48bf5SDavid du Colombier #include "gserrors.h"
243ff48bf5SDavid du Colombier #include "gsstruct.h"
253ff48bf5SDavid du Colombier #include "stream.h"
263ff48bf5SDavid du Colombier #include "gxcspace.h"		/* for gxcie.c */
273ff48bf5SDavid du Colombier #include "gxarith.h"
283ff48bf5SDavid du Colombier #include "gxcie.h"
293ff48bf5SDavid du Colombier #include "gzstate.h"
303ff48bf5SDavid du Colombier #include "stream.h"
313ff48bf5SDavid du Colombier #include "icc.h"		/* must precede icc.h */
323ff48bf5SDavid du Colombier #include "gsicc.h"
333ff48bf5SDavid du Colombier 
343ff48bf5SDavid du Colombier 
353ff48bf5SDavid du Colombier typedef struct _icmFileGs icmFileGs;
363ff48bf5SDavid du Colombier 
373ff48bf5SDavid du Colombier struct _icmFileGs {
383ff48bf5SDavid du Colombier     ICM_FILE_BASE
393ff48bf5SDavid du Colombier 
403ff48bf5SDavid du Colombier     /* Private: */
413ff48bf5SDavid du Colombier     stream *strp;
423ff48bf5SDavid du Colombier };
433ff48bf5SDavid du Colombier 
443ff48bf5SDavid du Colombier /* Garbage collection code */
453ff48bf5SDavid du Colombier 
463ff48bf5SDavid du Colombier /*
473ff48bf5SDavid du Colombier  * Discard a gs_cie_icc_s structure. This requires that we call the
483ff48bf5SDavid du Colombier  * destructor for ICC profile, lookup, and file objects (which are
493ff48bf5SDavid du Colombier  * stored in "foreign" memory).
503ff48bf5SDavid du Colombier  *
513ff48bf5SDavid du Colombier  * No special action is taken with respect to the stream pointer; that is
523ff48bf5SDavid du Colombier  * the responsibility of the client.  */
533ff48bf5SDavid du Colombier private void
cie_icc_finalize(void * pvicc_info)543ff48bf5SDavid du Colombier cie_icc_finalize(void * pvicc_info)
553ff48bf5SDavid du Colombier {
563ff48bf5SDavid du Colombier     gs_cie_icc *    picc_info = (gs_cie_icc *)pvicc_info;
573ff48bf5SDavid du Colombier 
583ff48bf5SDavid du Colombier     if (picc_info->plu != NULL) {
593ff48bf5SDavid du Colombier         picc_info->plu->del(picc_info->plu);
603ff48bf5SDavid du Colombier         picc_info->plu = NULL;
613ff48bf5SDavid du Colombier     }
623ff48bf5SDavid du Colombier     if (picc_info->picc != NULL) {
633ff48bf5SDavid du Colombier         picc_info->picc->del(picc_info->picc);
643ff48bf5SDavid du Colombier         picc_info->picc = NULL;
653ff48bf5SDavid du Colombier     }
663ff48bf5SDavid du Colombier     if (picc_info->pfile != NULL) {
673ff48bf5SDavid du Colombier         picc_info->pfile->del(picc_info->pfile);
683ff48bf5SDavid du Colombier         picc_info->pfile = NULL;
693ff48bf5SDavid du Colombier     }
703ff48bf5SDavid du Colombier }
713ff48bf5SDavid du Colombier 
723ff48bf5SDavid du Colombier private_st_cie_icc();
733ff48bf5SDavid du Colombier 
743ff48bf5SDavid du Colombier /*
753ff48bf5SDavid du Colombier  * Because the color space structure stores alternative color space in-line,
763ff48bf5SDavid du Colombier  * we must enumerate and relocate pointers in these space explicity.
773ff48bf5SDavid du Colombier  */
783ff48bf5SDavid du Colombier gs_private_st_composite( st_color_space_CIEICC,
793ff48bf5SDavid du Colombier                          gs_paint_color_space,
803ff48bf5SDavid du Colombier                          "gs_color_space_CIEICC",
813ff48bf5SDavid du Colombier                          cs_CIEICC_enum_ptrs,
823ff48bf5SDavid du Colombier                          cs_CIEICC_reloc_ptrs );
833ff48bf5SDavid du Colombier 
843ff48bf5SDavid du Colombier /* pointer enumeration routine */
853ff48bf5SDavid du Colombier private
863ff48bf5SDavid du Colombier ENUM_PTRS_WITH(cs_CIEICC_enum_ptrs, gs_color_space * pcs)
873ff48bf5SDavid du Colombier         return ENUM_USING( *pcs->params.icc.alt_space.type->stype,
883ff48bf5SDavid du Colombier                            &pcs->params.icc.alt_space,
893ff48bf5SDavid du Colombier                            sizeof(pcs->params.separation.alt_space),
903ff48bf5SDavid du Colombier                            index - 1 );
913ff48bf5SDavid du Colombier 
923ff48bf5SDavid du Colombier         ENUM_PTR(0, gs_color_space, params.icc.picc_info);
933ff48bf5SDavid du Colombier ENUM_PTRS_END
943ff48bf5SDavid du Colombier 
953ff48bf5SDavid du Colombier /* pointer relocation routine */
963ff48bf5SDavid du Colombier private
973ff48bf5SDavid du Colombier RELOC_PTRS_WITH(cs_CIEICC_reloc_ptrs, gs_color_space * pcs)
983ff48bf5SDavid du Colombier     RELOC_PTR(gs_color_space, params.icc.picc_info);
993ff48bf5SDavid du Colombier     RELOC_USING( *pcs->params.icc.alt_space.type->stype,
1003ff48bf5SDavid du Colombier                  &pcs->params.icc.alt_space,
1013ff48bf5SDavid du Colombier                  sizeof(pcs->params.separation.alt_space) );
1023ff48bf5SDavid du Colombier RELOC_PTRS_END
1033ff48bf5SDavid du Colombier 
1043ff48bf5SDavid du Colombier 
1053ff48bf5SDavid du Colombier /*
1063ff48bf5SDavid du Colombier  * Color space methods for ICCBased color spaces.
1073ff48bf5SDavid du Colombier  *
1083ff48bf5SDavid du Colombier  * As documented, ICCBased color spaces may be used as both base and
1093ff48bf5SDavid du Colombier  * alternative color spaces. Futhermore,, they can themselves contain paint
1103ff48bf5SDavid du Colombier  * color spaces as alternative color space. In this implementation we allow
1113ff48bf5SDavid du Colombier  * them to be used as base and alternative color spaces, but only to contain
1123ff48bf5SDavid du Colombier  * "small" base color spaces (CIEBased or smaller). This arrangement avoids
1133ff48bf5SDavid du Colombier  * breaking the color space heirarchy. Providing a more correct arrangement
1143ff48bf5SDavid du Colombier  * requires a major change in the color space mechanism.
1153ff48bf5SDavid du Colombier  *
1163ff48bf5SDavid du Colombier  * Several of the methods used by ICCBased color space apply as well to
1173ff48bf5SDavid du Colombier  * DeviceN color spaces, in that they are generic to color spaces having
1183ff48bf5SDavid du Colombier  * a variable number of components. We have elected not to attempt to
1193ff48bf5SDavid du Colombier  * extract and combine these operations, because this would save only a
1203ff48bf5SDavid du Colombier  * small amount of code, and much more could be saved by intorducing certain
1213ff48bf5SDavid du Colombier  * common elements (ranges, number of components, etc.) into the color space
1223ff48bf5SDavid du Colombier  * root class.
1233ff48bf5SDavid du Colombier  */
1243ff48bf5SDavid du Colombier private cs_proc_num_components(gx_num_components_CIEICC);
1253ff48bf5SDavid du Colombier private cs_proc_base_space(gx_alt_space_CIEICC);
1263ff48bf5SDavid du Colombier private cs_proc_init_color(gx_init_CIEICC);
1273ff48bf5SDavid du Colombier private cs_proc_restrict_color(gx_restrict_CIEICC);
1283ff48bf5SDavid du Colombier private cs_proc_concrete_space(gx_concrete_space_CIEICC);
1293ff48bf5SDavid du Colombier private cs_proc_concretize_color(gx_concretize_CIEICC);
1303ff48bf5SDavid du Colombier private cs_proc_adjust_cspace_count(gx_adjust_cspace_CIEICC);
131*593dc095SDavid du Colombier private cs_proc_serialize(gx_serialize_CIEICC);
1323ff48bf5SDavid du Colombier 
1333ff48bf5SDavid du Colombier private const gs_color_space_type gs_color_space_type_CIEICC = {
1343ff48bf5SDavid du Colombier     gs_color_space_index_CIEICC,    /* index */
1353ff48bf5SDavid du Colombier     true,                           /* can_be_base_space */
1363ff48bf5SDavid du Colombier     true,                           /* can_be_alt_space */
1373ff48bf5SDavid du Colombier     &st_color_space_CIEICC,         /* stype - structure descriptor */
1383ff48bf5SDavid du Colombier     gx_num_components_CIEICC,       /* num_components */
1393ff48bf5SDavid du Colombier     gx_alt_space_CIEICC,            /* base_space */
1403ff48bf5SDavid du Colombier     gx_init_CIEICC,                 /* init_color */
1413ff48bf5SDavid du Colombier     gx_restrict_CIEICC,             /* restrict_color */
1423ff48bf5SDavid du Colombier     gx_concrete_space_CIEICC,       /* concrete_space */
1433ff48bf5SDavid du Colombier     gx_concretize_CIEICC,           /* concreteize_color */
1443ff48bf5SDavid du Colombier     NULL,                           /* remap_concrete_color */
1453ff48bf5SDavid du Colombier     gx_default_remap_color,         /* remap_color */
1463ff48bf5SDavid du Colombier     gx_install_CIE,                 /* install_cpsace */
147*593dc095SDavid du Colombier     gx_spot_colors_set_overprint,   /* set_overprint */
1483ff48bf5SDavid du Colombier     gx_adjust_cspace_CIEICC,        /* adjust_cspace_count */
149*593dc095SDavid du Colombier     gx_no_adjust_color_count,       /* adjust_color_count */
150*593dc095SDavid du Colombier     gx_serialize_CIEICC,		    /* serialize */
151*593dc095SDavid du Colombier     gx_cspace_is_linear_default
1523ff48bf5SDavid du Colombier };
1533ff48bf5SDavid du Colombier 
1543ff48bf5SDavid du Colombier 
1553ff48bf5SDavid du Colombier /*
1563ff48bf5SDavid du Colombier  * Return the number of components used by a ICCBased color space - 1, 3, or 4
1573ff48bf5SDavid du Colombier  */
1583ff48bf5SDavid du Colombier private int
gx_num_components_CIEICC(const gs_color_space * pcs)1593ff48bf5SDavid du Colombier gx_num_components_CIEICC(const gs_color_space * pcs)
1603ff48bf5SDavid du Colombier {
1613ff48bf5SDavid du Colombier     return pcs->params.icc.picc_info->num_components;
1623ff48bf5SDavid du Colombier }
1633ff48bf5SDavid du Colombier 
1643ff48bf5SDavid du Colombier /*
1653ff48bf5SDavid du Colombier  * Return the alternative space for an ICCBasee color space, but only if
1663ff48bf5SDavid du Colombier  * that space is being used.
1673ff48bf5SDavid du Colombier  */
1683ff48bf5SDavid du Colombier private const gs_color_space *
gx_alt_space_CIEICC(const gs_color_space * pcs)1693ff48bf5SDavid du Colombier gx_alt_space_CIEICC(const gs_color_space * pcs)
1703ff48bf5SDavid du Colombier {
1713ff48bf5SDavid du Colombier     return (pcs->params.icc.picc_info->picc == NULL)
1723ff48bf5SDavid du Colombier                 ? (const gs_color_space *)&pcs->params.icc.alt_space
1733ff48bf5SDavid du Colombier                 : NULL;
1743ff48bf5SDavid du Colombier }
1753ff48bf5SDavid du Colombier 
1763ff48bf5SDavid du Colombier /*
1773ff48bf5SDavid du Colombier  * Set the initial client color for an ICCBased color space. The convention
1783ff48bf5SDavid du Colombier  * suggested by the ICC specification is to set all components to 0.
1793ff48bf5SDavid du Colombier  */
1803ff48bf5SDavid du Colombier private void
gx_init_CIEICC(gs_client_color * pcc,const gs_color_space * pcs)1813ff48bf5SDavid du Colombier gx_init_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
1823ff48bf5SDavid du Colombier {
1833ff48bf5SDavid du Colombier     int     i, ncomps = pcs->params.icc.picc_info->num_components;
1843ff48bf5SDavid du Colombier 
1853ff48bf5SDavid du Colombier     for (i = 0; i < ncomps; ++i)
1863ff48bf5SDavid du Colombier 	pcc->paint.values[i] = 0.0;
1873ff48bf5SDavid du Colombier 
1883ff48bf5SDavid du Colombier     /* make sure that [ 0, ... 0] is in range */
1893ff48bf5SDavid du Colombier     gx_restrict_CIEICC(pcc, pcs);
1903ff48bf5SDavid du Colombier }
1913ff48bf5SDavid du Colombier 
1923ff48bf5SDavid du Colombier /*
1933ff48bf5SDavid du Colombier  * Restrict an color to the range specified for an ICCBased color space.
1943ff48bf5SDavid du Colombier  */
1953ff48bf5SDavid du Colombier private void
gx_restrict_CIEICC(gs_client_color * pcc,const gs_color_space * pcs)1963ff48bf5SDavid du Colombier gx_restrict_CIEICC(gs_client_color * pcc, const gs_color_space * pcs)
1973ff48bf5SDavid du Colombier {
1983ff48bf5SDavid du Colombier     int                 i, ncomps = pcs->params.icc.picc_info->num_components;
1993ff48bf5SDavid du Colombier     const gs_range *    ranges = pcs->params.icc.picc_info->Range.ranges;
2003ff48bf5SDavid du Colombier 
2013ff48bf5SDavid du Colombier     for (i = 0; i < ncomps; ++i) {
2023ff48bf5SDavid du Colombier         floatp  v = pcc->paint.values[i];
2033ff48bf5SDavid du Colombier         floatp  rmin = ranges[i].rmin, rmax = ranges[i].rmax;
2043ff48bf5SDavid du Colombier 
2053ff48bf5SDavid du Colombier         if (v < rmin)
2063ff48bf5SDavid du Colombier             pcc->paint.values[i] = rmin;
2073ff48bf5SDavid du Colombier         else if (v > rmax)
2083ff48bf5SDavid du Colombier             pcc->paint.values[i] = rmax;
2093ff48bf5SDavid du Colombier     }
2103ff48bf5SDavid du Colombier }
2113ff48bf5SDavid du Colombier 
2123ff48bf5SDavid du Colombier /*
2133ff48bf5SDavid du Colombier  * Return the conrecte space to which this color space will map. If the
2143ff48bf5SDavid du Colombier  * ICCBased color space is being used in native mode, the concrete space
2153ff48bf5SDavid du Colombier  * will be dependent on the current color rendering dictionary, as it is
2163ff48bf5SDavid du Colombier  * for all CIE bases. If the alternate color space is being used, then
2173ff48bf5SDavid du Colombier  * this question is passed on the the appropriate method of that space.
2183ff48bf5SDavid du Colombier  */
2193ff48bf5SDavid du Colombier private const gs_color_space *
gx_concrete_space_CIEICC(const gs_color_space * pcs,const gs_imager_state * pis)2203ff48bf5SDavid du Colombier gx_concrete_space_CIEICC(const gs_color_space * pcs, const gs_imager_state * pis)
2213ff48bf5SDavid du Colombier {
2223ff48bf5SDavid du Colombier     if (pcs->params.icc.picc_info->picc == NULL) {
2233ff48bf5SDavid du Colombier         const gs_color_space *  pacs = (const gs_color_space *)
2243ff48bf5SDavid du Colombier                                         &pcs->params.icc.alt_space;
2253ff48bf5SDavid du Colombier 
2263ff48bf5SDavid du Colombier         return cs_concrete_space(pacs, pis);
2273ff48bf5SDavid du Colombier     } else
2283ff48bf5SDavid du Colombier         return gx_concrete_space_CIE(NULL, pis);
2293ff48bf5SDavid du Colombier }
2303ff48bf5SDavid du Colombier 
2313ff48bf5SDavid du Colombier /*
2323ff48bf5SDavid du Colombier  * Convert an ICCBased color space to a concrete color space.
2333ff48bf5SDavid du Colombier  */
2343ff48bf5SDavid du Colombier private int
gx_concretize_CIEICC(const gs_client_color * pcc,const gs_color_space * pcs,frac * pconc,const gs_imager_state * pis)2353ff48bf5SDavid du Colombier gx_concretize_CIEICC(
2363ff48bf5SDavid du Colombier     const gs_client_color * pcc,
2373ff48bf5SDavid du Colombier     const gs_color_space *  pcs,
2383ff48bf5SDavid du Colombier     frac *                  pconc,
2393ff48bf5SDavid du Colombier     const gs_imager_state * pis )
2403ff48bf5SDavid du Colombier {
2413ff48bf5SDavid du Colombier     const gs_icc_params *   picc_params = &pcs->params.icc;
2423ff48bf5SDavid du Colombier     const gs_cie_icc *      picc_info = picc_params->picc_info;
2433ff48bf5SDavid du Colombier     stream *                instrp = picc_info->instrp;
2443ff48bf5SDavid du Colombier     icc *                   picc = picc_info->picc;
2453ff48bf5SDavid du Colombier     double                  inv[4], outv[3];
2463ff48bf5SDavid du Colombier     cie_cached_vector3      vlmn;
2473ff48bf5SDavid du Colombier     gs_client_color         lcc = *pcc;
2483ff48bf5SDavid du Colombier     int                     i, ncomps = picc_info->num_components;
2493ff48bf5SDavid du Colombier 
2503ff48bf5SDavid du Colombier     /* use the altenate space concretize if appropriate */
2513ff48bf5SDavid du Colombier     if (picc == NULL)
2523ff48bf5SDavid du Colombier         return picc_params->alt_space.type->concretize_color(
2533ff48bf5SDavid du Colombier                             pcc,
2543ff48bf5SDavid du Colombier                             (const gs_color_space *)&picc_params->alt_space,
2553ff48bf5SDavid du Colombier                             pconc,
2563ff48bf5SDavid du Colombier                             pis );
2573ff48bf5SDavid du Colombier 
2583ff48bf5SDavid du Colombier     /* set up joint cache as required */
2593ff48bf5SDavid du Colombier     CIE_CHECK_RENDERING(pcs, pconc, pis, return 0);
2603ff48bf5SDavid du Colombier 
2613ff48bf5SDavid du Colombier     /* verify and update the stream pointer */
2623ff48bf5SDavid du Colombier     if (picc_info->file_id != (instrp->read_id | instrp->write_id))
2633ff48bf5SDavid du Colombier         return_error(gs_error_ioerror);
2643ff48bf5SDavid du Colombier     ((icmFileGs *)picc->fp)->strp = instrp;
2653ff48bf5SDavid du Colombier 
2663ff48bf5SDavid du Colombier     /* translate the input components */
2673ff48bf5SDavid du Colombier     gx_restrict_CIEICC(&lcc, pcs);
2683ff48bf5SDavid du Colombier     for (i = 0; i < ncomps; i++)
2693ff48bf5SDavid du Colombier         inv[i] = lcc.paint.values[i];
2703ff48bf5SDavid du Colombier 
271*593dc095SDavid du Colombier     /* For input Lab color space massage the values into Lab range */
272*593dc095SDavid du Colombier 
273*593dc095SDavid du Colombier     if (picc_info->plu->e_inSpace == icSigLabData) {
274*593dc095SDavid du Colombier         inv[0] *= 100;
275*593dc095SDavid du Colombier         inv[1] = inv[1]*255 - 128;
276*593dc095SDavid du Colombier         inv[2] = inv[2]*255 - 128;
277*593dc095SDavid du Colombier     }
278*593dc095SDavid du Colombier 
2793ff48bf5SDavid du Colombier     /*
2803ff48bf5SDavid du Colombier      * Perform the lookup operation. A return value of 1 indicates that
2813ff48bf5SDavid du Colombier      * clipping occurred somewhere in the operation, but the result is
2823ff48bf5SDavid du Colombier      * legitimate. Other non-zero return values indicate an error, which
2833ff48bf5SDavid du Colombier      * should not occur in practice.
2843ff48bf5SDavid du Colombier      */
2853ff48bf5SDavid du Colombier     if (picc_info->plu->lookup(picc_info->plu, outv, inv) > 1)
2863ff48bf5SDavid du Colombier         return_error(gs_error_unregistered);
2873ff48bf5SDavid du Colombier 
2883ff48bf5SDavid du Colombier     /* if the output is in the CIE L*a*b* space, convert to XYZ */
2893ff48bf5SDavid du Colombier     if (picc_info->pcs_is_cielab) {
2903ff48bf5SDavid du Colombier         floatp              f[3];
2913ff48bf5SDavid du Colombier         const gs_vector3 *  pwhtpt = &picc_info->common.points.WhitePoint;
2923ff48bf5SDavid du Colombier 
2933ff48bf5SDavid du Colombier 
2943ff48bf5SDavid du Colombier         f[1] = (outv[0] + 16.0) / 116.0;
2953ff48bf5SDavid du Colombier         f[0] = f[1] + outv[1] / 500.0;
2963ff48bf5SDavid du Colombier         f[2] = f[1] - outv[2] / 200;
2973ff48bf5SDavid du Colombier 
2983ff48bf5SDavid du Colombier         for (i = 0; i < 3; i++) {
2993ff48bf5SDavid du Colombier             if (f[i] >= 6.0 / 29.0)
3003ff48bf5SDavid du Colombier                 outv[i] = f[i] * f[i] * f[i];
3013ff48bf5SDavid du Colombier             else
3023ff48bf5SDavid du Colombier                 outv[i] = 108.0 * (f[i] - 4.0 / 29.0) / 841.0;
3033ff48bf5SDavid du Colombier         }
3043ff48bf5SDavid du Colombier 
3053ff48bf5SDavid du Colombier         /*
3063ff48bf5SDavid du Colombier          * The connection space white-point is known to be D50, but we
3073ff48bf5SDavid du Colombier          * use the more general form in case of future revisions.
3083ff48bf5SDavid du Colombier          */
3093ff48bf5SDavid du Colombier         outv[0] *= pwhtpt->u;
3103ff48bf5SDavid du Colombier         outv[1] *= pwhtpt->v;
3113ff48bf5SDavid du Colombier         outv[2] *= pwhtpt->w;
3123ff48bf5SDavid du Colombier     }
3133ff48bf5SDavid du Colombier 
3143ff48bf5SDavid du Colombier     /* translate the output */
3153ff48bf5SDavid du Colombier     vlmn.u = float2cie_cached(outv[0]);
3163ff48bf5SDavid du Colombier     vlmn.v = float2cie_cached(outv[1]);
3173ff48bf5SDavid du Colombier     vlmn.w = float2cie_cached(outv[2]);
3183ff48bf5SDavid du Colombier 
3193ff48bf5SDavid du Colombier     gx_cie_remap_finish(vlmn, pconc, pis, pcs);
3203ff48bf5SDavid du Colombier     return 0;
3213ff48bf5SDavid du Colombier }
3223ff48bf5SDavid du Colombier 
3233ff48bf5SDavid du Colombier /*
3243ff48bf5SDavid du Colombier  * Handle a reference or de-reference of the prameter structure of an
3253ff48bf5SDavid du Colombier  * ICCBased color space. For the purposes of this routine, the color space
3263ff48bf5SDavid du Colombier  * is considered a reference rather than an object, and is not itself
3273ff48bf5SDavid du Colombier  * reference counted (an unintuitive but otherwise legitimate state of
3283ff48bf5SDavid du Colombier  * affairs).
3293ff48bf5SDavid du Colombier  *
3303ff48bf5SDavid du Colombier  * Because color spaces store alternative/base color space inline, these
3313ff48bf5SDavid du Colombier  * need to have their reference count adjusted explicitly.
3323ff48bf5SDavid du Colombier  */
3333ff48bf5SDavid du Colombier private void
gx_adjust_cspace_CIEICC(const gs_color_space * pcs,int delta)3343ff48bf5SDavid du Colombier gx_adjust_cspace_CIEICC(const gs_color_space * pcs, int delta)
3353ff48bf5SDavid du Colombier {
3363ff48bf5SDavid du Colombier     const gs_icc_params *   picc_params = &pcs->params.icc;
3373ff48bf5SDavid du Colombier 
3383ff48bf5SDavid du Colombier     rc_adjust_const(picc_params->picc_info, delta, "gx_adjust_cspace_CIEICC");
3393ff48bf5SDavid du Colombier     picc_params->alt_space.type->adjust_cspace_count(
3403ff48bf5SDavid du Colombier                 (const gs_color_space *)&picc_params->alt_space, delta );
3413ff48bf5SDavid du Colombier }
3423ff48bf5SDavid du Colombier 
343*593dc095SDavid du Colombier /*
344*593dc095SDavid du Colombier  * Increment color space reference counts.
345*593dc095SDavid du Colombier  */
346*593dc095SDavid du Colombier void
gx_increment_cspace_count(const gs_color_space * pcs)347*593dc095SDavid du Colombier gx_increment_cspace_count(const gs_color_space * pcs)
348*593dc095SDavid du Colombier {
349*593dc095SDavid du Colombier     pcs->type->adjust_cspace_count(pcs, 1);
350*593dc095SDavid du Colombier }
351*593dc095SDavid du Colombier 
3523ff48bf5SDavid du Colombier private int
icmFileGs_seek(icmFile * pp,long int offset)3533ff48bf5SDavid du Colombier icmFileGs_seek(icmFile *pp, long int offset)
3543ff48bf5SDavid du Colombier {
3553ff48bf5SDavid du Colombier     icmFileGs *p = (icmFileGs *)pp;
3563ff48bf5SDavid du Colombier 
3573ff48bf5SDavid du Colombier     return spseek(p->strp, offset);
3583ff48bf5SDavid du Colombier }
3593ff48bf5SDavid du Colombier 
3603ff48bf5SDavid du Colombier private size_t
icmFileGs_read(icmFile * pp,void * buffer,size_t size,size_t count)3613ff48bf5SDavid du Colombier icmFileGs_read(icmFile *pp, void *buffer, size_t size, size_t count)
3623ff48bf5SDavid du Colombier {
3633ff48bf5SDavid du Colombier     icmFileGs *p = (icmFileGs *)pp;
3643ff48bf5SDavid du Colombier     uint    tot;
3653ff48bf5SDavid du Colombier     int     status = sgets(p->strp, buffer, size * count, &tot);
3663ff48bf5SDavid du Colombier 
3673ff48bf5SDavid du Colombier     return (status < 0) ? status : tot;
3683ff48bf5SDavid du Colombier }
3693ff48bf5SDavid du Colombier 
3703ff48bf5SDavid du Colombier private size_t
icmFileGs_write(icmFile * pp,void * buffer,size_t size,size_t count)3713ff48bf5SDavid du Colombier icmFileGs_write(icmFile *pp, void *buffer, size_t size, size_t count)
3723ff48bf5SDavid du Colombier {
3733ff48bf5SDavid du Colombier     icmFileGs *p = (icmFileGs *)pp;
3743ff48bf5SDavid du Colombier     uint    tot;
3753ff48bf5SDavid du Colombier     int     status = sputs(p->strp, buffer, size * count, &tot);
3763ff48bf5SDavid du Colombier 
3773ff48bf5SDavid du Colombier     return (status < 0) ? status : tot;
3783ff48bf5SDavid du Colombier }
3793ff48bf5SDavid du Colombier 
3803ff48bf5SDavid du Colombier private int
icmFileGs_flush(icmFile * pp)3813ff48bf5SDavid du Colombier icmFileGs_flush(icmFile *pp)
3823ff48bf5SDavid du Colombier {
3833ff48bf5SDavid du Colombier     icmFileGs *p = (icmFileGs *)pp;
3843ff48bf5SDavid du Colombier 
3853ff48bf5SDavid du Colombier     return s_std_write_flush(p->strp);
3863ff48bf5SDavid du Colombier }
3873ff48bf5SDavid du Colombier 
3883ff48bf5SDavid du Colombier private int
icmFileGs_delete(icmFile * pp)3893ff48bf5SDavid du Colombier icmFileGs_delete(icmFile *pp)
3903ff48bf5SDavid du Colombier {
3913ff48bf5SDavid du Colombier     free(pp);
3923ff48bf5SDavid du Colombier     return 0;
3933ff48bf5SDavid du Colombier }
3943ff48bf5SDavid du Colombier 
3953ff48bf5SDavid du Colombier /**
3963ff48bf5SDavid du Colombier  * gx_wrap_icc_stream: Wrap a Ghostscript stream as an icclib file.
3973ff48bf5SDavid du Colombier  * @strp: The Ghostscript stream.
3983ff48bf5SDavid du Colombier  *
3993ff48bf5SDavid du Colombier  * Creates an icmFile object that wraps @stream.
4003ff48bf5SDavid du Colombier  *
4013ff48bf5SDavid du Colombier  * Note: the memory for this object is allocated using malloc, and the
4023ff48bf5SDavid du Colombier  * relocation of the stream pointer is done lazily, before an icclu
4033ff48bf5SDavid du Colombier  * operation. It would probably be cleaner to allocate the icmFile in
4043ff48bf5SDavid du Colombier  * garbage collected memory, and have the relocation happen there, but
4053ff48bf5SDavid du Colombier  * I wanted to minimally modify Jan's working code.
4063ff48bf5SDavid du Colombier  *
4073ff48bf5SDavid du Colombier  * Return value: the stream wrapped as an icmFile object, or NULL on
4083ff48bf5SDavid du Colombier  * error.
4093ff48bf5SDavid du Colombier  **/
4103ff48bf5SDavid du Colombier private icmFile *
gx_wrap_icc_stream(stream * strp)4113ff48bf5SDavid du Colombier gx_wrap_icc_stream(stream *strp)
4123ff48bf5SDavid du Colombier {
4133ff48bf5SDavid du Colombier     icmFileGs *p;
4143ff48bf5SDavid du Colombier 
4153ff48bf5SDavid du Colombier     if ((p = (icmFileGs *) calloc(1,sizeof(icmFileGs))) == NULL)
4163ff48bf5SDavid du Colombier 	return NULL;
4173ff48bf5SDavid du Colombier     p->seek  = icmFileGs_seek;
4183ff48bf5SDavid du Colombier     p->read  = icmFileGs_read;
4193ff48bf5SDavid du Colombier     p->write = icmFileGs_write;
4203ff48bf5SDavid du Colombier     p->flush = icmFileGs_flush;
4213ff48bf5SDavid du Colombier     p->del   = icmFileGs_delete;
4223ff48bf5SDavid du Colombier 
4233ff48bf5SDavid du Colombier     p->strp = strp;
4243ff48bf5SDavid du Colombier 
4253ff48bf5SDavid du Colombier     return (icmFile *)p;
4263ff48bf5SDavid du Colombier }
4273ff48bf5SDavid du Colombier 
4283ff48bf5SDavid du Colombier int
gx_load_icc_profile(gs_cie_icc * picc_info)4293ff48bf5SDavid du Colombier gx_load_icc_profile(gs_cie_icc *picc_info)
4303ff48bf5SDavid du Colombier {
4313ff48bf5SDavid du Colombier     stream *        instrp = picc_info->instrp;
4323ff48bf5SDavid du Colombier     icc *           picc;
4333ff48bf5SDavid du Colombier     icmLuBase * plu = NULL;
4343ff48bf5SDavid du Colombier     icmFile *pfile = NULL;
4353ff48bf5SDavid du Colombier 
4363ff48bf5SDavid du Colombier     /* verify that the file is legitimate */
4373ff48bf5SDavid du Colombier     if (picc_info->file_id != (instrp->read_id | instrp->write_id))
4383ff48bf5SDavid du Colombier 	return_error(gs_error_ioerror);
4393ff48bf5SDavid du Colombier     /*
4403ff48bf5SDavid du Colombier      * Load the top-level ICC profile.
4413ff48bf5SDavid du Colombier      *
4423ff48bf5SDavid du Colombier      * If an ICC profile fails to load, generate an error.
4433ff48bf5SDavid du Colombier      *
4443ff48bf5SDavid du Colombier      * Testing demonstrates, however, Acrobat Reader silently
4453ff48bf5SDavid du Colombier      * ignores the error and uses the alternate color space.
4463ff48bf5SDavid du Colombier      * This behaviour is implemented by catching the error using
4473ff48bf5SDavid du Colombier      * a stopped context from within the interpreter (gs_icc.ps).
4483ff48bf5SDavid du Colombier      *
4493ff48bf5SDavid du Colombier      * Failure to allocate the top-level profile object is considered
4503ff48bf5SDavid du Colombier      * a limitcheck rather than a VMerror, as profile data structures
4513ff48bf5SDavid du Colombier      * are stored in "foreign" memory.
4523ff48bf5SDavid du Colombier      */
4533ff48bf5SDavid du Colombier     if ((picc = new_icc()) == NULL)
4543ff48bf5SDavid du Colombier 	return_error(gs_error_limitcheck);
4553ff48bf5SDavid du Colombier     {
4563ff48bf5SDavid du Colombier 	icProfileClassSignature profile_class;
4573ff48bf5SDavid du Colombier 	icColorSpaceSignature   cspace_type;
4583ff48bf5SDavid du Colombier 	gs_vector3 *            ppt;
4593ff48bf5SDavid du Colombier 
4603ff48bf5SDavid du Colombier 	pfile = gx_wrap_icc_stream (instrp);
4613ff48bf5SDavid du Colombier 
4623ff48bf5SDavid du Colombier 	if ((picc->read(picc, pfile, 0)) != 0)
4633ff48bf5SDavid du Colombier 	    goto return_rangecheck;
4643ff48bf5SDavid du Colombier 
4653ff48bf5SDavid du Colombier 	/* verify the profile type */
4663ff48bf5SDavid du Colombier 	profile_class = picc->header->deviceClass;
4673ff48bf5SDavid du Colombier 	if ( profile_class != icSigInputClass     &&
4683ff48bf5SDavid du Colombier 	     profile_class != icSigDisplayClass   &&
4693ff48bf5SDavid du Colombier 	     profile_class != icSigOutputClass    &&
4703ff48bf5SDavid du Colombier 	     profile_class != icSigColorSpaceClass  )
4713ff48bf5SDavid du Colombier 	    goto return_rangecheck;
4723ff48bf5SDavid du Colombier 
4733ff48bf5SDavid du Colombier 	/* verify the profile connection space */
4743ff48bf5SDavid du Colombier 	cspace_type = picc->header->pcs;
4753ff48bf5SDavid du Colombier 	if (cspace_type == icSigLabData)
4763ff48bf5SDavid du Colombier 	    picc_info->pcs_is_cielab = true;
4773ff48bf5SDavid du Colombier 	else if (cspace_type == icSigXYZData)
4783ff48bf5SDavid du Colombier 	    picc_info->pcs_is_cielab = false;
4793ff48bf5SDavid du Colombier 	else
4803ff48bf5SDavid du Colombier 	    goto return_rangecheck;
4813ff48bf5SDavid du Colombier 
4823ff48bf5SDavid du Colombier 	/* verify the source color space */
4833ff48bf5SDavid du Colombier 	cspace_type = picc->header->colorSpace;
4843ff48bf5SDavid du Colombier 	if (cspace_type == icSigCmykData) {
4853ff48bf5SDavid du Colombier 	    if (picc_info->num_components != 4)
4863ff48bf5SDavid du Colombier 		goto return_rangecheck;
4873ff48bf5SDavid du Colombier 	} else if ( cspace_type == icSigRgbData ||
4883ff48bf5SDavid du Colombier 		    cspace_type == icSigLabData   ) {
4893ff48bf5SDavid du Colombier 	    if (picc_info->num_components != 3)
4903ff48bf5SDavid du Colombier 		goto return_rangecheck;
4913ff48bf5SDavid du Colombier 	} else if (cspace_type == icSigGrayData) {
4923ff48bf5SDavid du Colombier 	    if (picc_info->num_components != 1)
4933ff48bf5SDavid du Colombier 		goto return_rangecheck;
4943ff48bf5SDavid du Colombier 	}
4953ff48bf5SDavid du Colombier 
4963ff48bf5SDavid du Colombier 	/*
4973ff48bf5SDavid du Colombier 	 * Fetch the lookup object.
4983ff48bf5SDavid du Colombier 	 *
4993ff48bf5SDavid du Colombier 	 * PostScript and PDF deal with rendering intent as strictly a
5003ff48bf5SDavid du Colombier 	 * rendering dictionary facility. ICC profiles allow a rendering
5013ff48bf5SDavid du Colombier 	 * intent to be specified for both the input (device ==> pcs) and
5023ff48bf5SDavid du Colombier 	 * output (pcs ==> device) operations. Hence, when using ICCBased
5033ff48bf5SDavid du Colombier 	 * color spaces with PDF, no clue is provided as to which source
5043ff48bf5SDavid du Colombier 	 * mapping to select.
5053ff48bf5SDavid du Colombier 	 *
5063ff48bf5SDavid du Colombier 	 * In the absence of other information, there are two possible
5073ff48bf5SDavid du Colombier 	 * selections. If our understanding is correct, when relative
5083ff48bf5SDavid du Colombier 	 * colorimetry is specified, the icclib code will map source
5093ff48bf5SDavid du Colombier 	 * color values to XYZ or L*a*b* values such that the relationship
5103ff48bf5SDavid du Colombier 	 * of the source color, relative to the source white and black
5113ff48bf5SDavid du Colombier 	 * points, will be the same as the output colors and the
5123ff48bf5SDavid du Colombier 	 * profile connection space illuminant (currently always D50)
5133ff48bf5SDavid du Colombier 	 * and pure black ([0, 0, 0]). In this case, the white and black
5143ff48bf5SDavid du Colombier 	 * points that should be listed in the color space are the
5153ff48bf5SDavid du Colombier 	 * profile connection space illuminant (D50) and pure black.
5163ff48bf5SDavid du Colombier 	 *
5173ff48bf5SDavid du Colombier 	 * If absolute colorimetry is employed, the XYZ or L*a*b* values
5183ff48bf5SDavid du Colombier 	 * generated will be absolute in the chromatic sense (they are
5193ff48bf5SDavid du Colombier 	 * not literally "absolute", as we still must have overall
5203ff48bf5SDavid du Colombier 	 * intensity information inorder to determine weighted spectral
5213ff48bf5SDavid du Colombier 	 * power levels). To achieve relative colorimetry for the output,
5223ff48bf5SDavid du Colombier 	 * these colors must be evaluated relative to the source white
5233ff48bf5SDavid du Colombier 	 * and black points. Hence, in this case, the appropriate white
5243ff48bf5SDavid du Colombier 	 * and black points to list in the color space are the source
5253ff48bf5SDavid du Colombier 	 * white and black points provided in the profile tag array.
5263ff48bf5SDavid du Colombier 	 *
5273ff48bf5SDavid du Colombier 	 * In this implementation, we will always request relative
5283ff48bf5SDavid du Colombier 	 * colorimetry from the icclib, and so will use the profile
5293ff48bf5SDavid du Colombier 	 * connection space illuminant and pure black as the white and
5303ff48bf5SDavid du Colombier 	 * black points of the color space. This approach is somewhat
5313ff48bf5SDavid du Colombier 	 * simpler, as it allows the color space white point to also
5323ff48bf5SDavid du Colombier 	 * be used for L*a*b* to XYZ conversion (otherwise we would
5333ff48bf5SDavid du Colombier 	 * need to store the profile connection space illuminant
5343ff48bf5SDavid du Colombier 	 * separately for that purpose). The approach does reduce to
5353ff48bf5SDavid du Colombier 	 * to some extent the range of mappings that can be achieved
5363ff48bf5SDavid du Colombier 	 * via the color rendering dictionary, but for now we believe
5373ff48bf5SDavid du Colombier 	 * this loss is not significant.
5383ff48bf5SDavid du Colombier 	 *
5393ff48bf5SDavid du Colombier 	 * For reasons that are not clear to us, the icclib code does
5403ff48bf5SDavid du Colombier 	 * not support relative colorimetry for all color profiles. For
5413ff48bf5SDavid du Colombier 	 * this reason, we specify icmDefaultIntent rather than
5423ff48bf5SDavid du Colombier 	 * icRelativeColormetric.
5433ff48bf5SDavid du Colombier 	 *
5443ff48bf5SDavid du Colombier 	 * NB: We are not color experts; our understanding of this area
5453ff48bf5SDavid du Colombier 	 *     may well be incorrect.
5463ff48bf5SDavid du Colombier 	 */
5473ff48bf5SDavid du Colombier 	plu = picc->get_luobj( picc,
5483ff48bf5SDavid du Colombier 			       icmFwd,
5493ff48bf5SDavid du Colombier 			       icmDefaultIntent,
5503ff48bf5SDavid du Colombier 			       0, /* PCS override */
5513ff48bf5SDavid du Colombier 			       icmLuOrdNorm );
5523ff48bf5SDavid du Colombier 	if (plu == NULL)
5533ff48bf5SDavid du Colombier 	    goto return_rangecheck;
5543ff48bf5SDavid du Colombier 
5553ff48bf5SDavid du Colombier 	/*
5563ff48bf5SDavid du Colombier 	 * Get the appropriate white and black points. See the note on
5573ff48bf5SDavid du Colombier 	 * rendering intent above for a discussion of why we are using
5583ff48bf5SDavid du Colombier 	 * the profile space illuminant and pure black. (Pure black need
5593ff48bf5SDavid du Colombier 	 * not be set explicitly, as it is the default.)
5603ff48bf5SDavid du Colombier 	 */
5613ff48bf5SDavid du Colombier 	ppt = &picc_info->common.points.WhitePoint;
5623ff48bf5SDavid du Colombier 	ppt->u = picc->header->illuminant.X;
5633ff48bf5SDavid du Colombier 	ppt->v = picc->header->illuminant.Y;
5643ff48bf5SDavid du Colombier 	ppt->w = picc->header->illuminant.Z;
5653ff48bf5SDavid du Colombier 
5663ff48bf5SDavid du Colombier 	picc_info->picc = picc;
5673ff48bf5SDavid du Colombier 	picc_info->plu = plu;
5683ff48bf5SDavid du Colombier 	picc_info->pfile = pfile;
5693ff48bf5SDavid du Colombier     }
5703ff48bf5SDavid du Colombier 
5713ff48bf5SDavid du Colombier     return 0;
5723ff48bf5SDavid du Colombier 
5733ff48bf5SDavid du Colombier  return_rangecheck:
5743ff48bf5SDavid du Colombier     if (plu != NULL)
5753ff48bf5SDavid du Colombier 	plu->del(plu);
5763ff48bf5SDavid du Colombier     if (picc != NULL)
5773ff48bf5SDavid du Colombier 	picc->del(picc);
5783ff48bf5SDavid du Colombier     if (pfile != NULL)
5793ff48bf5SDavid du Colombier 	pfile->del(pfile);
5803ff48bf5SDavid du Colombier     return_error(gs_error_rangecheck);
5813ff48bf5SDavid du Colombier }
5823ff48bf5SDavid du Colombier 
5833ff48bf5SDavid du Colombier /*
5843ff48bf5SDavid du Colombier  * Install an ICCBased color space.
5853ff48bf5SDavid du Colombier  *
5863ff48bf5SDavid du Colombier  * Note that an ICCBased color space must be installed before it is known if
5873ff48bf5SDavid du Colombier  * the ICC profile or the alternate color space is to be used.
5883ff48bf5SDavid du Colombier  */
5893ff48bf5SDavid du Colombier private int
gx_install_CIEICC(const gs_color_space * pcs,gs_state * pgs)5903ff48bf5SDavid du Colombier gx_install_CIEICC(const gs_color_space * pcs, gs_state * pgs)
5913ff48bf5SDavid du Colombier {
5923ff48bf5SDavid du Colombier     const gs_icc_params * picc_params = (const gs_icc_params *)&pcs->params.icc;
5933ff48bf5SDavid du Colombier     gs_cie_icc *    picc_info = picc_params->picc_info;
5943ff48bf5SDavid du Colombier 
5953ff48bf5SDavid du Colombier     /* update the stub information used by the joint caches */
5963ff48bf5SDavid du Colombier     gx_cie_load_common_cache(&picc_info->common, pgs);
5973ff48bf5SDavid du Colombier     gx_cie_common_complete(&picc_info->common);
5983ff48bf5SDavid du Colombier     return gs_cie_cs_complete(pgs, true);
5993ff48bf5SDavid du Colombier }
6003ff48bf5SDavid du Colombier 
6013ff48bf5SDavid du Colombier 
6023ff48bf5SDavid du Colombier /*
6033ff48bf5SDavid du Colombier  * Constructor for ICCBased color space. As with the other color space
6043ff48bf5SDavid du Colombier  * constructors, this provides only minimal initialization.
6053ff48bf5SDavid du Colombier  */
6063ff48bf5SDavid du Colombier int
gs_cspace_build_CIEICC(gs_color_space ** ppcspace,void * client_data,gs_memory_t * pmem)6073ff48bf5SDavid du Colombier gs_cspace_build_CIEICC(
6083ff48bf5SDavid du Colombier     gs_color_space **   ppcspace,
6093ff48bf5SDavid du Colombier     void *              client_data,
6103ff48bf5SDavid du Colombier     gs_memory_t *       pmem )
6113ff48bf5SDavid du Colombier {
6123ff48bf5SDavid du Colombier     gs_cie_icc *        picc_info;
6133ff48bf5SDavid du Colombier     gs_color_space *    pcs;
6143ff48bf5SDavid du Colombier 
6153ff48bf5SDavid du Colombier     /*
6163ff48bf5SDavid du Colombier      * The gs_cie_icc_s structure is the only CIE-based color space structure
6173ff48bf5SDavid du Colombier      * which accesses additional memory for which it is responsible. We make
6183ff48bf5SDavid du Colombier      * use of the finalization procedure to handle this task, so we can use
6193ff48bf5SDavid du Colombier      * the generic CIE space build routine (otherwise we would need a
6203ff48bf5SDavid du Colombier      * separate build routine that provided its own reference count freeing
6213ff48bf5SDavid du Colombier      * procedure).
6223ff48bf5SDavid du Colombier      */
6233ff48bf5SDavid du Colombier     picc_info = gx_build_cie_space( ppcspace,
6243ff48bf5SDavid du Colombier                                     &gs_color_space_type_CIEICC,
6253ff48bf5SDavid du Colombier                                     &st_cie_icc,
6263ff48bf5SDavid du Colombier                                     pmem );
6273ff48bf5SDavid du Colombier 
6283ff48bf5SDavid du Colombier     if (picc_info == NULL)
6293ff48bf5SDavid du Colombier         return_error(gs_error_VMerror);
6303ff48bf5SDavid du Colombier 
6313ff48bf5SDavid du Colombier     gx_set_common_cie_defaults(&picc_info->common, client_data);
6323ff48bf5SDavid du Colombier     /*
6333ff48bf5SDavid du Colombier      * Now set the D50 WhitePoint. The above function does not set any
6343ff48bf5SDavid du Colombier      * valid WhitepPoint since PostScript always requires this, but ICC
6353ff48bf5SDavid du Colombier      * assumes a D50 WhitePoint as a default
6363ff48bf5SDavid du Colombier      */
637*593dc095SDavid du Colombier     picc_info->common.points.WhitePoint.u = (float)0.9642;		/* Profile illuminant - D50 */
6383ff48bf5SDavid du Colombier     picc_info->common.points.WhitePoint.v = 1.0000;
639*593dc095SDavid du Colombier     picc_info->common.points.WhitePoint.w = (float)0.8249;
6403ff48bf5SDavid du Colombier     picc_info->common.install_cspace = gx_install_CIEICC;
6413ff48bf5SDavid du Colombier     picc_info->num_components = 0;
6423ff48bf5SDavid du Colombier     picc_info->Range = Range4_default;
6433ff48bf5SDavid du Colombier     picc_info->instrp = NULL;
6443ff48bf5SDavid du Colombier     picc_info->pcs_is_cielab = false;
6453ff48bf5SDavid du Colombier     picc_info->picc = NULL;
6463ff48bf5SDavid du Colombier     picc_info->plu = NULL;
6473ff48bf5SDavid du Colombier     picc_info->pfile = NULL;
6483ff48bf5SDavid du Colombier 
6493ff48bf5SDavid du Colombier     pcs = *ppcspace;
6503ff48bf5SDavid du Colombier     pcs->params.icc.picc_info = picc_info;
6513ff48bf5SDavid du Colombier     return 0;
6523ff48bf5SDavid du Colombier }
653*593dc095SDavid du Colombier 
654*593dc095SDavid du Colombier /* ---------------- Serialization. -------------------------------- */
655*593dc095SDavid du Colombier 
656*593dc095SDavid du Colombier private int
gx_serialize_CIEICC(const gs_color_space * pcs,stream * s)657*593dc095SDavid du Colombier gx_serialize_CIEICC(const gs_color_space * pcs, stream * s)
658*593dc095SDavid du Colombier {
659*593dc095SDavid du Colombier     const gs_icc_params * p = &pcs->params.icc;
660*593dc095SDavid du Colombier     gs_cie_icc *picc = p->picc_info;
661*593dc095SDavid du Colombier     uint n;
662*593dc095SDavid du Colombier     int code = gx_serialize_cspace_type(pcs, s);
663*593dc095SDavid du Colombier     long avail, pos, count;
664*593dc095SDavid du Colombier     byte buf[100];
665*593dc095SDavid du Colombier 
666*593dc095SDavid du Colombier     if (code < 0)
667*593dc095SDavid du Colombier 	return code;
668*593dc095SDavid du Colombier     code = gx_serialize_cie_common_elements(pcs, s);
669*593dc095SDavid du Colombier     if (code < 0)
670*593dc095SDavid du Colombier 	return code;
671*593dc095SDavid du Colombier     code = sputs(s, (byte *)&picc->num_components, sizeof(picc->num_components), &n);
672*593dc095SDavid du Colombier     if (code < 0)
673*593dc095SDavid du Colombier 	return code;
674*593dc095SDavid du Colombier     code = sputs(s, (byte *)&picc->Range, sizeof(picc->Range), &n);
675*593dc095SDavid du Colombier     if (code < 0)
676*593dc095SDavid du Colombier 	return code;
677*593dc095SDavid du Colombier     if (sseek(picc->instrp, 0) < 0)
678*593dc095SDavid du Colombier 	return_error(gs_error_unregistered); /* Unimplemented. */
679*593dc095SDavid du Colombier     if (savailable(picc->instrp, &avail) != 0)
680*593dc095SDavid du Colombier 	return_error(gs_error_unregistered); /* Unimplemented. */
681*593dc095SDavid du Colombier     code = sputs(s, (byte *)&avail, sizeof(avail), &n);
682*593dc095SDavid du Colombier     if (code < 0)
683*593dc095SDavid du Colombier 	return code;
684*593dc095SDavid du Colombier     for (pos = 0; pos < avail; pos += count) {
685*593dc095SDavid du Colombier 	count = min(sizeof(buf), avail - pos);
686*593dc095SDavid du Colombier 	code = sgets(picc->instrp, buf, count, &n);
687*593dc095SDavid du Colombier 	if (code < 0)
688*593dc095SDavid du Colombier 	    return code;
689*593dc095SDavid du Colombier 	code = sputs(s, buf, count, &n);
690*593dc095SDavid du Colombier 	if (code < 0)
691*593dc095SDavid du Colombier 	    return code;
692*593dc095SDavid du Colombier     }
693*593dc095SDavid du Colombier     return sputs(s, (byte *)&picc->pcs_is_cielab, sizeof(picc->pcs_is_cielab), &n);
694*593dc095SDavid du Colombier }
695